Pārlūkot izejas kodu

test(training): verify unified introduction navigation and responsive layouts

main
leiyun pirms 1 dienas
vecāks
revīzija
756fd87067
21 mainītis faili ar 227 papildinājumiem un 0 dzēšanām
  1. Binārs
     
  2. Binārs
     
  3. Binārs
     
  4. Binārs
     
  5. Binārs
     
  6. Binārs
     
  7. Binārs
     
  8. Binārs
     
  9. Binārs
     
  10. Binārs
     
  11. Binārs
     
  12. Binārs
     
  13. Binārs
     
  14. Binārs
     
  15. +1
    -0
      reports/bridge-introduction-layout-20260920/index.html
  16. +112
    -0
      reports/bridge-introduction-layout-20260920/result.json
  17. Binārs
     
  18. Binārs
     
  19. Binārs
     
  20. Binārs
     
  21. +114
    -0
      tools/bridge-introduction-layout-live.mjs

Binārs
Parādīt failu


Binārs
Parādīt failu


Binārs
Parādīt failu


Binārs
Parādīt failu


Binārs
Parādīt failu


Binārs
Parādīt failu


Binārs
Parādīt failu


Binārs
Parādīt failu


Binārs
Parādīt failu


Binārs
Parādīt failu


Binārs
Parādīt failu


Binārs
Parādīt failu


Binārs
Parādīt failu


Binārs
Parādīt failu


+ 1
- 0
reports/bridge-introduction-layout-20260920/index.html Parādīt failu

