forked from bots-garden/ori
| Add copy-paste functionality for code blocks and completion widgets | 1 | import { describe, it, expect, beforeEach, vi } from "vitest"; |
| 2 | import { render, screen, fireEvent, waitFor } from "@testing-library/react"; | |
| 3 | import { CopyButton } from "./CopyButton"; | |
| 4 | ||
| 5 | describe("CopyButton", () => { | |
| 6 | let mockWriteText: ReturnType<typeof vi.fn>; | |
| 7 | ||
| 8 | beforeEach(() => { | |
| 9 | mockWriteText = vi.fn(() => Promise.resolve()); | |
| 10 | // Mock clipboard API with secure context | |
| 11 | Object.assign(navigator, { | |
| 12 | clipboard: { | |
| 13 | writeText: mockWriteText, | |
| 14 | }, | |
| 15 | }); | |
| 16 | // Mock secure context | |
| 17 | Object.defineProperty(window, "isSecureContext", { | |
| 18 | value: true, | |
| 19 | writable: true, | |
| 20 | }); | |
| 21 | // Mock execCommand as fallback | |
| 22 | document.execCommand = vi.fn(() => true); | |
| 23 | }); | |
| 24 | ||
| 25 | it("renders with default label", () => { | |
| 26 | render(<CopyButton content="test content" />); | |
| 27 | const button = screen.getByRole("button", { name: "Copy" }); | |
| 28 | expect(button).toBeTruthy(); | |
| 29 | }); | |
| 30 | ||
| 31 | it("renders with custom label", () => { | |
| 32 | render(<CopyButton content="test" label="Copy code" />); | |
| 33 | const button = screen.getByRole("button", { name: "Copy code" }); | |
| 34 | expect(button).toBeTruthy(); | |
| 35 | }); | |
| 36 | ||
| 37 | it("copies content to clipboard on click", async () => { | |
| 38 | render(<CopyButton content="hello world" />); | |
| 39 | const button = screen.getByRole("button"); | |
| 40 | ||
| 41 | fireEvent.click(button); | |
| 42 | ||
| 43 | await waitFor(() => { | |
| 44 | expect(mockWriteText).toHaveBeenCalledWith("hello world"); | |
| 45 | }); | |
| 46 | }); | |
| 47 | ||
| 48 | it("shows copied state after click", async () => { | |
| 49 | render(<CopyButton content="test" />); | |
| 50 | const button = screen.getByRole("button"); | |
| 51 | ||
| 52 | fireEvent.click(button); | |
| 53 | ||
| 54 | // Button should show "Copied!" label after async operation | |
| 55 | await waitFor(() => { | |
| 56 | expect(button.getAttribute("aria-label")).toBe("Copied!"); | |
| 57 | expect(button.classList.contains("copy-btn-copied")).toBe(true); | |
| 58 | }); | |
| 59 | }); | |
| 60 | ||
| 61 | it("applies custom className", () => { | |
| 62 | render(<CopyButton content="test" className="custom-class" />); | |
| 63 | const button = screen.getByRole("button"); | |
| 64 | expect(button.classList.contains("custom-class")).toBe(true); | |
| 65 | }); | |
| 66 | }); |