feat: единая админка runtime-конфигов и indpic (#22)
deploy-preland / deploy zoomstage.online (push) Successful in 1m1s

This commit is contained in:
Panfilov Konstantin committed 2026-10-25 11:33:56 +03:00
1 parent 5b6b2d2053
commit 9515c1c62b
52 files changed
+2459 -34

No files matched your search

+47
View File
@@ -0,0 +1,47 @@
/* Browser plugin not available; run only inside the supplied Docker Playwright image.
* Required env: ADMIN_URL, ADMIN_USER, ADMIN_PASSWORD, UI_OUTPUT; optional SECOND_TARGET.
*/
const { chromium } = require('playwright-core');
const assert = require('node:assert/strict');
const fs = require('node:fs');
(async () => {
const browser = await chromium.launch({headless:true,executablePath:process.env.CHROMIUM_PATH || '/usr/bin/chromium',args:['--no-sandbox']});
const page = await browser.newPage({baseURL:process.env.ADMIN_URL||'http://admin',viewport:{width:1440,height:1000}});
const errors=[],consoleMessages=[]; page.on('pageerror',e=>errors.push(e.message));page.on('console',m=>{if(['error','warning'].includes(m.type()))consoleMessages.push({type:m.type(),text:m.text()});});
await page.goto(process.env.ADMIN_URL || 'http://admin');
assert.match(await page.title(), /Прелендинги/);
await page.getByLabel('Логин', {exact:true}).fill(process.env.ADMIN_USER || 'admin');
await page.getByLabel('Пароль', {exact:true}).fill(process.env.ADMIN_PASSWORD || 'test-password');
await page.getByRole('button',{name:'Войти',exact:true}).click();
await page.locator('#workspace').waitFor({state:'visible'});
await page.locator('#source-target').selectOption({index:1});
await page.getByLabel('Основной сайт', {exact:true}).waitFor();
const host = page.getByLabel('Основной сайт', {exact:true});
const original = await host.inputValue();
const secondOriginal=process.env.SECOND_TARGET?await page.request.get('/api/config?target='+encodeURIComponent(process.env.SECOND_TARGET)).then(r=>r.json()).then(r=>r.config.host):null;
await host.fill('ui-check.example.org');
assert.match(await page.locator('#change-summary').innerText(), /host/);
assert.equal(await page.locator('#targets input:checked').count(),1);
if (process.env.SECOND_TARGET) await page.locator('#targets input[value="'+process.env.SECOND_TARGET+'"]').check();
const apply = async () => {
const pending=page.waitForResponse(r=>r.url().endsWith('/api/apply')&&r.request().method()==='POST');
await page.getByRole('button',{name:'Применить к выбранным',exact:true}).click();
const accepted=await(await pending).json();assert.equal(accepted.ok,true,accepted.error);
await page.locator('.job').filter({hasText:accepted.job.id}).getByText('Сохранено и проверено',{exact:true}).first().waitFor();
};
await apply();
await page.getByRole('button',{name:'Перечитать',exact:true}).click();
await page.waitForFunction(()=>document.querySelector('[aria-label="Основной сайт"]')?.value==='ui-check.example.org');
await host.fill(original);
await apply();
if(process.env.SECOND_TARGET){await page.locator('#source-target').selectOption(process.env.SECOND_TARGET);await host.waitFor();await host.fill(secondOriginal);await apply();}
assert.equal(await page.locator('textarea').count(),0,'JSON textarea absent');
assert.equal(await page.locator('.indpic-sets-table th').allTextContents().then(x=>x.join('|')),'Номер / название|Default|Проверка|ZIP|Действия');
await page.screenshot({path:(process.env.UI_OUTPUT||'/tmp')+'/admin-desktop.png',fullPage:true});
await page.setViewportSize({width:390,height:844});
await page.screenshot({path:(process.env.UI_OUTPUT||'/tmp')+'/admin-mobile.png',fullPage:true});
assert.equal(await page.evaluate(()=>document.documentElement.scrollWidth<=innerWidth),true,'no page-level horizontal overflow');
fs.writeFileSync((process.env.UI_OUTPUT||'/tmp')+'/admin-console.json',JSON.stringify({pageErrors:errors,console:consoleMessages},null,2));
assert.deepEqual(errors,[]);assert.deepEqual(consoleMessages.filter(m=>!m.text.includes('status of 401')),[],'no unexpected browser console errors');
await browser.close(); console.log('PASS real login/read/edit/apply/reload/restore + mobile + console');
})().catch(e=>{console.error(e);process.exit(1);});