pediatric-ai-scribe-v3/test/calculators-data.test.js
2026-05-08 03:28:52 +02:00

149 lines
6.2 KiB
JavaScript

const { test } = require('node:test');
const assert = require('node:assert/strict');
const fs = require('node:fs');
const path = require('node:path');
function loadVitals() {
const raw = fs.readFileSync(path.join(__dirname, '..', 'public', 'data', 'calculators', 'vitals.json'), 'utf8');
return JSON.parse(raw);
}
test('vitals.json exposes all calculator age groups', () => {
const data = loadVitals();
assert.equal(data.version, '1.0');
assert.deepEqual(Object.keys(data.ageGroups), [
'premie',
'0-3mo',
'3-6mo',
'6-12mo',
'1-3yr',
'3-6yr',
'6-12yr',
'>12yr'
]);
});
test('vitals.json preserves key Harriet Lane ranges', () => {
const groups = loadVitals().ageGroups;
assert.equal(groups.premie.hr.awake, '120-170');
assert.equal(groups.premie.spo2, '88-95% (target)');
assert.equal(groups['0-3mo'].sbp, '65-85');
assert.equal(groups['3-6mo'].rr, '30-45');
assert.equal(groups['1-3yr'].weight, '10-15 kg');
assert.equal(groups['6-12yr'].hr.sleeping, '50-85');
assert.equal(groups['>12yr'].dbp, '65-85');
});
test('vitals.json entries have complete renderable fields', () => {
const groups = loadVitals().ageGroups;
Object.entries(groups).forEach(([key, group]) => {
assert.ok(group.label, `${key}.label`);
assert.ok(group.hr && group.hr.awake && group.hr.sleeping, `${key}.hr`);
['rr', 'sbp', 'dbp', 'temp', 'weight', 'spo2'].forEach((field) => {
assert.ok(group[field], `${key}.${field}`);
});
assert.ok(Array.isArray(group.notes) && group.notes.length > 0, `${key}.notes`);
});
});
test('resus-meds.json exposes all PALS medication formulas', () => {
const raw = fs.readFileSync(path.join(__dirname, '..', 'public', 'data', 'calculators', 'resus-meds.json'), 'utf8');
const data = JSON.parse(raw);
assert.equal(data.version, '1.0');
assert.deepEqual(data.medications.map((m) => m.formula), [
'adenosine',
'amiodarone',
'atropine',
'calciumChloride',
'calciumGluconate',
'dextrose',
'epinephrine',
'hydrocortisone',
'insulin',
'lidocaine',
'magnesiumSulfate',
'naloxone',
'sodiumBicarbonate'
]);
});
test('resus dose formulas preserve representative outputs', async () => {
const { calculateResusDose } = await import('../public/js/calculators/resus.js');
assert.equal(calculateResusDose('adenosine', 20).dose, '2 mg (0.1 mg/kg)');
assert.equal(calculateResusDose('epinephrine', 10).dose, '0.1 mg IV/IO (0.01 mg/kg of 0.1 mg/mL = 1 mL) q3-5 min');
assert.equal(calculateResusDose('magnesiumSulfate', 50).dose, '2000 mg (50 mg/kg)');
assert.equal(calculateResusDose('sodiumBicarbonate', 8).extra, 'Dilute to 0.5 mEq/mL (use 4.2% solution) for neonates/small infants.');
});
test('fenton-lms.json preserves key LMS anchors', () => {
const raw = fs.readFileSync(path.join(__dirname, '..', 'public', 'data', 'calculators', 'fenton-lms.json'), 'utf8');
const data = JSON.parse(raw);
assert.equal(data.version, '1.0');
assert.deepEqual(data.weightLms.male['22'], { L: 0.21, M: 496, S: 0.17 });
assert.deepEqual(data.weightLms.male['40'], { L: 0.01, M: 3530, S: 0.12 });
assert.deepEqual(data.weightLms.female['22'], { L: 0.23, M: 474, S: 0.17 });
assert.deepEqual(data.weightLms.female['40'], { L: 0.01, M: 3340, S: 0.12 });
});
test('neonatal Fenton helpers preserve interpolation and classification', async () => {
const neonatal = await import('../public/js/calculators/neonatal.js');
const raw = fs.readFileSync(path.join(__dirname, '..', 'public', 'data', 'calculators', 'fenton-lms.json'), 'utf8');
const data = JSON.parse(raw).weightLms;
assert.deepEqual(neonatal.interpolateLMS(data.male, 30), { L: 0.18, M: 1430, S: 0.14 });
assert.equal(Math.round(neonatal.interpolateLMS(data.female, 30.5).M), 1415);
assert.equal(neonatal.classifyGA(36, 6).label, 'Late Preterm');
assert.equal(neonatal.classifyBirthWeight(900).label, 'Extremely Low Birth Weight (ELBW)');
assert.equal(neonatal.classifyWeight(50).label, 'AGA');
});
test('equipment.json preserves equipment age groups and anchors', () => {
const raw = fs.readFileSync(path.join(__dirname, '..', 'public', 'data', 'calculators', 'equipment.json'), 'utf8');
const data = JSON.parse(raw);
assert.equal(data.version, '1.0');
assert.deepEqual(Object.keys(data.ageGroups), [
'premie',
'newborn',
'6mo',
'1yr',
'2-3yr',
'4-6yr',
'7-10yr',
'11-15yr',
'16yr'
]);
assert.equal(data.ageGroups.newborn.ett, '3.0-3.5');
assert.equal(data.ageGroups['1yr'].lma, '2');
assert.equal(data.ageGroups['4-6yr'].blade, 'Miller 2 / MAC 2');
assert.equal(data.ageGroups['16yr'].foley, '12 Fr');
});
test('equipment.json entries have complete renderable fields', () => {
const raw = fs.readFileSync(path.join(__dirname, '..', 'public', 'data', 'calculators', 'equipment.json'), 'utf8');
const groups = JSON.parse(raw).ageGroups;
Object.entries(groups).forEach(([key, group]) => {
['label', 'bvm', 'nasal', 'oral', 'blade', 'ett', 'lma', 'glidescope', 'iv', 'cvl', 'ngt', 'chest', 'foley'].forEach((field) => {
assert.ok(group[field], `${key}.${field}`);
});
});
});
test('bhutani-zones.json preserves risk-zone curves', () => {
const raw = fs.readFileSync(path.join(__dirname, '..', 'public', 'data', 'calculators', 'bhutani-zones.json'), 'utf8');
const data = JSON.parse(raw);
assert.equal(data.version, '1.0');
assert.deepEqual(Object.keys(data.zones), ['p95', 'p75', 'p40']);
assert.equal(data.zones.p95['24'], 9.6);
assert.equal(data.zones.p75['48'], 12.6);
assert.equal(data.zones.p40['120'], 13.2);
});
test('bilirubin helpers preserve Bhutani interpolation and classification', async () => {
const bilirubin = await import('../public/js/calculators/bilirubin.js');
const raw = fs.readFileSync(path.join(__dirname, '..', 'public', 'data', 'calculators', 'bhutani-zones.json'), 'utf8');
const zones = JSON.parse(raw).zones;
assert.equal(bilirubin.interpolateThreshold(zones.p95, 21), 9.05);
assert.equal(bilirubin.classifyBhutaniRisk(zones, 24, 10).zone, 'High-Risk Zone');
assert.equal(bilirubin.classifyBhutaniRisk(zones, 24, 8).zone, 'High-Intermediate Zone');
assert.equal(bilirubin.classifyBhutaniRisk(zones, 24, 7).zone, 'Low-Intermediate Zone');
assert.equal(bilirubin.classifyBhutaniRisk(zones, 24, 5).zone, 'Low-Risk Zone');
});