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!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{});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();}