@@ -0,0 +1 @@
<!doctype html><html lang="zh-CN"><meta charset="utf-8"><title>背景讲解布局验收</title><style>body{font:16px system-ui;margin:32px;background:#eff5f3;color:#16463e}img{width:100%;border:1px solid #bed5d0;border-radius:8px}section{margin:24px 0}a{color:#078773}</style><h1>背景讲解布局验收</h1><p>四个任务通过:统一滚动、图文分栏、小屏布局、翻页与跳过;操作进度保持不变。未写入任务数据。</p><section><h2>TASK-VIRTUAL-005</h2><a href="86-desktop.png">桌面截图</a> · <a href="86-1280.png">1280 × 720</a><img src="86-1366.png"></section><section><h2>TASK-VIRTUAL-006</h2><a href="87-desktop.png">桌面截图</a> · <a href="87-1280.png">1280 × 720</a><img src="87-1366.png"></section><section><h2>TASK-VIRTUAL-007</h2><a href="88-desktop.png">桌面截图</a> · <a href="88-1280.png">1280 × 720</a><img src="88-1366.png"></section><section><h2>TASK-VIRTUAL-008</h2><a href="89-desktop.png">桌面截图</a> · <a href="89-1280.png">1280 × 720</a><img src="89-1366.png"></section></html>

+ 112
- 0
reports/bridge-introduction-layout-20260920/result.json Parādīt failu

@@ -0,0 +1,112 @@
{
"pass": true,
"checks": [
{
"id": 86,
"viewport": {
"width": 1366,
"height": 768
},
"scrollable": true,
"introMoves": true,
"stepsOverflow": "visible",
"horizontalOverflow": false,
"imageTextOverlap": false
},
{
"id": 86,
"viewport": {
"width": 1280,
"height": 720
},
"scrollable": true,
"introMoves": true,
"stepsOverflow": "visible",
"horizontalOverflow": false,
"imageTextOverlap": false
},
{
"id": 87,
"viewport": {
"width": 1366,
"height": 768
},
"scrollable": true,
"introMoves": true,
"stepsOverflow": "visible",
"horizontalOverflow": false,
"imageTextOverlap": false
},
{
"id": 87,
"viewport": {
"width": 1280,
"height": 720
},
"scrollable": true,
"introMoves": true,
"stepsOverflow": "visible",
"horizontalOverflow": false,
"imageTextOverlap": false
},
{
"id": 88,
"viewport": {
"width": 1366,
"height": 768
},
"scrollable": true,
"introMoves": true,
"stepsOverflow": "visible",
"horizontalOverflow": false,
"imageTextOverlap": false
},
{
"id": 88,
"viewport": {
"width": 1280,
"height": 720
},
"scrollable": true,
"introMoves": true,
"stepsOverflow": "visible",
"horizontalOverflow": false,
"imageTextOverlap": false
},
{
"id": 89,
"viewport": {
"width": 1366,
"height": 768
},
"scrollable": true,
"introMoves": true,
"stepsOverflow": "visible",
"horizontalOverflow": false,
"imageTextOverlap": false
},
{
"id": 89,
"viewport": {
"width": 1280,
"height": 720
},
"scrollable": true,
"introMoves": true,
"stepsOverflow": "visible",
"horizontalOverflow": false,
"imageTextOverlap": false
},
{
"optionalTextAndVideo": true,
"videoStopsOnSkip": true
},
{
"lanGatewayProxy": true
}
],
"errors": [],
"writes": [],
"accountType": "internal maintenance preview",
"testDataCreated": false
}

Binārs
Parādīt failu


Binārs
Parādīt failu


Binārs
Parādīt failu


Binārs
Parādīt failu


+ 114
- 0
tools/bridge-introduction-layout-live.mjs Parādīt failu

@@ -0,0 +1,114 @@
import fs from 'node:fs';
import assert from 'node:assert/strict';
import {chromium, expect} from '@playwright/test';
import {login} from './role-permissions-live.mjs';
import videoManifest from '../../unreal_tran_web/src/features/virtual-training-scripts/narration-video-manifest.js';

const dir='reports/bridge-introduction-layout-20260920';
fs.mkdirSync(dir,{recursive:true});
const signed=await login('root'), checks=[], errors=[], writes=[];
const browser=await chromium.launch({channel:'msedge',headless:true,args:['--enable-unsafe-swiftshader']});
const page=await browser.newPage({viewport:{width:1920,height:1080}});
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'}));
},signed);
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()+'\nglobalThis.introLayoutState=()=>activeTraining?{step:activeTraining.session.stepIndex,completed:[...activeTraining.session.completed]}:null;'});
});
page.on('pageerror',e=>errors.push(e.message));
page.on('request',r=>{if(r.url().includes('/api/tran/')&&!['GET','HEAD'].includes(r.method()))writes.push(new URL(r.url()).pathname);});
const state=()=>page.evaluate(()=>globalThis.introLayoutState?.());
const overlay=page.locator('.training-introduction');
try {
for(const [id,pages,steps] of [[86,6,5],[87,3,7],[88,1,11],[89,1,16]]) {
await page.goto(`http://127.0.0.1:6180/teaching/virtual-training/preview/${id}`);
await expect(overlay).toBeVisible({timeout:120000});
await expect(page.locator('[data-intro-page]')).toHaveCount(pages);
await expect(page.locator('[data-step-index]')).toHaveCount(steps);
await expect(page.locator('[data-role="step-count"]')).toHaveText(`1 / ${pages+steps}`);
await expect.poll(()=>overlay.locator('img').evaluateAll(images=>images.every(i=>i.complete&&i.naturalWidth>0)),{timeout:30000}).toBe(true);
const original=await state(), writeCount=writes.length;
await page.screenshot({path:`${dir}/${id}-desktop.png`});
for(const viewport of [{width:1366,height:768},{width:1280,height:720}]) {
await page.setViewportSize(viewport);
const layout=await page.evaluate(()=>{
const scroller=document.querySelector('.training-sequence-scroll');
const root=document.querySelector('[data-role="steps"]');
const content=document.querySelector('.training-introduction-content');
const image=document.querySelector('.introduction-visual'),text=document.querySelector('.introduction-reading');
const before=scroller.querySelector('[data-intro-page]').getBoundingClientRect().top;
scroller.scrollTop=scroller.scrollHeight;
return {scrollable:scroller.scrollHeight>scroller.clientHeight,
introMoves:scroller.querySelector('[data-intro-page]').getBoundingClientRect().top<before,
stepsOverflow:getComputedStyle(root).overflowY,
horizontalOverflow:content.scrollWidth>content.clientWidth,
imageTextOverlap:image&&text?image.getBoundingClientRect().right>text.getBoundingClientRect().left:false};
});
assert.ok(layout.scrollable);assert.ok(layout.introMoves);
assert.equal(layout.stepsOverflow,'visible');assert.equal(layout.horizontalOverflow,false);assert.equal(layout.imageTextOverlap,false);
await expect(page.locator('[data-step-index]').last()).toBeInViewport();
await expect(overlay.locator('[data-intro-command="skip"]')).toBeInViewport();
await expect(overlay.locator('[data-intro-command="next"]')).toBeInViewport();
await page.locator('.training-sequence-scroll').evaluate(el=>el.scrollTop=0);
await page.screenshot({path:`${dir}/${id}-${viewport.width}.png`});
checks.push({id,viewport,...layout});
}
for(let i=1;i<pages;i++) {
await overlay.locator('[data-intro-command="next"]').click();
await expect(page.locator(`[data-intro-page="${i}"]`)).toHaveAttribute('aria-current','page');
assert.deepEqual(await state(),original);
}
if(pages>1)await page.screenshot({path:`${dir}/${id}-lecture.png`});
await overlay.locator('[data-intro-command="next"]').click();
await expect(overlay).toBeHidden();
assert.deepEqual(await state(),original);
await expect(page.locator('[data-step-index="0"]')).toBeInViewport();
await page.locator('[data-intro-page="0"]').click();
await expect(overlay).toBeVisible();
await overlay.locator('[data-intro-command="skip"]').click();
await expect(overlay).toBeHidden();assert.deepEqual(await state(),original);
assert.equal(writes.length,writeCount);
await page.setViewportSize({width:1920,height:1080});
console.log('PASS task',id);
}
// Browser-only response fixture validates optional media without changing any saved task.
await page.route(/\/api\/tran\/v1\/teaching\/assignments\/86$/,async route=>{
const response=await route.fetch(),body=await response.json();
body.data.definitionSnapshot.introduction={background:{enabled:true,title:'纯文字背景',body:'没有背景图时,正文保持居中阅读。\n讲解切换不推进操作步骤。'},lectures:[{id:'video-check',title:'视频讲解',format:'video',videoUrl:videoManifest.scripts[0].steps[0].url}]};
await route.fulfill({response,json:body});
});
await page.goto('http://127.0.0.1:6180/teaching/virtual-training/preview/86');
await expect(overlay).toBeVisible({timeout:120000});
await expect(overlay.locator('.is-text-only')).toBeVisible();
await expect(overlay.locator('.introduction-reading p')).toHaveCount(2);
await page.screenshot({path:`${dir}/text-only.png`});
await overlay.locator('[data-intro-command="next"]').click();
const video=overlay.locator('video');await expect(video).toBeVisible();
await video.evaluate(el=>el.play());
await expect.poll(()=>video.evaluate(el=>el.currentTime),{timeout:30000}).toBeGreaterThan(0);
await page.screenshot({path:`${dir}/video.png`});
await page.evaluate(()=>globalThis.previousIntroVideo=document.querySelector('.training-introduction video'));
await overlay.locator('[data-intro-command="skip"]').click();
assert.equal(await page.evaluate(()=>globalThis.previousIntroVideo.paused&&!globalThis.previousIntroVideo.getAttribute('src')),true);
checks.push({optionalTextAndVideo:true,videoStopsOnSkip:true});
await page.unroute(/\/api\/tran\/v1\/teaching\/assignments\/86$/);
await page.goto('http://127.0.0.1:6180/teaching/virtual-training/preview/86');
await expect(overlay).toBeVisible({timeout:120000});
await expect.poll(()=>overlay.locator('img').evaluateAll(images=>images.every(i=>i.complete&&i.naturalWidth>0))).toBe(true);
for(const mode of ['dark','military']) {
await page.evaluate(mode=>{document.documentElement.classList.toggle('dark',mode==='dark');document.documentElement.dataset.colorTheme=mode;document.documentElement.dataset.theme=mode==='dark'?'dark':'light';},mode);
await page.screenshot({path:`${dir}/theme-${mode}.png`});
}
const lan=await page.request.get('http://192.168.31.168:6180/api/auth/v1/system-config/public');
assert.equal(lan.status(),200);checks.push({lanGatewayProxy:true});
assert.deepEqual(errors,[]);
fs.writeFileSync(`${dir}/result.json`,JSON.stringify({pass:true,checks,errors,writes,accountType:'internal maintenance preview',testDataCreated:false},null,2));
fs.writeFileSync(`${dir}/index.html`,`<!doctype html><html lang="zh-CN"><meta charset="utf-8"><title>背景讲解布局验收</title><style>body{font:16px system-ui;margin:32px;background:#eff5f3;color:#16463e}img{width:100%;border:1px solid #bed5d0;border-radius:8px}section{margin:24px 0}a{color:#078773}</style><h1>背景讲解布局验收</h1><p>四个任务通过:统一滚动、图文分栏、小屏布局、翻页与跳过;操作进度保持不变。未写入任务数据。</p>${[86,87,88,89].map((id,i)=>`<section><h2>TASK-VIRTUAL-00${i+5}</h2><a href="${id}-desktop.png">桌面截图</a> · <a href="${id}-1280.png">1280 × 720</a><img src="${id}-1366.png"></section>`).join('')}</html>`);
} catch(error) {
await page.screenshot({path:`${dir}/failure.png`});
fs.writeFileSync(`${dir}/failure.json`,JSON.stringify({error:error.stack,errors},null,2));
throw error;
} finally {await browser.close();}

Notiek ielāde…
Atcelt
Saglabāt