238 lines
8.3 KiB
React
238 lines
8.3 KiB
React
import { describe, expect, it } from "vitest";
|
|
import React from "react";
|
|
import { render, screen } from "@testing-library/react";
|
|
import "@testing-library/jest-dom";
|
|
|
|
vi.mock("next/navigation", () => ({
|
|
useRouter: () => ({ push: () => {} }),
|
|
}));
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Route-level assertions for v0.55 architecture
|
|
// Portfolio = /index ; Investigation Report = dedicated page
|
|
// ---------------------------------------------------------------------------
|
|
|
|
function makeSnapshot(overrides = {}) {
|
|
const situationGraph = {
|
|
evidence: [
|
|
{ id: "e1", claim: "Complaints rose.", type: "finding" },
|
|
{ id: "e2", claim: "Production increased.", type: "finding" },
|
|
],
|
|
reconstruction: {
|
|
plausibleInterpretations: ["The denominator may have been narrowed."],
|
|
},
|
|
};
|
|
|
|
return {
|
|
scenario: "Complaints increased while production increased.",
|
|
situationGraph,
|
|
selectedQuestion: null,
|
|
summary: "Production quality declined.",
|
|
updatedAt: new Date().toISOString(),
|
|
schemaVersion: 1,
|
|
investigationReport: null,
|
|
findings: [],
|
|
...overrides,
|
|
};
|
|
}
|
|
|
|
describe("Portfolio page (v0.55 route architecture)", () => {
|
|
let Portfolio;
|
|
|
|
beforeAll(async () => {
|
|
const mod = await import("@/app/page.jsx");
|
|
Portfolio = mod.default;
|
|
});
|
|
|
|
it("shows + Create new investigation when no investigation exists", async () => {
|
|
localStorage.clear();
|
|
render(React.createElement(Portfolio));
|
|
expect(await screen.findByText(/Create new investigation/i)).toBeInTheDocument();
|
|
expect(screen.queryByText(/Open investigation/i)).not.toBeInTheDocument();
|
|
});
|
|
|
|
it("shows Open investigation card when one persisted investigation exists", async () => {
|
|
localStorage.setItem(
|
|
"confidence-engine-investigation",
|
|
JSON.stringify(makeSnapshot()),
|
|
);
|
|
render(React.createElement(Portfolio));
|
|
expect(await screen.findByText(/Open investigation/i)).toBeInTheDocument();
|
|
localStorage.removeItem("confidence-engine-investigation");
|
|
});
|
|
|
|
it("shows View report only when a persisted report exists", async () => {
|
|
localStorage.setItem(
|
|
"confidence-engine-investigation",
|
|
JSON.stringify(
|
|
makeSnapshot({
|
|
investigationReport: {
|
|
understanding: "We understand complaints rose.",
|
|
hasPlausibleInterpretations: false,
|
|
},
|
|
}),
|
|
),
|
|
);
|
|
render(React.createElement(Portfolio));
|
|
expect(await screen.findByText(/View report/i)).toBeInTheDocument();
|
|
localStorage.removeItem("confidence-engine-investigation");
|
|
});
|
|
|
|
it("does not show View report when no report persists", async () => {
|
|
localStorage.setItem(
|
|
"confidence-engine-investigation",
|
|
JSON.stringify(makeSnapshot()),
|
|
);
|
|
render(React.createElement(Portfolio));
|
|
expect(screen.queryByText(/View report/i)).not.toBeInTheDocument();
|
|
localStorage.removeItem("confidence-engine-investigation");
|
|
});
|
|
});
|
|
|
|
describe("Investigation Report page (v0.55 route architecture)", () => {
|
|
let ReportPage;
|
|
|
|
beforeAll(async () => {
|
|
const mod = await import("@/app/investigations/[id]/report/page.jsx");
|
|
ReportPage = mod.default;
|
|
});
|
|
|
|
it("renders persisted report with Situation and What we understand", async () => {
|
|
localStorage.setItem(
|
|
"confidence-engine-investigation",
|
|
JSON.stringify(
|
|
makeSnapshot({
|
|
investigationReport: {
|
|
understanding: "We understand complaints rose alongside production increases.",
|
|
hasPlausibleInterpretations: false,
|
|
},
|
|
}),
|
|
),
|
|
);
|
|
render(React.createElement(ReportPage));
|
|
expect(await screen.findByText(/Investigation Report/i)).toBeInTheDocument();
|
|
expect(await screen.findByText(/Situation/i)).toBeInTheDocument();
|
|
expect(screen.getByText(/What we understand/i)).toBeInTheDocument();
|
|
expect(screen.getByText("We understand complaints rose alongside production increases.")).toBeInTheDocument();
|
|
localStorage.removeItem("confidence-engine-investigation");
|
|
});
|
|
|
|
it("does not show pending placeholder during pre-hydration", async () => {
|
|
render(React.createElement(ReportPage));
|
|
// During pre-hydration, the page should render Investigation Report title
|
|
// but NOT the "Report generation pending" placeholder (which is for post-hydration no-report)
|
|
const pending = await screen.findByText(/Investigation Report/i);
|
|
expect(pending).toBeInTheDocument();
|
|
});
|
|
|
|
it("shows skeleton after hydration when genuinely no report exists", async () => {
|
|
localStorage.setItem(
|
|
"confidence-engine-investigation",
|
|
JSON.stringify(makeSnapshot()),
|
|
);
|
|
render(React.createElement(ReportPage));
|
|
expect(await screen.findByText(/Investigation Report/i)).toBeInTheDocument();
|
|
// After hydration, if no report, skeleton should appear (not during pre-hydration)
|
|
const pending = await screen.findByText(/Report generation pending/i);
|
|
expect(pending).toBeInTheDocument();
|
|
localStorage.removeItem("confidence-engine-investigation");
|
|
});
|
|
|
|
it("conditionally renders What remains plausible only when hasPlausibleInterpretations is true", async () => {
|
|
localStorage.setItem(
|
|
"confidence-engine-investigation",
|
|
JSON.stringify(
|
|
makeSnapshot({
|
|
investigationReport: {
|
|
understanding: "Some understanding.",
|
|
hasPlausibleInterpretations: false,
|
|
plausibleInterpretations: "",
|
|
},
|
|
}),
|
|
),
|
|
);
|
|
render(React.createElement(ReportPage));
|
|
expect(await screen.findByText(/Investigation Report/i)).toBeInTheDocument();
|
|
expect(screen.queryByText(/What remains plausible/i)).not.toBeInTheDocument();
|
|
localStorage.removeItem("confidence-engine-investigation");
|
|
});
|
|
|
|
it("renders What remains plausible when hasPlausibleInterpretations is true", async () => {
|
|
localStorage.setItem(
|
|
"confidence-engine-investigation",
|
|
JSON.stringify(
|
|
makeSnapshot({
|
|
investigationReport: {
|
|
understanding: "Some understanding.",
|
|
hasPlausibleInterpretations: true,
|
|
plausibleInterpretations: "The denominator may have been narrowed.",
|
|
},
|
|
}),
|
|
),
|
|
);
|
|
render(React.createElement(ReportPage));
|
|
expect(await screen.findByText(/What remains plausible/i)).toBeInTheDocument();
|
|
localStorage.removeItem("confidence-engine-investigation");
|
|
});
|
|
|
|
it("renders Back to investigation link", async () => {
|
|
localStorage.setItem(
|
|
"confidence-engine-investigation",
|
|
JSON.stringify(
|
|
makeSnapshot({
|
|
investigationReport: {
|
|
understanding: "Some understanding.",
|
|
hasPlausibleInterpretations: false,
|
|
},
|
|
}),
|
|
),
|
|
);
|
|
render(React.createElement(ReportPage));
|
|
expect(await screen.findByText(/Back to investigation/i)).toBeInTheDocument();
|
|
localStorage.removeItem("confidence-engine-investigation");
|
|
});
|
|
|
|
it("renders Back to portfolio link", async () => {
|
|
localStorage.setItem(
|
|
"confidence-engine-investigation",
|
|
JSON.stringify(
|
|
makeSnapshot({
|
|
investigationReport: {
|
|
understanding: "Some understanding.",
|
|
hasPlausibleInterpretations: false,
|
|
},
|
|
}),
|
|
),
|
|
);
|
|
render(React.createElement(ReportPage));
|
|
expect(await screen.findByText(/Back to portfolio/i)).toBeInTheDocument();
|
|
localStorage.removeItem("confidence-engine-investigation");
|
|
});
|
|
|
|
it("shows skeleton loading state when no persisted report exists", async () => {
|
|
localStorage.setItem(
|
|
"confidence-engine-investigation",
|
|
JSON.stringify(makeSnapshot()),
|
|
);
|
|
render(React.createElement(ReportPage));
|
|
expect(await screen.findByText(/Investigation Report/i)).toBeInTheDocument();
|
|
// Skeleton should not have actual understanding content
|
|
expect(screen.queryByText(/Report generation pending/i)).toBeInTheDocument();
|
|
localStorage.removeItem("confidence-engine-investigation");
|
|
});
|
|
});
|
|
|
|
describe("Investigation page (v0.55 route architecture)", () => {
|
|
let InvestigationPage;
|
|
|
|
beforeAll(async () => {
|
|
const mod = await import("@/app/investigations/[id]/page.jsx");
|
|
InvestigationPage = mod.default;
|
|
});
|
|
|
|
it("renders Back to portfolio link", async () => {
|
|
render(React.createElement(InvestigationPage));
|
|
expect(await screen.findByText(/Back to portfolio/i)).toBeInTheDocument();
|
|
});
|
|
});
|