spb/cancerindex
Public
TypeScript 97.2%
SQL 1.5%
CSS 0.6%
JavaScript 0.5%
1import { describe, it, expect } from 'vitest';2import { fmtValue, fmtPct, fmtInt, fmtNum, scopeLabel, unitLabel, parseScopeKey, toDate, isoDate, humanize, phaseLabel, truncate, pluralize } from '@/lib/format';34describe('fmtValue', () => {5 it('formats counts as integers with thousands separators', () => {6 expect(fmtValue(1234567, 'count')).toBe('1,234,567');7 expect(fmtValue('42', 'count')).toBe('42');8 expect(fmtValue(3.7, 'count')).toBe('4');9 });10 it('formats rates per 100k with one decimal', () => {11 expect(fmtValue(12.345, 'per_100k')).toBe('12.3');12 expect(fmtValue(0, 'per_100k')).toBe('0');13 });14 it('formats ratios with two decimals and probabilities as percentages', () => {15 expect(fmtValue(0.4567, 'ratio')).toBe('0.46');16 expect(fmtValue(0.4567, 'probability')).toBe('45.7%');17 expect(fmtValue(1, 'probability')).toBe('100%');18 });19 it('signs percentile points', () => {20 expect(fmtValue(3.21, 'percentile_points')).toBe('+3.2');21 expect(fmtValue(-3.21, 'percentile_points')).toBe('-3.2');22 expect(fmtValue(0, 'percentile_points')).toBe('0');23 });24 it('falls back sensibly for unknown units', () => {25 expect(fmtValue(12345.6, null)).toBe('12,346');26 expect(fmtValue(1.2345, 'unknown')).toBe('1.23');27 });28 it('never invents a number for missing values', () => {29 expect(fmtValue(null, 'count')).toBe('—');30 expect(fmtValue(undefined, 'ratio')).toBe('—');31 expect(fmtValue('abc', 'count')).toBe('—');32 expect(fmtValue(Number.NaN, 'per_100k')).toBe('—');33 });34});3536describe('fmtPct / fmtInt / fmtNum', () => {37 it('fmtPct multiplies by 100 and respects digits', () => {38 expect(fmtPct(0.12345)).toBe('12.3%');39 expect(fmtPct(0.12345, 2)).toBe('12.35%');40 expect(fmtPct(null)).toBe('—');41 expect(fmtPct(Number.POSITIVE_INFINITY)).toBe('—');42 });43 it('fmtInt handles strings, empties and non-finite values', () => {44 expect(fmtInt('1000')).toBe('1,000');45 expect(fmtInt('')).toBe('—');46 expect(fmtInt(null)).toBe('—');47 expect(fmtInt('x')).toBe('—');48 });49 it('fmtNum caps at 3 decimals', () => {50 expect(fmtNum(1.23456, 3)).toBe('1.235');51 expect(fmtNum(1.23456, 9)).toBe('1.235');52 expect(fmtNum(1.5, 0)).toBe('2');53 });54});5556describe('scope keys', () => {57 it('parses a scope key into a record', () => {58 expect(parseScopeKey('geo=WORLD|sex=all|age=all|year=latest|level=top')).toEqual({ geo: 'WORLD', sex: 'all', age: 'all', year: 'latest', level: 'top' });59 expect(parseScopeKey('')).toEqual({});60 expect(parseScopeKey('geo=USA|broken')).toEqual({ geo: 'USA' });61 });62 it('labels the default world scope', () => {63 expect(scopeLabel('geo=WORLD|sex=all|age=all|year=latest|level=top')).toBe('World · both sexes · all ages · latest · top-level cancers');64 });65 it('labels a specific scope', () => {66 expect(scopeLabel('geo=USA|sex=female|age=65+|year=2021|level=all')).toBe('USA · Female · ages 65+ · 2021 · all malignant entities');67 expect(scopeLabel('geo=USA|sex=all|age=all|year=2021|level=subtype')).toContain('subtype level');68 });69});7071describe('unitLabel', () => {72 it('maps known units', () => {73 expect(unitLabel('count')).toBe('count');74 expect(unitLabel('per_100k')).toBe('per 100,000');75 expect(unitLabel('ratio')).toBe('ratio');76 expect(unitLabel('probability')).toBe('%');77 expect(unitLabel('percentile_points')).toBe('percentile points');78 });79 it('passes unknown units through and empties for null', () => {80 expect(unitLabel('years')).toBe('years');81 expect(unitLabel(null)).toBe('');82 expect(unitLabel(undefined)).toBe('');83 });84});8586describe('dates (drizzle execute returns timestamp strings)', () => {87 it('parses postgres timestamp strings with a numeric offset', () => {88 const d = toDate('2026-09-08 05:07:09.317-04');89 expect(d).not.toBeNull();90 expect(d!.toISOString()).toBe('2026-09-08T09:07:09.317Z');91 });92 it('parses plain dates as UTC midnight and rejects garbage', () => {93 expect(isoDate('2024-02-29')).toBe('2024-02-29');94 expect(toDate('not a date')).toBeNull();95 expect(toDate('')).toBeNull();96 expect(toDate(null)).toBeNull();97 expect(isoDate(new Date(Number.NaN))).toBe('—');98 });99});100101describe('labels', () => {102 it('humanizes enums', () => {103 expect(humanize('NOT_YET_RECRUITING')).toBe('Not Yet Recruiting');104 expect(humanize('adenocarcinoma_nos')).toBe('Adenocarcinoma NOS');105 expect(humanize(null)).toBe('—');106 });107 it('labels phases', () => {108 expect(phaseLabel('PHASE3')).toBe('Phase 3');109 expect(phaseLabel('EARLY_PHASE1')).toBe('Early Phase 1');110 expect(phaseLabel('NA')).toBe('N/A');111 expect(phaseLabel('SOMETHING_ELSE')).toBe('Something Else');112 });113 it('truncates on word boundaries and pluralizes', () => {114 expect(truncate('The quick brown fox jumps over the lazy dog', 20)).toBe('The quick brown fox…');115 expect(truncate('short', 20)).toBe('short');116 expect(truncate(null, 5)).toBe('');117 expect(pluralize(1, 'study', 'studies')).toBe('study');118 expect(pluralize(2, 'study', 'studies')).toBe('studies');119 expect(pluralize(0, 'gene')).toBe('genes');120 });121});122