Files
Investidor-V2/tests/frontend/proactive-investment.test.mjs
T

195 lines
6.7 KiB
JavaScript

import test from 'node:test';
import assert from 'node:assert/strict';
import fs from 'node:fs';
import { buildProjectDossierRows } from '../../resources/js/lib/project-dossier.ts';
import { proactiveInvestmentRows } from '../../resources/js/lib/proactive-investment-report.ts';
const source = (id, need) => ({
key: 'opportunity:' + id,
title: 'SYNTHETIC QA ' + id,
version: 3,
analysis: {
proactive: {
version: 1,
group: 'ideas',
state: 'hypothesis',
need,
proposal: 'Solução ' + id,
basis: 'Fixture pública sintética',
limitations: 'Não comprova procura real.',
next_action: 'Confirmar dados reais.',
evidence: [
{
statement: 'QA facto ' + id,
source: 'QA exemplar',
locator: 'Fixture linha1',
period: '2026',
scope: 'Piloto',
coverage: 'Sintética',
verified_on: '2026-10-27',
},
],
},
},
});
void test('absent proactivity is a no-op for accepted dossiers', () => {
assert.deepEqual(proactiveInvestmentRows({}), []);
assert.deepEqual(
proactiveInvestmentRows({
context_applicability_snapshot:
'{"version":1,"opportunity_choices":[]}',
}),
[],
);
assert.deepEqual(
proactiveInvestmentRows({
context_opportunity_snapshot: 'unreadable-original-preserved',
}),
[],
);
});
void test('each idea retains origin,source,need,limits without summing or inventing economic values', () => {
const choices = [
{ opportunity: source(1, 'A') },
{ opportunity: source(2, 'B') },
],
d = {
context_applicability_snapshot: JSON.stringify({
version: 1,
opportunity_choices: choices,
}),
},
r = proactiveInvestmentRows(d);
assert.equal(
r.filter((x) => x[1] === 'Origem da análise e ideia').length,
2,
);
assert.match(JSON.stringify(r), /opportunity:1/);
assert.match(JSON.stringify(r), /opportunity:2/);
assert.match(JSON.stringify(r), /Hipótese analítica/);
assert.match(JSON.stringify(r), /não é zero/);
assert.equal(
d.context_applicability_snapshot,
JSON.stringify({ version: 1, opportunity_choices: choices }),
);
});
void test('consumer selection only reports its idea even when other source contexts are present', () => {
const choices = [
{ opportunity: source(1, 'A') },
{ opportunity: source(2, 'B') },
],
r = proactiveInvestmentRows({
context_opportunity: 'opportunity:2',
context_applicability_snapshot: JSON.stringify({
version: 1,
opportunity_choices: choices,
}),
});
assert.doesNotMatch(JSON.stringify(r), /opportunity:1/);
assert.match(JSON.stringify(r), /opportunity:2/);
});
void test('explicit consumer snapshot is retained and repeat references do not duplicate report rows', () => {
const a = source(1, 'A');
let r = proactiveInvestmentRows({
context_opportunity_snapshot: JSON.stringify({
choice: { opportunity: a },
}),
});
assert.equal(
r.filter((x) => x[1] === 'Origem da análise e ideia').length,
1,
);
r = proactiveInvestmentRows({
context_applicability_snapshot: JSON.stringify({
version: 1,
opportunity_choices: [{ opportunity: a }, { opportunity: a }],
}),
});
assert.equal(
r.filter((x) => x[1] === 'Origem da análise e ideia').length,
1,
);
});
void test('portable API consumer snapshot produces an independently scoped report', () => {
const d = JSON.parse(
fs.readFileSync(
new URL('./fixtures/proactive-api-consumers.json', import.meta.url),
'utf8',
),
);
const before = JSON.stringify(d);
const perConsumer = d.consumer_contexts.map((c) =>
proactiveInvestmentRows(c.prefill.simulator),
);
for (const rows of perConsumer)
assert.equal(
rows.filter((x) => x[1] === 'Origem da análise e ideia').length,
1,
);
const r = perConsumer.flat();
assert.equal(
r.filter((x) => x[1] === 'Origem da análise e ideia').length,
2,
);
assert.match(JSON.stringify(perConsumer[0]), /opportunity:399/);
assert.doesNotMatch(JSON.stringify(perConsumer[0]), /opportunity:400/);
assert.match(JSON.stringify(perConsumer[1]), /opportunity:400/);
assert.doesNotMatch(JSON.stringify(perConsumer[1]), /opportunity:399/);
assert.doesNotMatch(JSON.stringify(r), /PRIVATE-QA-/);
assert.equal(JSON.stringify(d), before);
});
void test('resources,assumptions and selected relationships are retained in the existing dossier report', () => {
const a = source(7, 'A');
Object.assign(a.analysis.proactive, {
resources: 'QA recurso declarado',
assumptions: 'QA pressuposto explícito',
conditions: 'QA condição',
relations: [
{
kind: 'project',
target_id: 'QA-reference',
label: 'QA projecto existente',
relationship: 'hypothesis',
basis: 'QA fundamento público',
},
],
});
const draft = {
context_applicability_snapshot: JSON.stringify({
version: 1,
opportunity_choices: [{ opportunity: a }],
}),
},
rows = buildProjectDossierRows(draft);
assert.match(JSON.stringify(rows), /QA pressuposto explícito/);
assert.match(JSON.stringify(rows), /QA projecto existente/);
assert.match(
JSON.stringify(rows),
/sem contrato, acesso ou participação presumidos/,
);
});
void test('existing facts hide unrelated need and idea rows without deleting previous preparation', () => {
const a = source(8, 'Old need');
a.analysis.proactive.group = 'exists';
a.analysis.proactive.proposal = 'Old idea';
const d = {
context_applicability_snapshot: JSON.stringify({
version: 1,
opportunity_choices: [{ opportunity: a }],
}),
},
before = d.context_applicability_snapshot,
r = proactiveInvestmentRows(d);
assert.equal(
r.some(
(x) =>
x[1] === 'Estado da necessidade' ||
x[1] === 'Proposta de investimento',
),
false,
);
assert.equal(d.context_applicability_snapshot, before);
assert.match(JSON.stringify(r), /QA facto 8/);
});