95982fad23
Overlay 46 upstream items; full patch set re-applied (all patched files reset by overlay regardless of upstream change status — lesson recorded). Verified: theme suites 35/35; dual-baseline 418 passed vs pristine 389+29 ours, FAILED-set diff EMPTY (same 10 Windows env fails). Live: container 8.32.0-dev.1 healthy, hesupipe 192 entries intact, trade-pro build 203 pages 0 errors. Co-Authored-By: Claude Code <noreply@anthropic.com>
82 lines
7.6 KiB
Python
82 lines
7.6 KiB
Python
"""Exercise actual V8.32 editor HTML/CSS/JS with deterministic same-page mock data.
|
|
Not an authenticated back-end browser E2E (Chromium container blocks local network).
|
|
"""
|
|
from pathlib import Path
|
|
import json,re
|
|
from playwright.sync_api import sync_playwright
|
|
ROOT=Path(__file__).resolve().parents[1]
|
|
OUT=ROOT/'reports/v832'
|
|
OUT.mkdir(parents=True,exist_ok=True)
|
|
source=(ROOT/'app/templates/editor.html').read_text(encoding='utf-8')
|
|
source=re.sub(r'<script[^>]+src="[^"]+"[^>]*></script>','',source)
|
|
source=re.sub(r'<link[^>]+href="/ui/[^"]+"[^>]*>','',source)
|
|
js=(ROOT/'app/static/editor.js').read_text(encoding='utf-8').replace('const siteId=pathParts[1],initialPage=pathParts[2];',"const siteId='demo',initialPage='p1';")
|
|
schema={'blocks':{
|
|
'hero':{'name':'大图横幅','icon':'▧','description':'网站首页顶部横幅','fields':['title','subtitle','image'],'defaults':{'title':'HESU AUTO','subtitle':'连接中国汽车与全球市场','image':''}},
|
|
'richtext':{'name':'文字介绍','icon':'▤','description':'企业介绍文字','fields':['title','description'],'defaults':{'title':'关于我们','description':'车辆出口服务'}},
|
|
'collection':{'name':'车型列表','icon':'▦','description':'展示产品与车型','fields':['title'],'defaults':{'title':'精选车型'}},
|
|
'layout':{'name':'多列布局','icon':'◫','fields':['title'],'defaults':{'title':'两列布局','columns':[{'width':1,'blocks':[]},{'width':1,'blocks':[]}]}}
|
|
},'page_templates':{'standard':{'name':'标准页面'}}}
|
|
errors=[]
|
|
with sync_playwright() as p:
|
|
browser=p.chromium.launch(executable_path='/usr/bin/chromium',args=['--no-sandbox','--disable-dev-shm-usage'],headless=True)
|
|
page=browser.new_page(viewport={'width':1440,'height':900},device_scale_factor=1)
|
|
page.on('pageerror',lambda err:errors.append(str(err)))
|
|
page.set_content(source)
|
|
page.add_style_tag(content=(ROOT/'app/static/editor.css').read_text(encoding='utf-8'))
|
|
page.add_script_tag(content=(ROOT/'app/static/editor-helpers.js').read_text(encoding='utf-8'))
|
|
page.add_script_tag(content=(ROOT/'app/static/studio-experience-v829.js').read_text(encoding='utf-8'))
|
|
page.evaluate('''(schema)=>{
|
|
window.fetch=async function(url,options={}){
|
|
const path=String(url).split('?')[0];
|
|
if(path.startsWith('/api/factory/themes/')){
|
|
const ok=window.__previewOk!==false;
|
|
return {ok,status:ok?200:503,headers:{get:()=>ok?'text/html':'text/plain'},text:async()=>'<html><body><h1>主题预览</h1></body></html>'};
|
|
}
|
|
if(path.endsWith('/editor-preview'))return {ok:true,status:200,headers:{get:()=> 'text/html'},text:async()=>`<html><head><meta name=viewport content='width=device-width,initial-scale=1'><style>*{box-sizing:border-box}body{margin:0;font:15px/1.6 system-ui,sans-serif;color:#20354a;background:#fff}nav{display:flex;justify-content:space-between;align-items:center;gap:18px;padding:17px 5%;border-bottom:1px solid #e8eef3}nav b{color:#d56a2e;font-size:22px}nav span{font-size:12px;color:#64748b}.hero{background:linear-gradient(110deg,#eaf0f5,#f5f8fb);padding:62px 6%;border-bottom:1px solid #dde5ee}.eyebrow{color:#cd6b33;font-weight:800;letter-spacing:2px;font-size:11px}.hero h1{font-size:clamp(29px,4vw,54px);max-width:670px;line-height:1.18;margin:14px 0}.hero p{font-size:15px;color:#627588;max-width:560px}.hero button{border:0;background:#d87939;color:white;border-radius:8px;padding:12px 20px;margin-top:14px;font-weight:700}.cars{padding:26px 6%}.cars h2{font-size:25px}.cards{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:14px}.car{border:1px solid #e1e8ef;border-radius:9px;overflow:hidden}.car .art{height:85px;background:linear-gradient(135deg,#d2dde6,#e8eef3)}.car b{font-size:12px;display:block;padding:9px 12px}.car span{display:block;font-size:10px;color:#6b7f8f;padding:0 12px 11px}@media(max-width:500px){nav{padding:13px 4%}nav span{font-size:10px}.hero{padding:39px 5%}.cards{grid-template-columns:repeat(2,minmax(0,1fr))}.car .art{height:66px}}</style></head><body><nav><b>HESU AUTO</b><span>车型展示 品牌 关于我们 联系我们</span></nav><section class=hero><div class=eyebrow>GLOBAL AUTO EXPORT</div><h1>中国汽车供应<br>连接全球市场</h1><p>从车型采购到国际物流与海外交付的一站式出口服务。</p><button>了解我们的车型</button></section><section class=cars><h2>精选车型</h2><div class=cards><div class=car><div class=art></div><b>ROX 01</b><span>Luxury SUV</span></div><div class=car><div class=art></div><b>DONGFENG Z9</b><span>Pickup Truck</span></div><div class=car><div class=art></div><b>BYD YUAN UP</b><span>Electric Vehicle</span></div></div></section></body></html>`};
|
|
const data={
|
|
'/api/auth/me':{csrf:'demo'},
|
|
'/api/sites/demo':{id:'demo',name:'汽车演示站',theme:'automotive'},
|
|
'/api/sites/demo/entries':[{id:'p1',title:'首页',route:'/'}],
|
|
'/api/editor/blocks':schema,
|
|
'/api/sites/demo/components':[],
|
|
'/api/sites/demo/pages/p1/studio-draft':{revision:0,blocks:[{id:'b1',type:'hero',title:'HESU AUTO',subtitle:'全球汽车出口',image:'',visible:true,style:{}},{id:'b2',type:'collection',title:'热门车型',visible:true,style:{}}],page_template:'standard',layout_mode:'append',entry:{title:'首页',route:'/'}},
|
|
}[path];
|
|
return {ok:!!data,status:data?200:404,headers:{get:()=> 'application/json'},json:async()=>data||{detail:'not available'},text:async()=>JSON.stringify(data)};
|
|
};
|
|
window.__previewOk=true;
|
|
}''',schema)
|
|
page.add_script_tag(content=js)
|
|
page.evaluate('Studio.init()')
|
|
page.wait_for_function("document.querySelector('#blockCount').textContent.includes('2')")
|
|
assert page.locator('#tabStyle').is_hidden(),'Beginner mode should hide style tab'
|
|
assert page.locator('#sfNextAction').inner_text()
|
|
page.screenshot(path=str(OUT/'editor-desktop.png'),full_page=True)
|
|
page.locator('#studioAdvancedButton').click()
|
|
assert page.locator('#tabStyle').is_visible()
|
|
page.locator('#tabStyle').click()
|
|
assert page.locator('#tabStyle').get_attribute('aria-selected')=='true'
|
|
page.locator('#studioAdvancedButton').click()
|
|
assert page.locator('#tabStyle').is_hidden()
|
|
assert page.locator('#tabContent').get_attribute('aria-selected')=='true'
|
|
assert page.locator('.sf-photo-action button').count()==1
|
|
page.locator('#studioThemePreviewButton').click()
|
|
page.wait_for_function("document.querySelector('#themePreviewStatus').textContent.includes('预览已显示')",timeout=5000)
|
|
page.evaluate('window.__previewOk=false')
|
|
page.locator('#themePreviewPage').select_option('product')
|
|
page.wait_for_function("document.querySelector('#themePreviewRetry').hidden===false",timeout=5000)
|
|
assert '503' in page.locator('#themePreviewStatus').inner_text()
|
|
page.locator('button[onclick="Studio.closeThemePreview()"]').click()
|
|
page.set_viewport_size({'width':390,'height':844})
|
|
page.wait_for_timeout(350) # allow the responsive drawers' CSS transition to finish
|
|
page.screenshot(path=str(OUT/'editor-mobile.png'),full_page=True)
|
|
overflow=page.evaluate('document.documentElement.scrollWidth>innerWidth+1')
|
|
assert not overflow, 'Mobile horizontal overflow'
|
|
page.locator('button[onclick="Studio.togglePane(\'right\')"]').click()
|
|
assert page.locator('body').evaluate("x=>x.classList.contains('show-inspector')")
|
|
page.locator('#sfCloseInspector').click()
|
|
assert not page.locator('body').evaluate("x=>x.classList.contains('show-inspector')")
|
|
assert not errors,errors
|
|
browser.close()
|
|
print(json.dumps({'browser':'isolated chromium','desktop':True,'mobile390':True,'preview_error_recovery':True,'advanced_mode':True,'js_errors':errors},ensure_ascii=False))
|