From 9b34e4eb3256126c896f0e202d8d520d4505d402 Mon Sep 17 00:00:00 2001 From: Elsa Date: Sat, 23 Nov 2024 15:17:58 -0500 Subject: [PATCH] Add create and update tests for QuestionnaireResponse and Task --- config/presets/inferno_dtr_server_suite.json | 20 + lib/davinci_dtr_test_kit/create_test.rb | 24 + .../dtr_light_ehr_suite.rb | 8 + .../questionnaire_response_create.rb | 21 + .../questionnaire_response_update.rb | 21 + .../profiles/task/task_create.rb | 21 + .../profiles/task/task_update.rb | 21 + lib/davinci_dtr_test_kit/update_test.rb | 24 + spec/davinci_dtr_test_kit/create_test_spec.rb | 175 +++++ spec/davinci_dtr_test_kit/update_test_spec.rb | 191 +++++ ...nnaire_response_create_update_example.json | 721 ++++++++++++++++++ 11 files changed, 1247 insertions(+) create mode 100644 lib/davinci_dtr_test_kit/create_test.rb create mode 100644 lib/davinci_dtr_test_kit/profiles/questionnaire_response/questionnaire_response_create.rb create mode 100644 lib/davinci_dtr_test_kit/profiles/questionnaire_response/questionnaire_response_update.rb create mode 100644 lib/davinci_dtr_test_kit/profiles/task/task_create.rb create mode 100644 lib/davinci_dtr_test_kit/profiles/task/task_update.rb create mode 100644 lib/davinci_dtr_test_kit/update_test.rb create mode 100644 spec/davinci_dtr_test_kit/create_test_spec.rb create mode 100644 spec/davinci_dtr_test_kit/update_test_spec.rb create mode 100644 spec/fixtures/questionnaire_response_create_update_example.json diff --git a/config/presets/inferno_dtr_server_suite.json b/config/presets/inferno_dtr_server_suite.json index 6c9a3ff..6230610 100644 --- a/config/presets/inferno_dtr_server_suite.json +++ b/config/presets/inferno_dtr_server_suite.json @@ -74,6 +74,26 @@ "type": "text", "value": "cdex-task-example19" }, + { + "name": "create_questionnaire_resources", + "type": "textarea", + "value": "[{\"resourceType\":\"QuestionnaireResponse\",\"id\":\"home-o2-questionnaireresponse-2\",\"meta\":{\"profile\":[\"http://hl7.org/fhir/us/davinci-dtr/StructureDefinition/dtr-questionnaireresponse\"]},\"extension\":[{\"url\":\"http://hl7.org/fhir/us/davinci-dtr/StructureDefinition/qr-context\",\"valueReference\":{\"reference\":\"Coverage/CoverageExample\"}},{\"url\":\"http://hl7.org/fhir/us/davinci-dtr/StructureDefinition/qr-context\",\"valueReference\":{\"reference\":\"ServiceRequest/ServiceRequestExample\"}},{\"url\":\"http://hl7.org/fhir/us/davinci-dtr/StructureDefinition/intendedUse\",\"valueCodeableConcept\":{\"coding\":[{\"system\":\"http://hl7.org/fhir/us/davinci-crd/CodeSystem/temp\",\"code\":\"withorder\",\"display\":\"Include with order\"}]}}],\"questionnaire\":\"http://example.com/Questionnaire/referred-questionnaire\",\"status\":\"completed\",\"subject\":{\"reference\":\"Patient/examplepatient\",\"display\":\"Vlad\"},\"authored\":\"2023-08-21\",\"item\":[{\"linkId\":\"1\",\"text\":\"PatientInformation\",\"item\":[{\"linkId\":\"1.1\",\"text\":\"LastNamebutDifferentThisTime\",\"answer\":[{\"extension\":[{\"extension\":[{\"url\":\"source\",\"valueCode\":\"override\"},{\"extension\":[{\"url\":\"role\",\"valueCodeableConcept\":{\"coding\":[{\"system\":\"http://terminology.hl7.org/CodeSystem/practitioner-role\",\"code\":\"doctor\",\"display\":\"Doctor\"}]}},{\"url\":\"practitioner\",\"valueReference\":{\"reference\":\"Practitioner/PractitionerExample\",\"display\":\"Dr.JaneDoe\"}}],\"url\":\"author\"}],\"url\":\"http://hl7.org/fhir/us/davinci-dtr/StructureDefinition/information-origin\"}],\"valueString\":\"Quinton\"}]},{\"linkId\":\"1.2\",\"text\":\"FirstName\",\"answer\":[{\"extension\":[{\"extension\":[{\"url\":\"source\",\"valueCode\":\"auto\"}],\"url\":\"http://hl7.org/fhir/us/davinci-dtr/StructureDefinition/information-origin\"}],\"valueString\":\"Vlad\"}]},{\"linkId\":\"1.3\",\"text\":\"MiddleInitial\",\"answer\":[{\"extension\":[{\"extension\":[{\"url\":\"source\",\"valueCode\":\"auto\"}],\"url\":\"http://hl7.org/fhir/us/davinci-dtr/StructureDefinition/information-origin\"}],\"valueString\":\"A,N\"}]},{\"linkId\":\"1.4\",\"text\":\"DateOfBirth\",\"answer\":[{\"extension\":[{\"extension\":[{\"url\":\"source\",\"valueCode\":\"auto\"}],\"url\":\"http://hl7.org/fhir/us/davinci-dtr/StructureDefinition/information-origin\"}],\"valueDate\":\"1956-12-01\"}]},{\"linkId\":\"1.5\",\"text\":\"Gender\",\"answer\":[{\"extension\":[{\"extension\":[{\"url\":\"source\",\"valueCode\":\"auto\"}],\"url\":\"http://hl7.org/fhir/us/davinci-dtr/StructureDefinition/information-origin\"}],\"valueCoding\":{\"system\":\"http://hl7.org/fhir/administrative-gender\",\"code\":\"male\",\"display\":\"Male\"}}]},{\"linkId\":\"1.6\",\"text\":\"MedicareID\",\"answer\":[{\"extension\":[{\"extension\":[{\"url\":\"source\",\"valueCode\":\"auto\"}],\"url\":\"http://hl7.org/fhir/us/davinci-dtr/StructureDefinition/information-origin\"}],\"valueString\":\"10A3D58WH22\"}]}]},{\"linkId\":\"2\",\"text\":\"Providerwhoisperformingface-to-faceevaluation\",\"item\":[{\"linkId\":\"2.1\",\"text\":\"LastName\",\"answer\":[{\"extension\":[{\"extension\":[{\"url\":\"source\",\"valueCode\":\"auto\"}],\"url\":\"http://hl7.org/fhir/us/davinci-dtr/StructureDefinition/information-origin\"}],\"valueString\":\"Doe\"}]},{\"linkId\":\"2.2\",\"text\":\"FirstName\",\"answer\":[{\"extension\":[{\"extension\":[{\"url\":\"source\",\"valueCode\":\"auto\"}],\"url\":\"http://hl7.org/fhir/us/davinci-dtr/StructureDefinition/information-origin\"}],\"valueString\":\"Jane\"}]},{\"linkId\":\"2.3\",\"text\":\"MiddleInitial\",\"answer\":[{\"extension\":[{\"extension\":[{\"url\":\"source\",\"valueCode\":\"auto\"}],\"url\":\"http://hl7.org/fhir/us/davinci-dtr/StructureDefinition/information-origin\"}],\"valueString\":\"B\"}]},{\"linkId\":\"2.4\",\"text\":\"NPI\",\"answer\":[{\"extension\":[{\"extension\":[{\"url\":\"source\",\"valueCode\":\"auto\"}],\"url\":\"http://hl7.org/fhir/us/davinci-dtr/StructureDefinition/information-origin\"}],\"valueString\":\"1122334455\"}]},{\"linkId\":\"2.5\",\"text\":\"DateofFace-To-FaceEvaluation\",\"answer\":[{\"extension\":[{\"extension\":[{\"url\":\"source\",\"valueCode\":\"override\"},{\"extension\":[{\"url\":\"role\",\"valueCodeableConcept\":{\"coding\":[{\"system\":\"http://terminology.hl7.org/CodeSystem/practitioner-role\",\"code\":\"doctor\",\"display\":\"Doctor\"}]}},{\"url\":\"practitioner\",\"valueReference\":{\"reference\":\"Practitioner/PractitionerExample\",\"display\":\"Dr.JaneDoe\"}}],\"url\":\"author\"}],\"url\":\"http://hl7.org/fhir/us/davinci-dtr/StructureDefinition/information-origin\"}],\"valueDate\":\"2019-07-18\"}]}]},{\"linkId\":\"3\",\"text\":\"CoverageRequirements\",\"item\":[{\"linkId\":\"3.1\",\"text\":\"RelevantPatientDiagnoses(conditionsthatmightbeexpectedtoimprovewithoxygentherapy)\",\"answer\":[{\"extension\":[{\"extension\":[{\"url\":\"source\",\"valueCode\":\"auto\"}],\"url\":\"http://hl7.org/fhir/us/davinci-dtr/StructureDefinition/information-origin\"}],\"valueCoding\":{\"system\":\"http://snomed.info/sct\",\"code\":\"313296004\",\"display\":\"Mild chronic obstructive pulmonary disease\"}},{\"extension\":[{\"extension\":[{\"url\":\"source\",\"valueCode\":\"auto\"}],\"url\":\"http://hl7.org/fhir/us/davinci-dtr/StructureDefinition/information-origin\"}],\"valueCoding\":{\"system\":\"http://snomed.info/sct\",\"code\":\"389087006\",\"display\":\"Hypoxemia (disorder)\"}}]},{\"linkId\":\"3.2\",\"text\":\"Arterialoxygensaturation(Patientonroomairwhileatrestandawakewhentested)\",\"answer\":[{\"extension\":[{\"extension\":[{\"url\":\"source\",\"valueCode\":\"auto\"}],\"url\":\"http://hl7.org/fhir/us/davinci-dtr/StructureDefinition/information-origin\"}],\"valueQuantity\":{\"value\":95,\"system\":\"http://unitsofmeasure.org\",\"code\":\"mm[Hg]\"}}]},{\"linkId\":\"3.3\",\"text\":\"ArterialPartialPressureofOxygen(PO2)(Patientonroomairwhileatrestandawakewhentested)\",\"answer\":[{\"extension\":[{\"extension\":[{\"url\":\"source\",\"valueCode\":\"auto\"}],\"url\":\"http://hl7.org/fhir/us/davinci-dtr/StructureDefinition/information-origin\"}],\"valueQuantity\":{\"value\":83,\"system\":\"http://unitsofmeasure.org\",\"code\":\"mm[Hg]\"}}]},{\"linkId\":\"3.4\",\"text\":\"Arterialoxygensaturation(Patienttestedduringexercise)\",\"answer\":[{\"extension\":[{\"extension\":[{\"url\":\"source\",\"valueCode\":\"auto\"}],\"url\":\"http://hl7.org/fhir/us/davinci-dtr/StructureDefinition/information-origin\"}],\"valueQuantity\":{\"value\":95,\"system\":\"http://unitsofmeasure.org\",\"code\":\"mm[Hg]\"}}]},{\"linkId\":\"3.5\",\"text\":\"ArterialPartialPressureofOxygen(PO2)(Patienttestedduringexercise)\",\"answer\":[{\"extension\":[{\"extension\":[{\"url\":\"source\",\"valueCode\":\"auto\"}],\"url\":\"http://hl7.org/fhir/us/davinci-dtr/StructureDefinition/information-origin\"}],\"valueQuantity\":{\"value\":78,\"system\":\"http://unitsofmeasure.org\",\"code\":\"mm[Hg]\"}}]},{\"linkId\":\"3.6\",\"text\":\"Isthereadocumentedimprovementofhypoxemiaduringexercisewithoxygen?\",\"answer\":[{\"extension\":[{\"extension\":[{\"url\":\"source\",\"valueCode\":\"auto\"}],\"url\":\"http://hl7.org/fhir/us/davinci-dtr/StructureDefinition/information-origin\"}],\"valueBoolean\":true}]}]},{\"linkId\":\"4\",\"text\":\"PrescribedUse\",\"item\":[{\"linkId\":\"4.1\",\"text\":\"Startdate\",\"answer\":[{\"extension\":[{\"extension\":[{\"url\":\"source\",\"valueCode\":\"auto\"}],\"url\":\"http://hl7.org/fhir/us/davinci-dtr/StructureDefinition/information-origin\"}],\"valueDate\":\"2019-07-18\"}]},{\"linkId\":\"4.2\",\"text\":\"Lengthofneed:(months)(99=lifetime)\",\"answer\":[{\"extension\":[{\"extension\":[{\"url\":\"source\",\"valueCode\":\"auto\"}],\"url\":\"http://hl7.org/fhir/us/davinci-dtr/StructureDefinition/information-origin\"}],\"valueQuantity\":{\"value\":99}}]},{\"linkId\":\"4.3\",\"text\":\"PeakFlowRate\",\"item\":[{\"linkId\":\"4.3.1\",\"text\":\"LPM\",\"answer\":[{\"extension\":[{\"extension\":[{\"url\":\"source\",\"valueCode\":\"auto\"}],\"url\":\"http://hl7.org/fhir/us/davinci-dtr/StructureDefinition/information-origin\"}],\"valueInteger\":2}]},{\"linkId\":\"4.3.2\",\"text\":\"oxygen%\",\"answer\":[{\"extension\":[{\"extension\":[{\"url\":\"source\",\"valueCode\":\"auto\"}],\"url\":\"http://hl7.org/fhir/us/davinci-dtr/StructureDefinition/information-origin\"}],\"valueInteger\":98}]}]},{\"linkId\":\"4.4\",\"text\":\"AverageFlowRate\",\"item\":[{\"linkId\":\"4.4.1\",\"text\":\"LPM\",\"answer\":[{\"extension\":[{\"extension\":[{\"url\":\"source\",\"valueCode\":\"auto\"}],\"url\":\"http://hl7.org/fhir/us/davinci-dtr/StructureDefinition/information-origin\"}],\"valueInteger\":2}]},{\"linkId\":\"4.4.2\",\"text\":\"oxygen%\",\"answer\":[{\"extension\":[{\"extension\":[{\"url\":\"source\",\"valueCode\":\"auto\"}],\"url\":\"http://hl7.org/fhir/us/davinci-dtr/StructureDefinition/information-origin\"}],\"valueInteger\":97}]}]},{\"linkId\":\"4.5\",\"text\":\"Frequencyofuse(chooseallthatapply)\",\"answer\":[{\"extension\":[{\"extension\":[{\"url\":\"source\",\"valueCode\":\"auto\"}],\"url\":\"http://hl7.org/fhir/us/davinci-dtr/StructureDefinition/information-origin\"}]}]}]},{\"linkId\":\"5\",\"text\":\"OxygenSupplyOrderDetails\",\"item\":[{\"linkId\":\"5.1\",\"text\":\"CurrentOrderDescription\",\"answer\":[{\"extension\":[{\"extension\":[{\"url\":\"source\",\"valueCode\":\"auto\"}],\"url\":\"http://hl7.org/fhir/us/davinci-dtr/StructureDefinition/information-origin\"}],\"valueString\":\"HCPCSE0424-StationaryCompressedGaseousOxygenSystem,Rental\"}]},{\"linkId\":\"5.1b\",\"text\":\"CurrentOrderIsForAPortableDevice\"},{\"linkId\":\"5.2\",\"text\":\"Type\",\"answer\":[{\"extension\":[{\"extension\":[{\"url\":\"source\",\"valueCode\":\"auto\"}],\"url\":\"http://hl7.org/fhir/us/davinci-dtr/StructureDefinition/information-origin\"}]}]},{\"linkId\":\"5.3\",\"text\":\"Meansofoxygendeliveryandaccessories\",\"answer\":[{\"extension\":[{\"extension\":[{\"url\":\"source\",\"valueCode\":\"auto\"}],\"url\":\"http://hl7.org/fhir/us/davinci-dtr/StructureDefinition/information-origin\"}]}]}]}]}]" + }, + { + "name": "update_questionnaire_resources", + "type": "textarea", + "value": "[{\"resourceType\":\"QuestionnaireResponse\",\"id\":\"home-o2-questionnaireresponse\",\"meta\":{\"profile\":[\"http://hl7.org/fhir/us/davinci-dtr/StructureDefinition/dtr-questionnaireresponse\"]},\"extension\":[{\"url\":\"http://hl7.org/fhir/us/davinci-dtr/StructureDefinition/qr-context\",\"valueReference\":{\"reference\":\"Coverage/CoverageExample\"}},{\"url\":\"http://hl7.org/fhir/us/davinci-dtr/StructureDefinition/qr-context\",\"valueReference\":{\"reference\":\"ServiceRequest/ServiceRequestExample\"}},{\"url\":\"http://hl7.org/fhir/us/davinci-dtr/StructureDefinition/intendedUse\",\"valueCodeableConcept\":{\"coding\":[{\"system\":\"http://hl7.org/fhir/us/davinci-crd/CodeSystem/temp\",\"code\":\"withorder\",\"display\":\"Include with order\"}]}}],\"questionnaire\":\"http://example.com/Questionnaire/referred-questionnaire\",\"status\":\"completed\",\"subject\":{\"reference\":\"Patient/examplepatient\",\"display\":\"Vlad\"},\"authored\":\"2023-08-21\",\"item\":[{\"linkId\":\"1\",\"text\":\"PatientInformation\",\"item\":[{\"linkId\":\"1.1\",\"text\":\"LastNamebutDifferentThisTime\",\"answer\":[{\"extension\":[{\"extension\":[{\"url\":\"source\",\"valueCode\":\"override\"},{\"extension\":[{\"url\":\"role\",\"valueCodeableConcept\":{\"coding\":[{\"system\":\"http://terminology.hl7.org/CodeSystem/practitioner-role\",\"code\":\"doctor\",\"display\":\"Doctor\"}]}},{\"url\":\"practitioner\",\"valueReference\":{\"reference\":\"Practitioner/PractitionerExample\",\"display\":\"Dr.JaneDoe\"}}],\"url\":\"author\"}],\"url\":\"http://hl7.org/fhir/us/davinci-dtr/StructureDefinition/information-origin\"}],\"valueString\":\"Quinton\"}]},{\"linkId\":\"1.2\",\"text\":\"FirstName\",\"answer\":[{\"extension\":[{\"extension\":[{\"url\":\"source\",\"valueCode\":\"auto\"}],\"url\":\"http://hl7.org/fhir/us/davinci-dtr/StructureDefinition/information-origin\"}],\"valueString\":\"Vlad\"}]},{\"linkId\":\"1.3\",\"text\":\"MiddleInitial\",\"answer\":[{\"extension\":[{\"extension\":[{\"url\":\"source\",\"valueCode\":\"auto\"}],\"url\":\"http://hl7.org/fhir/us/davinci-dtr/StructureDefinition/information-origin\"}],\"valueString\":\"A,N\"}]},{\"linkId\":\"1.4\",\"text\":\"DateOfBirth\",\"answer\":[{\"extension\":[{\"extension\":[{\"url\":\"source\",\"valueCode\":\"auto\"}],\"url\":\"http://hl7.org/fhir/us/davinci-dtr/StructureDefinition/information-origin\"}],\"valueDate\":\"1957-12-01\"}]},{\"linkId\":\"1.5\",\"text\":\"Gender\",\"answer\":[{\"extension\":[{\"extension\":[{\"url\":\"source\",\"valueCode\":\"auto\"}],\"url\":\"http://hl7.org/fhir/us/davinci-dtr/StructureDefinition/information-origin\"}],\"valueCoding\":{\"system\":\"http://hl7.org/fhir/administrative-gender\",\"code\":\"male\",\"display\":\"Male\"}}]},{\"linkId\":\"1.6\",\"text\":\"MedicareID\",\"answer\":[{\"extension\":[{\"extension\":[{\"url\":\"source\",\"valueCode\":\"auto\"}],\"url\":\"http://hl7.org/fhir/us/davinci-dtr/StructureDefinition/information-origin\"}],\"valueString\":\"10A3D58WH22\"}]}]},{\"linkId\":\"2\",\"text\":\"Providerwhoisperformingface-to-faceevaluation\",\"item\":[{\"linkId\":\"2.1\",\"text\":\"LastName\",\"answer\":[{\"extension\":[{\"extension\":[{\"url\":\"source\",\"valueCode\":\"auto\"}],\"url\":\"http://hl7.org/fhir/us/davinci-dtr/StructureDefinition/information-origin\"}],\"valueString\":\"Doe\"}]},{\"linkId\":\"2.2\",\"text\":\"FirstName\",\"answer\":[{\"extension\":[{\"extension\":[{\"url\":\"source\",\"valueCode\":\"auto\"}],\"url\":\"http://hl7.org/fhir/us/davinci-dtr/StructureDefinition/information-origin\"}],\"valueString\":\"Jane\"}]},{\"linkId\":\"2.3\",\"text\":\"MiddleInitial\",\"answer\":[{\"extension\":[{\"extension\":[{\"url\":\"source\",\"valueCode\":\"auto\"}],\"url\":\"http://hl7.org/fhir/us/davinci-dtr/StructureDefinition/information-origin\"}],\"valueString\":\"B\"}]},{\"linkId\":\"2.4\",\"text\":\"NPI\",\"answer\":[{\"extension\":[{\"extension\":[{\"url\":\"source\",\"valueCode\":\"auto\"}],\"url\":\"http://hl7.org/fhir/us/davinci-dtr/StructureDefinition/information-origin\"}],\"valueString\":\"1122334455\"}]},{\"linkId\":\"2.5\",\"text\":\"DateofFace-To-FaceEvaluation\",\"answer\":[{\"extension\":[{\"extension\":[{\"url\":\"source\",\"valueCode\":\"override\"},{\"extension\":[{\"url\":\"role\",\"valueCodeableConcept\":{\"coding\":[{\"system\":\"http://terminology.hl7.org/CodeSystem/practitioner-role\",\"code\":\"doctor\",\"display\":\"Doctor\"}]}},{\"url\":\"practitioner\",\"valueReference\":{\"reference\":\"Practitioner/PractitionerExample\",\"display\":\"Dr.JaneDoe\"}}],\"url\":\"author\"}],\"url\":\"http://hl7.org/fhir/us/davinci-dtr/StructureDefinition/information-origin\"}],\"valueDate\":\"2019-07-18\"}]}]},{\"linkId\":\"3\",\"text\":\"CoverageRequirements\",\"item\":[{\"linkId\":\"3.1\",\"text\":\"RelevantPatientDiagnoses(conditionsthatmightbeexpectedtoimprovewithoxygentherapy)\",\"answer\":[{\"extension\":[{\"extension\":[{\"url\":\"source\",\"valueCode\":\"auto\"}],\"url\":\"http://hl7.org/fhir/us/davinci-dtr/StructureDefinition/information-origin\"}],\"valueCoding\":{\"system\":\"http://snomed.info/sct\",\"code\":\"313296004\",\"display\":\"Mild chronic obstructive pulmonary disease\"}},{\"extension\":[{\"extension\":[{\"url\":\"source\",\"valueCode\":\"auto\"}],\"url\":\"http://hl7.org/fhir/us/davinci-dtr/StructureDefinition/information-origin\"}],\"valueCoding\":{\"system\":\"http://snomed.info/sct\",\"code\":\"389087006\",\"display\":\"Hypoxemia (disorder)\"}}]},{\"linkId\":\"3.2\",\"text\":\"Arterialoxygensaturation(Patientonroomairwhileatrestandawakewhentested)\",\"answer\":[{\"extension\":[{\"extension\":[{\"url\":\"source\",\"valueCode\":\"auto\"}],\"url\":\"http://hl7.org/fhir/us/davinci-dtr/StructureDefinition/information-origin\"}],\"valueQuantity\":{\"value\":95,\"system\":\"http://unitsofmeasure.org\",\"code\":\"mm[Hg]\"}}]},{\"linkId\":\"3.3\",\"text\":\"ArterialPartialPressureofOxygen(PO2)(Patientonroomairwhileatrestandawakewhentested)\",\"answer\":[{\"extension\":[{\"extension\":[{\"url\":\"source\",\"valueCode\":\"auto\"}],\"url\":\"http://hl7.org/fhir/us/davinci-dtr/StructureDefinition/information-origin\"}],\"valueQuantity\":{\"value\":83,\"system\":\"http://unitsofmeasure.org\",\"code\":\"mm[Hg]\"}}]},{\"linkId\":\"3.4\",\"text\":\"Arterialoxygensaturation(Patienttestedduringexercise)\",\"answer\":[{\"extension\":[{\"extension\":[{\"url\":\"source\",\"valueCode\":\"auto\"}],\"url\":\"http://hl7.org/fhir/us/davinci-dtr/StructureDefinition/information-origin\"}],\"valueQuantity\":{\"value\":95,\"system\":\"http://unitsofmeasure.org\",\"code\":\"mm[Hg]\"}}]},{\"linkId\":\"3.5\",\"text\":\"ArterialPartialPressureofOxygen(PO2)(Patienttestedduringexercise)\",\"answer\":[{\"extension\":[{\"extension\":[{\"url\":\"source\",\"valueCode\":\"auto\"}],\"url\":\"http://hl7.org/fhir/us/davinci-dtr/StructureDefinition/information-origin\"}],\"valueQuantity\":{\"value\":78,\"system\":\"http://unitsofmeasure.org\",\"code\":\"mm[Hg]\"}}]},{\"linkId\":\"3.6\",\"text\":\"Isthereadocumentedimprovementofhypoxemiaduringexercisewithoxygen?\",\"answer\":[{\"extension\":[{\"extension\":[{\"url\":\"source\",\"valueCode\":\"auto\"}],\"url\":\"http://hl7.org/fhir/us/davinci-dtr/StructureDefinition/information-origin\"}],\"valueBoolean\":true}]}]},{\"linkId\":\"4\",\"text\":\"PrescribedUse\",\"item\":[{\"linkId\":\"4.1\",\"text\":\"Startdate\",\"answer\":[{\"extension\":[{\"extension\":[{\"url\":\"source\",\"valueCode\":\"auto\"}],\"url\":\"http://hl7.org/fhir/us/davinci-dtr/StructureDefinition/information-origin\"}],\"valueDate\":\"2019-07-18\"}]},{\"linkId\":\"4.2\",\"text\":\"Lengthofneed:(months)(99=lifetime)\",\"answer\":[{\"extension\":[{\"extension\":[{\"url\":\"source\",\"valueCode\":\"auto\"}],\"url\":\"http://hl7.org/fhir/us/davinci-dtr/StructureDefinition/information-origin\"}],\"valueQuantity\":{\"value\":99}}]},{\"linkId\":\"4.3\",\"text\":\"PeakFlowRate\",\"item\":[{\"linkId\":\"4.3.1\",\"text\":\"LPM\",\"answer\":[{\"extension\":[{\"extension\":[{\"url\":\"source\",\"valueCode\":\"auto\"}],\"url\":\"http://hl7.org/fhir/us/davinci-dtr/StructureDefinition/information-origin\"}],\"valueInteger\":2}]},{\"linkId\":\"4.3.2\",\"text\":\"oxygen%\",\"answer\":[{\"extension\":[{\"extension\":[{\"url\":\"source\",\"valueCode\":\"auto\"}],\"url\":\"http://hl7.org/fhir/us/davinci-dtr/StructureDefinition/information-origin\"}],\"valueInteger\":98}]}]},{\"linkId\":\"4.4\",\"text\":\"AverageFlowRate\",\"item\":[{\"linkId\":\"4.4.1\",\"text\":\"LPM\",\"answer\":[{\"extension\":[{\"extension\":[{\"url\":\"source\",\"valueCode\":\"auto\"}],\"url\":\"http://hl7.org/fhir/us/davinci-dtr/StructureDefinition/information-origin\"}],\"valueInteger\":2}]},{\"linkId\":\"4.4.2\",\"text\":\"oxygen%\",\"answer\":[{\"extension\":[{\"extension\":[{\"url\":\"source\",\"valueCode\":\"auto\"}],\"url\":\"http://hl7.org/fhir/us/davinci-dtr/StructureDefinition/information-origin\"}],\"valueInteger\":97}]}]},{\"linkId\":\"4.5\",\"text\":\"Frequencyofuse(chooseallthatapply)\",\"answer\":[{\"extension\":[{\"extension\":[{\"url\":\"source\",\"valueCode\":\"auto\"}],\"url\":\"http://hl7.org/fhir/us/davinci-dtr/StructureDefinition/information-origin\"}]}]}]},{\"linkId\":\"5\",\"text\":\"OxygenSupplyOrderDetails\",\"item\":[{\"linkId\":\"5.1\",\"text\":\"CurrentOrderDescription\",\"answer\":[{\"extension\":[{\"extension\":[{\"url\":\"source\",\"valueCode\":\"auto\"}],\"url\":\"http://hl7.org/fhir/us/davinci-dtr/StructureDefinition/information-origin\"}],\"valueString\":\"HCPCSE0424-StationaryCompressedGaseousOxygenSystem,Rental\"}]},{\"linkId\":\"5.1b\",\"text\":\"CurrentOrderIsForAPortableDevice\"},{\"linkId\":\"5.2\",\"text\":\"Type\",\"answer\":[{\"extension\":[{\"extension\":[{\"url\":\"source\",\"valueCode\":\"auto\"}],\"url\":\"http://hl7.org/fhir/us/davinci-dtr/StructureDefinition/information-origin\"}]}]},{\"linkId\":\"5.3\",\"text\":\"Meansofoxygendeliveryandaccessories\",\"answer\":[{\"extension\":[{\"extension\":[{\"url\":\"source\",\"valueCode\":\"auto\"}],\"url\":\"http://hl7.org/fhir/us/davinci-dtr/StructureDefinition/information-origin\"}]}]}]}]}]" + }, + { + "name": "create_task_resources", + "type": "textarea", + "value": "[{\"resourceType\":\"Task\",\"id\":\"cdex-task-example20\",\"meta\":{\"profile\":[\"http://hl7.org/fhir/us/davinci-cdex/StructureDefinition/cdex-task-attachment-request\"]},\"contained\":[{\"resourceType\":\"Patient\",\"id\":\"patient\",\"meta\":{\"profile\":[\"http://hl7.org/fhir/us/davinci-cdex/StructureDefinition/cdex-patient-demographics\"]},\"identifier\":[{\"use\":\"usual\",\"type\":{\"coding\":[{\"system\":\"http://hl7.org/fhir/us/davinci-hrex/CodeSystem/hrex-temp\",\"code\":\"UMB\"}],\"text\":\"Member Number\"},\"system\":\"http://inferno.healthit.gov/reference-server/r4/cdex/payer/member-ids\",\"value\":\"Member123\"}],\"name\":[{\"family\":\"Shaw\",\"given\":[\"Amy\"]}],\"birthDate\":\"1987-02-20\"},{\"resourceType\":\"PractitionerRole\",\"id\":\"practitionerrole\",\"meta\":{\"profile\":[\"http://hl7.org/fhir/us/davinci-cdex/StructureDefinition/cdex-practitionerrole\"]},\"practitioner\":{\"identifier\":{\"system\":\"http://hl7.org/fhir/sid/us-npi\",\"value\":\"9941339100\"}},\"organization\":{\"identifier\":{\"system\":\"http://hl7.org/fhir/sid/us-npi\",\"value\":\"1234567893\"}}}],\"identifier\":[{\"type\":{\"coding\":[{\"system\":\"http://hl7.org/fhir/us/davinci-cdex/CodeSystem/cdex-temp\",\"code\":\"tracking-id\",\"display\":\"Tracking Id\"}],\"text\":\"Re-AssociationTrackingControlNumber\"},\"system\":\"http://inferno.healthit.gov/reference-server/r4/payer\",\"value\":\"trackingid123\"}],\"status\":\"requested\",\"intent\":\"order\",\"code\":{\"coding\":[{\"system\":\"http://hl7.org/fhir/us/davinci-cdex/CodeSystem/cdex-temp\",\"code\":\"attachment-request-code\"}],\"text\":\"CodedAttachmentRequest\"},\"for\":{\"reference\":\"#patient\"},\"authoredOn\":\"2022-06-17T16:16:06Z\",\"lastModified\":\"2022-06-17T16:16:06Z\",\"requester\":{\"identifier\":{\"system\":\"http://inferno.healthit.gov/reference-server/r4/cdex/payer/payer-ids\",\"value\":\"Payer123\"}},\"owner\":{\"reference\":\"#practitionerrole\"},\"reasonCode\":{\"coding\":[{\"system\":\"http://hl7.org/fhir/claim-use\",\"code\":\"claim\",\"display\":\"Claim\"}],\"text\":\"claim\"},\"reasonReference\":{\"identifier\":{\"system\":\"http://inferno.healthit.gov/r4/reference-server/r4/cdex/payer/claim-ids\",\"value\":\"Claim123\"}},\"restriction\":{\"period\":{\"end\":\"2022-06-21\"}},\"input\":[{\"extension\":[{\"url\":\"http://hl7.org/fhir/us/davinci-pas/StructureDefinition/extension-serviceLineNumber\",\"valuePositiveInt\":1}],\"type\":{\"coding\":[{\"system\":\"http://hl7.org/fhir/us/davinci-hrex/CodeSystem/hrex-temp\",\"code\":\"data-code\"}]},\"valueCodeableConcept\":{\"coding\":[{\"system\":\"http://loinc.org\",\"code\":\"11506-3\",\"display\":\"Progress note\"}],\"text\":\"Progress note\"}},{\"type\":{\"coding\":[{\"system\":\"http://hl7.org/fhir/us/davinci-cdex/CodeSystem/cdex-temp\",\"code\":\"signature-flag\"}]},\"valueBoolean\":true},{\"type\":{\"coding\":[{\"system\":\"http://hl7.org/fhir/us/davinci-cdex/CodeSystem/cdex-temp\",\"code\":\"payer-url\"}]},\"valueUrl\":\"http://inferno.healthit.gov/reference-server/r4/cdex/payer/$submit-attachment\"},{\"type\":{\"coding\":[{\"system\":\"http://hl7.org/fhir/us/davinci-cdex/CodeSystem/cdex-temp\",\"code\":\"service-date\"}]},\"valueDate\":\"2022-06-13\"},{\"type\":{\"coding\":[{\"system\":\"http://hl7.org/fhir/us/davinci-cdex/CodeSystem/cdex-temp\",\"code\":\"purpose-of-use\"}]},\"valueCodeableConcept\":{\"coding\":[{\"system\":\"http://terminology.hl7.org/CodeSystem/v3-ActReason\",\"code\":\"CLMATTCH\",\"display\":\"claim attachment\"}]}}]}]" + }, + { + "name": "update_task_resources", + "type": "textarea", + "value": "[{\"resourceType\":\"Task\",\"id\":\"cdex-task-example19\",\"meta\":{\"profile\":[\"http://hl7.org/fhir/us/davinci-cdex/StructureDefinition/cdex-task-attachment-request\"]},\"contained\":[{\"resourceType\":\"Patient\",\"id\":\"patient\",\"meta\":{\"profile\":[\"http://hl7.org/fhir/us/davinci-cdex/StructureDefinition/cdex-patient-demographics\"]},\"identifier\":[{\"use\":\"usual\",\"type\":{\"coding\":[{\"system\":\"http://hl7.org/fhir/us/davinci-hrex/CodeSystem/hrex-temp\",\"code\":\"UMB\"}],\"text\":\"Member Number\"},\"system\":\"http://inferno.healthit.gov/reference-server/r4/cdex/payer/member-ids\",\"value\":\"Member123\"}],\"name\":[{\"family\":\"Shaw\",\"given\":[\"Amy\"]}],\"birthDate\":\"1988-02-20\"},{\"resourceType\":\"PractitionerRole\",\"id\":\"practitionerrole\",\"meta\":{\"profile\":[\"http://hl7.org/fhir/us/davinci-cdex/StructureDefinition/cdex-practitionerrole\"]},\"practitioner\":{\"identifier\":{\"system\":\"http://hl7.org/fhir/sid/us-npi\",\"value\":\"9941339100\"}},\"organization\":{\"identifier\":{\"system\":\"http://hl7.org/fhir/sid/us-npi\",\"value\":\"1234567893\"}}}],\"identifier\":[{\"type\":{\"coding\":[{\"system\":\"http://hl7.org/fhir/us/davinci-cdex/CodeSystem/cdex-temp\",\"code\":\"tracking-id\",\"display\":\"Tracking Id\"}],\"text\":\"Re-AssociationTrackingControlNumber\"},\"system\":\"http://inferno.healthit.gov/reference-server/r4/payer\",\"value\":\"trackingid123\"}],\"status\":\"requested\",\"intent\":\"order\",\"code\":{\"coding\":[{\"system\":\"http://hl7.org/fhir/us/davinci-cdex/CodeSystem/cdex-temp\",\"code\":\"attachment-request-code\"}],\"text\":\"CodedAttachmentRequest\"},\"for\":{\"reference\":\"#patient\"},\"authoredOn\":\"2022-06-17T16:16:06Z\",\"lastModified\":\"2022-06-17T16:16:06Z\",\"requester\":{\"identifier\":{\"system\":\"http://inferno.healthit.gov/reference-server/r4/cdex/payer/payer-ids\",\"value\":\"Payer123\"}},\"owner\":{\"reference\":\"#practitionerrole\"},\"reasonCode\":{\"coding\":[{\"system\":\"http://hl7.org/fhir/claim-use\",\"code\":\"claim\",\"display\":\"Claim\"}],\"text\":\"claim\"},\"reasonReference\":{\"identifier\":{\"system\":\"http://inferno.healthit.gov/r4/reference-server/r4/cdex/payer/claim-ids\",\"value\":\"Claim123\"}},\"restriction\":{\"period\":{\"end\":\"2022-06-21\"}},\"input\":[{\"extension\":[{\"url\":\"http://hl7.org/fhir/us/davinci-pas/StructureDefinition/extension-serviceLineNumber\",\"valuePositiveInt\":1}],\"type\":{\"coding\":[{\"system\":\"http://hl7.org/fhir/us/davinci-hrex/CodeSystem/hrex-temp\",\"code\":\"data-code\"}]},\"valueCodeableConcept\":{\"coding\":[{\"system\":\"http://loinc.org\",\"code\":\"11506-3\",\"display\":\"Progress note\"}],\"text\":\"Progress note\"}},{\"type\":{\"coding\":[{\"system\":\"http://hl7.org/fhir/us/davinci-cdex/CodeSystem/cdex-temp\",\"code\":\"signature-flag\"}]},\"valueBoolean\":true},{\"type\":{\"coding\":[{\"system\":\"http://hl7.org/fhir/us/davinci-cdex/CodeSystem/cdex-temp\",\"code\":\"payer-url\"}]},\"valueUrl\":\"http://inferno.healthit.gov/reference-server/r4/cdex/payer/$submit-attachment\"},{\"type\":{\"coding\":[{\"system\":\"http://hl7.org/fhir/us/davinci-cdex/CodeSystem/cdex-temp\",\"code\":\"service-date\"}]},\"valueDate\":\"2022-06-13\"},{\"type\":{\"coding\":[{\"system\":\"http://hl7.org/fhir/us/davinci-cdex/CodeSystem/cdex-temp\",\"code\":\"purpose-of-use\"}]},\"valueCodeableConcept\":{\"coding\":[{\"system\":\"http://terminology.hl7.org/CodeSystem/v3-ActReason\",\"code\":\"CLMATTCH\",\"display\":\"claim attachment\"}]}}]}]" + }, { "name": "vision_prescription_ids", "type": "text", diff --git a/lib/davinci_dtr_test_kit/create_test.rb b/lib/davinci_dtr_test_kit/create_test.rb new file mode 100644 index 0000000..dd7e24a --- /dev/null +++ b/lib/davinci_dtr_test_kit/create_test.rb @@ -0,0 +1,24 @@ +module DaVinciDTRTestKit + module CreateTest + def perform_create_test(create_resources, resource_type) + assert_valid_json(create_resources) + create_resources_list = JSON.parse(create_resources) + skip_if(!create_resources_list.is_a?(Array), 'Resources to create not inputted in list format, skipping test.') + + valid_create_resources = + create_resources_list + .compact_blank + .map { |resource| FHIR.from_contents(resource.to_json) } + .select { |resource| resource.resourceType == resource_type } + .select { |resource| resource_is_valid?(resource:) } + + skip_if(valid_create_resources.blank?, + %(No valid #{resource_type} resources were provided to send in Create requests, skipping test.)) + + valid_create_resources.each do |create_resource| + fhir_create(create_resource) + assert_response_status(201) + end + end + end +end diff --git a/lib/davinci_dtr_test_kit/dtr_light_ehr_suite.rb b/lib/davinci_dtr_test_kit/dtr_light_ehr_suite.rb index 79a9225..3cb8e89 100644 --- a/lib/davinci_dtr_test_kit/dtr_light_ehr_suite.rb +++ b/lib/davinci_dtr_test_kit/dtr_light_ehr_suite.rb @@ -9,6 +9,8 @@ require_relative 'profiles/questionnaire_response/questionnaire_response_context_search' require_relative 'profiles/questionnaire_response/questionnaire_response_read' require_relative 'profiles/questionnaire_response/questionnaire_response_validation' +require_relative 'profiles/questionnaire_response/questionnaire_response_create' +require_relative 'profiles/questionnaire_response/questionnaire_response_update' require_relative 'profiles/coverage/coverage_read' require_relative 'profiles/coverage/coverage_validation' require_relative 'profiles/communication_request/communication_request_read' @@ -25,6 +27,8 @@ require_relative 'profiles/service_request/service_request_validation' require_relative 'profiles/task/task_read' require_relative 'profiles/task/task_validation' +require_relative 'profiles/task/task_create' +require_relative 'profiles/task/task_update' require_relative 'profiles/vision_prescription/vision_prescription_read' require_relative 'profiles/vision_prescription/vision_prescription_validation' require 'smart_app_launch/smart_stu1_suite' @@ -136,6 +140,8 @@ class DTRLightEHRSuite < Inferno::TestSuite test from: :questionnaire_response_context_search test from: :questionnaire_response_read test from: :questionnaire_response_validation + test from: :questionnaire_response_create + test from: :questionnaire_response_update end group do @@ -216,6 +222,8 @@ class DTRLightEHRSuite < Inferno::TestSuite test from: :task_read test from: :task_validation + test from: :task_create + test from: :task_update end group do diff --git a/lib/davinci_dtr_test_kit/profiles/questionnaire_response/questionnaire_response_create.rb b/lib/davinci_dtr_test_kit/profiles/questionnaire_response/questionnaire_response_create.rb new file mode 100644 index 0000000..bda8b36 --- /dev/null +++ b/lib/davinci_dtr_test_kit/profiles/questionnaire_response/questionnaire_response_create.rb @@ -0,0 +1,21 @@ +require_relative '../../create_test' + +module DaVinciDTRTestKit + class QuestionnaireResponseCreateTest < Inferno::Test + include DaVinciDTRTestKit::CreateTest + + title 'Server is capable of creating a QuestionnaireResponse resource from QuestionnaireResponse create interaction' + description 'A sever SHALL support the QuestionnaireResponse create interaction' + + id :questionnaire_response_create + input :create_questionnaire_resources + + def resource_type + 'QuestionnaireResponse' + end + + run do + perform_create_test(create_questionnaire_resources, resource_type) + end + end +end diff --git a/lib/davinci_dtr_test_kit/profiles/questionnaire_response/questionnaire_response_update.rb b/lib/davinci_dtr_test_kit/profiles/questionnaire_response/questionnaire_response_update.rb new file mode 100644 index 0000000..bb0cd13 --- /dev/null +++ b/lib/davinci_dtr_test_kit/profiles/questionnaire_response/questionnaire_response_update.rb @@ -0,0 +1,21 @@ +require_relative '../../update_test' + +module DaVinciDTRTestKit + class QuestionnaireResponseUpdateTest < Inferno::Test + include DaVinciDTRTestKit::UpdateTest + + title 'Server is capable of updating a QuestionnaireResponse resource from QuestionnaireResponse update interaction' + description 'A server SHALL support the QuestionnaireResponse update interaction' + + id :questionnaire_response_update + input :update_questionnaire_resources + + def resource_type + 'QuestionnaireResponse' + end + + run do + perform_update_test(update_questionnaire_resources, resource_type) + end + end +end diff --git a/lib/davinci_dtr_test_kit/profiles/task/task_create.rb b/lib/davinci_dtr_test_kit/profiles/task/task_create.rb new file mode 100644 index 0000000..aa56610 --- /dev/null +++ b/lib/davinci_dtr_test_kit/profiles/task/task_create.rb @@ -0,0 +1,21 @@ +require_relative '../../create_test' + +module DaVinciDTRTestKit + class TaskCreateTest < Inferno::Test + include DaVinciDTRTestKit::CreateTest + + title 'Server is capable of creating a Task resource from Task create interaction' + description 'A server SHOULD support the Task create interaction' + + id :task_create + input :create_task_resources + + def resource_type + 'Task' + end + + run do + perform_create_test(create_task_resources, resource_type) + end + end +end diff --git a/lib/davinci_dtr_test_kit/profiles/task/task_update.rb b/lib/davinci_dtr_test_kit/profiles/task/task_update.rb new file mode 100644 index 0000000..bb7f88d --- /dev/null +++ b/lib/davinci_dtr_test_kit/profiles/task/task_update.rb @@ -0,0 +1,21 @@ +require_relative '../../update_test' + +module DaVinciDTRTestKit + class TaskUpdateTest < Inferno::Test + include DaVinciDTRTestKit::UpdateTest + + title 'Server is capable of updating a Task resource from Task update interaction' + description 'A server SHOULD support the Task update interaction' + + id :task_update + input :update_task_resources + + def resource_type + 'Task' + end + + run do + perform_update_test(update_task_resources, resource_type) + end + end +end diff --git a/lib/davinci_dtr_test_kit/update_test.rb b/lib/davinci_dtr_test_kit/update_test.rb new file mode 100644 index 0000000..5be2641 --- /dev/null +++ b/lib/davinci_dtr_test_kit/update_test.rb @@ -0,0 +1,24 @@ +module DaVinciDTRTestKit + module UpdateTest + def perform_update_test(update_resources, resource_type) + assert_valid_json(update_resources) + update_resources_list = JSON.parse(update_resources) + skip_if(!update_resources_list.is_a?(Array), 'Resources to update not inputted in list format, skipping test.') + + valid_update_resources = + update_resources_list + .compact_blank + .map { |resource| FHIR.from_contents(resource.to_json) } + .select { |resource| resource.resourceType == resource_type } + .select { |resource| resource_is_valid?(resource:) } + + skip_if(valid_update_resources.blank?, + %(No valid #{resource_type} resources were provided to send in Update requests, skipping test.)) + + valid_update_resources.each do |update_resource| + fhir_update(update_resource, update_resource.id) + assert_response_status([200, 201]) + end + end + end +end diff --git a/spec/davinci_dtr_test_kit/create_test_spec.rb b/spec/davinci_dtr_test_kit/create_test_spec.rb new file mode 100644 index 0000000..ec62389 --- /dev/null +++ b/spec/davinci_dtr_test_kit/create_test_spec.rb @@ -0,0 +1,175 @@ +RSpec.describe DaVinciDTRTestKit::CreateTest do + let(:validator_url) { ENV.fetch('FHIR_RESOURCE_VALIDATOR_URL') } + let(:suite) { Inferno::Repositories::TestSuites.new.find('dtr_light_ehr') } + let(:session_data_repo) { Inferno::Repositories::SessionData.new } + let(:test_session) { repo_create(:test_session, test_suite_id: suite.id) } + let(:server_endpoint) { 'http://example.com' } + + def run(runnable, inputs = {}) + test_run_params = { test_session_id: test_session.id }.merge(runnable.reference_hash) + test_run = Inferno::Repositories::TestRuns.new.create(test_run_params) + inputs.each do |name, value| + session_data_repo.save( + test_session_id: test_session.id, + name:, + value:, + type: runnable.config.input_type(name) + ) + end + Inferno::TestRunner.new(test_session:, test_run:).run(runnable) + end + + describe 'Behavior of create test' do + let(:create_test) do + Class.new(Inferno::Test) do + include DaVinciDTRTestKit::CreateTest + + fhir_resource_validator do + url ENV.fetch('FHIR_RESOURCE_VALIDATOR_URL', 'http://hl7_validator_service:3500') + + cli_context do + txServer nil + displayWarnings true + disableDefaultResourceFetcher true + end + + igs('hl7.fhir.us.davinci-dtr', 'hl7.fhir.us.core') + end + + fhir_client do + url :server_endpoint + end + + input :server_endpoint + input :create_resources + + def resource_type + 'QuestionnaireResponse' + end + + run do + perform_create_test(create_resources, resource_type) + end + end + end + + let(:operation_outcome_success) do + { + outcomes: [{ + issues: [] + }], + sessionId: 'b8cf5547-1dc7-4714-a797-dc2347b93fe2' + } + end + + let(:operation_outcome_failure) do + { + outcomes: [{ + issues: [{ + level: 'ERROR' + }] + }], + sessionId: 'b8cf5547-1dc7-4714-a797-dc2347b93fe2' + } + end + + let(:create_resources) do + JSON.parse( + File.read(File.join( + __dir__, '..', 'fixtures', 'questionnaire_response_create_update_example.json' + )) + ) + end + + let(:encounter_resources) do + [FHIR::Encounter.new( + status: 'finished', + period: { + start: '2021-12-08T16:35:11.000Z', + end: '2022-02-07T17:51:00.000Z' + }, + subject: { + reference: 'Patient/pat001' + } + )].to_json + end + + before do + Inferno::Repositories::Tests.new.insert(create_test) + end + + it 'passes if a 201 is received' do + validation_request = stub_request(:post, "#{validator_url}/validate") + .to_return(status: 200, body: operation_outcome_success.to_json) + questionnaire_response_create_request = stub_request(:post, "#{server_endpoint}/QuestionnaireResponse") + .to_return(status: 201, body: create_resources.to_json) + + result = run(create_test, create_resources: create_resources.to_json, server_endpoint:) + expect(result.result).to eq('pass') + expect(validation_request).to have_been_made + expect(questionnaire_response_create_request).to have_been_made + end + + it 'fails if the json is invalid' do + result = run(create_test, create_resources: '[[', server_endpoint:) + expect(result.result).to eq('fail') + end + + it 'skips if the create_resources input is not an Array' do + result = run(create_test, create_resources: create_resources[0].to_json, server_endpoint:) + expect(result.result).to eq('skip') + expect(result.result_message).to eq( + 'Resources to create not inputted in list format, skipping test.' + ) + end + + it 'skips if create_resources input is empty' do + result = run(create_test, create_resources: [], server_endpoint:) + expect(result.result).to eq('skip') + expect(result.result_message).to eq( + "Input 'create_resources' is nil, skipping test." + ) + end + + it 'skips if empty resource json is inputted' do + result = run(create_test, create_resources: [{}].to_json, server_endpoint:) + expect(result.result).to eq('skip') + expect(result.result_message).to eq( + 'No valid QuestionnaireResponse resources were provided to send in Create requests, skipping test.' + ) + end + + it 'skips if inputted resource is the wrong resource type' do + result = run(create_test, create_resources: encounter_resources, server_endpoint:) + expect(result.result).to eq('skip') + expect(result.result_message).to eq( + 'No valid QuestionnaireResponse resources were provided to send in Create requests, skipping test.' + ) + end + + it 'skips if passed in QuestionnaireResponse resource is invalid' do + validation_request = stub_request(:post, "#{validator_url}/validate") + .to_return(status: 200, body: operation_outcome_failure.to_json) + + result = run(create_test, create_resources: create_resources.to_json, server_endpoint:) + expect(result.result).to eq('skip') + expect(result.result_message).to eq( + 'No valid QuestionnaireResponse resources were provided to send in Create requests, skipping test.' + ) + expect(validation_request).to have_been_made + end + + it 'fails if QuestionnaireResponse creation interaction returns non 201' do + validation_request = stub_request(:post, "#{validator_url}/validate") + .to_return(status: 200, body: operation_outcome_success.to_json) + questionnaire_response_create_request = stub_request(:post, "#{server_endpoint}/QuestionnaireResponse") + .to_return(status: 400) + + result = run(create_test, create_resources: create_resources.to_json, server_endpoint:) + expect(result.result).to eq('fail') + expect(result.result_message).to eq('Unexpected response status: expected 201, but received 400') + expect(validation_request).to have_been_made + expect(questionnaire_response_create_request).to have_been_made + end + end +end diff --git a/spec/davinci_dtr_test_kit/update_test_spec.rb b/spec/davinci_dtr_test_kit/update_test_spec.rb new file mode 100644 index 0000000..fae7985 --- /dev/null +++ b/spec/davinci_dtr_test_kit/update_test_spec.rb @@ -0,0 +1,191 @@ +RSpec.describe DaVinciDTRTestKit::UpdateTest do + let(:validator_url) { ENV.fetch('FHIR_RESOURCE_VALIDATOR_URL') } + let(:suite) { Inferno::Repositories::TestSuites.new.find('dtr_light_ehr') } + let(:session_data_repo) { Inferno::Repositories::SessionData.new } + let(:test_session) { repo_create(:test_session, test_suite_id: suite.id) } + let(:server_endpoint) { 'http://example.com' } + + def run(runnable, inputs = {}) + test_run_params = { test_session_id: test_session.id }.merge(runnable.reference_hash) + test_run = Inferno::Repositories::TestRuns.new.create(test_run_params) + inputs.each do |name, value| + session_data_repo.save( + test_session_id: test_session.id, + name:, + value:, + type: runnable.config.input_type(name) + ) + end + Inferno::TestRunner.new(test_session:, test_run:).run(runnable) + end + + describe 'behavior of update test' do + let(:update_test) do + Class.new(Inferno::Test) do + include DaVinciDTRTestKit::UpdateTest + + fhir_resource_validator do + url ENV.fetch('FHIR_RESOURCE_VALIDATOR_URL', 'http://hl7_validator_service:3500') + + cli_context do + txServer nil + displayWarnings true + disableDefaultResourceFetcher true + end + + igs('hl7.fhir.us.davinci-dtr', 'hl7.fhir.us.core') + end + + fhir_client do + url :server_endpoint + end + + input :server_endpoint + input :update_resources + + def resource_type + 'QuestionnaireResponse' + end + + run do + perform_update_test(update_resources, resource_type) + end + end + end + + let(:operation_outcome_success) do + { + outcomes: [{ + issues: [] + }], + sessionId: 'b8cf5547-1dc7-4714-a797-dc2347b93fe2' + } + end + + let(:operation_outcome_failure) do + { + outcomes: [{ + issues: [{ + level: 'ERROR' + }] + }], + sessionId: 'b8cf5547-1dc7-4714-a797-dc2347b93fe2' + } + end + + let(:update_resources) do + JSON.parse( + File.read(File.join( + __dir__, '..', 'fixtures', 'questionnaire_response_create_update_example.json' + )) + ) + end + + let(:encounter_resources) do + [FHIR::Encounter.new( + status: 'finished', + period: { + start: '2021-12-08T16:35:11.000Z', + end: '2022-02-07T17:51:00.000Z' + }, + subject: { + reference: 'Patient/pat001' + } + )].to_json + end + + let(:update_resource_id) { 'home-o2-questionnaireresponse' } + + before do + Inferno::Repositories::Tests.new.insert(update_test) + end + + it 'passes if a 200 is received' do + validation_request = stub_request(:post, "#{validator_url}/validate") + .to_return(status: 200, body: operation_outcome_success.to_json) + questionnaire_response_update_request = + stub_request(:put, "#{server_endpoint}/QuestionnaireResponse/#{update_resource_id}") + .to_return(status: 200, body: update_resources.to_json) + + result = run(update_test, update_resources: update_resources.to_json, server_endpoint:) + expect(result.result).to eq('pass') + expect(validation_request).to have_been_made + expect(questionnaire_response_update_request).to have_been_made + end + + it 'passes if a 201 is received' do + validation_request = stub_request(:post, "#{validator_url}/validate") + .to_return(status: 200, body: operation_outcome_success.to_json) + questionnaire_response_update_request = + stub_request(:put, "#{server_endpoint}/QuestionnaireResponse/#{update_resource_id}") + .to_return(status: 201, body: update_resources.to_json) + + result = run(update_test, update_resources: update_resources.to_json, server_endpoint:) + expect(result.result).to eq('pass') + expect(validation_request).to have_been_made + expect(questionnaire_response_update_request).to have_been_made + end + + it 'fails if the json is invalid' do + result = run(update_test, update_resources: '[[', server_endpoint:) + expect(result.result).to eq('fail') + end + + it 'skips if the update_resources input is not an Array' do + result = run(update_test, update_resources: update_resources[0].to_json, server_endpoint:) + expect(result.result).to eq('skip') + expect(result.result_message).to eq( + 'Resources to update not inputted in list format, skipping test.' + ) + end + + it 'skips if update_resources input is empty' do + result = run(update_test, update_resources: [], server_endpoint:) + expect(result.result).to eq('skip') + expect(result.result_message).to eq( + "Input 'update_resources' is nil, skipping test." + ) + end + + it 'skips if empty resource json is inputted' do + result = run(update_test, update_resources: [{}].to_json, server_endpoint:) + expect(result.result).to eq('skip') + expect(result.result_message).to eq( + 'No valid QuestionnaireResponse resources were provided to send in Update requests, skipping test.' + ) + end + + it 'skips if inputted resource is the wrong resource type' do + result = run(update_test, update_resources: encounter_resources, server_endpoint:) + expect(result.result).to eq('skip') + expect(result.result_message).to eq( + 'No valid QuestionnaireResponse resources were provided to send in Update requests, skipping test.' + ) + end + + it 'skips if passed in QuestionnaireResponse resource is invalid' do + validation_request = stub_request(:post, "#{validator_url}/validate") + .to_return(status: 200, body: operation_outcome_failure.to_json) + + result = run(update_test, update_resources: update_resources.to_json, server_endpoint:) + expect(result.result).to eq('skip') + expect(result.result_message).to eq( + 'No valid QuestionnaireResponse resources were provided to send in Update requests, skipping test.' + ) + expect(validation_request).to have_been_made + end + + it 'fails if QuestionnaireResponse creation interaction returns non 201/200' do + validation_request = stub_request(:post, "#{validator_url}/validate") + .to_return(status: 200, body: operation_outcome_success.to_json) + questionnaire_response_update_request = + stub_request(:put, "#{server_endpoint}/QuestionnaireResponse/#{update_resource_id}").to_return(status: 400) + + result = run(update_test, update_resources: update_resources.to_json, server_endpoint:) + expect(result.result).to eq('fail') + expect(result.result_message).to eq('Unexpected response status: expected 200, 201, but received 400') + expect(validation_request).to have_been_made + expect(questionnaire_response_update_request).to have_been_made + end + end +end diff --git a/spec/fixtures/questionnaire_response_create_update_example.json b/spec/fixtures/questionnaire_response_create_update_example.json new file mode 100644 index 0000000..6fd3b12 --- /dev/null +++ b/spec/fixtures/questionnaire_response_create_update_example.json @@ -0,0 +1,721 @@ +[ + { + "resourceType": "QuestionnaireResponse", + "id": "home-o2-questionnaireresponse", + "meta": { + "profile": [ + "http://hl7.org/fhir/us/davinci-dtr/StructureDefinition/dtr-questionnaireresponse" + ] + }, + "extension": [ + { + "url": "http://hl7.org/fhir/us/davinci-dtr/StructureDefinition/qr-context", + "valueReference": { + "reference": "Coverage/CoverageExample" + } + }, + { + "url": "http://hl7.org/fhir/us/davinci-dtr/StructureDefinition/qr-context", + "valueReference": { + "reference": "ServiceRequest/ServiceRequestExample" + } + }, + { + "url": "http://hl7.org/fhir/us/davinci-dtr/StructureDefinition/intendedUse", + "valueCodeableConcept": { + "coding": [ + { + "system": "http://hl7.org/fhir/us/davinci-crd/CodeSystem/temp", + "code": "withorder", + "display": "Include with order" + } + ] + } + } + ], + "questionnaire": "http://example.com/Questionnaire/referred-questionnaire", + "status": "completed", + "subject": { + "reference": "Patient/examplepatient", + "display": "Vlad" + }, + "authored": "2023-08-21", + "item": [ + { + "linkId": "1", + "text": "Patient Information", + "item": [ + { + "linkId": "1.1", + "text": "Last Name but Different This Time", + "answer": [ + { + "extension": [ + { + "extension": [ + { + "url": "source", + "valueCode": "override" + }, + { + "extension": [ + { + "url": "role", + "valueCodeableConcept": { + "coding": [ + { + "system": "http://terminology.hl7.org/CodeSystem/practitioner-role", + "code": "doctor", + "display": "Doctor" + } + ] + } + }, + { + "url": "practitioner", + "valueReference": { + "reference": "Practitioner/PractitionerExample", + "display": "Dr. Jane Doe" + } + } + ], + "url": "author" + } + ], + "url": "http://hl7.org/fhir/us/davinci-dtr/StructureDefinition/information-origin" + } + ], + "valueString": "Quinton" + } + ] + }, + { + "linkId": "1.2", + "text": "First Name", + "answer": [ + { + "extension": [ + { + "extension": [ + { + "url": "source", + "valueCode": "auto" + } + ], + "url": "http://hl7.org/fhir/us/davinci-dtr/StructureDefinition/information-origin" + } + ], + "valueString": "Vlad" + } + ] + }, + { + "linkId": "1.3", + "text": "Middle Initial", + "answer": [ + { + "extension": [ + { + "extension": [ + { + "url": "source", + "valueCode": "auto" + } + ], + "url": "http://hl7.org/fhir/us/davinci-dtr/StructureDefinition/information-origin" + } + ], + "valueString": "A, N" + } + ] + }, + { + "linkId": "1.4", + "text": "Date Of Birth", + "answer": [ + { + "extension": [ + { + "extension": [ + { + "url": "source", + "valueCode": "auto" + } + ], + "url": "http://hl7.org/fhir/us/davinci-dtr/StructureDefinition/information-origin" + } + ], + "valueDate": "1956-12-01" + } + ] + }, + { + "linkId": "1.5", + "text": "Gender", + "answer": [ + { + "extension": [ + { + "extension": [ + { + "url": "source", + "valueCode": "auto" + } + ], + "url": "http://hl7.org/fhir/us/davinci-dtr/StructureDefinition/information-origin" + } + ], + "valueCoding": { + "system": "http://hl7.org/fhir/administrative-gender", + "code": "male", + "display": "Male" + } + } + ] + }, + { + "linkId": "1.6", + "text": "Medicare ID", + "answer": [ + { + "extension": [ + { + "extension": [ + { + "url": "source", + "valueCode": "auto" + } + ], + "url": "http://hl7.org/fhir/us/davinci-dtr/StructureDefinition/information-origin" + } + ], + "valueString": "10A3D58WH22" + } + ] + } + ] + }, + { + "linkId": "2", + "text": "Provider who is performing face-to-face evaluation", + "item": [ + { + "linkId": "2.1", + "text": "Last Name", + "answer": [ + { + "extension": [ + { + "extension": [ + { + "url": "source", + "valueCode": "auto" + } + ], + "url": "http://hl7.org/fhir/us/davinci-dtr/StructureDefinition/information-origin" + } + ], + "valueString": "Doe" + } + ] + }, + { + "linkId": "2.2", + "text": "First Name", + "answer": [ + { + "extension": [ + { + "extension": [ + { + "url": "source", + "valueCode": "auto" + } + ], + "url": "http://hl7.org/fhir/us/davinci-dtr/StructureDefinition/information-origin" + } + ], + "valueString": "Jane" + } + ] + }, + { + "linkId": "2.3", + "text": "Middle Initial", + "answer": [ + { + "extension": [ + { + "extension": [ + { + "url": "source", + "valueCode": "auto" + } + ], + "url": "http://hl7.org/fhir/us/davinci-dtr/StructureDefinition/information-origin" + } + ], + "valueString": "B" + } + ] + }, + { + "linkId": "2.4", + "text": "NPI", + "answer": [ + { + "extension": [ + { + "extension": [ + { + "url": "source", + "valueCode": "auto" + } + ], + "url": "http://hl7.org/fhir/us/davinci-dtr/StructureDefinition/information-origin" + } + ], + "valueString": "1122334455" + } + ] + }, + { + "linkId": "2.5", + "text": "Date of Face-To-Face Evaluation", + "answer": [ + { + "extension": [ + { + "extension": [ + { + "url": "source", + "valueCode": "override" + }, + { + "extension": [ + { + "url": "role", + "valueCodeableConcept": { + "coding": [ + { + "system": "http://terminology.hl7.org/CodeSystem/practitioner-role", + "code": "doctor", + "display": "Doctor" + } + ] + } + }, + { + "url": "practitioner", + "valueReference": { + "reference": "Practitioner/PractitionerExample", + "display": "Dr. Jane Doe" + } + } + ], + "url": "author" + } + ], + "url": "http://hl7.org/fhir/us/davinci-dtr/StructureDefinition/information-origin" + } + ], + "valueDate": "2019-07-18" + } + ] + } + ] + }, + { + "linkId": "3", + "text": "Coverage Requirements", + "item": [ + { + "linkId": "3.1", + "text": "Relevant Patient Diagnoses (conditions that might be expected to improve with oxygen therapy)", + "answer": [ + { + "extension": [ + { + "extension": [ + { + "url": "source", + "valueCode": "auto" + } + ], + "url": "http://hl7.org/fhir/us/davinci-dtr/StructureDefinition/information-origin" + } + ], + "valueCoding": { + "system": "http://snomed.info/sct", + "code": "313296004", + "display": "Mild chronic obstructive pulmonary disease" + } + }, + { + "extension": [ + { + "extension": [ + { + "url": "source", + "valueCode": "auto" + } + ], + "url": "http://hl7.org/fhir/us/davinci-dtr/StructureDefinition/information-origin" + } + ], + "valueCoding": { + "system": "http://snomed.info/sct", + "code": "389087006", + "display": "Hypoxemia (disorder)" + } + } + ] + }, + { + "linkId": "3.2", + "text": "Arterial oxygen saturation (Patient on room air while at rest and awake when tested)", + "answer": [ + { + "extension": [ + { + "extension": [ + { + "url": "source", + "valueCode": "auto" + } + ], + "url": "http://hl7.org/fhir/us/davinci-dtr/StructureDefinition/information-origin" + } + ], + "valueQuantity": { + "value": 95, + "system": "http://unitsofmeasure.org", + "code": "mm[Hg]" + } + } + ] + }, + { + "linkId": "3.3", + "text": "Arterial Partial Pressure of Oxygen (PO2) (Patient on room air while at rest and awake when tested)", + "answer": [ + { + "extension": [ + { + "extension": [ + { + "url": "source", + "valueCode": "auto" + } + ], + "url": "http://hl7.org/fhir/us/davinci-dtr/StructureDefinition/information-origin" + } + ], + "valueQuantity": { + "value": 83, + "system": "http://unitsofmeasure.org", + "code": "mm[Hg]" + } + } + ] + }, + { + "linkId": "3.4", + "text": "Arterial oxygen saturation (Patient tested during exercise)", + "answer": [ + { + "extension": [ + { + "extension": [ + { + "url": "source", + "valueCode": "auto" + } + ], + "url": "http://hl7.org/fhir/us/davinci-dtr/StructureDefinition/information-origin" + } + ], + "valueQuantity": { + "value": 95, + "system": "http://unitsofmeasure.org", + "code": "mm[Hg]" + } + } + ] + }, + { + "linkId": "3.5", + "text": "Arterial Partial Pressure of Oxygen (PO2) (Patient tested during exercise)", + "answer": [ + { + "extension": [ + { + "extension": [ + { + "url": "source", + "valueCode": "auto" + } + ], + "url": "http://hl7.org/fhir/us/davinci-dtr/StructureDefinition/information-origin" + } + ], + "valueQuantity": { + "value": 78, + "system": "http://unitsofmeasure.org", + "code": "mm[Hg]" + } + } + ] + }, + { + "linkId": "3.6", + "text": "Is there a documented improvement of hypoxemia during exercise with oxygen?", + "answer": [ + { + "extension": [ + { + "extension": [ + { + "url": "source", + "valueCode": "auto" + } + ], + "url": "http://hl7.org/fhir/us/davinci-dtr/StructureDefinition/information-origin" + } + ], + "valueBoolean": true + } + ] + } + ] + }, + { + "linkId": "4", + "text": "Prescribed Use", + "item": [ + { + "linkId": "4.1", + "text": "Start date", + "answer": [ + { + "extension": [ + { + "extension": [ + { + "url": "source", + "valueCode": "auto" + } + ], + "url": "http://hl7.org/fhir/us/davinci-dtr/StructureDefinition/information-origin" + } + ], + "valueDate": "2019-07-18" + } + ] + }, + { + "linkId": "4.2", + "text": "Length of need: (months) (99 = lifetime)", + "answer": [ + { + "extension": [ + { + "extension": [ + { + "url": "source", + "valueCode": "auto" + } + ], + "url": "http://hl7.org/fhir/us/davinci-dtr/StructureDefinition/information-origin" + } + ], + "valueQuantity": { + "value": 99 + } + } + ] + }, + { + "linkId": "4.3", + "text": "Peak Flow Rate", + "item": [ + { + "linkId": "4.3.1", + "text": "LPM", + "answer": [ + { + "extension": [ + { + "extension": [ + { + "url": "source", + "valueCode": "auto" + } + ], + "url": "http://hl7.org/fhir/us/davinci-dtr/StructureDefinition/information-origin" + } + ], + "valueInteger": 2 + } + ] + }, + { + "linkId": "4.3.2", + "text": "oxygen %", + "answer": [ + { + "extension": [ + { + "extension": [ + { + "url": "source", + "valueCode": "auto" + } + ], + "url": "http://hl7.org/fhir/us/davinci-dtr/StructureDefinition/information-origin" + } + ], + "valueInteger": 98 + } + ] + } + ] + }, + { + "linkId": "4.4", + "text": "Average Flow Rate", + "item": [ + { + "linkId": "4.4.1", + "text": "LPM", + "answer": [ + { + "extension": [ + { + "extension": [ + { + "url": "source", + "valueCode": "auto" + } + ], + "url": "http://hl7.org/fhir/us/davinci-dtr/StructureDefinition/information-origin" + } + ], + "valueInteger": 2 + } + ] + }, + { + "linkId": "4.4.2", + "text": "oxygen %", + "answer": [ + { + "extension": [ + { + "extension": [ + { + "url": "source", + "valueCode": "auto" + } + ], + "url": "http://hl7.org/fhir/us/davinci-dtr/StructureDefinition/information-origin" + } + ], + "valueInteger": 97 + } + ] + } + ] + }, + { + "linkId": "4.5", + "text": "Frequency of use (choose all that apply)", + "answer": [ + { + "extension": [ + { + "extension": [ + { + "url": "source", + "valueCode": "auto" + } + ], + "url": "http://hl7.org/fhir/us/davinci-dtr/StructureDefinition/information-origin" + } + ] + } + ] + } + ] + }, + { + "linkId": "5", + "text": "Oxygen Supply Order Details", + "item": [ + { + "linkId": "5.1", + "text": "Current Order Description", + "answer": [ + { + "extension": [ + { + "extension": [ + { + "url": "source", + "valueCode": "auto" + } + ], + "url": "http://hl7.org/fhir/us/davinci-dtr/StructureDefinition/information-origin" + } + ], + "valueString": "HCPCS E0424 - Stationary Compressed Gaseous Oxygen System, Rental" + } + ] + }, + { + "linkId": "5.1b", + "text": "Current Order Is For A Portable Device" + }, + { + "linkId": "5.2", + "text": "Type", + "answer": [ + { + "extension": [ + { + "extension": [ + { + "url": "source", + "valueCode": "auto" + } + ], + "url": "http://hl7.org/fhir/us/davinci-dtr/StructureDefinition/information-origin" + } + ] + } + ] + }, + { + "linkId": "5.3", + "text": "Means of oxygen delivery and accessories", + "answer": [ + { + "extension": [ + { + "extension": [ + { + "url": "source", + "valueCode": "auto" + } + ], + "url": "http://hl7.org/fhir/us/davinci-dtr/StructureDefinition/information-origin" + } + ] + } + ] + } + ] + } + ] + } +]