/*! * @license * Copyright Squiz Australia Pty Ltd. All Rights Reserved. */ import { AxiosInstance } from 'axios'; import path from 'path'; import { JobManifestV1, ManifestServiceForDev } from '../../../../manifest'; import { getAndValidateManifest } from './manifestValidator'; import { checkIfVersionExists } from './versionChecker'; jest.mock('../../../../manifest', () => ({ ManifestServiceForDev: jest.fn(), JobManifestV1: jest.fn(), })); jest.mock('./versionChecker', () => ({ checkIfVersionExists: jest.fn(), })); jest.mock('path', () => ({ join: jest.fn(), })); describe('manifestValidator', () => { let mockApiClient: AxiosInstance; let mockManifestService: jest.Mocked; let mockManifest: jest.Mocked; const mockCheckIfVersionExists = checkIfVersionExists as jest.MockedFunction; const mockPathJoin = path.join as jest.MockedFunction; beforeEach(() => { jest.clearAllMocks(); mockApiClient = { get: jest.fn(), post: jest.fn(), } as any; mockManifest = { getName: jest.fn(), getVersion: jest.fn(), getModel: jest.fn(), } as any; mockManifestService = { readJobManifest: jest.fn(), } as any; (ManifestServiceForDev as jest.Mock).mockImplementation(() => mockManifestService); }); describe('getAndValidateManifest', () => { const testFolderPath = '/test/job/folder'; const testManifestPath = '/test/job/folder/manifest.json'; const testJobName = 'test-job'; const testJobVersion = '1.0.0'; beforeEach(() => { mockPathJoin.mockReturnValue(testManifestPath); mockManifest.getName.mockReturnValue(testJobName); mockManifest.getVersion.mockReturnValue(testJobVersion); mockManifestService.readJobManifest.mockResolvedValue(mockManifest); }); it('should successfully validate manifest when version does not exist', async () => { mockCheckIfVersionExists.mockResolvedValue(false); const result = await getAndValidateManifest(mockApiClient, testFolderPath); expect(ManifestServiceForDev).toHaveBeenCalledWith(); expect(mockPathJoin).toHaveBeenCalledWith(testFolderPath, 'manifest.json'); expect(mockManifestService.readJobManifest).toHaveBeenCalledWith(testManifestPath); expect(mockCheckIfVersionExists).toHaveBeenCalledWith(mockApiClient, `/job/${testJobName}/${testJobVersion}`); expect(result).toBe(mockManifest); }); it('should throw error when version already exists', async () => { mockCheckIfVersionExists.mockResolvedValue(true); await expect(getAndValidateManifest(mockApiClient, testFolderPath)).rejects.toThrow( `Cannot upload job version, ${testJobName} ${testJobVersion} already exists`, ); expect(mockManifestService.readJobManifest).toHaveBeenCalledWith(testManifestPath); expect(mockCheckIfVersionExists).toHaveBeenCalledWith(mockApiClient, `/job/${testJobName}/${testJobVersion}`); }); it('should handle manifest reading failure', async () => { const manifestError = new Error('Failed to read manifest'); mockManifestService.readJobManifest.mockRejectedValue(manifestError); await expect(getAndValidateManifest(mockApiClient, testFolderPath)).rejects.toThrow('Failed to read manifest'); expect(mockManifestService.readJobManifest).toHaveBeenCalledWith(testManifestPath); expect(mockCheckIfVersionExists).not.toHaveBeenCalled(); }); it('should handle version check failure', async () => { const versionCheckError = new Error('Version check failed'); mockCheckIfVersionExists.mockRejectedValue(versionCheckError); await expect(getAndValidateManifest(mockApiClient, testFolderPath)).rejects.toThrow('Version check failed'); expect(mockManifestService.readJobManifest).toHaveBeenCalledWith(testManifestPath); expect(mockCheckIfVersionExists).toHaveBeenCalledWith(mockApiClient, `/job/${testJobName}/${testJobVersion}`); }); it('should handle manifest with special characters in name', async () => { const specialJobName = 'test-job@special#characters'; const specialJobVersion = '1.0.0-beta.1'; mockManifest.getName.mockReturnValue(specialJobName); mockManifest.getVersion.mockReturnValue(specialJobVersion); mockCheckIfVersionExists.mockResolvedValue(false); const result = await getAndValidateManifest(mockApiClient, testFolderPath); expect(mockCheckIfVersionExists).toHaveBeenCalledWith( mockApiClient, `/job/${specialJobName}/${specialJobVersion}`, ); expect(result).toBe(mockManifest); }); it('should handle empty job name', async () => { mockManifest.getName.mockReturnValue(''); mockManifest.getVersion.mockReturnValue(testJobVersion); mockCheckIfVersionExists.mockResolvedValue(false); const result = await getAndValidateManifest(mockApiClient, testFolderPath); expect(mockCheckIfVersionExists).toHaveBeenCalledWith(mockApiClient, `/job//${testJobVersion}`); expect(result).toBe(mockManifest); }); it('should handle empty job version', async () => { mockManifest.getName.mockReturnValue(testJobName); mockManifest.getVersion.mockReturnValue(''); mockCheckIfVersionExists.mockResolvedValue(false); const result = await getAndValidateManifest(mockApiClient, testFolderPath); expect(mockCheckIfVersionExists).toHaveBeenCalledWith(mockApiClient, `/job/${testJobName}/`); expect(result).toBe(mockManifest); }); it('should handle different folder path formats', async () => { const relativePath = './test/job'; const expectedManifestPath = './test/job/manifest.json'; mockPathJoin.mockReturnValue(expectedManifestPath); mockCheckIfVersionExists.mockResolvedValue(false); await getAndValidateManifest(mockApiClient, relativePath); expect(mockPathJoin).toHaveBeenCalledWith(relativePath, 'manifest.json'); expect(mockManifestService.readJobManifest).toHaveBeenCalledWith(expectedManifestPath); }); it('should handle folder path with trailing slash', async () => { const folderPathWithSlash = '/test/job/folder/'; const expectedManifestPath = '/test/job/folder/manifest.json'; mockPathJoin.mockReturnValue(expectedManifestPath); mockCheckIfVersionExists.mockResolvedValue(false); await getAndValidateManifest(mockApiClient, folderPathWithSlash); expect(mockPathJoin).toHaveBeenCalledWith(folderPathWithSlash, 'manifest.json'); expect(mockManifestService.readJobManifest).toHaveBeenCalledWith(expectedManifestPath); }); it('should properly construct version check endpoint', async () => { const complexJobName = 'my-complex_job.name'; const complexJobVersion = '2.1.0-rc.1'; mockManifest.getName.mockReturnValue(complexJobName); mockManifest.getVersion.mockReturnValue(complexJobVersion); mockCheckIfVersionExists.mockResolvedValue(false); await getAndValidateManifest(mockApiClient, testFolderPath); expect(mockCheckIfVersionExists).toHaveBeenCalledWith( mockApiClient, `/job/${complexJobName}/${complexJobVersion}`, ); }); it('should handle null/undefined values from manifest', async () => { mockManifest.getName.mockReturnValue(null as any); mockManifest.getVersion.mockReturnValue(undefined as any); mockCheckIfVersionExists.mockResolvedValue(false); await getAndValidateManifest(mockApiClient, testFolderPath); expect(mockCheckIfVersionExists).toHaveBeenCalledWith(mockApiClient, `/job/${null}/${undefined}`); }); }); });