import test from 'node:test'; import assert from 'node:assert/strict'; import { readFileSync } from 'node:fs'; import { testerBrowser } from './tester-browser-fixture.mjs'; import { testerFixture, testerChat } from './tester-fixture.mjs'; test('tester Console banner exposes only instance route and name editors and saves a route as tester', { timeout: 60000 }, async t => { const s = await testerFixture(t), b = await testerBrowser(s.web); try { const wait = expr => b.evaluate(`(async()=>{for(let n=0;n<150;n++){if(${expr})return true;await new Promise(r=>setTimeout(r,30));}throw Error('wait failed: '+${JSON.stringify(expr)});})()`); await b.navigate(`http://mosaic-tester.invalid/#/settings/routing`); await wait('!!document.querySelector("#tester-banner") && document.querySelector("#routes-form button[type=submit]")?.disabled === false'); assert.match(await b.evaluate('document.querySelector("#tester-banner")?.textContent ?? ""'), /tester/i); assert.equal(await b.evaluate('document.querySelector("#routes-form button[type=submit]").disabled'), false); assert.ok(await b.evaluate('[...document.querySelectorAll("#settings-nav a")].some(a=>a.getAttribute("href")==="#/settings/agents")')); assert.ok(await b.evaluate('[...document.querySelectorAll("#settings-nav a")].some(a=>a.getAttribute("href")==="#/settings/names")')); assert.equal(await b.evaluate('!!document.querySelector("#launch-settings-form, .assistant-form, #token-limits-table [data-limit-reset], #send-section")'), false); const selector = JSON.stringify('[data-route=\'["coder","thinking"]\']'); await b.evaluate(`(()=>{const e=document.querySelector(${selector});e.value='low';e.dispatchEvent(new Event('change',{bubbles:true}));document.querySelector('#routes-form').requestSubmit();return true;})()`); await wait('document.querySelector("#routes-receipt")?.textContent.startsWith("Routes saved")'); assert.equal(JSON.parse(readFileSync(s.file, 'utf8')).roles.coder.vars.thinking, 'low'); assert.equal(s.history().at(-1).actor, 'tester'); assert.ok(s.lines.some(l => l.includes('routes user="tester"'))); } finally { await b.close(); } }); test('row 177: the tester Console chat composer is enabled and a send shows in its own thread', { timeout: 60000 }, async t => { const s = await testerChat(t), b = await testerBrowser(s.web); try { const wait = expr => b.evaluate(`(async()=>{for(let n=0;n<150;n++){if(${expr})return true;await new Promise(r=>setTimeout(r,30));}throw Error('wait failed: '+${JSON.stringify(expr)});})()`); const tester = s.broker.bindTester({ business: 'demo' }); const project = s.broker.request(tester, { verb: 'project.create', args: { name: 'probe work' } }).id; const thread = s.broker.request(tester, { verb: 'thread.create', args: { project, name: 'probe' } }).id; await b.navigate(`http://mosaic-tester.invalid/#/chat/threads/${thread}`); await wait('!!document.querySelector("#tester-banner") && document.querySelector("#chat-body")?.disabled === false'); await b.evaluate(`(()=>{const e=document.querySelector('#chat-body');e.value='from the tester console';e.dispatchEvent(new Event('input',{bubbles:true}));document.querySelector('#chat-send-form').requestSubmit();return true;})()`); await wait('document.querySelector("#chat-receipt")?.textContent.includes("Accepted")'); // The log shows a send at the next read, as on the human Console; Refresh reads now. await wait('!document.querySelector("#refresh").disabled'); await b.evaluate('document.querySelector("#refresh").click(),true'); await wait('document.querySelector(".chat-log")?.textContent.includes("from the tester console")'); const m = s.store.get("SELECT * FROM messages WHERE body='from the tester console'"); assert.equal(m.from_role, 'tester'); assert.equal(m.from_run, 'tester-cli'); assert.ok(s.lines.some(l => l.includes('action=send user="tester"'))); } finally { await b.close(); } });