fix(resume): recover cleanly after Pi exits
This commit is contained in:
@@ -116,6 +116,86 @@ test("resuming the active session reconnects its EventSource", async () => {
|
||||
expect(first.closed).toBe(true);
|
||||
});
|
||||
|
||||
test("same-session Resume reconnects only after the deferred POST succeeds", async () => {
|
||||
server.use(
|
||||
http.post("http://localhost:8787/sessions/:id/resume", () =>
|
||||
new HttpResponse(null, { status: 204 })),
|
||||
http.get("http://localhost:8787/sessions/:id", () =>
|
||||
HttpResponse.json({ id: "s1", status: "open", phase: 1 })),
|
||||
);
|
||||
wrap();
|
||||
await userEvent.click(await screen.findByText("Attiva uno"));
|
||||
await userEvent.click(await screen.findByRole("button", { name: /resume/i }));
|
||||
await waitFor(() => expect(FakeEventSource.instances).toHaveLength(1));
|
||||
const first = FakeEventSource.instances[0];
|
||||
|
||||
let releaseResume!: () => void;
|
||||
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 () => {
|
||||
markStarted();
|
||||
await resumeReleased;
|
||||
return new HttpResponse(null, { status: 204 });
|
||||
}));
|
||||
|
||||
await userEvent.click(screen.getByText("Attiva uno"));
|
||||
await userEvent.click(await screen.findByRole("button", { name: /resume/i }));
|
||||
await resumeStarted;
|
||||
expect(FakeEventSource.instances).toHaveLength(1);
|
||||
expect(first.closed).toBe(false);
|
||||
|
||||
releaseResume();
|
||||
await waitFor(() => expect(FakeEventSource.instances).toHaveLength(2));
|
||||
expect(first.closed).toBe(true);
|
||||
});
|
||||
|
||||
test("a failed same-session Resume does not create a replacement EventSource", async () => {
|
||||
server.use(
|
||||
http.post("http://localhost:8787/sessions/:id/resume", () =>
|
||||
new HttpResponse(null, { status: 204 })),
|
||||
http.get("http://localhost:8787/sessions/:id", () =>
|
||||
HttpResponse.json({ id: "s1", status: "open", phase: 1 })),
|
||||
);
|
||||
wrap();
|
||||
await userEvent.click(await screen.findByText("Attiva uno"));
|
||||
await userEvent.click(await screen.findByRole("button", { name: /resume/i }));
|
||||
await waitFor(() => expect(FakeEventSource.instances).toHaveLength(1));
|
||||
|
||||
server.use(http.post("http://localhost:8787/sessions/:id/resume", () =>
|
||||
new HttpResponse(null, { status: 409 })));
|
||||
await userEvent.click(screen.getByText("Attiva uno"));
|
||||
await userEvent.click(await screen.findByRole("button", { name: /resume/i }));
|
||||
await waitFor(() => expect(screen.getByText("Domanda originale")).toBeInTheDocument());
|
||||
|
||||
expect(FakeEventSource.instances).toHaveLength(1);
|
||||
});
|
||||
|
||||
test("resuming a different session opens exactly one new EventSource", async () => {
|
||||
const other = {
|
||||
...LIST[0], id: "s3", question: "Attiva tre", group: null,
|
||||
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", () =>
|
||||
new HttpResponse(null, { status: 204 })),
|
||||
http.get("http://localhost:8787/sessions/:id", ({ params }) =>
|
||||
HttpResponse.json({ id: params.id, status: "open", phase: params.id === "s3" ? 3 : 1 })),
|
||||
);
|
||||
wrap();
|
||||
await userEvent.click(await screen.findByText("Attiva uno"));
|
||||
await userEvent.click(await screen.findByRole("button", { name: /resume/i }));
|
||||
await waitFor(() => expect(FakeEventSource.instances).toHaveLength(1));
|
||||
|
||||
await userEvent.click(screen.getByText("Attiva tre"));
|
||||
await userEvent.click(await screen.findByRole("button", { name: /resume/i }));
|
||||
await waitFor(() => expect(useSessionStore.getState().currentPhase).toBe("F3"));
|
||||
|
||||
expect(FakeEventSource.instances).toHaveLength(2);
|
||||
expect(FakeEventSource.instances[1].url).toContain("/sessions/s3/events");
|
||||
});
|
||||
|
||||
test("a failed resume keeps the panel open and does not activate the session", async () => {
|
||||
server.use(http.post("http://localhost:8787/sessions/:id/resume", () => new HttpResponse(null, { status: 409 })));
|
||||
wrap();
|
||||
|
||||
Reference in New Issue
Block a user