93 lines
4.1 KiB
TypeScript
93 lines
4.1 KiB
TypeScript
import assert from "node:assert/strict";
|
|
import { existsSync, readFileSync } from "node:fs";
|
|
import path from "node:path";
|
|
import test from "node:test";
|
|
|
|
const source = (relativePath: string) => {
|
|
return readFileSync(path.join(process.cwd(), ...relativePath.split("/")), "utf8");
|
|
};
|
|
|
|
const fileExists = (relativePath: string) => {
|
|
return existsSync(path.join(process.cwd(), ...relativePath.split("/")));
|
|
};
|
|
|
|
test("Convex Workflow and Workpool dependencies and components are registered", () => {
|
|
const packageSource = source("package.json");
|
|
const configSource = source("convex/convex.config.ts");
|
|
|
|
assert.match(packageSource, /"@convex-dev\/workflow"/);
|
|
assert.match(packageSource, /"@convex-dev\/workpool"/);
|
|
assert.match(configSource, /from\s+["@']@convex-dev\/workflow\/convex\.config["@']/);
|
|
assert.match(configSource, /from\s+["@']@convex-dev\/workpool\/convex\.config["@']/);
|
|
assert.match(configSource, /app\.use\(workflow/);
|
|
assert.match(configSource, /app\.use\(auditWorkpool/);
|
|
});
|
|
|
|
test("audit workflow defines durable workflow manager with retrying workpool options", () => {
|
|
assert.equal(fileExists("convex/auditWorkflow.ts"), true);
|
|
const workflowSource = source("convex/auditWorkflow.ts");
|
|
|
|
assert.match(workflowSource, /WorkflowManager/);
|
|
assert.match(workflowSource, /components\.workflow/);
|
|
assert.match(workflowSource, /workpoolOptions/);
|
|
assert.match(workflowSource, /maxParallelism:\s*3/);
|
|
assert.match(workflowSource, /retryActionsByDefault:\s*true/);
|
|
assert.match(workflowSource, /maxAttempts:\s*3/);
|
|
assert.match(workflowSource, /initialBackoffMs:\s*1000/);
|
|
assert.match(workflowSource, /base:\s*2/);
|
|
assert.match(workflowSource, /step\.runAction/);
|
|
assert.match(workflowSource, /step\.runMutation/);
|
|
assert.match(workflowSource, /Promise\.all/);
|
|
});
|
|
|
|
test("requestLeadAudit creates a visible agentRun and starts the workflow", () => {
|
|
const pageSpeedSource = source("convex/pageSpeed.ts");
|
|
|
|
assert.match(pageSpeedSource, /internal\.auditWorkflow\.startLeadAuditWorkflow/);
|
|
assert.match(pageSpeedSource, /type:\s*"audit"/);
|
|
assert.match(pageSpeedSource, /progressLabel:\s*"Audit vorbereitet"/);
|
|
assert.match(pageSpeedSource, /workflowId/);
|
|
});
|
|
|
|
test("workflow PageSpeed start accepts root runs already marked running", () => {
|
|
const pageSpeedSource = source("convex/pageSpeed.ts");
|
|
|
|
assert.match(
|
|
pageSpeedSource,
|
|
/run\.status\s*!==\s*"pending"[\s\S]*run\.status\s*!==\s*"failed"[\s\S]*run\.status\s*!==\s*"running"/,
|
|
);
|
|
});
|
|
|
|
test("workflow failure progress stays on the failing step instead of jumping to quality review", () => {
|
|
const workflowSource = source("convex/auditWorkflow.ts");
|
|
const catchIndex = workflowSource.indexOf("} catch (error)");
|
|
assert.notEqual(catchIndex, -1, "Expected workflow catch block.");
|
|
const nextExportIndex = workflowSource.indexOf("export const startLeadAuditWorkflow", catchIndex);
|
|
assert.notEqual(nextExportIndex, -1, "Expected workflow catch block end.");
|
|
const catchSource = workflowSource.slice(catchIndex, nextExportIndex);
|
|
|
|
assert.doesNotMatch(catchSource, /progressPatch\(args\.runId,\s*"qualityReview"\)/);
|
|
assert.doesNotMatch(catchSource, /progressStep|progressTotal|progressLabel|progressPercent/);
|
|
assert.match(catchSource, /status:\s*"failed"/);
|
|
});
|
|
|
|
test("audit dashboard query includes root audit runs and exposes progress and retry fields", () => {
|
|
const auditsSource = source("convex/audits.ts");
|
|
|
|
assert.match(auditsSource, /\.eq\("type",\s*"audit"\)/);
|
|
assert.match(auditsSource, /kind:\s*"generation"/);
|
|
assert.match(auditsSource, /runType/);
|
|
assert.match(auditsSource, /progress:/);
|
|
assert.match(auditsSource, /retry:/);
|
|
assert.match(auditsSource, /canRetry/);
|
|
});
|
|
|
|
test("audit retry mutation restarts final failed or canceled runs through workflow", () => {
|
|
const auditsSource = source("convex/audits.ts");
|
|
|
|
assert.match(auditsSource, /export const retryAuditRun = mutation/);
|
|
assert.match(auditsSource, /requireOperator\(ctx\)/);
|
|
assert.match(auditsSource, /status !== "failed"[\s\S]*status !== "canceled"/);
|
|
assert.match(auditsSource, /internal\.auditWorkflow\.restartAuditWorkflow/);
|
|
});
|