import assert from 'node:assert/strict'; import test from 'node:test'; import { catalogueDetailHref, catalogueReturnHref, } from '../../resources/js/lib/catalogue-context.ts'; import { portalNavigation, legacyPortalNavigation, currentNavigationGroup, currentNavigationItem, canShowLegacyManagement, } from '../../resources/js/lib/portal-navigation.ts'; void test('public and authenticated navigation share groups without revealing management', () => { const publicGroups = portalNavigation({ authenticated: false, manager: false, }); const investor = portalNavigation({ authenticated: true, manager: false }); assert.deepEqual(publicGroups.slice(0, 3), investor.slice(0, 3)); assert.deepEqual( publicGroups.map((g) => g.id), ['discovery', 'realization', 'support', 'work', 'account'], ); const hrefs = JSON.stringify(investor); assert.equal(hrefs.includes('/management/'), false); assert.equal(JSON.stringify(publicGroups).includes('/login'), true); assert.equal(hrefs.includes('/investidor/profile'), true); assert.equal(hrefs.includes('/balcao-virtual'), true); }); void test('management and optional modules follow permissions and feature flags', () => { const groups = portalNavigation({ authenticated: true, manager: true, businesses: true, education: true, ai: true, }); assert.ok(groups.some((group) => group.id === 'work')); assert.equal(JSON.stringify(groups).includes('/investidor/negocios'), true); assert.equal(JSON.stringify(groups).includes('/management/ai'), true); assert.equal( JSON.stringify( portalNavigation({ authenticated: false, manager: false, education: false, }), ).includes('/educacao'), false, ); }); void test('detail URLs and filtered catalogue pages retain the current group', () => { // 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', '/zonas/fixture', '/oportunidades/fixture', ]) assert.equal(currentNavigationGroup(groups, url), 'explore'); assert.equal( currentNavigationGroup( groups, '/balcao-virtual/dossiers/fixture?phase=market', ), 'support', ); assert.equal( currentNavigationGroup(groups, '/investidor/profile'), 'account', ); assert.equal( currentNavigationGroup(groups, '/management/crm/leads/fixture'), 'management', ); assert.equal(currentNavigationGroup(groups, '/unknown'), null); assert.equal( currentNavigationItem(groups, '/carteira?q=QA&kind=project'), 'projects', ); assert.equal( currentNavigationItem(groups, '/zonas?category=zee&q=QA'), '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'), 'discovery', ); assert.equal( currentNavigationGroup(groups, '/balcao-virtual/dossiers/fixture'), 'support', ); assert.equal(currentNavigationGroup(groups, '/management/crm/leads'), null); }); void test('discovery keeps four entry points and catalogue destinations without duplicates', () => { const groups = portalNavigation({ authenticated: false, manager: false, businesses: true, education: true, }); const links = []; const collect = (items) => items.forEach((item) => { if (item.href) links.push(item.href); if (item.children) collect(item.children); }); collect(groups); assert.equal(new Set(links).size, links.length); for (const href of [ '/investimentos/iniciar', '/oportunidades', '/sectores', '/oportunidades?view=map', '/carteira', '/zonas', '/negocios', '/educacao', '/documentos', '/legislacao', ]) assert.ok(links.includes(href), href); }); void test('catalogue detail and return preserve the search inside the local catalogue', () => { const query = 'q=turismo+em+Inhambane&kind=cluster&province_id=fixture'; const href = catalogueDetailHref('/carteira/fixture', query); assert.equal(catalogueReturnHref('/carteira', href), '/carteira?' + query); assert.equal( catalogueReturnHref( '/zonas', '/zonas/fixture?catalogue_query=https%3A%2F%2Foutside.invalid', ), '/zonas?https%3A%2F%2Foutside.invalid=', ); }); const destinations=(items)=>items.flatMap(item=>[...(item.href?[item.href]:[]),...destinations(item.children??[])]); void test('both menu consumers respect the existing scoped server decision rather than generic manager status',()=>{ assert.equal(canShowLegacyManagement({user:{id:1},canManagePortal:true,legacyManagementAccess:false}),false); assert.equal(canShowLegacyManagement({user:{id:1},canManagePortal:true,legacyManagementAccess:true}),true); assert.equal(canShowLegacyManagement({user:null,canManagePortal:true,legacyManagementAccess:true}),false); assert.equal(canShowLegacyManagement({user:{id:1},canManagePortal:true}),true); }); void test('work entry is discoverable without exposing private capabilities to an anonymous visitor',()=>{ const groups=portalNavigation({authenticated:false,manager:true,contentManagementHref:'/gestao-conteudos',contentManagementAccess:{opportunities:{index:'/management/opportunities',create:'/management/opportunities/create'}},scopedAdministration:[{label:'Private QA administration',href:'/management/secret'}]}); assert.deepEqual(destinations(groups.find(g=>g.id==='work').children),['/acesso-gestao']); assert.equal(JSON.stringify(groups).includes('/management/'),false); assert.equal(JSON.stringify(groups).includes('/gestao-conteudos'),false); }); void test('work area exposes existing content capability even when the old dashboard flag has no menu object',()=>{ const groups=portalNavigation({authenticated:true,manager:true,opportunityManagement:null,contentManagementHref:'/gestao-conteudos',contentManagementAccess:{opportunities:{index:'/management/opportunities',create:'/management/opportunities/create'}}}); const work=groups.find(g=>g.id==='work'); assert.equal(work.label,'Área de trabalho'); assert.ok(work.children.some(i=>i.label==='Preparar análise e ideia'&&i.href==='/management/opportunities/create?analysis=proactive')); assert.ok(work.children.some(i=>i.href==='/gestao-conteudos')); assert.ok(work.children.some(i=>i.href==='/management/opportunities')); }); void test('every previously authorised management/profile destination survives the regrouping exactly once',()=>{ const access={authenticated:true,manager:true,businesses:true,education:true,ai:true,contentManagementHref:'/gestao-conteudos',profileAccess:{contexts:[],mine:'/minhas-oportunidades',create:'/minhas-oportunidades/create',request:'/perfil/promotor',review:null,audit:'/perfis/auditoria',administration:'/perfis/gestao'},scopedAdministration:[{label:'Referências económicas',href:'/management/economic-references/lot-01'}]}; const old=destinations(legacyPortalNavigation(access).filter(g=>['management','profile-opportunities'].includes(g.id))); const groups=portalNavigation(access);const after=destinations(groups); for(const href of old)assert.equal(after.filter(x=>x===href).length,1,href); assert.equal(after.length,new Set(after).size); assert.ok(destinations(groups.find(g=>g.id==='work').children).includes('/management/economic-references/lot-01')); assert.equal(after.filter(href=>href==='/management/profile-install').length,1,'profile installation already present in the old authorised sidebar must survive'); }); void test('ordinary authenticated account has an explanation entry and does not acquire creation or management links',()=>{ const groups=portalNavigation({authenticated:true,manager:false}); assert.deepEqual(destinations(groups.find(g=>g.id==='work').children),['/acesso-gestao']); assert.equal(JSON.stringify(groups).includes('analysis=proactive'),false); assert.equal(JSON.stringify(groups).includes('/management/'),false); }); void test('direct analysis and ordinary creation preserve distinct selection state in the same work group',()=>{ const access={authenticated:true,manager:false,profileAccess:{contexts:[],mine:'/minhas-oportunidades',create:'/minhas-oportunidades/create',request:'/perfil/promotor',review:null,administration:null}}; const groups=portalNavigation(access); assert.equal(currentNavigationGroup(groups,'/minhas-oportunidades/create?analysis=proactive'),'work'); assert.equal(currentNavigationItem(groups,'/minhas-oportunidades/create?analysis=proactive'),'prepare-analysis'); assert.equal(currentNavigationItem(groups,'/minhas-oportunidades/create'),'new-my-opportunity'); });