import type { ElectronApplication } from '@playwright/test'; import { closeElectronApp, expect, getStableWindow, test } from './fixtures/electron'; type ContextMenuProbe = { popupCount: number; template: Array<{ label: string | null; role: string | null; type: string; }>; }; async function installContextMenuProbe(app: ElectronApplication): Promise { await app.evaluate(({ Menu }) => { const probe: ContextMenuProbe = { popupCount: 0, template: [], }; const globalWithProbe = globalThis as typeof globalThis & { __makeloreContextMenuProbe?: ContextMenuProbe; }; globalWithProbe.__makeloreContextMenuProbe = probe; Menu.buildFromTemplate = ((template) => { probe.template = template.map((item) => ({ label: item.label ?? null, role: item.role ?? null, type: item.type ?? 'normal', })); return { popup: () => { probe.popupCount += 1; }, } as unknown as Electron.Menu; }) as typeof Menu.buildFromTemplate; }); } async function readContextMenuProbe(app: ElectronApplication): Promise { return await app.evaluate(() => { const globalWithProbe = globalThis as typeof globalThis & { __makeloreContextMenuProbe?: ContextMenuProbe; }; return globalWithProbe.__makeloreContextMenuProbe ?? null; }); } test.describe('Makelore text context menu', () => { test('opens native editing actions for Code and Design textareas', async ({ launchElectronApp }) => { const app = await launchElectronApp({ skipSetup: true }); try { const page = await getStableWindow(app); await installContextMenuProbe(app); await page.evaluate(() => { const composerIds = [ 'context-menu-e2e-code-composer', 'design-chat-composer', ]; for (const [index, id] of composerIds.entries()) { const textarea = document.createElement('textarea'); textarea.id = id; textarea.style.position = 'fixed'; textarea.style.inset = `${80 + index * 80}px auto auto 80px`; textarea.style.zIndex = '2147483647'; document.body.append(textarea); } }); for (const selector of [ '#context-menu-e2e-code-composer', '#design-chat-composer', ]) { const textarea = page.locator(selector); await textarea.fill('Makelore'); await textarea.selectText(); await textarea.click({ button: 'right' }); } await expect.poll(async () => await readContextMenuProbe(app)).toEqual({ popupCount: 2, template: [ { label: '剪切', role: 'cut', type: 'normal' }, { label: '复制', role: 'copy', type: 'normal' }, { label: '粘贴', role: 'paste', type: 'normal' }, { label: null, role: null, type: 'separator' }, { label: '全选', role: 'selectAll', type: 'normal' }, ], }); } finally { await closeElectronApp(app); } }); });