Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.
 
 
 
 

46 lignes
5.9 KiB

  1. import fs from 'node:fs';
  2. import assert from 'node:assert/strict';
  3. import {chromium,expect} from '@playwright/test';
  4. import {login} from './role-permissions-live.mjs';
  5. const baseline=process.env.BASELINE==='1',dir='reports/bridge-entry-view-20260925'+(baseline?'-before':'')+(process.env.REPORT_SUFFIX||'');fs.mkdirSync(dir,{recursive:true});
  6. const viewport={width:Number(process.env.WIDTH||1920),height:Number(process.env.HEIGHT||945)},baseUrl=process.env.BASE_URL||'http://127.0.0.1:6180';
  7. const session=await login('root'),checks=[],errors=[];
  8. const browser=await chromium.launch({channel:'msedge',headless:true,args:['--enable-unsafe-swiftshader','--autoplay-policy=no-user-gesture-required']});
  9. const page=await browser.newPage({viewport});
  10. 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:'light'}));globalThis.__mediaPlays=[];document.addEventListener('play',ev=>globalThis.__mediaPlays.push({src:ev.target.currentSrc,className:ev.target.className}),true);},session);
  11. 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()+`
  12. globalThis.__entryView=()=>{const e=activeTraining;if(!e?.sceneReady)return null;const r=e.canvas.getBoundingClientRect(),primary=e.viewerPrimaryObject,meshes=[];
  13. primary?.traverse(m=>{if(!m.isMesh||m.userData.trainingPickProxy)return;for(let p=m;p;p=p.parent)if(!p.visible)return;const box=m.geometry.boundingBox||(m.geometry.computeBoundingBox(),m.geometry.boundingBox);if(!box)return;for(const x of [box.min.x,box.max.x])for(const y of [box.min.y,box.max.y])for(const z of [box.min.z,box.max.z]){const v=new THREE.Vector3(x,y,z).applyMatrix4(m.matrixWorld).project(e.camera);meshes.push({x:(v.x+1)*r.width/2,y:(1-v.y)*r.height/2});}});
  14. const left=Math.min(...meshes.map(p=>p.x)),top=Math.min(...meshes.map(p=>p.y)),right=Math.max(...meshes.map(p=>p.x)),bottom=Math.max(...meshes.map(p=>p.y));
  15. return {step:e.session.stepIndex,completed:[...e.session.completed],autoVoice:e.teacherVoiceEnabled,camera:e.camera.position.toArray(),target:e.controls.target.toArray(),zoom:e.camera.zoom,viewport:{x:r.x,y:r.y,w:r.width,h:r.height},area:e.inspection.clearArea(),primary:{x:left,y:top,w:right-left,h:bottom-top},rootBounds:(e.viewerEquipmentRoots||[]).map(o=>({name:o.name,size:new THREE.Box3().setFromObject(o).getSize(new THREE.Vector3()).toArray()})),pending:!!e.viewerCameraTween};};`});});
  16. page.on('pageerror',error=>errors.push(error.message));
  17. const snap=()=>page.evaluate(()=>globalThis.__entryView?.());
  18. const settled=async()=>{await page.waitForTimeout(750);await expect.poll(async()=>(await snap())?.pending,{timeout:15000}).toBe(false);};
  19. try{
  20. for(const id of (process.env.TASK_IDS||'86,87,88,89').split(',')){
  21. await page.goto(baseUrl+'/teaching/virtual-training/preview/'+id);
  22. await expect.poll(async()=>Boolean(await snap()),{timeout:120000}).toBe(true);await page.waitForTimeout(1600);
  23. const overlay=page.locator('.training-introduction'),media=overlay.locator('video');
  24. const initial={task:id,view:'entry',snapshot:await snap(),media:await media.evaluate(v=>({paused:v.paused,time:v.currentTime})),badge:await page.locator('.training-preview-badge').evaluate(el=>({max:getComputedStyle(el).maxWidth,width:el.getBoundingClientRect().width,title:el.title}))};
  25. checks.push(initial);await page.screenshot({path:`${dir}/task-${id}-entry.png`});
  26. if(!baseline){assert.equal(initial.media.paused,true);assert.equal(initial.media.time,0);assert.equal(initial.snapshot.autoVoice,false);assert.equal(initial.badge.max,'300px');assert.ok(initial.badge.width<=300);assert.deepEqual(await page.evaluate(()=>globalThis.__mediaPlays),[]);}
  27. await overlay.locator('[data-intro-command="skip"]').click();await settled();await page.waitForTimeout(900);
  28. if(!baseline)assert.equal(await page.locator('.training-server-video').evaluate(v=>v.paused),true,'entering operation remains silent');
  29. checks.push({task:id,view:'overview',snapshot:await snap()});await page.screenshot({path:`${dir}/task-${id}-overview.png`});
  30. await page.locator('[data-role="part-label"]').click();await settled();
  31. await page.locator('[data-action="reset-view"]').click();await settled();
  32. checks.push({task:id,view:'reset',snapshot:await snap()});await page.screenshot({path:`${dir}/task-${id}-reset.png`});
  33. if(!baseline){
  34. const current=await snap(),initialView=checks.find(c=>c.task===id&&c.view==='overview').snapshot;
  35. assert.ok(Math.abs(current.primary.w-initialView.primary.w)<2,'reset and overview scale match');assert.deepEqual(current.completed,[]);
  36. await page.locator('[data-action="teacher-speak"]').click();await expect.poll(()=>page.locator('.training-server-video').evaluate(v=>v.currentTime),{timeout:30000}).toBeGreaterThan(.1);
  37. await page.locator('[data-intro-page="0"]').click();await page.waitForTimeout(700);assert.equal(await media.evaluate(v=>v.paused&&v.currentTime===0),true);
  38. await overlay.locator('[data-intro-media="toggle"]').click();await expect.poll(()=>media.evaluate(v=>v.currentTime),{timeout:30000}).toBeGreaterThan(.1);
  39. await overlay.locator('[data-intro-command="next"]').click();await page.waitForTimeout(700);
  40. assert.equal(await page.locator('video').evaluateAll(videos=>videos.every(v=>v.paused)),true,'next page never auto starts');
  41. }
  42. console.log('PASS entry view',id);
  43. }
  44. assert.deepEqual(errors,[]);fs.writeFileSync(dir+'/result.json',JSON.stringify({pass:true,baseline,baseUrl,viewport,accountRole:'root',serverMutations:[],checks,errors},null,2));
  45. }catch(error){await page.screenshot({path:dir+'/failure.png'}).catch(()=>{});fs.writeFileSync(dir+'/result.json',JSON.stringify({pass:false,error:error.stack,checks,errors,snapshot:await snap().catch(()=>null)},null,2));throw error;}finally{await browser.close();}