保存前端调整前的当前状态

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
LongtailandCopilot committed 2026-10-31 17:55:39 +08:00
1 parent f0be4f5596
commit 77012b93c6
10 files changed
+204 -3

No files matched your search

+73
View File
@@ -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;});