From b472ec914bf273ff9095ebb352bd828b2b7ff4d0 Mon Sep 17 00:00:00 2001 From: Barry Gordon Date: Fri, 26 Sep 2025 13:33:36 +0100 Subject: [PATCH] Add a quick regression test for the artefact summary --- __tests__/main.test.ts | 153 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 153 insertions(+) create mode 100644 __tests__/main.test.ts diff --git a/__tests__/main.test.ts b/__tests__/main.test.ts new file mode 100644 index 0000000..efea986 --- /dev/null +++ b/__tests__/main.test.ts @@ -0,0 +1,153 @@ +import { + afterEach, + beforeEach, + describe, + expect, + jest, + test +} from '@jest/globals' +import * as fs from 'fs' +import * as core from '@actions/core' +import {DefaultArtifactClient} from '@actions/artifact' +import type {SpyInstance} from 'jest-mock' +import {handleLargeSummary} from '../src/main' + +jest.mock('ansi-styles', () => ({ + __esModule: true, + default: { + color: { + red: {open: '', close: ''}, + yellow: {open: '', close: ''}, + grey: {open: '', close: ''}, + green: {open: '', close: ''} + }, + bold: {open: '', close: ''} + } +})) +jest.mock('../src/dependency-graph', () => ({})) +jest.mock('@actions/core', () => { + const summary = { + addRaw: jest.fn().mockReturnThis(), + addHeading: jest.fn().mockReturnThis(), + addTable: jest.fn().mockReturnThis(), + addSeparator: jest.fn().mockReturnThis(), + addImage: jest.fn().mockReturnThis(), + addList: jest.fn().mockReturnThis(), + addBreak: jest.fn().mockReturnThis(), + addLink: jest.fn().mockReturnThis(), + addDetails: jest.fn().mockReturnThis(), + addSection: jest.fn().mockReturnThis(), + addCodeBlock: jest.fn().mockReturnThis(), + addFields: jest.fn().mockReturnThis(), + addEol: jest.fn().mockReturnThis(), + write: jest.fn(async () => undefined), + emptyBuffer: jest.fn(), + stringify: jest.fn(() => '') + } + return { + __esModule: true, + getInput: jest.fn((name: string) => + name === 'repo-token' ? 'gh_test_token' : '' + ), + setOutput: jest.fn(), + setFailed: jest.fn(), + warning: jest.fn(), + info: jest.fn(), + debug: jest.fn(), + startGroup: jest.fn(), + endGroup: jest.fn(), + group: jest.fn(async (_name: string, fn: () => Promise) => fn()), + summary + } +}) +jest.mock('@actions/artifact', () => ({ + DefaultArtifactClient: jest.fn() +})) + +const ORIGINAL_ENV = {...process.env} + +type ArtifactClientInstance = { + uploadArtifact: jest.Mock +} + +const DefaultArtifactClientMock = DefaultArtifactClient as unknown as jest.Mock + +const createArtifactClient = (): ArtifactClientInstance => ({ + uploadArtifact: jest.fn(async () => undefined) +}) + +describe('handleLargeSummary', () => { + let writeFileSpy: SpyInstance + + beforeEach(() => { + process.env = {...ORIGINAL_ENV} + writeFileSpy = jest + .spyOn(fs.promises, 'writeFile') + .mockImplementation(async () => undefined) + DefaultArtifactClientMock.mockClear() + DefaultArtifactClientMock.mockImplementation(() => createArtifactClient()) + }) + + afterEach(() => { + writeFileSpy.mockRestore() + jest.clearAllMocks() + process.env = {...ORIGINAL_ENV} + }) + + test('returns original summary when under size threshold', async () => { + const summaryContent = 'short summary' + + const result = await handleLargeSummary(summaryContent) + + expect(result).toBe(summaryContent) + expect(writeFileSpy).not.toHaveBeenCalled() + expect(DefaultArtifactClientMock).not.toHaveBeenCalled() + }) + + test('uploads artifact and returns minimal summary when summary is too large', async () => { + process.env.GITHUB_SERVER_URL = 'https://github.com' + process.env.GITHUB_REPOSITORY = 'owner/repo' + process.env.GITHUB_RUN_ID = '12345' + + const largeSummary = 'a'.repeat(1024 * 1024 + 1) + + const result = await handleLargeSummary(largeSummary) + + expect(writeFileSpy).toHaveBeenCalledTimes(1) + expect(writeFileSpy).toHaveBeenCalledWith('summary.md', largeSummary) + expect(DefaultArtifactClientMock).toHaveBeenCalledTimes(1) + + const artifactInstance = DefaultArtifactClientMock.mock.results[0] + ?.value as ArtifactClientInstance + + expect(artifactInstance.uploadArtifact).toHaveBeenCalledWith( + 'dependency-review-summary', + ['summary.md'], + '.', + {retentionDays: 1} + ) + + expect(result).toContain('# Dependency Review Summary') + expect(result).toContain('dependency-review-summary') + expect(result).toContain('actions/runs/12345') + }) + + test('returns original summary and logs a warning when artifact handling fails', async () => { + const warningMock = core.warning as jest.Mock + warningMock.mockClear() + const largeSummary = 'b'.repeat(1024 * 1024 + 1) + + DefaultArtifactClientMock.mockImplementation(() => ({ + uploadArtifact: jest.fn(async () => { + throw new Error('upload failed') + }) + })) + + const result = await handleLargeSummary(largeSummary) + + expect(result).toBe(largeSummary) + expect(warningMock).toHaveBeenCalledWith( + expect.stringContaining('Failed to handle large summary') + ) + }) +})