Chart, ephemeris, reports, daily language, consult, and synastry read birth data only through resolveSubjectBirth. The current person is a request parameter outside Home(). /people replaces the settings chart pane, and deleting someone removes that person's chats and reports.
137 lines
4.5 KiB
TypeScript
137 lines
4.5 KiB
TypeScript
import assert from "node:assert/strict";
|
|
import { readFileSync } from "node:fs";
|
|
import test from "node:test";
|
|
|
|
import { resolveConsultationSubject } from "../src/lib/consultation-subject-resolver.ts";
|
|
import {
|
|
reportBelongsToSubject,
|
|
resolveSubjectBirth,
|
|
sessionBelongsToSubject,
|
|
} from "../src/lib/subject-birth.ts";
|
|
|
|
const selfRow = {
|
|
name: "虚构甲",
|
|
birth_date: "1991-04-07",
|
|
reported_birth_time: "09:15:00",
|
|
birth_time_source: "family_exact",
|
|
birth_time_status: "reported",
|
|
birth_place_label: "虚构城",
|
|
latitude: 31.2,
|
|
longitude: 121.4,
|
|
timezone_offset: 8,
|
|
timezone_id: "Asia/Shanghai",
|
|
ayanamsa: "lahiri",
|
|
};
|
|
|
|
const otherRow = {
|
|
id: "11111111-1111-4111-8111-111111111111",
|
|
user_id: "user-1",
|
|
role: "other",
|
|
name: "虚构乙",
|
|
birth_date: "1988-03-04",
|
|
reported_birth_time: "07:40:00",
|
|
birth_time_source: "hospital_record",
|
|
birth_time_status: "reported",
|
|
birth_place_label: "虚构港",
|
|
latitude: 22.3,
|
|
longitude: 114.1,
|
|
timezone_offset: 8,
|
|
timezone_id: "Asia/Shanghai",
|
|
ayanamsa: "raman",
|
|
};
|
|
|
|
test("resolveSubjectBirth reads self from profiles and another person from typed columns", async () => {
|
|
const self = await resolveSubjectBirth({
|
|
userId: "user-1",
|
|
subjectId: "self",
|
|
loadSelfRow: async () => selfRow,
|
|
loadOtherRow: async () => {
|
|
throw new Error("self must not read another person");
|
|
},
|
|
});
|
|
assert.equal(self.role, "self");
|
|
assert.equal(self.row.birth_date, "1991-04-07");
|
|
assert.equal(self.chartable, true);
|
|
|
|
let requested = "";
|
|
const other = await resolveSubjectBirth({
|
|
userId: "user-1",
|
|
subjectId: otherRow.id,
|
|
loadSelfRow: async () => {
|
|
throw new Error("another person must not fall back to self");
|
|
},
|
|
loadOtherRow: async (id) => {
|
|
requested = id;
|
|
return otherRow;
|
|
},
|
|
});
|
|
assert.equal(requested, otherRow.id);
|
|
assert.equal(other.name, "虚构乙");
|
|
assert.equal(other.row.reported_birth_time, "07:40:00");
|
|
assert.equal(other.row.latitude, 22.3);
|
|
});
|
|
|
|
test("a missing or foreign person fails closed", async () => {
|
|
await assert.rejects(
|
|
() => resolveSubjectBirth({
|
|
userId: "user-1",
|
|
subjectId: otherRow.id,
|
|
loadSelfRow: async () => selfRow,
|
|
loadOtherRow: async () => null,
|
|
}),
|
|
/subject_not_found/,
|
|
);
|
|
await assert.rejects(
|
|
() => resolveSubjectBirth({
|
|
userId: "user-1",
|
|
subjectId: otherRow.id,
|
|
loadSelfRow: async () => selfRow,
|
|
loadOtherRow: async () => ({ ...otherRow, user_id: "user-2" }),
|
|
}),
|
|
/subject_not_found/,
|
|
);
|
|
});
|
|
|
|
test("legacy self sessions stay visible when the filter is self", () => {
|
|
assert.equal(sessionBelongsToSubject({ chart_profile_id: null }, "self"), true);
|
|
assert.equal(sessionBelongsToSubject({ chart_profile_id: "self" }, "self"), true);
|
|
assert.equal(sessionBelongsToSubject({ chart_profile_id: otherRow.id }, "self"), false);
|
|
assert.equal(sessionBelongsToSubject({ chart_profile_id: otherRow.id }, otherRow.id), true);
|
|
assert.equal(reportBelongsToSubject({ chart_profile_id: null }, "self"), true);
|
|
assert.equal(reportBelongsToSubject({ chart_profile_id: otherRow.id }, otherRow.id), true);
|
|
});
|
|
|
|
test("ordinary chat resolves another person through resolveSubjectBirth", async () => {
|
|
const resolved = await resolveConsultationSubject({
|
|
userId: "user-1",
|
|
binding: { chartProfileId: otherRow.id, chartProfileRole: "other", chartProfileName: "伪造" },
|
|
loadSelfProfile: async () => selfRow,
|
|
loadOwnedChartProfile: async () => ({
|
|
id: otherRow.id,
|
|
userId: "user-1",
|
|
role: "other",
|
|
profile: otherRow,
|
|
}),
|
|
});
|
|
assert.equal(resolved.name, "虚构乙");
|
|
assert.equal((resolved.profile as { latitude?: number }).latitude, 22.3);
|
|
assert.notEqual((resolved.profile as { name?: string }).name, "伪造");
|
|
});
|
|
|
|
test("chart, ephemeris, reports, daily language and consult all use the one birth lookup", () => {
|
|
const files = [
|
|
"../src/lib/chart-view-service.ts",
|
|
"../src/app/api/ephemeris/route.ts",
|
|
"../src/app/api/reports/route.ts",
|
|
"../src/app/api/daily-starlanguage/route.ts",
|
|
"../src/lib/consultation-subject-resolver.ts",
|
|
];
|
|
for (const file of files) {
|
|
const source = readFileSync(new URL(file, import.meta.url), "utf8");
|
|
assert.match(source, /loadSubjectBirth|resolveSubjectBirth/);
|
|
}
|
|
const consult = readFileSync(new URL("../src/app/api/consult/route.ts", import.meta.url), "utf8");
|
|
assert.match(consult, /CHART_SUBJECT_SELECT/);
|
|
assert.match(consult, /prepareConsultationRoute/);
|
|
});
|