Files
clean-architecture-frontend…/tests/component/server-state-scope-provider.test.tsx
T
2026-08-01 19:39:59 +09:00

84 lines
2.6 KiB
TypeScript

// @vitest-environment jsdom
import { act, render, screen, waitFor } from "@testing-library/react";
import { afterEach, describe, expect, it } from "vitest";
import { createServerStateScopeRuntime } from "../../src/adapters/query-cache/server-state-scope-runtime.ts";
import { ServerStateScopeProvider } from "../../src/presentation/adapters/query/server-state-scope-provider.tsx";
const activeRuntimes: Array<{ dispose(): void }> = [];
afterEach(() => {
for (const runtime of activeRuntimes.splice(0)) runtime.dispose();
});
function scopeFixture(resetLocal: () => Promise<void>) {
let sessionListener: () => void = () => {};
let token = 0;
const runtime = createServerStateScopeRuntime({
session: {
subscribe(listener) {
sessionListener = listener;
return () => {};
},
},
queryInvalidation: {
resetLocal,
},
tokenFactory: () => `scope-provider-token-${String(token++).padStart(4, "0")}`,
});
activeRuntimes.push(runtime);
return { runtime, triggerSessionChange: () => sessionListener() };
}
describe("server-state scope provider", () => {
it("removes previous-scope children synchronously while reset is pending", async () => {
let completeReset: () => void = () => {};
const reset = new Promise<void>((resolve) => {
completeReset = resolve;
});
const fixture = scopeFixture(async () => reset);
render(
<ServerStateScopeProvider
runtime={fixture.runtime}
transitionFallback={<div>scope-transition</div>}
>
<div>previous-account-secret</div>
</ServerStateScopeProvider>,
);
expect(screen.getByText("previous-account-secret")).toBeVisible();
act(() => fixture.triggerSessionChange());
expect(screen.queryByText("previous-account-secret")).toBeNull();
expect(screen.getByText("scope-transition")).toBeVisible();
completeReset();
await waitFor(() =>
expect(screen.getByText("previous-account-secret")).toBeVisible(),
);
});
it("never remounts previous-scope children after mandatory cleanup failure", async () => {
const fixture = scopeFixture(async () => {
throw new Error("reset failed");
});
render(
<ServerStateScopeProvider
runtime={fixture.runtime}
transitionFallback={<div>scope-transition</div>}
>
<div>previous-account-secret</div>
</ServerStateScopeProvider>,
);
act(() => fixture.triggerSessionChange());
await waitFor(() => expect(fixture.runtime.getPhase()).toBe("FAILED"));
expect(screen.queryByText("previous-account-secret")).toBeNull();
expect(screen.getByText("scope-transition")).toBeVisible();
});
});