Skip to content
Source
Sign inSign up
Open History to see the last commit

PickPreload.test.ts

107 lines3.5 KB

1import { expect, it, vi } from "vite-plus/test";
2​
3import { START_PICK_CHANNEL } from "./GuestProtocol.ts";
4import "./PickPreload.ts";
5​
6const ipcListeners = vi.hoisted(() => new Map<string, Array<(...args: unknown[]) => void>>());
7​
8vi.mock("electron", () => ({
9 ipcRenderer: {
10 on: (channel: string, listener: (...args: unknown[]) => void) => {
11 ipcListeners.set(channel, [...(ipcListeners.get(channel) ?? []), listener]);
12 },
13 off: () => {},
14 send: () => {},
15 invoke: async () => undefined,
16 },
17}));
18​
19vi.mock("react-grab/primitives", () => ({ getElementContext: async () => null }));
20​
21const startAnnotation = (): ShadowRoot => {
22 vi.stubGlobal(
23 "ResizeObserver",
24 class {
25 observe() {}
26 disconnect() {}
27 },
28 );
29 using attachShadow = vi.spyOn(Element.prototype, "attachShadow");
30 for (const listener of ipcListeners.get(START_PICK_CHANNEL) ?? []) listener({}, undefined, false);
31 const shadowRoot = attachShadow.mock.results[0]?.value;
32 if (!(shadowRoot instanceof ShadowRoot)) throw new Error("annotation overlay did not start");
33 return shadowRoot;
34};
35​
36it("switches tools from the keyboard after a toolbar button is clicked", () => {
37 const shadowRoot = startAnnotation();
38 const region = Array.from(shadowRoot.querySelectorAll("button")).find(
39 (button) => button.textContent === "Region",
40 );
41 if (!region) throw new Error("Region toolbar button not found");
42​
43 region.focus();
44 region.click();
45 expect(document.documentElement.getAttribute("data-t3code-annotation-tool")).toBe("marquee");
46​
47 region.dispatchEvent(new KeyboardEvent("keydown", { key: "v", bubbles: true, composed: true }));
48​
49 expect(
50 document.documentElement.getAttribute("data-t3code-annotation-tool"),
51 "V should switch to Select while focus is on a toolbar button",
52 ).toBe("select");
53});
54​
55it("keeps the tool while typing a tool key in the comment", () => {
56 const shadowRoot = startAnnotation();
57 const comment = shadowRoot.querySelector("textarea");
58 if (!comment) throw new Error("comment textarea not found");
59​
60 comment.focus();
61 comment.dispatchEvent(new KeyboardEvent("keydown", { key: "r", bubbles: true, composed: true }));
62​
63 expect(document.documentElement.getAttribute("data-t3code-annotation-tool")).toBe("select");
64});
65​
66it("keeps comment keystrokes away from the page's capture-phase shortcuts", () => {
67 const pageShortcut = vi.fn((event: KeyboardEvent) => event.preventDefault());
68 window.addEventListener("keydown", pageShortcut, { capture: true });
69 const shadowRoot = startAnnotation();
70 const comment = shadowRoot.querySelector("textarea");
71 if (!comment) throw new Error("comment textarea not found");
72​
73 comment.focus();
74 const space = new KeyboardEvent("keydown", {
75 key: " ",
76 code: "Space",
77 bubbles: true,
78 cancelable: true,
79 composed: true,
80 });
81 comment.dispatchEvent(space);
82 window.removeEventListener("keydown", pageShortcut, { capture: true });
83​
84 expect(pageShortcut).not.toHaveBeenCalled();
85 expect(space.defaultPrevented).toBe(false);
86});
87​
88it("keeps the annotation when Escape dismisses an IME candidate in the comment", () => {
89 const shadowRoot = startAnnotation();
90 const comment = shadowRoot.querySelector("textarea");
91 if (!comment) throw new Error("comment textarea not found");
92​
93 comment.value = "draft";
94 comment.focus();
95 comment.dispatchEvent(
96 new KeyboardEvent("keydown", {
97 key: "Escape",
98 isComposing: true,
99 bubbles: true,
100 cancelable: true,
101 composed: true,
102 }),
103 );
104​
105 expect(shadowRoot.host.isConnected).toBe(true);
106 expect(comment.value).toBe("draft");
107});