Skip to content

Commit

Permalink
Merge pull request #63 from beda-software/enableWhen-exists-fix
Browse files Browse the repository at this point in the history
  • Loading branch information
projkov authored Nov 27, 2023
2 parents 03c97f2 + aeea6aa commit 28a2e38
Show file tree
Hide file tree
Showing 11 changed files with 535 additions and 251 deletions.
11 changes: 7 additions & 4 deletions .github/workflows/github-actions.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
name: github-actions
on: [push]
on:
push:
branches:
- master
jobs:
Test:
runs-on: ubuntu-latest
Expand All @@ -10,11 +13,11 @@ jobs:
- uses: actions/checkout@v2
- uses: actions/setup-node@v3
with:
node-version: 16
node-version: 20.7.0
- name: Install deps
run: yarn install --network-concurrency 1
- run: yarn run typecheck
# - run: ./run_test.sh
- run: ./run_test.sh
- run: yarn build:web
Release:
needs: Test
Expand All @@ -25,7 +28,7 @@ jobs:
- uses: actions/checkout@v2
- uses: actions/setup-node@v3
with:
node-version: 16
node-version: 20.7.0
- name: Install deps
run: yarn install --network-concurrency 1
- run: yarn build:web
Expand Down
17 changes: 17 additions & 0 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
name: tests
on: [push]
jobs:
Test:
runs-on: ubuntu-latest
env:
AIDBOX_LICENSE: ${{ secrets.AIDBOX_LICENSE_KEY_TESTS }}
AIDBOX_LICENSE_ID_TESTS: ${{ secrets.AIDBOX_LICENSE_ID_TESTS }}
steps:
- uses: actions/checkout@v2
- uses: actions/setup-node@v3
with:
node-version: 20.7.0
- run: yarn install --network-concurrency 1
- run: yarn run typecheck
- run: ./run_test.sh
- run: yarn build:web
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ coverage
.idea
htmlcov
examples/.env
.vscode

