Files
Jyotisha/frontend/tests/chart-table-span-20261023.test.tsx
T
jesse-uxandGrok (agent loop) fc2283693d fix(chart): span natal and moon planet tables across the row
VedicLayout now owns the third grid item, so a wrapper around the table cannot drop the natal or Moon table into the left column. Desktop grid-column targets that row. BUG-1421.

Self-test: tsc exit 0, lint 0 errors, 49 targeted tests, next build with / static.

Co-Authored-By: Grok (agent loop)
2026-10-23 01:22:46 +08:00

98 lines
4.0 KiB
TypeScript

import assert from "node:assert/strict";
import { readFileSync } from "node:fs";
import React from "react";
import { renderToStaticMarkup } from "react-dom/server";
import test from "node:test";
import { ChartVedicTab } from "../src/components/chart-page/chart-vedic-tab.tsx";
import { assembleChartView } from "../src/lib/chart-view-load.ts";
import { chartViewOkSchema, type ChartViewOk } from "../src/lib/chart-view-contract.ts";
Object.assign(globalThis, { React });
const golden = JSON.parse(readFileSync(new URL("./fixtures/chart-view-golden.json", import.meta.url), "utf8"));
const bhavaGolden = JSON.parse(readFileSync(new URL("./fixtures/chart-view-bhava-golden.json", import.meta.url), "utf8"));
const transitPacket = JSON.parse(readFileSync(new URL("./fixtures/ephemeris-chart-transit-2026-09-15.golden.json", import.meta.url), "utf8"));
const globalStyles = readFileSync(new URL("../src/app/globals.css", import.meta.url), "utf8");
const profile = {
name: "示例",
date: "1990-06-15",
time: "12:00",
placeLabel: "北京",
latitude: 39.9042,
longitude: 116.4074,
timezoneOffset: 8,
timezoneId: "Asia/Shanghai",
ayanamsa: "raman",
birthTimeStatus: "confirmed",
};
function directDivClasses(html: string, parentClass: string): string[] {
const needle = `<div class="${parentClass}">`;
const start = html.indexOf(needle);
assert.ok(start >= 0, parentClass);
let index = start + needle.length;
let depth = 1;
const classes: string[] = [];
while (index < html.length && depth > 0) {
const nextOpen = html.indexOf("<div", index);
const nextClose = html.indexOf("</div>", index);
assert.ok(nextClose >= 0);
if (nextOpen >= 0 && nextOpen < nextClose) {
if (depth === 1) {
const tagEnd = html.indexOf(">", nextOpen);
const tag = html.slice(nextOpen, tagEnd + 1);
classes.push(tag.match(/class="([^"]*)"/)?.[1] ?? "");
}
depth += 1;
index = html.indexOf(">", nextOpen) + 1;
} else {
depth -= 1;
index = nextClose + "</div>".length;
}
}
return classes;
}
async function fullView(): Promise<ChartViewOk> {
const result = await assembleChartView({
userId: "user-1",
profile,
asOf: "2026-09-15",
layers: ["varga", "bhava", "transit"],
postEngine: async (path, _body, cacheScope) => {
if (path === "/api/chart" && cacheScope?.startsWith("transit:")) return { status: "ok", payload: transitPacket };
if (path === "/api/chart") return { status: "ok", payload: golden.chart };
if (path === "/api/varga_full") return { status: "ok", payload: golden.varga_full };
if (path === "/api/bhava_chalit") return { status: "ok", payload: bhavaGolden.bhava_chalit };
return { status: "http_error", path, elapsedMs: 1, httpStatus: 500 };
},
});
assert.equal(result.body.status, "ok");
return chartViewOkSchema.parse(result.body);
}
test("every Vedic chart type puts its table in the layout's full-width row", async () => {
const view = await fullView();
for (const vargaId of ["D1", "MOON", "D9", "BHAVA", "TRANSIT"]) {
const markup = renderToStaticMarkup(React.createElement(ChartVedicTab, { view, vargaId, onSelectVarga: () => {} }));
const children = directDivClasses(markup, "chart-page-vedic-layout");
assert.deepEqual(children, [
"chart-page-vedic-stage",
"chart-page-params",
"chart-page-vedic-tables",
], vargaId);
}
});
test("the desktop chart grid spans the table row, not a table's own class", () => {
const desktopStart = globalStyles.indexOf("@media (min-width: 1024px) {\n .chart-page-vedic-layout,");
assert.ok(desktopStart >= 0);
const desktopEnd = globalStyles.indexOf("\n}", desktopStart);
const desktop = globalStyles.slice(desktopStart, desktopEnd);
assert.match(desktop, /\.chart-page-vedic-tables \{ grid-column: 1 \/ -1; \}/);
assert.doesNotMatch(desktop, /\.chart-page-planet-table-wrap[\s\S]*grid-column/);
assert.doesNotMatch(desktop, /\.chart-page-varga-table-block[\s\S]*grid-column/);
});