From 53fcb45d5a79eaea72567fb462e0634aa839e42b Mon Sep 17 00:00:00 2001 From: Anders Richardsson <2107110+caravinci@users.noreply.github.com> Date: Wed, 25 Oct 2023 14:54:55 -0400 Subject: [PATCH] add unknown treatment exception validations --- .gitignore | 1 + .../treatment/checkWhenNoTreatment.js | 97 ++- tests/treatment/checkWhenNoTreatment.test.js | 604 +++++++++++------- 3 files changed, 446 insertions(+), 256 deletions(-) diff --git a/.gitignore b/.gitignore index c25e1928..f985e1de 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ +.DS_Store node_modules dictionary.json populated_dictionary.json diff --git a/references/validationFunctions/treatment/checkWhenNoTreatment.js b/references/validationFunctions/treatment/checkWhenNoTreatment.js index 249d4689..e6318a45 100644 --- a/references/validationFunctions/treatment/checkWhenNoTreatment.js +++ b/references/validationFunctions/treatment/checkWhenNoTreatment.js @@ -5,42 +5,81 @@ * You should have received a copy of the GNU Affero General Public License along with * this program. If not, see . * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT - * SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED - * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER - * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * + * * */ /** - * If treatment_type is 'No treatment', core treatment fields should not be submitted. + * If treatment_type is 'No treatment' or 'Unknown', core treatment fields should not be submitted. */ -const validation = () => - (function validate(inputs) { - const {$row, $name, $field} = inputs; - let result = {valid: true, message: "Ok"}; - const coreFields = ['treatment_start_interval', 'treatment_duration', 'is_primary_treatment', 'treatment_intent', 'treatment_setting', 'response_to_treatment_criteria_method', 'response_to_treatment']; - - // checks for a string just consisting of whitespace - const checkforEmpty = (entry) => {return /^\s+$/g.test(decodeURI(entry).replace(/^"(.*)"$/, '$1'))}; - const treatmentType = ($row.treatment_type).map(value => value.toLowerCase()); - - if (!treatmentType.includes("no treatment") && coreFields.includes($name) && (!$field || $field === null || checkforEmpty($field))) { - result = { valid: false, message: `The '${$name}' field must be submitted when the 'treatment_type' field is '${treatmentType}'`}; - } - else if (treatmentType.includes("no treatment") && ($field && $field != null && !(checkforEmpty($field)))) { - if (coreFields.includes($name) || (typeof($field) === 'string' && $field.trim().toLowerCase() != 'not applicable') || typeof($field) === 'number') { - result = { valid: false, message: `The '${$name}' field cannot be submitted if the 'treatment_type' field is '${treatmentType}'`}; +const validation = () => + (function validate(inputs) { + const { $row, $name, $field } = inputs; + const result = { valid: true, message: 'Ok' }; + + const arrayItemsInSecondArray = (arr1, arr2) => { + return arr2.some(arr2Item => { + return arr1.includes(arr2Item); + }); + }; + + const coreFields = [ + 'treatment_start_interval', + 'treatment_duration', + 'is_primary_treatment', + 'treatment_intent', + 'treatment_setting', + 'response_to_treatment_criteria_method', + 'response_to_treatment', + ]; + + const treatmentExceptionTypes = ['no treatment', 'unknown']; + + // checks for a string just consisting of whitespace + const checkforEmpty = entry => { + return /^\s+$/g.test(decodeURI(entry).replace(/^"(.*)"$/, '$1')); + }; + const treatmentTypes = $row.treatment_type.map(value => value.toLowerCase()); + + const recordHasTreatments = !arrayItemsInSecondArray( + treatmentExceptionTypes, + treatmentTypes, + ); + + if (recordHasTreatments) { + if ( + coreFields.includes($name) && + (!$field || $field === null || checkforEmpty($field)) + ) { + return { + valid: false, + message: `The '${$name}' field must be submitted when the 'treatment_type' field is '${treatmentTypes}'`, + }; + } + + } else if ($field && $field != null && !checkforEmpty($field)) { + if ( + coreFields.includes($name) || + (typeof $field === 'string' && $field.trim().toLowerCase() != 'not applicable') || + typeof $field === 'number' + ) { + return { + valid: false, + message: `The '${$name}' field cannot be submitted if the 'treatment_type' field is '${treatmentTypes}'`, + }; + } } - } - return result; - }); + return result; + }); module.exports = validation; diff --git a/tests/treatment/checkWhenNoTreatment.test.js b/tests/treatment/checkWhenNoTreatment.test.js index b85b5994..0361f790 100644 --- a/tests/treatment/checkWhenNoTreatment.test.js +++ b/tests/treatment/checkWhenNoTreatment.test.js @@ -5,16 +5,16 @@ * You should have received a copy of the GNU Affero General Public License along with * this program. If not, see . * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT - * SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED - * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER - * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * + * * */ @@ -26,288 +26,438 @@ const loadObjects = require('../loadObjects'); // load in all fields with entries prepopulated to null const treatment = require('../constructDummyData').getSchemaDummy('treatment'); - // key -> name of field, value -> unit tests const myUnitTests = { - 'treatment_start_interval': [ + treatment_start_interval: [ + [ + 'treatment_start_interval is submitted when treatment was given', + true, + loadObjects(treatment, { + treatment_start_interval: 409, + treatment_type: ['Chemotherapy'], + }), + ], + [ + 'treatment_start_interval is missing when treatment was given', + false, + loadObjects(treatment, { + treatment_type: ['Surgery'], + }), + ], [ 'treatment_start_interval is submitted when no treatment was given', false, - loadObjects(treatment, - { - "treatment_start_interval": 30, - "treatment_type": ["No treatment"] - } - ) + loadObjects(treatment, { + treatment_start_interval: 30, + treatment_type: ['No treatment'], + }), ], [ - 'treatment_start_interval is submitted when treatment is given', + 'treatment_start_interval is submitted when treatment was unknown', + false, + loadObjects(treatment, { + treatment_start_interval: 30, + treatment_type: ['Unknown'], + }), + ], + [ + 'treatment_start_interval is missing when no treatment was given', true, - loadObjects(treatment, - { - "treatment_start_interval": 409, - "treatment_type": ["Chemotherapy"] - } - ) + loadObjects(treatment, { + treatment_type: ['No treatment'], + }), ], [ - 'treatment_start_interval is not submitted when no treatment is given', + 'treatment_start_interval is missing when treatment was unknown', true, - loadObjects(treatment, - { - "treatment_type": ["No treatment"] - } - ) - ] + loadObjects(treatment, { + treatment_type: ['Unknown'], + }), + ], ], - 'treatment_duration': [ + treatment_duration: [ [ - 'treatment_duration is submitted when no treatment was given', + 'treatment_duration is submitted when treatment was given', + true, + loadObjects(treatment, { + treatment_duration: 40, + treatment_type: ['Chemotherapy'], + }), + ], + [ + 'treatment_duration is missing when treatment was given', false, - loadObjects(treatment, - { - "treatment_duration": 30, - "treatment_type": ["No treatment"] - } - ) + loadObjects(treatment, { + treatment_type: ['Surgery'], + }), ], [ - 'treatment_duration is submitted when treatment is given', + 'treatment_duration is missing when no treatment was given', true, - loadObjects(treatment, - { - "treatment_duration": 40, - "treatment_type": ["Chemotherapy"] - } - ) + loadObjects(treatment, { + treatment_type: ['No treatment'], + }), ], [ - 'treatment_duration is missing when treatment is given', + 'treatment_duration is missing when treatment was unknown', + true, + loadObjects(treatment, { + treatment_type: ['Unknown'], + }), + ], + [ + 'treatment_duration is submitted when no treatment was given', false, - loadObjects(treatment, - { - "treatment_type": ["Surgery"] - } - ) - ] + loadObjects(treatment, { + treatment_duration: 30, + treatment_type: ['No treatment'], + }), + ], + [ + 'treatment_duration is submitted when treatment was unknown', + false, + loadObjects(treatment, { + treatment_duration: 30, + treatment_type: ['Unknown'], + }), + ], ], - 'is_primary_treatment': [ + is_primary_treatment: [ + [ + 'is_primary_treatment is submitted when treatment was given', + true, + loadObjects(treatment, { + is_primary_treatment: 'No', + treatment_type: ['Chemotherapy'], + }), + ], + [ + 'is_primary_treatment is missing when no treatment was given', + true, + loadObjects(treatment, { + treatment_type: ['No treatment'], + }), + ], + [ + 'is_primary_treatment is missing when no treatment was given', + true, + loadObjects(treatment, { + treatment_type: ['Unknown'], + }), + ], + [ + 'is_primary_treatment is empty when no treatment was given', + true, + loadObjects(treatment, { + is_primary_treatment: '', + treatment_type: ['No treatment'], + }), + ], + [ + 'is_primary_treatment is empty when no treatment was given', + true, + loadObjects(treatment, { + is_primary_treatment: '', + treatment_type: ['Unknown'], + }), + ], [ 'is_primary_treatment is missing when treatment was given', false, - loadObjects(treatment, - { - "treatment_type": ["Chemotherapy"] - } - ) + loadObjects(treatment, { + treatment_type: ['Chemotherapy'], + }), ], [ 'is_primary_treatment is submitted when no treatment was given', false, - loadObjects(treatment, - { - "is_primary_treatment": "Yes", - "treatment_type": ["No treatment"] - } - ) + loadObjects(treatment, { + is_primary_treatment: 'Yes', + treatment_type: ['No treatment'], + }), ], [ - 'is_primary_treatment is submitted when treatment is given', + 'is_primary_treatment is submitted when treatment was unknown', + false, + loadObjects(treatment, { + is_primary_treatment: 'Yes', + treatment_type: ['Unknown'], + }), + ], + ], + treatment_setting: [ + [ + 'treatment_setting is submitted when treatment was given', true, - loadObjects(treatment, - { - "is_primary_treatment": "No", - "treatment_type": ["Chemotherapy"] - } - ) + loadObjects(treatment, { + treatment_setting: 'adjuvant', + treatment_type: ['Chemotherapy'], + }), + ], + [ + 'treatment_setting is missing when treatment was given', + false, + loadObjects(treatment, { + treatment_type: ['Surgery'], + }), ], [ - 'is_primary_treatment is not submitted when no treatment is given', + 'treatment_setting is missing when no treatment was given', true, - loadObjects(treatment, - { - "is_primary_treatment": "", - "treatment_type": ["No treatment"] - } - ) + loadObjects(treatment, { + treatment_type: ['no treatment'], + }), ], [ - 'is_primary_treatment is not submitted when no treatment is given', + 'treatment_setting is missing when treatment was unknowm', true, - loadObjects(treatment, - { - "treatment_type": ["No treatment"] - } - ) - ] - ], - 'treatment_setting': [ + loadObjects(treatment, { + treatment_type: ['Unknown'], + }), + ], [ 'treatment_setting is submitted when no treatment was given', false, - loadObjects(treatment, - { - "treatment_setting": "neoadjuvant", - "treatment_type": ["No treatment"] - } - ) + loadObjects(treatment, { + treatment_setting: 'neoadjuvant', + treatment_type: ['No treatment'], + }), + ], + [ + 'treatment_setting is submitted when treatment was unknown', + false, + loadObjects(treatment, { + treatment_setting: 'neoadjuvant', + treatment_type: ['Unknown'], + }), ], + ], + treatment_intent: [ [ - 'treatment_setting is submitted when treatment is given', + 'treatment_intent is submitted when treatment was given', true, - loadObjects(treatment, - { - "treatment_setting": "adjuvant", - "treatment_type": ["Chemotherapy"] - } - ) + loadObjects(treatment, { + treatment_intent: 'palliative', + treatment_type: ['Chemotherapy'], + }), ], [ - 'treatment_setting is not submitted when no treatment is given', + 'treatment_intent is missing when treatment was given', + false, + loadObjects(treatment, { + treatment_type: ['Surgery'], + }), + ], + [ + 'treatment_intent is not submitted when no treatment was given', true, - loadObjects(treatment, - { - "treatment_type": ["no treatment"] - } - ) - ] - - ], - 'treatment_intent': [ + loadObjects(treatment, { + treatment_type: ['No treatment'], + }), + ], + [ + 'treatment_intent is not submitted when treatment was unknown', + true, + loadObjects(treatment, { + treatment_type: ['Unknown'], + }), + ], [ 'treatment_intent is submitted when no treatment was given', false, - loadObjects(treatment, - { - "treatment_intent": "curative", - "treatment_type": ["No treatment"] - } - ) + loadObjects(treatment, { + treatment_intent: 'curative', + treatment_type: ['No treatment'], + }), ], [ - 'treatment_intent is submitted when treatment is given', + 'treatment_intent is submitted when treatment was unknown', + false, + loadObjects(treatment, { + treatment_intent: 'curative', + treatment_type: ['Unknown'], + }), + ], + ], + days_per_cycle: [ + [ + 'days per cycle is submitted when treatment was given', true, - loadObjects(treatment, - { - "treatment_intent": "palliative", - "treatment_type": ["Chemotherapy"] - } - ) + loadObjects(treatment, { + days_per_cycle: 12, + treatment_type: ['Chemotherapy'], + }), ], [ - 'treatment_intent is not submitted when no treatment is given', + 'days per cycle is missing when treatment was given', true, - loadObjects(treatment, - { - "treatment_type": ["no treatment"] - } - ) - ] - - ], - 'days_per_cycle': [ - [ - 'days per cycle is submitted when Chemotherapy was given', - true, - loadObjects(treatment, - { - "days_per_cycle": 12, - "treatment_type": ["Chemotherapy"] - } - ) - ], - [ - 'days per cycle is submitted when no treatment was given', - false, - loadObjects(treatment, - { - "days_per_cycle": 10, - "treatment_type": ["no treatment"] - } - ) - ] + loadObjects(treatment, { + treatment_type: ['Surgery'], + }), + ], + [ + 'days per cycle is missing when no treatment was given', + true, + loadObjects(treatment, { + treatment_type: ['No treatment'], + }), + ], + [ + 'days per cycle is missing when treatment was unknown', + true, + loadObjects(treatment, { + treatment_type: ['Unknown'], + }), + ], + [ + 'days per cycle is submitted when no treatment was given', + false, + loadObjects(treatment, { + days_per_cycle: 10, + treatment_type: ['No treatment'], + }), + ], + [ + 'days per cycle is submitted when treatment was unknown', + false, + loadObjects(treatment, { + days_per_cycle: 10, + treatment_type: ['Unknown'], + }), + ], + ], + outcome_of_treatment: [ + [ + 'outcome_of_treatment is submitted when treatment was given', + true, + loadObjects(treatment, { + outcome_of_treatment: 'treatment completed as prescribed', + treatment_type: ['Chemotherapy'], + }), + ], + [ + 'outcome_of_treatment is missing when treatment was given', + true, + loadObjects(treatment, { + treatment_type: ['Surgery'], + }), + ], + [ + 'outcome_of_treatment is not applicable when no treatment was given', + true, + loadObjects(treatment, { + outcome_of_treatment: 'Not Applicable', + treatment_type: ['No treatment'], + }), + ], + [ + 'outcome_of_treatment is not applicable when treatment was unknown', + true, + loadObjects(treatment, { + outcome_of_treatment: 'Not Applicable', + treatment_type: ['Unknown'], + }), + ], + [ + 'outcome_of_treatment is empty when no treatment was given', + true, + loadObjects(treatment, { + outcome_of_treatment: '', + treatment_type: ['No treatment'], + }), + ], + [ + 'outcome_of_treatment is empty when treatment was unknown', + true, + loadObjects(treatment, { + outcome_of_treatment: '', + treatment_type: ['Unknown'], + }), + ], + [ + 'outcome_of_treatment is missing when no treatment was given', + true, + loadObjects(treatment, { + treatment_type: ['No treatment'], + }), + ], + [ + 'outcome_of_treatment is missing when treatment was unknown', + true, + loadObjects(treatment, { + treatment_type: ['Unknown'], + }), + ], + [ + 'outcome_of_treatment is submitted when no treatment was given', + false, + loadObjects(treatment, { + outcome_of_treatment: 'treatment completed as prescribed', + treatment_type: ['No treatment'], + }), + ], + [ + 'outcome_of_treatment is submitted when treatment was unknown', + false, + loadObjects(treatment, { + outcome_of_treatment: 'treatment completed as prescribed', + treatment_type: ['Unknown'], + }), + ], ], - 'outcome_of_treatment': [ - [ - 'outcome_of_treatment is submitted when no treatment was given', - false, - loadObjects(treatment, - { - "outcome_of_treatment": "treatment completed as prescribed", - "treatment_type": ["no treatment"] - } - ) - ], - [ - 'outcome_of_treatment is not applicable when no treatment was given', - true, - loadObjects(treatment, - { - "outcome_of_treatment": "Not Applicable", - "treatment_type": ["no treatment"] - } - ) - ], - [ - 'outcome_of_treatment is empty when no treatment was given', - true, - loadObjects(treatment, - { - "outcome_of_treatment": "", - "treatment_type": ["no treatment"] - } - ) - ] + response_to_treatment_criteria_method: [ + [ + 'response_to_treatment_criteria_method is submitted when no treatment was given', + false, + loadObjects(treatment, { + response_to_treatment_criteria_method: 'RECIST', + treatment_type: ['no treatment'], + }), + ], + [ + 'response_to_treatment_criteria_method is missing when radiation treatment was given', + false, + loadObjects(treatment, { + treatment_type: ['radiation therapy'], + }), + ], ], - 'response_to_treatment_criteria_method': [ - [ - 'response_to_treatment_criteria_method is submitted when no treatment was given', - false, - loadObjects(treatment, - { - "response_to_treatment_criteria_method": "RECIST", - "treatment_type": ["no treatment"] - } - ) - ], - [ - 'response_to_treatment_criteria_method is missing when radiation treatment was given', - false, - loadObjects(treatment, - { - "treatment_type": ["radiation therapy"] - } - ) - ] - ] +}; -} - -describe("Common Tests",()=>{ - Object.entries(myUnitTests).forEach(field =>{ +describe('Common Tests', () => { + Object.entries(myUnitTests).forEach(field => { const name = field[0]; const unitTests = field[1]; - unitTests.forEach(test=>{ + + unitTests.forEach(test => { const testIndex = 2; const testInputs = test[testIndex]; - universalTest(validation()({ $row: testInputs, $name: name, $field: testInputs[name]})); - }) - }) - -}) -describe("Unit Tests for treatment fields when no treatment is given",()=>{ + universalTest( + validation()({ $row: testInputs, $name: name, $field: testInputs[name] }), + ); + }); + }); +}); + +describe('Unit Tests for treatment fields when no treatment was given', () => { Object.entries(myUnitTests).forEach(field => { const name = field[0]; const unitTests = field[1]; - describe(`Tests for the ${name} field.`,()=>{ - test.each(unitTests)('\n Test %# : %s \nExpecting result.valid to be: %s',(description,target,inputs) =>{ - const scriptOutput = validation()({ $row: inputs, $field: inputs[name], $name: name}); - expect(scriptOutput.valid).toBe(target); - }) - }) - - }) - -}) + describe(`Tests for the ${name} field.`, () => { + test.each(unitTests)( + '\n Test %# : %s \nExpecting result.valid to be: %s', + (description, target, inputs) => { + const scriptOutput = validation()({ + $row: inputs, + $field: inputs[name], + $name: name, + }); + + expect(scriptOutput.valid).toBe(target); + }, + ); + }); + }); +});