Files
workinf_Blender_Wasm/web/tests/e2e/desktop-menu-workflows.spec.ts
mes123456 f3e21c6b98
Some checks failed
M6 deployable RC / quick (push) Has been cancelled
M6 deployable RC / chromium (push) Has been cancelled
M6 deployable RC / release (push) Has been cancelled
chore: checkpoint web Blender migration source, tools and docs
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>
2026-11-10 11:18:01 +08:00

48 lines
5.1 KiB
TypeScript

import {expect,test} from '@playwright/test';
import path from 'node:path';
const fixture=path.resolve(import.meta.dirname,'../../app/public/robot-assets/abb-irb120/start-scene.blend');
test('desktop header menus add, undo, rename and export a real Main scene',async({page},testInfo)=>{
await page.goto('/');await page.getByTestId('blend-file-input').setInputFiles(fixture);
await expect(page.getByTestId('engine-status')).toContainText('SceneIR');
await expect(page.getByRole('button',{name:'添加立方体',exact:true})).not.toBeVisible();
const menu=async(label:string,...items:string[])=>{await page.getByRole('button',{name:label,exact:true}).click();for(const name of items)await page.getByRole('menuitem',{name,exact:true}).click();};
await menu('添加','网格','立方体');await expect(page.getByTestId('scene-stats')).toContainText('Objects 4');
await menu('编辑','撤销');await expect(page.getByTestId('scene-stats')).toContainText('Objects 3');
await menu('编辑','重做');await expect(page.getByTestId('scene-stats')).toContainText('Objects 4');
await menu('物体','重命名');await page.getByLabel('新对象名称').fill('Menu Regression Cube');await page.getByRole('button',{name:'确认',exact:true}).click();
await expect(page.getByRole('treeitem',{name:'Menu Regression Cube',exact:true})).toBeVisible();
const download=page.waitForEvent('download');
await menu('文件','导出','glTF 2.0 (.glb)');
await expect(page.getByTestId('engine-status')).toContainText('GLB:');
if((await page.getByTestId('engine-status').textContent())?.includes('blocked')){
const diagnostic=page.waitForEvent('download');await page.getByTestId('export-diagnostics').click();const file=await diagnostic;await testInfo.attach('export-diagnostic',{path:(await file.path())!,contentType:'application/json'});
}
await expect(page.getByTestId('engine-status')).toContainText('GLB: exported');
const file=await download;expect(file.suggestedFilename()).toBe('blender-web.glb');
await testInfo.attach('edited-menu-scene.glb',{path:(await file.path())!,contentType:'model/gltf-binary'});
});
test('desktop mode menu gates object types and changes mesh editor menus',async({page})=>{
await page.goto('/');await page.getByTestId('blend-file-input').setInputFiles(fixture);await expect(page.getByTestId('engine-status')).toContainText('SceneIR');
await page.getByRole('treeitem',{name:'ParityCamera',exact:true}).click();await page.getByRole('button',{name:'Object Mode',exact:true}).click();await expect(page.getByRole('menuitem',{name:'编辑模式',exact:true})).toBeDisabled();await page.keyboard.press('Escape');
await page.getByRole('treeitem',{name:'ParityCube',exact:true}).click();await page.getByRole('button',{name:'Object Mode',exact:true}).click();await page.getByRole('menuitem',{name:'编辑模式',exact:true}).click();
await expect(page.getByRole('button',{name:'面',exact:true})).toBeVisible();await page.getByRole('button',{name:'面选择',exact:true}).click();
await page.getByRole('button',{name:'选择',exact:true}).click();await page.getByRole('menuitem',{name:'全部',exact:true}).click();
await page.getByRole('button',{name:'面',exact:true}).click();await page.getByRole('menuitem',{name:'三角化',exact:true}).click();await expect(page.getByTestId('scene-stats')).toContainText('Faces 12');
});
test('desktop menus stay reachable on mobile and unsupported commands stay disabled',async({page})=>{
await page.setViewportSize({width:390,height:844});await page.goto('/');await expect(page.getByTestId('engine-status')).toContainText('ready');
await page.getByRole('button',{name:'文件',exact:true}).click();await expect(page.getByRole('menuitem',{name:'保存',exact:true})).toBeDisabled();await page.getByRole('menuitem',{name:'导出',exact:true}).click();
const panel=page.getByRole('menu',{name:'导出',exact:true});await expect(panel.getByRole('menuitem',{name:'FBX (.fbx)',exact:true})).toBeDisabled();const rect=await panel.boundingBox();expect(rect!.x).toBeGreaterThanOrEqual(0);expect(rect!.x+rect!.width).toBeLessThanOrEqual(390);
await page.keyboard.press('Escape');await expect(page.getByRole('button',{name:'文件',exact:true})).toBeFocused();
});
test('render menu executes scene-engine image rendering and preserves explicit range limits',async({page})=>{
test.setTimeout(120000);await page.goto('/');await page.getByTestId('blend-file-input').setInputFiles(fixture);await expect(page.getByTestId('engine-status')).toContainText('SceneIR');
await page.getByRole('button',{name:'渲染',exact:true}).click();await expect(page.getByRole('menuitem',{name:'导出 GLB',exact:true})).toHaveCount(0);await page.getByRole('menuitem',{name:'渲染图像',exact:true}).click();
await expect(page.locator('.native-render-panel .native-workflow-output')).toContainText('SUCCEEDED',{timeout:90000});await expect(page.locator('.native-render-panel img')).toBeVisible();
await page.getByRole('button',{name:'渲染',exact:true}).click();await page.getByRole('menuitem',{name:'渲染动画',exact:true}).click();await expect(page.locator('.native-render-panel .native-workflow-output')).toContainText('超过当前单次 240 帧上限');
});