import * as github from '@actions/github' import type {RestEndpointMethods} from '@octokit/plugin-rest-endpoint-methods/dist-types/generated/method-types' import type {RestEndpointMethodTypes} from '@octokit/plugin-rest-endpoint-methods/dist-types/generated/parameters-and-response-types' import { listArtifactsInternal, listArtifactsPublic } from '../src/internal/find/list-artifacts' import * as config from '../src/internal/shared/config' import {ArtifactServiceClientJSON, Timestamp} from '../src/generated' import * as util from '../src/internal/shared/util' import {noopLogs} from './common' import {Artifact} from '../src/internal/shared/interfaces' type MockedListWorkflowRunArtifacts = jest.MockedFunction< RestEndpointMethods['actions']['listWorkflowRunArtifacts'] > jest.mock('@actions/github', () => ({ getOctokit: jest.fn().mockReturnValue({ rest: { actions: { listWorkflowRunArtifacts: jest.fn() } } }) })) const artifactsToListResponse = ( artifacts: Artifact[] ): RestEndpointMethodTypes['actions']['listWorkflowRunArtifacts']['response']['data'] => { return { total_count: artifacts.length, artifacts: artifacts.map(artifact => ({ name: artifact.name, id: artifact.id, size_in_bytes: artifact.size, created_at: artifact.createdAt?.toISOString() || '', run_id: fixtures.runId, // unused fields for tests url: '', archive_download_url: '', expired: false, expires_at: '', node_id: '', run_url: '', type: '', updated_at: '' })) } } const fixtures = { repo: 'toolkit', owner: 'actions', token: 'ghp_1234567890', runId: 123, backendIds: { workflowRunBackendId: 'c4d7c21f-ba3f-4ddc-a8c8-6f2f626f8422', workflowJobRunBackendId: '760803a1-f890-4d25-9a6e-a3fc01a0c7cf' }, artifacts: [ { id: 1, name: 'my-artifact', size: 456, createdAt: new Date('2023-12-01') }, { id: 2, name: 'my-artifact', size: 456, createdAt: new Date('2023-12-02') } ] } describe('list-artifact', () => { beforeAll(() => { noopLogs() }) describe('public', () => { it('should return a list of artifacts', async () => { const mockListArtifacts = github.getOctokit(fixtures.token).rest.actions .listWorkflowRunArtifacts as MockedListWorkflowRunArtifacts mockListArtifacts.mockResolvedValueOnce({ status: 200, headers: {}, url: '', data: artifactsToListResponse(fixtures.artifacts) }) const response = await listArtifactsPublic( fixtures.runId, fixtures.owner, fixtures.repo, fixtures.token, false ) expect(response).toEqual({ artifacts: fixtures.artifacts }) }) it('should return the latest artifact when latest is specified', async () => { const mockListArtifacts = github.getOctokit(fixtures.token).rest.actions .listWorkflowRunArtifacts as MockedListWorkflowRunArtifacts mockListArtifacts.mockResolvedValueOnce({ status: 200, headers: {}, url: '', data: artifactsToListResponse(fixtures.artifacts) }) const response = await listArtifactsPublic( fixtures.runId, fixtures.owner, fixtures.repo, fixtures.token, true ) expect(response).toEqual({ artifacts: [fixtures.artifacts[1]] }) }) it('can return empty artifacts', async () => { const mockListArtifacts = github.getOctokit(fixtures.token).rest.actions .listWorkflowRunArtifacts as MockedListWorkflowRunArtifacts mockListArtifacts.mockResolvedValueOnce({ status: 200, headers: {}, url: '', data: { total_count: 0, artifacts: [] } }) const response = await listArtifactsPublic( fixtures.runId, fixtures.owner, fixtures.repo, fixtures.token, true ) expect(response).toEqual({ artifacts: [] }) }) it('should fail if non-200 response', async () => { const mockListArtifacts = github.getOctokit(fixtures.token).rest.actions .listWorkflowRunArtifacts as MockedListWorkflowRunArtifacts mockListArtifacts.mockRejectedValue(new Error('boom')) await expect( listArtifactsPublic( fixtures.runId, fixtures.owner, fixtures.repo, fixtures.token, false ) ).rejects.toThrow('boom') }) }) describe('internal', () => { beforeEach(() => { jest.spyOn(config, 'getRuntimeToken').mockReturnValue('test-token') jest .spyOn(util, 'getBackendIdsFromToken') .mockReturnValue(fixtures.backendIds) jest .spyOn(config, 'getResultsServiceUrl') .mockReturnValue('https://results.local') }) it('should return a list of artifacts', async () => { jest .spyOn(ArtifactServiceClientJSON.prototype, 'ListArtifacts') .mockResolvedValue({ artifacts: fixtures.artifacts.map(artifact => ({ ...fixtures.backendIds, databaseId: artifact.id.toString(), name: artifact.name, size: artifact.size.toString(), createdAt: Timestamp.fromDate(artifact.createdAt) })) }) const response = await listArtifactsInternal(false) expect(response).toEqual({ artifacts: fixtures.artifacts }) }) it('should return the latest artifact when latest is specified', async () => { jest .spyOn(ArtifactServiceClientJSON.prototype, 'ListArtifacts') .mockResolvedValue({ artifacts: fixtures.artifacts.map(artifact => ({ ...fixtures.backendIds, databaseId: artifact.id.toString(), name: artifact.name, size: artifact.size.toString(), createdAt: Timestamp.fromDate(artifact.createdAt) })) }) const response = await listArtifactsInternal(true) expect(response).toEqual({ artifacts: [fixtures.artifacts[1]] }) }) it('can return empty artifacts', async () => { jest .spyOn(ArtifactServiceClientJSON.prototype, 'ListArtifacts') .mockResolvedValue({ artifacts: [] }) const response = await listArtifactsInternal(false) expect(response).toEqual({ artifacts: [] }) }) it('should fail if non-200 response', async () => { jest .spyOn(ArtifactServiceClientJSON.prototype, 'ListArtifacts') .mockRejectedValue(new Error('boom')) await expect(listArtifactsInternal(false)).rejects.toThrow('boom') }) }) })