Open History to see the last commit
1import { describe, expect, it, vi } from "vite-plus/test";
2import { page, userEvent } from "vite-plus/test/browser";
3
4import "~/index.css";
5import { render } from "../../../test/render";
6import { MarkdownCodeBlock } from "./MarkdownCodeBlock";
7import { MarkdownTable } from "./MarkdownTable";
8
9// Insecure origins (a LAN or tailnet address over plain http) have no async clipboard.
10function withoutAsyncClipboard() {
11 const original = Object.getOwnPropertyDescriptor(Navigator.prototype, "clipboard");
12 Object.defineProperty(navigator, "clipboard", { configurable: true, value: undefined });
13 const execCommand = vi.spyOn(document, "execCommand").mockReturnValue(true);
14 return {
15 execCommand,
16 [Symbol.dispose]() {
17 execCommand.mockRestore();
18 Reflect.deleteProperty(navigator, "clipboard");
19 if (original) Object.defineProperty(Navigator.prototype, "clipboard", original);
20 },
21 };
22}
23
24describe("markdown copy without the async clipboard", () => {
25 it("copies a code block through the execCommand fallback", async () => {
26 await using screen = await render(
27 <MarkdownCodeBlock
28 code="echo hi"
29 language="sh"
30 fenceTitle={null}
31 theme="light"
32 isStreaming={false}
33 >
34 <pre>
35 <code>echo hi</code>
36 </pre>
37 </MarkdownCodeBlock>,
38 // The block renders no links and reads no route.
39 { router: false },
40 );
41 using clipboard = withoutAsyncClipboard();
42
43 await userEvent.click(screen.getByRole("button", { name: "Copy code" }));
44 await expect.element(screen.getByRole("button", { name: "Copied" })).toBeInTheDocument();
45 expect(clipboard.execCommand).toHaveBeenCalledWith("copy");
46 });
47
48 it("copies a table through the execCommand fallback", async () => {
49 await using screen = await render(
50 <MarkdownTable>
51 <thead>
52 <tr>
53 <th>Name</th>
54 </tr>
55 </thead>
56 <tbody>
57 <tr>
58 <td>Ada</td>
59 </tr>
60 </tbody>
61 </MarkdownTable>,
62 // The table renders no links and reads no route.
63 { router: false },
64 );
65 using clipboard = withoutAsyncClipboard();
66
67 await userEvent.click(screen.getByRole("button", { name: "Copy table" }));
68 await userEvent.click(page.getByRole("menuitem", { name: "Copy as Markdown" }));
69 await expect.element(screen.getByRole("button", { name: "Copied" })).toBeInTheDocument();
70 expect(clipboard.execCommand).toHaveBeenCalledWith("copy");
71 });
72});