260 lines
9.6 KiB
JavaScript
260 lines
9.6 KiB
JavaScript
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;
|
|
});
|