Ви не можете вибрати більше 25 тем Теми мають розпочинатися з літери або цифри, можуть містити дефіси (-) і не повинні перевищувати 35 символів.
 
 
 
 

65 рядки
5.8 KiB

  1. import fs from 'node:fs/promises';
  2. import path from 'node:path';
  3. import assert from 'node:assert/strict';
  4. import {chromium,expect} from '@playwright/test';
  5. import {login} from './role-permissions-live.mjs';
  6. const folder=path.resolve('reports/'+(process.env.REPORT_NAME||'bridge-solid-view-20260915'));
  7. await fs.mkdir(folder,{recursive:true});
  8. const checks=[],errors=[],writes=[],signed=await login('root');
  9. const browser=await chromium.launch({channel:'msedge',headless:true,args:['--enable-unsafe-swiftshader']});
  10. const page=await browser.newPage({viewport:{width:1366,height:768}});
  11. 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);
  12. await page.route(/\/src\/features\/virtual-training-legacy\/upstream\/views\/training\.js(?:\?|$)/,async route=>{
  13. const response=await route.fetch();await route.fulfill({response,body:(await response.text())+`
  14. globalThis.__solidSnapshot=(options={})=>{
  15. const e=activeTraining;if(!e?.sceneReady)return null;
  16. const meshes=[],canvas=e.canvas.getBoundingClientRect(),active=e.parts.get(e.getActiveTargetId()),dragPoints=[];
  17. 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}))});});
  18. const ray=new THREE.Raycaster();
  19. if(options.drag)for(let y=110;y<canvas.height-100;y+=55)for(let x=20;x<canvas.width-30;x+=55){
  20. if(document.elementFromPoint(canvas.left+x,canvas.top+y)!==e.canvas)continue;
  21. ray.setFromCamera(new THREE.Vector2(x/canvas.width*2-1,1-y/canvas.height*2),e.camera);
  22. const hit=ray.intersectObjects(e.pickables,false).find(h=>!h.object.userData.trainingPickProxy&&effectivelyVisible(h.object));
  23. if(!hit||hit.object.userData.partId==='scene:front-pump-rescue-vehicle')dragPoints.push({x:canvas.left+x,y:canvas.top+y});
  24. }
  25. 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};
  26. };`});
  27. });
  28. page.on('pageerror',e=>errors.push(e.message));
  29. page.on('request',r=>{if(r.url().includes('/api/tran/')&&!['GET','HEAD'].includes(r.method()))writes.push(r.url());});
  30. const snap=(options={})=>page.evaluate(o=>globalThis.__solidSnapshot?.(o),options);
  31. const visible=s=>s.meshes.filter(m=>m.visible).map(m=>m.id).sort();
  32. try{
  33. for(const id of (process.env.TASK_IDS||'86,87,88,89').split(',')){
  34. await page.goto((process.env.BASE_URL||'http://127.0.0.1:6180')+'/teaching/virtual-training/preview/'+id);
  35. await expect(page.locator('[data-role="loading"]')).toHaveClass(/is-hidden/,{timeout:120000});
  36. await expect.poll(snap,{timeout:30000}).not.toBeNull();await page.waitForTimeout(1500);
  37. const initial=await snap();assert.ok(initial.meshes.every(m=>m.materials.every(v=>v.side===2)));
  38. await page.locator('[data-role="part-label"]').click();await page.waitForTimeout(1100);
  39. const focused=await snap();await page.screenshot({path:path.join(folder,`task-${id}-focused.png`)});
  40. checks.push({id,name:'focus keeps every previously visible mesh',before:visible(initial).length,after:visible(focused).length,automaticHidden:focused.cutaway});
  41. assert.deepEqual(visible(focused),visible(initial),'focusing must not hide vehicle or terrain meshes');
  42. for(const [index,dx,dy] of [[1,155,20],[2,-90,135],[3,-170,-75]]){
  43. const start=await snap({drag:true});assert.ok(start.dragPoints.length);const point=start.dragPoints[Math.floor(start.dragPoints.length/2)];
  44. 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);
  45. 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);
  46. await page.screenshot({path:path.join(folder,`task-${id}-orbit-${index}.png`)});
  47. }
  48. await page.locator('[data-viewer-action="tools"]').click();
  49. for(let n=0;n<4;n++)await page.locator('[data-action="toggle-issue-highlight"]').click();
  50. assert.deepEqual(visible(await snap()),visible(initial));
  51. await page.locator('[data-action="toggle-translucent-others"]').click();
  52. const faded=await snap();assert.deepEqual(visible(faded),visible(initial));assert.ok(faded.meshes.some(m=>m.materials.some(v=>v.opacity<.5)));
  53. await page.locator('[data-action="toggle-translucent-others"]').click();assert.deepEqual((await snap()).meshes,initial.meshes);
  54. await page.locator('[data-action="toggle-hide-others"]').click();assert.ok(visible(await snap()).length<visible(initial).length);
  55. await page.locator('[data-action="toggle-hide-others"]').click();assert.deepEqual((await snap()).meshes,initial.meshes);
  56. await page.locator('[data-action="viewer-reset-view"]').click();await page.waitForTimeout(1000);assert.deepEqual((await snap()).meshes,initial.meshes);
  57. await page.screenshot({path:path.join(folder,`task-${id}-restored.png`)});
  58. checks.push({id,name:'three orbit directions, glow, explicit opacity/hide and restore',pass:true,meshes:initial.meshes.length});console.log('PASS',id);
  59. }
  60. assert.deepEqual(errors,[]);assert.deepEqual(writes,[]);
  61. await fs.writeFile(path.join(folder,'result.json'),JSON.stringify({pass:true,checks,errors,writes},null,2));
  62. }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;}
  63. finally{await browser.close();}