| ... | ... | @@ -1,8 +1,13 @@ |
| 1 | | import { describe, expect, it } from "vite-plus/test"; |
| 1 | // @vitest-environment jsdom |
| 2 | |
| 3 | import { act, createElement } from "react"; |
| 4 | import { createRoot, type Root } from "react-dom/client"; |
| 5 | import { afterEach, beforeEach, describe, expect, it, vi } from "vite-plus/test"; |
| 2 | 6 | |
| 3 | 7 | import { |
| 4 | 8 | areShortcutModifierStatesEqual, |
| 5 | 9 | shortcutModifierStateAfterKeyboardEvent, |
| 10 | useShortcutModifierState, |
| 6 | 11 | type ShortcutModifierState, |
| 7 | 12 | } from "./shortcutModifierState"; |
| 8 | 13 | |
| ... | ... | @@ -13,6 +18,67 @@ const emptyState = (): ShortcutModifierState => ({ |
| 13 | 18 | shiftKey: false, |
| 14 | 19 | }); |
| 15 | 20 | |
| 21 | describe("useShortcutModifierState", () => { |
| 22 | let root: Root; |
| 23 | let container: HTMLDivElement; |
| 24 | |
| 25 | beforeEach(() => { |
| 26 | vi.stubGlobal("IS_REACT_ACT_ENVIRONMENT", true); |
| 27 | container = document.createElement("div"); |
| 28 | document.body.append(container); |
| 29 | root = createRoot(container); |
| 30 | }); |
| 31 | |
| 32 | afterEach(async () => { |
| 33 | await act(async () => root.unmount()); |
| 34 | container.remove(); |
| 35 | vi.unstubAllGlobals(); |
| 36 | }); |
| 37 | |
| 38 | it.each(["keyup", "paste", "blur"] as const)( |
| 39 | "does not render for unchanged modifiers after %s resets the state", |
| 40 | async (reset) => { |
| 41 | const render = vi.fn(); |
| 42 | function Consumer() { |
| 43 | render(useShortcutModifierState()); |
| 44 | return null; |
| 45 | } |
| 46 | await act(async () => { |
| 47 | root.render(createElement(Consumer)); |
| 48 | }); |
| 49 | const press = async (type: "keydown" | "keyup", key: string, shiftKey = false) => { |
| 50 | await act(async () => { |
| 51 | window.dispatchEvent(new KeyboardEvent(type, { key, shiftKey })); |
| 52 | }); |
| 53 | }; |
| 54 | |
| 55 | await press("keydown", "Shift", true); |
| 56 | expect(render).toHaveBeenLastCalledWith({ ...emptyState(), shiftKey: true }); |
| 57 | if (reset === "keyup") { |
| 58 | await press("keyup", "Shift"); |
| 59 | } else { |
| 60 | await act(async () => { |
| 61 | window.dispatchEvent(new Event(reset)); |
| 62 | }); |
| 63 | } |
| 64 | expect(render).toHaveBeenLastCalledWith(emptyState()); |
| 65 | render.mockClear(); |
| 66 | |
| 67 | for (const key of "typing") { |
| 68 | await press("keydown", key); |
| 69 | await press("keyup", key); |
| 70 | } |
| 71 | await act(async () => { |
| 72 | window.dispatchEvent(new Event("paste")); |
| 73 | window.dispatchEvent(new Event("blur")); |
| 74 | }); |
| 75 | expect(render).not.toHaveBeenCalled(); |
| 76 | await press("keydown", "Shift", true); |
| 77 | expect(render).toHaveBeenCalledExactlyOnceWith({ ...emptyState(), shiftKey: true }); |
| 78 | }, |
| 79 | ); |
| 80 | }); |
| 81 | |
| 16 | 82 | function keyboardEventLike(type: "keydown" | "keyup", init: Partial<KeyboardEvent>): KeyboardEvent { |
| 17 | 83 | return { |
| 18 | 84 | type, |