UNPKG

@apistudio/apim-cli

Version:

CLI for API Management Products

205 lines (180 loc) 6.01 kB
/** * Copyright IBM Corp. 2024, 2025 */ import { AssetValidator } from '../../src/service/validation-service.js'; import { Logger, SchemaHandler, YamlContent } from '@apic/studio-shared'; import type { ValidateFunction, ErrorObject } from 'ajv'; // Mock SchemaHandler specifically for this test while preserving Logger mock from setup.ts jest.mock('@apic/studio-shared', () => { const mockLogger = { debug: jest.fn(), info: jest.fn(), warn: jest.fn(), error: jest.fn(), log: jest.fn(), createChildLogger: jest.fn().mockReturnThis(), }; return { Logger: mockLogger, LogComponent: jest.fn(() => (target: any) => target), Component: { Build: 'Build', }, SchemaHandler: jest.fn().mockImplementation(() => { return { getSchema: jest.fn((kind: string): string | null => { // Return different schemas based on test cases if (kind === 'InvalidSchema') { return 'invalid-json'; } else if (kind === 'EmptySchema') { return null; } else if (kind === 'StagedPolicySequence') { return JSON.stringify({ type: 'object', properties: {} }); } else if (kind === 'ValidationFailure') { return JSON.stringify({ type: 'object', required: ['requiredProperty'], properties: { requiredProperty: { type: 'string' }, }, }); } else { return JSON.stringify({ type: 'object', properties: {} }); } }), }; }), }; }); jest.mock('ajv', () => { return { Ajv: jest.fn().mockImplementation(() => { return { addFormat: jest.fn(), compile: jest.fn((): ValidateFunction => { const validate = ((data: any): boolean => { if (data.kind === 'ValidationFailure') { validate.errors = [ { instancePath: '/path/to/error', schemaPath: '#/required', keyword: 'required', message: 'must have required property', params: { missingProperty: 'requiredProperty' }, } as ErrorObject, ]; return false; } return true; }) as ValidateFunction; validate.errors = null; return validate; }), }; }), }; }); jest.mock('ajv-formats', () => { return { default: jest.fn(() => {}), }; }); describe('Asset Validate', () => { let assetValidator: AssetValidator; beforeEach(() => { const schemaHandler = new SchemaHandler(); assetValidator = new AssetValidator(schemaHandler); jest.clearAllMocks(); }); test('should return invalid when kind is missing', () => { const genObj = {} as YamlContent; const result = assetValidator.validateAssets(genObj); expect(result.valid).toBe(false); expect(result.errors).toHaveLength(1); expect(result.errors[0]).toContain( `Error validating asset: Cannot read properties of undefined (reading 'namespace')` ); expect(Logger.error).toHaveBeenCalledWith(expect.any(String), expect.any(Error)); }); test('should return invalid when schema is not found', () => { const genObj = { kind: 'EmptySchema', apiVersion: 'v1', metadata: { labels: { gatewayTypes: ['test-gateway'], }, }, } as unknown as YamlContent; const result = assetValidator.validateAssets(genObj); expect(result.valid).toBe(false); expect(result.errors).toHaveLength(1); expect(result.errors[0]).toContain('Schema not found for kind'); expect(Logger.error).toHaveBeenCalledWith(expect.any(String)); }); test('should skip validation for StagedPolicySequence', () => { const genObj = { kind: 'StagedPolicySequence', apiVersion: 'v1', metadata: { labels: { gatewayTypes: ['test-gateway'], }, }, } as unknown as YamlContent; const result = assetValidator.validateAssets(genObj); expect(result.valid).toBe(true); expect(result.errors).toHaveLength(0); }); test('should return invalid when validation fails', () => { const genObj = { kind: 'ValidationFailure', apiVersion: 'v1', metadata: { labels: { gatewayTypes: ['test-gateway'], }, }, } as unknown as YamlContent; const result = assetValidator.validateAssets(genObj); expect(result.valid).toBe(false); expect(result.errors).toHaveLength(1); expect(result.errors[0]).toContain( 'The asset undefined:undefined:undefined has one or more problems.' ); expect(result.errors[0]).toContain('must have required property'); expect(result.errors[0]).toContain('Review the error and try publishing again'); expect(Logger.error).toHaveBeenCalledWith(expect.any(String)); }); test('should return valid when validation passes', () => { const genObj = { kind: 'ValidKind', apiVersion: 'v1', metadata: { labels: { gatewayTypes: ['test-gateway'], }, }, } as unknown as YamlContent; const result = assetValidator.validateAssets(genObj); expect(result.valid).toBe(true); expect(result.errors).toHaveLength(0); }); test('should handle exceptions during validation', () => { const genObj = { kind: 'InvalidSchema', apiVersion: 'v1', metadata: { labels: { gatewayTypes: ['test-gateway'], }, }, } as unknown as YamlContent; // This will cause an exception when trying to parse the schema const result = assetValidator.validateAssets(genObj); expect(result.valid).toBe(false); expect(result.errors).toHaveLength(1); expect(result.errors[0]).toContain('Error validating asset'); expect(Logger.error).toHaveBeenCalledWith(expect.any(String), expect.any(Error)); }); });