|
1 | | -import type { DevframeDocksUserSettings } from '@devframes/hub' |
| 1 | +import type { DevframeDocksUserSettings, DevframeServerCommandEntry } from '@devframes/hub' |
2 | 2 | import type { DevframeRpcClient } from '@devframes/hub/client' |
| 3 | +import { DEFAULT_STATE_USER_SETTINGS, HUB_EVENTS } from '@devframes/hub/constants' |
3 | 4 | import { createSharedState } from 'devframe/utils/shared-state' |
4 | | -import { afterEach, expect, it, vi } from 'vitest' |
| 5 | +import { afterEach, describe, expect, it, vi } from 'vitest' |
5 | 6 | import { effectScope, nextTick, shallowRef } from 'vue' |
6 | 7 | import { createCommandsContext } from './commands' |
7 | 8 | import { isMac } from './keybindings' |
@@ -65,3 +66,61 @@ it.each(['standalone', 'shadow-root', 'popup'] as const)('leaves recording keyst |
65 | 66 | scope.stop() |
66 | 67 | } |
67 | 68 | }) |
| 69 | + |
| 70 | +describe('command shortcut eligibility', () => { |
| 71 | + it('ignores saved and default bindings while preserving explicit calls and palette shortcuts', async () => { |
| 72 | + const command = { |
| 73 | + id: 'tool:open-file', |
| 74 | + title: 'Open File', |
| 75 | + source: 'server', |
| 76 | + showInPalette: false, |
| 77 | + allowShortcuts: false, |
| 78 | + keybindings: [{ key: 'Alt+E' }], |
| 79 | + } satisfies DevframeServerCommandEntry |
| 80 | + const serverState = createSharedState<DevframeServerCommandEntry[]>({ initialValue: [command] }) |
| 81 | + const settings = createSharedState({ |
| 82 | + initialValue: { |
| 83 | + ...DEFAULT_STATE_USER_SETTINGS(), |
| 84 | + commandShortcuts: { [command.id]: [{ key: 'Alt+Y' }] }, |
| 85 | + }, |
| 86 | + }) |
| 87 | + const call = vi.fn() |
| 88 | + // eslint-disable-next-line slop/no-chained-type-assertions -- the command context only needs these two RPC APIs. |
| 89 | + const rpc = { sharedState: { get: async () => serverState }, call } as unknown as DevframeRpcClient |
| 90 | + const window = new EventTarget() |
| 91 | + vi.stubGlobal('window', window) |
| 92 | + const context = await createCommandsContext('embedded', rpc, settings) |
| 93 | + const openPalette = vi.fn() |
| 94 | + context.register({ |
| 95 | + id: 'tool:palette', |
| 96 | + title: 'Toggle Palette', |
| 97 | + source: 'client', |
| 98 | + showInPalette: false, |
| 99 | + keybindings: [{ key: 'Alt+K' }], |
| 100 | + action: openPalette, |
| 101 | + }) |
| 102 | + |
| 103 | + const press = (key: string) => window.dispatchEvent(Object.assign(new Event('keydown', { cancelable: true }), { |
| 104 | + key, |
| 105 | + altKey: true, |
| 106 | + ctrlKey: false, |
| 107 | + metaKey: false, |
| 108 | + shiftKey: false, |
| 109 | + })) |
| 110 | + |
| 111 | + const unhandled = press('y') |
| 112 | + expect(call).not.toHaveBeenCalled() |
| 113 | + expect(unhandled).toBe(true) |
| 114 | + expect(context.getKeybindings(command.id)).toEqual([]) |
| 115 | + settings.mutate((state) => { |
| 116 | + delete state.commandShortcuts[command.id] |
| 117 | + }) |
| 118 | + expect(press('e')).toBe(true) |
| 119 | + expect(call).not.toHaveBeenCalled() |
| 120 | + |
| 121 | + press('k') |
| 122 | + expect(openPalette).toHaveBeenCalledOnce() |
| 123 | + await context.execute(command.id, 'src/main.ts') |
| 124 | + expect(call).toHaveBeenCalledExactlyOnceWith(HUB_EVENTS.rpc.commandsExecute, command.id, 'src/main.ts') |
| 125 | + }) |
| 126 | +}) |
0 commit comments