Reconciliar verificacoes com navegacao e relatorios aprovados
This commit is contained in:
@@ -114,7 +114,7 @@ export async function portalRequest<T>(
|
||||
const headers = new Headers(options.headers);
|
||||
headers.set('Accept', 'application/json');
|
||||
if (options.method && !['GET', 'HEAD'].includes(options.method.toUpperCase())) {
|
||||
const token = document.cookie.split('; ').find(value => value.startsWith('XSRF-TOKEN='))?.slice(11);
|
||||
const token = typeof document === 'undefined' ? undefined : document.cookie.split('; ').find(value => value.startsWith('XSRF-TOKEN='))?.slice(11);
|
||||
if (token) headers.set('X-XSRF-TOKEN', decodeURIComponent(token));
|
||||
}
|
||||
const response = await fetch(url, {
|
||||
|
||||
@@ -144,6 +144,21 @@ await test('fetch accepts a real server confirmation', async (t) => {
|
||||
assert.equal(response.data.reference, 'IR-SERVER-001');
|
||||
});
|
||||
|
||||
await test('browser writes preserve the CSRF cookie header', async (t) => {
|
||||
const previous = Object.getOwnPropertyDescriptor(globalThis, 'document');
|
||||
Object.defineProperty(globalThis, 'document', { configurable: true, value: { cookie: 'other=x; XSRF-TOKEN=qa%2Ftoken' } });
|
||||
try {
|
||||
t.mock.method(globalThis, 'fetch', async (_url, options) => {
|
||||
assert.equal(options.headers.get('X-XSRF-TOKEN'), 'qa/token');
|
||||
return new Response('{"success":true}', { status: 201 });
|
||||
});
|
||||
await portalRequest('/api/v1/interest-requests', { method: 'POST' });
|
||||
} finally {
|
||||
if (previous) Object.defineProperty(globalThis, 'document', previous);
|
||||
else delete globalThis.document;
|
||||
}
|
||||
});
|
||||
|
||||
for (const status of [422, 429, 500]) {
|
||||
await test(`HTTP ${status} never becomes a successful confirmation`, async (t) => {
|
||||
t.mock.method(
|
||||
|
||||
@@ -2,6 +2,7 @@ import assert from 'node:assert/strict';
|
||||
import test from 'node:test';
|
||||
import {
|
||||
portalNavigation,
|
||||
legacyPortalNavigation,
|
||||
currentNavigationGroup,
|
||||
currentNavigationItem,
|
||||
} from '../../resources/js/lib/portal-navigation.ts';
|
||||
@@ -15,7 +16,7 @@ void test('public and authenticated navigation share groups without revealing ma
|
||||
assert.deepEqual(publicGroups.slice(0, 3), investor.slice(0, 3));
|
||||
assert.deepEqual(
|
||||
publicGroups.map((g) => g.id),
|
||||
['explore', 'prepare', 'support', 'partnerships', 'account'],
|
||||
['discovery', 'realization', 'support', 'account'],
|
||||
);
|
||||
const hrefs = JSON.stringify(investor);
|
||||
assert.equal(hrefs.includes('/management/'), false);
|
||||
@@ -32,7 +33,7 @@ void test('management and optional modules follow permissions and feature flags'
|
||||
education: true,
|
||||
ai: true,
|
||||
});
|
||||
assert.equal(groups.at(-1).id, 'management');
|
||||
assert.ok(groups.some((group) => group.id === 'management'));
|
||||
assert.equal(JSON.stringify(groups).includes('/investidor/negocios'), true);
|
||||
assert.equal(JSON.stringify(groups).includes('/management/ai'), true);
|
||||
assert.equal(
|
||||
@@ -48,7 +49,9 @@ void test('management and optional modules follow permissions and feature flags'
|
||||
});
|
||||
|
||||
void test('detail URLs and filtered catalogue pages retain the current group', () => {
|
||||
const groups = portalNavigation({ authenticated: true, manager: true });
|
||||
// Preserve the retained catalogue's detail/filter matching independently
|
||||
// of the reconciled shell's new grouping names.
|
||||
const groups = legacyPortalNavigation({ authenticated: true, manager: true });
|
||||
for (const url of [
|
||||
'/carteira/project/fixture',
|
||||
'/zonas?category=zee',
|
||||
@@ -81,3 +84,11 @@ void test('detail URLs and filtered catalogue pages retain the current group', (
|
||||
'zee',
|
||||
);
|
||||
});
|
||||
|
||||
void test('reconciled navigation selects discovery, realization and private support correctly', () => {
|
||||
const groups = portalNavigation({ authenticated: false, manager: false });
|
||||
assert.equal(currentNavigationGroup(groups, '/oportunidades/fixture'), 'discovery');
|
||||
assert.equal(currentNavigationGroup(groups, '/simulador-fiscal'), 'realization');
|
||||
assert.equal(currentNavigationGroup(groups, '/balcao-virtual/dossiers/fixture'), 'support');
|
||||
assert.equal(currentNavigationGroup(groups, '/management/crm/leads'), null);
|
||||
});
|
||||
|
||||
@@ -114,15 +114,19 @@ void test('business plan values in the dossier equal the existing simulator fore
|
||||
const finance = report.sections.find((section) => section.id === 'finance');
|
||||
const row = (field) =>
|
||||
finance.rows.find((item) => item.field === field).value;
|
||||
const numeric = (value) => {
|
||||
assert.match(value, /MZN$/);
|
||||
return value.replace(/\s|MZN/g, '').replace(',', '.');
|
||||
};
|
||||
assert.equal(
|
||||
row('Facturação no horizonte'),
|
||||
`${expected.totalRevenue} MZN`,
|
||||
numeric(row('Facturação no horizonte')),
|
||||
expected.totalRevenue,
|
||||
);
|
||||
assert.equal(
|
||||
row('Resultado antes de impostos'),
|
||||
`${expected.totalProfitBeforeTax} MZN`,
|
||||
numeric(row('Resultado antes de impostos')),
|
||||
expected.totalProfitBeforeTax,
|
||||
);
|
||||
assert.equal(row('Caixa final projectada'), `${expected.endingCash} MZN`);
|
||||
assert.equal(numeric(row('Caixa final projectada')), expected.endingCash);
|
||||
assert.equal(row('Reconciliação do financiamento'), expected.fundingStatus);
|
||||
});
|
||||
|
||||
|
||||
@@ -26,8 +26,8 @@ void test('portal home hero exposes a direct public simulator link', () => {
|
||||
void test('completed simulator result keeps public interest submission independent', () => {
|
||||
assert.match(simulator, /href="\/manifestar-interesse"/);
|
||||
assert.match(
|
||||
simulator,
|
||||
/Manifestar interesse sem partilhar\s+esta simulação/,
|
||||
simulator.replace(/\s+/g, ' '),
|
||||
/Manifestar interesse sem partilhar esta simulação/,
|
||||
);
|
||||
assert.match(simulator, /sem\s+partilhar os dados desta simulação/);
|
||||
assert.match(simulator.replace(/\s+/g, ' '), /sem partilhar os dados desta simulação/);
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user