fix: harden Pi management readiness
This commit is contained in:
@@ -56,20 +56,20 @@ beforeEach(() => {
|
||||
window.matchMedia = vi.fn().mockReturnValue({ matches: true, addEventListener: vi.fn(), removeEventListener: vi.fn() });
|
||||
useSessionStore.getState().resetSession();
|
||||
server.use(
|
||||
http.get("http://localhost:8787/me", () =>
|
||||
http.get("/api/me", () =>
|
||||
HttpResponse.json({ issuer: "portal", subject: "alice", displayName: "Alice", isAdmin: false }),
|
||||
),
|
||||
http.get("http://localhost:8787/sessions", () => HttpResponse.json(LIST)),
|
||||
http.get("http://localhost:8787/sessions/:id/documents", () => HttpResponse.json([
|
||||
http.get("/api/sessions", () => HttpResponse.json(LIST)),
|
||||
http.get("/api/sessions/:id/documents", () => HttpResponse.json([
|
||||
{ phase: "—", key: "question", title: "Domanda originale", format: "text", content: "Attiva uno" },
|
||||
])),
|
||||
http.post("http://localhost:8787/sessions/:id/archive", () => new HttpResponse(null, { status: 204 })),
|
||||
http.post("/api/sessions/:id/archive", () => new HttpResponse(null, { status: 204 })),
|
||||
);
|
||||
});
|
||||
|
||||
test("regular users load only their sessions and never see administrator controls", async () => {
|
||||
let scope: string | null = null;
|
||||
server.use(http.get("http://localhost:8787/sessions", ({ request }) => {
|
||||
server.use(http.get("/api/sessions", ({ request }) => {
|
||||
scope = new URL(request.url).searchParams.get("scope");
|
||||
return HttpResponse.json(LIST);
|
||||
}));
|
||||
@@ -80,17 +80,12 @@ test("regular users load only their sessions and never see administrator control
|
||||
expect(screen.queryByText(/administrator view/i)).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
test("opens Pi management from the session rail without replacing session controls", async () => {
|
||||
test("Pi management preserves the open session summary and the model activity timeline", async () => {
|
||||
const user = userEvent.setup();
|
||||
server.use(
|
||||
http.get("/api/me", () => HttpResponse.json({ issuer: "portal", subject: "alice", displayName: "Alice", isAdmin: false })),
|
||||
http.get("/api/sessions", () => HttpResponse.json(LIST)),
|
||||
http.get("/api/health/dwh", () => HttpResponse.json({ ok: true, detail: "ok" })),
|
||||
http.get("/api/settings", () => HttpResponse.json({})),
|
||||
http.get("/api/workspaces", () => HttpResponse.json([])),
|
||||
http.get("/api/models", () => HttpResponse.json([])),
|
||||
http.get("/api/pi-management/status", () => HttpResponse.json({
|
||||
version: "0.80.3", ready: true,
|
||||
credentials: "present",
|
||||
config: { provider: "zai", model: "glm-5.2", reasoning: "medium" },
|
||||
checkedAt: "2026-08-05T10:00:00.000Z",
|
||||
})),
|
||||
@@ -98,24 +93,41 @@ test("opens Pi management from the session rail without replacing session contro
|
||||
providers: ["zai"], models: [{ provider: "zai", id: "glm-5.2" }],
|
||||
reasoning: ["low", "medium", "high"], checkedAt: "2026-08-05T10:00:00.000Z",
|
||||
})),
|
||||
http.post("/api/sessions/:id/resume", () => resumeResult("s1")),
|
||||
http.get("/api/sessions/:id", () => HttpResponse.json({ phase: 4 })),
|
||||
);
|
||||
wrap();
|
||||
|
||||
expect(await screen.findByText("Attiva uno")).toBeVisible();
|
||||
await user.click(await screen.findByText("Attiva uno"));
|
||||
expect(await screen.findByRole("complementary", { name: "Session summary" })).toHaveTextContent("Domanda originale");
|
||||
await user.click(screen.getByRole("button", { name: "Pi management" }));
|
||||
expect(await screen.findByRole("heading", { name: "Pi management" })).toBeVisible();
|
||||
const shell = document.querySelector('[data-testid="app-shell"]');
|
||||
expect(shell).toHaveTextContent("Workspace management");
|
||||
expect(shell).toHaveTextContent("Active sessions");
|
||||
const hiddenSummary = document.querySelector<HTMLElement>('aside[aria-label="Session summary"]');
|
||||
expect(hiddenSummary).toHaveAttribute("aria-hidden", "true");
|
||||
expect(hiddenSummary).toHaveTextContent("Attiva uno");
|
||||
await user.click(screen.getByRole("button", { name: "Close Pi management" }));
|
||||
await waitFor(() => {
|
||||
expect(screen.getByRole("complementary", { name: "Session summary" })).toHaveTextContent("Domanda originale");
|
||||
});
|
||||
|
||||
await user.click(screen.getByRole("button", { name: "Resume" }));
|
||||
await screen.findByRole("button", { name: "Show model activity" });
|
||||
act(() => useSessionStore.getState().setLastUserEntry({ kind: "input", text: "Preserved activity" }));
|
||||
await user.click(screen.getByRole("button", { name: "Pi management" }));
|
||||
await user.click(await screen.findByRole("button", { name: "Close Pi management" }));
|
||||
await waitFor(() => expect(screen.queryByRole("heading", { name: "Pi management" })).not.toBeInTheDocument());
|
||||
await user.click(screen.getByRole("button", { name: "Show model activity" }));
|
||||
expect(await screen.findByRole("heading", { name: "Model activity" })).toBeVisible();
|
||||
expect(screen.getByLabelText("Model activity timeline")).toHaveTextContent("Preserved activity");
|
||||
});
|
||||
|
||||
test("administrators can explicitly switch to all sessions and see owners", async () => {
|
||||
let scope = "";
|
||||
server.use(
|
||||
http.get("http://localhost:8787/me", () =>
|
||||
http.get("/api/me", () =>
|
||||
HttpResponse.json({ issuer: "portal", subject: "alice-id", displayName: "Alice", isAdmin: true }),
|
||||
),
|
||||
http.get("http://localhost:8787/sessions", ({ request }) => {
|
||||
http.get("/api/sessions", ({ request }) => {
|
||||
scope = new URL(request.url).searchParams.get("scope") ?? "";
|
||||
return HttpResponse.json([
|
||||
{ ...LIST[0], author: "Alice" },
|
||||
@@ -138,14 +150,14 @@ test("administrators can explicitly switch to all sessions and see owners", asyn
|
||||
test("administrator confirms before deleting a same-named user's session", async () => {
|
||||
let deletes = 0;
|
||||
server.use(
|
||||
http.get("http://localhost:8787/me", () =>
|
||||
http.get("/api/me", () =>
|
||||
HttpResponse.json({ issuer: "portal", subject: "alice-id", displayName: "Alice", isAdmin: true }),
|
||||
),
|
||||
http.get("http://localhost:8787/sessions", () => HttpResponse.json([
|
||||
http.get("/api/sessions", () => HttpResponse.json([
|
||||
{ ...LIST[0], author: "Alice" },
|
||||
{ ...LIST[1], id: "s3", question: "Second session", archived: false, author: "Bob" },
|
||||
])),
|
||||
http.delete("http://localhost:8787/sessions/:id", () => {
|
||||
http.delete("/api/sessions/:id", () => {
|
||||
deletes += 1;
|
||||
return new HttpResponse(null, { status: 204 });
|
||||
}),
|
||||
@@ -165,13 +177,13 @@ test("administrator confirms before archiving a same-named user's session", asyn
|
||||
let archives = 0;
|
||||
const confirm = vi.spyOn(window, "confirm").mockReturnValue(false);
|
||||
server.use(
|
||||
http.get("http://localhost:8787/me", () =>
|
||||
http.get("/api/me", () =>
|
||||
HttpResponse.json({ issuer: "portal", subject: "alice-id", displayName: "Alice", isAdmin: true }),
|
||||
),
|
||||
http.get("http://localhost:8787/sessions", () => HttpResponse.json([
|
||||
http.get("/api/sessions", () => HttpResponse.json([
|
||||
{ ...LIST[0], author: "Alice" },
|
||||
])),
|
||||
http.post("http://localhost:8787/sessions/:id/archive", () => {
|
||||
http.post("/api/sessions/:id/archive", () => {
|
||||
archives += 1;
|
||||
return new HttpResponse(null, { status: 204 });
|
||||
}),
|
||||
@@ -195,7 +207,7 @@ test("active list shows group header and hides archived sessions", async () => {
|
||||
|
||||
test("ungrouped sessions render after groups with no 'No group' label", async () => {
|
||||
server.use(
|
||||
http.get("http://localhost:8787/sessions", () => HttpResponse.json([
|
||||
http.get("/api/sessions", () => HttpResponse.json([
|
||||
{ id: "g1", status: "open", question: "In gruppo", summary: null, created_at: "2026-01-02T00:00:00Z", updated_at: null, author: null, name: null, group: "Aritmologia", archived: false },
|
||||
{ id: "u1", status: "open", question: "Senza gruppo", summary: null, created_at: "2026-01-03T00:00:00Z", updated_at: null, author: null, name: null, group: null, archived: false },
|
||||
])),
|
||||
@@ -271,13 +283,13 @@ test("supports keyboard session resizing and hides its divider when the split is
|
||||
test("clicking a session with a live runtime reconnects to its gate instead of the panel", async () => {
|
||||
let resumed: string | null = null;
|
||||
server.use(
|
||||
http.get("http://localhost:8787/sessions", () =>
|
||||
http.get("/api/sessions", () =>
|
||||
HttpResponse.json([{ ...LIST[0], active: true }])),
|
||||
http.post("http://localhost:8787/sessions/:id/resume", ({ params }) => {
|
||||
http.post("/api/sessions/:id/resume", ({ params }) => {
|
||||
resumed = params.id as string;
|
||||
return resumeResult(resumed, true); // warm runtime → alreadyActive
|
||||
}),
|
||||
http.get("http://localhost:8787/sessions/:id", () =>
|
||||
http.get("/api/sessions/:id", () =>
|
||||
HttpResponse.json({ id: "s1", status: "open", phase: 1 })),
|
||||
);
|
||||
wrap();
|
||||
@@ -289,7 +301,7 @@ test("clicking a session with a live runtime reconnects to its gate instead of t
|
||||
});
|
||||
|
||||
test("New session closes an open session detail panel", async () => {
|
||||
server.use(http.post("http://localhost:8787/runtime/prewarm", () =>
|
||||
server.use(http.post("/api/runtime/prewarm", () =>
|
||||
HttpResponse.json({ status: "warming" }, { status: 202 })));
|
||||
wrap();
|
||||
await userEvent.click(await screen.findByText("Attiva uno")); // cold session → panel opens
|
||||
@@ -316,7 +328,7 @@ test("Resume from the panel activates the session and closes the panel", async (
|
||||
activityLog: [{ kind: "status", phase: "F7", text: "Stale prior activity", level: "info" }],
|
||||
});
|
||||
server.use(
|
||||
http.post("http://localhost:8787/sessions/:id/resume", ({ params }) => {
|
||||
http.post("/api/sessions/:id/resume", ({ params }) => {
|
||||
resumed = params.id as string;
|
||||
return resumeResult(resumed);
|
||||
}),
|
||||
@@ -335,8 +347,8 @@ test("Resume from the panel activates the session and closes the panel", async (
|
||||
test("Resume paints the re-entry phase from the manifest after the cold Resume succeeds", async () => {
|
||||
useSessionStore.getState().resetSession();
|
||||
server.use(
|
||||
http.post("http://localhost:8787/sessions/:id/resume", () => resumeResult("s1")),
|
||||
http.get("http://localhost:8787/sessions/:id", () =>
|
||||
http.post("/api/sessions/:id/resume", () => resumeResult("s1")),
|
||||
http.get("/api/sessions/:id", () =>
|
||||
HttpResponse.json({ id: "s1", status: "open", phase: 4 })),
|
||||
);
|
||||
wrap();
|
||||
@@ -349,11 +361,11 @@ test("Resume paints the re-entry phase from the manifest after the cold Resume s
|
||||
test("an already-active same-session Resume preserves its EventSource and store", async () => {
|
||||
let resumeCalls = 0;
|
||||
server.use(
|
||||
http.post("http://localhost:8787/sessions/:id/resume", () => {
|
||||
http.post("/api/sessions/:id/resume", () => {
|
||||
resumeCalls += 1;
|
||||
return resumeResult("s1", resumeCalls > 1);
|
||||
}),
|
||||
http.get("http://localhost:8787/sessions/:id", () =>
|
||||
http.get("/api/sessions/:id", () =>
|
||||
HttpResponse.json({ id: "s1", status: "open", phase: 1 })),
|
||||
);
|
||||
wrap();
|
||||
@@ -379,14 +391,14 @@ test("concurrent same-id Resume invocations share one cold request and replaceme
|
||||
const coldGate = deferred();
|
||||
const coldStarted = deferred();
|
||||
server.use(
|
||||
http.post("http://localhost:8787/sessions/:id/resume", async () => {
|
||||
http.post("/api/sessions/:id/resume", async () => {
|
||||
resumeCalls += 1;
|
||||
if (resumeCalls === 1) return resumeResult("s1", false);
|
||||
if (resumeCalls === 2) coldStarted.resolve();
|
||||
await coldGate.promise;
|
||||
return resumeResult("s1", false);
|
||||
}),
|
||||
http.get("http://localhost:8787/sessions/:id", () =>
|
||||
http.get("/api/sessions/:id", () =>
|
||||
HttpResponse.json({ id: "s1", status: "open", phase: 1 })),
|
||||
);
|
||||
wrap();
|
||||
@@ -408,7 +420,7 @@ test("concurrent same-id Resume invocations share one cold request and replaceme
|
||||
await waitFor(() => expect(FakeEventSource.instances).toHaveLength(2));
|
||||
const replacement = FakeEventSource.instances[1];
|
||||
expect(oldSource.closed).toBe(true);
|
||||
expect(replacement.url).toBe("http://localhost:8787/sessions/s1/events");
|
||||
expect(replacement.url).toBe("/api/sessions/s1/events");
|
||||
expect(useSessionStore.getState().activityLog).toEqual([
|
||||
{ kind: "lifecycle", phase: null, text: "Resuming session" },
|
||||
]);
|
||||
@@ -431,13 +443,13 @@ test("a committed Resume releases same-id single-flight before its manifest sett
|
||||
const firstS1ManifestGate = deferred();
|
||||
const firstS1ManifestStarted = deferred();
|
||||
server.use(
|
||||
http.get("http://localhost:8787/sessions", () => HttpResponse.json([LIST[0], other])),
|
||||
http.post("http://localhost:8787/sessions/:id/resume", ({ params }) => {
|
||||
http.get("/api/sessions", () => HttpResponse.json([LIST[0], other])),
|
||||
http.post("/api/sessions/:id/resume", ({ params }) => {
|
||||
const id = params.id as string;
|
||||
if (id === "s1") s1ResumeCalls += 1;
|
||||
return resumeResult(id);
|
||||
}),
|
||||
http.get("http://localhost:8787/sessions/:id", async ({ params }) => {
|
||||
http.get("/api/sessions/:id", async ({ params }) => {
|
||||
if (params.id === "s1") {
|
||||
s1ManifestCalls += 1;
|
||||
if (s1ManifestCalls === 1) {
|
||||
@@ -476,9 +488,9 @@ test("a committed Resume releases same-id single-flight before its manifest sett
|
||||
|
||||
test("cold same-session Resume keeps the old stream until success then receives post-clear events once", async () => {
|
||||
server.use(
|
||||
http.post("http://localhost:8787/sessions/:id/resume", () =>
|
||||
http.post("/api/sessions/:id/resume", () =>
|
||||
resumeResult("s1")),
|
||||
http.get("http://localhost:8787/sessions/:id", () =>
|
||||
http.get("/api/sessions/:id", () =>
|
||||
HttpResponse.json({ id: "s1", status: "open", phase: 1 })),
|
||||
);
|
||||
wrap();
|
||||
@@ -492,7 +504,7 @@ test("cold same-session Resume keeps the old stream until success then receives
|
||||
let markStarted!: () => void;
|
||||
const resumeStarted = new Promise<void>((resolve) => { markStarted = resolve; });
|
||||
const resumeReleased = new Promise<void>((resolve) => { releaseResume = resolve; });
|
||||
server.use(http.post("http://localhost:8787/sessions/:id/resume", async () => {
|
||||
server.use(http.post("/api/sessions/:id/resume", async () => {
|
||||
markStarted();
|
||||
await resumeReleased;
|
||||
return resumeResult("s1");
|
||||
@@ -517,7 +529,7 @@ test("cold same-session Resume keeps the old stream until success then receives
|
||||
await waitFor(() => expect(FakeEventSource.instances).toHaveLength(2));
|
||||
expect(first.closed).toBe(true);
|
||||
const replacement = FakeEventSource.instances[1];
|
||||
expect(replacement.url).toBe("http://localhost:8787/sessions/s1/events");
|
||||
expect(replacement.url).toBe("/api/sessions/s1/events");
|
||||
expect(useSessionStore.getState().transcript).toEqual([]);
|
||||
expect(useSessionStore.getState().activityLog).toEqual([
|
||||
{ kind: "lifecycle", phase: null, text: "Resuming session" },
|
||||
@@ -549,9 +561,9 @@ test("cold same-session Resume keeps the old stream until success then receives
|
||||
|
||||
test("a failed same-session Resume preserves its source, activity, and document panel", async () => {
|
||||
server.use(
|
||||
http.post("http://localhost:8787/sessions/:id/resume", () =>
|
||||
http.post("/api/sessions/:id/resume", () =>
|
||||
resumeResult("s1")),
|
||||
http.get("http://localhost:8787/sessions/:id", () =>
|
||||
http.get("/api/sessions/:id", () =>
|
||||
HttpResponse.json({ id: "s1", status: "open", phase: 1 })),
|
||||
);
|
||||
wrap();
|
||||
@@ -562,7 +574,7 @@ test("a failed same-session Resume preserves its source, activity, and document
|
||||
act(() => first.emitNamed("info", { type: "info", text: "Keep me" }, "4"));
|
||||
const before = useSessionStore.getState().activityLog.map((entry) => ({ ...entry }));
|
||||
|
||||
server.use(http.post("http://localhost:8787/sessions/:id/resume", () =>
|
||||
server.use(http.post("/api/sessions/:id/resume", () =>
|
||||
new HttpResponse(null, { status: 409 })));
|
||||
await userEvent.click(screen.getByTestId("session-item-s1"));
|
||||
await userEvent.click(await screen.findByRole("button", { name: /resume/i }));
|
||||
@@ -581,10 +593,10 @@ test("resuming a different already-active session binds it only after success",
|
||||
created_at: "2026-01-03T00:00:00Z",
|
||||
};
|
||||
server.use(
|
||||
http.get("http://localhost:8787/sessions", () => HttpResponse.json([LIST[0], other])),
|
||||
http.post("http://localhost:8787/sessions/:id/resume", ({ params }) =>
|
||||
http.get("/api/sessions", () => HttpResponse.json([LIST[0], other])),
|
||||
http.post("/api/sessions/:id/resume", ({ params }) =>
|
||||
resumeResult(params.id as string, params.id === "s3")),
|
||||
http.get("http://localhost:8787/sessions/:id", ({ params }) =>
|
||||
http.get("/api/sessions/:id", ({ params }) =>
|
||||
HttpResponse.json({ id: params.id, status: "open", phase: params.id === "s3" ? 3 : 1 })),
|
||||
);
|
||||
wrap();
|
||||
@@ -617,8 +629,8 @@ test("competing Resume requests for different ids commit only the latest intent"
|
||||
const s1Started = deferred();
|
||||
const s3Started = deferred();
|
||||
server.use(
|
||||
http.get("http://localhost:8787/sessions", () => HttpResponse.json([LIST[0], other])),
|
||||
http.post("http://localhost:8787/sessions/:id/resume", async ({ params }) => {
|
||||
http.get("/api/sessions", () => HttpResponse.json([LIST[0], other])),
|
||||
http.post("/api/sessions/:id/resume", async ({ params }) => {
|
||||
const id = params.id as string;
|
||||
if (id === "s1") {
|
||||
s1Started.resolve();
|
||||
@@ -629,7 +641,7 @@ test("competing Resume requests for different ids commit only the latest intent"
|
||||
}
|
||||
return resumeResult(id);
|
||||
}),
|
||||
http.get("http://localhost:8787/sessions/:id", ({ params }) =>
|
||||
http.get("/api/sessions/:id", ({ params }) =>
|
||||
HttpResponse.json({ id: params.id, status: "open", phase: params.id === "s3" ? 3 : 1 })),
|
||||
);
|
||||
wrap();
|
||||
@@ -667,10 +679,10 @@ test("a stale Resume manifest cannot repaint the latest session phase", async ()
|
||||
const s1ManifestGate = deferred();
|
||||
const s1ManifestStarted = deferred();
|
||||
server.use(
|
||||
http.get("http://localhost:8787/sessions", () => HttpResponse.json([LIST[0], other])),
|
||||
http.post("http://localhost:8787/sessions/:id/resume", ({ params }) =>
|
||||
http.get("/api/sessions", () => HttpResponse.json([LIST[0], other])),
|
||||
http.post("/api/sessions/:id/resume", ({ params }) =>
|
||||
resumeResult(params.id as string)),
|
||||
http.get("http://localhost:8787/sessions/:id", async ({ params }) => {
|
||||
http.get("/api/sessions/:id", async ({ params }) => {
|
||||
if (params.id === "s1") {
|
||||
s1ManifestStarted.resolve();
|
||||
await s1ManifestGate.promise;
|
||||
@@ -700,12 +712,12 @@ test("starting a new question invalidates a pending Resume intent", async () =>
|
||||
const resumeGate = deferred();
|
||||
const resumeStarted = deferred();
|
||||
server.use(
|
||||
http.post("http://localhost:8787/sessions/:id/resume", async () => {
|
||||
http.post("/api/sessions/:id/resume", async () => {
|
||||
resumeStarted.resolve();
|
||||
await resumeGate.promise;
|
||||
return resumeResult("s1");
|
||||
}),
|
||||
http.post("http://localhost:8787/runtime/prewarm", () =>
|
||||
http.post("/api/runtime/prewarm", () =>
|
||||
HttpResponse.json({ status: "warming" }, { status: 202 })),
|
||||
);
|
||||
wrap();
|
||||
@@ -728,12 +740,12 @@ test("a successful Delete invalidates an earlier pending Resume for the same tar
|
||||
const resumeStarted = deferred();
|
||||
const deleteCompleted = deferred();
|
||||
server.use(
|
||||
http.post("http://localhost:8787/sessions/:id/resume", async () => {
|
||||
http.post("/api/sessions/:id/resume", async () => {
|
||||
resumeStarted.resolve();
|
||||
await resumeGate.promise;
|
||||
return resumeResult("s1");
|
||||
}),
|
||||
http.delete("http://localhost:8787/sessions/:id", ({ params }) => {
|
||||
http.delete("/api/sessions/:id", ({ params }) => {
|
||||
expect(params.id).toBe("s1");
|
||||
deleteCompleted.resolve();
|
||||
return new HttpResponse(null, { status: 204 });
|
||||
@@ -760,14 +772,14 @@ test("a successful Delete detaches a Resume that commits while Delete is pending
|
||||
const deleteGate = deferred();
|
||||
const deleteStarted = deferred();
|
||||
server.use(
|
||||
http.delete("http://localhost:8787/sessions/:id", async ({ params }) => {
|
||||
http.delete("/api/sessions/:id", async ({ params }) => {
|
||||
expect(params.id).toBe("s1");
|
||||
deleteStarted.resolve();
|
||||
await deleteGate.promise;
|
||||
return new HttpResponse(null, { status: 204 });
|
||||
}),
|
||||
http.post("http://localhost:8787/sessions/:id/resume", () => resumeResult("s1")),
|
||||
http.get("http://localhost:8787/sessions/:id", () =>
|
||||
http.post("/api/sessions/:id/resume", () => resumeResult("s1")),
|
||||
http.get("/api/sessions/:id", () =>
|
||||
HttpResponse.json({ id: "s1", status: "open", phase: 1 })),
|
||||
);
|
||||
wrap();
|
||||
@@ -794,12 +806,12 @@ test("deleting another session does not invalidate a pending Resume", async () =
|
||||
const resumeStarted = deferred();
|
||||
const deleteCompleted = deferred();
|
||||
server.use(
|
||||
http.post("http://localhost:8787/sessions/:id/resume", async () => {
|
||||
http.post("/api/sessions/:id/resume", async () => {
|
||||
resumeStarted.resolve();
|
||||
await resumeGate.promise;
|
||||
return resumeResult("s1");
|
||||
}),
|
||||
http.delete("http://localhost:8787/sessions/:id", ({ params }) => {
|
||||
http.delete("/api/sessions/:id", ({ params }) => {
|
||||
expect(params.id).toBe("s2");
|
||||
deleteCompleted.resolve();
|
||||
return new HttpResponse(null, { status: 204 });
|
||||
@@ -831,8 +843,8 @@ test("deleting active A preserves a pending Resume for different session B", asy
|
||||
const s3ResumeGate = deferred();
|
||||
const s3ResumeStarted = deferred();
|
||||
server.use(
|
||||
http.get("http://localhost:8787/sessions", () => HttpResponse.json([LIST[0], other])),
|
||||
http.post("http://localhost:8787/sessions/:id/resume", async ({ params }) => {
|
||||
http.get("/api/sessions", () => HttpResponse.json([LIST[0], other])),
|
||||
http.post("/api/sessions/:id/resume", async ({ params }) => {
|
||||
const id = params.id as string;
|
||||
if (id === "s3") {
|
||||
s3ResumeStarted.resolve();
|
||||
@@ -840,9 +852,9 @@ test("deleting active A preserves a pending Resume for different session B", asy
|
||||
}
|
||||
return resumeResult(id);
|
||||
}),
|
||||
http.get("http://localhost:8787/sessions/:id", ({ params }) =>
|
||||
http.get("/api/sessions/:id", ({ params }) =>
|
||||
HttpResponse.json({ id: params.id, status: "open", phase: params.id === "s3" ? 3 : 1 })),
|
||||
http.delete("http://localhost:8787/sessions/:id", ({ params }) => {
|
||||
http.delete("/api/sessions/:id", ({ params }) => {
|
||||
expect(params.id).toBe("s1");
|
||||
return new HttpResponse(null, { status: 204 });
|
||||
}),
|
||||
@@ -876,12 +888,12 @@ test("a failed Delete does not invalidate a pending Resume for its target", asyn
|
||||
const resumeStarted = deferred();
|
||||
const deleteFailed = deferred();
|
||||
server.use(
|
||||
http.post("http://localhost:8787/sessions/:id/resume", async () => {
|
||||
http.post("/api/sessions/:id/resume", async () => {
|
||||
resumeStarted.resolve();
|
||||
await resumeGate.promise;
|
||||
return resumeResult("s1");
|
||||
}),
|
||||
http.delete("http://localhost:8787/sessions/:id", ({ params }) => {
|
||||
http.delete("/api/sessions/:id", ({ params }) => {
|
||||
expect(params.id).toBe("s1");
|
||||
deleteFailed.resolve();
|
||||
return new HttpResponse(null, { status: 500 });
|
||||
@@ -905,7 +917,7 @@ test("a failed Delete does not invalidate a pending Resume for its target", asyn
|
||||
});
|
||||
|
||||
test("a failed Resume with no active session preserves the panel and existing activity", async () => {
|
||||
server.use(http.post("http://localhost:8787/sessions/:id/resume", () => new HttpResponse(null, { status: 409 })));
|
||||
server.use(http.post("/api/sessions/:id/resume", () => new HttpResponse(null, { status: 409 })));
|
||||
useSessionStore.setState({
|
||||
activityLog: [{ kind: "status", phase: "F7", text: "Preserve activity", level: "info" }],
|
||||
});
|
||||
@@ -923,7 +935,7 @@ test("a failed Resume with no active session preserves the panel and existing ac
|
||||
|
||||
test("closing and reopening Model activity preserves the complete activity log", async () => {
|
||||
wrap();
|
||||
server.use(http.post("http://localhost:8787/sessions/:id/resume", () => resumeResult("s1")));
|
||||
server.use(http.post("/api/sessions/:id/resume", () => resumeResult("s1")));
|
||||
await userEvent.click(await screen.findByText("Attiva uno"));
|
||||
await userEvent.click(await screen.findByRole("button", { name: /resume/i }));
|
||||
act(() => {
|
||||
@@ -971,8 +983,8 @@ test("session finalization shows the completion banner and returns to landing",
|
||||
useSessionStore.getState().resetSession();
|
||||
let finalized = false;
|
||||
server.use(
|
||||
http.post("http://localhost:8787/sessions/:id/resume", () => resumeResult("s1")),
|
||||
http.get("http://localhost:8787/sessions", () =>
|
||||
http.post("/api/sessions/:id/resume", () => resumeResult("s1")),
|
||||
http.get("/api/sessions", () =>
|
||||
HttpResponse.json(finalized ? [{ ...LIST[0], status: "finalized" }] : LIST)),
|
||||
);
|
||||
wrap();
|
||||
@@ -995,7 +1007,7 @@ test("session finalization shows the completion banner and returns to landing",
|
||||
test("renaming a group reassigns its members via setSessionGroup", async () => {
|
||||
const groupSets: Array<{ id: string; group: string }> = [];
|
||||
server.use(
|
||||
http.post("http://localhost:8787/sessions/:id/group", async ({ params, request }) => {
|
||||
http.post("/api/sessions/:id/group", async ({ params, request }) => {
|
||||
const body = (await request.json()) as { group: string };
|
||||
groupSets.push({ id: params.id as string, group: body.group });
|
||||
return new HttpResponse(null, { status: 204 });
|
||||
@@ -1013,7 +1025,7 @@ test("renaming a group reassigns its members via setSessionGroup", async () => {
|
||||
|
||||
|
||||
test("opens an accessible resizable activity split and persists pointer width", async () => {
|
||||
server.use(http.post("http://localhost:8787/sessions/:id/resume", () => resumeResult("s1")));
|
||||
server.use(http.post("/api/sessions/:id/resume", () => resumeResult("s1")));
|
||||
wrap();
|
||||
await userEvent.click(await screen.findByText("Attiva uno"));
|
||||
await userEvent.click(await screen.findByRole("button", { name: /resume/i }));
|
||||
@@ -1043,7 +1055,7 @@ test("opens an accessible resizable activity split and persists pointer width",
|
||||
|
||||
test("resizes the activity split with keyboard and exposes responsive drawer classes", async () => {
|
||||
localStorage.setItem(ACTIVITY_PANEL_STORAGE_KEY, "448");
|
||||
server.use(http.post("http://localhost:8787/sessions/:id/resume", () => resumeResult("s1")));
|
||||
server.use(http.post("/api/sessions/:id/resume", () => resumeResult("s1")));
|
||||
wrap();
|
||||
await userEvent.click(await screen.findByText("Attiva uno"));
|
||||
await userEvent.click(await screen.findByRole("button", { name: /resume/i }));
|
||||
@@ -1070,7 +1082,7 @@ test("resizes the activity split with keyboard and exposes responsive drawer cla
|
||||
|
||||
test("uses the measured app shell for the desktop activity split", async () => {
|
||||
localStorage.setItem(ACTIVITY_PANEL_STORAGE_KEY, "576");
|
||||
server.use(http.post("http://localhost:8787/sessions/:id/resume", () => resumeResult("s1")));
|
||||
server.use(http.post("/api/sessions/:id/resume", () => resumeResult("s1")));
|
||||
wrap();
|
||||
await userEvent.click(await screen.findByText("Attiva uno"));
|
||||
await userEvent.click(await screen.findByRole("button", { name: /resume/i }));
|
||||
@@ -1092,7 +1104,7 @@ test("uses the measured app shell for the desktop activity split", async () => {
|
||||
|
||||
test("cancels an active resize when the measured shell becomes too narrow", async () => {
|
||||
localStorage.setItem(ACTIVITY_PANEL_STORAGE_KEY, "576");
|
||||
server.use(http.post("http://localhost:8787/sessions/:id/resume", () => resumeResult("s1")));
|
||||
server.use(http.post("/api/sessions/:id/resume", () => resumeResult("s1")));
|
||||
wrap();
|
||||
await userEvent.click(await screen.findByText("Attiva uno"));
|
||||
await userEvent.click(await screen.findByRole("button", { name: /resume/i }));
|
||||
|
||||
Reference in New Issue
Block a user