Files
SGF/scripts/module-navigation-check.mjs
T
2026-11-02 08:06:45 +02:00

33 lines
2.9 KiB
JavaScript

import assert from 'node:assert/strict';
import React from 'react';
import {renderToStaticMarkup} from 'react-dom/server';
import {createServer} from 'vite';
import {ContextTransition} from '../resources/js/context-transition.js';
const server=await createServer({server:{middlewareMode:true},appType:'custom'});
try {
const {default:Navigation,moduleGroups}=await server.ssrLoadModule('/resources/js/ModuleNavigation.jsx');
const {navigationGroups}=await server.ssrLoadModule('/resources/js/WorkspaceNavigation.jsx');
const groups=navigationGroups(()=>true,7);
assert.deepEqual(moduleGroups(groups,'purchasing').map(g=>g.id),['purchasing','shared_records']);
assert.deepEqual(moduleGroups(groups,'commercial').map(g=>g.id),['services','billing','billing_support']);
assert.equal(moduleGroups(groups,'invalid').length,0);
const html=renderToStaticMarkup(React.createElement(Navigation,{groups,context:{module_id:'workshop',modules:[{id:'workshop',label:'Oficinas'}]},page:'workshop',user:{name:'Synthetic'},navigate(){},changeModule(){},logout(){}}));
assert(html.includes('Módulo activo'));assert(html.includes('Navegação de Oficinas'));assert(html.includes('Opções gerais'));
assert(!html.includes('Todos os documentos'));assert(!html.includes('Obrigações a fornecedores'));
assert(html.includes('aria-current="page"'));assert(!html.includes('consulta@example'));
const t=new ContextTransition();
const form={isConnected:true,reportValidity:()=>true,requestSubmit:()=>{void t.command(async()=>true);}};
t.changed(form);await t.save();assert.equal(t.dirty.size,0);assert.equal(t.saved,1);
const failure={...form,requestSubmit:()=>{void t.command(async()=>{throw Error('save refused');}).catch(()=>{});}};
t.changed(failure);await assert.rejects(()=>t.save(),/contexto foi mantido/);assert(t.dirty.has(failure));
t.discard();assert.equal(t.dirty.size,0);
const invalid={...form,reportValidity:()=>false};t.changed(invalid);await assert.rejects(()=>t.save(),/Corrija/);assert(t.dirty.has(invalid));
t.discard();const editor={isConnected:true};t.changed(editor);await assert.rejects(()=>t.save(),/gravação explícita/);assert(t.dirty.has(editor));
t.discard();t.changed({...form,isConnected:false});t.prune();assert.equal(t.dirty.size,0);
// Editing during an in-flight save cannot be discarded by its late response.
let finish;const concurrent={...form,requestSubmit:()=>{void t.command(()=>new Promise(resolve=>{finish=resolve;}));}};
t.changed(concurrent);const saving=t.save();t.changed(concurrent);finish(true);await assert.rejects(()=>saving,/posteriores/);assert(t.dirty.has(concurrent));
console.log('Module navigation and transitions passed: module separation, active context, save, failed save, invalid form, discard, unsupported editor and edits during save. No browser or database.');
} finally {await server.close();}