44 lines
3.7 KiB
JavaScript
44 lines
3.7 KiB
JavaScript
/* Exercise report rendering and CSV export using the production script. */
|
|
const assert=require('node:assert/strict'),fs=require('node:fs'),vm=require('node:vm');
|
|
const elements=new Map(),requests=[];
|
|
function element(id){if(!elements.has(id))elements.set(id,{innerHTML:'',textContent:'',hidden:false,disabled:false,dataset:{},value:'',insertAdjacentHTML(_,html){this.innerHTML+=html;}});return elements.get(id);}
|
|
const form=element('absenceFilters');form.elements={start_date:element('absenceFrom'),end_date:element('absenceTo'),user_id:element('absenceEmployee')};
|
|
const item={id:1,kind:'vacation',name:'=Private spreadsheet formula',kind_label:'Ferie',starts_at:'2026-10-15T06:00:00Z',ends_at:'2026-10-16T14:00:00Z',norm_configured:true,planned_minutes:900,planned_days:2,actual_minutes:450,registered:true};
|
|
const result={employees:[{id:1,name:'One'}],summary:[{user_id:1,name:'One',norm_configured:true,planned_minutes:900,planned_days:2,actual_minutes:450}],items:[item],total:1,totals:{planned_minutes:900,planned_days:2,actual_minutes:450}};
|
|
result.type_summary=[{kind:'vacation',kind_label:'Ferie',periods:1,norm_configured:true,planned_minutes:900,planned_days:2,actual_minutes:450,employees:result.summary}];
|
|
let download=null;
|
|
const context={window:{},Intl,Date,Number,String,Promise,URLSearchParams,Blob,
|
|
FormData:class{constructor(form){this.values=Object.entries(form.elements).map(([key,input])=>[key,input.value]);}[Symbol.iterator](){return this.values[Symbol.iterator]();}},
|
|
document:{getElementById:element,createElement:()=>({click(){}})},
|
|
fetch:async path=>{requests.push(path);return{ok:true,json:async()=>result};},
|
|
URL:{createObjectURL:blob=>{download=blob;return 'blob:report';},revokeObjectURL(){}},setTimeout:()=>{},
|
|
};
|
|
vm.createContext(context);vm.runInContext(fs.readFileSync('static/js/absence-report.js','utf8'),context);
|
|
(async()=>{
|
|
await new Promise(resolve=>setImmediate(resolve));
|
|
assert.match(element('absenceRows').innerHTML,/Tid registreret/);
|
|
assert.match(element('absenceRows').innerHTML,/scope="rowgroup" colspan="8">Ferie/);
|
|
assert.match(element('absenceSummary').innerHTML,/Ferie/);
|
|
assert.match(element('absenceSummary').innerHTML,/One/);
|
|
assert.equal(new URLSearchParams(requests[0].split('?')[1]).get('group_by'),'type');
|
|
assert.match(element('absenceTotals').innerHTML,/15 t/);
|
|
assert.match(element('absenceTotals').innerHTML,/7,5 t/);
|
|
assert.match(element('absenceRows').innerHTML,/<td>2<\/td>/);
|
|
assert.match(element('absencePage').textContent,/2 arbejdsdage i alt/);
|
|
assert.equal(element('absenceExport').disabled,false);
|
|
await element('absenceExport').onclick();
|
|
const csv=await download.text();
|
|
assert.match(csv,/"Ferie";"'=Private spreadsheet formula"/);
|
|
assert.equal(new URLSearchParams(requests[1].split('?')[1]).get('group_by'),'type');
|
|
assert.match(csv,/"Arbejdsdage"/);
|
|
assert.match(csv,/"2";"15";"7,5";"Tid registreret"/);
|
|
assert.equal(requests.length,2);
|
|
assert.equal(new URLSearchParams(requests[1].split('?')[1]).get('limit'),'500');
|
|
assert.equal(new URLSearchParams(requests[0].split('?')[1]).get('start_date'),new URLSearchParams(requests[1].split('?')[1]).get('start_date'));
|
|
context.fetch=async()=>({ok:false,json:async()=>({detail:'Ingen adgang'})});
|
|
await form.onsubmit({preventDefault(){}});await new Promise(resolve=>setImmediate(resolve));
|
|
assert.equal(element('absenceExport').disabled,true);
|
|
assert.equal(element('absenceRows').innerHTML,'');assert.equal(element('absenceError').textContent,'Ingen adgang');
|
|
console.log('Absence report UI: rendering, separate actual time, CSV quoting, filters and access failures OK');
|
|
})().catch(err=>{console.error(err);process.exitCode=1;});
|