Files
stack/packages/webui/tests/proxy-browser.test.mjs
T
jason.woltje 362893d043 feat: integrate reviewed proxy page and managed model keys
Source-candidate: poe d9a564e6d20f5f0fd75ce45b12cbbf8bb4c9d568\nSource-candidate: magica38ba5762b06716db1dee00d0afec162656488f5c\nValidated321whole-file phase plus whole bus1349/model-proxy100/webui490; final gate tooling checks pending, not landed.
2026-10-26 12:04:21 -05:00

78 lines
6.1 KiB
JavaScript

// Native page behavior. HTTP authorization is covered by proxy-page.test.mjs;
// this stand-in serves the real page/script and records only route names/counts.
import test from 'node:test';
import assert from 'node:assert/strict';
import http from 'node:http';
import { readFileSync } from 'node:fs';
import { browser } from './browser.mjs';
async function setup(t, readonly = false) {
const state = { routes: [], loginStatus: 'wait', receivedKey: false, release: null, priority: 0 };
const server = http.createServer(async (req, res) => {
const send = value => { res.setHeader('content-type', 'application/json'); res.end(JSON.stringify(value)); };
if (req.url === '/api/config') return send({ send: !readonly });
if (req.url.startsWith('/api/proxy/')) {
state.routes.push(req.url);
const chunks = []; for await (const c of req) chunks.push(c);
const args = chunks.length ? JSON.parse(Buffer.concat(chunks)) : {};
if (req.url.endsWith('/accounts')) return send({ accounts: [{ accountId: 'a'.repeat(12), provider: 'claude', displayName: '<img src=x onerror="window.injected=true">', status: 'ready', priority: state.priority }] });
if (req.url.endsWith('/keys')) return send({ keys: [{ keyId: 'b'.repeat(12), management: 'sentinel', agent: null, issuedAt: null, state: null }] });
if (req.url.endsWith('/apikey/add')) {
state.receivedKey = args.key === 'p4-browser-key';
await new Promise(r => { state.release = r; }); return send({ added: true });
}
if (req.url.endsWith('/login/start')) return send({ url: 'https://claude.ai/oauth/authorize?state=p4-state', state: 'p4-state' });
if (req.url.endsWith('/login/status')) return send({ status: state.loginStatus });
if (req.url.endsWith('/login/submit')) return send({ status: 'wait' });
if (req.url.endsWith('/login/cancel')) return send({ status: 'cancelled' });
if (req.url.endsWith('/priority/set')) { state.priority = args.priority; return send({ priority: args.priority }); }
}
if (req.url === '/proxy') { res.setHeader('content-type', 'text/html'); return res.end(readFileSync(new URL('../src/public/proxy.html', import.meta.url))); }
if (req.url === '/proxy.js') { res.setHeader('content-type', 'text/javascript'); return res.end(readFileSync(new URL('../src/public/proxy.js', import.meta.url))); }
res.statusCode = 404; res.end();
});
await new Promise(r => server.listen(0, '127.0.0.1', r));
t.after(() => { state.release?.(); return new Promise(r => server.close(r)); });
const b = await browser({ machine: false }); t.after(() => b.close());
await b.call('Page.addScriptToEvaluateOnNewDocument', { source: "window.openFeatures=null;window.open=(url,target,features)=>{window.openFeatures=features;return null;};" });
await b.navigate(`http://127.0.0.1:${server.address().port}/proxy`);
const wait = expression => b.evaluate(`(async()=>{for(let n=0;n<200;n++){if(${expression})return true;await new Promise(r=>setTimeout(r,25));}throw Error('proxy UI condition timed out');})()`);
await wait('document.querySelector("#proxy-message").textContent.includes("loaded")');
return { b, state, wait };
}
test('proxy browser clears write-only key immediately, sends once and renders data as text', { timeout: 60000 }, async t => {
const { b, state, wait } = await setup(t);
assert.equal(await b.evaluate('window.injected===true'), false);
assert.equal(await b.evaluate('document.querySelectorAll("#proxy-accounts img").length'), 0);
assert.equal(await b.evaluate('document.querySelector("#proxy-apikey input").type'), 'password');
assert.equal(await b.evaluate('document.querySelector("#proxy-apikey input").autocomplete'), 'off');
await b.evaluate('document.querySelector("#proxy-apikey input").value="p4-browser-key";document.querySelector("#proxy-apikey").requestSubmit();true');
await wait('document.querySelector("#proxy-apikey input").value===""');
for (let n = 0; n < 100 && !state.release; n++) await new Promise(r => setTimeout(r, 20));
assert.equal(state.receivedKey, true);
state.release(); await wait('document.querySelector("#proxy-message").textContent.includes("added")');
assert.equal(state.routes.filter(r => r.endsWith('/apikey/add')).length, 1);
assert.equal(await b.evaluate('localStorage.length+sessionStorage.length'), 0);
assert.equal(await b.evaluate('document.body.textContent.includes("p4-browser-key")'), false);
});
test('proxy browser OAuth opens safely, callback wait stays pending, status ok completes', { timeout: 60000 }, async t => {
const { b, state, wait } = await setup(t);
await b.evaluate('document.querySelector("#proxy-login-start").requestSubmit();true');
await wait('!document.querySelector("#proxy-authorize").hidden');
assert.equal(await b.evaluate('window.openFeatures'), 'noopener,noreferrer');
assert.equal(await b.evaluate('document.querySelector("#proxy-authorize").rel'), 'noopener noreferrer');
await b.evaluate('document.querySelector("#proxy-login-submit input").value="http://localhost/callback?state=p4-state&code=p4-code";document.querySelector("#proxy-login-submit").requestSubmit();true');
await wait('document.querySelector("#proxy-login-message").textContent.includes("Waiting")');
assert.equal(await b.evaluate('document.querySelector("#proxy-login-message").textContent.includes("signed in")'), false);
assert.equal(await b.evaluate('document.querySelector("#proxy-login-submit input").value===""'), true);
state.loginStatus = 'ok';
await wait('document.querySelector("#proxy-login-message").textContent==="Account signed in."');
assert.equal(await b.evaluate('document.querySelector("#proxy-authorize").hasAttribute("href")'), false);
assert.equal(await b.evaluate('localStorage.length+sessionStorage.length'), 0);
});
test('proxy browser read-only disables account changes', { timeout: 60000 }, async t => {
const { b, state } = await setup(t, true);
assert.equal(await b.evaluate('[...document.querySelectorAll("[data-write]")].every(e=>e.disabled)'), true);
assert.equal(await b.evaluate('document.querySelector("#proxy-accounts input").disabled'), true);
assert.equal(state.routes.some(r => r.endsWith('/apikey/add') || r.endsWith('/login/start')), false);
});