209 lines
8.3 KiB
JavaScript
209 lines
8.3 KiB
JavaScript
import test from 'node:test';
|
|
import assert from 'node:assert/strict';
|
|
import fs from 'node:fs';
|
|
import { createRequire } from 'node:module';
|
|
import { compileFunction } from 'node:vm';
|
|
import ts from 'typescript';
|
|
import React from 'react';
|
|
import { renderToStaticMarkup } from 'react-dom/server';
|
|
import * as navigation from '../../resources/js/lib/portal-navigation.ts';
|
|
import { searchTerritoryHref } from '../../resources/js/lib/search-territory.ts';
|
|
const require = createRequire(import.meta.url);
|
|
let state, mobile;
|
|
const primitive =
|
|
(tag) =>
|
|
({ children, asChild, className, ...props }) =>
|
|
asChild
|
|
? React.cloneElement(children, { className })
|
|
: React.createElement(
|
|
tag,
|
|
{
|
|
className,
|
|
...Object.fromEntries(
|
|
Object.entries(props).filter(
|
|
([k]) =>
|
|
k.startsWith('aria-') ||
|
|
k.startsWith('data-'),
|
|
),
|
|
),
|
|
},
|
|
children,
|
|
);
|
|
const source = fs.readFileSync(
|
|
new URL(
|
|
'../../resources/js/components/portal-grouped-menu.tsx',
|
|
import.meta.url,
|
|
),
|
|
'utf8',
|
|
),
|
|
module = { exports: {} };
|
|
const output = ts.transpileModule(source, {
|
|
compilerOptions: {
|
|
module: ts.ModuleKind.CommonJS,
|
|
target: ts.ScriptTarget.ES2022,
|
|
jsx: ts.JsxEmit.ReactJSX,
|
|
},
|
|
}).outputText;
|
|
compileFunction(output, ['require', 'module', 'exports'])(
|
|
(name) =>
|
|
name === '@/components/portal-product-identity'
|
|
? {}
|
|
: name === '@inertiajs/react'
|
|
? {
|
|
usePage: () => state,
|
|
Link: ({ children, href, className, ...props }) =>
|
|
React.createElement(
|
|
'a',
|
|
{
|
|
href,
|
|
className,
|
|
...Object.fromEntries(
|
|
Object.entries(props).filter(
|
|
([k]) =>
|
|
k.startsWith('aria-') ||
|
|
k.startsWith('data-'),
|
|
),
|
|
),
|
|
},
|
|
children,
|
|
),
|
|
router: {},
|
|
}
|
|
: name === 'lucide-react'
|
|
? new Proxy({}, { get: () => () => null })
|
|
: name === '@/hooks/use-mobile'
|
|
? { useIsMobile: () => mobile }
|
|
: name === '@/components/navigation-context'
|
|
? { useNavigationContext: () => ({ view: null }) }
|
|
: name === '@/components/tempo-brand'
|
|
? { useTempoUi: () => ({ t: (x) => x, language: 'pt' }) }
|
|
: name === '@/components/tempo-header-tools'
|
|
? { TempoLanguageSelector: () => null }
|
|
: name === '@/components/ui/dropdown-menu'
|
|
? new Proxy(
|
|
{},
|
|
{
|
|
get: (_, key) =>
|
|
primitive(
|
|
String(key).includes('Trigger')
|
|
? 'button'
|
|
: 'div',
|
|
),
|
|
},
|
|
)
|
|
: name === '@/lib/portal-navigation'
|
|
? navigation
|
|
: name === '@/lib/search-territory'
|
|
? { searchTerritoryHref }
|
|
: name === '@/routes'
|
|
? { logout: () => '/logout' }
|
|
: require(name),
|
|
module,
|
|
module.exports,
|
|
);
|
|
test('actual header has exactly the requested six primary entries on desktop and mobile for public and signed-in users', () => {
|
|
const out = new URL(
|
|
'../../outputs/funding-uniform-menu-20261111/',
|
|
import.meta.url,
|
|
);
|
|
fs.mkdirSync(out, { recursive: true });
|
|
for (const authenticated of [false, true])
|
|
for (mobile of [false, true]) {
|
|
state = {
|
|
url: '/',
|
|
props: {
|
|
auth: {
|
|
user: authenticated
|
|
? {
|
|
name: 'SYNTHETIC QA',
|
|
email: 'qa@example.invalid',
|
|
}
|
|
: null,
|
|
canManagePortal: false,
|
|
},
|
|
procurementEnabled: true,
|
|
fundingEnabled: true,
|
|
},
|
|
};
|
|
const html = renderToStaticMarkup(
|
|
React.createElement(module.exports.PortalGroupedMenu),
|
|
);
|
|
const nav = html.match(
|
|
/<nav[^>]*aria-label="Áreas do portal"[\s\S]*?<\/nav>/,
|
|
)?.[0];
|
|
assert.ok(nav);
|
|
const labels = [
|
|
...nav.matchAll(
|
|
/<(?:a|button)[^>]*class="tempo-nav-trigger"[^>]*>([\s\S]*?)<\/(?:a|button)>/g,
|
|
),
|
|
].map((m) => m[1].replace(/<[^>]*>/g, '').trim());
|
|
assert.deepEqual(labels, [
|
|
'Início',
|
|
'Descoberta',
|
|
'Realização',
|
|
'Suporte',
|
|
'Sobre nós',
|
|
'Mais',
|
|
]);
|
|
for (const href of [
|
|
'/concursos',
|
|
'/fundos',
|
|
'/documentos',
|
|
'/legislacao',
|
|
'/sobre',
|
|
'/contacto',
|
|
'/acesso-gestao',
|
|
])
|
|
assert.ok(html.includes('href="' + href + '"'), href);
|
|
assert.ok(html.includes('step=S08'));
|
|
assert.equal(html.includes('/management/'), false);
|
|
fs.writeFileSync(
|
|
new URL(
|
|
'header-' + authenticated + '-' + mobile + '.html',
|
|
out,
|
|
),
|
|
html,
|
|
);
|
|
}
|
|
fs.writeFileSync(
|
|
new URL('verification.json', out),
|
|
JSON.stringify(
|
|
{
|
|
synthetic: true,
|
|
sharedInstitutionProfile: true,
|
|
suppliedExamples: ['Quorus', 'Moza Banco'],
|
|
sourceRowsPreserved: true,
|
|
primaryEntries: [
|
|
'Início',
|
|
'Descoberta',
|
|
'Realização',
|
|
'Suporte',
|
|
'Sobre nós',
|
|
'Mais',
|
|
],
|
|
actualHeaderRendered: true,
|
|
publicAndSignedIn: true,
|
|
mobileAndDesktopBranches: true,
|
|
visualBrowserReview: false,
|
|
activeDataWrites: 0,
|
|
},
|
|
null,
|
|
2,
|
|
),
|
|
);
|
|
});
|
|
|
|
test('authorised administration is primary and dashboard is a nested expandable group on desktop and mobile', () => {
|
|
for (mobile of [false, true]) {
|
|
state = {url: '/management/editorial', props: {auth: {user: {name: 'QA'}, canManagePortal: false}, dashboardNavigation: [{label: 'Visão geral', href: '/management/editorial'}, {label: 'Legislação', href: '/management/editorial?kind=legislation'}]}};
|
|
const html = renderToStaticMarkup(React.createElement(module.exports.PortalGroupedMenu));
|
|
const nav = html.match(/<nav[^>]*aria-label="Áreas do portal"[\s\S]*?<\/nav>/)?.[0];
|
|
assert.ok(nav);
|
|
const labels = [...nav.matchAll(/<(?:a|button)[^>]*class="tempo-nav-trigger"[^>]*>([\s\S]*?)<\/(?:a|button)>/g)].map(m => m[1].replace(/<[^>]*>/g, '').replace('Grupo actual', '').trim());
|
|
assert.deepEqual(labels, ['Início', 'Descoberta', 'Realização', 'Suporte', 'Administração', 'Sobre nós', 'Mais']);
|
|
assert.equal((nav.match(/href="\/management\/editorial"/g) ?? []).length, 1);
|
|
assert.match(nav, /Dashboard/);
|
|
if (mobile) assert.match(nav, /<summary[^>]*>Dashboard<\/summary>/);
|
|
}
|
|
});
|