|
- import fs from 'node:fs';
- import assert from 'node:assert/strict';
- import {chromium,expect} from '@playwright/test';
- import {login,call} from './role-permissions-live.mjs';
- const dir='reports/bridge-005-authoring-20260916',fixture=JSON.parse(fs.readFileSync(dir+'/pilot.json','utf8'));
- const angle=Number(process.env.TARGET_ANGLE||75);
- const signed=await login('root'),errors=[];
- const browser=await chromium.launch({channel:'msedge',headless:true,args:['--enable-unsafe-swiftshader']});
- const page=await browser.newPage({viewport:{width:1680,height:1050}});
- await page.addInitScript(s=>{sessionStorage.setItem('unreal-tran:web:access-token:v1',s.accessToken);sessionStorage.setItem('unreal-tran:web:refresh-token:v1',s.refreshToken);},signed);
- await page.route(/\/src\/features\/guide-legacy\/demo-src\/training-editor\.js(?:\?|$)/,async route=>{const response=await route.fetch();await route.fulfill({response,body:(await response.text()).replace('const editor = new TrainingProjectEditor(root, options);','const editor = new TrainingProjectEditor(root, options); globalThis.pilotEditor = editor;')});});
- await page.route(/\/src\/features\/guide-legacy\/demo-src\/scene-editor\.js(?:\?|$)/,async route=>{const response=await route.fetch();await route.fulfill({response,body:(await response.text())+'\nglobalThis.pilotScene=()=>activeSceneEditor;'});});
- page.on('pageerror',e=>errors.push(e.message));
- await page.route(/\/src\/views\/content\/LegacyScenePageView\.vue(?:\?|$)/,async route=>{const response=await route.fetch();await route.fulfill({response,body:(await response.text()).replace('mountError.value = error instanceof Error', 'globalThis.__sceneError = String(error?.stack || error); mountError.value = error instanceof Error')});});
- try{
- await page.goto('http://127.0.0.1:6180/content/scenes/'+fixture.sceneId+'/edit');
- await expect.poll(()=>page.evaluate(()=>{if(globalThis.__sceneError)throw new Error(globalThis.__sceneError);return !!globalThis.pilotScene?.()?.readySettled;}),{timeout:120000}).toBe(true);
- const scene=await page.evaluate(()=>{const e=globalThis.pilotScene();return {objects:e.serialize().objects,ready:e.pendingLoads};});
- fs.writeFileSync(dir+'/scene-editor-roundtrip.json',JSON.stringify(scene,null,2));
- assert.equal(scene.objects.filter(o=>o.type==='imported').length,2);assert.equal(scene.objects.flatMap(o=>o.modelPartTargets||[]).length,7);
- await page.screenshot({path:dir+'/scene-editor.png'});
- if(!process.env.FINALIZE||process.env.SAVE_SCENE==='1')await page.evaluate(async keepCamera=>{const e=globalThis.pilotScene();if(!keepCamera)e.camera.position.x+=0.25;await e.saveProject();await e.publishScene();},process.env.SAVE_SCENE==='1');
- const sceneSaved=(await call('tran/v1/content/projects/'+fixture.sceneId,signed.accessToken)).data;
- assert.equal(sceneSaved.currentVersion.status,'PUBLISHED');
- assert.equal(sceneSaved.currentVersion.content.objects.flatMap(o=>o.modelPartTargets||[]).length,7);
- fixture.sceneVersionId=sceneSaved.project.publishedVersionId;
- fs.writeFileSync(dir+'/pilot.json',JSON.stringify(fixture,null,2));
- await page.goto('http://127.0.0.1:6180/content/training-projects/'+fixture.trainingId+'/legacy');
- await expect(page.locator('[data-action="configure-mechanism"]')).toBeVisible({timeout:120000});
- await page.evaluate(async id=>{const e=globalThis.pilotEditor;await e.getPublishedScenes();await e.bindPublishedScene(id);for(const s of e.project.steps)e.setStepToolRequirements(s.id,[]);},fixture.sceneId+'@'+fixture.sceneVersionId);
- assert.equal(await page.evaluate(()=>globalThis.pilotEditor.project.scenario.sceneResource.sourceVersionId),fixture.sceneVersionId);
- const before=await page.evaluate(()=>structuredClone(globalThis.pilotEditor.project));
- assert.equal(before.steps.length,5);assert.ok(before.steps.every(s=>s.action.kind==='mechanism-operation'));
- assert.equal(before.steps[4].action.mechanism.steps.length,2);
- fs.writeFileSync(dir+'/training-editor-roundtrip.json',JSON.stringify(before,null,2));
- await page.locator('[data-action="select-step"][data-step-id="'+before.steps[2].id+'"]').first().click();
- await page.locator('[data-action="configure-mechanism"]').click();
- const dialog=page.getByRole('dialog',{name:'配置机构动作'});
- await dialog.getByRole('spinbutton').first().fill(String(angle));
- await dialog.getByRole('button',{name:'应用到步骤'}).click();
- await expect(dialog).toBeHidden();
- assert.equal(await page.evaluate(()=>globalThis.pilotEditor.project.steps[2].action.mechanism.steps[0].deltaDegrees),angle);
- await page.screenshot({path:dir+'/training-editor.png'});
- const saved=page.waitForResponse(r=>r.url().includes('/content/projects/'+fixture.trainingId)&&r.request().method()==='PUT');
- await page.locator('[data-action="save"]').click();assert.equal((await saved).status(),200);
- await page.reload();
- await expect(page.locator('[data-action="configure-mechanism"]')).toBeVisible({timeout:120000});
- assert.equal(await page.evaluate(()=>globalThis.pilotEditor.project.steps[2].action.mechanism.steps[0].deltaDegrees),angle);
- const detail=(await call('tran/v1/content/projects/'+fixture.trainingId,signed.accessToken)).data;
- assert.equal(detail.currentVersion.content.steps[2].action.mechanism.steps[0].deltaDegrees,angle);
- assert.ok(detail.currentVersion.content.steps.every(s=>s.action.kind==='mechanism-operation'));
- assert.equal(detail.currentVersion.content.steps[4].action.mechanism.steps.length,2);
- for(const [i,step] of detail.currentVersion.content.steps.entries()){
- assert.equal(step.audio.narrationVideoAssetCode,'PILOT-005-'+(i+1)+'-VIDEO');
- assert.equal(step.audio.narrationAssetCode,'PILOT-005-'+(i+1)+'-AUDIO');
- }
- const published=page.waitForResponse(r=>r.url().endsWith('/content/projects/'+fixture.trainingId+'/publish')&&r.request().method()==='POST',{timeout:30000});
- await page.locator('[data-action="publish"]').click();assert.equal((await published).status(),200);
- const publishedDetail=(await call('tran/v1/content/projects/'+fixture.trainingId,signed.accessToken)).data;
- fixture.trainingVersionId=publishedDetail.project.publishedVersionId;
- const task=(await call('tran/v1/teaching/assignments/'+fixture.taskId,signed.accessToken)).data;
- assert.equal(task.status,'DRAFT');
- const rebound=await call('tran/v1/teaching/assignments/'+fixture.taskId,signed.accessToken,{...task,contentVersionId:fixture.trainingVersionId,version:task.version},'PUT');
- assert.equal(rebound.status,200,rebound.message);
- fs.writeFileSync(dir+'/pilot.json',JSON.stringify(fixture,null,2));
- fs.writeFileSync(dir+'/editor-result-'+angle+'.json',JSON.stringify({pass:true,sceneObjects:2,partTargets:7,steps:5,operations:6,savedAngle:angle,originalPublishedVersion:fixture.trainingVersionId,draftVersion:detail.currentVersion.id,errors},null,2));
- console.log('EDITOR PASS',detail.currentVersion.id);
- }catch(error){await page.screenshot({path:dir+'/editor-failure.png'});fs.writeFileSync(dir+'/editor-error.json',JSON.stringify({error:error.stack,errors,body:(await page.locator('body').innerText()).slice(-6500)},null,2));throw error;}finally{await browser.close();}
|