Fix production TypeScript builds and add DEPLOY.md so the app can be hosted from this repo. Co-authored-by: Cursor <cursoragent@cursor.com>
63 lines
2.2 KiB
TypeScript
63 lines
2.2 KiB
TypeScript
import assert from 'node:assert/strict';
|
|
import { describe, it } from 'node:test';
|
|
import {
|
|
PCQ_QUESTION_IDS,
|
|
applyReverseScoring,
|
|
isReverseScored,
|
|
parseLikertValue,
|
|
scoreAnswer,
|
|
scoreAssessment,
|
|
ScoringValidationError,
|
|
validateAnswers,
|
|
} from '../src/modules/assessments/scoring/index.js';
|
|
|
|
function answersWithValue(value: string | number) {
|
|
return PCQ_QUESTION_IDS.map((questionId) => ({ questionId, selectedValue: value }));
|
|
}
|
|
|
|
describe('PCQ-24 scoring engine', () => {
|
|
it('reverse-scores pcq_13, pcq_20, and pcq_23 with 7 - raw', () => {
|
|
assert.equal(isReverseScored('pcq_13'), true);
|
|
assert.equal(isReverseScored('pcq_20'), true);
|
|
assert.equal(isReverseScored('pcq_23'), true);
|
|
assert.equal(isReverseScored('pcq_01'), false);
|
|
assert.equal(applyReverseScoring(1), 6);
|
|
assert.equal(applyReverseScoring(6), 1);
|
|
assert.equal(applyReverseScoring('4'), 3);
|
|
});
|
|
|
|
it('keeps raw Likert and stores reverse-scored points separately', () => {
|
|
const scored = scoreAnswer('pcq_13', '2');
|
|
assert.ok(scored);
|
|
assert.equal(scored.selectedValue, 2);
|
|
assert.equal(scored.rawScore, 5);
|
|
assert.equal(scored.dimension, 'resilience');
|
|
assert.equal(scored.isReverseScored, true);
|
|
});
|
|
|
|
it('scores a uniform Likert-4 attempt with known totals', () => {
|
|
const result = scoreAssessment('pre', answersWithValue(4));
|
|
assert.equal(result.totalScore, 93);
|
|
assert.equal(result.dimensions.efficacy, 24);
|
|
assert.equal(result.dimensions.hope, 24);
|
|
assert.equal(result.dimensions.resilience, 23);
|
|
assert.equal(result.dimensions.optimism, 22);
|
|
|
|
const reverse = result.answers.filter((answer) => answer.isReverseScored);
|
|
assert.equal(reverse.length, 3);
|
|
for (const answer of reverse) {
|
|
assert.equal(answer.selectedValue, 4);
|
|
assert.equal(answer.rawScore, 3);
|
|
}
|
|
});
|
|
|
|
it('rejects incomplete or out-of-range answers', () => {
|
|
assert.equal(validateAnswers(answersWithValue(4).slice(0, 23)).isValid, false);
|
|
assert.equal(parseLikertValue('7'), null);
|
|
assert.throws(
|
|
() => scoreAssessment('pre', answersWithValue(7)),
|
|
(err: unknown) => err instanceof ScoringValidationError,
|
|
);
|
|
});
|
|
});
|