Files
Investidor-V2/tests/frontend/partnership-room-recovery.test.mjs
T

421 lines
15 KiB
JavaScript

import test from 'node:test';
import assert from 'node:assert/strict';
import { File } from 'node:buffer';
import {
harness,
props,
original,
nodes,
text,
} from './helpers/partnership-room.mjs';
const newerRoom = (h, patch = {}) => ({
...h.props,
room: { ...h.props.room, version: h.props.room.version + 1, ...patch },
});
const mutableMilestone = (h, patch = {}) => ({
...h.props,
milestones: [{ ...h.props.milestones[0], ...patch }],
});
function row(scope, label) {
return nodes(scope).find(
(node) => node.type === 'tr' && text(node).startsWith(label),
);
}
test('untouched controls follow current data without requiring comparison of an empty new milestone', () => {
const h = harness(props({ milestones: [original] }));
h.change('message', 'Mensagem privada', 'SYNTHETIC separate draft');
h.render({
...newerRoom(h),
milestones: [
{
...original,
version: 4,
title: 'SYNTHETIC updated remote deliverable',
},
],
});
assert.equal(
h.field('milestone:7', 'Entregável').props.value,
'SYNTHETIC updated remote deliverable',
);
assert.equal(
h.button('Guardar marco', h.form('milestone:7')).props.disabled,
false,
);
assert.equal(
h.field('message', 'Mensagem privada').props.value,
'SYNTHETIC separate draft',
);
assert.equal(
h.button('Usar este contexto e conservar as alterações escolhidas'),
undefined,
);
h.change('milestone:new', 'Responsável pelo marco', '1');
assert.equal(
h.button('Guardar marco', h.form('milestone:new')).props.disabled,
false,
);
});
test('room version changes retain every independent form, including a selected File', () => {
const h = harness(props({ milestones: [original] }));
const file = new File(['SYNTHETIC bytes'], 'synthetic.pdf', {
type: 'application/pdf',
});
h.change('message', 'Mensagem privada', 'SYNTHETIC unsent question');
h.change('upload', 'Anexar PDF ou imagem', file);
h.change('agreement', 'Condições e plano de valor', 'SYNTHETIC own terms');
h.change(
'milestone:7',
'Evidência ou referência do resultado',
'SYNTHETIC own evidence',
);
h.render(newerRoom(h));
assert.equal(
h.field('message', 'Mensagem privada').props.value,
'SYNTHETIC unsent question',
);
assert.match(text(h.form('upload')), /synthetic.pdf/);
assert.equal(
h.field('agreement', 'Condições e plano de valor').props.value,
'SYNTHETIC own terms',
);
assert.equal(
h.field('milestone:7', 'Evidência ou referência do resultado').props
.value,
'SYNTHETIC own evidence',
);
assert.equal(
h.button('Guardar marco', h.form('milestone:7')).props.disabled,
true,
);
});
test('milestone conflicts are compared explicitly and return-to-original remains a deliberate edit', () => {
const h = harness(props({ milestones: [original] }));
h.change('milestone:7', 'Entregável', 'SYNTHETIC temporarily changed');
h.change('milestone:7', 'Entregável', original.title);
h.render(
mutableMilestone(h, {
title: 'SYNTHETIC remote title',
version: 4,
status: 'progress',
}),
);
const scope = h.form('milestone:7');
assert.match(text(scope), /Escolha o valor a conservar/);
assert.match(text(row(scope, 'Estado')), /Pendente/);
assert.doesNotMatch(text(row(scope, 'Estado')), /Submetida/);
h.click('Manter minha alteração', row(scope, 'Entregável'));
h.click(
'Usar este contexto e conservar as alterações escolhidas',
h.form('milestone:7'),
);
const request = h.submit('milestone:7');
assert.equal(request.data.version, 4);
assert.equal(request.data.title, original.title);
});
test('independent agreement conflicts keep previous choices while another field is edited', () => {
const h = harness();
h.change('agreement', 'Título do instrumento', 'SYNTHETIC local title');
h.change(
'agreement',
'Condições e plano de valor',
'SYNTHETIC local terms',
);
h.render(
newerRoom(h, {
agreement: {
...h.props.room.agreement,
title: 'SYNTHETIC remote title',
terms: 'SYNTHETIC remote terms',
},
}),
);
h.click('Manter minha alteração', row(h.tree, 'Título do instrumento'));
h.click(
'Manter minha alteração',
row(h.tree, 'Condições e plano de valor'),
);
h.change('agreement', 'Motivo da ação', 'SYNTHETIC compare decision');
const adopt = h.button(
'Usar este contexto e conservar as alterações escolhidas',
);
assert.equal(adopt.props.disabled, false);
h.click('Usar este contexto e conservar as alterações escolhidas');
const request = h.click('Registar versão do acordo');
assert.equal(request.data.version, 3);
assert.equal(request.data.title, 'SYNTHETIC local title');
assert.equal(request.data.terms, 'SYNTHETIC local terms');
});
test('context-only change requires adoption and a confirmed record clears only its sent reason', () => {
const h = harness();
h.change('agreement', 'Motivo da ação', 'SYNTHETIC edit');
h.render(newerRoom(h));
assert.equal(h.button('Registar versão do acordo').props.disabled, true);
h.click('Usar este contexto e conservar as alterações escolhidas');
const request = h.click('Registar versão do acordo');
const confirmed = newerRoom(h);
confirmed.agreementCommands = [
{
key: request.data.client_key,
action: 'record',
version: request.data.version + 1,
status: confirmed.room.status,
party: null,
},
];
h.success(confirmed, request);
assert.equal(h.field('agreement', 'Motivo da ação').props.value, '');
assert.equal(h.button('Registar versão do acordo').props.disabled, true);
});
test('milestone acknowledgement uses canonical data and conserves edits made after send', () => {
const h = harness(props({ milestones: [original] }));
h.change('milestone:7', 'Entregável', ' SYNTHETIC trimmed title ');
const request = h.submit('milestone:7');
h.change(
'milestone:7',
'Evidência ou referência do resultado',
'SYNTHETIC later evidence',
);
h.success(
mutableMilestone(h, { title: 'SYNTHETIC trimmed title', version: 4 }),
request,
);
assert.equal(
h.field('milestone:7', 'Entregável').props.value,
'SYNTHETIC trimmed title',
);
assert.equal(
h.field('milestone:7', 'Evidência ou referência do resultado').props
.value,
'SYNTHETIC later evidence',
);
assert.equal(
h.button('Guardar marco', h.form('milestone:7')).props.disabled,
false,
);
});
test('uncertain milestone creation repeats original bytes and retains later changes as new preparation', () => {
const h = harness();
h.change('milestone:new', 'Entregável', 'SYNTHETIC original creation');
h.change('milestone:new', 'Responsável pelo marco', '1');
const first = h.submit('milestone:new');
h.fail(first);
h.change('milestone:new', 'Entregável', 'SYNTHETIC later draft');
const retry = h.submit('milestone:new');
assert.deepEqual(retry.data, first.data);
const saved = {
...original,
id: 11,
version: 1,
title: first.data.title,
client_key: first.data.client_key,
};
h.success({ ...h.props, milestones: [saved] }, retry);
assert.equal(
h.field('milestone:new', 'Entregável').props.value,
'SYNTHETIC later draft',
);
assert.match(text(h.form('milestone:new')), /como nova preparação/);
assert.ok(h.form('milestone:11'));
});
test('closed room keeps drafts mounted and blocks new changes until context and authority permit them', () => {
const h = harness(props({ milestones: [original] }));
h.change('milestone:7', 'Entregável', 'SYNTHETIC kept milestone');
h.change(
'agreement',
'Condições e plano de valor',
'SYNTHETIC kept agreement',
);
h.change('message', 'Mensagem privada', 'SYNTHETIC kept message');
h.render(newerRoom(h, { status: 'cancelled' }));
assert.ok(h.form('milestone:7'));
assert.equal(
h.field('milestone:7', 'Entregável').props.value,
'SYNTHETIC kept milestone',
);
assert.equal(
nodes(h.form('milestone:7')).find((node) => node.type === 'fieldset')
.props.disabled,
true,
);
assert.equal(
h.field('agreement', 'Condições e plano de valor').props.value,
'SYNTHETIC kept agreement',
);
assert.equal(h.button('Enviar mensagem').props.disabled, true);
assert.match(text(h.tree), /preparação.*conservada/);
});
test('uncertain messages retain their original key while later text is prepared separately', () => {
const h = harness();
h.change('message', 'Mensagem privada', 'SYNTHETIC first message');
const first = h.submit('message');
h.fail(first);
h.change('message', 'Mensagem privada', 'SYNTHETIC next message');
const retry = h.submit('message');
assert.deepEqual(retry.data, first.data);
h.success(
{
...h.props,
messages: [
{
id: 1,
author_id: 1,
client_key: first.data.client_key,
body: first.data.body,
name: 'SYNTHETIC owner',
created_at: 'synthetic',
},
],
},
retry,
);
assert.equal(
h.field('message', 'Mensagem privada').props.value,
'SYNTHETIC next message',
);
const next = h.submit('message');
assert.notEqual(next.data.client_key, first.data.client_key);
assert.equal(next.data.body, 'SYNTHETIC next message');
});
test('uncertain upload retains the immutable File and original sharing consent through retry', () => {
const h = harness();
const firstFile = new File(['SYNTHETIC first'], 'first.pdf'),
laterFile = new File(['SYNTHETIC later'], 'later.pdf');
h.change('upload', 'Anexar PDF ou imagem', firstFile);
const first = h.submit('upload');
h.fail(first);
h.change('upload', 'Anexar PDF ou imagem', laterFile);
const retry = h.submit('upload');
assert.equal(retry.data.file, firstFile);
assert.equal(retry.data.client_key, first.data.client_key);
assert.equal(retry.data.shared, false);
h.success(
{
...h.props,
documents: [
{
id: 1,
document_id: 'synthetic-document',
owner_id: 1,
file_name: 'first.pdf',
shared: false,
status: 'quarantined',
malware_scan_status: 'pending',
},
],
flash: { uploaded_document_id: 'synthetic-document' },
},
retry,
);
assert.match(text(h.form('upload')), /later.pdf/);
const next = h.submit('upload');
assert.equal(next.data.file, laterFile);
assert.notEqual(next.data.client_key, first.data.client_key);
});
test('unrelated or malformed acknowledgement never erases message or upload preparation', () => {
const h = harness();
h.change('message', 'Mensagem privada', 'SYNTHETIC retained');
const request = h.submit('message');
h.success({ ...h.props, room: { ...h.props.room, id: 999 } }, request);
assert.equal(
h.field('message', 'Mensagem privada').props.value,
'SYNTHETIC retained',
);
assert.match(text(h.form('message')), /não foi confirmado/);
});
test('one leave guard covers all drafts; comparison refresh does not trigger a leave prompt', () => {
const h = harness(props({ milestones: [original] }));
h.change('message', 'Mensagem privada', 'SYNTHETIC message');
h.change('milestone:7', 'Entregável', 'SYNTHETIC draft');
assert.equal(h.leave(), true);
assert.equal(h.confirmCalls, 1);
assert.equal(h.unload(), true);
assert.equal(h.leave(true), false);
assert.equal(h.confirmCalls, 1);
});
test('losing write access conserves preparation and another account gets a fresh room editor', () => {
const h = harness();
h.change('message', 'Mensagem privada', 'SYNTHETIC private local draft');
h.render({ ...h.props, canWrite: false, participants: [] });
assert.equal(h.button('Enviar mensagem').props.disabled, true);
assert.equal(
h.field('message', 'Mensagem privada').props.value,
'SYNTHETIC private local draft',
);
h.render({ ...h.props, canWrite: true, actorId: 2 });
assert.equal(h.field('message', 'Mensagem privada').props.value, '');
});
test('HTTP409 preserves agreement text and a successful refresh of the unchanged base permits a retry', () => {
const h = harness();
h.change('agreement', 'Motivo da ação', 'SYNTHETIC retry');
const request = h.click('Registar versão do acordo');
h.fail(request, 409);
assert.equal(h.button('Registar versão do acordo').props.disabled, true);
h.click('Comparar com os dados actuais da sala');
h.refreshed(h.props);
assert.equal(h.button('Registar versão do acordo').props.disabled, false);
assert.equal(
h.field('agreement', 'Motivo da ação').props.value,
'SYNTHETIC retry',
);
});
test('confirmation uses a fresh reviewed room version and preserves unsent instrument changes', () => {
const h = harness();
h.change(
'agreement',
'Título do instrumento',
'SYNTHETIC local unrecorded title',
);
h.change(
'agreement',
'Motivo da ação',
'SYNTHETIC confirm published terms',
);
const request = h.click('Confirmar pela minha parte');
assert.equal(request.data.title, undefined);
assert.equal(request.data.version, 2);
const confirmed = newerRoom(h);
confirmed.room.agreement = {
...confirmed.room.agreement,
confirmations: {
proponent: {
actor_id: 1,
date: 'SYNTHETIC',
reason: request.data.reason,
},
},
};
confirmed.agreementCommands = [
{
key: request.data.client_key,
action: 'confirm',
version: request.data.version + 1,
status: confirmed.room.status,
party: 'proponent',
},
];
h.success(confirmed, request);
assert.equal(
h.field('agreement', 'Título do instrumento').props.value,
'SYNTHETIC local unrecorded title',
);
assert.equal(h.field('agreement', 'Motivo da ação').props.value, '');
});
test('a newer unexpected acknowledgement is compared instead of being accepted as the sent edit', () => {
const h = harness(props({ milestones: [original] }));
h.change('milestone:7', 'Entregável', 'SYNTHETIC own title');
const request = h.submit('milestone:7');
h.success(
mutableMilestone(h, { title: 'SYNTHETIC another edit', version: 5 }),
request,
);
assert.equal(
h.field('milestone:7', 'Entregável').props.value,
'SYNTHETIC own title',
);
assert.equal(
h.button('Guardar marco', h.form('milestone:7')).props.disabled,
true,
);
});