|
- import fs from 'node:fs/promises';
- import path from 'node:path';
- import assert from 'node:assert/strict';
- import {chromium,expect} from '@playwright/test';
- import {login} from './role-permissions-live.mjs';
-
- const folder=path.resolve('reports/'+(process.env.REPORT_NAME||'bridge-solid-view-20260915'));
- await fs.mkdir(folder,{recursive:true});
- const checks=[],errors=[],writes=[],signed=await login('root');
- const browser=await chromium.launch({channel:'msedge',headless:true,args:['--enable-unsafe-swiftshader']});
- const page=await browser.newPage({viewport:{width:1366,height:768}});
- await page.addInitScript(s=>{sessionStorage.setItem('unreal-tran:web:access-token:v1',s.accessToken);sessionStorage.setItem('unreal-tran:web:refresh-token:v1',s.refreshToken);localStorage.setItem('unreal-tran:web:preferences:v1',JSON.stringify({themeMode:'military'}));},signed);
- await page.route(/\/src\/features\/virtual-training-legacy\/upstream\/views\/training\.js(?:\?|$)/,async route=>{
- const response=await route.fetch();await route.fulfill({response,body:(await response.text())+`
- globalThis.__solidSnapshot=(options={})=>{
- const e=activeTraining;if(!e?.sceneReady)return null;
- const meshes=[],canvas=e.canvas.getBoundingClientRect(),active=e.parts.get(e.getActiveTargetId()),dragPoints=[];
- e.publishedContentRoot.traverse(o=>{if(!o.isMesh||o.userData.trainingPickProxy)return;meshes.push({id:o.uuid,visible:effectivelyVisible(o),materials:(Array.isArray(o.material)?o.material:[o.material]).map(m=>({side:m.side,opacity:m.opacity,transparent:m.transparent}))});});
- const ray=new THREE.Raycaster();
- if(options.drag)for(let y=110;y<canvas.height-100;y+=55)for(let x=20;x<canvas.width-30;x+=55){
- if(document.elementFromPoint(canvas.left+x,canvas.top+y)!==e.canvas)continue;
- ray.setFromCamera(new THREE.Vector2(x/canvas.width*2-1,1-y/canvas.height*2),e.camera);
- const hit=ray.intersectObjects(e.pickables,false).find(h=>!h.object.userData.trainingPickProxy&&effectivelyVisible(h.object));
- if(!hit||hit.object.userData.partId==='scene:front-pump-rescue-vehicle')dragPoints.push({x:canvas.left+x,y:canvas.top+y});
- }
- return {meshes,dragPoints,camera:e.camera.position.toArray(),step:e.session.stepIndex,operation:e.getActiveMechanismOperation()?.state.index,errors:e.errorCount,cutaway:e.inspection.cutaway?.size||0};
- };`});
- });
- page.on('pageerror',e=>errors.push(e.message));
- page.on('request',r=>{if(r.url().includes('/api/tran/')&&!['GET','HEAD'].includes(r.method()))writes.push(r.url());});
- const snap=(options={})=>page.evaluate(o=>globalThis.__solidSnapshot?.(o),options);
- const visible=s=>s.meshes.filter(m=>m.visible).map(m=>m.id).sort();
- try{
- for(const id of (process.env.TASK_IDS||'86,87,88,89').split(',')){
- await page.goto((process.env.BASE_URL||'http://127.0.0.1:6180')+'/teaching/virtual-training/preview/'+id);
- await expect(page.locator('[data-role="loading"]')).toHaveClass(/is-hidden/,{timeout:120000});
- await expect.poll(snap,{timeout:30000}).not.toBeNull();await page.waitForTimeout(1500);
- const initial=await snap();assert.ok(initial.meshes.every(m=>m.materials.every(v=>v.side===2)));
- await page.locator('[data-role="part-label"]').click();await page.waitForTimeout(1100);
- const focused=await snap();await page.screenshot({path:path.join(folder,`task-${id}-focused.png`)});
- checks.push({id,name:'focus keeps every previously visible mesh',before:visible(initial).length,after:visible(focused).length,automaticHidden:focused.cutaway});
- assert.deepEqual(visible(focused),visible(initial),'focusing must not hide vehicle or terrain meshes');
- for(const [index,dx,dy] of [[1,155,20],[2,-90,135],[3,-170,-75]]){
- const start=await snap({drag:true});assert.ok(start.dragPoints.length);const point=start.dragPoints[Math.floor(start.dragPoints.length/2)];
- await page.mouse.move(point.x,point.y);await page.mouse.down();await page.mouse.move(point.x+dx,point.y+dy,{steps:12});await page.mouse.up();await page.waitForTimeout(1000);
- const after=await snap();assert.notDeepEqual(after.camera,start.camera);assert.deepEqual(visible(after),visible(initial),'orbit keeps complete mesh set');assert.equal(after.errors,0);assert.equal(after.step,initial.step);assert.equal(after.operation,initial.operation);
- await page.screenshot({path:path.join(folder,`task-${id}-orbit-${index}.png`)});
- }
- await page.locator('[data-viewer-action="tools"]').click();
- for(let n=0;n<4;n++)await page.locator('[data-action="toggle-issue-highlight"]').click();
- assert.deepEqual(visible(await snap()),visible(initial));
- await page.locator('[data-action="toggle-translucent-others"]').click();
- const faded=await snap();assert.deepEqual(visible(faded),visible(initial));assert.ok(faded.meshes.some(m=>m.materials.some(v=>v.opacity<.5)));
- await page.locator('[data-action="toggle-translucent-others"]').click();assert.deepEqual((await snap()).meshes,initial.meshes);
- await page.locator('[data-action="toggle-hide-others"]').click();assert.ok(visible(await snap()).length<visible(initial).length);
- await page.locator('[data-action="toggle-hide-others"]').click();assert.deepEqual((await snap()).meshes,initial.meshes);
- await page.locator('[data-action="viewer-reset-view"]').click();await page.waitForTimeout(1000);assert.deepEqual((await snap()).meshes,initial.meshes);
- await page.screenshot({path:path.join(folder,`task-${id}-restored.png`)});
- checks.push({id,name:'three orbit directions, glow, explicit opacity/hide and restore',pass:true,meshes:initial.meshes.length});console.log('PASS',id);
- }
- assert.deepEqual(errors,[]);assert.deepEqual(writes,[]);
- await fs.writeFile(path.join(folder,'result.json'),JSON.stringify({pass:true,checks,errors,writes},null,2));
- }catch(error){await page.screenshot({path:path.join(folder,'failure.png')}).catch(()=>{});await fs.writeFile(path.join(folder,'result.json'),JSON.stringify({pass:false,error:error.message,checks,errors,writes},null,2));throw error;}
- finally{await browser.close();}
|