UNPKG

@apistudio/apim-cli

Version:

CLI for API Management Products

560 lines (515 loc) 17.3 kB
/** * Copyright IBM Corp. 2024, 2025 */ import { TestManager } from '../../src/index.js'; import path from 'path'; import fs from 'fs'; import { TestRunner } from '../../src/engine/execution/test-runner.js'; jest.mock('../../src/service/log-wrapper.js'); jest.mock('../../src/helpers/trace-helper.js', () => ({ fetchTraceAndCatalogData: jest.fn(), fetchCaptureId: jest.fn() })); jest.mock('@apic/studio-logger', () => ({ LoggerConfig: { isLoggerEnabled: jest.fn(), }, })); jest.mock('../../src/engine/execution/test-runner.js', () => ({ TestRunner: jest.fn().mockImplementation(() => ({ run: jest.fn(), })), })); describe('test manager tests', () => { const MockTestResponseValid = { id: '6d619b61-1de3-473c-a508-948f872ce090', name: 'PetPostTest Collection', timestamp: 1750224392789, totalPass: 8, status: 'finished', startedAt: 1750224389787, totalFail: 0, totalTime: 3002, results: [ { id: '', name: 'POST /pet', url: 'https://petstore.swagger.io/v2/pet', method: 'POST', header: { 'Content-Type': 'application/json', Accept: 'application/json', }, time: 1539, responseCode: { code: 200, name: 'OK', time: 1538, size: 0, }, response: { id: 9223372036854739000, category: { id: 0, name: 'string', }, name: 'doggie', photoUrls: ['string'], tags: [ { id: 0, name: 'string', }, ], status: 'available', }, responseHeaders: [ { key: 'date', value: 'Wed, 18 Jun 2025 05:26:31 GMT', }, { key: 'content-type', value: 'application/json', }, { key: 'transfer-encoding', value: 'chunked', }, { key: 'connection', value: 'close', }, { key: 'access-control-allow-origin', value: '*', }, { key: 'access-control-allow-methods', value: 'GET, POST, DELETE, PUT', }, { key: 'access-control-allow-headers', value: 'Content-Type, api_key, Authorization', }, { key: 'server', value: 'Jetty(9.2.9.v20150224)', }, ], allTests: [ { 'Validate Response time': { status: true, actualValue: 1538, expectedValue: 3, action: 'notEquals', }, }, ], }, ], }; const mockedResponseInvalidOutputvariable = { id: '1fb34fdd-989d-4a4f-b821-b2c9b776694b', name: 'PetPostTest Collection', timestamp: 1750227902380, totalPass: 0, status: 'finished', startedAt: 1750227902377, totalFail: 0, totalTime: 3, results: [], }; const mockedResponseValidOutputVariable = { id: 'd4bf0632-86f2-42dc-b7f6-9485815f553a', name: 'PetPostTest Collection', timestamp: 1750233105313, totalPass: 3, status: 'finished', startedAt: 1750233104110, totalFail: 0, totalTime: 1203, results: [ { id: '', name: 'GET /pet/9223372036854740000', url: 'https://petstore.swagger.io/v2/pet/9223372036854740000', method: 'GET', header: { 'Content-Type': 'application/json', Accept: 'application/json', }, time: 1202, responseCode: { code: 200, name: 'OK', time: 1201, size: 0, }, response: { id: 9223372036854740000, name: 'UPDATED DOGGIE', photoUrls: ['https://example.com/dog.jpg'], tags: [], }, responseHeaders: [ { key: 'date', value: 'Wed, 18 Jun 2025 07:51:45 GMT', }, { key: 'content-type', value: 'application/json', }, { key: 'transfer-encoding', value: 'chunked', }, { key: 'connection', value: 'close', }, { key: 'access-control-allow-origin', value: '*', }, { key: 'access-control-allow-methods', value: 'GET, POST, DELETE, PUT', }, { key: 'access-control-allow-headers', value: 'Content-Type, api_key, Authorization', }, { key: 'server', value: 'Jetty(9.2.9.v20150224)', }, ], allTests: [ { 'Validate Response time': { status: true, actualValue: 1201, expectedValue: 3, action: 'notEquals', }, }, { 'Validate data id': { status: true, actualValue: 9223372036854740000, expectedValue: 1000, action: 'greaterThan', }, }, { 'Custom chai assertion': { status: true, actualValue: 9223372036854740000, expectedValue: 2, action: 'notEquals', }, }, ], }, ], }; const mockedResponseInvalidOutputVariableAssertion = { id: '7134489e-4481-4fc9-9401-51f03bbcf550', name: 'PetPostTest Collection', timestamp: 1750237726325, totalPass: 2, status: 'finished', startedAt: 1750237725089, totalFail: 1, totalTime: 1236, results: [ { id: '', name: 'GET /pet/9223372036854741000', url: 'https://petstore.swagger.io/v2/pet/9223372036854741000', method: 'GET', header: { 'Content-Type': 'application/json', Accept: 'application/json', }, time: 1235, responseCode: { code: 200, name: 'OK', time: 1235, size: 0, }, response: { id: 9223372036854741000, category: { id: 0, name: 'string', }, name: 'doggie', photoUrls: ['string'], tags: [ { id: 0, name: 'string', }, ], status: 'string', }, responseHeaders: [ { key: 'date', value: 'Wed, 18 Jun 2025 09:08:46 GMT', }, { key: 'content-type', value: 'application/json', }, { key: 'transfer-encoding', value: 'chunked', }, { key: 'connection', value: 'close', }, { key: 'access-control-allow-origin', value: '*', }, { key: 'access-control-allow-methods', value: 'GET, POST, DELETE, PUT', }, { key: 'access-control-allow-headers', value: 'Content-Type, api_key, Authorization', }, { key: 'server', value: 'Jetty(9.2.9.v20150224)', }, ], allTests: [ { 'Validate Response time': { status: true, actualValue: 1235, expectedValue: 2, action: 'notEquals', }, }, { 'Validate data id': { status: false, error: { name: 'Error', test: 'Validate data id', message: "Cannot resolve path 'payload.data.ids' – 'ids' not found.", stack: "Error: Cannot resolve path 'payload.data.ids' – 'ids' not found.\n at ContextManager.resolvePath (file:///Users/anulal/Developer/api-studio/packages/studio-test/dist/engine/variable-context-manager/context-manager.js:137:23)\n at ContextManager.resolveValue (file:///Users/anulal/Developer/api-studio/packages/studio-test/dist/engine/variable-context-manager/context-manager.js:110:25)\n at ContextManager.resolve (file:///Users/anulal/Developer/api-studio/packages/studio-test/dist/engine/variable-context-manager/context-manager.js:86:21)\n at AssertionEngine.resolveValue (file:///Users/anulal/Developer/api-studio/packages/studio-test/dist/engine/assertion/assertion.engine.js:75:20)\n at AssertionEngine.assert (file:///Users/anulal/Developer/api-studio/packages/studio-test/dist/engine/assertion/assertion.engine.js:22:42)\n at TestRunner.run (file:///Users/anulal/Developer/api-studio/packages/studio-test/dist/engine/execution/test-runner.js:35:68)\n at process.processTicksAndRejections (node:internal/process/task_queues:95:5)\n at async Promise.allSettled (index 0)\n at async TestManager.processFile (file:///Users/anulal/Developer/api-studio/packages/studio-test/dist/managers/test.manager.js:210:35)\n at async file:///Users/anulal/Developer/api-studio/packages/studio-server/dist/controllers/test.controller.js:36:25", }, action: 'equals', }, }, { 'Custom chai assertion': { status: true, actualValue: 9223372036854741000, expectedValue: 2, action: 'notEquals', }, }, ], }, ], }; it('should return response for valid asset', async () => { (TestRunner as jest.Mock).mockImplementation(() => { return { run: () => MockTestResponseValid, }; }); const obj = new TestManager(); const zipFilePath = path.resolve(__dirname, '../assets/valid-asset.zip'); const zipBuffer = fs.readFileSync(zipFilePath); const result = await obj.processFile(zipBuffer); expect(Array.isArray(result)).toBe(true); expect(result[0]).toEqual(MockTestResponseValid); }); it('should return empty result if output variable is not defined in test file', async () => { (TestRunner as jest.Mock).mockImplementation(() => { return { run: () => mockedResponseInvalidOutputvariable, }; }); const obj = new TestManager(); const zipFilePath = path.resolve( __dirname, '../assets/invalidOutputVariable.zip', ); const zipBuffer = fs.readFileSync(zipFilePath); const result = await obj.processFile(zipBuffer); expect(Array.isArray(result)).toBe(true); expect(result).toEqual([mockedResponseInvalidOutputvariable]); }); it('should return response if output variable is defined in test file', async () => { (TestRunner as jest.Mock).mockImplementation(() => { return { run: () => mockedResponseValidOutputVariable, }; }); const obj = new TestManager(); const zipFilePath = path.resolve(__dirname, '../assets/valid-asset.zip'); const zipBuffer = fs.readFileSync(zipFilePath); const result = await obj.processFile(zipBuffer); expect(result).toEqual([mockedResponseValidOutputVariable]); }); it('should return null if output variable is not defined in Assertion file', async () => { (TestRunner as jest.Mock).mockImplementation(() => { return { run: () => mockedResponseInvalidOutputVariableAssertion, }; }); const obj = new TestManager(); const zipFilePath = path.resolve( __dirname, '../assets/InvalidOutputVariableInAssertion.zip', ); const zipBuffer = fs.readFileSync(zipFilePath); const result = await obj.processFile(zipBuffer); expect(Array.isArray(result)).toBe(true); expect(result).toEqual([mockedResponseInvalidOutputVariableAssertion]); }); describe('processTrace', () => { beforeEach(() => { jest.clearAllMocks(); }); it('should call fetchTraceAndCatalogData with the correct parameters', async () => { // Mock the fetchTraceAndCatalogData function const mockTraceData = { traceData: { id: 'trace-123', details: 'Sample trace data' }, catalogData: { id: 'catalog-456', name: 'Test API' } }; const traceHelperModule = require('../../src/helpers/trace-helper.js'); traceHelperModule.fetchTraceAndCatalogData.mockResolvedValue(mockTraceData); // Create test data const reqBody = JSON.stringify({ url: 'https://api.example.com', apiName: 'test-api' }); const reqHeader = { 'x-access-token': 'test-token' }; // Call the method const testManager = new TestManager(); const result = await testManager.processTrace(reqBody, reqHeader); // Assertions expect(traceHelperModule.fetchTraceAndCatalogData).toHaveBeenCalledWith(reqBody, reqHeader); expect(result).toEqual(mockTraceData); }); it('should handle errors from fetchTraceAndCatalogData', async () => { // Mock the fetchTraceAndCatalogData function to throw an error const mockError = new Error('Failed to fetch trace data'); const traceHelperModule = require('../../src/helpers/trace-helper.js'); traceHelperModule.fetchTraceAndCatalogData.mockRejectedValue(mockError); // Create test data const reqBody = JSON.stringify({ url: 'https://api.example.com', apiName: 'test-api' }); const reqHeader = { 'x-access-token': 'test-token' }; // Call the method const testManager = new TestManager(); // Assert that the error is propagated await expect(testManager.processTrace(reqBody, reqHeader)).rejects.toThrow('Failed to fetch trace data'); }); it('should return null when fetchTraceAndCatalogData returns null', async () => { // Mock the fetchTraceAndCatalogData function to return null const traceHelperModule = require('../../src/helpers/trace-helper.js'); traceHelperModule.fetchTraceAndCatalogData.mockResolvedValue(null); // Create test data const reqBody = JSON.stringify({ url: 'https://api.example.com', apiName: 'test-api' }); const reqHeader = { 'x-access-token': 'test-token' }; // Call the method const testManager = new TestManager(); const result = await testManager.processTrace(reqBody, reqHeader); // Assertions expect(result).toBeNull(); }); }); describe('getCaptureId', () => { beforeEach(() => { jest.clearAllMocks(); }); it('should call fetchCaptureId with the correct parameters', async () => { // Mock the fetchCaptureId function const mockCaptureData = { captureId: 'capture-123', status: 'success' }; const traceHelperModule = require('../../src/helpers/trace-helper.js'); traceHelperModule.fetchCaptureId.mockResolvedValue(mockCaptureData); // Create test data const reqBody = JSON.stringify({ url: 'https://api.example.com', apiName: 'test-api' }); const reqHeader = { 'x-access-token': 'test-token' }; // Call the method const testManager = new TestManager(); const result = await testManager.getCaptureId(reqBody, reqHeader); // Assertions expect(traceHelperModule.fetchCaptureId).toHaveBeenCalledWith(reqBody, reqHeader); expect(result).toEqual(mockCaptureData); }); it('should handle errors from fetchCaptureId', async () => { // Mock the fetchCaptureId function to throw an error const mockError = new Error('Failed to fetch capture ID'); const traceHelperModule = require('../../src/helpers/trace-helper.js'); traceHelperModule.fetchCaptureId.mockRejectedValue(mockError); // Create test data const reqBody = JSON.stringify({ url: 'https://api.example.com', apiName: 'test-api' }); const reqHeader = { 'x-access-token': 'test-token' }; // Call the method const testManager = new TestManager(); // Assert that the error is propagated await expect(testManager.getCaptureId(reqBody, reqHeader)).rejects.toThrow('Failed to fetch capture ID'); }); it('should return null when fetchCaptureId returns null', async () => { // Mock the fetchCaptureId function to return null const traceHelperModule = require('../../src/helpers/trace-helper.js'); traceHelperModule.fetchCaptureId.mockResolvedValue(null); // Create test data const reqBody = JSON.stringify({ url: 'https://api.example.com', apiName: 'test-api' }); const reqHeader = { 'x-access-token': 'test-token' }; // Call the method const testManager = new TestManager(); const result = await testManager.getCaptureId(reqBody, reqHeader); // Assertions expect(result).toBeNull(); }); }); });