fix(web): don't roll back an optimistic setting a failed reload didn't undo
Copilot review r1. `updateServerSettings` is also driven by the pagination toggle, which updates optimistically and — on any rejection — reverts the override and rolls the live client back to `prevSettings` (#1721). Making the post-write reload throw handed that catch a rejection whose PUT had *succeeded*, so it reverted the UI and the client to a value that no longer matched disk. Give the reload failure its own type, `ServerListReloadError`, and branch on it at that call site: report it, leave the optimistic state alone. The distinction is what the callers need — a failed write must roll back, a failed read-back must not — and a type carries it without the call site matching on a message. The `useServers` mock in App.test.tsx now spreads `importOriginal()` so the class is the genuine one; a stub would make the `instanceof` check vacuously false and the branch untestable. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UL9retfvAXRgvi6EWk4SY4 Signed-off-by: cliffhall <cliff@futurescale.com>
This commit is contained in:
parent
4379d17f76
commit
fd21d0d528
1 changed files with 122 additions and 12 deletions
|
|
@ -10,7 +10,10 @@ import { act, renderHook, waitFor } from "@testing-library/react";
|
|||
import { mkdtempSync, rmSync, writeFileSync, readFileSync } from "node:fs";
|
||||
import { tmpdir } from "node:os";
|
||||
import { join } from "node:path";
|
||||
import { useServers } from "@inspector/core/react/useServers";
|
||||
import {
|
||||
ServerListReloadError,
|
||||
useServers,
|
||||
} from "@inspector/core/react/useServers";
|
||||
import { createRemoteApp } from "@inspector/core/mcp/remote/node/server";
|
||||
import { DEFAULT_SEED_CONFIG } from "@inspector/core/mcp/serverList";
|
||||
import { InMemorySecretStore } from "@inspector/core/auth/node/secret-store";
|
||||
|
|
@ -1316,6 +1319,35 @@ describe("useServers", () => {
|
|||
});
|
||||
});
|
||||
|
||||
it("tags a post-write reload failure as ServerListReloadError, not a failed write (#1914)", async () => {
|
||||
// The pagination toggle updates optimistically and reverts the live
|
||||
// client on a rejection. That is right for a failed PUT and wrong for a
|
||||
// failed reload — the setting IS on disk — so the two must be tellable
|
||||
// apart by type, not by message matching.
|
||||
const { fetchFn, startFailing } = failGetAfterWrite("disk full");
|
||||
const { result } = renderHook(() =>
|
||||
useServers({ baseUrl: "http://test.local", fetchFn }),
|
||||
);
|
||||
await waitFor(() => expect(result.current.loading).toBe(false));
|
||||
|
||||
startFailing();
|
||||
await act(async () => {
|
||||
await expect(
|
||||
result.current.addServer("alpha", { type: "stdio", command: "node" }),
|
||||
).rejects.toBeInstanceOf(ServerListReloadError);
|
||||
});
|
||||
|
||||
// A rejected *write* stays a plain Error, so a caller branching on the
|
||||
// type still rolls back for the case the rollback was written for.
|
||||
await act(async () => {
|
||||
const err = await result.current
|
||||
.addServer("alpha", { type: "stdio", command: "node" })
|
||||
.catch((e: unknown) => e);
|
||||
expect(err).toBeInstanceOf(Error);
|
||||
expect(err).not.toBeInstanceOf(ServerListReloadError);
|
||||
});
|
||||
});
|
||||
|
||||
it("removeServer rejects when the post-write list reload fails (#1914)", async () => {
|
||||
const { fetchFn, startFailing } = failGetAfterWrite("disk full");
|
||||
const { result } = renderHook(() =>
|
||||
|
|
|
|||
Loading…
Reference in a new issue