mirror of
				https://github.com/actions/download-artifact.git
				synced 2025-10-31 16:43:41 +00:00 
			
		
		
		
	Add tests & test dependencies
This commit is contained in:
		
							parent
							
								
									c7cfc3a2a3
								
							
						
					
					
						commit
						96a6f165f4
					
				
							
								
								
									
										226
									
								
								__tests__/download.test.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										226
									
								
								__tests__/download.test.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,226 @@ | ||||
| import * as core from '@actions/core' | ||||
| import * as github from '@actions/github' | ||||
| import * as os from 'os' | ||||
| import artifact, {ArtifactNotFoundError} from '@actions/artifact' | ||||
| import {run} from '../src/download-artifact' | ||||
| import {Inputs} from '../src/constants' | ||||
| 
 | ||||
| const fixtures = { | ||||
|   artifactName: 'artifact-name', | ||||
|   rootDirectory: '/some/artifact/path', | ||||
|   filesToUpload: [ | ||||
|     '/some/artifact/path/file1.txt', | ||||
|     '/some/artifact/path/file2.txt' | ||||
|   ] | ||||
| } | ||||
| 
 | ||||
| jest.mock('@actions/github', () => ({ | ||||
|   context: { | ||||
|     repo: { | ||||
|       owner: 'actions', | ||||
|       repo: 'toolkit' | ||||
|     }, | ||||
|     runId: 123, | ||||
|     serverUrl: 'https://github.com' | ||||
|   } | ||||
| })) | ||||
| 
 | ||||
| jest.mock('@actions/core') | ||||
| 
 | ||||
| /* eslint-disable no-unused-vars */ | ||||
| const mockInputs = (overrides?: Partial<{[K in Inputs]?: any}>) => { | ||||
|   const inputs = { | ||||
|     [Inputs.Name]: 'artifact-name', | ||||
|     [Inputs.Path]: '/some/artifact/path', | ||||
|     [Inputs.GitHubToken]: 'warn', | ||||
|     [Inputs.Repository]: 'owner/some-repository', | ||||
|     [Inputs.RunID]: 'some-run-id', | ||||
|     [Inputs.Pattern]: 'some-pattern', | ||||
|     ...overrides | ||||
|   } | ||||
| 
 | ||||
|   ;(core.getInput as jest.Mock).mockImplementation((name: string) => { | ||||
|     return inputs[name] | ||||
|   }) | ||||
|   ;(core.getBooleanInput as jest.Mock).mockImplementation((name: string) => { | ||||
|     return inputs[name] | ||||
|   }) | ||||
| 
 | ||||
|   return inputs | ||||
| } | ||||
| 
 | ||||
