import * as Clipboard from "expo-clipboard"; import { clearClipboardNow, copyToClipboard } from "../clipboard"; jest.mock("expo-clipboard", () => { let value = ""; return { setStringAsync: jest.fn(async (v) => { value = v; return true; }), getStringAsync: async () => value, __get: () => value, }; }); const setStringAsync = Clipboard.setStringAsync as jest.MockedFunction< typeof Clipboard.setStringAsync >; describe("copyToClipboard", () => { beforeEach(() => { setStringAsync.mockClear(); jest.useFakeTimers(); }); afterEach(() => { jest.useRealTimers(); }); it("writes the value and schedules a 30s auto-clear", async () => { const ok = await copyToClipboard("secret"); expect(ok).toBe(true); expect(setStringAsync).toHaveBeenLastCalledWith("secret"); jest.advanceTimersByTime(30_000); expect(setStringAsync).toHaveBeenLastCalledWith(""); }); it("re-scheduling cancels the prior auto-clear", async () => { await copyToClipboard("first"); jest.advanceTimersByTime(15_000); await copyToClipboard("second"); jest.advanceTimersByTime(15_000); // Still inside the second copy's window — auto-clear hasn't fired. expect(setStringAsync).toHaveBeenLastCalledWith("second"); }); it("clearClipboardNow wipes immediately and cancels pending timers", async () => { await copyToClipboard("x"); await clearClipboardNow(); expect(setStringAsync).toHaveBeenLastCalledWith(""); setStringAsync.mockClear(); jest.advanceTimersByTime(60_000); expect(setStringAsync).not.toHaveBeenCalled(); }); it("returns false when the platform refuses the write", async () => { setStringAsync.mockResolvedValueOnce(false); expect(await copyToClipboard("nope")).toBe(false); }); });