Não pode escolher mais do que 25 tópicos Os tópicos devem começar com uma letra ou um número, podem incluir traços ('-') e podem ter até 35 caracteres.
 
 
 
 

75 linhas
6.0 KiB

  1. import { chromium, expect } from '@playwright/test';
  2. import fs from 'node:fs';
  3. import assert from 'node:assert/strict';
  4. import crypto from 'node:crypto';
  5. import { login, call } from './role-permissions-live.mjs';
  6. import { scripts, scriptDefinition } from '../../unreal_tran_web/src/features/virtual-training-scripts/definition.js';
  7. import { verifyVisualEffects } from './bridge-model-match-assertions.mjs';
  8. const dir='reports/bridge-model-match-20260914';fs.mkdirSync(dir,{recursive:true});
  9. const session=await login('root'), fixtures=[], checks=[], errors=[];
  10. const api=async(path,data,method)=>{const r=await call(path,session.accessToken,data,method);assert.equal(r.status,200,`${path}: ${r.message}`);return r.data;};
  11. const fixtureFile=`${dir}/fixtures-${Date.now()}.json`;
  12. const saveFixtures=()=>fs.writeFileSync(fixtureFile,JSON.stringify(fixtures,null,2));
  13. const browser=await chromium.launch({channel:'msedge',headless:true,args:['--enable-unsafe-swiftshader']});
  14. const page=await browser.newPage({viewport:{width:1600,height:1000}});
  15. await page.addInitScript(s=>sessionStorage.setItem('unreal-tran:web:access-token:v1',s.accessToken),session);
  16. page.on('pageerror',e=>errors.push(e.message));
  17. const waitReady=async()=>{await expect(page.locator('[data-role="loading"]')).toHaveClass(/is-hidden/,{timeout:120000});await page.waitForFunction(()=>globalThis.__trainingSceneDiagnostics()?.bridgeWorkshop?.targets.length>0);await page.waitForTimeout(1800);};
  18. try {
  19. for(const script of scripts.filter(s=>s.version==='3' && (!process.env.BRIDGE_CODE || process.env.BRIDGE_CODE===s.code))) {
  20. const existing=fs.readdirSync(dir).filter(f=>f.startsWith('fixtures-')).flatMap(f=>JSON.parse(fs.readFileSync(dir+'/'+f,'utf8'))).find(f=>f.code===script.code && f.taskId);
  21. let task,fixture;
  22. if(existing){fixture={...existing};task=await api('tran/v1/teaching/assignments/'+fixture.taskId);fixtures.push(fixture);saveFixtures();}
  23. else {
  24. const content=await api('tran/v1/content/projects',{type:'TRAINING',name:`三维验收·${script.title}`,description:'Temporary 3D acceptance fixture',categoryCode:'MAINTENANCE',trainingMode:'VIRTUAL',content:scriptDefinition(script),dependencies:[],assets:[]});
  25. fixture={code:script.code,projectId:content.project.id};fixtures.push(fixture);saveFixtures();
  26. const project=(await api(`tran/v1/content/projects/${fixture.projectId}/publish`,{version:content.project.version})).project;
  27. task=await api('tran/v1/teaching/assignments',{code:`CHECK-3D-${Date.now()}-${script.code}`,name:`三维验收·${script.title}`,description:'Temporary acceptance fixture',channel:'VIRTUAL',assignmentKind:'TRAINING',executionMode:'PRACTICE',audienceType:'COMMON',collaborationMode:'INDIVIDUAL',digitalHumanAllowed:false,contentProjectId:project.id,contentVersionId:project.publishedVersionId,members:[]});
  28. fixture.taskId=task.id;saveFixtures();
  29. task=await api(`tran/v1/teaching/assignments/${task.id}/publish`,{version:task.version});
  30. }
  31. await page.goto(`http://127.0.0.1:6180/teaching/virtual-training/preview/${task.id}`);await waitReady();
  32. await expect(page.locator('.bridge-procedure')).toHaveCount(0);
  33. const bar=page.locator('[data-role="model-commandbar"]');
  34. for(const action of ['toggle-structure-tree','focus-selected-part','viewer-reset-view','toggle-part-labels','toggle-issue-highlight','toggle-hide-others','toggle-explosion'])await expect(bar.locator(`[data-action="${action}"]`)).toBeVisible();
  35. await page.screenshot({path:`${dir}/${script.code}-start.png`});
  36. fs.writeFileSync(`${dir}/${script.code}-diagnostic.json`,JSON.stringify(await page.evaluate(()=>globalThis.__trainingSceneDiagnostics()),null,2));
  37. for(let index=0;index<script.definition.steps.length;index++) {
  38. const step=script.definition.steps[index];
  39. await expect(page.locator('[data-role="step-count"]')).toHaveText(`${index+1} / ${script.steps.length}`);
  40. if(step.mode==='measure'){
  41. await page.locator('[data-open-preparation]').click();
  42. await page.locator('[data-measurement]').fill('按原稿连接管路,矛盾描述交教员核对。');
  43. await page.locator('[data-close-preparation]').click();
  44. }
  45. for(let k=0;k<step.action.mechanism.steps.length;k++) {
  46. const op=step.action.mechanism.steps[k];
  47. await expect.poll(async()=>page.evaluate(()=>globalThis.__trainingSceneDiagnostics().bridgeWorkshop.operationIndex)).toBe(k);
  48. if(k===step.action.mechanism.steps.length-1){
  49. const response=page.waitForResponse(r=>r.url().includes(`/assignments/${task.id}/preview/validate`));
  50. await page.locator('[data-role="part-label"]').click();
  51. assert.equal((await response).status(),200);
  52. }else{
  53. await page.locator('[data-role="part-label"]').click();
  54. await expect.poll(async()=>page.evaluate(()=>globalThis.__trainingSceneDiagnostics().bridgeWorkshop.operationIndex)).toBe(k+1);
  55. }
  56. await verifyVisualEffects(page,op);
  57. console.log(script.code,index+1,k+1,op.targetId);
  58. }
  59. await expect(page.locator('[data-action="next"]')).toBeEnabled();
  60. if([1,3,4,7,10,15].includes(index))await page.screenshot({path:`${dir}/${script.code}-step-${index+1}.png`});
  61. if(index<script.steps.length-1)await page.locator('[data-action="next"]').click();
  62. }
  63. assert.equal((await api(`tran/v1/teaching/runs?assignmentId=${task.id}&size=100`)).total,0);
  64. checks.push(`${script.code}: ${script.steps.length} steps, ${script.definition.steps.flatMap(s=>s.action.mechanism.steps).length} 3D operations; preview server validation passed`);
  65. fixture.passed=true;saveFixtures();
  66. }
  67. assert.deepEqual(errors,[]);
  68. fs.writeFileSync(`${dir}/acceptance.json`,JSON.stringify({pass:true,checks,errors},null,2));
  69. } catch(error){
  70. console.log('Feedback',await page.locator('.el-message').allTextContents());
  71. await page.screenshot({path:`${dir}/failure.png`}).catch(()=>{});
  72. fs.writeFileSync(`${dir}/acceptance.json`,JSON.stringify({pass:false,error:error.message,checks,errors},null,2));throw error;
  73. }finally{await browser.close();saveFixtures();}