保存前端调整前的当前状态
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
10 files changed
+204
-3
No files matched your search
@@ -0,0 +1,73 @@
|
||||
'use strict';
|
||||
// Isolated UI regression: all requests use fixture data, never the user's queue.
|
||||
const {chromium}=require('playwright');
|
||||
const fs=require('node:fs');
|
||||
const path=require('node:path');
|
||||
const assert=require('node:assert/strict');
|
||||
const ROOT=path.resolve(__dirname,'..');
|
||||
(async()=>{
|
||||
const browser=await chromium.launch({headless:true,executablePath:process.env.CHROME_PATH||'/Applications/Google Chrome.app/Contents/MacOS/Google Chrome'});
|
||||
try{
|
||||
const page=await browser.newPage({viewport:{width:1440,height:1000}}),errors=[],requests=[];
|
||||
page.on('pageerror',error=>errors.push(error.message));
|
||||
const data={run:{running:false,active:'active',config:{},reason:'已暂停',batch:null},clients:[],
|
||||
jobs:['a','b','active'].map(id=>({id,title:'测试文章 '+id,original_title:'测试文章 '+id,image_count:0,source:'测试来源',state:id==='active'?'awaiting_user_review':'queued'})),
|
||||
download:{status:'idle',saved:0,target:0,skipped:0,failed:0,logs:[]}};
|
||||
let failRemoval=false;
|
||||
await page.route('**/*',async route=>{
|
||||
const url=new URL(route.request().url());
|
||||
if(url.hostname!=='queue.test')return route.abort();
|
||||
if(url.pathname==='/api/session')return route.fulfill({json:{token:'fixture'}});
|
||||
if(url.pathname==='/api/state')return route.fulfill({json:data});
|
||||
if(url.pathname==='/api/remove'){
|
||||
const body=route.request().postDataJSON();requests.push(body);
|
||||
if(failRemoval)return route.fulfill({status:400,json:{error:'模拟移除失败'}});
|
||||
data.jobs=data.jobs.filter(job=>!body.ids.includes(job.id));
|
||||
return route.fulfill({json:{ok:true,removed:body.ids.length}});
|
||||
}
|
||||
const files={'/':'index.html','/app.js':'app.js','/style.css':'style.css'};
|
||||
if(files[url.pathname])return route.fulfill({path:path.join(ROOT,'static',files[url.pathname])});
|
||||
return route.abort();
|
||||
});
|
||||
await page.goto('http://queue.test/');
|
||||
await page.waitForFunction(()=>document.querySelectorAll('.job-select').length===3);
|
||||
const box=id=>page.locator(`.job-select[value="${id}"]`);
|
||||
assert.equal(await page.locator('#remove-selected').isDisabled(),true);
|
||||
assert.equal(await box('active').isDisabled(),true);
|
||||
await box('a').check();
|
||||
assert.equal(await page.locator('#select-all').evaluate(el=>el.indeterminate),true);
|
||||
await page.evaluate(()=>refresh());
|
||||
assert.equal(await box('a').isChecked(),true,'polling preserves selection');
|
||||
page.once('dialog',dialog=>dialog.dismiss());
|
||||
await page.locator('#remove-selected').click();
|
||||
assert.equal(requests.length,0,'cancel does not delete');
|
||||
failRemoval=true;
|
||||
page.once('dialog',dialog=>dialog.accept());
|
||||
await page.locator('#remove-selected').click();
|
||||
await page.getByText('模拟移除失败',{exact:true}).waitFor();
|
||||
assert.equal(await box('a').isChecked(),true,'failure preserves selection');
|
||||
failRemoval=false;
|
||||
page.once('dialog',dialog=>dialog.accept());
|
||||
await page.locator('#remove-selected').click();
|
||||
await page.waitForFunction(()=>document.querySelectorAll('.job-select').length===2);
|
||||
assert.deepEqual(requests.at(-1),{ids:['a']});
|
||||
assert.equal(await box('b').count(),1,'unselected article remains');
|
||||
await page.locator('#select-all').check();
|
||||
assert.equal(await box('b').isChecked(),true);
|
||||
assert.equal(await box('active').isChecked(),false);
|
||||
data.run.running=true;await page.evaluate(()=>refresh());
|
||||
assert.equal(await page.locator('#remove-selected').isDisabled(),true,'running flow blocks removal');
|
||||
data.run.running=false;data.run.active=null;await page.evaluate(()=>refresh());
|
||||
await page.locator('#select-all').check();
|
||||
await page.setViewportSize({width:390,height:844});
|
||||
assert.equal(await page.evaluate(()=>document.documentElement.scrollWidth>innerWidth),false,'mobile has no horizontal overflow');
|
||||
page.once('dialog',dialog=>dialog.accept());
|
||||
await page.locator('#remove-selected').click();
|
||||
await page.locator('#empty').waitFor({state:'visible'});
|
||||
assert.equal(await page.locator('#total').textContent(),'0');
|
||||
assert.equal(await page.locator('#select-all').isDisabled(),true);
|
||||
assert.equal(await page.locator('#remove-selected').isDisabled(),true);
|
||||
assert.deepEqual(errors,[]);
|
||||
console.log('PASS queue UI: selection, polling, cancellation, failure, selected deletion, protected task, running state, select all, empty state, mobile layout');
|
||||
}finally{await browser.close();}
|
||||
})().catch(error=>{console.error(error);process.exitCode=1;});
|
||||
Reference in new issue
Block a user