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
98 lines
4.0 KiB
TypeScript
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"\]/);
|
|
});
|