import { describe, test, expect, vi, afterEach, beforeEach } from 'vitest'; import React from 'react'; import { renderEditorHarness, EditorHarness } from '../../test-utils/editorHarness'; import { registerCommands, __resetCommandsForTests } from '../../editor/commands'; import { TopBarCommandMenu } from './TopBarCommandMenu'; let h: EditorHarness; const run = vi.fn(); beforeEach(() => { __resetCommandsForTests(); run.mockReset(); registerCommands([ { id: 'site.download', title: 'Download site', group: 'site', shortcut: 'mod+shift+e', run }, { id: 'site.disabled', title: 'Disabled thing', group: 'site', when: () => false, run }, { id: 'site.hidden', title: 'Hidden thing', group: 'site', hidden: true, run }, { id: 'edit.duplicate', title: 'Duplicate', group: 'edit', run }, ]); h = renderEditorHarness(); h.mountChild(); }); afterEach(() => { h.unmount(); __resetCommandsForTests(); }); const button = () => h.container.querySelector('.topbar-command-btn') as HTMLButtonElement; const items = () => Array.from(h.container.querySelectorAll('.topbar-command-item')) as HTMLButtonElement[]; describe('TopBarCommandMenu', () => { test('lists only visible site commands, with shortcut labels and disabled state', () => { expect(items()).toHaveLength(0); h.act(() => button().click()); const titles = items().map((i) => i.querySelector('.topbar-command-title')!.textContent); expect(titles).toEqual(['Download site', 'Disabled thing']); expect(items()[0].querySelector('.topbar-command-shortcut')!.textContent).toMatch(/Shift\+E$|⇧E$/); expect(items()[0].disabled).toBe(false); expect(items()[1].disabled).toBe(true); }); test('click runs the command and closes the menu', async () => { h.act(() => button().click()); await h.act(async () => { items()[0].click(); }); expect(run).toHaveBeenCalledTimes(1); expect(items()).toHaveLength(0); }); test('disabled item does not run', async () => { h.act(() => button().click()); await h.act(async () => { items()[1].click(); }); expect(run).not.toHaveBeenCalled(); }); test('Escape closes; outside mousedown closes', () => { h.act(() => button().click()); expect(items().length).toBeGreaterThan(0); h.act(() => { document.dispatchEvent(new KeyboardEvent('keydown', { key: 'Escape', bubbles: true })); }); expect(items()).toHaveLength(0); h.act(() => button().click()); h.act(() => { document.body.dispatchEvent(new MouseEvent('mousedown', { bubbles: true })); }); expect(items()).toHaveLength(0); }); test('late registration shows up without reopening', () => { h.act(() => button().click()); h.act(() => { registerCommands([{ id: 'site.late', title: 'Late one', group: 'site', run }]); }); expect(items().map((i) => i.textContent)).toContain('Late one'); }); });