Files
Investidor-V2/tests/frontend/ispc-eligibility.test.mjs
T

341 lines
12 KiB
JavaScript

import test from 'node:test';
import assert from 'node:assert/strict';
import fs from 'node:fs';
import {
newIspcEligibilityInput,
ispcEligibilityBook,
saveIspcEligibilityBook,
recordIspcEligibility,
ispcEligibilityCurrent,
ispcEligibilityReportRows,
ispcReuseValues,
ispcReuseDiff,
} from '../../resources/js/lib/ispc-eligibility.ts';
const seed = JSON.parse(
fs.readFileSync(
new URL('./fixtures/iva-l3e-preserved.json', import.meta.url),
'utf8',
),
);
function fixture(patch = {}) {
const d = {
...structuredClone(seed),
context_opportunity: 'opportunity:375',
fiscal_component: 'ispc',
person_type: 'collective',
fiscal_activity: 'SYNTHETIC QA comércio',
fiscal_establishments: '1',
project_title: 'SYNTHETIC QA — L4-A ISPC',
},
input = {
...newIspcEligibilityInput(d),
activities: ['commerce'],
territory: 'yes',
basis: 'previous_year',
referenceYear: '2025',
annualReference: '4000000',
annualReferenceRef: 'SYNTHETIC QA referência2025',
organizedRequired: 'no',
sharesInIspc: 'no',
sharesAnonymous: 'no',
otherActivities: 'no',
generalRegimeChosen: 'no',
...patch,
};
return { d, b: { version: 1, input } };
}
const evaluate = (patch) => {
const { d, b } = fixture(patch);
return recordIspcEligibility(d, b).result;
};
void test('reuses only valid person/activity/establishments;does not invent activity category,prior annual volume or option', () => {
const d = {
person_type: 'sole_trader',
fiscal_activity: 'Actividade conhecida',
fiscal_establishments: 2,
currency: 'MZN',
annual_sales: '3000000',
fiscal_turnover: '3000000',
};
const i = newIspcEligibilityInput(d);
assert.equal(i.personType, 'singular');
assert.equal(i.establishments, '2');
assert.equal(i.activityDescription, 'Actividade conhecida');
assert.deepEqual(i.activities, []);
assert.equal(i.annualReference, '');
assert.equal(i.option, 'preparation');
assert.equal(
newIspcEligibilityInput({ ...d, person_type: 'consortium' }).personType,
'',
);
});
void test('2025reference4000000inclusive is compatible;optative choice remains preparation;foreign investor does not imply foreign operation', () => {
const { d, b } = fixture();
d.nationality = 'estrangeira';
const r = recordIspcEligibility(d, b).result;
assert.equal(r.status, 'compatible', r.reason);
assert.equal(r.annualReference.numerator, '4000000');
assert.equal(r.optionStatus, 'preparation');
assert.match(r.optionReason, /não é adesão/);
assert.equal(
evaluate({ annualReference: '4000000.000001' }).status,
'incompatible',
);
assert.equal(evaluate({ annualReference: '' }).status, 'indeterminate');
assert.equal(evaluate({ annualReference: '0' }).status, 'compatible');
});
void test('known statutory exclusions are specific and do not require filling irrelevant remaining inputs', () => {
for (const patch of [
{ organizedRequired: 'yes' },
{ sharesInIspc: 'yes' },
{ sharesAnonymous: 'yes' },
{ otherActivities: 'yes' },
{ activities: ['other'] },
{ establishments: '2' },
{ territory: 'no' },
])
assert.equal(
evaluate({ ...patch, annualReference: '' }).status,
'incompatible',
JSON.stringify(patch),
);
for (const field of [
'organizedRequired',
'sharesInIspc',
'sharesAnonymous',
'otherActivities',
'generalRegimeChosen',
])
assert.equal(evaluate({ [field]: '' }).status, 'indeterminate', field);
});
void test('liberal183days versus184;8b services do not inherit the8c duration rule;inapplicable retained facts do not become exclusions', () => {
const p = {
activities: ['liberal15'],
unlistedServices: 'no',
liberalDaysSameEntity: '183',
liberalClientRef: 'SYNTHETIC QA maior duração do ano',
};
assert.equal(evaluate(p).status, 'compatible');
assert.equal(
evaluate({ ...p, liberalDaysSameEntity: '184' }).status,
'incompatible',
);
assert.equal(
evaluate({ ...p, liberalDaysSameEntity: '' }).status,
'indeterminate',
);
assert.equal(
evaluate({ ...p, liberalDaysSameEntity: '367' }).status,
'indeterminate',
);
assert.equal(
evaluate({
...p,
activities: ['services12'],
liberalDaysSameEntity: '184',
}).status,
'compatible',
);
assert.equal(
evaluate({
...p,
activities: ['commerce'],
unlistedServices: 'yes',
liberalDaysSameEntity: '184',
}).status,
'compatible',
);
assert.equal(
evaluate({
...p,
activities: ['commerce', 'liberal15'],
liberalDaysSameEntity: '184',
}).status,
'incompatible',
);
});
void test('startup forecast has its own2026basis and AT confirmation;projected assumption and effective reference stay distinct', () => {
const p = {
basis: 'start_forecast',
referenceYear: '2026',
annualReference: '1000000',
};
assert.equal(evaluate(p).status, 'indeterminate');
assert.equal(
evaluate({ ...p, forecastConfirmed: 'yes' }).status,
'compatible',
);
assert.equal(
evaluate({ ...p, origin: 'effective', forecastConfirmed: 'yes' })
.status,
'indeterminate',
);
assert.equal(
evaluate({
...p,
origin: 'effective',
forecastConfirmed: 'yes',
forecastConfirmationRef: 'SYNTHETIC QA confirmaçãoAT',
}).status,
'compatible',
);
assert.equal(
evaluate({
...p,
referenceYear: '2025',
forecastConfirmed: 'yes',
annualReference: '5000000',
}).status,
'indeterminate',
);
assert.equal(
evaluate({ basis: '', referenceYear: '', annualReference: '5000000' })
.status,
'indeterminate',
);
});
void test('three-year general-regime commitment is explicit;no new approver or assumption from an empty field', () => {
const p = { generalRegimeChosen: 'yes', generalThreeYearsCompleted: 'no' };
assert.equal(evaluate(p).status, 'incompatible');
assert.equal(
evaluate({ ...p, generalThreeYearsCompleted: 'yes' }).status,
'indeterminate',
);
assert.equal(
evaluate({
...p,
generalThreeYearsCompleted: 'yes',
generalRegimeRef: 'SYNTHETIC QA opção e período cumprido',
}).status,
'compatible',
);
assert.equal(
evaluate({
generalRegimeChosen: 'no',
generalThreeYearsCompleted: 'no',
}).status,
'compatible',
);
});
void test('documented option is separate from eligibility and cannot be inferred from selectingISPC', () => {
const p = { option: 'opted' };
let r = evaluate(p);
assert.equal(r.status, 'compatible');
assert.equal(r.optionStatus, 'indeterminate');
r = evaluate({
...p,
optionReference: 'SYNTHETIC QA opção',
optionDate: '2025-12-31',
});
assert.equal(r.optionStatus, 'recorded');
assert.equal(
evaluate({ ...p, optionReference: 'x', optionDate: '2026-02-01' })
.optionStatus,
'indeterminate',
);
assert.equal(evaluate({ option: 'not_opted' }).optionStatus, 'not_opted');
});
void test('wrong currency/year and occasional scope remain indeterminate rather than zero or invented ineligibility', () => {
for (const patch of [
{ currency: 'USD' },
{ currency: '' },
{ assessmentDate: '2025-12-31' },
{ assessmentDate: '2026-02-30' },
{ assessmentDate: '2027-01-01' },
{ mode: 'occasional' },
{ personType: '' },
{ referenceYear: '2026' },
{ establishments: '' },
])
assert.equal(
evaluate(patch).status,
'indeterminate',
JSON.stringify(patch),
);
});
void test('save/recovery preserves all prior fiscal maps;deliberate edits keep frozen report and append history only on calculation', () => {
const { d, b } = fixture(),
before = JSON.parse(d.modelo_a_snapshot);
let book = recordIspcEligibility(d, b, '2026-10-25T14:00:00Z');
d.modelo_a_snapshot = saveIspcEligibilityBook(d, book);
for (const [k, v] of Object.entries(before))
assert.deepEqual(JSON.parse(d.modelo_a_snapshot)[k], v, k);
assert.ok(ispcEligibilityCurrent(d, book));
const first = structuredClone(book.result);
book.input.activityDescription = 'Deliberate future edit';
d.modelo_a_snapshot = saveIspcEligibilityBook(d, book);
assert.equal(ispcEligibilityCurrent(d, book), false);
assert.doesNotMatch(
ispcEligibilityReportRows(d).flat().join(' '),
/Deliberate future edit/,
);
book = recordIspcEligibility(d, book);
assert.deepEqual(book.history.at(-1), first);
d.modelo_a_snapshot = saveIspcEligibilityBook(d, book);
assert.deepEqual(ispcEligibilityBook(JSON.parse(JSON.stringify(d))), book);
});
void test('reuse differences are reviewable;new profile values do not overwrite annual amounts,option or deliberate edits', () => {
const { d, b } = fixture();
b.input.activityDescription = 'Deliberate activity';
b.input.option = 'not_opted';
const diff = ispcReuseDiff(
{
...d,
fiscal_establishments: '2',
fiscal_activity: 'New profile activity',
},
b,
);
assert.equal(b.input.establishments, '1');
assert.equal(b.input.activityDescription, 'Deliberate activity');
assert.ok(
diff.some((v) => v.field === 'establishments' && v.after === '2'),
);
assert.ok(diff.some((v) => v.field === 'activityDescription'));
assert.ok(
!(
'annualReference' in
ispcReuseValues({ ...d, annual_sales: '9000000' })
),
);
assert.equal(b.input.option, 'not_opted');
});
void test('malformed books and ambiguous opportunity are preserved errors,not silently empty preparations', () => {
const { d, b } = fixture();
b.input.activities = ['commerce', 'commerce'];
assert.throws(() => saveIspcEligibilityBook(d, b), /não recuperáveis/);
assert.throws(
() =>
ispcEligibilityBook({
...d,
modelo_a_snapshot: JSON.stringify({
version: 1,
books: {},
ispcEligibility: [],
}),
}),
/não recuperável/,
);
assert.throws(
() =>
ispcEligibilityBook({
...d,
context_opportunity: '',
context_applicability_snapshot: JSON.stringify({
opportunity_choices: ['a', 'b'],
}),
}),
/Escolha/,
);
});
void test('export synthetic eligibility book for isolated private persistence and actual component proof', () => {
const { d, b } = fixture({ annualReference: '2500000' });
let book = recordIspcEligibility(d, b, '2026-10-25T14:00:00Z');
book = recordIspcEligibility(d, book, '2026-10-25T14:01:00Z');
d.modelo_a_snapshot = saveIspcEligibilityBook(d, book);
assert.equal(book.result.status, 'compatible');
assert.equal(book.result.optionStatus, 'preparation');
if (process.env.L4A_ISPC_OUTPUT)
fs.writeFileSync(process.env.L4A_ISPC_OUTPUT, JSON.stringify(d));
});