| describe('download', () => { | ||||
|     beforeEach(async () => { | ||||
|       mockInputs() | ||||
|       jest.clearAllMocks() | ||||
|        | ||||
|       // Mock artifact client methods
 | ||||
|       jest.spyOn(artifact, 'listArtifacts').mockImplementation(() =>  | ||||
|         Promise.resolve({ artifacts: [] }) | ||||
|       ) | ||||
|       jest.spyOn(artifact, 'getArtifact').mockImplementation((name) => { | ||||
|         throw new ArtifactNotFoundError(`Artifact '${name}' not found`) | ||||
|       }) | ||||
|       jest.spyOn(artifact, 'downloadArtifact').mockImplementation(() =>  | ||||
|         Promise.resolve({ digestMismatch: false }) | ||||
|       ) | ||||
|     }) | ||||
| 
 | ||||
|     test('downloads a single artifact by name', async () => { | ||||
|       const mockArtifact = {  | ||||
|         id: 123,  | ||||
|         name: 'artifact-name',  | ||||
|         size: 1024,  | ||||
|         digest: 'abc123'  | ||||
|       } | ||||
|        | ||||
|       jest.spyOn(artifact, 'getArtifact').mockImplementation(() =>  | ||||
|         Promise.resolve({ artifact: mockArtifact }) | ||||
|       ) | ||||
|        | ||||
|       await run() | ||||
|        | ||||
|       expect(artifact.downloadArtifact).toHaveBeenCalledWith( | ||||
|         mockArtifact.id,  | ||||
|         expect.objectContaining({ | ||||
|           expectedHash: mockArtifact.digest | ||||
|         }) | ||||
|       ) | ||||
|       expect(core.info).toHaveBeenCalledWith('Total of 1 artifact(s) downloaded') | ||||
|     }) | ||||
| 
 | ||||
|     test('downloads multiple artifacts when no name or pattern provided', async () => { | ||||
|       jest.clearAllMocks() | ||||
|       mockInputs({  | ||||
|         [Inputs.Name]: '',  | ||||
|         [Inputs.Pattern]: ''  | ||||
|       }) | ||||
|        | ||||
|       const mockArtifacts = [ | ||||
|         { id: 123, name: 'artifact1', size: 1024, digest: 'abc123' }, | ||||
|         { id: 456, name: 'artifact2', size: 2048, digest: 'def456' } | ||||
|       ] | ||||
|        | ||||
|       // Set up artifact mock after clearing mocks
 | ||||
|       jest.spyOn(artifact, 'listArtifacts').mockImplementation(() =>  | ||||
|         Promise.resolve({ artifacts: mockArtifacts }) | ||||
|       ) | ||||
|        | ||||
|       // Reset downloadArtifact mock as well
 | ||||
|       jest.spyOn(artifact, 'downloadArtifact').mockImplementation(() =>  | ||||
|         Promise.resolve({ digestMismatch: false }) | ||||
|       ) | ||||
|        | ||||
|       await run() | ||||
| 
 | ||||
|       expect(core.info).toHaveBeenCalledWith('No input name or pattern filtered specified, downloading all artifacts') | ||||
|        | ||||
|       expect(core.info).toHaveBeenCalledWith('Total of 2 artifact(s) downloaded') | ||||
|       expect(artifact.downloadArtifact).toHaveBeenCalledTimes(2) | ||||
|     }) | ||||
|      | ||||
|     test('sets download path output even when no artifacts are found', async () => { | ||||
|       mockInputs({ [Inputs.Name]: '' }) | ||||
|        | ||||
|       await run() | ||||
|        | ||||
|       expect(core.setOutput).toHaveBeenCalledWith( | ||||
|         'download-path', | ||||
|         expect.any(String) | ||||
|       ) | ||||
| 
 | ||||
|       expect(core.info).toHaveBeenCalledWith( | ||||
|         'Download artifact has finished successfully' | ||||
|       ) | ||||
|        | ||||
|       expect(core.info).toHaveBeenCalledWith( | ||||
|         'Total of 0 artifact(s) downloaded' | ||||
|       ) | ||||
|     }) | ||||
| 
 | ||||
|     test('filters artifacts by pattern', async () => { | ||||
|       const mockArtifacts = [ | ||||
|         { id: 123, name: 'test-artifact', size: 1024, digest: 'abc123' }, | ||||
|         { id: 456, name: 'prod-artifact', size: 2048, digest: 'def456' } | ||||
|       ] | ||||
|        | ||||
|       jest.spyOn(artifact, 'listArtifacts').mockImplementation(() =>  | ||||
|         Promise.resolve({ artifacts: mockArtifacts }) | ||||
|       ) | ||||
|        | ||||
|       mockInputs({  | ||||
|         [Inputs.Name]: '', | ||||
|         [Inputs.Pattern]: 'test-*'  | ||||
|       }) | ||||
|        | ||||
|       await run() | ||||
|        | ||||
|       expect(artifact.downloadArtifact).toHaveBeenCalledTimes(1) | ||||
|       expect(artifact.downloadArtifact).toHaveBeenCalledWith( | ||||
|         123, | ||||
|         expect.anything() | ||||
|       ) | ||||
|     }) | ||||
| 
 | ||||
|     test('uses token and repository information when provided', async () => { | ||||
|       const token = 'ghp_testtoken123' | ||||
|        | ||||
|       mockInputs({ | ||||
|         [Inputs.Name]: '', | ||||
|         [Inputs.GitHubToken]: token, | ||||
|         [Inputs.Repository]: 'myorg/myrepo', | ||||
|         [Inputs.RunID]: '789' | ||||
|       }) | ||||
|        | ||||
|       jest.spyOn(artifact, 'listArtifacts').mockImplementation(() =>  | ||||
|         Promise.resolve({ artifacts: [] }) | ||||
|       ) | ||||
|        | ||||
|       await run() | ||||
|        | ||||
|       expect(artifact.listArtifacts).toHaveBeenCalledWith( | ||||
|         expect.objectContaining({ | ||||
|           findBy: { | ||||
|             token, | ||||
|             workflowRunId: 789, | ||||
|             repositoryName: 'myrepo', | ||||
|             repositoryOwner: 'myorg' | ||||
|           } | ||||
|         }) | ||||
|       ) | ||||
|     }) | ||||
| 
 | ||||
|     test('throws error when repository format is invalid', async () => { | ||||
|       mockInputs({ | ||||
|         [Inputs.GitHubToken]: 'some-token', | ||||
|         [Inputs.Repository]: 'invalid-format'  // Missing the owner/repo format
 | ||||
|       }) | ||||
|        | ||||
|       await expect(run()).rejects.toThrow( | ||||
|         "Invalid repository: 'invalid-format'. Must be in format owner/repo" | ||||
|       ) | ||||
|     }) | ||||
|      | ||||
|     test('warns when digest validation fails', async () => { | ||||
|       const mockArtifact = {  | ||||
|         id: 123,  | ||||
|         name: 'corrupted-artifact',  | ||||
|         size: 1024,  | ||||
|         digest: 'abc123'  | ||||
|       } | ||||
|        | ||||
|       jest.spyOn(artifact, 'getArtifact').mockImplementation(() =>  | ||||
|         Promise.resolve({ artifact: mockArtifact }) | ||||
|       ) | ||||
|        | ||||
|       jest.spyOn(artifact, 'downloadArtifact').mockImplementation(() =>  | ||||
|         Promise.resolve({ digestMismatch: true }) | ||||
|       ) | ||||
|        | ||||
|       await run() | ||||
|        | ||||
|       expect(core.warning).toHaveBeenCalledWith( | ||||
|         expect.stringContaining('digest validation failed') | ||||
|       ) | ||||
|     }) | ||||
|   }) | ||||
							
								
								
									
										12
									
								
								jest.config.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								jest.config.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,12 @@ | ||||
