SPB Git forge

spb/cancerindex

Public
37commits 1branches 0releases
2.9 MBsize
maindefault branch
10 days agolast push
TypeScript 97.2% SQL 1.5% CSS 0.6% JavaScript 0.5%
5.1 KB · 122 lines typescript
Raw Blame History
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