import assert from "node:assert/strict"; import { readFileSync } from "node:fs"; import test from "node:test"; import { accountProfilePatchSchema } from "../src/lib/account-profile-patch.ts"; import { AYANAMSA_VALUES } from "../src/lib/ayanamsa.ts"; import { assembleChartView } from "../src/lib/chart-view-load.ts"; import { libraryProfileFromSubjectRow, parseChartSubjectWrite } from "../src/lib/chart-subject-write.ts"; import { ephemerisAyanamsaNote } from "../src/lib/ephemeris-view.ts"; import { globalBirthProfileFromAccountRow } from "../src/lib/server-owned-birth-profile.ts"; // TASK-chart-types-and-report-buttons-20260928 T6. `resolveAyanamsa` falls // back to Raman for anything it does not know, so each new value is walked // through the paths that store it or send it to the engine. Fictional data only. const NEW_VALUES = ["true_citra", "fagan_bradley"] as const; test("the account PATCH accepts the six values and still rejects the ones not offered", () => { for (const value of AYANAMSA_VALUES) { assert.equal(accountProfilePatchSchema.safeParse({ ayanamsa: value }).success, true, value); } for (const value of ["djwhal_khul", "sassanian", "fagan", "yukteshwar"]) { assert.equal(accountProfilePatchSchema.safeParse({ ayanamsa: value }).success, false, value); } }); test("the profiles CHECK is widened to exactly the six values by an additive migration", () => { const sql = readFileSync( new URL("../supabase/migrations/20260928010000_profile_ayanamsa_six.sql", import.meta.url), "utf8", ); assert.match(sql, /drop constraint if exists profiles_ayanamsa_check/); assert.match( sql, /check \(ayanamsa in \('raman', 'lahiri', 'kp', 'true_citra', 'true_pushya', 'fagan_bradley'\)\)/, ); assert.doesNotMatch(sql, /djwhal_khul|sassanian/); assert.doesNotMatch(sql, /drop column|alter column|rename|set not null|update public\.|set default/i); }); test("the account row keeps a new ayanamsa instead of turning it into Raman", () => { for (const value of NEW_VALUES) { const profile = globalBirthProfileFromAccountRow({ name: "虚构甲", birth_date: "1990-01-01", reported_birth_time: "08:00", latitude: 22.3, longitude: 114.1, timezone_offset: 8, ayanamsa: value, }); assert.equal(profile.ayanamsa, value); } }); test("a saved person keeps a new ayanamsa on write and on read", () => { for (const value of NEW_VALUES) { const parsed = parseChartSubjectWrite({ name: "虚构乙", date: "1990-01-01", reportedTime: "08:00", ayanamsa: value }); assert.equal(parsed.ok, true); if (!parsed.ok) continue; assert.equal(parsed.write.columns.ayanamsa, value); assert.equal(libraryProfileFromSubjectRow({ id: "p-1", name: "虚构乙", ayanamsa: value }).ayanamsa, value); } }); test("the chart page sends the new ayanamsa to the engine unchanged", async () => { for (const value of NEW_VALUES) { const bodies: Record[] = []; await assembleChartView({ userId: "user-1", profile: { date: "1990-01-01", time: "08:00", latitude: 22.3, longitude: 114.1, timezoneOffset: 8, ayanamsa: value, }, postEngine: async (path, body) => { bodies.push(body); return { status: "http_error", path, elapsedMs: 0, httpStatus: 500 }; }, asOf: "2026-09-28", }); assert.equal(bodies[0]?.ayanamsa, value); } }); test("the ephemeris note names the new ayanamsa rather than calling it unknown", () => { assert.equal(ephemerisAyanamsaNote("true_citra"), "五要素按 Lahiri 岁差算,和星盘页的 True Citra 不同。"); assert.equal(ephemerisAyanamsaNote("fagan_bradley"), "五要素按 Lahiri 岁差算,和星盘页的 Fagan-Bradley 不同。"); }); test("the report generator already has a display name for both new values", () => { const source = readFileSync(new URL("../src/lib/personal-report-generation.ts", import.meta.url), "utf8"); assert.match(source, /\["true_citra", "True Citra"\]/); assert.match(source, /\["fagan_bradley", "Fagan-Bradley"\]/); });