// Draait de echte Alpine-component uit index.html en toetst de logica van // het invulmenu. Wordt aangeroepen door tests/test_ui_logica.py; los draaien // kan met: node tests/js/menu.test.js const fs = require('fs'); const html = fs.readFileSync(__dirname + '/../../server-up/templates/index.html', 'utf8'); // Alleen de component-functie uitsnijden en uitvoeren. const start = html.indexOf('function app() {'); const eind = html.indexOf('', start); const bron = html.slice(start, eind); global.localStorage = { getItem: () => null, setItem: () => {} }; global.location = { hash: '', search: '' }; global.window = { matchMedia: () => ({matches:false, addEventListener(){}}), addEventListener(){}, innerWidth: 1200 }; global.document = { documentElement: {classList:{add(){},remove(){}}}, addEventListener(){}, querySelector: () => null }; global.navigator = { clipboard: { writeText: async () => {} }, language: 'nl' }; global.crypto = require('crypto').webcrypto; eval(bron); const c = app(); c.t = (k, v) => k; // vertaling niet nodig voor de logica c.bpFieldVisible = () => true; c.rpc = async () => ({ok: true, preview_files: {}, env_preview: ''}); c.toast = () => {}; function veld(naam, stap, extra = {}) { return Object.assign({name: naam, title: naam, step: stap, type: 'str', group: 'Algemeen', required: false, advanced: false}, extra); } let fouten = 0; const check = (naam, waar) => { if (!waar) { fouten++; console.log(' ✖ ' + naam); } else console.log(' ✓ ' + naam); }; // ── Eenvoudige app: alleen basisvelden ────────────────────────────────────── c.install = {format:'boilerplate', loading:false, fields:[ veld('service_name','basis'), veld('port','basis'), veld('data_dir','basis'), ], values:{}, step:0}; c.onePage = false; c.showAdvanced = false; let s = c.wizardSteps().map(x => x.id); check('eenvoudige app: basis, verbinden, controleren', JSON.stringify(s) === '["basis","verbinden","controleren"]'); // ── App met geheimen ──────────────────────────────────────────────────────── c.install.fields.push(veld('db_password','geheimen',{required:true, secret:true})); s = c.wizardSteps().map(x => x.id); check('geheimenstap verschijnt', s.includes('geheimen')); // ── Lege stap wordt overgeslagen ──────────────────────────────────────────── check('geen lege instellingenstap', !s.includes('instellingen')); // ── Geavanceerde velden ───────────────────────────────────────────────────── c.install.fields.push(veld('retention','instellingen',{advanced:true})); check('geavanceerd veld verborgen', c.stepFields('instellingen').length === 0); check('stap zonder zichtbare velden verdwijnt', !c.wizardSteps().map(x=>x.id).includes('instellingen')); c.showAdvanced = true; check('geavanceerd veld zichtbaar na aanzetten', c.stepFields('instellingen').length === 1); check('stap komt terug', c.wizardSteps().map(x=>x.id).includes('instellingen')); check('teller klopt', c.advancedCount() === 1); // ── Verplicht veld blokkeert Volgende ─────────────────────────────────────── c.install.step = c.wizardSteps().findIndex(x => x.id === 'geheimen'); check('leeg verplicht veld wordt gemeld', c.stepMissing().length === 1); c.install.values.db_password = 'ietsGeheims'; check('ingevuld: niets meer te melden', c.stepMissing().length === 0); // ── Groepsschakelaar uit: veld telt niet mee ──────────────────────────────── c.install.fields.push(veld('opt_pass','geheimen', {required:true, secret:true, group:'Extra', group_toggle:'gebruik_extra'})); c.install.values.gebruik_extra = false; check('uitgeschakelde groep blokkeert niet', c.stepMissing().length === 0); c.install.values.gebruik_extra = true; check('ingeschakelde groep blokkeert wel', c.stepMissing().length === 1); // ── Navigatie ─────────────────────────────────────────────────────────────── c.install.values.opt_pass = 'x'; c.install.step = 0; check('niet op de laatste stap', !c.opLaatsteStap()); c.install.step = c.wizardSteps().length - 1; check('wel op de laatste stap', c.opLaatsteStap()); check('laatste stap is controleren', c.wizardSteps()[c.install.step].id === 'controleren'); // ── Alles op één pagina ───────────────────────────────────────────────────── c.onePage = true; check('wizard uit bij één pagina', !c.wizardActief()); // ── Groepskoppen ──────────────────────────────────────────────────────────── c.onePage = false; c.install.fields = [veld('a','basis'), veld('b','basis')]; check('één groep: geen kop', c.stepGroups('basis')[0].showHeader === false); c.install.fields.push(veld('c','basis',{group:'Tweede'})); check('twee groepen: wel koppen', c.stepGroups('basis').every(g => g.showHeader)); console.log(fouten === 0 ? '\nAlle menucontroles geslaagd' : `\n${fouten} FOUTEN`); process.exit(fouten ? 1 : 0);