// Self-contained loopback browser fixture; never a deployed Gateway.
import assert from 'node:assert/strict';
import {createServer} from 'node:http';
import {readFile} from 'node:fs/promises';
const {chromium}=await import(process.env.PLAYWRIGHT_MODULE ?? '../../frontend/node_modules/@playwright/test/index.mjs');
const directory=new URL('./deerflow_extension_workflows/static/',import.meta.url);
const server=createServer(async(req,res)=>{
if(req.url==='/index.mjs'||req.url==='/style.css'){
res.setHeader('Content-Type',req.url.endsWith('.mjs')?'text/javascript':'text/css');
res.end(await readFile(new URL(req.url.slice(1),directory)));return;
}
res.setHeader('Content-Type','text/html');
res.end(`
Workflow test`);
});
await new Promise(resolve=>server.listen(0,'127.0.0.1',resolve));
const browser=await chromium.launch({headless:true,...(process.env.PLAYWRIGHT_CHANNEL?{channel:process.env.PLAYWRIGHT_CHANNEL}:{})});
try{
const page=await browser.newPage({viewport:{width:1280,height:1000}});
const errors=[];page.on('pageerror',e=>errors.push(e.message));
await page.goto(`http://127.0.0.1:${server.address().port}/`);
await page.getByRole('button',{name:'Launch workflow',exact:true}).click();
await page.getByRole('heading',{name:'fixture-run · running',exact:true}).waitFor();
const launch=await page.evaluate(()=>calls.find(c=>c.action==='launch'));
assert.equal(launch.payload.request_id.length,32);
assert.match(launch.payload.script,/await agent/);
await page.getByRole('button',{name:'Open child conversation',exact:true}).click();
assert.deepEqual(await page.evaluate(()=>opened),['child-thread']);
assert.equal(await page.locator('img').count(),0);
await page.getByRole('button',{name:'Cancel workflow',exact:true}).click();
await page.getByRole('heading',{name:'fixture-run · cancelled',exact:true}).waitFor();
await page.getByRole('button',{name:'Delete retained record',exact:true}).click();
await page.waitForFunction(()=>window.hidden);
for(const failure of ['failList','failGet','loseLaunch']){
await page.reload();
await page.waitForFunction(()=>calls.some(c=>c.action==='list'));
await page.evaluate(key=>window[key]=1,failure);
await page.getByRole('button',{name:'Launch workflow',exact:true}).click();
await page.waitForFunction(()=>!document.querySelector('button[type=submit]').disabled);
if(failure!=='loseLaunch'){
assert.match(await page.getByRole('status').textContent(),/fixture-run/);
await page.getByRole('button',{name:'Retry inspection',exact:true}).click();
}else{
await page.getByRole('button',{name:'Launch workflow',exact:true}).click();
}
await page.getByRole('heading',{name:'fixture-run · running',exact:true}).waitFor();
// Resubmitting unchanged accepted input also keeps its launch identity.
await page.getByRole('button',{name:'Launch workflow',exact:true}).click();
await page.waitForFunction(()=>!document.querySelector('button[type=submit]').disabled);
assert.equal(await page.evaluate(()=>identities.size),1,failure);
await page.getByLabel('Script',{exact:true}).fill('return 43;');
await page.getByRole('button',{name:'Launch workflow',exact:true}).click();
await page.waitForFunction(()=>!document.querySelector('button[type=submit]').disabled);
assert.equal(await page.evaluate(()=>identities.size),2,failure);
}
await page.evaluate(()=>view.dispose());
assert.equal(await page.locator('.script-workflows').count(),0);
assert.deepEqual(errors,[]);
console.log('Browser checks passed: launch, versioned inspection, child navigation, cancellation, escaped output, deletion and disposal.');
}finally{
await browser.close();await new Promise(resolve=>server.close(resolve));
}