Files
Codeman/test/cron-docs.test.ts
T

57 lines
2.8 KiB
TypeScript

/** @fileoverview Guards cron docs against drift from routes, schema, statuses, and UI entry points. */
import { readFileSync } from 'node:fs';
import { describe, expect, it } from 'vitest';
import { CronJobSchema } from '../src/web/schemas.js';
const read = (path: string) => readFileSync(new URL(`../${path}`, import.meta.url), 'utf8');
const reference = read('docs/api-reference.md');
const wiki = read('docs/wiki/HTTP-API.md');
const guide = read('docs/wiki/Cron-Jobs.md');
const cronSection = (text: string) => text.split('## Cron jobs\n')[1]?.split('\n## ')[0] ?? '';
describe('cron documentation', () => {
it('documents every cron route in both API references', () => {
const routes = [...read('src/web/routes/cron-routes.ts').matchAll(/app\.(get|post|put|delete)\('([^']+)'/g)];
expect(routes).toHaveLength(9);
for (const [, method, path] of routes) {
const row = `| ${method.toUpperCase()} | \`${path.replace('/api/', '/api/v1/')}\` |`;
expect(cronSection(reference)).toContain(row);
expect(cronSection(wiki)).toContain(row);
}
});
it('documents every accepted job field and validates the guide example', () => {
for (const field of Object.keys(CronJobSchema.shape)) {
expect(cronSection(reference)).toContain(`| \`${field}\` |`);
}
const example = guide.match(/-d '(\{[\s\S]*?\})'/)?.[1];
expect(example).toBeDefined();
expect(CronJobSchema.safeParse(JSON.parse(example!)).success).toBe(true);
});
it('documents all run statuses without treating prompt delivery as task success', () => {
const statusType = read('src/types/cron.ts').match(/export type CronJobRunStatus = ([^;]+);/)?.[1];
expect(statusType).toBeDefined();
for (const [, status] of statusType!.matchAll(/'([^']+)'/g)) {
expect(guide).toContain(`| \`${status}\``);
expect(cronSection(reference)).toContain(`\`${status}\``);
}
expect(guide.replace(/\s+/g, ' ')).toContain("not whether the agent's task succeeded");
expect(guide).toContain('bottom toolbar');
expect(guide).toContain('App Settings → Header & Panels → Scheduling');
});
it('keeps linked pages consistent and explains non-terminal launch history', () => {
expect(read('docs/wiki/The-Dashboard.md')).toMatch(/\| Cron\s*\| Bottom toolbar/);
expect(read('docs/cron-guide.md')).not.toMatch(/Cron\*\* (?:button )?in the header/);
for (const text of [reference, guide]) {
const normalized = text.replace(/\s+/g, ' ');
expect(normalized).toContain('session is closed during the readiness wait');
expect(normalized).toContain('server restarts before delivery');
expect(normalized).toContain('`session_started` indefinitely with `finishedAt: null`');
}
expect(reference).toContain("also closes the previous run's session before launching");
});
});