const {chromium}=require(process.env.PLAYWRIGHT_MODULE || 'playwright'); const fs=require('fs'); (async()=>{ const browser=await chromium.launch({headless:true,channel:'chrome'});const page=await browser.newPage({viewport:{width:375,height:812}}); const errors=[];page.on('pageerror',e=>errors.push(e.message)); const feedback={contentSummary:'学习了八下4个,必修一6个,一共10个单词',reviewStatus:'复习上节课易错词',reviewSummary:'全部复习完成',trainingStatus:'正常进行',trainingSummary:'第4节课 / 20节',homework:'填写学习报表,并完成课后复习',noHomework:false,coachComment:'表现很好,继续保持',notes:'',vocabularyCount:10,durationMinutes:60,revision:'2026-10-13 10:26:09.101256+08'}; const order={GeneralID:901,szyh:20,pl:30,HoneyName:'测试学员',kcmc:'新课标高中考纲3000词',yykcmc:'新课标高中考纲3000词',dslx:2,dszt:30,bxrq:'2026-10-13',sdsd:'16:00',yysj:'2026-10-13 16:00',jffs:'线上',plxm:'钱老师',allowedActions:['editFeedback'],reviewStatus:'pending',feedback}; let saves=0; await page.addInitScript(()=>localStorage.setItem('xiaoshu.angular.session',JSON.stringify({token:'r:isolated-ui',user:{userId:30,groupId:3,honeyName:'测试老师'},student:null}))); await page.route('**/*',async r=>{if(!['127.0.0.1','localhost'].includes(new URL(r.request().url()).hostname))return r.abort();return r.continue();}); await page.route('**/cloud-functions/**',async route=>{ const p=route.request().postDataJSON()?.params||{};let result=[]; if(p.action==='e_order_detail')result=[order]; if(p.action==='app_live_versions')result={version:'test=1',scopeVersions:{appointments:'1'},syncStatus:{state:'current'}}; if(p.action==='user_get')result={userId:20,groupId:1,honeyName:'测试学员'}; if(p.action==='content_list'&&Number(p.ModelID)===59)result=[{yyds:'901',pldp:feedback.coachComment,plpjsj:'2026-10-13 10:26:09.101256+08'}]; if(p.action==='app_lesson_report')result={order,feedback,records:[{generalId:1,dqrq:'20261013',learned:10,ygg:10,djq:0,con:'八下 · 必修一'}],antiForget:{total:10,completed:2},refreshedAt:'2026-10-13T03:26:00Z'}; if(p.action==='app_lesson_feedback_update'){if(!p.requestKey)throw Error('missing key');Object.assign(feedback,JSON.parse(p.feedback));saves++;result={saved:true};} await route.fulfill({json:{retcode:0,result}}); }); const root='docs/qa/launch-fixes-2026-10-13/report-previews';fs.mkdirSync(root,{recursive:true}); for(const width of [375,812]){ await page.setViewportSize({width,height:812});await page.goto('http://127.0.0.1:4202/pages/shop/baobiao?id=901');await page.getByText('本次课堂报告').waitFor();await page.screenshot({path:`${root}/report-${width}.png`,fullPage:true}); if(await page.evaluate(()=>document.documentElement.scrollWidth>innerWidth))throw Error('report overflow '+width); await page.goto('http://127.0.0.1:4202/pages/shop/get_order?id=901');await page.getByText('课堂内容与下次学习安排').waitFor();await page.screenshot({path:`${root}/appointment-${width}.png`,fullPage:true}); if(await page.evaluate(()=>document.documentElement.scrollWidth>innerWidth))throw Error('appointment overflow '+width); await page.getByRole('button',{name:'修改报告'}).last().click();await page.getByRole('dialog').waitFor();await page.screenshot({path:`${root}/edit-${width}.png`}); await page.getByRole('button',{name:'取消修改'}).click(); } await page.getByRole('button',{name:'修改报告'}).last().click();await page.getByRole('textbox',{name:'本次学习的课本或强化内容'}).fill('已修改内容');await page.getByRole('button',{name:'保存修改'}).click();await page.getByText('报告修改已保存',{exact:true}).first().waitFor(); await page.goto('http://127.0.0.1:4202/pages/shop/baobiao?id=901');await page.getByRole('link',{name:'修改报告'}).click();await page.getByRole('dialog').waitFor({timeout:8000}).catch(async e=>{console.log('EDIT_LINK_DEBUG',page.url(),await page.evaluate(()=>{const c=ng.getComponent(document.querySelector('app-appointment-page'));return {meta:c.meta,handled:c.handledEditNavigation,navigation:c.editNavigation(),submitting:c.submitting(),verified:c.detailVerified(),can:c.can('editFeedback'),student:c.isStudentView,editing:c.editingFeedback(),dialog:c.completionDialog()?.nativeElement.outerHTML.slice(0,800),feedback:c.feedback(),url:c.router.url,params:c.route.snapshot.queryParams}}),errors);throw e;});await page.getByRole('button',{name:'取消修改'}).click(); await page.emulateMedia({reducedMotion:'reduce'});await page.setViewportSize({width:812,height:375});await page.getByRole('button',{name:'修改报告'}).last().click();await page.getByRole('button',{name:'保存修改'}).scrollIntoViewIfNeeded();if(await page.getByRole('dialog').evaluate(e=>e.scrollWidth>e.clientWidth))throw Error('landscape dialog overflow'); if(await page.evaluate(()=>JSON.parse(sessionStorage.getItem('xiaoshu.safe-diagnostics.v1')||'[]').some(x=>x.kind==='runtime')))throw Error('Angular runtime error');if(saves!==1)throw Error('save count '+saves);if(errors.length)throw Error(errors.join('\n')); console.log(JSON.stringify({viewports:[375,812],overflow:false,saves,pageErrors:errors,screenshots:root}));await browser.close(); })().catch(e=>{console.error(e);process.exit(1)});