Files
Investidor-V2/tests/frontend/navigation-sidebar-render.test.mjs
T

55 lines
4.0 KiB
JavaScript

import assert from 'node:assert/strict';
import test from 'node:test';
import fs from 'node:fs';
import {createRequire} from 'node:module';
import React from 'react';
import {renderToStaticMarkup} from 'react-dom/server';
import ts from 'typescript';
import {portalNavigation,currentNavigationItem} from '../../resources/js/lib/portal-navigation.ts';
import {searchTerritoryHref} from '../../resources/js/lib/search-territory.ts';
// Shallow SSR of the actual navigation component. Inertia and visual primitives
// are replaced by semantic wrappers; this is not a browser/viewport proof.
const require=createRequire(import.meta.url);
const source=fs.readFileSync(new URL('../../resources/js/components/portal-sidebar-navigation.tsx',import.meta.url),'utf8');
const output=ts.transpileModule(source,{compilerOptions:{module:ts.ModuleKind.CommonJS,target:ts.ScriptTarget.ES2022,jsx:ts.JsxEmit.ReactJSX}}).outputText;
const primitive=(tag)=>({children,asChild,...props})=>asChild?React.cloneElement(children,{}):React.createElement(tag,props,children);
const module={exports:{}};
new Function('require','module','exports',output)((name)=>{
if(name==='@inertiajs/react')return {Link:({href,children,...props})=>React.createElement('a',{href,...props},children)};
if(name==='@/lib/portal-navigation')return {currentNavigationItem};
if(name==='@/lib/search-territory')return {searchTerritoryHref};
if(name==='lucide-react')return {LayoutGrid:()=>null};
if(name==='@/components/ui/sidebar')return {SidebarGroup:primitive('section'),SidebarGroupLabel:primitive('h2'),SidebarMenu:primitive('ul'),SidebarMenuButton:primitive('div'),SidebarMenuItem:primitive('li')};
return require(name);
},module,module.exports);
const Component=module.exports.PortalSidebarNavigation;
const flatten=(rows)=>rows.flatMap(r=>[...(r.href?[r.href]:[]),...flatten(r.children??[])]);
const render=(access,url='/')=>{const groups=portalNavigation(access);return {groups,html:renderToStaticMarkup(React.createElement(Component,{groups,url}))};};
void test('sidebar renders every nested authorised destination instead of a first-child shortcut',()=>{
const {groups,html}=render({authenticated:true,manager:true,businesses:true,education:true,ai:true,contentManagementHref:'/gestao-conteudos',contentManagementAccess:{opportunities:{index:'/management/opportunities',create:'/management/opportunities/create'}},scopedAdministration:[{label:'Referências económicas',href:'/management/economic-references/lot-01'}]});
const hrefs=[...html.matchAll(/<a\b[^>]*href="([^"]+)"/g)].map(m=>m[1].replaceAll('&amp;','&'));
assert.deepEqual([...hrefs].sort(),flatten(groups).sort());
assert.equal(hrefs[0],'/gestao-conteudos');
for(const href of ['/carteira','/zonas','/documentos','/legislacao','/management/opportunities','/management/economic-references/lot-01'])assert.ok(hrefs.includes(href),href);
assert.match(html,/Área de trabalho/);
});
void test('nested current destination is selected without changing its URL or replacing it with a group root',()=>{
const {html}=render({authenticated:true,manager:false},'/zonas?category=zee');
const current=[...html.matchAll(/<a\b([^>]*aria-current="page"[^>]*)>/g)];
assert.equal(current.length,1);
assert.match(current[0][1],/href="\/zonas"/);
});
void test('rendered visitor sidebar explains access without private operation links',()=>{
const {html}=render({authenticated:false,manager:false});
assert.match(html,/href="\/acesso-gestao"/);
assert.doesNotMatch(html,/href="\/management\//);
assert.doesNotMatch(html,/analysis=proactive/);
});
void test('sidebar carries the existing search territory when moving between catalogues',()=>{
const {html}=render({authenticated:false,manager:false},'/oportunidades?province_id=QA-province&district_id=QA-district');
assert.match(html,/href="\/carteira\?province_id=QA-province&amp;district_id=QA-district"/);
assert.match(html,/href="\/zonas\?province_id=QA-province&amp;district_id=QA-district"/);
assert.match(html,/href="\/acesso-gestao"/);
});