Files
Investidor-V2/tools/portal-revision-materiality-visual-qa.cjs
nala 287e991486
tests / ci (push) Waiting to run
oportunidades 7
2026-10-13 11:40:29 +02:00

187 lines
7.4 KiB
JavaScript

const { start, assert, sanitized } = require('./portal-visual-qa-lib.cjs');
void (async () => {
const q = await start('revision-materiality-chromium-20261011');
let page, ctx, props;
const id = 31;
const route = '/minhas-oportunidades/' + id;
async function actor(role) {
if (ctx) await ctx.close();
({ page, ctx } = await q.context(role));
await q.login(page, role);
}
async function open(edit = false) {
const r = await q.open(page, route + (edit ? '/edit' : '/view'));
assert.equal(r.status(), 200);
const html = await r.text();
const attr = html.match(/data-page="([^"]+)"/);
const raw =
attr && attr[1].startsWith('{')
? attr[1]
.replace(/"/g, '"')
.replace(/&/g, '&')
.replace(/'/g, "'")
: html.match(
/<script[^>]*type="application\/json"[^>]*>([\s\S]*?)<\/script>/,
)?.[1];
props = JSON.parse(raw).props;
await page.getByRole('heading').first().waitFor();
await page.waitForLoadState('networkidle');
}
const names = {
request_revision: 'Preparar alteração material',
submit: 'Submeter para validação',
approve: 'Aprovar versão',
review_gate: 'Guardar revisão especializada',
publish: 'Disponibilizar com acesso restrito',
};
async function action(name, gate) {
await open();
q.phase('Materiality #' + id + ' ' + name);
const region = page.getByRole('region', {
name: 'Workflow interno',
exact: true,
});
await region
.getByLabel('Fundamentação', { exact: true })
.fill(
'Ensaio sintético QA de materialidade: assinatura original conservada, revisão afetada identificada e aprovação independente.',
);
if (gate) {
await region.getByLabel(/^Revisão/).selectOption(gate);
await region.getByLabel(/^Decisão/).selectOption('approved');
const d = props.canonicalOptions.resources.documents[0];
await region
.getByLabel(d.payload.title || d.file.file_name, {
exact: true,
})
.check();
}
if (name === 'publish')
await region.getByLabel(/Confirmei a pré-visualização/).check();
const pending = page.waitForResponse(
(r) =>
r.request().method() === 'POST' &&
new URL(r.url()).pathname === route + '/workflow',
);
await region
.getByRole('button', { name: names[name], exact: true })
.click();
const r = await pending;
assert.equal(r.status(), 200, name + ': ' + (await r.json()).message);
await open();
await q.shot(page, name + (gate ? '-' + gate : ''));
}
async function save(label, value) {
await open(true);
await page.getByLabel(label, { exact: true }).fill(value);
await page
.getByLabel('Motivo da alteração', { exact: true })
.fill(
'Correção sintética QA delimitada para testar materialidade e recuperação; nenhuma alteração na base ativa.',
);
const pending = page.waitForResponse(
(r) =>
r.request().method() === 'PUT' &&
new URL(r.url()).pathname === route + '/draft',
);
await page.getByRole('button', { name: /Guardar rascunho/ }).click();
const r = await pending;
assert.equal(r.status(), 200);
await open();
}
try {
await actor('promoter');
await open();
q.proof.baseline ||= {
reviews: props.profileContext.reviews,
title: props.values.canonical.official_title,
price: props.values.canonical.real_estate.price,
};
q.save();
if (!q.prior.checks?.editorial) {
if (['published', 'approved'].includes(props.workflowState))
await action('request_revision');
if (props.workflowState === 'needs_information') {
await save(
'Título oficial',
q.proof.baseline.title + ' — revisão editorial QA',
);
await action('submit');
}
assert.deepEqual(props.canonicalResponse.materiality.reopened, []);
for (const [gate, r] of Object.entries(q.proof.baseline.reviews))
assert.equal(props.profileContext.reviews[gate].hash, r.hash);
assert(
await page
.getByRole('region', { name: 'Preenchimento e revisões' })
.isVisible(),
);
await actor('validator');
await action('approve');
await actor('publisher');
await action('publish');
q.proof.checks.editorial = true;
q.save();
}
await actor('promoter');
await open();
if (['published', 'approved'].includes(props.workflowState))
await action('request_revision');
if (props.workflowState === 'needs_information') {
await save('Preço do imóvel', String(q.proof.baseline.price + 25));
await action('submit');
}
assert.deepEqual(props.canonicalResponse.materiality.reopened, [
'property_review',
]);
assert.equal(props.canonicalResponse.materiality.retained.length, 2);
q.proof.checks.only_affected_reopened = true;
await q.shot(page, 'only-property-review-reopened');
await actor('validator');
await action('review_gate', 'property_review');
await action('approve');
await actor('publisher');
await action('publish');
await actor('promoter');
const response = await q.open(page, route + '/response');
const body = await response.json();
assert.equal(body.completion.percentage, 100);
assert(body.data.real_estate.id);
assert.equal(body.compatibility.normative_response_complete, false);
q.proof.response = {
status: response.status(),
module_id: body.data.real_estate.id,
completion: body.completion,
legacy_creation: body.data.real_estate.identity_source,
metadata_gaps: body.compatibility.metadata_gaps,
};
await actor('outsider');
assert.equal((await q.open(page, route + '/response')).status(), 403);
q.proof.checks.response_permissions = true;
q.proof.result = 'passed';
} catch (e) {
q.proof.result = 'failed';
q.proof.error = sanitized(e);
if (
page &&
!['/login', '/two-factor-challenge'].includes(
new URL(page.url()).pathname,
)
)
await q.shot(page, 'failure').catch(() => {});
} finally {
q.proof.finished_at = new Date().toISOString();
q.save();
await q.browser.close();
console.log(
JSON.stringify({
result: q.proof.result,
phase: q.proof.phase,
checks: q.proof.checks,
receipt: q.receipt,
}),
);
if (q.proof.result === 'failed') process.exitCode = 1;
}
})();