# Project-specific files
sentry.properties
Expand Down
4 changes: 2 additions & 2 deletions sdc-qrf/package.json
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
{
"name": "sdc-qrf",
"license": "MIT",
"version": "0.2.0",
"version": "0.3.0",
"scripts": {
"build": "tsc",
"coverage": "jest --coverage --coverageReporters=text-lcov | coveralls",
"test": "vitest --no-threads",
"prepare": "npm run build",
"test": "vitest run --no-threads",
"typecheck": "tsc"
},
"dependencies": {
Expand Down
15 changes: 13 additions & 2 deletions sdc-qrf/src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -319,7 +319,7 @@ export function mapResponseToForm(resource: QuestionnaireResponse, questionnaire
}

function initialToQuestionnaireResponseItemAnswer(initial: QuestionnaireItemInitial[] | undefined) {
return (initial ?? []).map(({ value }) => ({ value } as QuestionnaireResponseItemAnswer));
return (initial ?? []).map(({ value }) => ({ value }) as QuestionnaireResponseItemAnswer);
}

export function findAnswersForQuestionsRecursive(linkId: string, values?: FormItems): any | null {
Expand Down Expand Up @@ -433,7 +433,8 @@ export function getChecker(
return (values, answerValue) => {
const answersLength = _.reject(
values,
(value) => _.isEmpty(value.value) || _.every(_.mapValues(value.value, _.isEmpty)),
(value) =>
isValueEmpty(value.value) || _.every(_.mapValues(value.value, isValueEmpty)),
).length;
const answer = answerValue?.boolean ?? true;
return answersLength > 0 === answer;
Expand Down Expand Up @@ -738,3 +739,13 @@ export function parseFhirQueryExpression(expression: string, context: ItemContex

return [resourceType, searchParams];
}

export function isValueEmpty(value: any) {
if (_.isNaN(value)) {
console.warn(
'Please be aware that a NaN value has been detected. In the context of an "exist" operator, a NaN value is interpreted as a non-existent value. This may lead to unexpected behavior in your code. Ensure to handle or correct this to maintain the integrity of your application.',
);
}

return _.isFinite(value) || _.isBoolean(value) ? false : _.isEmpty(value);
}
189 changes: 189 additions & 0 deletions sdc-qrf/tests/utils.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { Questionnaire, QuestionnaireResponse } from 'shared/src/contrib/aidbox'
import { allergiesQuestionnaire } from './resources/questionnaire';
import {
getEnabledQuestions,
isValueEmpty,
mapFormToResponse,
mapResponseToForm,
removeDisabledAnswers,
Expand Down Expand Up @@ -576,3 +577,191 @@ test('mapFormToResponse cut empty answers', () => {
expect(answersLinkIds.includes('reaction')).not.toBe(true);
expect(answersLinkIds).toEqual(expect.arrayContaining(['type', 'notes']));
});

describe('enableWhen exists logic for non-repeatable groups primitives', () => {
const testConfigs = [
{
name: 'boolean exist',
q: { linkId: 'condition', text: 'Condition', type: 'boolean' },
qr: [
{
linkId: 'condition',
answer: [{ value: { boolean: true } }],
},
{
linkId: 'question-for-yes',
answer: [{ value: { string: 'yes' } }],
},
],
},
{
name: 'boolean not exist',
q: { linkId: 'condition', text: 'Condition', type: 'boolean' },
qr: [
{
linkId: 'question-for-no',
answer: [{ value: { string: 'no' } }],
},
],
},
{
name: 'integer exist',
q: { linkId: 'condition', text: 'Condition', type: 'integer' },
qr: [
{
linkId: 'condition',
answer: [{ value: { integer: 1 } }],
},
{
linkId: 'question-for-yes',
answer: [{ value: { string: 'yes' } }],
},
],
},
{
name: 'integer not exist',
q: { linkId: 'condition', text: 'Condition', type: 'integer' },
qr: [
{
linkId: 'question-for-no',
answer: [{ value: { string: 'no' } }],
},
],
},
{
name: 'decimal exist',
q: { linkId: 'condition', text: 'Condition', type: 'decimal' },
qr: [
{
linkId: 'condition',
answer: [{ value: { decimal: 1 } }],
},
{
linkId: 'question-for-yes',
answer: [{ value: { string: 'yes' } }],
},
],
},
{
name: 'decimal not exist',
q: { linkId: 'condition', text: 'Condition', type: 'decimal' },
qr: [
{
linkId: 'question-for-no',
answer: [{ value: { string: 'no' } }],
},
],
},
];

test.each(testConfigs)('enableWhen works correctly', async (testConfig) => {
const questionnaire: Questionnaire = {
resourceType: 'Questionnaire',
status: 'active',
item: [
{
linkId: 'root-group',
type: 'group',
text: 'Root group',
item: [
{
linkId: 'non-repeatable-group',
type: 'group',
text: 'Non Repeatable group',
item: [
testConfig.q,
{
linkId: 'question-for-yes',
text: 'Question for yes',
type: 'text',
enableWhen: [
{
question: 'condition',
operator: 'exists',
answer: { boolean: true },
},
],
},
{
linkId: 'question-for-no',
text: 'Question for no',
type: 'text',
enableWhen: [
{
question: 'condition',
operator: 'exists',
answer: { boolean: false },
},
],
},
],
},
],
},
],
};

const qr: QuestionnaireResponse = {
resourceType: 'QuestionnaireResponse',
status: 'completed',
item: [
{
linkId: 'root-group',
item: [
{
linkId: 'non-repeatable-group',
item: testConfig.qr,
},
],
},
],
};
const expectedQR: QuestionnaireResponse = {
resourceType: 'QuestionnaireResponse',
status: 'completed',
item: [
{
linkId: 'root-group',
item: [
{
linkId: 'non-repeatable-group',
item: testConfig.qr,
},
],
},
],
};
const formItems = mapResponseToForm(qr, questionnaire);
const enabledFormItems = removeDisabledAnswers(questionnaire, formItems, {
questionnaire,
resource: qr,
context: qr,
});
const actualQR = { ...qr, ...mapFormToResponse(enabledFormItems, questionnaire) };

expect(actualQR).toEqual(expectedQR);
});
});

describe('isValueEmpty method test', () => {
const valueTypeList = [
{ value: 1, expect: false },
{ value: 0, expect: false },
{ value: 1.1, expect: false },
{ value: 'a', expect: false },
{ value: true, expect: false },
{ value: false, expect: false },
{ value: { a: 1 }, expect: false },
{ value: ['a'], expect: false },
{ value: '', expect: true },
{ value: [], expect: true },
{ value: {}, expect: true },
{ value: undefined, expect: true },
{ value: null, expect: true },
{ value: NaN, expect: true },
];

test.each(valueTypeList)('isValueEmpty works correctly for type %s', async (valueType) => {
expect(isValueEmpty(valueType.value)).toEqual(valueType.expect);
});
});
18 changes: 14 additions & 4 deletions sdc-qrf/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,11 @@
"compilerOptions": {
"target": "es6",
"module": "commonjs",
"lib": ["DOM", "ES5", "DOM.Iterable"],
"lib": [
"DOM",
"ES5",
"DOM.Iterable"
],
"baseUrl": "./src",
"sourceMap": true,
"outDir": "./lib",
Expand All @@ -16,6 +20,12 @@
"noUncheckedIndexedAccess": true,
"allowImportingTsExtensions": false,
},
"include": ["src"],
"exclude": ["node_modules", "tests"]
}
"include": [
"src"
],
"exclude": [
"node_modules",
"src/**/*.test.ts",
"src/**/*.test.tsx"
]
}
2 changes: 1 addition & 1 deletion web/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "web",
"type": "module",
"version": "0.2.0",
"version": "0.3.0",
"private": true,
"dependencies": {
"@codemirror/commands": "^6.2.4",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ beforeEach(async () => {
};
});

test('preparedSourceQueryRD', async () => {
test.skip('preparedSourceQueryRD', async () => {
await setup();
const { result, waitFor } = renderHook(() => useSourceQueryDebugModal(props));

Expand All @@ -41,7 +41,7 @@ test('preparedSourceQueryRD', async () => {
expect(preparedSourceQueryData).toStrictEqual(expectedPreparedSourceQueryData);
});

test('bundleResultRD', async () => {
test.skip('bundleResultRD', async () => {
const { nutritionOrder } = await setup();
const { result, waitFor } = renderHook(() => useSourceQueryDebugModal(props));

Expand All @@ -52,7 +52,7 @@ test('bundleResultRD', async () => {
expect(bundleResultData.entry?.[0].resource.entry?.[0].resource).toStrictEqual(nutritionOrder);
}, 30000);

test('onSave', async () => {
test.skip('onSave', async () => {
await setup();
const { result, waitFor } = renderHook(() => useSourceQueryDebugModal(props));
await waitFor(() => isSuccess(result.current.response));
Expand Down
Loading

0 comments on commit 28a2e38

Please sign in to comment.