fix: stabilize terminal dashboard states
This commit is contained in:
@@ -1,8 +1,8 @@
|
||||
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
|
||||
import { focusManager, onlineManager, QueryClient, QueryClientProvider } from "@tanstack/react-query";
|
||||
import { act, renderHook, waitFor } from "@testing-library/react";
|
||||
import type { ReactNode } from "react";
|
||||
import type { Address } from "viem";
|
||||
import { beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import type { DashboardSnapshot, DeploymentManifest } from "../types/dashboard";
|
||||
import { useBankDashboard } from "./useBankDashboard";
|
||||
|
||||
@@ -55,8 +55,7 @@ function deferred<T>() {
|
||||
return { promise, resolve, reject };
|
||||
}
|
||||
|
||||
function createWrapper() {
|
||||
const client = new QueryClient({ defaultOptions: { queries: { retry: false, gcTime: 0 } } });
|
||||
function createWrapper(client = new QueryClient({ defaultOptions: { queries: { retry: false, gcTime: 0 } } })) {
|
||||
return function Wrapper({ children }: { children: ReactNode }) {
|
||||
return <QueryClientProvider client={client}>{children}</QueryClientProvider>;
|
||||
};
|
||||
@@ -65,6 +64,13 @@ function createWrapper() {
|
||||
describe("useBankDashboard", () => {
|
||||
beforeEach(() => {
|
||||
notifyBlock = undefined;
|
||||
focusManager.setFocused(true);
|
||||
onlineManager.setOnline(true);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
focusManager.setFocused(undefined);
|
||||
onlineManager.setOnline(true);
|
||||
});
|
||||
|
||||
it("starts in loading while the manifest and first reconciled snapshot are pending", () => {
|
||||
@@ -151,6 +157,52 @@ describe("useBankDashboard", () => {
|
||||
expect(loader).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it("does not retry a terminal manifest-fetch failure on focus, reconnect, or remount", async () => {
|
||||
const loadManifest = vi.fn().mockRejectedValue(new Error("manifest request failed"));
|
||||
const client = new QueryClient({ defaultOptions: { queries: { retry: false, gcTime: Number.POSITIVE_INFINITY } } });
|
||||
const wrapper = createWrapper(client);
|
||||
const options = { loadManifest, loader: vi.fn() };
|
||||
const first = renderHook(() => useBankDashboard(options), { wrapper });
|
||||
await waitFor(() => expect(first.result.current.status).toBe("invalid-manifest"));
|
||||
|
||||
await act(async () => {
|
||||
focusManager.setFocused(false);
|
||||
focusManager.setFocused(true);
|
||||
onlineManager.setOnline(false);
|
||||
onlineManager.setOnline(true);
|
||||
await new Promise((resolve) => setTimeout(resolve, 0));
|
||||
});
|
||||
first.unmount();
|
||||
const second = renderHook(() => useBankDashboard(options), { wrapper });
|
||||
await waitFor(() => expect(second.result.current.status).toBe("invalid-manifest"));
|
||||
|
||||
expect(loadManifest).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it("does not retry a terminal chain mismatch on focus, reconnect, or remount", async () => {
|
||||
const loader = vi.fn().mockRejectedValue(new Error(
|
||||
"endpoint chain ID 84532 does not match manifest chain ID 31337",
|
||||
));
|
||||
const client = new QueryClient({ defaultOptions: { queries: { retry: false, gcTime: Number.POSITIVE_INFINITY } } });
|
||||
const wrapper = createWrapper(client);
|
||||
const options = { loadManifest: async () => manifestJson, loader };
|
||||
const first = renderHook(() => useBankDashboard(options), { wrapper });
|
||||
await waitFor(() => expect(first.result.current.status).toBe("chain-mismatch"));
|
||||
|
||||
await act(async () => {
|
||||
focusManager.setFocused(false);
|
||||
focusManager.setFocused(true);
|
||||
onlineManager.setOnline(false);
|
||||
onlineManager.setOnline(true);
|
||||
await new Promise((resolve) => setTimeout(resolve, 0));
|
||||
});
|
||||
first.unmount();
|
||||
const second = renderHook(() => useBankDashboard(options), { wrapper });
|
||||
await waitFor(() => expect(second.result.current.status).toBe("chain-mismatch"));
|
||||
|
||||
expect(loader).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it("reconciles exactly once when a new watched block arrives", async () => {
|
||||
const nextSnapshot = { ...snapshot, blockNumber: 13n, synchronizedAt: new Date("2026-08-21T10:01:00.000Z") };
|
||||
const loader = vi.fn().mockResolvedValueOnce(snapshot).mockResolvedValueOnce(nextSnapshot);
|
||||
|
||||
Reference in New Issue
Block a user