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'); }); test('aap-bilirubin-thresholds.json preserves treatment threshold anchors', () => { const raw = fs.readFileSync(path.join(__dirname, '..', 'public', 'data', 'calculators', 'aap-bilirubin-thresholds.json'), 'utf8'); const data = JSON.parse(raw); assert.equal(data.version, '1.0'); assert.deepEqual(Object.keys(data.phototherapy.noRisk), ['35', '36', '37', '38', '39', '40']); assert.deepEqual(Object.keys(data.phototherapy.risk), ['35', '36', '37', '38']); assert.deepEqual(Object.keys(data.exchange.noRisk), ['35', '36', '37', '38']); assert.deepEqual(Object.keys(data.exchange.risk), ['35', '36', '37', '38']); assert.equal(data.phototherapy.noRisk['35']['24'], 10.6); assert.equal(data.phototherapy.noRisk['40']['48'], 17.0); assert.equal(data.phototherapy.risk['38']['72'], 16.6); assert.equal(data.exchange.noRisk['38']['96'], 27.0); assert.equal(data.exchange.risk['35']['24'], 16.1); }); test('bilirubin helpers preserve AAP 2022 GA plateau selection and interpolation', async () => { const bilirubin = await import('../public/js/calculators/bilirubin.js'); const raw = fs.readFileSync(path.join(__dirname, '..', 'public', 'data', 'calculators', 'aap-bilirubin-thresholds.json'), 'utf8'); const data = JSON.parse(raw); assert.equal(bilirubin.interpolateThreshold(data.phototherapy.noRisk['35'], 12.5), 8.6); assert.equal(bilirubin.selectAapBilirubinThresholdTables(data, 41, 'none').phototherapy['48'], 17.0); assert.equal(bilirubin.selectAapBilirubinThresholdTables(data, 39, 'none').phototherapy['48'], 16.6); assert.equal(bilirubin.selectAapBilirubinThresholdTables(data, 41, 'medium').phototherapy['48'], 14.0); assert.equal(bilirubin.selectAapBilirubinThresholdTables(data, 40, 'none').exchange['48'], 24.0); }); test('AAP bilirubin sample calculation below phototherapy threshold', async () => { const bilirubin = await import('../public/js/calculators/bilirubin.js'); const raw = fs.readFileSync(path.join(__dirname, '..', 'public', 'data', 'calculators', 'aap-bilirubin-thresholds.json'), 'utf8'); const data = JSON.parse(raw); const assessment = bilirubin.calculateAapBilirubinAssessment(data, 40, 48, 16.0, 'none'); assert.equal(assessment.phototherapyThreshold, 17.0); assert.equal(assessment.exchangeThreshold, 24.0); assert.equal(assessment.phototherapyMargin, -1.0); assert.equal(assessment.exchangeMargin, -8.0); assert.equal(assessment.abovePhototherapy, false); assert.equal(assessment.aboveExchange, false); assert.equal(assessment.status, 'below'); }); test('AAP bilirubin sample calculation above phototherapy threshold', async () => { const bilirubin = await import('../public/js/calculators/bilirubin.js'); const raw = fs.readFileSync(path.join(__dirname, '..', 'public', 'data', 'calculators', 'aap-bilirubin-thresholds.json'), 'utf8'); const data = JSON.parse(raw); const assessment = bilirubin.calculateAapBilirubinAssessment(data, 39, 48, 17.0, 'none'); assert.equal(assessment.phototherapyThreshold, 16.6); assert.equal(assessment.exchangeThreshold, 24.0); assert.equal(Math.round(assessment.phototherapyMargin * 10) / 10, 0.4); assert.equal(assessment.abovePhototherapy, true); assert.equal(assessment.aboveExchange, false); assert.equal(assessment.status, 'phototherapy'); }); test('AAP bilirubin sample calculation above exchange threshold', async () => { const bilirubin = await import('../public/js/calculators/bilirubin.js'); const raw = fs.readFileSync(path.join(__dirname, '..', 'public', 'data', 'calculators', 'aap-bilirubin-thresholds.json'), 'utf8'); const data = JSON.parse(raw); const assessment = bilirubin.calculateAapBilirubinAssessment(data, 35, 24, 16.2, 'medium'); assert.equal(assessment.phototherapyThreshold, 8.9); assert.equal(assessment.exchangeThreshold, 16.1); assert.equal(Math.round(assessment.phototherapyMargin * 10) / 10, 7.3); assert.equal(Math.round(assessment.exchangeMargin * 10) / 10, 0.1); assert.equal(assessment.abovePhototherapy, true); assert.equal(assessment.aboveExchange, true); assert.equal(assessment.status, 'exchange'); }); test('AAP bilirubin sample calculation interpolates fractional age', async () => { const bilirubin = await import('../public/js/calculators/bilirubin.js'); const raw = fs.readFileSync(path.join(__dirname, '..', 'public', 'data', 'calculators', 'aap-bilirubin-thresholds.json'), 'utf8'); const data = JSON.parse(raw); const assessment = bilirubin.calculateAapBilirubinAssessment(data, 35, 12.5, 8.55, 'none'); assert.equal(assessment.phototherapyThreshold, 8.6); assert.equal(assessment.abovePhototherapy, false); assert.equal(assessment.status, 'below'); }); test('bmi-lms.json exposes complete CDC BMI-for-age tables', () => { const raw = fs.readFileSync(path.join(__dirname, '..', 'public', 'data', 'calculators', 'bmi-lms.json'), 'utf8'); const data = JSON.parse(raw); assert.equal(data.version, '1.0'); ['male', 'female'].forEach((sex) => { const ages = Object.keys(data.lms[sex]).map(Number).sort((a, b) => a - b); assert.equal(ages[0], 24); assert.equal(ages[ages.length - 1], 240); assert.equal(ages.length, 37); ages.forEach((age) => { const row = data.lms[sex][age]; assert.equal(typeof row.L, 'number', `${sex}.${age}.L`); assert.equal(typeof row.M, 'number', `${sex}.${age}.M`); assert.equal(typeof row.S, 'number', `${sex}.${age}.S`); }); }); }); test('BMI sample calculation preserves healthy-weight result', async () => { const bmi = await import('../public/js/calculators/bmi.js'); const raw = fs.readFileSync(path.join(__dirname, '..', 'public', 'data', 'calculators', 'bmi-lms.json'), 'utf8'); const data = JSON.parse(raw).lms; const assessment = bmi.calculateBMIAssessment(data, 'male', 10, 32, 140); assert.equal(assessment.ageMonths, 120); assert.equal(Number(assessment.bmi.toFixed(1)), 16.3); assert.equal(Number(assessment.z.toFixed(2)), -0.17); assert.equal(assessment.percentile, 43.42); assert.equal(assessment.classification.text, 'Healthy Weight'); }); test('BMI sample calculation preserves obesity classification', async () => { const bmi = await import('../public/js/calculators/bmi.js'); const raw = fs.readFileSync(path.join(__dirname, '..', 'public', 'data', 'calculators', 'bmi-lms.json'), 'utf8'); const data = JSON.parse(raw).lms; const assessment = bmi.calculateBMIAssessment(data, 'male', 12, 70, 150); assert.equal(Number(assessment.bmi.toFixed(1)), 31.1); assert.equal(assessment.percentile, 98.97); assert.equal(assessment.classification.text, 'Class 2 Severe Obesity'); assert.equal(Number(assessment.classification.pctOf95.toFixed(0)), 128); assert.equal(Number(assessment.classification.bmi95.toFixed(1)), 24.2); }); test('BMI sample calculation preserves fractional-age interpolation', async () => { const bmi = await import('../public/js/calculators/bmi.js'); const raw = fs.readFileSync(path.join(__dirname, '..', 'public', 'data', 'calculators', 'bmi-lms.json'), 'utf8'); const data = JSON.parse(raw).lms; const lms = bmi.interpolateLMS(data.male, 123); assert.equal(Number(lms.M.toFixed(4)), 16.7806); const assessment = bmi.calculateBMIAssessment(data, 'male', 10.5, 40, 145); assert.equal(assessment.ageMonths, 126); assert.equal(assessment.percentile, 79.26); assert.equal(assessment.classification.text, 'Healthy Weight'); }); test('BMI calculator preserves legacy outputs across sex/age/body-size combinations', async () => { const bmi = await import('../public/js/calculators/bmi.js'); const raw = fs.readFileSync(path.join(__dirname, '..', 'public', 'data', 'calculators', 'bmi-lms.json'), 'utf8'); const data = JSON.parse(raw).lms; const cases = [ { name: 'male healthy 10y', sex: 'male', ageYears: 10, weightKg: 32, heightCm: 140, ageMonths: 120, bmi: 16.3, z: -0.17, percentile: 43.42, classification: 'Healthy Weight', pctOf95: 74, bmi95: 22.2 }, { name: 'female obese 8y', sex: 'female', ageYears: 8, weightKg: 35, heightCm: 130, ageMonths: 96, bmi: 20.7, z: 1.65, percentile: 95.03, classification: 'Obese (Class 1)', pctOf95: 100, bmi95: 20.7 }, { name: 'male class 2 severe 12y', sex: 'male', ageYears: 12, weightKg: 70, heightCm: 150, ageMonths: 144, bmi: 31.1, z: 2.32, percentile: 98.97, classification: 'Class 2 Severe Obesity', pctOf95: 128, bmi95: 24.2 }, { name: 'female underweight 5y', sex: 'female', ageYears: 5, weightKg: 13, heightCm: 110, ageMonths: 60, bmi: 10.7, z: -7.66, percentile: 0, classification: 'Underweight', pctOf95: 59, bmi95: 18.3 }, { name: 'male fractional age 10.5y', sex: 'male', ageYears: 10.5, weightKg: 40, heightCm: 145, ageMonths: 126, bmi: 19.0, z: 0.82, percentile: 79.26, classification: 'Healthy Weight', pctOf95: 84, bmi95: 22.7 }, { name: 'female healthy 15y', sex: 'female', ageYears: 15, weightKg: 52, heightCm: 162, ageMonths: 180, bmi: 19.8, z: -0.04, percentile: 48.44, classification: 'Healthy Weight', pctOf95: 70, bmi95: 28.1 }, { name: 'male overweight 6y', sex: 'male', ageYears: 6, weightKg: 26, heightCm: 120, ageMonths: 72, bmi: 18.1, z: 1.51, percentile: 93.42, classification: 'Overweight', pctOf95: 98, bmi95: 18.4 }, { name: 'female class 3 severe 14y', sex: 'female', ageYears: 14, weightKg: 100, heightCm: 155, ageMonths: 168, bmi: 41.6, z: 2.61, percentile: 99.55, classification: 'Class 3 Severe Obesity', pctOf95: 153, bmi95: 27.3 } ]; cases.forEach((expected) => { const actual = bmi.calculateBMIAssessment(data, expected.sex, expected.ageYears, expected.weightKg, expected.heightCm); assert.equal(actual.ageMonths, expected.ageMonths, expected.name + ' ageMonths'); assert.equal(Number(actual.bmi.toFixed(1)), expected.bmi, expected.name + ' bmi'); assert.equal(Number(actual.z.toFixed(2)), expected.z, expected.name + ' z'); assert.equal(actual.percentile, expected.percentile, expected.name + ' percentile'); assert.equal(actual.classification.text, expected.classification, expected.name + ' classification'); assert.equal(Number(actual.classification.pctOf95.toFixed(0)), expected.pctOf95, expected.name + ' pctOf95'); assert.equal(Number(actual.classification.bmi95.toFixed(1)), expected.bmi95, expected.name + ' bmi95'); }); }); test('growth-lms.json exposes complete WHO/CDC/Fenton datasets', () => { const raw = fs.readFileSync(path.join(__dirname, '..', 'public', 'data', 'calculators', 'growth-lms.json'), 'utf8'); const data = JSON.parse(raw); assert.equal(data.version, '1.0'); assert.deepEqual(Object.keys(data.lms), ['wfaLMS', 'cdcWfaLMS', 'lfaLMS', 'cdcLfaLMS', 'hcfaLMS', 'wflLMS', 'fentonLMS']); Object.entries(data.lms).forEach(([tableName, bySex]) => { ['male', 'female'].forEach((sex) => { const rows = bySex[sex]; assert.ok(rows, `${tableName}.${sex}`); const keys = Object.keys(rows).map(Number).sort((a, b) => a - b); assert.ok(keys.length > 0, `${tableName}.${sex}.rows`); keys.forEach((key) => { assert.equal(typeof rows[key].L, 'number', `${tableName}.${sex}.${key}.L`); assert.equal(typeof rows[key].M, 'number', `${tableName}.${sex}.${key}.M`); assert.equal(typeof rows[key].S, 'number', `${tableName}.${sex}.${key}.S`); }); }); }); }); test('growth calculator preserves legacy outputs across chart combinations', async () => { const growth = await import('../public/js/calculators/growth.js'); const raw = fs.readFileSync(path.join(__dirname, '..', 'public', 'data', 'calculators', 'growth-lms.json'), 'utf8'); const data = JSON.parse(raw).lms; const cases = [ { name: 'who wfa male 6mo 8kg', table: data.wfaLMS.male, x: 6, value: 8, z: 0.07, percentile: 52.79, lms: { L: 0.1256, M: 7.9389, S: 0.10957 } }, { name: 'cdc wfa female 72mo 20kg', table: data.cdcWfaLMS.female, x: 72, value: 20, z: -0.11, percentile: 45.51, lms: { L: -1.326764, M: 20.3364, S: 0.14959 } }, { name: 'who lfa male 12mo 75cm', table: data.lfaLMS.male, x: 12, value: 75, z: -0.31, percentile: 37.79, lms: { L: 1, M: 75.7391, S: 0.03137 } }, { name: 'cdc lfa female 120mo 140cm', table: data.cdcLfaLMS.female, x: 120, value: 140, z: 0.26, percentile: 60.43, lms: { L: 0.284749, M: 138.2112, S: 0.048705 } }, { name: 'who hcfa male 12mo 46cm', table: data.hcfaLMS.male, x: 12, value: 46, z: -0.05, percentile: 48.02, lms: { L: 1, M: 46.0637, S: 0.02789 } }, { name: 'who wfl female 70cm 8kg', table: data.wflLMS.female, x: 70, value: 8, z: -0.22, percentile: 41.17, lms: { L: -0.3833, M: 8.163, S: 0.09068 } }, { name: 'fenton male 30w 1.5kg', table: data.fentonLMS.male, x: 30, value: 1500, z: 0.34, percentile: 63.41, lms: { L: 0.18, M: 1430, S: 0.14 } } ]; cases.forEach((expected) => { const actual = growth.calculateLmsPercentile(expected.table, expected.x, expected.value); assert.equal(Number(actual.z.toFixed(2)), expected.z, expected.name + ' z'); assert.equal(Number(actual.percentile.toFixed(2)), expected.percentile, expected.name + ' percentile'); assert.equal(Number(actual.lms.L.toFixed(6)), expected.lms.L, expected.name + ' L'); assert.equal(Number(actual.lms.M.toFixed(4)), expected.lms.M, expected.name + ' M'); assert.equal(Number(actual.lms.S.toFixed(6)), expected.lms.S, expected.name + ' S'); }); }); test('growth helper exports preserve mid-parental height and result rendering', async () => { const growth = await import('../public/js/calculators/growth.js'); assert.deepEqual(growth.calcMidParentalHeight(160, 180, 'male'), { target: 176.5, low: 168, high: 185 }); assert.deepEqual(growth.calcMidParentalHeight(160, 180, 'female'), { target: 163.5, low: 155, high: 172 }); assert.equal(Number(growth.valueFromLMS(1, 75, 0.03, 0).toFixed(2)), 75); const html = growth.renderGrowthResult('Weight-for-Age', 8, 'kg', 0.07, 52.79); assert.match(html, /52\.79th/); assert.match(html, /Weight-for-Age: 8 kg/); }); test('bp-reference.json exposes complete height LMS and coefficient tables', () => { const raw = fs.readFileSync(path.join(__dirname, '..', 'public', 'data', 'calculators', 'bp-reference.json'), 'utf8'); const data = JSON.parse(raw); assert.equal(data.version, '1.0'); ['female', 'male'].forEach((sex) => { ['L', 'M', 'S'].forEach((field) => { assert.equal(data.heightLms[sex][field].length, 218, `${sex}.${field}`); data.heightLms[sex][field].forEach((value, index) => { assert.equal(typeof value, 'number', `${sex}.${field}.${index}`); }); }); ['sys', 'dia'].forEach((type) => { assert.equal(data.coefficients[sex][type].length, 99, `${sex}.${type}`); data.coefficients[sex][type].forEach((row, index) => { assert.equal(row.length, 13, `${sex}.${type}.${index}`); row.forEach((value, col) => assert.equal(typeof value, 'number', `${sex}.${type}.${index}.${col}`)); }); }); }); }); test('BP calculator preserves legacy outputs across sex/age/height/BP combinations', async () => { const bp = await import('../public/js/calculators/bp.js'); const raw = fs.readFileSync(path.join(__dirname, '..', 'public', 'data', 'calculators', 'bp-reference.json'), 'utf8'); const data = JSON.parse(raw); const cases = [ { name: 'male child normal', age: 5, sex: 'male', heightCm: 110, sys: 95, dia: 55, heightPctile: 61.69, heightZ: 0.3, sysPctile: 56, diaPctile: 56, sys50: 93, sys90: 106, sys95: 109, dia50: 53, dia90: 65, dia95: 69, sysClass: 'normal', diaClass: 'normal', classification: 'normal' }, { name: 'female child stage1 systolic', age: 8, sex: 'female', heightCm: 130, sys: 116, dia: 70, heightPctile: 67.28, heightZ: 0.45, sysPctile: 97, diaPctile: 86, sys50: 97, sys90: 110, sys95: 113, dia50: 59, dia90: 72, dia95: 75, sysClass: 'stage1', diaClass: 'normal', classification: 'stage1' }, { name: 'male child stage1 both', age: 10, sex: 'male', heightCm: 140, sys: 120, dia: 80, heightPctile: 59.5, heightZ: 0.24, sysPctile: 98, diaPctile: 97, sys50: 100, sys90: 112, sys95: 116, dia50: 62, dia90: 75, dia95: 78, sysClass: 'stage1', diaClass: 'stage1', classification: 'stage1' }, { name: 'female child stage2 absolute', age: 11, sex: 'female', heightCm: 145, sys: 142, dia: 92, heightPctile: 57.13, heightZ: 0.18, sysPctile: 99, diaPctile: 99, sys50: 102, sys90: 114, sys95: 118, dia50: 61, dia90: 74, dia95: 77, sysClass: 'stage2', diaClass: 'stage2', classification: 'stage2' }, { name: 'male teen elevated', age: 14, sex: 'male', heightCm: 165, sys: 124, dia: 76, heightPctile: 57.25, heightZ: 0.18, sysPctile: 88, diaPctile: 89, sys50: 111, sys90: 125, sys95: 129, dia50: 63, dia90: 77, dia95: 80, sysClass: 'elevated', diaClass: 'normal', classification: 'elevated' }, { name: 'female teen stage1 diastolic', age: 16, sex: 'female', heightCm: 162, sys: 118, dia: 82, heightPctile: 46.75, heightZ: -0.08, sysPctile: 79, diaPctile: 95, sys50: 109, sys90: 123, sys95: 127, dia50: 66, dia90: 78, dia95: 82, sysClass: 'normal', diaClass: 'stage1', classification: 'stage1' }, { name: 'male teen stage2 systolic', age: 17, sex: 'male', heightCm: 175, sys: 142, dia: 78, heightPctile: 48.69, heightZ: -0.03, sysPctile: 98, diaPctile: 83, sys50: 117, sys90: 131, sys95: 136, dia50: 68, dia90: 81, dia95: 85, sysClass: 'stage2', diaClass: 'normal', classification: 'stage2' } ]; cases.forEach((expected) => { const actual = bp.calculateBPAssessment(data, expected.age, expected.sex, expected.heightCm, expected.sys, expected.dia); assert.equal(Number(actual.height.percentile.toFixed(2)), expected.heightPctile, expected.name + ' height percentile'); assert.equal(Number(actual.height.z.toFixed(2)), expected.heightZ, expected.name + ' height z'); assert.equal(actual.systolic.percentile, expected.sysPctile, expected.name + ' systolic percentile'); assert.equal(actual.diastolic.percentile, expected.diaPctile, expected.name + ' diastolic percentile'); assert.equal(Number(actual.systolic.predicted[49].toFixed(0)), expected.sys50, expected.name + ' sys50'); assert.equal(Number(actual.systolic.predicted[89].toFixed(0)), expected.sys90, expected.name + ' sys90'); assert.equal(Number(actual.systolic.predicted[94].toFixed(0)), expected.sys95, expected.name + ' sys95'); assert.equal(Number(actual.diastolic.predicted[49].toFixed(0)), expected.dia50, expected.name + ' dia50'); assert.equal(Number(actual.diastolic.predicted[89].toFixed(0)), expected.dia90, expected.name + ' dia90'); assert.equal(Number(actual.diastolic.predicted[94].toFixed(0)), expected.dia95, expected.name + ' dia95'); assert.equal(actual.classification.sysClass, expected.sysClass, expected.name + ' sys class'); assert.equal(actual.classification.diaClass, expected.diaClass, expected.name + ' dia class'); assert.equal(actual.classification.classification, expected.classification, expected.name + ' classification'); }); }); test('dosing helpers preserve BSA and weight-based dose outputs', async () => { const dosing = await import('../public/js/calculators/dosing.js'); assert.equal(Number(dosing.calculateBsa(20, 110).toFixed(3)), 0.782); const uncapped = dosing.calculateWeightBasedDose(12, 15, 3, 0, 40); assert.equal(uncapped.singleDose, 180); assert.equal(uncapped.dailyDose, 540); assert.equal(uncapped.volumeMl, 4.5); assert.equal(uncapped.capped, false); const capped = dosing.calculateWeightBasedDose(40, 15, 4, 500, 50); assert.equal(capped.singleDose, 500); assert.equal(capped.dailyDose, 2000); assert.equal(capped.volumeMl, 10); assert.equal(capped.capped, true); }); test('GCS helper preserves severity thresholds', async () => { const gcs = await import('../public/js/calculators/gcs.js'); assert.deepEqual(gcs.calculateGcs(1, 1, 1), { total: 3, severity: 'Severe (Coma)', color: '#ef4444', bg: '#fee2e2' }); assert.equal(gcs.calculateGcs(2, 3, 4).severity, 'Moderate'); assert.equal(gcs.calculateGcs(4, 5, 6).severity, 'Mild'); });