import { test, expect } from '@playwright/test'; import path from 'node:path'; import { observeNative, performNativeAction, exposeWebTools } from '../fixtures/native-ui-workflow'; import { webMain } from '../fixtures/console-main-workflow'; import { openFromUI } from '../fixtures/wasm-console-workflow'; import { focusNativeViewport, readModelingMain, readNativeBlend, readNativeHistory } from '../fixtures/native-modeling-workflow'; const fixture = path.resolve(import.meta.dirname, '../../../tests/files/web/basic_scene.blend'); /* Isolation: press `g` right after focusing the viewport, then again after the * modeling / history / blend reads, so the step that swallows input is visible. */ test('isolate which prerequisite loses the g key', async ({ page }) => { const rec: Record = {}; const gpu = () => page.evaluate(() => { const g = (window as any).__nativeWorkflowGPU; return g ? { active: g.modalActive, ready: g.displayAcknowledged, owner: g.ownerGeneration, req: g.requestId } : null; }); const pressG = async (label: string) => { const canvas = page.locator('canvas[aria-label="Blender desktop"]').first(); await canvas.focus(); const series: unknown[] = []; await page.keyboard.press('g'); for (let i = 0; i < 15; i++) { await page.waitForTimeout(100); series.push({ t: (i + 1) * 100, ...(await gpu()) }); } const sawModal = series.some((s: any) => s.active === true); rec[label] = { sawModal, maxActive: series.filter((s: any) => s.active).length, series }; if (sawModal) { await page.keyboard.press('Escape'); await page.waitForTimeout(1200); } rec[`${label}_afterEscape`] = await gpu(); return sawModal; }; await observeNative(page); await page.goto('/'); await expect.poll(() => page.evaluate(() => Array.isArray((window as any).__nativeWorkflowMain?.nodes)), { timeout: 60_000 }).toBe(true); await exposeWebTools(page); await openFromUI(page, () => page.getByTestId('blend-file-input').setInputFiles(fixture)); const opened = await webMain(page); await performNativeAction(page, { command: 'createPrimitive' }, () => page.getByRole('button', { name: '添加立方体', exact: true }).click()); const added = (await webMain(page)).nodes.filter((node: any) => !opened.nodes.some((previous: any) => previous.id === node.id)); const name = added[0]?.name; rec.addedNames = added.map((node: any) => node.name); const { canvas } = await focusNativeViewport(page); rec.gpuAfterFocus = await gpu(); rec.step1_rightAfterFocus = await pressG('step1'); rec.gpuAfterStep1 = await gpu(); await readModelingMain(page, name); rec.gpuAfterModelingRead = await gpu(); rec.step2_afterModelingRead = await pressG('step2'); rec.gpuAfterStep2 = await gpu(); await readNativeHistory(page); rec.gpuAfterHistory = await gpu(); rec.step3_afterHistory = await pressG('step3'); rec.gpuAfterStep3 = await gpu(); await readNativeBlend(page); rec.gpuAfterBlendRead = await gpu(); rec.step4_afterBlendRead = await pressG('step4'); rec.gpuFinal = await gpu(); console.log(JSON.stringify({ summary: { step1: rec.step1_rightAfterFocus, step2: rec.step2_afterModelingRead, step3: rec.step3_afterHistory, step4: rec.step4_afterBlendRead, owners: [rec.gpuAfterFocus, rec.gpuAfterStep1, rec.gpuAfterModelingRead, rec.gpuAfterStep2, rec.gpuAfterHistory, rec.gpuAfterStep3, rec.gpuAfterBlendRead, rec.gpuFinal], } }, null, 1)); });