A zero-year Chara period is shown as 0 years instead of failing the whole chart. Switching ephemeris dates drops the previous day immediately and can be retried. Missing birth data links to chart settings.
108 lines
4.2 KiB
TypeScript
108 lines
4.2 KiB
TypeScript
import assert from "node:assert/strict";
|
|
import { readFileSync } from "node:fs";
|
|
import React from "react";
|
|
import test from "node:test";
|
|
import { renderToStaticMarkup } from "react-dom/server";
|
|
|
|
import { ChartDashaTab } from "../src/components/chart-page/chart-dasha-tab.tsx";
|
|
import type { ChartViewOk } from "../src/lib/chart-view-contract.ts";
|
|
import { assembleChartView } from "../src/lib/chart-view-load.ts";
|
|
import { CHARA_ZERO_YEAR_LABEL, CHARA_ZERO_YEAR_NOTE } from "../src/lib/chart-view-labels.ts";
|
|
import { buildChartView, type ChartViewProfileInput } from "../src/lib/chart-view-mapper.ts";
|
|
|
|
Object.assign(globalThis, { React });
|
|
|
|
/**
|
|
* Generated from the real engine, not a hand-built shape:
|
|
* C:\Users\74082\anaconda3\python.exe
|
|
* JyotishAPIHandler.__new__()._compute_chart + _compute_chara_dasha
|
|
* 1985-08-03 03:59, lat 39.9042, lon 116.4074, tz 8, ayanamsa raman, node_mode mean,
|
|
* skip_vedastro_main_entry_overview, antardasha true.
|
|
* Sagittarius duration_years is 0 (debilitated). scripts/jaimini.py was not modified.
|
|
*/
|
|
const golden = JSON.parse(readFileSync(new URL("./fixtures/chara-zero-year-1985-08-03-beijing.golden.json", import.meta.url), "utf8")) as {
|
|
chart: Record<string, unknown>;
|
|
chara: Record<string, unknown>;
|
|
};
|
|
|
|
const profile: ChartViewProfileInput = {
|
|
name: "虚构",
|
|
date: "1985-08-03",
|
|
time: "03:59",
|
|
placeLabel: "北京",
|
|
latitude: 39.9042,
|
|
longitude: 116.4074,
|
|
timezoneOffset: 8,
|
|
timezoneId: "Asia/Shanghai",
|
|
ayanamsa: "raman",
|
|
birthTimeStatus: "reported",
|
|
};
|
|
|
|
function viewFrom(chara: Record<string, unknown>): ChartViewOk {
|
|
return buildChartView({
|
|
chart: golden.chart,
|
|
varga: null,
|
|
chara,
|
|
western: null,
|
|
qizheng: null,
|
|
profile,
|
|
asOf: "2026-09-25",
|
|
});
|
|
}
|
|
|
|
test("a real zero-year Chara mahadasha keeps twelve continuous periods and does not throw", async () => {
|
|
const view = viewFrom(golden.chara);
|
|
const periods = view.dasha.chara.periods;
|
|
assert.equal(periods.length, 12);
|
|
const sagittarius = periods.find((period) => period.sign === "Sagittarius");
|
|
assert.ok(sagittarius);
|
|
assert.equal(sagittarius.zeroYear, true);
|
|
assert.equal(sagittarius.antardashas.length, 0);
|
|
assert.equal(sagittarius.start, sagittarius.end);
|
|
for (let index = 0; index < periods.length - 1; index += 1) {
|
|
assert.equal(periods[index]?.end, periods[index + 1]?.start);
|
|
}
|
|
const assembled = await assembleChartView({
|
|
userId: "synthetic",
|
|
accountId: "synthetic",
|
|
profileFingerprint: "fixture-zero-year",
|
|
profile,
|
|
asOf: "2026-09-25",
|
|
layers: ["chara"],
|
|
postEngine: async (path) => {
|
|
if (path === "/api/chart") return { status: "ok", payload: golden.chart };
|
|
if (path === "/api/dasha/chara") return { status: "ok", payload: golden.chara };
|
|
return { status: "http_error", path, elapsedMs: 0, httpStatus: 404 };
|
|
},
|
|
});
|
|
assert.equal(assembled.httpStatus, 200);
|
|
assert.equal(assembled.body.status, "ok");
|
|
});
|
|
|
|
test("zero antardasha weights on a positive mahadasha do not produce an invalid date", () => {
|
|
const chara = structuredClone(golden.chara) as {
|
|
result: { chara_dasha: { dasha_sequence: Array<{ duration_years: number; antardashas?: Array<{ duration_years: number }> }> } };
|
|
};
|
|
const positive = chara.result.chara_dasha.dasha_sequence.find((row) => row.duration_years > 0);
|
|
assert.ok(positive?.antardashas?.length);
|
|
for (const antar of positive.antardashas ?? []) antar.duration_years = 0;
|
|
const view = viewFrom(chara);
|
|
const mapped = view.dasha.chara.periods.find((period) => period.sign !== "Sagittarius" && period.antardashas.length > 0);
|
|
assert.ok(mapped);
|
|
for (const antar of mapped.antardashas) {
|
|
assert.match(antar.start, /^\d{4}-\d{2}-\d{2}$/);
|
|
assert.match(antar.end, /^\d{4}-\d{2}-\d{2}$/);
|
|
}
|
|
});
|
|
|
|
test("the zero-year Chara row shows 0 年 and does not render sub-periods", () => {
|
|
const view = viewFrom(golden.chara);
|
|
const markup = renderToStaticMarkup(React.createElement(ChartDashaTab, { view }));
|
|
const marker = markup.indexOf(CHARA_ZERO_YEAR_LABEL);
|
|
const note = markup.indexOf(CHARA_ZERO_YEAR_NOTE, marker);
|
|
assert.ok(marker >= 0 && note > marker);
|
|
const slice = markup.slice(Math.max(0, marker - 40), note);
|
|
assert.match(slice, /射手/);
|
|
assert.doesNotMatch(markup.slice(marker, note), /<ul/);
|
|
});
|