UNPKG

@agentled/cli

Version:

CLI for Agentled — manage workflows, apps, and knowledge from the command line. Zero context-window cost for AI agents.

98 lines 4.4 kB
/** * `agentled test <workflowId>` — run declarative test assertions. * * Default mode: zero-credit replay against captured fixtures (fixtures/ * step-outputs/). Use `--live` to call testAiAction / testAppAction / * testCodeAction (costs credits for AI/app steps; code is always free). * * Test file format: tests/<workflowId>.test.json * Generate one with `agentled workflows pull <workflowId>`. * * Assertion verbs: hasKey, isType, equals, matches, inRange, hasLength, contains * (see utils/test-runner.ts for full schema) */ import { existsSync, readFileSync } from 'node:fs'; import { join, resolve } from 'node:path'; import { AgentledClient } from '../client.js'; import { printOutput, printError } from '../utils/output.js'; import { findWorkspaceDir } from '../utils/workspace-folder.js'; import { runStepFixture, runStepLive } from '../utils/test-runner.js'; export function registerTestCommand(program) { program .command('test <workflowId>') .description('Run declarative test assertions against captured fixtures (zero credits) or live API calls (--live).') .option('--live', 'Use live API calls (costs credits for AI/app steps)', false) .option('--step <stepId>', 'Run assertions for a single step only') .option('--format <fmt>', 'Output format', 'json') .action(async (workflowId, opts) => { try { const wsDir = findWorkspaceDir(); const candidates = []; if (wsDir) candidates.push(join(wsDir, 'tests', `${workflowId}.test.json`)); candidates.push(resolve(`tests/${workflowId}.test.json`), resolve(`${workflowId}.test.json`)); const testFilePath = candidates.find(existsSync); if (!testFilePath) { printError(`Test file not found for workflow ${workflowId}. Expected: tests/${workflowId}.test.json. Run "agentled workflows pull ${workflowId}" to generate a skeleton.`); return; } let testFile; try { testFile = JSON.parse(readFileSync(testFilePath, 'utf-8')); } catch (err) { printError(`Failed to parse test file: ${err instanceof Error ? err.message : String(err)}`); return; } let stepsToRun = testFile.steps ?? []; if (opts.step) { stepsToRun = stepsToRun.filter((s) => s.stepId === opts.step); if (stepsToRun.length === 0) { printError(`Step "${opts.step}" not found in test file.`); return; } } const client = opts.live ? new AgentledClient() : null; const results = []; for (const step of stepsToRun) { if (step.skip) { results.push({ stepId: step.stepId, description: step.description, mode: 'skipped', passed: 0, failed: 0, skipped: step.assertions.length, errors: ['Skipped (skip: true)'], }); continue; } const result = opts.live && client ? await runStepLive(step, client) : runStepFixture(step, wsDir); results.push(result); } const summary = { totalPassed: results.reduce((a, r) => a + r.passed, 0), totalFailed: results.reduce((a, r) => a + r.failed, 0), totalSkipped: results.reduce((a, r) => a + r.skipped, 0), stepsFailed: results.filter((r) => r.failed > 0).length, stepsSkipped: results.filter((r) => r.mode === 'skipped').length, }; printOutput({ workflowId, workflowName: testFile.workflowName, mode: opts.live ? 'live' : 'fixture', testFilePath, summary, results, }, (opts.format ?? 'json')); if (summary.totalFailed > 0) process.exitCode = 1; } catch (e) { printError(e instanceof Error ? e.message : String(e)); } }); } //# sourceMappingURL=test.js.map