-
Notifications
You must be signed in to change notification settings - Fork 7
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
35 changed files
with
857 additions
and
1,130 deletions.
There are no files selected for viewing
File renamed without changes.
File renamed without changes.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,135 @@ | ||
import { ZodError } from 'zod' | ||
import { Score } from '../../classes' | ||
import { ScoreLibrary } from '../library' | ||
import { | ||
best_response, | ||
median_response, | ||
random_response, | ||
worst_response, | ||
} from './__testdata__/cat_test_responses' | ||
import { cat } from './cat' | ||
|
||
const BEST_SCORE = 0 | ||
const MEDIAN_SCORE = 20 | ||
const WORST_SCORE = 40 | ||
|
||
const cat_calculation = new Score(cat) | ||
|
||
describe('cat', function () { | ||
it('cat calculation function should be available as a calculation', function () { | ||
expect(ScoreLibrary).toHaveProperty('cat') | ||
}) | ||
|
||
describe('basic assumptions', function () { | ||
const outcome = cat_calculation.calculate({ payload: best_response }) | ||
|
||
it('should return 2 calculation results', function () { | ||
expect(Object.keys(outcome).length).toEqual(2) | ||
}) | ||
|
||
it('should have the expected calculation result ids', function () { | ||
const EXPECTED_CALCULATION_ID = ['CAT_POINTS', 'CAT_HEALTH_IMPACT'] | ||
|
||
const configured_calculation_id = Object.keys(outcome) | ||
|
||
expect(configured_calculation_id).toEqual(EXPECTED_CALCULATION_ID) | ||
}) | ||
}) | ||
|
||
describe('validation', function () { | ||
describe('the score includes the correct input fields', function () { | ||
it('should have all the expected input ids configured', function () { | ||
const EXPECTED_INPUT_IDS = [ | ||
'1_COUGH', | ||
'2_PHLEGM', | ||
'3_CHEST_TIGHTNESS', | ||
'4_BREATHLESSNESS', | ||
'5_ACTIVITIES', | ||
'6_CONFIDENCE', | ||
'7_SLEEP', | ||
'8_ENERGY', | ||
] | ||
|
||
const configured_input_ids = Object.keys(cat_calculation.inputSchema) | ||
|
||
expect(EXPECTED_INPUT_IDS).toEqual(configured_input_ids) | ||
}) | ||
}) | ||
|
||
describe('when an answer is not not one of the allowed answers', function () { | ||
it('should throw an ZodError', function () { | ||
expect(() => | ||
cat_calculation.calculate({ | ||
payload: { | ||
'1_COUGH': -1, | ||
}, | ||
}), | ||
).toThrow(ZodError) | ||
}) | ||
}) | ||
|
||
describe('when called with an empty response', function () { | ||
it('should throw an error', function () { | ||
expect(() => | ||
cat_calculation.calculate({ | ||
payload: {}, | ||
}), | ||
).toThrow(ZodError) | ||
}) | ||
}) | ||
}) | ||
|
||
describe('score calculation', function () { | ||
describe('when called with the best response', function () { | ||
const outcome = cat_calculation.calculate({ payload: best_response }) | ||
|
||
it('should return the best score', function () { | ||
expect(outcome.CAT_POINTS).toEqual(BEST_SCORE) | ||
}) | ||
|
||
it('should return the best health impact', function () { | ||
expect(outcome.CAT_HEALTH_IMPACT).toEqual('LOW') | ||
}) | ||
}) | ||
|
||
describe('when called with the median response', function () { | ||
const outcome = cat_calculation.calculate({ payload: median_response }) | ||
|
||
it('should return the worst score', function () { | ||
expect(outcome.CAT_POINTS).toEqual(MEDIAN_SCORE) | ||
}) | ||
|
||
it('should return the median health impact', function () { | ||
expect(outcome.CAT_HEALTH_IMPACT).toEqual('MEDIUM') | ||
}) | ||
}) | ||
|
||
describe('when called with the worst response', function () { | ||
const outcome = cat_calculation.calculate({ payload: worst_response }) | ||
|
||
it('should return the worst score', function () { | ||
expect(outcome.CAT_POINTS).toEqual(WORST_SCORE) | ||
}) | ||
|
||
it('should return the worst health impact', function () { | ||
expect(outcome.CAT_HEALTH_IMPACT).toEqual('VERY HIGH') | ||
}) | ||
}) | ||
|
||
describe('when called with a random response', function () { | ||
const outcome = cat_calculation.calculate({ payload: random_response }) | ||
|
||
it('should return the expected score', function () { | ||
const EXPECTED_SCORE = 16 | ||
|
||
expect(outcome.CAT_POINTS).toEqual(EXPECTED_SCORE) | ||
}) | ||
|
||
it('should return the expected health impact', function () { | ||
const EXPECTED_HEALTH_IMPACT = 'MEDIUM' | ||
|
||
expect(outcome.CAT_HEALTH_IMPACT).toEqual(EXPECTED_HEALTH_IMPACT) | ||
}) | ||
}) | ||
}) | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
import { ScoreType } from '../../types' | ||
import { CAT_OUTPUT, CAT_INPUTS, CAT_INTERPRATION_TABLE } from './definition' | ||
import { sum } from 'lodash' | ||
|
||
export const cat: ScoreType<typeof CAT_INPUTS, typeof CAT_OUTPUT> = { | ||
name: 'COPD Assessment Test (CAT)', | ||
readmeLocation: __dirname, | ||
inputSchema: CAT_INPUTS, | ||
outputSchema: CAT_OUTPUT, | ||
calculate: ({ data }) => { | ||
const score = sum(Object.values(data)) | ||
|
||
return { | ||
CAT_POINTS: score, | ||
CAT_HEALTH_IMPACT: CAT_INTERPRATION_TABLE[score.toString()], | ||
} | ||
}, | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,199 @@ | ||
import { z } from 'zod' | ||
import { ScoreInputSchemaType } from '../../../types' | ||
|
||
export const CAT_INPUTS = { | ||
'1_COUGH': { | ||
label: { en: 'Cough' }, | ||
type: z.union([ | ||
z.literal(0), | ||
z.literal(1), | ||
z.literal(2), | ||
z.literal(3), | ||
z.literal(4), | ||
z.literal(5), | ||
]), | ||
uiOptions: { | ||
options: [ | ||
{ | ||
label: { en: 'I never cough' }, | ||
value: 0, | ||
}, | ||
{ | ||
label: { en: 'I cough all the time' }, | ||
value: 5, | ||
}, | ||
], | ||
}, | ||
}, | ||
'2_PHLEGM': { | ||
label: { en: 'Phlegm' }, | ||
type: z.union([ | ||
z.literal(0), | ||
z.literal(1), | ||
z.literal(2), | ||
z.literal(3), | ||
z.literal(4), | ||
z.literal(5), | ||
]), | ||
uiOptions: { | ||
options: [ | ||
{ | ||
label: { en: 'I have no phlegm in my chest at all' }, | ||
value: 0, | ||
}, | ||
{ | ||
label: { en: 'My chest is completely full of pleghm' }, | ||
value: 5, | ||
}, | ||
], | ||
}, | ||
}, | ||
'3_CHEST_TIGHTNESS': { | ||
label: { en: 'Chest tightness' }, | ||
type: z.union([ | ||
z.literal(0), | ||
z.literal(1), | ||
z.literal(2), | ||
z.literal(3), | ||
z.literal(4), | ||
z.literal(5), | ||
]), | ||
uiOptions: { | ||
options: [ | ||
{ | ||
label: { en: 'My chest does not feel tight at all' }, | ||
value: 0, | ||
}, | ||
{ | ||
label: { en: 'My chest feels very tight' }, | ||
value: 5, | ||
}, | ||
], | ||
}, | ||
}, | ||
'4_BREATHLESSNESS': { | ||
label: { en: 'Breathlessness' }, | ||
type: z.union([ | ||
z.literal(0), | ||
z.literal(1), | ||
z.literal(2), | ||
z.literal(3), | ||
z.literal(4), | ||
z.literal(5), | ||
]), | ||
uiOptions: { | ||
options: [ | ||
{ | ||
label: { | ||
en: 'When I walk up a hill or one flight of stairs I am not breathless', | ||
}, | ||
value: 0, | ||
}, | ||
{ | ||
label: { | ||
en: 'When I walk up a hill or one flight of stairs I am very breathless', | ||
}, | ||
value: 5, | ||
}, | ||
], | ||
}, | ||
}, | ||
'5_ACTIVITIES': { | ||
label: { en: 'Activities' }, | ||
type: z.union([ | ||
z.literal(0), | ||
z.literal(1), | ||
z.literal(2), | ||
z.literal(3), | ||
z.literal(4), | ||
z.literal(5), | ||
]), | ||
uiOptions: { | ||
options: [ | ||
{ | ||
label: { en: 'I am not limited doing any activities at home' }, | ||
value: 0, | ||
}, | ||
{ | ||
label: { en: 'I am very limited doing any activities at home' }, | ||
value: 5, | ||
}, | ||
], | ||
}, | ||
}, | ||
'6_CONFIDENCE': { | ||
label: { | ||
en: 'Confidence', | ||
}, | ||
type: z.union([ | ||
z.literal(0), | ||
z.literal(1), | ||
z.literal(2), | ||
z.literal(3), | ||
z.literal(4), | ||
z.literal(5), | ||
]), | ||
uiOptions: { | ||
options: [ | ||
{ | ||
label: { | ||
en: 'I am confident leaving my home despite my lung condition', | ||
}, | ||
value: 0, | ||
}, | ||
{ | ||
label: { | ||
en: 'I am not at all confident leaving my home because of my lung condition', | ||
}, | ||
value: 5, | ||
}, | ||
], | ||
}, | ||
}, | ||
'7_SLEEP': { | ||
label: { en: 'Sleep' }, | ||
type: z.union([ | ||
z.literal(0), | ||
z.literal(1), | ||
z.literal(2), | ||
z.literal(3), | ||
z.literal(4), | ||
z.literal(5), | ||
]), | ||
uiOptions: { | ||
options: [ | ||
{ | ||
label: { en: 'I sleep soundly' }, | ||
value: 0, | ||
}, | ||
{ | ||
label: { en: 'I don’t sleep soundly because of my lung condition' }, | ||
value: 5, | ||
}, | ||
], | ||
}, | ||
}, | ||
'8_ENERGY': { | ||
label: { en: 'Energy' }, | ||
type: z.union([ | ||
z.literal(0), | ||
z.literal(1), | ||
z.literal(2), | ||
z.literal(3), | ||
z.literal(4), | ||
z.literal(5), | ||
]), | ||
uiOptions: { | ||
options: [ | ||
{ | ||
label: { en: 'I have lots of energy' }, | ||
value: 0, | ||
}, | ||
{ | ||
label: { en: 'I have no energy at all' }, | ||
value: 5, | ||
}, | ||
], | ||
}, | ||
}, | ||
} satisfies ScoreInputSchemaType |
File renamed without changes.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
import { z } from 'zod' | ||
import { ScoreOutputSchemaType } from '../../../types' | ||
|
||
export const CAT_OUTPUT = { | ||
CAT_POINTS: { | ||
label: { en: 'CAT points' }, | ||
type: z.number(), | ||
}, | ||
CAT_HEALTH_IMPACT: { | ||
label: { en: 'Health impact' }, | ||
type: z.string(), | ||
}, | ||
} satisfies ScoreOutputSchemaType |
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
Oops, something went wrong.