| 1234567891011121314151617181920212223242526272829303132333435363738394041424344 |
- const {chromium}=require('playwright');const fs=require('fs');
- (async()=>{const browser=await chromium.launch({channel:'chrome',headless:true}),page=await browser.newPage(),errors=[];page.on('pageerror',e=>errors.push(e.message));page.on('dialog',d=>d.accept());
- await page.addInitScript(()=>{
- if(location.pathname.includes('/stu/')) {
- localStorage.setItem('xiaoshu.angular.session',JSON.stringify({token:'r:fixture',user:{userId:100,groupId:1,honeyName:'隔离学员'}}));
- const prefix='xiaoshu.learning.100.100.practice.',words=[{GeneralID:1,Title:'apple',sy:'苹果'},{GeneralID:2,Title:'banana',sy:'香蕉'},{GeneralID:3,Title:'orange',sy:'橙子'},{GeneralID:4,Title:'pear',sy:'梨'}];
- for(const [key,value]of Object.entries({learn_mode:'newword',choose_newword_learn:words,_page_word_orilist:[words],_page_current_learn:1}))localStorage.setItem(prefix+key,JSON.stringify(value));
- return;
- }
- localStorage.setItem('xiaoshu.angular.session',JSON.stringify({token:'r:fixture',user:{userId:30,groupId:3,honeyName:'测试老师'},student:{userId:20,groupId:1,honeyName:'测试学员'}}));
- });
- let learned=52,fail=true;const order={GeneralID:901,szyh:20,pl:30,dszt:10,HoneyName:'测试学员',bindingId:'binding',kcid:161,allowedActions:['continue','complete'],updatedAt:new Date().toISOString()};
- await page.route('**/*',r=>['127.0.0.1','localhost'].includes(new URL(r.request().url()).hostname)?r.continue():r.abort());
- await page.route('**/cloud-functions/**',async r=>{const p=r.request().postDataJSON()?.params||{};let result=[];
- if(p.action==='e_order_detail')result=[order];
- if(p.action==='app_lesson_study')result={record:null,batches:[],pending:0};
- if(p.action==='app_lesson_courses')result={items:[{bindingId:'binding',kcid:161,Title:'高中词库',categoryKey:'word',syjd:learned===100?'{"172":"172@必修一全册@1"}':'{}'}]};
- if(p.action==='node_list')result=[{NodeID:172,NodeName:'必修一全册',total:100,yx_word:learned}];
- if(p.action==='app_live_versions')result={version:'fixture',scopeVersions:{},syncStatus:{state:'current'}};
- if(p.action==='app_lesson_unit_complete'){
- if(fail){fail=false;return r.fulfill({status:503,json:{retcode:-1,retmsg:'保存失败'}});}
- learned=100;result={nodeId:172,total:100,learned:100,percent:100,syjd:'{"172":"172@必修一全册@1"}'};
- }
- if(p.action==='content_list')result=Array.from({length:20},(_,i)=>({GeneralID:300+i,Title:'extra'+i,sy:'拓展释义'+i}));
- await r.fulfill({json:{retcode:0,result}});
- });
- const out='docs/qa/learning-experience-2026-10-13';
- await page.setViewportSize({width:375,height:812});await page.goto('http://127.0.0.1:4200/pages/shop/get_order?id=901');
- await page.getByText('已学 52%',{exact:true}).waitFor();await page.getByRole('button',{name:'标记已学完'}).click();
- await page.getByRole('button',{name:'标记已学完'}).waitFor();await page.waitForFunction(()=>!document.querySelector('.mark-complete')?.disabled);
- if(!(await page.getByText('已学 52%',{exact:true}).count()))throw Error('failed save changed progress');
- await page.getByRole('button',{name:'标记已学完'}).click();await page.getByText('已学 100%',{exact:true}).waitFor();await page.reload();await page.getByText('已学 100%',{exact:true}).waitFor();
- for(const width of [375,812]){await page.setViewportSize({width,height:812});await page.locator('.unit-grid').scrollIntoViewIfNeeded();await page.screenshot({path:out+'/unit-'+width+'.png'});if(await page.evaluate(()=>document.documentElement.scrollWidth>innerWidth))throw Error('overflow');}
- await page.setViewportSize({width:375,height:812});await page.goto('http://127.0.0.1:4200/pages/stu/stu4');
- await page.locator('.option-list button').first().waitFor();
- const options=await page.locator('.option-list button').allTextContents();
- if(options.length!==4||options.filter(x=>x.startsWith('拓展释义')).length<2)throw Error('missing external choices');
- await page.screenshot({path:out+'/listening-375.png',fullPage:true});
- const audio=await page.evaluate(async()=>{const results=[];for(const kind of ['success','error']){const response=await fetch('/assets/audio/learning-'+kind+'.wav');const data=await response.arrayBuffer();const context=new AudioContext();const buffer=await context.decodeAudioData(data);results.push({kind,ok:response.ok,duration:buffer.duration});await context.close();}return results;});
- if(audio.some(a=>!a.ok||a.duration<.1||a.duration>.5))throw Error('invalid audio asset');
- await browser.close();
- fs.writeFileSync(out+'/browser-result.json',JSON.stringify({viewports:[375,812],failedSavePreserved:true,savedProgress:100,refreshProgress:100,listeningOptions:options,audio,pageErrors:errors},null,2));
- if(errors.length)throw Error(errors.join('\n'));console.log('Unit progress failure, success, reload and responsive browser checks passed');
- })().catch(e=>{console.error(e);process.exit(1)});
|