fix: make active reasoning state visible
This commit is contained in:
@@ -8,6 +8,7 @@ import ReasoningWorkspace, {
|
||||
useLoadingStatus,
|
||||
INITIAL_MESSAGES,
|
||||
UPDATE_MESSAGES,
|
||||
LoadingOverlay,
|
||||
} from "@/components/reasoning-workspace.jsx";
|
||||
import {
|
||||
ScenarioResultPanels,
|
||||
@@ -1286,4 +1287,259 @@ describe("ReasoningWorkspace UI", () => {
|
||||
"What evidence would clarify how the two observations were measured?",
|
||||
);
|
||||
});
|
||||
|
||||
// ── Loading card UI tests ───────────────────────────────
|
||||
|
||||
it("LoadingOverlay shows spinner and heading when isLoading is true", () => {
|
||||
const html = renderToStaticMarkup(
|
||||
<LoadingOverlay
|
||||
isLoading={true}
|
||||
elapsed={0}
|
||||
currentMessage="Reading your situation"
|
||||
variant="initial"
|
||||
/>,
|
||||
);
|
||||
|
||||
expect(html).toContain("Working through your situation");
|
||||
expect(html).toContain("Reading your situation");
|
||||
});
|
||||
|
||||
it("LoadingOverlay is hidden when isLoading is false", () => {
|
||||
const html = renderToStaticMarkup(
|
||||
<LoadingOverlay
|
||||
isLoading={false}
|
||||
elapsed={0}
|
||||
currentMessage="Reading your situation"
|
||||
variant="initial"
|
||||
/>,
|
||||
);
|
||||
|
||||
expect(html).not.toContain("Working through your situation");
|
||||
});
|
||||
|
||||
it("LoadingOverlay shows correct initial status at elapsed 0", () => {
|
||||
const html = renderToStaticMarkup(
|
||||
<LoadingOverlay
|
||||
isLoading={true}
|
||||
elapsed={0}
|
||||
currentMessage="Reading your situation"
|
||||
variant="initial"
|
||||
/>,
|
||||
);
|
||||
|
||||
expect(html).toContain("Reading your situation");
|
||||
});
|
||||
|
||||
it("LoadingOverlay shows correct status at elapsed >= 10", () => {
|
||||
const html = renderToStaticMarkup(
|
||||
<LoadingOverlay
|
||||
isLoading={true}
|
||||
elapsed={12}
|
||||
currentMessage="Building a structured understanding"
|
||||
variant="initial"
|
||||
/>,
|
||||
);
|
||||
|
||||
expect(html).toContain("Building a structured understanding");
|
||||
});
|
||||
|
||||
it("LoadingOverlay shows correct status at elapsed >= 25", () => {
|
||||
const html = renderToStaticMarkup(
|
||||
<LoadingOverlay
|
||||
isLoading={true}
|
||||
elapsed={30}
|
||||
currentMessage="Identifying what is known and still unclear"
|
||||
variant="initial"
|
||||
/>,
|
||||
);
|
||||
|
||||
expect(html).toContain("Identifying what is known and still unclear");
|
||||
});
|
||||
|
||||
it("LoadingOverlay shows correct status at elapsed >= 45", () => {
|
||||
const html = renderToStaticMarkup(
|
||||
<LoadingOverlay
|
||||
isLoading={true}
|
||||
elapsed={50}
|
||||
currentMessage="Selecting the next useful question"
|
||||
variant="initial"
|
||||
/>,
|
||||
);
|
||||
|
||||
expect(html).toContain("Selecting the next useful question");
|
||||
});
|
||||
|
||||
it("LoadingOverlay shows reassurance text after 45s for initial variant", () => {
|
||||
const html = renderToStaticMarkup(
|
||||
<LoadingOverlay
|
||||
isLoading={true}
|
||||
elapsed={60}
|
||||
currentMessage="Selecting the next useful question"
|
||||
variant="initial"
|
||||
/>,
|
||||
);
|
||||
|
||||
expect(html).toContain("This can take around a minute");
|
||||
});
|
||||
|
||||
it("LoadingOverlay hides reassurance text for update variant regardless of elapsed", () => {
|
||||
const html = renderToStaticMarkup(
|
||||
<LoadingOverlay
|
||||
isLoading={true}
|
||||
elapsed={90}
|
||||
currentMessage="Choosing the next question"
|
||||
variant="update"
|
||||
/>,
|
||||
);
|
||||
|
||||
expect(html).not.toContain("This can take around a minute");
|
||||
});
|
||||
|
||||
it("LoadingOverlay displays elapsed time", () => {
|
||||
const html = renderToStaticMarkup(
|
||||
<LoadingOverlay
|
||||
isLoading={true}
|
||||
elapsed={42}
|
||||
currentMessage="Building a structured understanding"
|
||||
variant="initial"
|
||||
/>,
|
||||
);
|
||||
|
||||
expect(html).toContain("This has been running for 42s.");
|
||||
});
|
||||
|
||||
it("LoadingOverlay has aria-busy and role for accessibility", () => {
|
||||
const html = renderToStaticMarkup(
|
||||
<LoadingOverlay
|
||||
isLoading={true}
|
||||
elapsed={0}
|
||||
currentMessage="Reading your situation"
|
||||
variant="initial"
|
||||
/>,
|
||||
);
|
||||
|
||||
expect(html).toContain("aria-busy");
|
||||
expect(html).toContain("role=\"status\"");
|
||||
});
|
||||
|
||||
it("LoadingOverlay uses aria-live on elapsed time element", () => {
|
||||
const html = renderToStaticMarkup(
|
||||
<LoadingOverlay
|
||||
isLoading={true}
|
||||
elapsed={5}
|
||||
currentMessage="Reading your situation"
|
||||
variant="initial"
|
||||
/>,
|
||||
);
|
||||
|
||||
expect(html).toContain("aria-live");
|
||||
});
|
||||
|
||||
it("scenario-form hides Analyse button and shows loading card during initial analysis", () => {
|
||||
// We verify ReasoningWorkspace renders LoadingOverlay for initial status=loading
|
||||
// which is the direct proxy for the scenario form's loading behavior
|
||||
const html = renderToStaticMarkup(
|
||||
<ReasoningWorkspace
|
||||
status="loading"
|
||||
updateStatus="idle"
|
||||
result={null}
|
||||
answer=""
|
||||
setAnswer={vi.fn()}
|
||||
onAnswerSubmit={vi.fn()}
|
||||
/>,
|
||||
);
|
||||
|
||||
// Loading overlay is present
|
||||
expect(html).toContain("Working through your situation");
|
||||
expect(html).toContain("Reading your situation");
|
||||
|
||||
// No result content appears during loading
|
||||
expect(html).not.toContain("Your situation");
|
||||
expect(html).not.toContain("Next question");
|
||||
});
|
||||
|
||||
it("scenario-form shows update loading overlay when updateStatus is loading", () => {
|
||||
const html = renderToStaticMarkup(
|
||||
<ReasoningWorkspace
|
||||
status="success"
|
||||
updateStatus="loading"
|
||||
result={makeWorkspaceResult()}
|
||||
answer="some answer"
|
||||
setAnswer={vi.fn()}
|
||||
onAnswerSubmit={vi.fn()}
|
||||
/>,
|
||||
);
|
||||
|
||||
expect(html).toContain("Working through your situation");
|
||||
expect(html).toContain("Considering your answer");
|
||||
});
|
||||
|
||||
it("success state restores normal controls — no loading overlay", () => {
|
||||
const html = renderToStaticMarkup(
|
||||
<ReasoningWorkspace
|
||||
status="success"
|
||||
updateStatus="idle"
|
||||
result={makeWorkspaceResult()}
|
||||
answer=""
|
||||
setAnswer={vi.fn()}
|
||||
onAnswerSubmit={vi.fn()}
|
||||
/>,
|
||||
);
|
||||
|
||||
expect(html).not.toContain("Working through your situation");
|
||||
expect(html).toContain("Next question");
|
||||
expect(html).toContain("Update situation");
|
||||
});
|
||||
|
||||
it("error state remains visible and shows no loading overlay", () => {
|
||||
const html = renderToStaticMarkup(
|
||||
<ReasoningWorkspace
|
||||
status="error"
|
||||
updateStatus="idle"
|
||||
result={{ error: "Invalid start-case request" }}
|
||||
answer=""
|
||||
setAnswer={vi.fn()}
|
||||
onAnswerSubmit={vi.fn()}
|
||||
/>,
|
||||
);
|
||||
|
||||
expect(html).not.toContain("Working through your situation");
|
||||
expect(html).toContain("Error: Invalid start-case request");
|
||||
});
|
||||
|
||||
it("spinner renders without breaking layout when reduced-motion is active", () => {
|
||||
const html = renderToStaticMarkup(
|
||||
<LoadingOverlay
|
||||
isLoading={true}
|
||||
elapsed={3}
|
||||
currentMessage="Reading your situation"
|
||||
variant="initial"
|
||||
/>,
|
||||
);
|
||||
|
||||
// Spinner element present (CSS media query in globals.css handles reduced-motion)
|
||||
expect(html).toContain("rounded-full");
|
||||
// No JS animation dependency for rendering
|
||||
expect(html).not.toContain("animation-delay");
|
||||
});
|
||||
|
||||
it("loading card appears while Analyse button is hidden (duplicate prevention)", () => {
|
||||
// During status=loading: LoadingOverlay is shown and Analyse button is not rendered
|
||||
const html = renderToStaticMarkup(
|
||||
<ReasoningWorkspace
|
||||
status="loading"
|
||||
updateStatus="idle"
|
||||
result={null}
|
||||
answer=""
|
||||
setAnswer={vi.fn()}
|
||||
onAnswerSubmit={vi.fn()}
|
||||
/>,
|
||||
);
|
||||
|
||||
// Loading card visible (main signal)
|
||||
expect(html).toContain("Working through your situation");
|
||||
|
||||
// No form controls remain during loading
|
||||
expect(html).not.toContain("Update situation");
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user