UNPKG

@ehmpathy/as-command

Version:

easily create commands within a pit-of-success

293 lines 17 kB
"use strict"; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; Object.defineProperty(exports, "__esModule", { value: true }); const node_fs_1 = require("node:fs"); const promises_1 = require("node:fs/promises"); const node_path_1 = require("node:path"); const test_fns_1 = require("test-fns"); const asCommand_1 = require("./asCommand"); describe('asCommand (integration)', () => { const testDir = (0, node_path_1.resolve)(__dirname, '.temp/asCommand'); (0, test_fns_1.given)('a command created with asCommand', () => { const realLog = { debug: (message, metadata) => { console.debug(message, metadata); }, info: (message, metadata) => { console.info(message, metadata); }, warn: (message, metadata) => { console.warn(message, metadata); }, error: (message, metadata) => { console.error(message, metadata); }, }; (0, test_fns_1.when)('invoked with input', () => { (0, test_fns_1.then)('it should execute the logic and persist logs and outputs to disk', () => __awaiter(void 0, void 0, void 0, function* () { // Create a simple command const testCommand = (0, asCommand_1.asCommand)({ name: 'double-value', purpose: 'doubles a number', stage: 'test', log: realLog, dir: testDir, }, (input, context) => __awaiter(void 0, void 0, void 0, function* () { context.log.info('processing', { input }); return { doubled: input.value * 2 }; })); // Execute the command const result = yield testCommand({ value: 21 }); // Verify the result expect(result).toEqual({ doubled: 42 }); // Verify directory structure was created const commandDir = `${testDir}/__tmp__/test/double-value`; expect((0, node_fs_1.existsSync)(commandDir)).toBe(true); // Find the run directory const runDirs = yield (0, promises_1.readdir)(commandDir); expect(runDirs.length).toBeGreaterThan(0); const runDir = `${commandDir}/${runDirs[0]}`; const logFilePath = `${runDir}/log.json`; const outFilePath = `${runDir}/out.json`; expect((0, node_fs_1.existsSync)(logFilePath)).toBe(true); expect((0, node_fs_1.existsSync)(outFilePath)).toBe(true); // Read and verify log file contents const logContents = yield (0, promises_1.readFile)(logFilePath, 'utf-8'); expect(logContents).toContain('"level": "info"'); expect(logContents).toContain('"message": "input"'); expect(logContents).toContain('"value": 21'); expect(logContents).toContain('"message": "processing"'); expect(logContents).toContain('"message": "output.result"'); expect(logContents).toContain('"doubled": 42'); // Read and verify output file contents const outContents = yield (0, promises_1.readFile)(outFilePath, 'utf-8'); const output = JSON.parse(outContents); expect(output).toEqual({ doubled: 42 }); })); }); (0, test_fns_1.when)('the logic uses context.out.write', () => { (0, test_fns_1.then)('it should write custom output files to disk', () => __awaiter(void 0, void 0, void 0, function* () { const testCommand = (0, asCommand_1.asCommand)({ name: 'greet-user', purpose: 'greets a user', stage: 'test', log: realLog, dir: testDir, }, (input, context) => __awaiter(void 0, void 0, void 0, function* () { // Write a custom file using context.out.write const csvData = `name,greeting\n${input.name},Hello ${input.name}!`; const result = yield context.out.write({ name: 'greeting.csv', data: csvData, }); context.log.info('wrote csv file', { path: result.path }); return { message: `Greeted ${input.name}` }; })); const result = yield testCommand({ name: 'Alice' }); expect(result).toEqual({ message: 'Greeted Alice' }); // Verify custom output file was created const commandDir = `${testDir}/__tmp__/test/greet-user`; const runDirs = yield (0, promises_1.readdir)(commandDir); const runDir = `${commandDir}/${runDirs[0]}`; const csvFilePath = `${runDir}/greeting.csv`; expect((0, node_fs_1.existsSync)(csvFilePath)).toBe(true); const csvContents = yield (0, promises_1.readFile)(csvFilePath, 'utf-8'); expect(csvContents).toContain('name,greeting'); expect(csvContents).toContain('Alice,Hello Alice!'); })); }); (0, test_fns_1.when)('the logic uses context.out.write with nested directories', () => { (0, test_fns_1.then)('it should create nested directories and write the file', () => __awaiter(void 0, void 0, void 0, function* () { const testCommand = (0, asCommand_1.asCommand)({ name: 'nested-output', purpose: 'writes to nested directories', stage: 'test', log: realLog, dir: testDir, }, (input, context) => __awaiter(void 0, void 0, void 0, function* () { // Write a file to a nested path that doesn't exist yet const result = yield context.out.write({ name: 'reports/analytics/data.json', data: JSON.stringify({ value: input.data }, null, 2), }); context.log.info('wrote nested file', { path: result.path }); return { saved: true }; })); const result = yield testCommand({ data: 'test-data' }); expect(result).toEqual({ saved: true }); // Verify the file was created in the nested directory const commandDir = `${testDir}/__tmp__/test/nested-output`; const runDirs = yield (0, promises_1.readdir)(commandDir); const runDir = `${commandDir}/${runDirs[0]}`; const nestedFilePath = `${runDir}/reports/analytics/data.json`; expect((0, node_fs_1.existsSync)(nestedFilePath)).toBe(true); const fileContents = yield (0, promises_1.readFile)(nestedFilePath, 'utf-8'); const parsed = JSON.parse(fileContents); expect(parsed).toEqual({ value: 'test-data' }); })); }); (0, test_fns_1.when)('the logic throws an error', () => { (0, test_fns_1.then)('it should log the error and rethrow it', () => __awaiter(void 0, void 0, void 0, function* () { const testCommand = (0, asCommand_1.asCommand)({ name: 'failing-command', purpose: 'intentionally fails', stage: 'test', log: realLog, dir: testDir, }, (input) => __awaiter(void 0, void 0, void 0, function* () { if (input.shouldFail) { throw new Error('Intentional failure'); } throw new Error('Should not reach here'); })); // Execute and expect error const error = yield (0, test_fns_1.getError)(() => testCommand({ shouldFail: true })); expect(error === null || error === void 0 ? void 0 : error.message).toContain('Intentional failure'); // Verify error was logged to file const commandDir = `${testDir}/__tmp__/test/failing-command`; const runDirs = yield (0, promises_1.readdir)(commandDir); const runDir = `${commandDir}/${runDirs[0]}`; const logFilePath = `${runDir}/log.json`; expect((0, node_fs_1.existsSync)(logFilePath)).toBe(true); const logContents = yield (0, promises_1.readFile)(logFilePath, 'utf-8'); expect(logContents).toContain('"level": "error"'); expect(logContents).toContain('"message": "output.error"'); expect(logContents).toContain('Intentional failure'); })); }); (0, test_fns_1.when)('invoked multiple times with same input', () => { (0, test_fns_1.then)('it should create separate log files with same input hash but different timestamps', () => __awaiter(void 0, void 0, void 0, function* () { const testCommand = (0, asCommand_1.asCommand)({ name: 'echo-command', purpose: 'echoes input', stage: 'test', log: realLog, dir: testDir, }, (input) => __awaiter(void 0, void 0, void 0, function* () { // Add small delay to ensure different timestamps yield new Promise((resolveTimer) => setTimeout(resolveTimer, 1100)); return { result: input.value }; })); // Execute twice with same input yield testCommand({ value: 'test' }); yield testCommand({ value: 'test' }); // Verify multiple run directories exist const commandDir = `${testDir}/__tmp__/test/echo-command`; const runDirs = yield (0, promises_1.readdir)(commandDir); expect(runDirs.length).toBeGreaterThanOrEqual(2); // Verify directories have same hash but different timestamps const hashes = runDirs.map((d) => d.split('.')[2]); const timestamps = runDirs.map((d) => d.split('.').slice(0, 2).join('.')); expect(hashes[0]).toBe(hashes[1]); // Same input hash expect(timestamps[0]).not.toBe(timestamps[1]); // Different timestamps })); }); (0, test_fns_1.when)('invoked with different inputs', () => { (0, test_fns_1.then)('it should create files with different input hashes', () => __awaiter(void 0, void 0, void 0, function* () { const testCommand = (0, asCommand_1.asCommand)({ name: 'process-id', purpose: 'processes an id', stage: 'test', log: realLog, dir: testDir, }, () => __awaiter(void 0, void 0, void 0, function* () { return { processed: true }; })); // Execute with different inputs yield testCommand({ id: 1 }); yield testCommand({ id: 2 }); // Verify run directories have different hashes const commandDir = `${testDir}/__tmp__/test/process-id`; const runDirs = yield (0, promises_1.readdir)(commandDir); expect(runDirs.length).toBeGreaterThanOrEqual(2); const hashes = runDirs.map((d) => d.split('.')[2]); expect(hashes[0]).not.toBe(hashes[1]); // Different input hashes })); }); (0, test_fns_1.when)('the logic uses all log levels', () => { (0, test_fns_1.then)('it should persist all log levels to the log file', () => __awaiter(void 0, void 0, void 0, function* () { const testCommand = (0, asCommand_1.asCommand)({ name: 'all-log-levels', purpose: 'tests all log levels', stage: 'test', log: realLog, dir: testDir, }, (_input, context) => __awaiter(void 0, void 0, void 0, function* () { context.log.debug('debug message', { level: 'debug' }); context.log.info('info message', { level: 'info' }); context.log.warn('warn message', { level: 'warn' }); context.log.error('error message', { level: 'error' }); return { complete: true }; })); yield testCommand({}); const commandDir = `${testDir}/__tmp__/test/all-log-levels`; const runDirs = yield (0, promises_1.readdir)(commandDir); const runDir = `${commandDir}/${runDirs[0]}`; const logFilePath = `${runDir}/log.json`; expect((0, node_fs_1.existsSync)(logFilePath)).toBe(true); const logContents = yield (0, promises_1.readFile)(logFilePath, 'utf-8'); expect(logContents).toContain('"level": "debug"'); expect(logContents).toContain('"message": "debug message"'); expect(logContents).toContain('"level": "info"'); expect(logContents).toContain('"message": "info message"'); expect(logContents).toContain('"level": "warn"'); expect(logContents).toContain('"message": "warn message"'); expect(logContents).toContain('"level": "error"'); expect(logContents).toContain('"message": "error message"'); })); }); (0, test_fns_1.when)('the logic returns a string', () => { (0, test_fns_1.then)('it should persist the string directly to the output file', () => __awaiter(void 0, void 0, void 0, function* () { const testCommand = (0, asCommand_1.asCommand)({ name: 'return-string', purpose: 'returns a string', stage: 'test', log: realLog, dir: testDir, }, (input) => __awaiter(void 0, void 0, void 0, function* () { return `Hello, ${input.name}!`; })); const result = yield testCommand({ name: 'World' }); expect(result).toBe('Hello, World!'); const commandDir = `${testDir}/__tmp__/test/return-string`; const runDirs = yield (0, promises_1.readdir)(commandDir); const runDir = `${commandDir}/${runDirs[0]}`; const outFilePath = `${runDir}/out.json`; expect((0, node_fs_1.existsSync)(outFilePath)).toBe(true); const outContents = yield (0, promises_1.readFile)(outFilePath, 'utf-8'); expect(outContents).toBe('Hello, World!'); })); }); (0, test_fns_1.when)('the logic returns undefined', () => { (0, test_fns_1.then)('it should persist "undefined" to the output file', () => __awaiter(void 0, void 0, void 0, function* () { const testCommand = (0, asCommand_1.asCommand)({ name: 'return-undefined', purpose: 'returns undefined', stage: 'test', log: realLog, dir: testDir, }, () => __awaiter(void 0, void 0, void 0, function* () { return undefined; })); const result = yield testCommand({}); expect(result).toBeUndefined(); const commandDir = `${testDir}/__tmp__/test/return-undefined`; const runDirs = yield (0, promises_1.readdir)(commandDir); const runDir = `${commandDir}/${runDirs[0]}`; const outFilePath = `${runDir}/out.json`; expect((0, node_fs_1.existsSync)(outFilePath)).toBe(true); const outContents = yield (0, promises_1.readFile)(outFilePath, 'utf-8'); expect(outContents).toBe('undefined'); })); }); }); }); //# sourceMappingURL=asCommand.integration.test.js.map