Files
Investidor-V2/tools/territory-browser.mjs
T
2026-09-29 08:41:57 +02:00

40 lines
4.0 KiB
JavaScript

// Synthetic QA server only; never writes to the application database.
const target = await (await fetch('http://127.0.0.1:9224/json/new?about:blank', { method: 'PUT' })).json();
const ws = new WebSocket(target.webSocketDebuggerUrl);
await new Promise(resolve => ws.addEventListener('open', resolve, { once: true }));
let sequence = 0;
const pending = new Map();
const errors = [];
ws.onmessage = event => { const message = JSON.parse(event.data); if (message.method === 'Runtime.exceptionThrown') errors.push(message.params.exceptionDetails.text); if (message.id) { const callback = pending.get(message.id); pending.delete(message.id); message.error ? callback.reject(message.error) : callback.resolve(message.result); } };
const send = (method, params = {}) => new Promise((resolve, reject) => { const id = ++sequence; pending.set(id, { resolve, reject }); ws.send(JSON.stringify({ id, method, params })); });
const evaluate = async expression => { const result = await send('Runtime.evaluate', { expression, returnByValue: true, awaitPromise: true }); if (result.exceptionDetails) throw Error(JSON.stringify(result.exceptionDetails)); return result.result?.value; };
const wait = async expression => { for (let n = 0; n < 100; n++) { if (await evaluate(expression)) return; await new Promise(resolve => setTimeout(resolve, 100)); } throw Error('Timed out: ' + expression); };
const select = async (index, value) => evaluate(`(()=>{const element=document.querySelectorAll('select')[${index}];Object.getOwnPropertyDescriptor(HTMLSelectElement.prototype,'value').set.call(element,${JSON.stringify(value)});element.dispatchEvent(new Event('change',{bubbles:true}));})()`);
try {
await send('Runtime.enable'); await send('Page.enable');
await send('Page.navigate', { url: 'http://127.0.0.1:18027/login' });
await wait(`document.readyState==='complete' && (location.pathname!='/login' || !!document.querySelector('input[type="password"]'))`);
if (await evaluate(`location.pathname==='/login'`)) {
for (const [selector, text] of [['input[type="email"]', 'mne-browser@example.test'], ['input[type="password"]', 'SyntheticMneOnly-2026!']]) { await evaluate(`document.querySelector(${JSON.stringify(selector)}).focus()`); await send('Input.insertText', { text }); }
await evaluate(`document.querySelector('button[type="submit"]').click()`); await wait(`!location.pathname.startsWith('/login')`);
}
await send('Page.navigate', { url: 'http://127.0.0.1:18027/management/territory-associations' });
await wait(`document.querySelectorAll('select').length===2`);
await select(0, 'clusters');
await wait(`document.querySelectorAll('select')[1].options.length>1`);
await select(1, '20000000-0000-4000-8000-000000000001');
await wait(`document.querySelectorAll('select').length===6`);
for (let level = 0; level < 4; level++) {
await wait(`!document.querySelectorAll('select')[${level+2}].disabled && document.querySelectorAll('select')[${level+2}].options.length>1`);
await select(level+2, `10000000-0000-4000-8000-${String(level+2).padStart(12, '0')}`);
}
await evaluate(`[...document.querySelectorAll('button')].find(b=>b.textContent==='Guardar localização').click()`);
await wait(`document.body.innerText.includes('Localização associada e guardada.')`);
await select(2, '');
await wait(`[...document.querySelectorAll('section[aria-label="Localização do investimento"] select')].slice(1).every(s=>s.value===''&&s.disabled)`);
const widths = [];
for (const width of [390, 1440]) { await send('Emulation.setDeviceMetricsOverride', { width, height: 900, deviceScaleFactor: 1, mobile: width < 600 }); widths.push({ width, noOverflow: await evaluate('document.documentElement.scrollWidth<=innerWidth+1') }); }
if (errors.length || widths.some(w => !w.noOverflow)) throw Error('Browser validation failed');
console.log(JSON.stringify({ cascade: true, save: true, reset_descendants: true, widths, javascript_errors: errors.length }));
} finally { ws.close(); await fetch(`http://127.0.0.1:9224/json/close/${target.id}`); }