"""Mock-backed real workspace Chromium test; NEVER touches production or localhost HTTP.""" from pathlib import Path from playwright.sync_api import sync_playwright ROOT=Path(__file__).resolve().parents[1] def run(): errors=[] with sync_playwright() as p: browser=p.chromium.launch(headless=True,executable_path='/usr/bin/chromium',args=['--no-sandbox']) page=browser.new_page(viewport={'width':1366,'height':900}) page.on('pageerror',lambda e:errors.append(str(e))) markup=(ROOT/'app/templates/workspace.html').read_text() for tag in ('','','',''): markup=markup.replace(tag,'') page.set_content(markup) page.add_style_tag(content=(ROOT/'app/static/workspace.css').read_text()) page.evaluate(r'''() => { window.history.replaceState=()=>{};window.history.pushState=()=>{};Object.defineProperty(window.crypto,'randomUUID',{value:()=> 'mock-idempotency-uuid'}); window.confirm=()=>true; window.mock={approved:false,submitCount:0,requests:[],deployCount:0,site:{id:'s1',name:'测试网站',theme:'corporate',mode:'new',domain:'https://www.example.com',updated_at:'2026-01-01T00:00:00Z'}, builds:[{id:'b1',status:'complete',created_at:'2026-01-03T00:00:00Z',total_pages:12}]}; window.fetch=async (uri,opts={})=>{ let key=String(uri).split('?')[0],method=opts.method||'GET',result=null,status=200; const m=window.mock; if(key==='/api/auth/me')result={csrf:'test'}; else if(key==='/api/health')result={version:'8.28.0-dev.1'}; else if(key==='/api/sites'&&method==='GET')result=[m.site]; else if(key==='/api/sites/s1')result=m.site; else if(key==='/api/sites/s1/entries')result=[{id:'h1',source:'manual',status:'published',route:'/',type:'page',title:'网站首页'}]; else if(key==='/api/sites/s1/builds')result=m.builds; else if(key==='/api/enterprise/sites/s1/jobs')result=[]; else if(key==='/api/production/sites/s1/delivery-status')result={jobs:[],history:[],configured:{production:true,staging:true}}; else if(key==='/api/factory/sites/s1/release-requests'&&method==='GET')result=m.requests; else if(key==='/api/factory/sites/s1/release-requests'&&method==='POST') {result={id:'r1',state:'pending'};m.requests=[{id:'r1',build_id:'b1',state:'pending'}]} else if(key==='/api/production/sites/s1/preflight/b1')result={ready:m.approved,build_id:'b1',message:m.approved?'已批准':'尚未批准'}; else if(key==='/api/production/sites/s1/deploy'&&method==='POST') {m.deployCount++; result={id:'job-test-1'};} else if(key==='/api/sites/s1/builds/b1/report')result={pages:12,warnings:[],redirects:0}; else {status=404;result={detail:'模拟接口没有实现 '+key};} return {ok:status<400,status,json:async()=>result}; }; }''') for name in ('workspace-guide.js','workspace-launch.js','workspace.js'): page.add_script_tag(content=(ROOT/'app/static'/name).read_text()) page.evaluate("document.dispatchEvent(new Event('DOMContentLoaded'))") page.wait_for_selector('.site-card',timeout=10000) page.locator('.site-card').first.click() page.locator('[data-view="launch"].nav-item').click() page.wait_for_timeout(1100) page.wait_for_selector('.sf-launch-step',timeout=3000) assert page.locator('.sf-launch-step').count()==6 assert page.locator('[data-action="launch-deploy"]').is_disabled() assert page.locator('[data-action="launch-request-approval"]').is_disabled() page.locator('#launchReviewCheck').check() assert page.locator('[data-action="launch-request-approval"]').is_enabled() page.locator('[data-action="launch-request-approval"]').click() page.wait_for_timeout(400) page.wait_for_function('window.mock.requests.length===1',timeout=3500) assert page.locator('[data-action="launch-preflight"]').is_disabled() page.evaluate("window.mock.requests[0].state='approved';window.mock.approved=true") page.locator('[data-action="launch-refresh"]').first.click() page.wait_for_timeout(600) page.wait_for_function("document.querySelector('[data-action=launch-preflight]')?.disabled===false",timeout=4000) page.locator('[data-action="launch-preflight"]').click() page.wait_for_timeout(450) page.wait_for_function("document.querySelector('[data-action=launch-deploy]')?.disabled===false",timeout=4000) page.locator('[data-action="launch-deploy"]').click() page.wait_for_function('window.mock.deployCount===1') assert '已进入后台队列' in page.locator('#launchNotice').inner_text() report=ROOT/'reports/v828';report.mkdir(parents=True,exist_ok=True) page.evaluate('window.scrollTo(0,0)') page.wait_for_timeout(150) page.screenshot(path=str(report/'launch-desktop.png'),full_page=True) page.set_viewport_size({'width':390,'height':844}) page.wait_for_timeout(250) page.screenshot(path=str(report/'launch-mobile.png'),full_page=True) assert page.evaluate('document.documentElement.scrollWidth<=innerWidth+1'),'mobile overflow' assert not errors,errors browser.close() print('PASS: original workspace JS, approval flow, preview checkbox, preflight, submit mock, mobile width, 0 runtime errors') if __name__=='__main__':run()