|
|
@@ -22,34 +22,36 @@ vi.mock('@/context/theme-provider', () => ({
|
|
|
useTheme: () => ({ setTheme: mocks.setTheme }),
|
|
|
}))
|
|
|
|
|
|
-/**
|
|
|
- * Matches SearchProvider (`metaKey || ctrlKey` + `key === 'k'`).
|
|
|
- * Use real key delivery via `userEvent.keyboard` so the document listener sees a trusted-like sequence (see Vitest browser interactivity).
|
|
|
- */
|
|
|
-async function toggleCommandPaletteShortcut() {
|
|
|
- await userEvent.keyboard('{Control>}k{/Control}')
|
|
|
-}
|
|
|
-
|
|
|
-async function flushEffects() {
|
|
|
- await new Promise<void>((resolve) => {
|
|
|
- requestAnimationFrame(() => {
|
|
|
- requestAnimationFrame(() => resolve())
|
|
|
- })
|
|
|
- })
|
|
|
-}
|
|
|
+type ShortcutModifier = 'Control' | 'Meta'
|
|
|
|
|
|
async function renderWithSearchProvider() {
|
|
|
- const screen = await render(<SearchProvider>{null}</SearchProvider>)
|
|
|
- await flushEffects()
|
|
|
- return screen
|
|
|
+ return await render(<SearchProvider>{null}</SearchProvider>)
|
|
|
}
|
|
|
|
|
|
-async function openCommandPalette(screen: RenderResult) {
|
|
|
- await toggleCommandPaletteShortcut()
|
|
|
- await vi.waitFor(() =>
|
|
|
- expect(
|
|
|
- screen.getByPlaceholder(COMMAND_MENU_PLACEHOLDER)
|
|
|
- ).toBeInTheDocument()
|
|
|
+/**
|
|
|
+ * Open the palette by shortcut, retrying while the keydown listener may not be mounted yet.
|
|
|
+ * Waits between attempts so a successful toggle is not immediately undone by a second chord.
|
|
|
+ */
|
|
|
+async function openCommandPalette(
|
|
|
+ screen: RenderResult,
|
|
|
+ modifier: ShortcutModifier = 'Control'
|
|
|
+) {
|
|
|
+ await vi.waitFor(
|
|
|
+ async () => {
|
|
|
+ const isCommandPaletteOpen =
|
|
|
+ document.querySelector(
|
|
|
+ `[placeholder="${COMMAND_MENU_PLACEHOLDER}"]`
|
|
|
+ ) !== null
|
|
|
+
|
|
|
+ if (!isCommandPaletteOpen) {
|
|
|
+ await userEvent.keyboard(`{${modifier}>}k{/${modifier}}`)
|
|
|
+ }
|
|
|
+
|
|
|
+ expect(
|
|
|
+ screen.getByPlaceholder(COMMAND_MENU_PLACEHOLDER)
|
|
|
+ ).toBeInTheDocument()
|
|
|
+ },
|
|
|
+ { interval: 50, timeout: 5000 }
|
|
|
)
|
|
|
}
|
|
|
|
|
|
@@ -78,19 +80,25 @@ describe('SearchProvider and CommandMenu', () => {
|
|
|
expect(getByPlaceholder(COMMAND_MENU_PLACEHOLDER)).not.toBeInTheDocument()
|
|
|
})
|
|
|
|
|
|
- it('opens the command menu when the Cmd/Ctrl + K shortcut is pressed', async () => {
|
|
|
- const screen = await renderWithSearchProvider()
|
|
|
+ it.each([
|
|
|
+ ['Ctrl', 'Control'],
|
|
|
+ ['Cmd', 'Meta'],
|
|
|
+ ] as const)(
|
|
|
+ 'opens the command menu when %s + K is pressed',
|
|
|
+ async (_label, modifier) => {
|
|
|
+ const screen = await renderWithSearchProvider()
|
|
|
|
|
|
- expect(
|
|
|
- screen.getByPlaceholder(COMMAND_MENU_PLACEHOLDER)
|
|
|
- ).not.toBeInTheDocument()
|
|
|
+ expect(
|
|
|
+ screen.getByPlaceholder(COMMAND_MENU_PLACEHOLDER)
|
|
|
+ ).not.toBeInTheDocument()
|
|
|
|
|
|
- await openCommandPalette(screen)
|
|
|
+ await openCommandPalette(screen, modifier)
|
|
|
|
|
|
- expect(
|
|
|
- screen.getByPlaceholder(COMMAND_MENU_PLACEHOLDER)
|
|
|
- ).toBeInTheDocument()
|
|
|
- })
|
|
|
+ expect(
|
|
|
+ screen.getByPlaceholder(COMMAND_MENU_PLACEHOLDER)
|
|
|
+ ).toBeInTheDocument()
|
|
|
+ }
|
|
|
+ )
|
|
|
|
|
|
it('navigates to a top-level route and closes the palette when a nav item is selected', async () => {
|
|
|
const screen = await renderWithSearchProvider()
|