Files
Jyotisha/frontend/tests/professional-report-reference-route.test.ts
T
Jesse_Chen cfcd369d4f feat(report): render longform Markdown as the report and close gaps2 holes
New reports skip the writer, persist pl9 Markdown as the body, and settle zero-token usage on the catalog model. Planned longform sections now emit blocked rows instead of vanishing.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-06 21:46:16 +08:00

147 lines
6.0 KiB
TypeScript

import assert from "node:assert/strict";
import { spawnSync } from "node:child_process";
import { readFileSync } from "node:fs";
import { fileURLToPath } from "node:url";
import test from "node:test";
const routeSource = readFileSync(
new URL("../src/app/api/reports/[reportId]/professional-reference/route.ts", import.meta.url),
"utf8",
);
const frontendRoot = fileURLToPath(new URL("../", import.meta.url));
function executeReadyReportExport(cached: boolean) {
const script = String.raw`
import { mock } from "node:test";
import { pathToFileURL } from "node:url";
import { Agent } from "@mastra/core/agent";
const moduleUrl = (path) => pathToFileURL(process.cwd() + "/" + path).href;
const cached = ${cached ? "true" : "false"};
mock.module("@/lib/personal-report-entitlement", { namedExports: {
checkSameOrigin: () => ({ ok: true }),
resolveAllowedReportOrigins: () => [],
}});
mock.module("@/lib/personal-report-service", { namedExports: {
createSupabasePersonalReportService: () => ({
getOwnedById: async () => ({ status: "ready", requestId: "123e4567-e89b-12d3-a456-426614174111" }),
}),
}});
mock.module("@/lib/personal-report-longform-appendix", { namedExports: {
LONGFORM_APPENDIX_TABLE: "personal_report_longform_appendices",
parseLongformAppendixRow: () => cached
? { status: "ready", markdown: "# Professional reference" }
: null,
nextLongformAppendixState: () => ({ status: "ready", attemptCount: 0, markdown: "# Professional reference", contentSha256: "ab", lastErrorCode: null }),
}});
mock.module("@/lib/personal-report-longform-copy", { namedExports: {
PERSONAL_REPORT_LEGACY_PLACEHOLDER: "旧版本报告,请重新生成",
}});
mock.module("@/lib/supabase/config", { namedExports: {
isSupabaseConfigurationError: () => false,
}});
mock.module("@/lib/supabase/server", { namedExports: {
createServerSupabaseClient: async () => ({
auth: { getUser: async () => ({ data: { user: { id: "user-1" } }, error: null }) },
from: () => ({
select() { return this; },
eq() { return this; },
async maybeSingle() { return { data: cached ? { markdown: "# Professional reference" } : null, error: null }; },
}),
}),
}});
let modelCalls = 0;
Agent.prototype.generate = async () => {
modelCalls += 1;
throw new Error("professional export must not call a model");
};
let telemetryEvents = 0;
console.info = (...args) => {
if (args[0] === "[personal-report-agent]") telemetryEvents += 1;
};
const upstream = [];
globalThis.fetch = async (input, init) => {
upstream.push({ url: String(input), method: init?.method });
throw new Error("cache-only export must not call the engine");
};
const { POST } = await import(moduleUrl("src/app/api/reports/[reportId]/professional-reference/route.ts"));
const response = await POST(
new Request("https://staging.jyotisha.chat/api/reports/123e4567-e89b-12d3-a456-426614174000/professional-reference", {
method: "POST",
headers: { origin: "https://staging.jyotisha.chat" },
}),
{ params: Promise.resolve({ reportId: "123e4567-e89b-12d3-a456-426614174000" }) },
);
console.log(JSON.stringify({
status: response.status,
body: await response.json(),
modelCalls,
telemetryEvents,
upstream,
}));
`;
const result = spawnSync(process.execPath, [
"--experimental-test-module-mocks",
"--import",
"tsx",
"--input-type=module",
"--eval",
script,
], { cwd: frontendRoot, encoding: "utf8" });
assert.equal(result.status, 0, result.stderr || result.stdout);
return JSON.parse(result.stdout.trim()) as {
status: number;
body: Record<string, unknown>;
modelCalls: number;
telemetryEvents: number;
upstream: Array<{ url: string; method: string }>;
};
}
test("professional reference route authenticates, checks origin, owner and ready status", () => {
assert.match(routeSource, /createServerSupabaseClient/);
assert.match(routeSource, /supabase\.auth\.getUser\(\)/);
assert.match(routeSource, /checkSameOrigin/);
assert.match(routeSource, /resolveAllowedReportOrigins/);
assert.match(routeSource, /getOwnedById\(user\.id, reportId\)/);
assert.match(routeSource, /report\.status !== "ready"/);
assert.match(routeSource, /status: 401/);
assert.match(routeSource, /status: 403/);
assert.match(routeSource, /status: 404/);
assert.match(routeSource, /status: 409/);
assert.match(routeSource, /status: 410/);
});
test("ready export is cache-only and never calls the writer or Python engine", () => {
assert.match(routeSource, /LONGFORM_APPENDIX_TABLE/);
assert.match(routeSource, /from "@\/lib\/personal-report-longform-appendix"/);
assert.match(routeSource, /PERSONAL_REPORT_LEGACY_PLACEHOLDER/);
assert.doesNotMatch(routeSource, /request\.json\(/);
assert.doesNotMatch(routeSource, /mastra|writer|billing|personal_report_sections/i);
assert.doesNotMatch(routeSource, /from\("personal_reports"\)/);
assert.doesNotMatch(routeSource, /\/api\/professional_report_reference/);
assert.doesNotMatch(routeSource, /\.from\("profiles"\)/);
assert.doesNotMatch(routeSource, /loadReportCandidateRange/);
});
test("cached appendix returns markdown without model or engine calls", () => {
const result = executeReadyReportExport(true);
assert.equal(result.status, 200);
assert.deepEqual(result.body, { format: "markdown", markdown: "# Professional reference" });
assert.equal(result.modelCalls, 0);
assert.equal(result.telemetryEvents, 0);
assert.equal(result.upstream.length, 0);
});
test("missing appendix is a retired report, not an on-demand generation", () => {
const result = executeReadyReportExport(false);
assert.equal(result.status, 410);
assert.equal(result.body.error, "旧版本报告,请重新生成");
assert.equal(result.body.code, "legacy_report");
assert.equal(result.modelCalls, 0);
assert.equal(result.upstream.length, 0);
});