| module.exports = { | ||||
|     clearMocks: true, | ||||
|     moduleFileExtensions: ['js', 'ts'], | ||||
|     roots: ['<rootDir>'], | ||||
|     testEnvironment: 'node', | ||||
|     testMatch: ['**/*.test.ts'], | ||||
|     testRunner: 'jest-circus/runner', | ||||
|     transform: { | ||||
|       '^.+\\.ts$': 'ts-jest' | ||||
|     }, | ||||
|     verbose: true | ||||
|   } | ||||
							
								
								
									
										8309
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										8309
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @ -1,6 +1,6 @@ | ||||
| { | ||||
|   "name": "download-artifact", | ||||
|   "version": "4.2.1", | ||||
|   "version": "4.2.0", | ||||
|   "description": "Download an Actions Artifact from a workflow run", | ||||
|   "main": "dist/index.js", | ||||
|   "scripts": { | ||||
| @ -9,7 +9,8 @@ | ||||
|     "check-all": "concurrently \"npm:format-check\" \"npm:lint\" \"npm:build\"", | ||||
|     "format": "prettier --write **/*.ts", | ||||
|     "format-check": "prettier --check **/*.ts", | ||||
|     "lint": "eslint **/*.ts" | ||||
|     "lint": "eslint **/*.ts", | ||||
|     "test": "jest" | ||||
|   }, | ||||
|   "repository": { | ||||
|     "type": "git", | ||||
| @ -34,6 +35,7 @@ | ||||
|     "minimatch": "^9.0.3" | ||||
|   }, | ||||
|   "devDependencies": { | ||||
|     "@types/jest": "^29.5.14", | ||||
|     "@types/node": "^12.12.6", | ||||
|     "@typescript-eslint/eslint-plugin": "^6.14.0", | ||||
|     "@vercel/ncc": "^0.33.4", | ||||
| @ -41,7 +43,10 @@ | ||||
|     "eslint": "^8.55.0", | ||||
|     "eslint-plugin-github": "^4.10.1", | ||||
|     "eslint-plugin-prettier": "^5.0.1", | ||||
|     "jest": "^29.7.0", | ||||
|     "prettier": "^3.1.1", | ||||
|     "ts-jest": "^29.2.6", | ||||
|     "ts-node": "^10.9.2", | ||||
|     "typescript": "^5.3.3" | ||||
|   } | ||||
| } | ||||
|  | ||||
| @ -15,7 +15,7 @@ export const chunk = <T>(arr: T[], n: number): T[][] => | ||||
|     return acc | ||||
|   }, [] as T[][]) | ||||
| 
 | ||||
| async function run(): Promise<void> { | ||||
| export async function run(): Promise<void> { | ||||
|   const inputs = { | ||||
|     name: core.getInput(Inputs.Name, {required: false}), | ||||
|     path: core.getInput(Inputs.Path, {required: false}), | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user