fix: совпадение видимого логотипа Preland и Tour (refs #12)
deploy-preland / deploy zoomstage.online (push) Successful in 40s

This commit is contained in:
Panfilov Konstantin committed 2026-10-21 17:35:07 +03:00
1 parent ec087ea636
commit 3740839321
6 files changed
+45 -3

No files matched your search

+2
View File
@@ -197,3 +197,5 @@ Workflow `.gitea/workflows/deploy.yml` содержит единственную
primary guard теперь сверяет PDF/favicon, а не заставляет возвращать Zoomzilla и реквизиты на преленд. Реквизиты не отображаются и больше автоматически не синхронизируются; хостовый config и его существующие значения не меняются этим поручением. Устаревшие requisites.html и patch-скрипт удалены из поставки. Статический manifest183, отдельный каталог брендов проверяется по собственным SHA. История #11 сохранена; её прежние инструкции о видимом бренде/реквизитах заменены этим датированным решением. primary guard теперь сверяет PDF/favicon, а не заставляет возвращать Zoomzilla и реквизиты на преленд. Реквизиты не отображаются и больше автоматически не синхронизируются; хостовый config и его существующие значения не меняются этим поручением. Устаревшие requisites.html и patch-скрипт удалены из поставки. Статический manifest183, отдельный каталог брендов проверяется по собственным SHA. История #11 сохранена; её прежние инструкции о видимом бренде/реквизитах заменены этим датированным решением.
Перед выпуском: девять tests/check-*.php и lint, --check/--primary/--stage-sets, оба бренда шапки/подвала на desktop/mobile, перенос Host, отсутствие карт/реквизитов, холодная/медленная загрузка, реальные локальные Preland→Tour→Join/error/retry и геометрия. Production-преленды по #4 не включать; выпускать только staging→zoomstage.online. API продуктовый код не меняется. Перед выпуском: девять tests/check-*.php и lint, --check/--primary/--stage-sets, оба бренда шапки/подвала на desktop/mobile, перенос Host, отсутствие карт/реквизитов, холодная/медленная загрузка, реальные локальные Preland→Tour→Join/error/retry и геометрия. Production-преленды по #4 не включать; выпускать только staging→zoomstage.online. API продуктовый код не меняется.
Дополнение приёмки #12: tests/e2e/brand-footer.cjs проверяет именно видимый SVG по центру шапки, а не только headerbox. PUBLISHED=1 использует zoomstage.online (или PRELAND_URL); без него — изолированный pre301.localhost QA proxy. Запускать в имеющемся Docker Playwright с /candidate=репозиторий,/qa=артефакты; POST/PUT блокируются. Пропущенное при compact CSS правило Bootstrap navbar>.container восстановлено во всех3CSS: API уже имеет его из полного Bootstrap. Это устраняет переход logo y0→13.5px, который рамочный тест не замечал.
+3 -3
View File
@@ -724,15 +724,15 @@
"source": "https://zoomstage.online/images/sprite.svg" "source": "https://zoomstage.online/images/sprite.svg"
}, },
"style.css": { "style.css": {
"sha256": "102aee00546d897dd94887d69b35fec0b3430448ef6a21e072f5b7d76964ce06", "sha256": "cc88246e4efb4f2884d0f268b897950cd75620998e0d3ad9985076ce1021abfc",
"source": "https://zoomstage.online/style.css" "source": "https://zoomstage.online/style.css"
}, },
"style.min.c.css": { "style.min.c.css": {
"sha256": "d4afd7aeaa56c97d6415beee220398f654d4d9ca0cac35770e7ea3d89412c878", "sha256": "7fc5684ab3eb00b046acf90c4c891ec393b9dc11da97db02a297876e342cad18",
"source": "https://zoomstage.online/style.min.c.css" "source": "https://zoomstage.online/style.min.c.css"
}, },
"style.min.css": { "style.min.css": {
"sha256": "3e579e90cd8dd1193db45cf0d433ae8acfac76eb38444755f0b4d15a3af7f2f2", "sha256": "524c44557f1a9631e88c8b8f5bbc603abcfff7dd4de76a402cec127c0895a404",
"source": "https://zoomstage.online/style.min.css" "source": "https://zoomstage.online/style.min.css"
} }
} }
+3
View File
@@ -2942,3 +2942,6 @@ body { isolation: isolate; }
/* preland#11: общий с API адаптивный платёжный бейдж подвала. */ /* preland#11: общий с API адаптивный платёжный бейдж подвала. */
.footer-main img[src$="/images/payment.svg"]{max-width:100%;height:auto;} .footer-main img[src$="/images/payment.svg"]{max-width:100%;height:auto;}
/* preland#12: восстановлен пропущенный в critical CSS Bootstrap-контракт navbar. */
.navbar>.container{display:flex;flex-wrap:inherit;align-items:center;justify-content:space-between;}
+3
View File
@@ -844,3 +844,6 @@ padding-top: 2svh !important;
/* preland#11: общий с API адаптивный платёжный бейдж подвала. */ /* preland#11: общий с API адаптивный платёжный бейдж подвала. */
.footer-main img[src$="/images/payment.svg"]{max-width:100%;height:auto;} .footer-main img[src$="/images/payment.svg"]{max-width:100%;height:auto;}
/* preland#12: восстановлен пропущенный в critical CSS Bootstrap-контракт navbar. */
.navbar>.container{display:flex;flex-wrap:inherit;align-items:center;justify-content:space-between;}
+3
View File
@@ -143,3 +143,6 @@ body { isolation: isolate; }
/* preland#11: общий с API адаптивный платёжный бейдж подвала. */ /* preland#11: общий с API адаптивный платёжный бейдж подвала. */
.footer-main img[src$="/images/payment.svg"]{max-width:100%;height:auto;} .footer-main img[src$="/images/payment.svg"]{max-width:100%;height:auto;}
/* preland#12: восстановлен пропущенный в critical CSS Bootstrap-контракт navbar. */
.navbar>.container{display:flex;flex-wrap:inherit;align-items:center;justify-content:space-between;}
+31
View File
@@ -0,0 +1,31 @@
const {chromium}=require('/e2e/node_modules/playwright-core'),fs=require('fs'),http=require('http'),assert=require('assert/strict'),crypto=require('crypto');
const production=process.env.PUBLISHED==='1';
const server=production?null:http.createServer((req,res)=>{const r=http.request(new URL(req.url,'http://api:8001'),{method:req.method,headers:{...req.headers,connection:'close'}},up=>{res.writeHead(up.statusCode,up.headers);up.pipe(res)});req.pipe(r)}).listen(8121);
const base=process.env.PRELAND_URL||(production?'https://zoomstage.online':'http://pre301.localhost:8121');
(async()=>{const browser=await chromium.launch({args:['--no-sandbox']});const out=[];
try{for(const width of [1440,768,390,320])for(const theme of ['light','dark'])for(const indpic of [1,2]){
console.log('CASE',width,theme,indpic);
const ctx=await browser.newContext({viewport:{width,height:900},isMobile:width<768,hasTouch:width<768}),page=await ctx.newPage(),errors=[];
page.on('pageerror',e=>errors.push(e.message));
await page.route('**/*',route=>['GET','HEAD','OPTIONS'].includes(route.request().method())?route.continue():route.abort());
await page.goto(base+'/?theme='+theme+'&indpic='+indpic,{waitUntil:'networkidle'});
await page.waitForFunction(()=>document.querySelector('#examples').dataset.examplesState==='ready');
assert.equal(await page.title(),'Улучшение изображения');assert(await page.locator('#dropzone-form').isVisible());
const footer=await page.locator('.footer').innerText();assert(!/Наши реквизиты|ИНН:|ОГРНИП:|Кардаполов|Иванов/.test(footer));assert.equal(await page.locator('.footer img[src*="payment.svg"] ').count(),0);assert(footer.includes(new URL(base).hostname));
const alignment=await page.evaluate(()=>{const h=document.querySelector('.header').getBoundingClientRect(),logo=[...document.querySelectorAll('.navbar-brand img')].find(e=>getComputedStyle(e).display!=='none').getBoundingClientRect();return {delta:logo.y-h.y-(h.height-logo.height)/2}});assert(Math.abs(alignment.delta)<1,'Видимый логотип должен быть по центру шапки');
const logos=await page.locator('.navbar-brand img,.footer-logo img').evaluateAll(es=>es.map(e=>({src:e.src,visible:getComputedStyle(e).display!=='none',width:e.naturalWidth,loaded:e.complete})));
assert.equal(logos.length,4);assert.equal(logos.filter(l=>l.visible).length,2);
for(const logo of logos){const url=new URL(logo.src);assert(url.searchParams.get('v'));const file=url.pathname.slice(1);const bytes=fs.readFileSync('/candidate/'+file);const digest=production?JSON.parse(fs.readFileSync('/candidate/release/brands.json'))[new URL(base).hostname].logos[file].sha256:crypto.createHash('sha256').update(bytes).digest('hex');assert.equal(url.searchParams.get('v'),digest.slice(0,16));if(logo.visible)assert(logo.loaded&&logo.width>0);}
assert(logos.filter(l=>l.visible).every(l=>new URL(l.src).pathname.endsWith(theme==='dark'?'logo-alt.svg':'logo.svg')));
await page.waitForFunction(()=>document.querySelectorAll('.image-examples-item')[1].getAttribute('aria-disabled')==='false');
await page.locator('.image-examples-item').nth(1).click();
await page.waitForFunction(()=>/02_(desk|mob)_1-source/.test(document.querySelector('#image-compare-source').src));
assert((await page.locator('#image-compare-source').getAttribute('src')).includes('/'+indpic+'/'));
assert(/02_(desk|mob)_2-result/.test(await page.locator('#image-compare-result').getAttribute('src')));
if(await page.evaluate(()=>document.documentElement.scrollWidth>innerWidth)){await page.screenshot({path:'/qa/overflow.png',fullPage:true});console.log(await page.evaluate(()=>[...document.querySelectorAll('body *')].map(e=>({tag:e.tagName,cls:e.className,x:e.getBoundingClientRect().x,right:e.getBoundingClientRect().right,width:e.getBoundingClientRect().width})).filter(e=>e.right>innerWidth+1)));}
assert.equal(await page.evaluate(()=>document.documentElement.scrollWidth>innerWidth),false);assert.deepEqual(errors,[]);
const row={width,theme,indpic,logos,errors};out.push(row);
if(indpic===1&&(width===1440||width===390))await page.screenshot({path:'/qa/brand-'+(production?'published':'local')+'-'+width+'-'+theme+'.png',fullPage:true});
await ctx.close();
}fs.writeFileSync('/qa/brand-'+(production?'published':'local')+'.json',JSON.stringify(out,null,2));console.log('PASS brand + thumbnail interactions',out.length,'cases');}
finally{await browser.close();server?.close();}})().catch(e=>{console.error(e);process.exit(1)});