import test from 'node:test'; import assert from 'node:assert/strict'; import { harness, props, text, nodes, companyId, } from './helpers/investment-profile-editor.mjs'; const account = 'Perfil de investimento', company = 'Declaração de empresa', fresh = 'Nova declaração de empresa', residence = 'País de residência do investidor'; test('the actual profile preserves the ISO selection and repeats the exact command after a lost response', async () => { const h = harness(); h.change(residence, 'ZA', account); const first = h.submit(account); assert.equal(first.data.payload.residence_country_code, 'ZA'); await h.fail(); assert.equal(h.value(residence, account), 'ZA'); assert.equal(h.field(residence, account).props.disabled, true); assert.match(text(h.tree), /preparação foi conservada/); assert.equal(h.sent.length, 1); h.submit(account); assert.deepEqual(h.sent[1].data, first.data); await h.reply({ version: 2 }); assert.equal(h.reloads.length, 1); assert.match(text(h.tree), /Gravação confirmada/); assert.equal(h.leave(), false); }); test('a new company retry uses the original creation key and clears only its confirmed preparation', async () => { const h = harness(); h.change('Nome da empresa', 'SYNTHETIC new', fresh); h.change('País de constituição da entidade', 'MZ', fresh); h.change('Função ou relação com a empresa', 'SYNTHETIC role', fresh); h.change('Telefone', 'SYNTHETIC unsaved phone', account); const first = h.submit(fresh); await h.fail(503); const second = h.submit(fresh); assert.deepEqual(second.data, first.data); await h.reply({ id: '10000000-0000-4000-8000-000000000002', version: 1 }); assert.equal(h.value('Nome da empresa', fresh), ''); assert.equal(h.value('Telefone', account), 'SYNTHETIC unsaved phone'); assert.equal(h.leave(), true); }); test('a refreshed newer version preserves local edits until explicit comparison and adoption', async () => { const h = harness(); h.change(residence, 'ZA', account); h.render( props({ account: { version: 2, payload: { residence_country_code: 'MZ', country: 'SYNTHETIC historical', }, }, }), ); assert.equal(h.value(residence, account), 'ZA'); assert.equal( h.button('Guardar perfil de investimento', account).props.disabled, true, ); const read = h.click('Consultar registo guardado', account); assert.equal(read.method, 'GET'); await h.reply( props({ account: { version: 2, payload: { residence_country_code: 'MZ' } }, }), ); assert.match(text(h.form(account)), /Compar|Preparação nesta página/); h.click('Usar versão actual e manter a preparação', account); assert.equal(h.value(residence, account), 'ZA'); const command = h.submit(account); assert.equal(command.data.version, 2); assert.equal(command.data.payload.residence_country_code, 'ZA'); }); test('conflict recovery reads current data without applying a write automatically', async () => { const h = harness(); h.change('Nome da empresa', 'SYNTHETIC local name', company); h.submit(company); await h.fail(409); assert.equal(h.value('Nome da empresa', company), 'SYNTHETIC local name'); const read = h.click('Consultar registo guardado', company); await h.reply( props({ companies: [ { id: companyId, version: 3, payload: { name: 'SYNTHETIC server name', incorporation_country_code: 'MZ', role: 'SYNTHETIC role', }, }, ], }), ); assert.equal(h.sent.length, 2); assert.equal(read.method, 'GET'); h.click('Usar versão actual e manter a preparação', company); const command = h.submit(company); assert.equal(command.data.version, 3); assert.equal(command.data.payload.name, 'SYNTHETIC local name'); }); test('validation shows each field message once and preserves its value', async () => { const h = harness(); h.change(residence, 'ZZ', account); const sent = h.submit(account); await h.fail(422, sent, { 'payload.residence_country_code': ['SYNTHETIC invalid country'], }); assert.equal( text(h.form(account)).split('SYNTHETIC invalid country').length - 1, 1, ); assert.equal(h.value(residence, account), 'ZZ'); assert.equal(h.field(residence, account).props['aria-invalid'], true); }); test('one page leave guard covers multiple dirty profile declarations', () => { const h = harness(); h.change(residence, 'ZA', account); h.change('Nome da empresa', 'SYNTHETIC edit', company); assert.equal(h.leave(), true); assert.equal(h.confirmCalls, 1); assert.equal(h.leave(true), false); }); test('a response from the prior actor cannot confirm or reload another account', async () => { const h = harness(); h.change(residence, 'ZA', account); const old = h.submit(account); h.render( props({ actorId: 2, account: { version: 0, payload: {} }, companies: [], }), ); await h.reply({ version: 2 }, old); assert.equal(h.reloads.length, 0); assert.equal(h.value(residence, account), ''); assert.doesNotMatch(text(h.tree), /Gravação confirmada/); }); test('an invalid creation acknowledgement keeps the new company and command unresolved', async () => { const h = harness(); h.change('Nome da empresa', 'SYNTHETIC retained', fresh); h.submit(fresh); await h.reply({ version: 1, id: 'invalid-id' }); assert.equal(h.value('Nome da empresa', fresh), 'SYNTHETIC retained'); assert.equal(h.reloads.length, 0); assert.match(text(h.tree), /Não foi possível confirmar/); }); test('long answers use multiline controls and text limits match the server', () => { const h = harness(); assert.equal(h.field('Experiência relevante', account).type, 'textarea'); assert.equal(h.field('Telefone', account).props.maxLength, 30); assert.equal( h.field('Referência de registo / NUIT', company).props.maxLength, 100, ); assert.equal( nodes(h.form(account)).filter( (node) => node.type === 'input' && node.props.required, ).length, 0, ); }); test('consulting after an uncertain creation never unlocks editing or replaces its original command', async () => { const h = harness(); h.change('Nome da empresa', 'SYNTHETIC original attempt', fresh); const first = h.submit(fresh); await h.fail(); h.click('Consultar registo guardado', fresh); await h.reply(props()); assert.equal( h.value('Nome da empresa', fresh), 'SYNTHETIC original attempt', ); assert.equal(h.field('Nome da empresa', fresh).props.disabled, true); assert.equal( h.button('Usar versão actual e manter a preparação', fresh), undefined, ); const retry = h.submit(fresh); assert.deepEqual(retry.data, first.data); }); test('company country validation is attached once to the selectable country field', async () => { const h = harness(); const request = h.submit(fresh); await h.fail(422, request, { 'payload.country': ['SYNTHETIC company country required'], }); assert.equal( h.field('País de constituição da entidade', fresh).props[ 'aria-invalid' ], true, ); assert.equal( text(h.form(fresh)).split('SYNTHETIC company country required').length - 1, 1, ); }); test('preparing a manifestation cannot discard unsaved profile data without the existing leave confirmation', () => { const h = harness(); h.change(residence, 'ZA', account); h.click('Preparar manifestação desta empresa'); assert.equal(h.confirmCalls, 1); assert.equal(h.value(residence, account), 'ZA'); assert.equal(h.sent.length, 0); }); test('a newer value read from the server requires explicit adoption before another write', async () => { const h = harness(); h.change(residence, 'ZA', account); h.click('Consultar registo guardado', account); await h.reply( props({ account: { version: 4, payload: { residence_country_code: 'MZ' } }, }), ); const count = h.sent.length; h.submit(account); assert.equal(h.sent.length, count); assert.equal( h.button('Guardar perfil de investimento', account).props.disabled, true, ); h.click('Usar versão actual e manter a preparação', account); assert.equal(h.submit(account).data.version, 4); });