import { describe, expect, it } from 'vitest'; import { createTextContextMenuTemplate, type TextContextMenuContext, } from '@electron/main/context-menu'; type ContextOverrides = { isEditable?: boolean; selectionText?: string; editFlags?: Partial; }; function context(overrides: ContextOverrides = {}): TextContextMenuContext { return { isEditable: overrides.isEditable ?? false, selectionText: overrides.selectionText ?? '', editFlags: { canUndo: false, canRedo: false, canCut: false, canCopy: false, canPaste: false, canDelete: false, canSelectAll: false, canEditRichly: false, ...overrides.editFlags, }, }; } function enabledByRole(template: Electron.MenuItemConstructorOptions[] | null) { return Object.fromEntries( (template ?? []) .filter((item) => item.role) .map((item) => [item.role, item.enabled]), ); } describe('text context menu', () => { it('does not create a menu for ordinary non-editable content', () => { expect(createTextContextMenuTemplate(context())).toBeNull(); }); it('allows paste and select all in an editable control without a selection', () => { const template = createTextContextMenuTemplate(context({ isEditable: true, editFlags: { canPaste: true, canSelectAll: true, }, })); expect(template?.map((item) => item.label ?? item.type)).toEqual([ '剪切', '复制', '粘贴', 'separator', '全选', ]); expect(enabledByRole(template)).toEqual({ cut: false, copy: false, paste: true, selectAll: true, }); }); it('enables every requested action for an editable selection when supported', () => { const template = createTextContextMenuTemplate(context({ isEditable: true, selectionText: 'Makelore', editFlags: { canCut: true, canCopy: true, canPaste: true, canSelectAll: true, }, })); expect(enabledByRole(template)).toEqual({ cut: true, copy: true, paste: true, selectAll: true, }); }); it('keeps cut and paste disabled for a read-only selection', () => { const template = createTextContextMenuTemplate(context({ selectionText: 'Makelore', editFlags: { canCut: true, canCopy: true, canPaste: true, canSelectAll: true, }, })); expect(enabledByRole(template)).toEqual({ cut: false, copy: true, paste: false, selectAll: true, }); }); it('respects disabled renderer editing capabilities', () => { const template = createTextContextMenuTemplate(context({ isEditable: true, selectionText: 'Makelore', })); expect(enabledByRole(template)).toEqual({ cut: false, copy: false, paste: false, selectAll: false, }); }); });