// @vitest-environment jsdom // // A Copy button beside its value: "Copied" for a moment and a notice a screen reader hears, or a // warning when the clipboard refused — the same at every such button. import { afterEach, describe, expect, it, vi } from "vitest"; import { act, renderHook } from "@testing-library/react"; const h = vi.hoisted(() => ({ copyText: vi.fn(async (_t: string) => true), notify: vi.fn() })); vi.mock("react-i18next", async (importOriginal) => ({ ...(await importOriginal()), useTranslation: () => ({ i18n: { language: "en" }, t: (key: string) => key }), })); vi.mock("../../lib/clipboard", () => ({ copyText: h.copyText })); vi.mock("../../lib/notifications", () => ({ notify: h.notify })); import { useCopyFeedback } from "./useCopyFeedback"; afterEach(() => { vi.useRealTimers(); h.notify.mockClear(); }); describe("useCopyFeedback", () => { it("a copy that worked reads Copied for a moment and is said out loud", async () => { vi.useFakeTimers(); const { result } = renderHook(() => useCopyFeedback()); await act(() => result.current.copy("sfl_x")); expect(h.copyText).toHaveBeenCalledWith("sfl_x"); expect(result.current.copied).toBe(true); expect(h.notify).toHaveBeenCalledWith({ level: "success", message: "common.copy.done" }); act(() => void vi.advanceTimersByTime(2000)); expect(result.current.copied).toBe(false); }); it("a copy again within the moment reads Copied for a whole moment again", async () => { vi.useFakeTimers(); const { result } = renderHook(() => useCopyFeedback()); await act(() => result.current.copy("sfl_x")); act(() => void vi.advanceTimersByTime(1500)); await act(() => result.current.copy("sfl_x")); act(() => void vi.advanceTimersByTime(1000)); // past the first copy's moment expect(result.current.copied).toBe(true); act(() => void vi.advanceTimersByTime(1000)); expect(result.current.copied).toBe(false); }); it("a copy the clipboard refused is a warning, and nothing reads Copied", async () => { h.copyText.mockResolvedValueOnce(false); const { result } = renderHook(() => useCopyFeedback()); await act(() => result.current.copy("sfl_x")); expect(result.current.copied).toBe(false); expect(h.notify).toHaveBeenCalledWith({ level: "warning", message: "common.copy.failed" }); }); });