A utility for translating, executing, and testing CQL libraries, specifically for the CDSS4PCP project
This project is forked from cql-testing-harness and modified for additional functionality for testing CDS Vaccine rules.
Users also need to configure a .env file in your CQL repository, defining the following values:
TRANSLATION_SERVICE_URL=http://localhost:8080/cql/translator # An endpoint exposing a CQL translation service
INPUT_CQL=./test/fixtures/cql # Folder(s) containing all CQL to translate
OUTPUT_ELM=./test/fixtures/elm # Folder where translated ELM will be saved
VALUESETS=./test/fixtures/valuesets # Folder where CQL-dependent valuesets live
PATIENTS=./test/fixtures/patients # Folder storing patient files used as test fixtures
VSAC_API_KEY=your_key # UMLS API key that will be used to download valuesets. For increased security, store the API key in a env variable instead
- cql-exec-vsac: Used for identifying and downloading valuesets within CQL rules
- cdss-common: The common module that is used for executing CQL rules in thee CDSS4PCP project
Contains the source code for
-
test/- Root directory for all test-related files.
-
test/fixtures/- Contains static test data for validating CQL logic.
-
test/fixtures/cql/- Contains original CQL files (human-readable clinical logic).
- Folder name must match the
libraryname in each.cqlfile.
-
test/fixtures/elm/- Contains compiled ELM files (machine-readable JSON).
- Folder name must match the corresponding CQL library.
-
test/fixtures/patients/- Contains FHIR/JSON patient examples used to test rules.
- Folder name must match the CQL library it tests.
-
test/fixtures/valuesets/- Contains shared ValueSet files (e.g., SNOMED, CVX codes).
- No strict naming requirement.
test-cql [-n] [-t path/to/test/directory]-n: When this option is included, the script will not start a new cql-translation-service docker container. When using this option, ensure you have an instance of the translation service running on your machine at the URL specified in .env-t: This option allows you to specify a specific directory or pattern thatjestshould use to run the tests. If omitted, the script will usejest's default which is any file that ends in.test.js
This script will do the following:
- Start a cql-translation-service docker container
- Translate all CQL in the
INPUT_CQLdirectory into ELM JSON and write it toOUTPUT_ELM. This will only occur if CQL files in theINPUT_CQLhave changed and the ELM needs to be updated - Run the unit tests present in the specified test directory
translate-cqlThis script will only do step 2. from above: translate all CQL in theINPUT_CQL directory into ELM JSON and write it
to OUTPUT_ELM. This will only occur if CQL files in the INPUT_CQL have changed and the ELM needs to be updated
loadJSONFromDirectory(pathToDir): loads all JSON files in pathToDir and returns the contents as an array
pathToDir(string): absolute path to the directory containing the JSON files
loadJSONFixture(pathToFixture): loads the JSON file present at pathToFixture and returns the parsed contents
pathToFixture(string): absolute path to the JSON file
defaultLoadElm(): loads the ELM JSON present at the OUTPUT_ELM value specified in .env
defaultLoadPatients(): loads all of the patient bundle JSONs present at the PATIENTS value specified in .env
defaultLoadValuesets(): loads all of the ValueSet JSON files present at the VALUESETS value specified in .env
- Setup
.envwith necessary content
# .env contents
TRANSLATION_SERVICE_URL=http://localhost:8080/cql/translator # An endpoint exposing a CQL translation service
INPUT_CQL=./test/fixtures/cql # Folder(s) containing all CQL to translate
OUTPUT_ELM=./test/fixtures/elm # Folder where translated ELM will be saved
VALUESETS=./test/fixtures/valuesets # Folder where CQL-dependent valuesets live
PATIENTS=./test/fixtures/patients # Folder storing patient files used as test fixtures
VSAC_API_KEY=your_key # UMLS API key that will be used to download valuesets. For increased security, store the API key in a env variable instead
- Create a test for your CQL:
/* example.test.js */
const dotenv = require('dotenv');
const vsac = require('cql-exec-vsac');
const {
executeCql,
} = require('cdss-common/src/cdss-module');
const {
defaultLoadElm,
defaultLoadPatients,
} = require('../src');
const {
getNumberOfMonths,
getNumberOfWeeks,
} = require('./timeUtil');
// Initialize the env variables
dotenv.config();
const API_KEY = process.env.VSAC_API_KEY;
const VALUESETS_CACHE = process.env.VALUESETS;
let elms;
let patientBundles;
beforeAll(() => {
// Set up necessary data for cql-execution
elms = defaultLoadElm();
// patientBundles = defaultCustomPatients();
const bundles = defaultLoadPatients();
patientBundles = {};
bundles.forEach((bundle) => {
patientBundles[bundle.id] = bundle;
});
});
describe('MMR Rule 1 Tests', () => {
test('VaccineName should be Measles, Mumps, and Rubella Virus Vaccine, Patient birthdate should be < 12 mon, No previous dose, Recommendations should be Schedule 1st dose 12-15 mon of age AND Schedule 2nd dose 4-6 yr of age', async () => {
const rule = elms.MMR1regularyoungerthan12monthsNoMMRRecommendation;
const patient = patientBundles.MMR1.entry[0].resource;
const libraries = {
FHIRHelpers: elms.FHIRHelpers,
Common: elms.MMR_Common_Library,
};
const codeService = new vsac.CodeService(VALUESETS_CACHE, true, true);
const result = await executeCql(patient, rule, libraries, { 'Imm': [] }, codeService, API_KEY);
expect(result)
.not
.toBeNull();
const patientResult = result[patient.id];
const patientBod = new Date(patient.birthDate);
expect(patientResult.VaccineName)
.toEqual('Measles, Mumps, and Rubella Virus Vaccine');
expect(patientResult.Recommendations)
.toHaveLength(2);
expect(patientResult.Recommendations[0].recommendation)
.toEqual(expect.stringContaining('Recommendation 1: Schedule 1st dose MMR when patient is 12-15 months'));
expect(patientResult.Recommendations[1].recommendation)
.toEqual(expect.stringContaining('Recommendation 2: Schedule 2nd dose MMR when patient is 4-6 years'));
});
});-
Run the test script to translate the CQL into ELM and get the execution results to use in unit test assertions:
npm run test-cql
Example output:
> [email protected] test-cql
> node ./src/scripts/run.js
> Starting cql-translation-service
26a543ed9ac3fcce8e308c6de1ae008db189be0e7765f50006dfbf2a51f36d29
> Waiting for server
.> Translating CQL
Wrote ELM to C:\Users\C2\Documents\Clemson\Assistantship\cdss-testing-harness\test\fixtures\elm\FHIRHelpers.json
Wrote ELM to C:\Users\C2\Documents\Clemson\Assistantship\cdss-testing-harness\test\fixtures\elm\MMR1\MMR1.json
Wrote ELM to C:\Users\C2\Documents\Clemson\Assistantship\cdss-testing-harness\test\fixtures\elm\MMR_Common_Library.json
> Running unit tests
PASS test/MMR_Positive.test.js
MMR Rule 1 Tests
√ VaccineName should be Measles, Mumps, and Rubella Virus Vaccine, Patient birthdate should be < 12 mon, No previous dose, Recommendations should be Schedule 1st dose 12-15 mon of age AND Schedule 2nd dose 4-6 yr of age (134 ms)
Test Suites: 1 passed, 1 total
Tests: 1 passed, 1 total
Snapshots: 0 total
Time: 2.038 s, estimated 3 s
Ran all test suites.
> Stopping cql-translation-service
cql-translation-service
Note: If you get errors similar to
Ran into error when gathering valuesets, then make you set your VSAC API key correctly.
Note: Some cql rules rely on date ranges relative to current date. This fact will cause certain tests to fail if the system date is not within the range of the cql file