UNPKG

@apistudio/apim-cli

Version:

CLI for API Management Products

287 lines (246 loc) 8.09 kB
/** * Copyright IBM Corp. 2024, 2025 */ /* eslint-disable no-unused-vars */ import { createAssetReferenceMap, convertNumberToString, isValidAsset, addErrorToResponse, constructErrorResponse, extractGatewayTypes, createPathReferenceMap, updatePathRefMap, validateMinAssets, updateRefs, processRef, checkFileExtension, isRelativePath, } from '../src/index.js'; import yaml from 'js-yaml'; import path from 'path'; import fs from 'fs'; jest.mock('@apic/studio-shared', () => ({ Logger: { debug: jest.fn(), info: jest.fn(), warn: jest.fn(), error: jest.fn(), log: jest.fn(), createChildLogger: jest.fn().mockReturnThis(), }, LogComponent: () => (target: any) => target, Component: { Build: 'Build', All: 'Studio', }, ErrorResponse: jest.fn(), Metadata_Ref: jest.fn(), SpecObject: jest.fn(), YamlContent: jest.fn(), UpperCaseKinds: jest.fn(), loadYaml: jest.fn((content) => require('js-yaml').load(content)), SchemaHandler: jest.fn().mockImplementation(() => ({ getSchema: jest.fn().mockReturnValue(JSON.stringify({ type: 'object' })), })), })); jest.mock('@apic/studio-client-model', () => ({ AssetModelKindConstants: { API: 'API', }, GatewayLabels: { WMGW: 'webMethods', LWGW: 'nano', DPGW: 'datapower', }, })); // Mock JSZip for specific tests const mockJSZip = { loadAsync: jest.fn(), file: jest.fn(), files: {}, forEach: jest.fn(), generateAsync: jest.fn(), }; jest.mock('jszip', () => { return jest.fn().mockImplementation(() => mockJSZip); }); import { createAssetReferenceMap, convertNumberToString, isValidAsset, addErrorToResponse, constructErrorResponse, extractGatewayTypes, createPathReferenceMap, updatePathRefMap, validateMinAssets, updateRefs, processRef, checkFileExtension, isRelativePath, } from '../src/index.js'; import { YamlContent } from '@apic/studio-shared'; describe('validateYamlFiles', () => { it('should create asset reference map successfully', async () => { const zipFilePath = path.resolve(__dirname, './assets/gateway-asset.zip'); const Buffer = fs.readFileSync(zipFilePath); const result = await createAssetReferenceMap(Buffer); expect(result).not.toBe(undefined); expect(result).not.toBe(false); }); it('should log error for invalid YAML parsing', async () => { const zipFilePath = path.resolve(__dirname, './assets/invalid-yaml-asset.zip'); const zipBuffer = fs.readFileSync(zipFilePath); await createAssetReferenceMap(zipBuffer); }); it('should convert number to string correctly', () => { expect(convertNumberToString(1)).toBe('1.0'); expect(convertNumberToString(1.5)).toBe('1.5'); expect(convertNumberToString('1.5')).toBe('1.5'); }); it('should return true for valid YAML content', () => { const filePath = path.resolve(__dirname, './assets/validate/api.yaml'); const buffer = fs.readFileSync(filePath); const yamlContent = yaml.load(buffer.toString()) as YamlContent; expect(isValidAsset(yamlContent)).toBe(true); }); }); describe('checking error response', () => { it('should construct an error response object', () => { addErrorToResponse('ERR001', 'field1', 'Error description 1'); addErrorToResponse('ERR002', 'field2', 'Error description 2'); const response = constructErrorResponse(); expect(response).not.toEqual([]); }); }); describe('extractGatewayTypes', () => { beforeEach(() => { jest.clearAllMocks(); }); it('should extract gateway types from gateways.json', async () => { // Setup mock for JSZip const mockFileContent = JSON.stringify({ gateways: [ { gatewayURL: 'http://example.com', gatewayUser: 'user', gatewaySecret: 'secret', gatewayTypes: ['webMethods', 'nano'], }, ], }); mockJSZip.loadAsync.mockResolvedValue({ file: jest.fn().mockReturnValue({ async: jest.fn().mockResolvedValue(mockFileContent), }), }); const result = await extractGatewayTypes(Buffer.from('test')); expect(result).toEqual(['webMethods', 'nano']); expect(mockJSZip.loadAsync).toHaveBeenCalled(); }); it('should return empty array when gateways.json is not found', async () => { mockJSZip.loadAsync.mockResolvedValue({ file: jest.fn().mockReturnValue(null), }); const result = await extractGatewayTypes(Buffer.from('test')); expect(result).toEqual([]); }); it('should handle errors and return empty array', async () => { mockJSZip.loadAsync.mockRejectedValue(new Error('Test error')); const result = await extractGatewayTypes(Buffer.from('test')); expect(result).toEqual([]); }); }); describe('file utility functions', () => { it('should check file extension correctly', () => { expect(checkFileExtension('file.yml')).toBe(true); expect(checkFileExtension('file.yaml')).toBe(true); expect(checkFileExtension('file.txt')).toBe(false); }); it('should detect relative paths correctly', () => { expect(isRelativePath('./file.yml')).toBe(true); expect(isRelativePath('../file.yml')).toBe(true); expect(isRelativePath('file.yml')).toBe(false); expect(isRelativePath('/absolute/path/file.yml')).toBe(false); }); }); describe('path reference functions', () => { beforeEach(() => { jest.clearAllMocks(); }); it('should create path reference map', async () => { // Setup mock for JSZip mockJSZip.loadAsync.mockResolvedValue({ files: { 'file.yaml': { dir: false, async: jest.fn().mockResolvedValue('spec:\n $path: path/to/file.txt'), }, }, }); const result = await createPathReferenceMap(Buffer.from('test')); expect(result).toBeInstanceOf(Map); }); it('should update path reference map', async () => { const refMap = new Map<string, boolean>(); refMap.set('file.txt', false); // Mock JSZip.loadAsync directly const mockZipInstance = { forEach: jest.fn().mockImplementation((callback: (path: string, obj: any) => void) => { callback('resources/file.txt', { name: 'file.txt' }); }), }; // Replace the original implementation for this test const originalJSZip = require('jszip'); originalJSZip.loadAsync = jest.fn().mockResolvedValue(mockZipInstance); await updatePathRefMap(Buffer.from('test'), refMap); expect(refMap.get('file.txt')).toBe(true); }); }); describe('validateMinAssets', () => { beforeEach(() => { jest.clearAllMocks(); }); it('should return true when yaml files exist', async () => { mockJSZip.loadAsync.mockResolvedValue({ files: { 'file.yaml': { dir: false }, }, }); const result = await validateMinAssets(Buffer.from('test')); expect(result).toBe(true); }); it('should return false when no yaml files exist', async () => { mockJSZip.loadAsync.mockResolvedValue({ files: { 'file.txt': { dir: false }, }, }); const result = await validateMinAssets(Buffer.from('test')); expect(result).toBe(false); }); it('should handle errors and return false', async () => { mockJSZip.loadAsync.mockRejectedValue(new Error('Test error')); const result = await validateMinAssets(Buffer.from('test')); expect(result).toBe(false); }); }); describe('reference processing functions', () => { it('should process ref correctly', () => { expect(processRef('namespace:name:1')).toBe('namespace:name:1.0'); expect(processRef('namespace:name:1.5')).toBe('namespace:name:1.5'); expect(processRef('namespace:name:string')).toBe('namespace:name:string'); }); it('should update refs in yaml content', () => { const yamlContent = { spec: { $ref: 'namespace:name:1', }, }; const versionMap = new Map<string, boolean>(); versionMap.set('namespace:name:1', false); const result = updateRefs(yamlContent as any, versionMap); expect(result.spec.$ref).toBe('namespace:name:1.0'); }); });