All checks were successful
dev - build & deploy naar test / build-and-deploy (push) Successful in 42s
126 lines
6.8 KiB
JavaScript
126 lines
6.8 KiB
JavaScript
import test from 'node:test';
|
||
import assert from 'node:assert/strict';
|
||
import {readFile} from 'node:fs/promises';
|
||
import {runInNewContext} from 'node:vm';
|
||
|
||
async function coloringContext(){
|
||
const [extra,widget]=await Promise.all([
|
||
readFile('public/js/widgets/coloring-scenes-extra.js','utf8'),readFile('public/js/widgets/coloring.js','utf8')
|
||
]),source=extra+'\n'+widget;
|
||
const context={};
|
||
runInNewContext(source+`;
|
||
globalThis.__coloring={
|
||
pages:COLORING_PAGES,
|
||
themes:COLORING_THEME_KEYS,
|
||
pagesFor:coloringPagesFor,
|
||
pencilWidth:coloringPencilWidth,
|
||
safeColor:coloringSafeColor
|
||
}`,context);
|
||
return{source,api:context.__coloring};
|
||
}
|
||
|
||
test('kleurplatenwidget laadt vóór het bord en is als creatieve leerlingwidget geregistreerd',async()=>{
|
||
const [html,board,pupil,cast,core,css]=await Promise.all([
|
||
readFile('public/index.html','utf8'),readFile('public/js/board.js','utf8'),
|
||
readFile('public/js/pupil.js','utf8'),readFile('public/js/cast.js','utf8'),
|
||
readFile('public/js/core.js','utf8'),readFile('public/css/coloring.css','utf8')
|
||
]);
|
||
assert.ok(html.indexOf('js/widgets/coloring-scenes-extra.js')>0);
|
||
assert.ok(html.indexOf('js/widgets/coloring-scenes-extra.js')<html.indexOf('js/widgets/coloring.js'));
|
||
assert.ok(html.indexOf('js/widgets/coloring.js')>0);
|
||
assert.ok(html.indexOf('js/widgets/coloring.js')<html.indexOf('js/board.js'));
|
||
assert.match(html,/css\/coloring\.css\?v=__V__/);
|
||
assert.match(board,/id:"coloring"[^\n]*cat:"creatief"[^\n]*mount:mountColoring/);
|
||
assert.match(pupil,/PUPIL_WIDGET_CATS\s*=\s*\[[^\]]*"creatief"/);
|
||
assert.match(cast,/CAST_WIDGET_CATEGORIES=new Set\(\[[^\]]*"creatief"/);
|
||
assert.match(css,/\.coloring-paper[^}]*aspect-ratio:4\/3/);
|
||
for(const key of ['wg_coloring','wg_coloring_d','catCreative','colorToolPencil','colorToolBucket','colorBucketHint','colorPencilHint']){
|
||
assert.equal((core.match(new RegExp(key+':','g'))||[]).length,2,key);
|
||
}
|
||
});
|
||
|
||
test('elk leerjaar heeft zeven herkenbare kleurplaten met diverse thema’s en drie detailniveaus',async()=>{
|
||
const {api}=await coloringContext();
|
||
const pages=JSON.parse(JSON.stringify(api.pages));
|
||
assert.equal(pages.length,28);
|
||
assert.equal(new Set(pages.map(page=>page.id)).size,pages.length);
|
||
const added=[
|
||
'farmyard','rainbow-weather','construction-site','forest-picnic',
|
||
'dinosaur-valley','spring-nest','fire-station','bee-meadow',
|
||
'coral-reef','mountain-camp','robot-workshop','canal-street',
|
||
'solar-observatory','savanna-web','japanese-garden'
|
||
];
|
||
assert.equal(added.filter(id=>pages.some(page=>page.id===id)).length,15);
|
||
for(let year=1;year<=8;year++){
|
||
const suitable=JSON.parse(JSON.stringify(api.pagesFor(year)));
|
||
assert.equal(suitable.length,7,`groep ${year} heeft zeven kleurplaten`);
|
||
assert.ok(suitable.every(page=>year>=page.years[0]&&year<=page.years[1]));
|
||
assert.equal(new Set(suitable.map(page=>page.theme)).size,5,`groep ${year} heeft alle vijf thema's`);
|
||
}
|
||
for(const page of pages){
|
||
assert.ok(api.themes[page.theme],page.id+' heeft een bekend thema');
|
||
assert.ok(page.title.nl&&page.title.en,page.id+' heeft een tweetalige titel');
|
||
const parts=[...page.svg.matchAll(/data-part="([^"]+)"/g)].map(match=>match[1]);
|
||
const details=(page.svg.match(/class="coloring-detail"/g)||[]).length;
|
||
const openFillablePaths=[...page.svg.matchAll(/<path data-fillable="true" data-part="([^"]+)"[^>]* d="([^"]+)"/g)]
|
||
.filter(match=>!/[zZ]\s*$/.test(match[2])).map(match=>match[1]);
|
||
assert.ok(parts.length>=14,page.id+' heeft voldoende afzonderlijke kleurvakken');
|
||
assert.equal(new Set(parts).size,parts.length,page.id+' heeft unieke kleurvakken');
|
||
assert.deepEqual(openFillablePaths,[],page.id+' heeft alleen gesloten aanklikbare paden');
|
||
assert.ok(details>=4,page.id+' heeft voldoende herkenbaar binnenlijnwerk');
|
||
assert.match(page.svg,new RegExp(`data-scene="${page.id}"`));
|
||
assert.match(page.svg,/data-level="2"/);
|
||
assert.match(page.svg,/data-level="3"/);
|
||
assert.doesNotMatch(page.svg,/<script|on\w+=/i);
|
||
}
|
||
const landmarks={
|
||
farmyard:['barn','cow-body','cow-head','farm-sun'],
|
||
'dinosaur-valley':['volcano','dino-body','dino-head','dino-tail'],
|
||
'robot-workshop':['robot-head','robot-body','robot-arm-a','gear-a'],
|
||
'japanese-garden':['pagoda-base','bridge','cherry-trunk','koi-a']
|
||
};
|
||
for(const [id,names] of Object.entries(landmarks)){
|
||
const page=pages.find(item=>item.id===id);
|
||
names.forEach(name=>assert.ok(page.svg.includes(`data-part="${name}"`),`${id} mist ${name}`));
|
||
}
|
||
assert.equal(api.pagesFor(5,'science').length,2);
|
||
assert.equal(api.pagesFor(3,'science').length,1);
|
||
});
|
||
|
||
test('potlood reageert op echte pendruk en bouwt kleur transparant op',async()=>{
|
||
const {source,api}=await coloringContext();
|
||
assert.ok(api.pencilWidth(7,.9,'pen')>api.pencilWidth(7,.2,'pen'));
|
||
assert.equal(api.pencilWidth(7,0,'mouse'),7);
|
||
assert.equal(api.safeColor('#AABBCC'),'#aabbcc');
|
||
assert.equal(api.safeColor('red'),'#e0554d');
|
||
for(const feature of ['getCoalescedEvents','event.pressure','erase?1:.27','quadraticCurveTo','Math.random()'])assert.ok(source.includes(feature),feature);
|
||
const css=await readFile('public/css/coloring.css','utf8');
|
||
assert.match(css,/mix-blend-mode:multiply/);
|
||
assert.match(css,/\.coloring-detail\{stroke-width:4\.5;pointer-events:none\}/);
|
||
});
|
||
|
||
test('verfemmer vult een SVG-vak in één keer en state bewaart potlood én vlakkleuren',async()=>{
|
||
const {source}=await coloringContext();
|
||
assert.match(source,/event\.target\.closest\("\[data-fillable\]\[data-part\]\"\)/);
|
||
assert.match(source,/part\.setAttribute\("fill",color\)/);
|
||
assert.match(source,/fills\[part\.dataset\.part\]=color/);
|
||
assert.match(source,/canvas\.toDataURL\("image\/png"\)/);
|
||
assert.match(source,/return\{theme,pageId,fills:\{\.\.\.fills\},ink,tool,color,size,completed,yearGroup,level/);
|
||
assert.match(source,/opts\.onProgress/);
|
||
});
|
||
|
||
test('creatief niveau is beschikbaar per klas, leerling en thuiskind',async()=>{
|
||
const [api,admin,progressions,parent,wiki,migration,live]=await Promise.all([
|
||
readFile('src/api.js','utf8'),readFile('public/js/admin.js','utf8'),
|
||
readFile('public/js/learning-progressions.js','utf8'),readFile('public/js/parent.js','utf8'),
|
||
readFile('public/js/wiki.js','utf8'),
|
||
readFile('db/024_creative_pupil_levels.sql','utf8'),readFile('src/live-classroom.js','utf8')
|
||
]);
|
||
assert.match(api,/LEVEL_SUBJECTS = \[[^\]]*'creatief'/);
|
||
assert.match(admin,/KM_SUBJECTS = \[[^\]]*"creatief"/);
|
||
assert.match(progressions,/LEARNING_SUBJECTS=\[[^\]]*"creatief"/);
|
||
assert.match(parent,/\["taal","rekenen","creatief"\]\.forEach/);
|
||
assert.match(wiki,/creatief:"parentLevelCreative"/);
|
||
assert.match(migration,/CHECK \(subject IN \('taal','rekenen','world','creatief'\)\)/);
|
||
assert.match(live,/LEVEL_SUBJECTS = new Set\(\[[^\]]*'creatief'/);
|
||
});
|