29 lines
5.8 KiB
JavaScript
29 lines
5.8 KiB
JavaScript
/* preland#22: real verified status refresh, isolated to disposable LOCAL fixtures. */
|
|
const {chromium}=require('playwright-core');const assert=require('node:assert/strict');const fs=require('node:fs');
|
|
(async()=>{
|
|
const browser=await chromium.launch({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}});
|
|
page.on('dialog',d=>d.accept());const errors=[];page.on('pageerror',e=>errors.push(e.message));let original=null,csrf='',primaryError=null;
|
|
const api=async(route,data)=>{const r=await page.request.post('/api/'+route,{data,headers:{'X-CSRF-Token':csrf}}).then(r=>r.json());assert.ok(r.ok,r.error);return r;};
|
|
const state=async()=>{const r=await page.request.get('/api/state').then(r=>r.json());assert.ok(r.ok,r.error);return r;};
|
|
const read=async id=>{const r=await page.request.get('/api/config?target='+id).then(r=>r.json());assert.ok(r.ok,r.error);return r;};
|
|
try{
|
|
await page.goto(process.env.ADMIN_URL||'http://admin');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'});
|
|
let current=await state();csrf=current.csrf;original=current.targets.find(t=>t.id===(process.env.TARGET_ID||'a'));assert.ok(original);assert.equal(original.type,'local','this test MUST NOT modify SSH targets');assert.ok(current.targets.some(t=>t.id==='b'&&t.enabled));
|
|
// A local adapter ignores port. Identity change invalidates verification without touching host/secret/root/config.
|
|
const changed={...original,port:original.port===22?23:22};const saved=await api('targets',{target:changed});assert.equal(saved.target.verified,false,'real server flag invalidated');
|
|
await page.reload();await page.locator('#workspace').waitFor({state:'visible'});current=await state();csrf=current.csrf;
|
|
const row=page.locator('#connection-list .connection').filter({hasText:original.domain}),header=page.locator('#overview-table th[data-overview-target="'+original.id+'"]');await header.waitFor();assert.match(await row.innerText(),/требуется проверка/);assert.match(await header.innerText(),/соединение не проверено/);
|
|
const before=await read(original.id);
|
|
await page.locator('#source-target').selectOption(original.id);await page.getByLabel('Основной сайт',{exact:true}).waitFor();await page.getByLabel('Основной сайт',{exact:true}).fill('unsaved-verification.example.org');await page.locator('#targets input[value=b]').check();await page.waitForFunction(()=>!document.querySelector('#targets').textContent.includes('чтение версии'));
|
|
const versionText=await page.locator('#read-state').innerText(),selected=await page.locator('#targets input:checked').evaluateAll(inputs=>inputs.map(i=>i.value));assert.equal(selected.length,2);
|
|
await page.locator('#builder-target').selectOption(original.id);const theme=page.locator('#builder-fields select[data-marker=theme]');await theme.waitFor();await theme.selectOption((await theme.inputValue())==='rnd'?'1':'rnd');const constructorDraft=await page.locator('#builder-fields select').evaluateAll(inputs=>inputs.map(i=>[i.dataset.marker,i.value]));
|
|
await row.getByRole('button',{name:'Проверить соединение',exact:true}).click();await page.locator('#indpic-result-modal').waitFor({state:'visible'});assert.match(await page.locator('#result-body').innerText(),/проверен/i);assert.equal((await state()).targets.find(t=>t.id===original.id).verified,true,'real backend verified flag true');
|
|
assert.match(await row.innerText(),/соединение проверено/,'connection row refreshed without reload');assert.doesNotMatch(await row.innerText(),/требуется проверка/);assert.doesNotMatch(await header.innerText(),/соединение не проверено/,'overview header refreshed without reload');
|
|
assert.equal(await page.getByLabel('Основной сайт',{exact:true}).inputValue(),'unsaved-verification.example.org');assert.equal(await page.locator('#read-state').innerText(),versionText);assert.deepEqual(await page.locator('#targets input:checked').evaluateAll(inputs=>inputs.map(i=>i.value)),selected);assert.deepEqual(await page.locator('#builder-fields select').evaluateAll(inputs=>inputs.map(i=>[i.dataset.marker,i.value])),constructorDraft);assert.match(await page.locator('#change-summary').innerText(),/host/);
|
|
const after=await read(original.id);assert.equal(after.version,before.version);assert.deepEqual(after.config,before.config);assert.deepEqual(errors,[]);
|
|
await page.screenshot({path:(process.env.UI_OUTPUT||'/tmp')+'/verified-refresh.png',fullPage:true});fs.writeFileSync((process.env.UI_OUTPUT||'/tmp')+'/verified-refresh-evidence.json',JSON.stringify({target:original.id,serverVerified:true,configVersion:after.version,selected,constructorDraftPreserved:true,pageErrors:errors},null,2));console.log('PASS real targets/test modal + connection/overview verified refresh + editor/selected2/CAS/constructor preserved/config unchanged');
|
|
}catch(error){primaryError=error;}finally{
|
|
const cleanup=[];if(original)try{await api('targets',{target:original});if(original.verified)await api('targets/test',{id:original.id});}catch(error){cleanup.push(error);}try{await browser.close();}catch(error){cleanup.push(error);}if(primaryError&&cleanup.length)throw new AggregateError([primaryError,...cleanup],'verification UI failure with separate fixture cleanup errors',{cause:primaryError});if(primaryError)throw primaryError;if(cleanup.length)throw new AggregateError(cleanup,'fixture cleanup failed');
|
|
}
|
|
})().catch(error=>{console.error(error);process.exit(1);});
|