const {chromium}=require('playwright-core'); const assert=require('node:assert/strict'),fs=require('node:fs'); const base='http://127.0.0.1:18882/api/v1'; async function api(path,body){const r=await fetch(base+path,{method:body?'PUT':'GET',headers:{'Content-Type':'application/json'},body:body?JSON.stringify(body):undefined});const data=await r.json();return {status:r.status,data:data.data};} (async()=>{ const baseline=(await api('/ai-configs')).data; const image=baseline.find(c=>c.id===6),video=baseline.find(c=>c.id===4),hd=baseline.find(c=>c.id===10); assert.ok(image&&video&&hd); for(const [id,gpu] of [[6,'gpu1'],[4,'gpu2'],[10,'gpu3']])assert.equal((await api('/ai-configs/'+id,{gpu})).status,200); assert.equal((await api('/ai-configs/6',{gpu:'gpu0'})).status,400); assert.equal((await api('/ai-configs/6')).data.gpu,'gpu1'); const browser=await chromium.launch({channel:'chrome',headless:true}); try{ const page=await browser.newPage({viewport:{width:1440,height:1000}});const errors=[];page.on('pageerror',e=>errors.push(e.message)); await page.goto('http://127.0.0.1:18882/settings',{waitUntil:'networkidle'}); const row=page.locator('.config-row').filter({hasText:'Qwen Image 2.1'}); await row.locator('button.btn-icon').first().click(); const select=page.getByLabel('使用显卡',{exact:true}); assert.deepEqual(await select.locator('option').evaluateAll(es=>es.map(e=>e.value)),['auto','gpu1','gpu2','gpu3']); assert.equal(await select.inputValue(),'gpu1');await select.selectOption('gpu3'); await page.locator('form.config-dialog button[type=submit]').click();await page.locator('form.config-dialog').waitFor({state:'hidden'}); assert.equal((await api('/ai-configs/6')).data.gpu,'gpu3'); assert.equal((await api('/ai-configs/4')).data.gpu,'gpu2'); assert.equal((await api('/ai-configs/10')).data.gpu,'gpu3'); await page.reload({waitUntil:'networkidle'});await row.locator('button.btn-icon').first().click(); assert.equal(await select.inputValue(),'gpu3'); await page.waitForTimeout(400); await page.screenshot({path:'D:/web/dj/integration-work/gpu-settings-verified.png'}); await select.selectOption('auto');await page.locator('form.config-dialog button[type=submit]').click();await page.locator('form.config-dialog').waitFor({state:'hidden'}); const after=(await api('/ai-configs/6')).data; assert.equal(after.gpu,'auto'); for(const key of ['api_key','base_url','model','priority','is_active'])assert.deepEqual(after[key],image[key]); assert.deepEqual(errors,[]); fs.writeFileSync('D:/web/dj/integration-work/gpu-settings-ui-result.json',JSON.stringify({passed:true,checks:['three GPUs plus automatic','per-model independence','reload persistence','invalid GPU rejected','protected config fields unchanged'],errors},null,2)); console.log('PASS: GPU1/2/3 and automatic selection persist independently; model credentials unchanged; no UI errors'); }finally{await browser.close()} })().catch(e=>{console.error(e.stack);process.exit(1)});