Bläddra i källkod

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

main
leiyun 1 dag sedan
förälder
incheckning
756fd87067
21 ändrade filer med 227 tillägg och 0 borttagningar
  1. Binär
     
  2. Binär
     
  3. Binär
     
  4. Binär
     
  5. Binär
     
  6. Binär
     
  7. Binär
     
  8. Binär
     
  9. Binär
     
  10. Binär
     
  11. Binär
     
  12. Binär
     
  13. Binär
     
  14. Binär
     
  15. +1
    -0
      reports/bridge-introduction-layout-20260920/index.html
  16. +112
    -0
      reports/bridge-introduction-layout-20260920/result.json
  17. Binär
     
  18. Binär
     
  19. Binär
     
  20. Binär
     
  21. +114
    -0
      tools/bridge-introduction-layout-live.mjs

Binär
Visa fil


Binär
Visa fil


Binär
Visa fil


Binär
Visa fil


Binär
Visa fil


Binär
Visa fil


Binär
Visa fil


Binär
Visa fil


Binär
Visa fil


Binär
Visa fil


Binär
Visa fil


Binär
Visa fil


Binär
Visa fil


Binär
Visa fil


+ 1
- 0
reports/bridge-introduction-layout-20260920/index.html Visa fil

@@ -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 Visa fil

@@ -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är
Visa fil


Binär
Visa fil


Binär
Visa fil


Binär
Visa fil


+ 114
- 0
tools/bridge-introduction-layout-live.mjs Visa fil

@@ -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();}

Laddar…
Avbryt
Spara