import { describe, it, expect, beforeEach, afterEach, vi } from "vitest"; import { act, renderHook, waitFor } from "@testing-library/react"; import { useGitHubEnabled } from "./use-github-enabled"; import { makeLocalStorageMock } from "../../local-storage-mock.test-helpers"; import { resetIntegrationEnabledMigrations } from "../integrations/use-integration-enabled"; const STORAGE_KEY = "kandev:github:enabled:v1"; const localStorageMock = makeLocalStorageMock(); vi.stubGlobal("localStorage", localStorageMock); Object.defineProperty(window, "localStorage", { value: localStorageMock, configurable: true, }); describe("useGitHubEnabled", () => { beforeEach(() => { localStorageMock.clear(); resetIntegrationEnabledMigrations(); }); afterEach(() => { localStorageMock.clear(); }); it("defaults to enabled=true when no localStorage entry exists", async () => { const { result } = renderHook(() => useGitHubEnabled()); await waitFor(() => expect(result.current.loaded).toBe(true)); expect(result.current.enabled).toBe(true); }); it('reads enabled=false when stored as the literal string "false"', async () => { window.localStorage.setItem(STORAGE_KEY, "false"); const { result } = renderHook(() => useGitHubEnabled()); await waitFor(() => expect(result.current.loaded).toBe(true)); expect(result.current.enabled).toBe(false); }); it("setEnabled persists to localStorage and updates state", async () => { const { result } = renderHook(() => useGitHubEnabled()); await waitFor(() => expect(result.current.loaded).toBe(true)); act(() => result.current.setEnabled(false)); expect(result.current.enabled).toBe(false); expect(window.localStorage.getItem(STORAGE_KEY)).toBe("false"); }); it("propagates updates dispatched via the kandev:github:enabled-changed event", async () => { const { result } = renderHook(() => useGitHubEnabled()); await waitFor(() => expect(result.current.loaded).toBe(true)); expect(result.current.enabled).toBe(true); act(() => { window.localStorage.setItem(STORAGE_KEY, "false"); window.dispatchEvent(new Event("kandev:github:enabled-changed")); }); await waitFor(() => expect(result.current.enabled).toBe(false)); }); it("propagates updates delivered via the native storage event (cross-tab)", async () => { const { result } = renderHook(() => useGitHubEnabled()); await waitFor(() => expect(result.current.loaded).toBe(true)); act(() => { window.localStorage.setItem(STORAGE_KEY, "false"); window.dispatchEvent(new StorageEvent("storage", { key: STORAGE_KEY, newValue: "false" })); }); await waitFor(() => expect(result.current.enabled).toBe(false)); }); it("restores a legacy per-workspace key to that workspace's own key", async () => { // The pre-scoping keys were `kandev:github:enabled::v1`, one per // workspace, so each is restored to the workspace it came from rather than // folded into a single install-wide value. window.localStorage.setItem("kandev:github:enabled:ws-123:v1", "false"); const { result } = renderHook(() => useGitHubEnabled("ws-123")); await waitFor(() => expect(result.current.loaded).toBe(true)); expect(result.current.enabled).toBe(false); expect(window.localStorage.getItem(`${STORAGE_KEY}:ws-123`)).toBe("false"); expect(window.localStorage.getItem("kandev:github:enabled:ws-123:v1")).toBeNull(); // Another workspace is untouched by that migration. expect(renderHook(() => useGitHubEnabled("ws-other")).result.current.enabled).toBe(true); }); });