import test from 'node:test'; import assert from 'node:assert/strict'; import {readFile} from 'node:fs/promises'; import {runInNewContext} from 'node:vm'; import {PERMISSIONS} from '../src/permissions.js'; test('curriculumdataset bevat negen leergebieden en alle veertig kerndoelen',async()=>{ const source=await readFile('public/js/curriculum.js','utf8'); const context={}; runInNewContext(source+';globalThis.__curriculum=CURRICULUM_PO_2026',context); const data=JSON.parse(JSON.stringify(context.__curriculum)); assert.equal(data.id,'slo-po-2026'); assert.equal(data.edition,'2026-07'); assert.match(data.tule,/slo\.nl/); assert.match(data.progressions,/slo\.nl/); assert.equal(data.areas.length,9); const goals=data.areas.flatMap(area=>area.goals); assert.deepEqual(goals.map(goal=>goal.id),Array.from({length:40},(_,index)=>index+1)); for(const area of data.areas){ assert.ok(area.title&&area.description&&area.page,area.id); for(const goal of area.goals){ assert.ok(goal.domain&&goal.summary,goal.id); assert.ok(goal.parts.length>=1,goal.id); assert.ok(['partial','support','open'].includes(goal.coverage),goal.id); assert.ok(Array.isArray(goal.widgets),goal.id); } } }); test('iedere kerndoelkoppeling verwijst naar een bestaande widget en de informatieknop linkt diep naar de wiki',async()=>{ const [curriculumSource,board,settings,wiki,css]=await Promise.all([ readFile('public/js/curriculum.js','utf8'), readFile('public/js/board.js','utf8'), readFile('public/js/settings.js','utf8'), readFile('public/js/wiki.js','utf8'), readFile('public/css/teach.css','utf8') ]); const context={}; runInNewContext(curriculumSource+';globalThis.__curriculum=CURRICULUM_PO_2026',context); const data=JSON.parse(JSON.stringify(context.__curriculum)); const registered=new Set([...board.matchAll(/\{\s*id:"([^"]+)"\s*,\s*cat:/g)].map(match=>match[1])); const linked=new Set(data.areas.flatMap(area=>area.goals.flatMap(goal=>goal.widgets))); for(const widget of linked)assert.ok(registered.has(widget),widget+' is gekoppeld maar niet geregistreerd'); for(const widget of ['letters','sentence','madd','fractions','dice','timer','schedule','trees','topography','noise','birthday','avatar']){ assert.ok(linked.has(widget),widget+' mist een inhoudelijke kerndoelkoppeling'); } assert.match(board,/function curriculumGoalsForWidget/); assert.match(board,/link\.href="#wiki-goal-"\+goal\.id/); assert.match(board,/openSettings\("curriculum",\{area:area\.id,goal:goal\.id\}\)/); assert.match(settings,/window\.openSettings = function\(section, payload\)/); assert.match(wiki,/card\.id="wiki-goal-"\+goal\.id/); assert.match(wiki,/target\.scrollIntoView\(\{block:"center"\}\)/); assert.match(css,/\.winfo\[hidden\]\{display:none\}/); assert.match(css,/\.widget-curriculum-modal/); }); test('curriculumwiki en widgetinformatie zijn alleen zichtbaar voor volwassen rollen',async()=>{ assert.deepEqual(PERMISSIONS['curriculum.view'],['super','admin','teacher','parent']); assert.ok(!PERMISSIONS['curriculum.view'].includes('pupil')); const [client,wiki,board,html]=await Promise.all([ readFile('public/js/permissions.js','utf8'), readFile('public/js/wiki.js','utf8'), readFile('public/js/board.js','utf8'), readFile('public/index.html','utf8') ]); assert.match(client,/'curriculum\.view':\s*\['super', 'admin', 'teacher', 'parent'\]/); assert.match(wiki,/visible:\(\)=>!!currentUser&&can\("curriculum\.view"\)/); assert.match(board,/infoBtn\.hidden=!\(currentUser&&can\("curriculum\.view"\)\)/); assert.match(board,/if\(!currentUser\|\|!can\("curriculum\.view"\)\)return/); assert.doesNotMatch(html,/id="btnWiki"/); assert.doesNotMatch(wiki,/wikiButton/); assert.doesNotMatch(wiki,/innerHTML\s*=/); }); test('curriculumwiki is geladen, doorzoekbaar, responsief en tweetalig bediend',async()=>{ const [html,wiki,core,css,version]=await Promise.all([ readFile('public/index.html','utf8'), readFile('public/js/wiki.js','utf8'), readFile('public/js/core.js','utf8'), readFile('public/css/teach.css','utf8'), readFile('VERSION','utf8') ]); assert.ok(html.indexOf('js/settings.js')