diff options
Diffstat (limited to 'src/features/layout/store.test.ts')
| -rw-r--r-- | src/features/layout/store.test.ts | 71 |
1 files changed, 68 insertions, 3 deletions
diff --git a/src/features/layout/store.test.ts b/src/features/layout/store.test.ts index 1d4cdf0..73850ed 100644 --- a/src/features/layout/store.test.ts +++ b/src/features/layout/store.test.ts @@ -1,4 +1,9 @@ -import { DEFAULT_LAYOUT, type LayoutTree } from "@dispatch/layout-contract"; +import { + type ApplyOpsResult, + DEFAULT_LAYOUT, + type LayoutOp, + type LayoutTree, +} from "@dispatch/layout-contract"; import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; import type { LayoutHttp, LayoutHttpResult } from "./adapter/http"; import { overlaySidePanels } from "./logic/seed"; @@ -15,8 +20,11 @@ import { createLayoutStore } from "./store.svelte"; interface HttpFake extends LayoutHttp { getCalls: string[]; putCalls: Array<{ workspaceId: string; tree: LayoutTree }>; + deleteCalls: string[]; getResult: (workspaceId: string) => LayoutHttpResult; putResult: (workspaceId: string, tree: LayoutTree) => LayoutHttpResult; + deleteResult: (workspaceId: string) => LayoutHttpResult; + opsResult: (workspaceId: string, ops: readonly LayoutOp[]) => ApplyOpsResult; } function fakeHttp( @@ -32,11 +40,18 @@ function fakeHttp( ): HttpFake { const getCalls: string[] = []; const putCalls: Array<{ workspaceId: string; tree: LayoutTree }> = []; + const deleteCalls: string[] = []; const fake: HttpFake = { getCalls, putCalls, + deleteCalls, getResult, putResult, + // Re-scriptable outcome (default: the fresh seed a reset returns). + deleteResult: () => ({ ok: true, tree: DEFAULT_LAYOUT }), + // Re-scriptable outcome (default: the typed no-provider failure the ABI + // documents; tests re-assign mid-test like putResult). + opsResult: () => ({ ok: false, error: "no layout provider active" }), // Delegate to the CURRENT properties so a test can re-script outcomes // mid-test (http.putResult = …). async getTree(workspaceId) { @@ -47,8 +62,12 @@ function fakeHttp( putCalls.push({ workspaceId, tree }); return fake.putResult(workspaceId, tree); }, - async deleteTree() { - return { ok: false, notFound: true, error: "unused" }; + async deleteTree(workspaceId) { + deleteCalls.push(workspaceId); + return fake.deleteResult(workspaceId); + }, + async postOps(workspaceId, ops) { + return fake.opsResult(workspaceId, ops); }, }; return fake; @@ -424,3 +443,49 @@ describe("layout store — one-way localStorage migration (§2.7)", () => { ]); }); }); + +describe("layout store — resetToDefault (plan 04 §4.4, the reset affordance)", () => { + it("DELETEs the workspace's layout, applies the fresh seed, and resolves null", async () => { + const custom = overlaySidePanels(DEFAULT_LAYOUT, ["extensions"]); + const http = fakeHttp(); + // The DELETE returns the FRESH SEED (the server re-seeded). + http.deleteResult = () => ({ ok: true, tree: DEFAULT_LAYOUT }); + const store = makeStore(http); + + // Get to a NON-default tree first: a present provider + a pushed edit. + http.getResult = () => ({ ok: true, tree: custom }); + await store.probe("ws-a"); + expect(store.tree).toEqual(custom); + + const failure = await store.resetToDefault("ws-a"); + expect(failure).toBeNull(); + expect(http.deleteCalls).toEqual(["ws-a"]); + // The fresh seed is applied locally (the WS broadcast echo is idempotent). + expect(store.tree).toEqual(DEFAULT_LAYOUT); + expect(store.providerState).toBe("present"); + }); + + it("a 404 (no provider) resolves to the user-facing 'no layout plugin enabled' reason", async () => { + const http = fakeHttp(); + http.deleteResult = () => ({ + ok: false, + notFound: true, + error: "No layout provider is active", + }); + const store = makeStore(http); + + const failure = await store.resetToDefault("ws-a"); + expect(failure).toBe("no layout plugin enabled"); + expect(store.tree).toEqual(DEFAULT_LAYOUT); // untouched local default + }); + + it("another failure (5xx on a present provider) resolves to its error message", async () => { + const http = fakeHttp(() => ({ ok: true, tree: DEFAULT_LAYOUT })); + http.deleteResult = () => ({ ok: false, notFound: false, error: "storage write failed" }); + const store = makeStore(http); + await store.probe("ws-a"); + + const failure = await store.resetToDefault("ws-a"); + expect(failure).toBe("storage write failed"); + }); +}); |
