Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 0 additions & 26 deletions cli/jest.config.js

This file was deleted.

2 changes: 1 addition & 1 deletion cli/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
"watch": "node watch.mjs",
"copy-calm-schema": "copyfiles \"../calm/draft/2024-10/meta/*\" dist/calm/",
"copy-docify-templates": "copyfiles \"../shared/src/docify/template-bundles/**/*\" dist --up 4",
"test": "jest",
"test": "vitest run",
"lint": "eslint src",
"lint-fix": "eslint src --fix",
"dependency-check": "dependency-check --project 'calm-cli' --scan . --out ./dependency-check-report --format ALL --suppression ../.github/node-cve-ignore-list.xml"
Expand Down
83 changes: 31 additions & 52 deletions cli/src/cli.e2e.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import axios from 'axios';


// Mock axios
jest.mock('axios');
vi.mock('axios');

const execPromise = util.promisify(exec);

Expand All @@ -19,11 +19,11 @@ describe('CLI Integration Tests', () => {
const millisPerSecond = 1000;
const integrationTestPrefix = 'calm-test';
const projectRoot = __dirname;
jest.setTimeout(30 * millisPerSecond);
vi.setConfig({ testTimeout: 30 * millisPerSecond });

beforeAll(async () => {
tempDir = fs.mkdtempSync(path.join(os.tmpdir(), integrationTestPrefix));
await callNpxFunction(`${projectRoot}/../..`, 'link cli'); // Link the CLI package to the top-level node_modules
await execPromise('npm link', { cwd: path.resolve(projectRoot, '../../cli') });
}, millisPerSecond * 20);

afterAll(async () => {
Expand All @@ -32,46 +32,42 @@ describe('CLI Integration Tests', () => {
}
}, millisPerSecond * 20);

test('shows help if no arguments provided', (done) => {
test('shows help if no arguments provided', async () => {
const noArgCommand = 'calm';
exec(noArgCommand, (error, _stdout, stderr) => {
expect(error).not.toBeNull();
expect(stderr).toContain('A set of tools for interacting with the Common Architecture Language Model');
expect(stderr).toContain('Usage:');
done();
});
});

test('shows help if -h provided', (done) => {
test('shows help if -h provided', async () => {
const helpShortFlagCommand = 'calm -h';
exec(helpShortFlagCommand, (_error, stdout, _stderr) => {
expect(stdout).toContain('A set of tools for interacting with the Common Architecture Language Model');
expect(stdout).toContain('Usage:');
done();
});
});

test('shows help if --help provided', (done) => {
test('shows help if --help provided', async () => {
const helpLongFlagCommand = 'calm --help';
exec(helpLongFlagCommand, (_error, stdout, _stderr) => {
expect(stdout).toContain('A set of tools for interacting with the Common Architecture Language Model');
expect(stdout).toContain('Usage:');
done();
});
});

test('example validate command - outputting JSON to stdout', (done) => {
test('example validate command - outputting JSON to stdout', async () => {
const exampleValidateCommand = 'calm validate -p ../calm/pattern/api-gateway.json -a ../calm/samples/api-gateway-architecture.json';
exec(exampleValidateCommand, (_error, stdout, _stderr) => {
const parsedOutput = JSON.parse(stdout);
const expectedFilePath = path.join(__dirname, '../test_fixtures/validate_output.json');
const expectedJson = JSON.parse(fs.readFileSync(expectedFilePath, 'utf-8'));
expect(parsedOutput).toEqual(expectedJson);
done();
});
});

test('example validate command - outputting JSON to file', (done) => {
test('example validate command - outputting JSON to file', async () => {
const targetOutputFile = path.join(tempDir, 'validate-output.json');
const exampleValidateCommand = `calm validate -p ../calm/pattern/api-gateway.json -a ../calm/samples/api-gateway-architecture.json -o ${targetOutputFile}`;
exec(exampleValidateCommand, (_error, _stdout, _stderr) => {
Expand All @@ -84,12 +80,10 @@ describe('CLI Integration Tests', () => {
const expectedJson = JSON.parse(fs.readFileSync(expectedFilePath, 'utf-8'));

expect(parsedOutput).toEqual(expectedJson);

done();
});
});

test('example validate command - outputting JUNIT to stdout', (done) => {
test('example validate command - outputting JUNIT to stdout', async () => {
const exampleValidateCommand = 'calm validate -p ../calm/pattern/api-gateway.json -a ../calm/samples/api-gateway-architecture.json -f junit';
exec(exampleValidateCommand, async (_error, stdout, _stderr) => {
const parsedOutput = await parseStringPromise(stdout);
Expand All @@ -99,11 +93,10 @@ describe('CLI Integration Tests', () => {
const expectedXml = await parseStringPromise(expectedXmlString);

expect(parsedOutput).toEqual(expectedXml);
done();
});
});

test('example validate command - outputting JUNIT to file', (done) => {
test('example validate command - outputting JUNIT to file', async () => {
const targetOutputFile = path.join(tempDir, 'validate-output.xml');
const exampleValidateCommand = `calm validate -p ../calm/pattern/api-gateway.json -a ../calm/samples/api-gateway-architecture.json -f junit -o ${targetOutputFile}`;
exec(exampleValidateCommand, async (_error, _stdout, _stderr) => {
Expand All @@ -117,13 +110,11 @@ describe('CLI Integration Tests', () => {
const expectedXml = await parseStringPromise(expectedXmlString);

expect(parsedOutput).toEqual(expectedXml);

done();
});
});


test('example generate command - does it give the output we expect', (done) => {
test('example generate command - does it give the output we expect', async () => {
const targetOutputFile = path.join(tempDir, 'generate-output.json');
const exampleGenerateCommand = `calm generate -p ../calm/pattern/api-gateway.json -o ${targetOutputFile}`;
exec(exampleGenerateCommand, async (_error, _stdout, _stderr) => {
Expand All @@ -136,23 +127,20 @@ describe('CLI Integration Tests', () => {
const expectedJson = JSON.parse(fs.readFileSync(expectedFilePath, 'utf-8'));

expect(parsedOutput).toEqual(expectedJson);

done();
});
});

test('example validate command - outputting PRETTY to stdout', (done) => {
test('example validate command - outputting PRETTY to stdout', async () => {
const exampleValidateCommand = 'calm validate -p ../calm/pattern/api-gateway.json -a ../calm/samples/api-gateway-architecture.json -f pretty';
exec(exampleValidateCommand, (_error, stdout, _stderr) => {
const expectedFilePath = path.join(__dirname, '../test_fixtures/validate_output_pretty.txt');
const expectedOutput = fs.readFileSync(expectedFilePath, 'utf-8');
//Some minor replacement logic to avoid issues with line endings
expect(stdout.replace(/\r\n/g, '\n')).toEqual(expectedOutput.replace(/\r\n/g, '\n'));
done();
});
});

test('example validate command - outputting PRETTY to file', (done) => {
test('example validate command - outputting PRETTY to file', async () => {
const targetOutputFile = path.join(tempDir, 'validate-output-pretty.txt');
const exampleValidateCommand = `calm validate -p ../calm/pattern/api-gateway.json -a ../calm/samples/api-gateway-architecture.json -f pretty -o ${targetOutputFile}`;
exec(exampleValidateCommand, (_error, _stdout, _stderr) => {
Expand All @@ -164,34 +152,31 @@ describe('CLI Integration Tests', () => {

//Some minor replacement logic to avoid issues with line endings
expect(outputString.replace(/\r\n/g, '\n')).toEqual(expectedOutput.replace(/\r\n/g, '\n'));
done();
});
});

test('example validate command - fails when neither an architecture or a pattern is provided', (done) => {
test('example validate command - fails when neither an architecture or a pattern is provided', async () => {
const calmValidateCommand = 'calm validate';
exec(calmValidateCommand, (error, _stdout, stderr) => {
expect(error).not.toBeNull();
expect(stderr).toContain('error: one of the required options \'-p, --pattern <file>\' or \'-a, --architecture <file>\' was not specified');
done();
});
});

test('example validate command - validates an architecture only', (done) => {
test('example validate command - validates an architecture only', async () => {
const calmValidateArchitectureOnlyCommand = 'calm validate -a ../calm/samples/api-gateway-architecture.json';
exec(calmValidateArchitectureOnlyCommand, (error, stdout, _stderr) => {
const expectedFilePath = path.join(__dirname, '../test_fixtures/validate_architecture_only_output.json');
const expectedOutput = fs.readFileSync(expectedFilePath, 'utf-8');
expect(error).toBeNull();
expect(stdout).toContain(expectedOutput);
done();
});
});

test('example server command - starts server and responds to requests', async () => {
// Mock the axios response
const mockResponse = { status: 200, data: { status: 'ok' } };
(axios.get as jest.Mock).mockResolvedValue(mockResponse);
(axios.get as vi.Mock).mockResolvedValue(mockResponse);

const serverCommand = 'calm server -p 3001 --schemaDirectory ../../dist/calm/';
const serverProcess = exec(serverCommand);
Expand All @@ -217,22 +202,21 @@ describe('CLI Integration Tests', () => {
const outputFile = path.join(outputDir, 'cli-e2e-output.html');

const templateCommand = `calm template --input ${testModelPath} --bundle ${templateBundlePath} --output ${outputDir} --url-to-local-file-mapping ${localDirectory}`;
await execPromise(templateCommand);
exec(templateCommand, (_stderr) => {

await new Promise(resolve => setTimeout(resolve, 2 * millisPerSecond));
expect(fs.existsSync(outputFile)).toBe(true);

expect(fs.existsSync(outputFile)).toBe(true);
if (fs.existsSync(outputFile)) {
const actualContent = fs.readFileSync(outputFile, 'utf8').trim();
const expectedContent = fs.readFileSync(expectedOutput, 'utf8').trim();

if (fs.existsSync(outputFile)) {
const actualContent = fs.readFileSync(outputFile, 'utf8').trim();
const expectedContent = fs.readFileSync(expectedOutput, 'utf8').trim();
expect(actualContent).toEqual(expectedContent);

expect(actualContent).toEqual(expectedContent);

if (fs.existsSync(outputDir)) {
fs.rmSync(outputDir, { recursive: true, force: true });
if (fs.existsSync(outputDir)) {
fs.rmSync(outputDir, {recursive: true, force: true});
}
}
}
});
});

test('example docify command - generates expected output', async () => {
Expand All @@ -252,13 +236,12 @@ describe('CLI Integration Tests', () => {

try {
const templateCommand = `calm docify --input ${testModelPath} --output ${outputDir} --url-to-local-file-mapping ${localDirectory}`;
await execPromise(templateCommand);

await new Promise(resolve => setTimeout(resolve, 2 * 1000));
exec(templateCommand, (_stderr) => {

for (const file of expectedFiles) {
expect(fs.existsSync(file)).toBeTruthy();
}
for (const file of expectedFiles) {
expect(fs.existsSync(file)).toBeTruthy();
}
});
} finally {
if (fs.existsSync(outputDir)) {
fs.rmSync(outputDir, { recursive: true, force: true });
Expand All @@ -268,7 +251,3 @@ describe('CLI Integration Tests', () => {


});

async function callNpxFunction(projectRoot: string, command: string) {
await execPromise(`npx ${command}`, { cwd: projectRoot });
}
Loading