Files
content-factory/apps/frontend/tests/article_detail.model.test.mjs
T

136 lines
4.3 KiB
JavaScript

import assert from "node:assert/strict";
import { readFileSync } from "node:fs";
import path from "node:path";
import { fileURLToPath } from "node:url";
import ts from "typescript";
const testDir = path.dirname(fileURLToPath(import.meta.url));
const sourcePath = path.resolve(testDir, "../src/features/article-detail/model.ts");
const source = readFileSync(sourcePath, "utf8");
const compiled = ts.transpileModule(source, {
compilerOptions: { module: ts.ModuleKind.CommonJS, target: ts.ScriptTarget.ES2022 },
});
const moduleExports = {};
new Function("exports", compiled.outputText)(moduleExports);
const { buildArticleTimeline, buildJobDetailRows, buildDetailSummary, buildJobControlState } = moduleExports;
const detail = {
article: {
id: "a1",
target_site_id: "site1",
status: "PARALLEL_PRODUCTION_RUNNING",
publishing_status: "PUBLISH_NOT_STARTED",
brief_description: "desc",
language: "en",
content_type: "longform_guide",
created_at: "2026-05-21T00:00:00Z",
updated_at: "2026-05-21T00:00:00Z",
},
target_site: { name: "Demo Site" },
timeline: [
{
id: "2",
article_id: "a1",
entry_type: "AGENT_JOB",
source: "AGENT",
event_type: "SECTION_SCAFFOLD_FAILED",
from_status: null,
to_status: null,
actor_user_id: null,
job_id: "job2",
job_type: "SECTION_SCAFFOLD",
job_status: "FAILED",
retry_eligible: true,
cancel_eligible: false,
safe_failure_summary: "Section failed.",
payload: {},
created_at: "2026-05-21T00:00:02Z",
},
{
id: "1",
article_id: "a1",
entry_type: "WORKFLOW_EVENT",
source: "USER",
event_type: "PLAN_APPROVED",
from_status: "PLAN_REVIEW_REQUIRED",
to_status: "RESEARCH_RUNNING",
actor_user_id: "u1",
job_id: null,
job_type: null,
job_status: null,
retry_eligible: false,
cancel_eligible: false,
safe_failure_summary: null,
payload: {},
created_at: "2026-05-21T00:00:01Z",
},
],
workflow_events: [],
agent_jobs: [
{
id: "job2",
article_id: "a1",
parent_job_id: null,
attempt: 1,
job_type: "SECTION_SCAFFOLD",
agent_profile: "fake-section-scaffold",
status: "FAILED",
workspace_path: null,
input_files: [],
output_files: [],
payload: { last_successful_step: "Outline written" },
error_category: "UNSUPPORTED_CLAIMS_FOUND",
error_message: "Unsupported claims introduced during scaffolding: 1",
stdout: "token=[REDACTED]",
stderr: "",
exit_code: 1,
duration_ms: 5,
queued_at: "2026-05-21T00:00:00Z",
started_at: "2026-05-21T00:00:01Z",
finished_at: "2026-05-21T00:00:02Z",
retry_eligible: true,
retry_block_reason: null,
cancel_eligible: false,
safe_failure_summary: "Section failed safely.",
},
],
publish_commit: null,
};
const timeline = buildArticleTimeline(detail);
assert.equal(timeline.length, 2);
assert.equal(timeline[0].eventType, "PLAN_APPROVED");
assert.equal(timeline[1].eventType, "SECTION_SCAFFOLD_FAILED");
assert.equal(timeline[1].source, "AGENT");
assert.equal(timeline[1].retryEligible, true);
const jobRows = buildJobDetailRows(detail.agent_jobs);
assert.equal(jobRows.length, 1);
assert.equal(jobRows[0].jobType, "SECTION_SCAFFOLD");
assert.equal(jobRows[0].status, "FAILED");
assert.equal(jobRows[0].errorCategory, "UNSUPPORTED_CLAIMS_FOUND");
assert.equal(jobRows[0].errorMessage, "Unsupported claims introduced during scaffolding: 1");
assert.equal(jobRows[0].lastSuccessfulStep, "Outline written");
assert.equal(jobRows[0].retryEligible, true);
assert.deepEqual(
buildJobControlState(jobRows[0], "ADMIN"),
{ showRetry: true, showCancel: false, showAdminLogs: true, showSafeSummary: false },
);
assert.deepEqual(
buildJobControlState(jobRows[0], "EDITOR"),
{ showRetry: false, showCancel: false, showAdminLogs: false, showSafeSummary: true },
);
const summary = buildDetailSummary(detail, {
viewerRole: "EDITOR",
viewerEmail: "editor@example.com",
});
assert.equal(summary.viewerRole, "EDITOR");
assert.equal(summary.viewerEmail, "editor@example.com");
assert.equal(summary.targetSite, "Demo Site");
assert.equal(summary.timeline.length, 2);
assert.equal(summary.jobDetails.length, 1);