All checks were successful
dev - build & deploy naar test / build-and-deploy (push) Successful in 23s
98 lines
6.1 KiB
JavaScript
98 lines
6.1 KiB
JavaScript
import test from 'node:test';
|
|
import assert from 'node:assert/strict';
|
|
import {readFile} from 'node:fs/promises';
|
|
|
|
const ids=['birthday','numberline','sentence'];
|
|
const learningIds=['fractions','clock','placevalue','money','wordtypes','schedule','mood','poll'];
|
|
|
|
test('nieuwe widgets zijn geladen vóór het widgetregister', async()=>{
|
|
const html=await readFile('public/index.html','utf8');
|
|
const board=html.indexOf('js/board.js');
|
|
for(const id of ids){
|
|
const pos=html.indexOf(`js/widgets/${id}.js`);
|
|
assert.ok(pos>0 && pos<board, `${id} moet vóór board.js laden`);
|
|
}
|
|
});
|
|
|
|
test('nieuwe widgets zijn geregistreerd en bewaren state', async()=>{
|
|
const registry=await readFile('public/js/board.js','utf8');
|
|
for(const id of ids){
|
|
assert.match(registry,new RegExp(`id:"${id}"`));
|
|
const source=await readFile(`public/js/widgets/${id}.js`,'utf8');
|
|
assert.match(source,/getState/);
|
|
assert.doesNotMatch(source,/innerHTML\s*=.*(?:name|word\.value)/);
|
|
}
|
|
});
|
|
|
|
test('nieuwe widgetnamen en beschrijvingen zijn tweetalig', async()=>{
|
|
const core=await readFile('public/js/core.js','utf8');
|
|
for(const id of ids){
|
|
assert.equal((core.match(new RegExp(`wg_${id}:`,'g'))||[]).length,2);
|
|
assert.equal((core.match(new RegExp(`wg_${id}_d:`,'g'))||[]).length,2);
|
|
}
|
|
});
|
|
|
|
|
|
test('educatieve widgetmodule laadt en registreert alle acht widgets', async()=>{
|
|
const html=await readFile('public/index.html','utf8');
|
|
assert.ok(html.indexOf('js/widgets/learning.js')<html.indexOf('js/board.js'));
|
|
const [board,source]=await Promise.all([readFile('public/js/board.js','utf8'),readFile('public/js/widgets/learning.js','utf8')]);
|
|
for(const id of learningIds){
|
|
assert.match(board,new RegExp('id:"'+id+'"'));
|
|
const mount='mount'+id[0].toUpperCase()+id.slice(1);
|
|
assert.match(source,new RegExp('function '+mount+'\\('));
|
|
}
|
|
assert.equal((source.match(/getState:/g)||[]).length,learningIds.length);
|
|
});
|
|
|
|
test('nieuwe widgets zijn tweetalig beschreven', async()=>{
|
|
const core=await readFile('public/js/core.js','utf8');
|
|
for(const id of learningIds){
|
|
assert.equal((core.match(new RegExp('wg_'+id+':','g'))||[]).length,2,id);
|
|
assert.equal((core.match(new RegExp('wg_'+id+'_d:','g'))||[]).length,2,id);
|
|
}
|
|
});
|
|
|
|
test('widgetbibliotheek bevat zoeken favorieten sjablonen en borddata-acties', async()=>{
|
|
const [html,board]=await Promise.all([readFile('public/index.html','utf8'),readFile('public/js/board.js','utf8')]);
|
|
for(const id of ['gallerySearch','galleryFavOnly','galleryTemplates','boardUndo','boardRedo','boardExport','boardImport'])assert.match(html,new RegExp('id="'+id+'"'));
|
|
for(const feature of ['teachWidgetFavorites','structuredClone','application/json','widgetDuplicate','widgetLock','widgetPreview'])assert.ok(board.includes(feature),feature);
|
|
});
|
|
|
|
|
|
test('oefenklok biedt drie niveaus leerwijzen en meerdere spellen', async()=>{
|
|
const [source,core]=await Promise.all([readFile('public/js/widgets/learning.js','utf8'),readFile('public/js/core.js','utf8')]);
|
|
for(const value of ["'analogue'","'digital'","'words'","'both'","'set'","'read'","'choose'","amode:'blocks'","clock-type-answer","clock-task-digital","clock-task-words"])assert.ok(source.includes(value),value);
|
|
assert.match(source,/S\.level===1\?\[0,30\]:S\.level===2\?Array\.from\(\{length:12\}/);
|
|
for(const key of ['clockLevel','clockLearningStyle','clockGame','clockScore','clockLevel1Hint','clockLevel2Hint','clockLevel3Hint','clockTypeHint'])assert.equal((core.match(new RegExp(key+':','g'))||[]).length,2,key);
|
|
});
|
|
|
|
|
|
test('analoge oefenklok is bedienbaar en houdt opdrachtacties buiten instellingen', async()=>{
|
|
const [source,css,core]=await Promise.all([readFile('public/js/widgets/learning.js','utf8'),readFile('public/css/teach.css','utf8'),readFile('public/js/core.js','utf8')]);
|
|
for(const feature of ['onpointerdown','onpointermove','setPointerCapture','releasePointerCapture','getBoundingClientRect','clock-time-blocks','dotGrid'])assert.ok(source.includes(feature),feature);
|
|
assert.match(css,/clock\.interactive[^}]*touch-action:none/);
|
|
assert.match(source,/learningShell\(root,\[field\(T\('clockLearningStyle'\),style\),field\(T\('clockGame'\),game\),linkSetting\],stage\)/);
|
|
const clockSource=source.slice(source.indexOf('function mountClock'),source.indexOf('function mountPlacevalue'));
|
|
assert.doesNotMatch(clockSource,/learningShell\(root,\[[^\]]*(?:numberlineCheck|numberlineNew|clockHour|clockMinute)/);
|
|
for(const feature of ['answerDigits','clock-answer-slots','clock-block-tray','dragClone','droptarget',"'0123456789'.split('')",'clock-keypad',"S.amode==='blocks'?'🧱':'⌨️'"])assert.ok(clockSource.includes(feature),feature);
|
|
assert.match(clockSource,/String\(hour\)\.padStart\(2,'0'\)\+String\(minute\)\.padStart\(2,'0'\)/);
|
|
assert.equal((core.match(/clockIncomplete:/g)||[]).length,2);
|
|
assert.ok(clockSource.includes("'clock-tick hour'"), 'uurposities krijgen een eigen korte markering');
|
|
assert.match(css,/clock-tick\.hour[^}]*width:4px[^}]*height:5%[^}]*background:var\(--blue\)/);
|
|
assert.match(css,/translateY\(calc\(var\(--clock-size\)\*-.34\)\)/);
|
|
assert.doesNotMatch(css,/clock-score\{margin-left:auto\{/);
|
|
assert.ok(clockSource.includes("linkHands:true"));
|
|
assert.ok(clockSource.includes("linkHands.type='checkbox'"));
|
|
assert.ok(clockSource.includes("linkSetting.hidden=game.value!=='set'"));
|
|
assert.ok(clockSource.includes('for(let hour=1;hour<=12;hour++)'), 'gekoppelde urenwijzer rekent de volledige tijd uit');
|
|
assert.ok(clockSource.includes("game.onchange=()=>{syncSettings();newTask()}"));
|
|
assert.doesNotMatch(clockSource,/clockStartTask|clockWelcomeHint/);
|
|
assert.equal((core.match(/clockLinkHands:/g)||[]).length,2);
|
|
assert.ok(clockSource.includes('Math.floor(Math.random()*24)'), 'niveau 3 gebruikt de volledige dag');
|
|
assert.ok(clockSource.includes("hourHand.onpointerdown=e=>start(e,'hour')"));
|
|
assert.ok(clockSource.includes("minuteHand.onpointerdown=e=>start(e,'minute')"));
|
|
for(const key of ['clockMorning','clockAfternoon','clockEvening','clockNight'])assert.equal((core.match(new RegExp(key+':','g'))||[]).length,2,key);
|
|
assert.match(css,/clock-top\{[^}]*position:sticky[^}]*flex-wrap:wrap/);
|
|
assert.match(css,/clock-app\{[^}]*justify-content:flex-start/);
|
|
});
|