@apistudio/apim-cli
Version:
CLI for API Management Products
227 lines (178 loc) • 7.21 kB
text/typescript
/**
* Copyright Super iPaaS Integration LLC, an IBM Company 2024
*/
/* eslint-disable @typescript-eslint/no-explicit-any */
import AdmZip from 'adm-zip';
import { getRandomFileName, isDirectory, isDirOrFileExists, normalizePath} from '../common/fs-helper.js';
import { showInfo } from '../common/message-helper.js';
import { addDependencyAsset, isSameAsset, searchAsset, fromAssetRefValue } from './build-helper.js';
import fs from 'fs';
import { Metadata } from '@apic/api-model/common/Metadata.js';
// Mock implementation
jest.mock('adm-zip', () => {
let entries: any[] = [];
const mockAddFile = jest.fn((name: string, data: Buffer) => {
entries = [...entries, {
entryName: name,
getData: () => data,
isDirectory: false,
}];
});
const mockGetEntries = jest.fn(() => entries);
return jest.fn().mockImplementation(() => ({
addFile: mockAddFile,
getEntries: mockGetEntries,
}));
});
jest.mock('../common/yaml-helper', () => ({
convertToYAMLString: jest.fn(),
readMultiYaml: jest.fn(),
}));
jest.mock('../common/fs-helper', () => ({
getRandomFileName: jest.fn(),
isDirectory: jest.fn(),
isDirOrFileExists: jest.fn(),
isYamlFile: jest.fn(),
readFile: jest.fn(),
normalizePath: jest.fn(),
}));
jest.mock('../common/message-helper', () => ({
showInfo: jest.fn(),
showWarning: jest.fn(),
}));
jest.mock('fs', () => ({
readdirSync: jest.fn(),
Dirent: jest.fn().mockImplementation((name: string, isDirectory: boolean) => ({
name,
isDirectory: () => isDirectory,
})),
readFileSync: jest.fn(),
readfileSync: jest.fn()
}));
describe('Build helper function test suite', () => {
afterEach(() => {
jest.clearAllMocks();
});
describe('addDependencyAsset function', () => {
let zip: AdmZip;
beforeEach(() => {
zip = new AdmZip();
zip.addLocalFile = jest.fn();
});
it('should add a dependency asset to the zip', () => {
const mockDirent: fs.Dirent = {
name: 'testName.yml',
isDirectory: () => false,
isFile: () => true,
isBlockDevice: () => false,
isCharacterDevice: () => false,
isFIFO: () => false,
isSocket: () => false,
isSymbolicLink: () => false,
[Symbol.toStringTag]: 'Dirent',
parentPath: '/mock/path',
} as unknown as fs.Dirent;
const mockFileName = 'randomFileName.yml';
(getRandomFileName as jest.Mock).mockReturnValue(mockFileName);
(normalizePath as jest.Mock).mockReturnValue(`/mock/path/${mockDirent.name}`);
addDependencyAsset(mockDirent, zip);
expect(getRandomFileName).toHaveBeenCalledWith('.yml');
expect(normalizePath).toHaveBeenCalledWith(`/mock/path/${mockDirent.name}`);
expect(zip.addLocalFile).toHaveBeenCalledWith(`/mock/path/${mockDirent.name}`, 'dependencies', mockFileName);
});
it('should not add a null asset to the zip', () => {
addDependencyAsset(null as unknown as fs.Dirent, zip);
expect(showInfo).not.toHaveBeenCalled();
expect(zip.addLocalFile).not.toHaveBeenCalled();
});
it('should not add an undefined asset to the zip', () => {
addDependencyAsset(undefined as unknown as fs.Dirent, zip);
expect(showInfo).not.toHaveBeenCalled();
expect(zip.addLocalFile).not.toHaveBeenCalled();
});
it('should add a dependency asset to the zip with a different file extension', () => {
const mockDirent: fs.Dirent = {
name: 'testName.json',
isDirectory: () => false,
isFile: () => true,
isBlockDevice: () => false,
isCharacterDevice: () => false,
isFIFO: () => false,
isSocket: () => false,
isSymbolicLink: () => false,
[Symbol.toStringTag]: 'Dirent',
parentPath: '/mock/path',
} as unknown as fs.Dirent;
const mockFileName = 'randomFileName.json';
(getRandomFileName as jest.Mock).mockReturnValue(mockFileName);
(normalizePath as jest.Mock).mockReturnValue(`/mock/path/${mockDirent.name}`);
addDependencyAsset(mockDirent, zip, '.json');
expect(getRandomFileName).toHaveBeenCalledWith('.json');
expect(normalizePath).toHaveBeenCalledWith(`/mock/path/${mockDirent.name}`);
expect(zip.addLocalFile).toHaveBeenCalledWith(`/mock/path/${mockDirent.name}`, 'dependencies', mockFileName);
});
});
describe('isSameAsset function', () => {
it('should return true for mixed version assets', () => {
const metadata1 = { namespace: 'ns', name: 'asset', version: '1' };
const metadata2 = { namespace: 'ns', name: 'asset', version: '1.0' };
expect(isSameAsset(metadata1, metadata2)).toBe(true);
});
it('should return true for identical assets', () => {
const metadata1 = { namespace: 'ns', name: 'asset', version: '1.0' };
const metadata2 = { namespace: 'ns', name: 'asset', version: '1.0' };
expect(isSameAsset(metadata1, metadata2)).toBe(true);
});
it('should return false for different namespace assets', () => {
const metadata1 = { namespace: 'ns2', name: 'asset', version: '1.0.0' };
const metadata2 = { namespace: 'ns', name: 'asset', version: '1.0' };
expect(isSameAsset(metadata1, metadata2)).toBe(false);
});
it('should return false for different assets', () => {
const metadata1: Metadata = { namespace: 'ns', name: 'name', version: '1.0.0' };
const metadata2: Metadata = { namespace: 'ns', name: 'name2', version: '1.0.0' };
expect(isSameAsset(metadata1, metadata2)).toBe(false);
});
});
describe('searchAsset function', () => {
const projectDirPath = '/path/to/project';
it('should throw an error for invalid directory', () => {
const projectDirPath = 'invalidPath';
(isDirOrFileExists as jest.Mock).mockReturnValue(false);
expect(() => searchAsset('kind', 'ref', projectDirPath)).toThrow(`Invalid directory ${projectDirPath}`);
});
it('should return undefined and show warning if no entries found', () => {
(isDirOrFileExists as jest.Mock).mockReturnValue(true);
(isDirectory as jest.Mock).mockReturnValue(true);
(fs.readdirSync as jest.Mock).mockReturnValue([]);
const result = searchAsset('kind', 'ref', projectDirPath);
expect(result).toBeUndefined();
});
});
describe('fromAssetRefValue function', () => {
it('should parse asset ref value with name only', () => {
const refValue = 'name';
expect(fromAssetRefValue(refValue)).toEqual({ name: 'name' });
});
it('should parse asset ref value with name and version', () => {
const refValue = 'name:1.0.0';
expect(fromAssetRefValue(refValue)).toEqual({ name: 'name', version: '1.0.0' });
});
it('should handle asset ref value with only colons', () => {
const refValue = ':::';
const expectedMetadata: Metadata = { namespace: '', name: '', version: '' };
const result = fromAssetRefValue(refValue);
expect(result).toEqual(expectedMetadata);
});
it('should parse asset ref value with namespace, name, and version', () => {
const refValue = 'ns:name:1.0.0';
expect(fromAssetRefValue(refValue)).toEqual({ namespace: 'ns', name: 'name', version: '1.0.0' });
});
it('should handle empty asset ref value', () => {
const refValue = '';
const expectedMetadata: Metadata = { name: '' };
const result = fromAssetRefValue(refValue);
expect(result).toEqual(expectedMetadata);
});
});
});