Accumulated uncommitted work: GHOST Web backend, WebGL/GPU web layer, web workflow engine and protocol, tooling, docs and task records. Large generated evidence, user-testing archives, build snapshots and imported test assets remain untracked. Co-Authored-By: Claude Code <noreply@anthropic.com>
61 lines
3.4 KiB
TypeScript
61 lines
3.4 KiB
TypeScript
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<string, unknown> = {};
|
|
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));
|
|
});
|