// @vitest-environment jsdom // // Escape closes the topmost layer only — the wizard included (deep-review round 4). Its own Escape // was a raw `document` listener with no layer check, and document listeners run before the window // listener ui/Modal uses: a sync that failed inside the wizard opens the global error dialog, and one // Esc dismissed the error AND ended onboarding, skipping the write-scope step. import { describe, it, expect, vi, beforeEach, afterEach } from "vitest"; import { render, cleanup, screen, fireEvent } from "@testing-library/react"; import { QueryClient, QueryClientProvider } from "@tanstack/react-query"; vi.mock("react-i18next", async (importOriginal) => { const actual = await importOriginal(); return { ...actual, useTranslation: () => ({ t: (key: string) => key, i18n: { language: "en" } }), Trans: ({ i18nKey }: { i18nKey: string }) => i18nKey, }; }); vi.mock("../lib/onboarding", () => ({ beginGrant: vi.fn(), endOnboarding: vi.fn() })); import OnboardingWizard from "./OnboardingWizard"; import Modal from "./ui/Modal"; import { api, type Me } from "../lib/api"; const me = { id: 1, email: "a@b", can_read: false, can_write: false } as unknown as Me; beforeEach(() => { vi.spyOn(api, "myStatus").mockResolvedValue({ channels_total: 0 } as never); }); afterEach(() => { cleanup(); vi.restoreAllMocks(); }); describe("the onboarding wizard's Escape", () => { const mount = (onClose: () => void, dialog: boolean) => render( {dialog && ( {}}>

the sync failed

)}
, ); it("closes the wizard when nothing is open above it", () => { const onClose = vi.fn(); mount(onClose, false); fireEvent.keyDown(document, { key: "Escape" }); expect(onClose).toHaveBeenCalledTimes(1); }); it("leaves the wizard alone while a dialog is open over it", () => { const onClose = vi.fn(); mount(onClose, true); fireEvent.keyDown(screen.getByText("the sync failed"), { key: "Escape" }); expect(onClose).not.toHaveBeenCalled(); }); });