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