Files
Jyotisha/frontend/tests/report-candidate-range.test.ts
T
Jesse_Chen 7baf230066 fix(report): load candidate ranges through a read-only RPC
Accepted profiles were selecting a revoked rectification table and failing the report before the engine ran. Degrade to a null window when that optional read fails.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-04 19:17:14 +08:00

149 lines
4.4 KiB
TypeScript

import assert from "node:assert/strict";
import { readFileSync } from "node:fs";
import test from "node:test";
import {
READ_REPORT_CANDIDATE_RANGE_RPC,
loadReportCandidateRange,
parseReportCandidateRange,
reportCandidateRangeErrorCode,
} from "../src/lib/report-candidate-range.ts";
import {
resolveReportBirthTimeSensitivityInput,
} from "../src/lib/personal-report-route-core.ts";
import { REPORT_STABLE_CODES } from "../src/lib/personal-report-codes.ts";
const workerSource = readFileSync(
new URL("../src/lib/personal-report-worker.ts", import.meta.url),
"utf8",
);
const createRoute = readFileSync(
new URL("../src/app/api/reports/route.ts", import.meta.url),
"utf8",
);
const helperSource = readFileSync(
new URL("../src/lib/report-candidate-range.ts", import.meta.url),
"utf8",
);
function capturingWarn() {
const reasons: string[] = [];
return {
reasons,
warn: (payload: { event: "report_candidate_range_unavailable"; reason: string }) => {
reasons.push(payload.reason);
},
};
}
test("permission denied, thrown errors, and empty rows all degrade to a null window", async () => {
const denied = capturingWarn();
assert.equal(
await loadReportCandidateRange(
{
rpc: async () => ({
data: null,
error: { code: "42501", message: "permission denied for table agentic_rectification_cases" },
}),
},
{ userId: "11111111-1111-4111-8111-111111111111" },
denied.warn,
),
null,
);
assert.deepEqual(denied.reasons, ["42501"]);
const thrown = capturingWarn();
assert.equal(
await loadReportCandidateRange(
{
rpc: async () => {
throw new TypeError("rpc exploded");
},
},
{ userId: "11111111-1111-4111-8111-111111111111" },
thrown.warn,
),
null,
);
assert.deepEqual(thrown.reasons, ["TypeError"]);
const empty = capturingWarn();
assert.equal(
await loadReportCandidateRange(
{ rpc: async () => ({ data: null, error: null }) },
{ userId: "11111111-1111-4111-8111-111111111111" },
empty.warn,
),
null,
);
assert.deepEqual(empty.reasons, []);
});
test("a valid RPC window is returned and extra columns are ignored", async () => {
const log = capturingWarn();
assert.deepEqual(
await loadReportCandidateRange(
{
rpc: async (fn, args) => {
assert.equal(fn, READ_REPORT_CANDIDATE_RANGE_RPC);
assert.equal(args.p_user_id, "11111111-1111-4111-8111-111111111111");
assert.equal(args.p_rectification_case_id, "22222222-2222-4222-8222-222222222222");
return {
data: {
start_time: "10:00:00",
end_time: "10:04:00",
user_id: "must-not-leak",
candidate_range: { secret: true },
},
error: null,
};
},
},
{
userId: "11111111-1111-4111-8111-111111111111",
rectificationCaseId: "22222222-2222-4222-8222-222222222222",
},
log.warn,
),
{ startTime: "10:00", endTime: "10:04" },
);
assert.deepEqual(log.reasons, []);
});
test("degraded candidate windows keep report sensitivity input unwindowed", () => {
const input = resolveReportBirthTimeSensitivityInput(
{},
"accepted",
"10:30",
null,
);
assert.equal(input.birth_time_accuracy, "provisional");
assert.equal("candidate_range" in input, false);
assert.equal(REPORT_STABLE_CODES.calculationUnavailable, "calculation_unavailable");
});
test("error codes never include messages or birth content", () => {
assert.equal(
reportCandidateRangeErrorCode({
code: "42501",
message: "permission denied for table agentic_rectification_cases",
}),
"42501",
);
assert.equal(parseReportCandidateRange({ start_time: "25:00", end_time: "10:00" }), null);
assert.doesNotMatch(helperSource, /error\.message|details|hint/);
});
test("worker and create route read candidate windows only through the shared RPC helper", () => {
for (const source of [workerSource, createRoute]) {
assert.match(source, /loadReportCandidateRange/);
assert.doesNotMatch(source, /from\("agentic_rectification_cases"\)/);
assert.doesNotMatch(source, /from\("birth_time_rectification_cases"\)/);
assert.doesNotMatch(source, /\.in\("status", \["confirmed", "completed"\]\)/);
}
assert.doesNotMatch(
workerSource,
/loadReportCandidateRange[\s\S]{0,400}calculation_unavailable/,
);
});