Nevar pievienot vairāk kā 25 tēmas Tēmai ir jāsākas ar burtu vai ciparu, tā var saturēt domu zīmes ('-') un var būt līdz 35 simboliem gara.
 
 
 
 

75 rindas
6.0 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,call} from './role-permissions-live.mjs';
  6. const dir=path.resolve('reports/bridge-pump-overview-20260915');
  7. await fs.mkdir(dir,{recursive:true});
  8. const signed=await login('root'),checks=[],errors=[],writes=[];
  9. const before=await call('tran/v1/teaching/assignments/88',signed.accessToken);
  10. assert.equal(before.status,200);assert.equal(before.data.code,'TASK-VIRTUAL-007');
  11. const browser=await chromium.launch({channel:'msedge',headless:true,args:['--enable-unsafe-swiftshader']});
  12. const page=await browser.newPage({viewport:{width:1920,height:1080}});
  13. 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);
  14. // Read-only material/camera snapshot for this browser; it does not drive the scene.
  15. await page.route(/\/src\/features\/virtual-training-legacy\/upstream\/views\/training\.js(?:\?|$)/,async route=>{
  16. const response=await route.fetch();await route.fulfill({response,body:(await response.text())+`
  17. globalThis.__pumpOverviewSnapshot = () => {
  18. const r=activeTraining;if(!r?.sceneReady)return null;
  19. let compared=0,faded=0,opaque=0;
  20. r.publishedContentRoot.traverse(o=>{if(!o.isMesh)return;for(const m of Array.isArray(o.material)?o.material:[o.material]){
  21. const base=r.viewerMaterialBaseline.get(m);if(!base)continue;compared++;if(m.opacity<base.opacity-0.001)faded++;if(m.opacity>=0.9)opaque++;
  22. }});
  23. return {compared,faded,opaque,detail:!!r.bridgeDetailActive,distance:r.camera.position.distanceTo(r.controls.target),homeDistance:r.cameraHome.position.distanceTo(r.cameraHome.target),position:r.camera.position.toArray(),target:r.controls.target.toArray(),step:r.session.stepIndex};
  24. };`});
  25. });
  26. page.on('pageerror',e=>errors.push(e.message));
  27. page.on('request',r=>{if(r.url().includes('/api/tran/')&&!['GET','HEAD'].includes(r.method()))writes.push(r.url());});
  28. const snapshot=()=>page.evaluate(()=>globalThis.__pumpOverviewSnapshot?.());
  29. const ready=async()=>{await expect(page.locator('[data-role="loading"]')).toHaveClass(/is-hidden/,{timeout:120000});await expect.poll(snapshot).not.toBeNull();await page.waitForTimeout(1400);};
  30. const solid=async(name)=>{const s=await snapshot();assert.ok(s.compared>50);assert.equal(s.faded,0,name);assert.equal(s.detail,false);assert.ok(s.opaque>50);assert.ok(s.distance>4);checks.push({name,...s});return s;};
  31. try{
  32. for(const [label,origin] of [['local','http://127.0.0.1:6180'],['lan',process.env.LAN_URL]].filter(([,origin])=>origin)){
  33. await page.goto(origin+'/teaching/virtual-training/preview/88');await ready();
  34. await solid(label+' first load uses solid vehicle overview');
  35. await page.screenshot({path:path.join(dir,`${label}-overview.png`)});
  36. await page.locator('[data-action="toggle-issue-highlight"]').click();
  37. await expect.poll(async()=>(await snapshot()).faded).toBeGreaterThan(0);
  38. await page.locator('[data-action="toggle-issue-highlight"]').click();await solid(label+' explicit highlight off restores original materials');
  39. await page.locator('[data-action="viewer-reset-view"]').click();await page.waitForTimeout(800);await solid(label+' reset keeps overview solid');
  40. await page.reload();await ready();await solid(label+' reload keeps overview solid');
  41. }
  42. // Real preview interactions must still execute and validate; every automatic
  43. // operation/step transition should preserve a normal exterior camera distance.
  44. for(let index=0;index<5;index++){
  45. const step=before.data.definitionSnapshot.steps[index];
  46. for(const [operationIndex] of step.action.mechanism.steps.entries()){
  47. await page.locator('[data-role="part-label"]').click();
  48. await expect.poll(()=>page.evaluate(()=>globalThis.__trainingSceneDiagnostics().bridgeWorkshop.pending)).toBe(false);
  49. await page.waitForTimeout(1000);
  50. await solid(`step ${index+1}, operation ${operationIndex+1}`);
  51. }
  52. await expect(page.locator('[data-action="next"]')).toBeEnabled({timeout:15000});
  53. if(index<4){await page.locator('[data-action="next"]').click();await page.waitForTimeout(1400);await solid(`enter step ${index+2}`);}
  54. }
  55. await page.screenshot({path:path.join(dir,'after-pump-removal.png')});
  56. // Manual close inspection remains available via existing structure/focus tools.
  57. await page.locator('[data-role="model-commandbar"] [data-action="toggle-structure-tree"]').click();
  58. const part=page.locator('[data-action="select-structure-part"]').filter({hasText:/^车_1$/}).first();
  59. const partKey=await part.getAttribute('data-part-id');
  60. await part.click();const previousDistance=(await snapshot()).distance;
  61. await page.locator('[data-action="focus-selected-part"]').click();await page.waitForTimeout(850);
  62. assert.ok((await snapshot()).distance<previousDistance);
  63. await page.screenshot({path:path.join(dir,'manual-focus.png')});
  64. await part.click();
  65. await page.locator('[data-action="viewer-reset-view"]').click();await page.waitForTimeout(850);await solid('manual focus then deselect/reset returns solid overview');
  66. checks.push({name:'manual structure selection and focus remain available',partKey});
  67. const after=await call('tran/v1/teaching/assignments/88',signed.accessToken);
  68. assert.deepEqual(after.data.definitionSnapshot,before.data.definitionSnapshot);assert.equal(after.data.version,before.data.version);
  69. assert.ok(writes.every(url=>url.endsWith('/preview/validate')));assert.deepEqual(errors,[]);
  70. await fs.writeFile(path.join(dir,'result.json'),JSON.stringify({pass:true,checks,errors,writes,taskVersionUnchanged:true},null,2));
  71. console.log(`PASS: ${checks.length} overview/material checks, five steps executed, manual focus, preview validation only`);
  72. }catch(error){await page.screenshot({path:path.join(dir,'failure.png')}).catch(()=>{});await fs.writeFile(path.join(dir,'result.json'),JSON.stringify({pass:false,message:error.message,checks,errors,writes},null,2));throw error;}
  73. finally{await browser.close();}