spb/cancerindex
Public
TypeScript 97.2%
SQL 1.5%
CSS 0.6%
JavaScript 0.5%
1import { describe, expect, it } from 'vitest';2import { DRUG_PIPELINE_FORMULA_VERSION, PIPELINE_STAGES, maxPhase, phaseLabel, stageFor } from './drug-pipeline.js';34describe('drug pipeline — highest phase', () => {5 it('ranks registry phases and treats EARLY_PHASE1 as phase 1', () => {6 expect(maxPhase([['PHASE2'], ['PHASE3']])).toBe('PHASE3');7 expect(maxPhase([['PHASE2', 'PHASE3']])).toBe('PHASE3');8 expect(maxPhase([['PHASE1', 'PHASE2']])).toBe('PHASE2');9 expect(maxPhase([['PHASE4'], ['NA']])).toBe('PHASE4');10 expect(maxPhase([['EARLY_PHASE1']])).toBe('EARLY_PHASE1');11 expect(maxPhase([['EARLY_PHASE1'], ['PHASE1']])).toBe('PHASE1');12 expect(maxPhase([['NA'], []])).toBe('NA');13 expect(maxPhase([[], ['UNKNOWN_LABEL']])).toBeNull();14 expect(maxPhase([])).toBeNull();15 });16 it('phaseLabel mirrors maxPhase for SQL-side ranks', () => {17 expect(phaseLabel(4, false)).toBe('PHASE4');18 expect(phaseLabel(3, true)).toBe('PHASE3');19 expect(phaseLabel(2, false)).toBe('PHASE2');20 expect(phaseLabel(1, true)).toBe('PHASE1');21 expect(phaseLabel(1, false)).toBe('EARLY_PHASE1');22 expect(phaseLabel(0, false)).toBe('NA');23 expect(phaseLabel(null, false)).toBeNull();24 });25});2627describe('drug pipeline — stage rule', () => {28 it('approval beats everything; withdrawn only when every approval is withdrawn/superseded', () => {29 expect(stageFor({ approvedLike: 1, withdrawnLike: 0, totalTrials: 0, maxPhase: null })).toBe('approved');30 expect(stageFor({ approvedLike: 1, withdrawnLike: 3, totalTrials: 12, maxPhase: 'PHASE3' })).toBe('approved');31 expect(stageFor({ approvedLike: 0, withdrawnLike: 2, totalTrials: 40, maxPhase: 'PHASE4' })).toBe('withdrawn');32 });33 it('otherwise the highest phase among interventional trials decides', () => {34 expect(stageFor({ approvedLike: 0, withdrawnLike: 0, totalTrials: 3, maxPhase: 'PHASE4' })).toBe('phase4');35 expect(stageFor({ approvedLike: 0, withdrawnLike: 0, totalTrials: 3, maxPhase: 'PHASE3' })).toBe('phase3');36 expect(stageFor({ approvedLike: 0, withdrawnLike: 0, totalTrials: 3, maxPhase: 'PHASE2' })).toBe('phase2');37 expect(stageFor({ approvedLike: 0, withdrawnLike: 0, totalTrials: 3, maxPhase: 'PHASE1' })).toBe('phase1');38 expect(stageFor({ approvedLike: 0, withdrawnLike: 0, totalTrials: 3, maxPhase: 'EARLY_PHASE1' })).toBe('phase1');39 expect(stageFor({ approvedLike: 0, withdrawnLike: 0, totalTrials: 3, maxPhase: 'NA' })).toBe('phase_not_stated');40 expect(stageFor({ approvedLike: 0, withdrawnLike: 0, totalTrials: 3, maxPhase: null })).toBe('phase_not_stated');41 });42 it('no trials and no approvals → no row', () => {43 expect(stageFor({ approvedLike: 0, withdrawnLike: 0, totalTrials: 0, maxPhase: null })).toBeNull();44 });45 it('every stage the rule can return is a declared stage; the formula is versioned', () => {46 const inputs = [47 { approvedLike: 1, withdrawnLike: 0, totalTrials: 0, maxPhase: null },48 { approvedLike: 0, withdrawnLike: 1, totalTrials: 0, maxPhase: null },49 ...['PHASE4', 'PHASE3', 'PHASE2', 'PHASE1', 'EARLY_PHASE1', 'NA'].map((p) => ({ approvedLike: 0, withdrawnLike: 0, totalTrials: 1, maxPhase: p })),50 ];51 for (const i of inputs) expect(PIPELINE_STAGES).toContain(stageFor(i));52 expect(DRUG_PIPELINE_FORMULA_VERSION).toMatch(/^ci-drug-pipeline-v\d+$/);53 });54});55