const { chromium, } = require('C:/Users/macbook/.cache/codex-runtimes/codex-primary-runtime/dependencies/node/node_modules/playwright'); const assert = require('node:assert/strict'); const fs = require('node:fs'); const base = 'http://127.0.0.1:18092'; (async () => { const b = await chromium.launch({ headless: true, executablePath: 'C:/Users/macbook/AppData/Local/ms-playwright/chromium-1243/chrome-win64/chrome.exe', }); try { const c = await b.newContext(); const p = await c.newPage(); let posts = 0; let requestPayload; const responses = []; await c.route('**/*', (r) => r.request().url().startsWith(base) ? r.continue() : r.abort(), ); p.on('response', async (r) => { if ( r.url().includes('/simulation-drafts') && r.request().method() === 'POST' ) { const body = await r.json(); responses.push({ status: r.status(), body, payload: r.request().postDataJSON(), }); requestPayload = r.request().postDataJSON(); } }); p.on('request', (r) => { if (r.method() === 'POST' && r.url().includes('/balcao-virtual')) posts++; }); await p.addInitScript(() => { if (!sessionStorage.getItem('investmoz-simulation-draft-v1')) sessionStorage.setItem( 'investmoz-simulation-draft-v1', JSON.stringify({ journey_type: 'personal', detail_level: 'simple', purpose: 'simulate_only', preferred_language: 'pt', fiscal_period: '2026', fiscal_periodicity: 'annual', fiscal_component: 'customs_ice', fiscal_customs_code: 'QA-NAO-CLASSIFICADO', fiscal_operation: 'import', fiscal_scenario_mode: 'custom_planning', base: '1000', rate: '5', reduction: '0', }), ); }); const initial = await p.goto(base + '/simulador-fiscal'); assert.equal( initial.headers()['x-investmoz-qa-target'], 'investmoz_v2_20261008_test:55441', ); await p .getByText('O servidor não confirmou a gravação.', { exact: false }) .waitFor(); await p .getByRole('button', { name: '1. Finalidade', exact: true }) .click(); const field = p.getByRole('combobox').last(); assert.equal(await field.getAttribute('aria-invalid'), 'true'); await field.fill(''); await field.press('ArrowDown'); console.log(await p.getByRole('option').allTextContents()); await p .getByRole('option', { name: /Portugu/ }) .first() .click(); await p .getByText('Rascunho guardado no servidor às', { exact: false }) .waitFor(); assert.equal(responses[0].status, 422); assert.equal( responses[0].body.errors['economic_snapshot.preferred_language'][0], 'The selected economic_snapshot.preferred_language is invalid.', ); assert.equal( requestPayload.economic_snapshot.preferred_language, 'pt-MZ', ); await p .getByRole('button', { name: '3. Revisão', exact: true }) .click(); await p .getByRole('button', { name: 'Validar este rascunho', exact: true }) .click(); await p.locator('#draft-validation-summary').waitFor(); const saved = responses.find((x) => x.status === 201); assert.ok(saved); await c.close(); async function login(page) { await page.goto(base + '/login'); await page .locator('input[type=email]') .fill('guidance-qa-investor@example.invalid'); await page .locator('input[type=password]') .fill('QA-Guidance-2026!'); await page.locator('button[type=submit]').click(); await page.waitForURL((u) => !u.pathname.startsWith('/login')); } const c2 = await b.newContext(); const p2 = await c2.newPage(); await login(p2); const result = await p2.evaluate(async (snapshots) => { const token = document.cookie .split('; ') .find((x) => x.startsWith('XSRF-TOKEN=')) ?.slice(11); const current = await fetch('/api/v1/simulation-drafts/current', { headers: { Accept: 'application/json' }, }); const existing = await current.json(); const r = await fetch( existing.data ? '/api/v1/simulation-drafts/' + existing.data.id : '/api/v1/simulation-drafts', { method: existing.data ? 'PUT' : 'POST', headers: { Accept: 'application/json', 'Content-Type': 'application/json', 'X-XSRF-TOKEN': decodeURIComponent(token), 'Idempotency-Key': crypto.randomUUID(), ...(existing.data ? { 'If-Match': current.headers.get('ETag') } : {}), }, body: JSON.stringify(snapshots), }, ); return { status: r.status, body: await r.json() }; }, requestPayload); assert.ok([200, 201].includes(result.status), JSON.stringify(result)); const id = result.body.data.id; await c2.close(); const c3 = await b.newContext(); const p3 = await c3.newPage(); await login(p3); assert.equal(await p3.evaluate(() => sessionStorage.length), 0); await p3.goto(base + '/simulador-fiscal?draft=' + id); await p3 .getByText('Dossier privado recuperado da sua conta.', { exact: false, }) .waitFor(); await p3 .getByRole('button', { name: '2. Operação fiscal', exact: true }) .click(); assert.equal( await p3 .getByLabel('Base hipotética para planeamento', { exact: false, }) .inputValue(), '1000', ); const uiSave = p3.waitForResponse( (r) => r.request().method() === 'PUT' && r.url().includes('/simulation-drafts/' + id) && r.request().postDataJSON()?.economic_snapshot?.base === '1200', ); await p3 .getByLabel('Base hipotética para planeamento', { exact: false }) .fill('1200'); assert.equal((await uiSave).status(), 200); await p3.evaluate(() => { sessionStorage.clear(); localStorage.clear(); }); await p3.reload(); await p3 .getByText('Dossier privado recuperado da sua conta.', { exact: false, }) .waitFor(); await p3 .getByRole('button', { name: '2. Operação fiscal', exact: true }) .click(); assert.equal( await p3 .getByLabel('Base hipotética para planeamento', { exact: false, }) .inputValue(), '1200', ); await p3 .getByRole('button', { name: '3. Revisão', exact: true }) .click(); let calculations = 0; p3.on('request', (r) => { if ( r.method() === 'POST' && new URL(r.url()).pathname === '/api/v1/simulations' ) calculations++; }); await p3 .getByRole('button', { name: 'Validar este rascunho', exact: true }) .click(); assert.equal(calculations, 0); await p3 .getByRole('button', { name: '2. Operação fiscal', exact: true }) .click(); await p3 .getByRole('button', { name: 'Validar e calcular no servidor', exact: true, }) .click(); await p3 .getByText('Cálculo concluído no servidor.', { exact: false }) .waitFor(); assert.equal(calculations, 1); assert.equal(posts, 0); fs.writeFileSync( 'storage/app/private/investmoz-v2/draft-422-browser.json', JSON.stringify( { qa: 'investmoz_v2_20261008_test:55441', responses, ownedDraft: id, ownedCreation: result.status, freshAuthenticatedSession: true, noLocalStorageRecovery: true, baseRecovered: '1200', authenticatedUiSave: 200, separateCalculationPosts: calculations, deskSubmissions: posts, }, null, 2, ), ); await c3.close(); console.log( '422 correction, field errors, server save and fresh account recovery passed', ); } finally { await b.close(); } })().catch((e) => { console.error(e); process.exitCode = 1; });