Files
Jyotisha/frontend/tests/ayanamsa-six-paths-20260928.test.ts
T
Jesse_ChenandClaude Opus 5.5 873fac8a5b feat(settings,reports): six ayanamsa options; report-scope solid button colours (T6/T7, BUG-1078)
T6: offer True Citra and Fagan-Bradley beside Raman/Lahiri/KP/True Pushya,
engine-supported values only; widen profiles_ayanamsa_check by an additive
migration; ephemeris note names; path tests so no new value falls back to
Raman.

T7: the unlayered `button { color: inherit; }` beats Tailwind's
text-primary-foreground, so solid report buttons showed page ink (light
(light 4.85:1, dark 5.77:1), grey disabled without fade, neutral selected
preset. button.tsx and theme tokens unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017eEAG8HD3mm8gsKXgk8uU8
2026-09-28 15:54:53 +08:00

98 lines
4.0 KiB
TypeScript

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<string, unknown>[] = [];
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"\]/);
});