Files
Investidor-V2/tests/frontend/crm-task-creation.test.mjs
T

208 lines
7.8 KiB
JavaScript

import test from 'node:test';
import assert from 'node:assert/strict';
import { harness, props, text, leadId } from './helpers/crm-task-creation.mjs';
const form = 'new-crm-task';
function fill(h, title = 'SYNTHETIC first') {
h.change(form, 'Tarefa', title);
h.change(form, 'Prazo (hora local)', '2027-11-04T10:30');
}
function saved(h, request, patch = {}) {
return {
...h.props,
lead: {
...h.props.lead,
tasks: [
{
id: '20000000-0000-4000-8000-000000000001',
title: request.data.title,
due_at: request.data.due_at,
assignee_user_id: Number(request.data.assignee_user_id),
version_no: 1,
status: 'open',
},
],
},
taskCreation: {
lead_id: leadId,
actor_id: 1,
commands: [
{
key: request.data.client_key,
task_id: '20000000-0000-4000-8000-000000000001',
version: 1,
},
],
},
...patch,
};
}
test('confirmation preserves title and deadline edited after the request was sent', () => {
const h = harness();
fill(h);
const request = h.submit(form);
h.change(form, 'Tarefa', 'SYNTHETIC later');
h.change(form, 'Prazo (hora local)', '2027-11-05T11:00');
h.success(saved(h, request), request);
assert.equal(h.field(form, 'Tarefa').props.value, 'SYNTHETIC later');
assert.equal(
h.field(form, 'Prazo (hora local)').props.value,
'2027-11-05T11:00',
);
});
test('a lost response retries exactly the frozen request, preserving later edits', () => {
const h = harness();
fill(h);
const request = h.submit(form);
h.change(form, 'Tarefa', 'SYNTHETIC next task');
h.change(form, 'Responsável pela tarefa', '2');
h.fail(request);
const retry = h.submit(form);
assert.deepEqual(retry.data, request.data);
h.success(saved(h, retry), retry);
assert.equal(h.field(form, 'Tarefa').props.value, 'SYNTHETIC next task');
assert.equal(h.field(form, 'Responsável pela tarefa').props.value, '2');
const next = h.submit(form);
assert.notEqual(next.data.client_key, request.data.client_key);
assert.equal(next.data.title, 'SYNTHETIC next task');
});
test('a fresh read acknowledges the committed creation without posting again', () => {
const h = harness();
fill(h);
const request = h.submit(form);
h.fail(request, 500);
h.click('Actualizar tarefas');
assert.deepEqual(h.reloads.at(-1).only, [
'lead',
'owners',
'taskCreation',
'nextAction',
]);
h.refreshed(saved(h, request));
assert.equal(h.sent.length, 1);
assert.equal(h.field(form, 'Tarefa').props.value, '');
assert.match(text(h.tree), /Tarefa registada/);
});
test('unconfirmed reads keep the original command and later edits', () => {
const h = harness();
fill(h);
const request = h.submit(form);
h.fail(request);
h.change(form, 'Tarefa', 'SYNTHETIC later');
h.click('Actualizar tarefas');
h.refreshed(h.props);
assert.equal(h.field(form, 'Tarefa').props.value, 'SYNTHETIC later');
assert.deepEqual(h.submit(form).data, request.data);
});
test('another account or lead cannot acknowledge or clear a pending command', () => {
for (const context of [
{ lead_id: leadId, actor_id: 2 },
{ lead_id: 'other', actor_id: 1 },
]) {
const h = harness();
fill(h);
const request = h.submit(form);
const next = saved(h, request);
next.taskCreation = { ...next.taskCreation, ...context };
request.options.onSuccess({ props: next });
request.form.processing = false;
h.render();
assert.equal(h.field(form, 'Tarefa').props.value, 'SYNTHETIC first');
assert.doesNotMatch(text(h.tree), /Tarefa registada/);
}
});
test('a same-version task mismatch does not count as confirmation', () => {
const h = harness();
fill(h);
const request = h.submit(form);
const next = saved(h, request);
next.lead.tasks[0].title = 'SYNTHETIC different';
h.success(next, request);
assert.equal(h.field(form, 'Tarefa').props.value, 'SYNTHETIC first');
assert.match(text(h.tree), /não permitiu confirmar/);
});
test('later task changes and a removed task are acknowledged without restoration', () => {
for (const removed of [false, true]) {
const h = harness();
fill(h);
const request = h.submit(form);
const next = saved(h, request);
if (removed) next.lead.tasks = [];
else
Object.assign(next.lead.tasks[0], {
version_no: 2,
status: 'done',
title: 'SYNTHETIC updated',
});
request.options.onSuccess({ props: next });
request.form.processing = false;
h.render();
assert.equal(h.field(form, 'Tarefa').props.value, '');
assert.equal(h.sent.length, 1);
if (removed) assert.match(text(h.tree), /já não está disponível/);
}
});
test('validation retains the draft and allows a corrected fresh command', () => {
const h = harness();
fill(h);
const request = h.submit(form);
h.validation({ due_at: 'SYNTHETIC validation' }, request);
assert.equal(h.field(form, 'Tarefa').props.value, 'SYNTHETIC first');
h.change(form, 'Prazo (hora local)', '2027-11-06T12:00');
const next = h.submit(form);
assert.notEqual(next.data.client_key, request.data.client_key);
assert.equal(next.data.due_at, new Date('2027-11-06T12:00').toISOString());
});
test('an untouched assignee follows a refreshed owner while an explicit choice is retained', () => {
const h = harness();
h.render({ ...h.props, lead: { ...h.props.lead, owner_user_id: 2 } });
assert.equal(h.field(form, 'Responsável pela tarefa').props.value, '2');
h.change(form, 'Responsável pela tarefa', '1');
h.render({
...h.props,
lead: { ...h.props.lead, owner_user_id: null },
owners: [],
});
assert.equal(h.field(form, 'Responsável pela tarefa').props.value, '1');
assert.match(text(h.form(form)), /Responsável anterior indisponível/);
});
test('draft and unknown results have one navigation guard; confirmed unchanged values clear it', () => {
const h = harness();
assert.equal(h.leave(), false);
fill(h);
assert.equal(h.leave(), true);
assert.equal(h.confirmCalls, 1);
assert.equal(h.unload(), true);
const request = h.submit(form);
h.fail(request);
assert.equal(h.leave(true), false);
h.success(saved(h, request), request);
assert.equal(h.leave(), false);
assert.equal(h.unload(), false);
});
test('an obsolete callback cannot erase the draft of a different lead or actor', () => {
const h = harness();
fill(h);
const request = h.submit(form);
const other = props({
lead: { ...h.props.lead, id: 'other' },
taskCreation: { lead_id: 'other', actor_id: 2, commands: [] },
});
h.render(other);
h.change(form, 'Tarefa', 'SYNTHETIC other draft');
request.options.onSuccess({ props: saved(h, request) });
request.form.processing = false;
h.render();
assert.equal(h.field(form, 'Tarefa').props.value, 'SYNTHETIC other draft');
});
test('access and conflict responses keep the command blocked until a scoped refresh', () => {
const h = harness();
fill(h);
const request = h.submit(form);
h.fail(request, 403);
assert.equal(h.button('Recuperar a mesma criação').props.disabled, true);
h.click('Actualizar tarefas');
h.refreshed(h.props);
assert.equal(h.button('Recuperar a mesma criação').props.disabled, false);
assert.deepEqual(h.submit(form).data, request.data);
});