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( /]*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; } })();