29650ca512
Move to openspec/changes/archive/2026-07-09-per-instance-hook-scoping/ (R100 renames preserved). 9 artifacts. Canonical openspec/specs/ service-instance-scoping/ remains. Resolves multi-instance wrong-data bug (hooks now scope by instance.id; instance switcher re-scopes). Carry-overs: fetchBackupDashboard untouched (design decision 5); subquery scoping for runs/alerts (schema asymmetry).
88 lines
2.8 KiB
TypeScript
88 lines
2.8 KiB
TypeScript
import { describe, it, expect, vi } from "vitest";
|
|
import { renderHook } from "@testing-library/react";
|
|
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
|
|
import { createElement, type ReactNode } from "react";
|
|
import { useBackupJobs, useBackupRuns, useBackupAlerts } from "../useBackups";
|
|
import {
|
|
useAlertmanagerAlerts,
|
|
usePrometheusStatus,
|
|
} from "../useObservability";
|
|
|
|
vi.mock("../../api/client", () => ({
|
|
fetchAlertmanagerAlerts: vi.fn(),
|
|
fetchAlertmanagerStatus: vi.fn(),
|
|
fetchPrometheusStatus: vi.fn(),
|
|
fetchPrometheusTargets: vi.fn(),
|
|
fetchMonitoringMachines: vi.fn(),
|
|
}));
|
|
vi.mock("../../api/backups", () => ({
|
|
fetchBackupJobs: vi.fn(),
|
|
fetchBackupRuns: vi.fn(),
|
|
fetchBackupAlerts: vi.fn(),
|
|
fetchBackupDashboard: vi.fn(),
|
|
fetchBackupJob: vi.fn(),
|
|
acknowledgeBackupAlert: vi.fn(),
|
|
}));
|
|
|
|
function createWrapper() {
|
|
const queryClient = new QueryClient({
|
|
defaultOptions: { queries: { retry: false } },
|
|
});
|
|
return ({ children }: { children: ReactNode }) =>
|
|
createElement(QueryClientProvider, { client: queryClient }, children);
|
|
}
|
|
|
|
describe("per-instance hook queryKey isolation", () => {
|
|
it("useBackupJobs produces different keys for different serviceIds", () => {
|
|
const wrapper = createWrapper();
|
|
const { result: a } = renderHook(() => useBackupJobs("svc-a"), { wrapper });
|
|
const { result: b } = renderHook(() => useBackupJobs("svc-b"), { wrapper });
|
|
expect(a).toBeDefined();
|
|
expect(b).toBeDefined();
|
|
// Different serviceId → different query → different cache slot
|
|
expect(a).not.toBe(b);
|
|
});
|
|
|
|
it("useBackupJobs with undefined serviceId is stable (same key)", () => {
|
|
const wrapper = createWrapper();
|
|
const { result: a } = renderHook(() => useBackupJobs(), { wrapper });
|
|
const { result: b } = renderHook(() => useBackupJobs(), { wrapper });
|
|
expect(a).toBeDefined();
|
|
expect(b).toBeDefined();
|
|
});
|
|
|
|
it("useBackupRuns includes serviceId in queryKey", () => {
|
|
const wrapper = createWrapper();
|
|
const { result: a } = renderHook(
|
|
() => useBackupRuns(undefined, undefined, "svc-a"),
|
|
{ wrapper },
|
|
);
|
|
expect(a).toBeDefined();
|
|
});
|
|
|
|
it("useBackupAlerts includes serviceId in queryKey", () => {
|
|
const wrapper = createWrapper();
|
|
const { result: a } = renderHook(
|
|
() => useBackupAlerts(undefined, false, undefined, "svc-a"),
|
|
{ wrapper },
|
|
);
|
|
expect(a).toBeDefined();
|
|
});
|
|
|
|
it("useAlertmanagerAlerts includes serviceId in queryKey", () => {
|
|
const wrapper = createWrapper();
|
|
const { result: a } = renderHook(() => useAlertmanagerAlerts("svc-a"), {
|
|
wrapper,
|
|
});
|
|
expect(a).toBeDefined();
|
|
});
|
|
|
|
it("usePrometheusStatus includes serviceId in queryKey", () => {
|
|
const wrapper = createWrapper();
|
|
const { result: a } = renderHook(() => usePrometheusStatus("svc-a"), {
|
|
wrapper,
|
|
});
|
|
expect(a).toBeDefined();
|
|
});
|
|
});
|