@apistudio/apim-cli
Version:
CLI for API Management Products
314 lines (267 loc) • 9.21 kB
text/typescript
/**
* Copyright IBM Corp. 2024, 2025
*/
import axios from 'axios';
import https from 'https';
import {
fetchCaptureId,
fetchTraceAndCatalogData,
} from '../../src/helpers/trace-helper.js';
// Mock axios
jest.mock('axios');
const mockedAxios = axios as jest.Mocked<typeof axios>;
// Mock https
jest.mock('https', () => ({
Agent: jest.fn().mockImplementation(() => ({})),
}));
describe('trace-helper', () => {
beforeEach(() => {
jest.clearAllMocks();
// Mock axios.create to return an object with post and get methods
mockedAxios.create.mockReturnValue({
post: jest.fn(),
get: jest.fn(),
} as any);
});
describe('fetchCaptureId', () => {
const mockReqBody = JSON.stringify({
url: 'https://api.example.com',
apiName: 'test-api',
orgName: 'test-org',
catalogName: 'test-catalog',
gatewayName: 'test-gateway',
});
const mockHeaders = {
'authorization': 'Bearer test-token',
};
it('should fetch capture ID successfully', async () => {
// Mock response data
const mockResponseData = {
captureId: 'test-capture-id',
status: 'success',
};
// Setup axios post mock
const mockPost = jest.fn().mockResolvedValue({
data: mockResponseData,
});
mockedAxios.create.mockReturnValue({
post: mockPost,
} as any);
// Call the function
const result = await fetchCaptureId(mockReqBody, mockHeaders);
// Assertions
expect(https.Agent).toHaveBeenCalledWith({
rejectUnauthorized: false,
});
expect(mockedAxios.create).toHaveBeenCalledWith({
httpsAgent: expect.any(Object),
baseURL: 'https://api.example.com',
});
// Verify the post call
expect(mockPost).toHaveBeenCalledWith(
'https://api.example.com/api/catalogs/test-org/test-catalog/configured-gateway-services/test-gateway/assembly-debug',
{ FilterByAPI: 'test-api' },
{
headers: {
Authorization: 'Bearer test-token',
Accept: 'application/json',
'Content-Type': 'application/json',
},
},
);
// Verify the result
expect(result).toEqual(mockResponseData);
});
it('should return null when token is not provided', async () => {
// Call the function without token
const result = await fetchCaptureId(mockReqBody, {});
// Assertions
expect(mockedAxios.create).not.toHaveBeenCalled();
expect(result).toBeNull();
});
it('should handle errors and return null', async () => {
// Setup axios post mock to throw error
const mockPost = jest.fn().mockRejectedValue(new Error('Network error'));
mockedAxios.create.mockReturnValue({
post: mockPost,
} as any);
// Mock console.error
console.error = jest.fn();
// Call the function
const result = await fetchCaptureId(mockReqBody, mockHeaders);
// Assertions
expect(console.error).toHaveBeenCalledWith('err ==> ', expect.any(Error));
expect(result).toBeNull();
});
});
describe('fetchTraceAndCatalogData', () => {
const mockReqBody = JSON.stringify({
url: 'https://api.example.com',
orgName: 'test-org',
catalogName: 'test-catalog',
gatewayName: 'test-gateway',
captureId: 'test-capture-id',
transactionId: 'test-transaction-id',
orgId: 'test-org-id',
apiName: 'test-api',
apiVersion: '1.0.0',
});
const mockHeaders = {
'authorization': 'Bearer test-token',
};
it('should fetch trace and catalog data successfully', async () => {
// Mock response data
const mockTraceData = {
id: 'trace-123',
details: 'Sample trace data',
};
const mockCatalogData = {
id: 'catalog-456',
name: 'Test API',
version: '1.0.0',
};
// Setup axios get mock for trace data
const mockGet = jest
.fn()
.mockResolvedValueOnce({ data: mockTraceData }) // First call for trace data
.mockResolvedValueOnce({ data: { catalog_api: mockCatalogData } }); // Second call for catalog data
mockedAxios.create.mockReturnValue({
get: mockGet,
} as any);
// Call the function
const result = await fetchTraceAndCatalogData(mockReqBody, mockHeaders);
// Assertions
expect(https.Agent).toHaveBeenCalledWith({
rejectUnauthorized: false,
});
// Verify the get calls
expect(mockGet).toHaveBeenCalledWith(
'https://api.example.com/api/catalogs/test-org/test-catalog/configured-gateway-services/test-gateway/assembly-debug/test-capture-id/transaction/test-transaction-id',
{
headers: {
Authorization: 'Bearer test-token',
Accept: 'application/json',
'Content-Type': 'application/json',
},
},
);
expect(mockGet).toHaveBeenCalledWith(
"https://api.example.com/api/catalogs/test-org-id/test-catalog/apis/test-api/1.0.0?fields=add(catalog_api,product_urls)'",
{
headers: {
Authorization: 'Bearer test-token',
Accept: 'application/json',
'Content-Type': 'application/json',
},
},
);
// Verify the result
expect(result).toEqual({
traceData: mockTraceData,
catalogData: mockCatalogData,
});
});
it('should handle missing transaction ID and fetch it', async () => {
// Mock request body without transaction ID
const reqBodyWithoutTransId = JSON.stringify({
url: 'https://api.example.com',
orgName: 'test-org',
catalogName: 'test-catalog',
gatewayName: 'test-gateway',
captureId: 'test-capture-id',
orgId: 'test-org-id',
apiName: 'test-api',
apiVersion: '1.0.0',
});
// Mock response data
const mockTransactionId = 'fetched-transaction-id';
const mockTraceData = {
id: 'trace-123',
details: 'Sample trace data',
};
const mockCatalogData = {
id: 'catalog-456',
name: 'Test API',
version: '1.0.0',
};
// Setup axios get mock
const mockGet = jest
.fn()
.mockResolvedValueOnce({ Probe: { ProbeID: mockTransactionId } }) // First call to fetch transaction ID (no data wrapper)
.mockResolvedValueOnce({ data: mockTraceData }) // Second call for trace data
.mockResolvedValueOnce({ data: { catalog_api: mockCatalogData } }); // Third call for catalog data
mockedAxios.create.mockReturnValue({
get: mockGet,
} as any);
// Call the function
const result = await fetchTraceAndCatalogData(
reqBodyWithoutTransId,
mockHeaders,
);
// Assertions for transaction ID fetch
expect(mockGet).toHaveBeenCalledWith(
'https://api.example.com/api/catalogs/test-org/test-catalog/configured-gateway-services/test-gateway/assembly-debug/test-capture-id/transaction',
{
headers: {
Authorization: 'Bearer test-token',
Accept: 'application/json',
'Content-Type': 'application/json',
},
},
);
// Verify the result
expect(result).toEqual({
traceData: mockTraceData,
catalogData: mockCatalogData,
});
});
it('should handle errors in fetchTraceData and return null', async () => {
// Setup axios get mock to throw error for trace data
const mockGet = jest
.fn()
.mockRejectedValueOnce(new Error('Network error')) // Error for trace data
.mockResolvedValueOnce({
data: { catalog_api: { id: 'catalog-456' } },
}); // Success for catalog data
mockedAxios.create.mockReturnValue({
get: mockGet,
} as any);
// Mock console.error
console.error = jest.fn();
// Call the function
const result = await fetchTraceAndCatalogData(mockReqBody, mockHeaders);
// Assertions
expect(console.error).toHaveBeenCalledWith(
'fetch trace error',
expect.any(Error),
);
expect(result).toEqual({
traceData: null,
catalogData: { id: 'catalog-456' },
});
});
it('should handle errors in fetchCatalogData and return null', async () => {
// Setup axios get mock
const mockGet = jest
.fn()
.mockResolvedValueOnce({ data: { id: 'trace-123' } }) // Success for trace data
.mockRejectedValueOnce(new Error('Catalog error')); // Error for catalog data
mockedAxios.create.mockReturnValue({
get: mockGet,
} as any);
// Mock console.error
console.error = jest.fn();
// Call the function
const result = await fetchTraceAndCatalogData(mockReqBody, mockHeaders);
// Assertions
expect(console.error).toHaveBeenCalledWith(
'catalog error ==>',
expect.any(Error),
);
expect(result).toEqual({
traceData: { id: 'trace-123' },
catalogData: null,
});
});
});
});