Files
Jyotisha/frontend/tests/synastry-chart-skip.test.ts
T
jesse-uxGrok (agent loop)Cursor
336286e428 fix(chart): skip unused synastry overview and doomed report subprocesses
Synastry charts now skip the unused external overview and run together. Reports skip PyJHora subprocesses when that library is missing, and a full heavy-compute slot logs which paths hold it. Splitting quotas stays a simulation.

Gate, growth, and report pytest passed, as did the frontend route tests, tsc, lint, and the A/B script.

Co-Authored-By: Grok (agent loop)
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-15 08:02:39 +08:00

104 lines
5.9 KiB
TypeScript

import assert from "node:assert/strict";
import { spawnSync } from "node:child_process";
import { fileURLToPath } from "node:url";
import test from "node:test";
const frontendRoot = fileURLToPath(new URL("../", import.meta.url));
const partnerId = "11111111-1111-4111-8111-111111111111";
function runRoute(script: string): { romance: Record<string, unknown>; business: Record<string, unknown>; maxChart: number; maxVarga: number; chartSkip: boolean } {
const result = spawnSync(process.execPath, [
"--experimental-test-module-mocks",
"--import",
"tsx",
"--input-type=module",
"--eval",
script,
], { cwd: frontendRoot, encoding: "utf8", timeout: 20000 });
assert.equal(result.status, 0, result.stderr || result.stdout);
const line = result.stdout.trim().split("\n").at(-1) ?? "{}";
return JSON.parse(line);
}
test("synastry charts send skip concurrently and keep the stubbed JSON", () => {
const script = String.raw`
import { mock } from "node:test";
import { pathToFileURL } from "node:url";
const moduleUrl = (path) => pathToFileURL(process.cwd() + "/" + path).href;
mock.module("server-only", { namedExports: {} });
mock.module("@/lib/account-deletion-server", { namedExports: { refuseWhenAccountDeletionPending: async () => null } });
mock.module("@/lib/product-access", { namedExports: { isProductEnabled: async () => true } });
mock.module("@/lib/request-rate-limit", { namedExports: { consumeUserRequestRateLimit: () => ({ ok: true, retryAfterSeconds: 1 }) } });
mock.module("@/lib/supabase/server", { namedExports: { createServerSupabaseClient: async () => ({ auth: { getUser: async () => ({ data: { user: { id: "user-1" } }, error: null }) } }) } });
mock.module("@/lib/subject-birth", { namedExports: {
ConsultationSubjectError: class ConsultationSubjectError extends Error {},
loadSubjectBirth: async () => ({ chartable: true, row: { name: "fixture" } }),
} });
mock.module("@/lib/server-owned-birth-profile", { namedExports: { globalBirthProfileFromAccountRow: (row) => row } });
mock.module("@/lib/global-birth-payloads", { namedExports: {
synastryBirthPayload: async () => ({ year: 1990, month: 1, day: 1, hour: 12, minute: 0, lat: 28.6139, lon: 77.209, tz: 5.5, ayanamsa: "lahiri" }),
} });
const chartBodies = [];
const maxInflight = { chart: 0, varga: 0 };
const inflight = { chart: 0, varga: 0 };
const waiters = { chart: [], varga: [] };
globalThis.fetch = async (inputUrl, init) => {
const url = String(inputUrl);
const body = JSON.parse(String(init.body));
const kind = url.endsWith("/api/chart") ? "chart" : url.endsWith("/api/varga_full") ? "varga" : "other";
if (kind === "chart") chartBodies.push(body);
if (kind === "chart" || kind === "varga") {
inflight[kind] += 1;
maxInflight[kind] = Math.max(maxInflight[kind], inflight[kind]);
await new Promise((resolve) => {
waiters[kind].push(resolve);
if (waiters[kind].length >= 2) {
const pending = waiters[kind].splice(0, 2);
pending.forEach((fn) => fn());
}
});
inflight[kind] -= 1;
}
if (url.endsWith("/api/chart")) {
return Response.json({
planets: { Moon: { lon: 12.5, sign: "Aries", nakshatra: "Ashwini", nakshatra_pada: 1, nakshatra_lord: "Ketu" } },
ascendant: { sign: "Leo" },
});
}
if (url.endsWith("/api/varga_full")) {
const divisions = body.divisions || [];
if (divisions.includes("D9")) {
return Response.json({ source: "engine", result: { D9_Navamsa: { ascendant: { sign: "Virgo" }, planets: { Moon: { sign: "Cancer" }, Venus: { sign: "Taurus" }, Mars: { sign: "Aries" } } } } });
}
return Response.json({ source: "engine", result: {
D2_Hora: { planets: { Moon: { sign: "Taurus" } } },
D10_Dasamsa: { ascendant: { sign: "Libra" } },
D11_Rudramsa: { planets: { Sun: { sign: "Capricorn" } } },
} });
}
if (url.endsWith("/api/synastry")) return Response.json({ total_score: 18, max_score: 36 });
return Response.json({}, { status: 500 });
};
const { POST } = await import(moduleUrl("src/app/api/synastry/route.ts"));
const romanceRes = await POST(new Request("https://example.test/api/synastry", { method: "POST", body: JSON.stringify({ partnerChartProfileId: "${partnerId}", relationshipType: "romance" }) }));
const romance = await romanceRes.json();
const businessRes = await POST(new Request("https://example.test/api/synastry", { method: "POST", body: JSON.stringify({ partnerChartProfileId: "${partnerId}", relationshipType: "business" }) }));
const business = await businessRes.json();
console.log(JSON.stringify({ romance, business, maxChart: maxInflight.chart, maxVarga: maxInflight.varga, chartSkip: chartBodies.every((body) => body.skip_vedastro_main_entry_overview === true) && chartBodies.length === 4 }));
`;
const got = runRoute(script);
assert.equal(got.maxChart, 2);
assert.equal(got.maxVarga, 2);
assert.equal(got.chartSkip, true);
assert.equal(got.romance.status, "ok");
assert.equal(got.romance.method, "ashtakoot_plus_moon_nakshatra_d9");
assert.deepEqual(got.romance.selfChart, {
moon: { sign: "Aries", nakshatra: "Ashwini", pada: 1, lord: "Ketu", longitude: 12.5 },
d9: { ascendant: { sign: "Virgo" }, moon: { sign: "Cancer" }, venus: { sign: "Taurus" }, mars: { sign: "Aries" }, source: "engine" },
});
assert.equal((got.romance.relationshipReport as { scoreBand?: string }).scoreBand, "mixed");
assert.equal(got.business.status, "ok");
assert.equal(got.business.method, "d2_d10_d11_business_screening_partial");
assert.equal((got.business.relationshipReport as { scoreBand?: string }).scoreBand, "not_scored");
});