teach/test/language-library.test.js
Ramon 6f593e05b2
All checks were successful
dev - build & deploy naar test / build-and-deploy (push) Successful in 1m1s
fix: corrigeer woordplaatjes in taalbibliotheek (v0.4.44-beta)
2026-07-21 22:01:41 +02:00

133 lines
7.1 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import test from 'node:test';
import assert from 'node:assert/strict';
import {readFile} from 'node:fs/promises';
import {runInNewContext} from 'node:vm';
async function languageData(extra=''){
const source=await readFile('public/js/data.js','utf8');
const context={LANG:'nl',T:key=>key};
runInNewContext(source+`; ${extra}
globalThis.__language={
concepts:LANGUAGE_CONCEPTS,
progression:LANGUAGE_NL_PROGRESSION_WORDS,
themesNl:languageThemeList("nl"),
themesEn:languageThemeList("en"),
words:WORDS,
catalogNl:languagePictureCatalog("nl")
};`,context);
return JSON.parse(JSON.stringify(context.__language));
}
test('taalwidgets delen ruim duizend extra Nederlandse woorden over leerjaar en thema',async()=>{
const data=await languageData();
assert.ok(data.concepts.length>=300,'verwacht minimaal 300 vaste woordplaatjes');
assert.ok(data.progression.length>=1000,'verwacht minimaal 1000 aanvullende Nederlandse woorden');
assert.equal(data.themesNl.length,16);
assert.equal(data.themesEn.length,12);
assert.deepEqual(data.themesNl.map(theme=>theme.id),[
'animals','food','nature','travel','home','body','actions','feelings',
'people','play','places','time','arts','science','learning','society'
]);
const all=data.concepts.concat(data.progression);
assert.equal(new Set(all.map(item=>item.id)).size,all.length);
assert.equal(new Set(all.map(item=>item.nl)).size,all.length);
for(const concept of data.concepts){
assert.ok(concept.nl&&concept.en&&concept.pic,concept.id);
assert.ok(data.themesNl.some(theme=>theme.id===concept.theme),concept.theme);
}
for(const word of data.progression){
assert.ok(word.nl&&word.pic,word.id);
assert.ok(word.yearGroup>=1&&word.yearGroup<=8,word.nl);
assert.ok(data.themesNl.some(theme=>theme.id===word.theme),word.theme);
}
for(let year=1;year<=8;year++)
assert.ok(data.progression.filter(word=>word.yearGroup===year).length>=60,'te weinig nieuwe woorden voor groep '+year);
for(const theme of data.themesNl)assert.ok(theme.words.length>=60,theme.id);
for(const theme of data.themesEn)assert.ok(theme.words.length>=18,theme.id);
assert.equal(data.themesNl.reduce((sum,theme)=>sum+theme.words.length,0),all.length);
assert.equal(data.themesEn.reduce((sum,theme)=>sum+theme.words.length,0),data.concepts.length);
});
test('alle aanvullende woorden hebben een gecontroleerd en correct gekoppeld woordplaatje',async()=>{
const data=await languageData();
const builtinByName=new Map(data.catalogNl.images.filter(image=>image.builtin).map(image=>[image.name,image]));
assert.ok(new Set(data.progression.map(word=>word.pic)).size>=400,'verwacht brede beeldvariatie');
for(const word of data.progression){
assert.equal(word.pictureChecked,true,word.nl);
const image=builtinByName.get(word.nl);
assert.ok(image,word.nl);
assert.equal(image.value,word.pic,word.nl);
assert.ok(image.src.startsWith('data:image/svg+xml;charset=utf-8,'),word.nl);
}
const expected={
kattenbak:'🐈📦',kattenvoer:'🐈🍽️',groentekraam:'🥕🏪',landingsbaan:'🛬',
kast:'🗄️',slaapkamerraam:'🪟',bewegingsapparaat:'🦴',bewegingsrichting:'🧭',
digitaal:'💻',kaart:'🃏',landbouwer:'🧑‍🌾',straat:'🛣️',plattegrond:'🗺️',
veehouderij:'🐄',wastafel:'🚰',tekstproductie:'✍️📄',verdrietverwerking:'😢🧠',
bezorgd:'😟',schoolslag:'🏊',toneelspeler:'🎭',spellingspatroon:'🔤',
meetinstrument:'📐',ruimtestation:'🛰️',grondrecht:'⚖️'
};
for(const [word,picture] of Object.entries(expected))
assert.equal(data.progression.find(item=>item.nl===word)?.pic,picture,word);
});
test('alle oude startwoorden blijven staan en krijgen ook een bibliotheekplaatje',async()=>{
const data=await languageData();
const oldNl=['aap','vis','zon','kat','bal','ei','boom','huis','maan','boot','kip','muis','boek','ster','roos','vuur','fiets','taart','jas','bril','klok','peer','kaas','eend','hand','voet','neus','oog','oor','mond'];
const oldEn=['cat','dog','sun','egg','ball','fish','tree','moon','boat','star','book','cake','house','mouse','apple','train','fire','rose','bear','duck','frog','bee','cow','pig','hand','foot','nose','eye','ear','milk'];
assert.deepEqual(data.words.nl.map(([word])=>word),oldNl);
assert.deepEqual(data.words.en.map(([word])=>word),oldEn);
const names=new Set(data.catalogNl.images.map(image=>image.name));
for(const word of oldNl)assert.ok(names.has(word),word);
});
test('vaste en eigen woordplaatjes worden als herbruikbare catalogusitems aangeboden',async()=>{
const data=await languageData('GENERAL_EXTRA.nl=[["test","🧪"]]; THEMES.nl=[{name:"Boerderij",folder:"School",words:[["stal","🏚️"]]}];');
const builtins=data.catalogNl.images.filter(image=>image.builtin);
assert.equal(builtins.length,data.concepts.length+data.progression.length);
assert.equal(data.catalogNl.themes.filter(theme=>theme.languageBuiltin).length,16);
for(const image of builtins){
assert.ok(image.id<0);
assert.ok(image.src.startsWith('data:image/svg+xml;charset=utf-8,'));
assert.ok(image.value&&image.themes.length===1);
assert.equal(image.canManage,false);
}
const testPic=data.catalogNl.images.find(image=>!image.builtin&&image.name==='test');
const stablePic=data.catalogNl.images.find(image=>!image.builtin&&image.name==='stal');
assert.equal(testPic.value,'🧪');
assert.equal(stablePic.value,'🏚️');
assert.equal(stablePic.folder,'Taal/Mijn themas/School/Boerderij');
for(const word of ['familiegeschiedenis','competitiewedstrijd','mediageletterdheid','waterkringloop']){
const image=data.catalogNl.images.find(item=>item.name===word);
assert.ok(image&&image.yearGroup>=7&&image.src.startsWith('data:image/svg+xml'),word);
}
});
test('alle vier taalspellen gebruiken themabronnen en kunnen de bibliotheek openen',async()=>{
const [data,catalog,picker,letters,css,catalogCss]=await Promise.all([
readFile('public/js/data.js','utf8'),
readFile('public/js/image-catalog.js','utf8'),
readFile('public/js/picker.js','utf8'),
readFile('public/js/widgets/letters.js','utf8'),
readFile('public/css/teach.css','utf8'),
readFile('public/css/image-catalog.css','utf8'),
]);
assert.match(data,/card\.startsWith\("b:"\)/);
assert.match(data,/builtinGroup\.label = "📚 "/);
for(const widget of ['letters','flits','hak','ball']){
const source=await readFile(`public/js/widgets/${widget}.js`,'utf8');
assert.match(source,/wordSourceList\(/,widget);
assert.match(source,/fillWordSourceSel\(/,widget);
}
assert.match(catalog,/refreshWordPictureCatalog/);
assert.match(catalog,/languagePictureCatalog\(LANG\)/);
assert.match(catalog,/ic-word-themes/);
assert.match(picker,/data-t="library"/);
assert.match(picker,/uploadImageToCatalog\(f,/);
assert.match(letters,/data-t="library"/);
assert.match(letters,/openImageCatalog\(\(src,image\)/);
assert.match(letters,/uploadImageToCatalog\(f,/);
assert.match(css,/\.ed-tabs\{[^}]*overflow-x:auto/);
assert.match(catalogCss,/\.ic-word-themes\{[^}]*overflow-x:auto/);
assert.match(catalogCss,/@media\(max-width:760px\)/);
});