davinci_dtr_test_kit 0.11.0 → 0.12.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (44) hide show
  1. checksums.yaml +4 -4
  2. data/lib/davinci_dtr_test_kit/auth_groups/token_request_test.rb +1 -1
  3. data/lib/davinci_dtr_test_kit/client_groups/dinner_static/dtr_full_ehr_dinner_questionnaire_package_request_test.rb +52 -0
  4. data/lib/davinci_dtr_test_kit/client_groups/dinner_static/dtr_full_ehr_launch_attestation_test.rb +28 -0
  5. data/lib/davinci_dtr_test_kit/client_groups/dinner_static/dtr_full_ehr_prepopulation_attestation_test.rb +30 -0
  6. data/lib/davinci_dtr_test_kit/client_groups/dinner_static/dtr_full_ehr_prepopulation_override_attestation_test.rb +27 -0
  7. data/lib/davinci_dtr_test_kit/client_groups/dinner_static/dtr_full_ehr_prepopulation_representation_attestation_test.rb +33 -0
  8. data/lib/davinci_dtr_test_kit/client_groups/dinner_static/dtr_full_ehr_questionnaire_workflow_group.rb +81 -0
  9. data/lib/davinci_dtr_test_kit/client_groups/dinner_static/dtr_full_ehr_rendering_enabled_questions_attestation_test.rb +30 -0
  10. data/lib/davinci_dtr_test_kit/client_groups/dinner_static/dtr_full_ehr_store_attestation_test.rb +29 -0
  11. data/lib/davinci_dtr_test_kit/client_groups/dinner_static/dtr_smart_app_dinner_questionnaire_package_request_test.rb +134 -0
  12. data/lib/davinci_dtr_test_kit/client_groups/dinner_static/{prepopulation_attestation_test.rb → dtr_smart_app_prepopulation_attestation_test.rb} +2 -2
  13. data/lib/davinci_dtr_test_kit/client_groups/dinner_static/{prepopulation_override_attestation_test.rb → dtr_smart_app_prepopulation_override_attestation_test.rb} +2 -2
  14. data/lib/davinci_dtr_test_kit/client_groups/dinner_static/{dtr_questionnaire_response_save_test.rb → dtr_smart_app_questionnaire_response_save_test.rb} +2 -2
  15. data/lib/davinci_dtr_test_kit/client_groups/dinner_static/dtr_smart_app_questionnaire_workflow_group.rb +13 -13
  16. data/lib/davinci_dtr_test_kit/client_groups/dinner_static/{rendering_enabled_questions_attestation_test.rb → dtr_smart_app_rendering_enabled_questions_attestation_test.rb} +2 -2
  17. data/lib/davinci_dtr_test_kit/client_groups/resp_assist_device/dtr_resp_questionnaire_package_request_test.rb +64 -27
  18. data/lib/davinci_dtr_test_kit/client_groups/shared/dtr_questionnaire_package_request_validation_test.rb +1 -1
  19. data/lib/davinci_dtr_test_kit/client_groups/shared/dtr_questionnaire_response_basic_conformance_test.rb +1 -1
  20. data/lib/davinci_dtr_test_kit/client_groups/shared/dtr_questionnaire_response_pre_population_test.rb +1 -0
  21. data/lib/davinci_dtr_test_kit/docs/dtr_full_ehr_suite_description_v201.md +127 -0
  22. data/lib/davinci_dtr_test_kit/docs/dtr_payer_server_suite_description_v201.md +2 -2
  23. data/lib/davinci_dtr_test_kit/dtr_full_ehr_suite.rb +4 -12
  24. data/lib/davinci_dtr_test_kit/dtr_questionnaire_response_validation.rb +2 -2
  25. data/lib/davinci_dtr_test_kit/dtr_smart_app_suite.rb +1 -1
  26. data/lib/davinci_dtr_test_kit/fixture_loader.rb +1 -1
  27. data/lib/davinci_dtr_test_kit/fixtures/dinner_adaptive/dinner_order_adaptive_next_question_hamburger.json +1 -1
  28. data/lib/davinci_dtr_test_kit/fixtures/dinner_static/questionnaire_dinner_order_static.json +1 -1
  29. data/lib/davinci_dtr_test_kit/mock_auth_server.rb +25 -15
  30. data/lib/davinci_dtr_test_kit/mock_ehr.rb +8 -3
  31. data/lib/davinci_dtr_test_kit/payer_server_groups/adaptive_next_questionnaire_expressions_test.rb +1 -1
  32. data/lib/davinci_dtr_test_kit/payer_server_groups/payer_server_adaptive_request_validation_test.rb +10 -19
  33. data/lib/davinci_dtr_test_kit/payer_server_groups/payer_server_adaptive_response_bundles_validation_test.rb +6 -6
  34. data/lib/davinci_dtr_test_kit/payer_server_groups/payer_server_adaptive_response_search_validation_test.rb +6 -6
  35. data/lib/davinci_dtr_test_kit/payer_server_groups/payer_server_adaptive_response_validation_test.rb +16 -18
  36. data/lib/davinci_dtr_test_kit/payer_server_groups/payer_server_next_request_validation_test.rb +6 -7
  37. data/lib/davinci_dtr_test_kit/payer_server_groups/payer_server_next_response_validation_test.rb +3 -1
  38. data/lib/davinci_dtr_test_kit/payer_server_groups/static_form_request_validation_test.rb +9 -20
  39. data/lib/davinci_dtr_test_kit/payer_server_groups/static_form_response_validation_test.rb +7 -14
  40. data/lib/davinci_dtr_test_kit/validation_test.rb +8 -9
  41. data/lib/davinci_dtr_test_kit/version.rb +1 -1
  42. data/lib/davinci_dtr_test_kit.rb +1 -1
  43. metadata +18 -9
  44. data/lib/davinci_dtr_test_kit/client_groups/dinner_static/dtr_dinner_questionnaire_package_request_test.rb +0 -97
@@ -10,39 +10,76 @@ module DaVinciDTRTestKit
10
10
  Inferno will wait for a DTR questionnaire package request from the client. Upon receipt, Inferno will generate and
11
11
  send a response.
12
12
  )
13
- input :smart_app_launch, type: 'radio', title: 'SMART App Launch',
14
- description: 'How will the DTR SMART App launch?',
15
- options: { list_options: [{ label: 'Launch from Inferno', value: 'inferno' },
16
- { label: 'Launch from EHR', value: 'ehr' }] }
13
+ input :smart_app_launch,
14
+ type: 'radio',
15
+ title: 'SMART App Launch',
16
+ description: 'How will the DTR SMART App launch?',
17
+ options: { list_options: [{ label: 'EHR Launch from Inferno', value: 'ehr' },
18
+ { label: 'Standalone Launch', value: 'standalone' }] }
17
19
  input :client_id
18
- input :launch_uri, optional: true, description: 'Required if "Launch from Inferno" is selected'
19
- input :smart_patient_id, optional: true, title: 'SMART App Launch Patient ID (Respiratory Assist Device)',
20
- type: 'text',
21
- description: %(
22
- Patient instance id to be provided by Inferno as the `patient` as a part of the SMART app
23
- launch.
24
- )
25
- input :smart_fhir_context, optional: true, title: 'SMART App Launch fhirContext (Respiratory Assist Device)',
26
- type: 'textarea',
27
- description: %(
28
- References to be provided by Inferno as the `fhirContext` as a part of the SMART app
29
- launch. These references help determine the behavior of the app. Referenced instances
30
- may be providedin the "EHR-available resources" input.
31
- )
32
- input :ehr_bundle, optional: true, title: 'EHR-available resources (Respiratory Assist Device)', type: 'textarea',
33
- description: %(
34
- Resources available from the EHR needed to drive the respiratory assist device
35
- workflow. Formatted as a FHIR bundle that contains resources, each with an `id`
36
- property populated. Each instance present will be available for retrieval from
37
- Inferno at the endpoint `[fhir-base]/[resource type]/[instance id].`
38
- )
20
+ input :launch_uri,
21
+ optional: true,
22
+ description: 'Required if "Launch from Inferno" is selected'
23
+ input :smart_patient_id,
24
+ optional: true,
25
+ title: 'SMART App Launch Patient ID (Respiratory Assist Device)',
26
+ type: 'text',
27
+ description: %(
28
+ Patient instance `id` to be provided by Inferno as the `patient` as a part of the SMART App
29
+ Launch.
30
+ ),
31
+ default: 'pat015'
32
+ input :smart_fhir_context,
33
+ optional: true,
34
+ title: 'SMART App Launch fhirContext (Respiratory Assist Device)',
35
+ type: 'textarea',
36
+ description: %(
37
+ References to be provided by Inferno as the `fhirContext` as a part of the SMART App
38
+ Launch. These references help determine the behavior of the app. Referenced instances
39
+ may be provided in the "EHR-available resources" input.
40
+ ),
41
+ default: JSON.pretty_generate([{ reference: 'Coverage/cov015' },
42
+ { reference: 'DeviceRequest/devreqe0470' }])
43
+ input :ehr_bundle,
44
+ optional: true,
45
+ title: 'EHR-available resources (Respiratory Assist Device)',
46
+ type: 'textarea',
47
+ description: %(
48
+ Resources available from the EHR needed to drive the respiratory assist device workflow.
49
+ Formatted as a FHIR bundle that contains resources, each with an `id` property populated. Each
50
+ instance present will be available for retrieval from Inferno at the endpoint
51
+
52
+ ```
53
+ [fhir-base]/[resource type]/[instance id]
54
+ ```
55
+ )
39
56
 
40
57
  def example_client_jwt_payload_part
41
58
  Base64.strict_encode64({ inferno_client_id: client_id }.to_json).delete('=')
42
59
  end
43
60
 
44
61
  run do
45
- launch_prompt = if smart_app_launch == 'inferno'
62
+ # validate relevant inputs and provide warnings if they are bad
63
+ warning do
64
+ if smart_fhir_context
65
+ assert_valid_json(smart_fhir_context,
66
+ 'The **SMART App Launch fhirContext** input is not valid JSON, so it will not be included in
67
+ the access token response.')
68
+ end
69
+ end
70
+
71
+ warning do
72
+ if ehr_bundle
73
+ assert_valid_json(ehr_bundle,
74
+ 'The **EHR-available resources** input is not valid JSON, so no tester-specified instances
75
+ will be available to access from Inferno.')
76
+ assert(FHIR.from_contents(ehr_bundle).is_a?(FHIR::Bundle),
77
+ 'The **EHR-available resources** input does not contain a FHIR Bundle, so no tester-specified instances
78
+ will be available to access from Inferno.')
79
+ end
80
+ end
81
+
82
+ launch_prompt = if smart_app_launch == 'ehr'
46
83
  %(Launch the DTR SMART App from Inferno by right clicking
47
84
  [this link](#{launch_uri}?iss=#{fhir_base_url}&launch=#{launch_uri})
48
85
  and selecting or "Open in new window" or "Open in new tab".)
@@ -58,7 +95,7 @@ module DaVinciDTRTestKit
58
95
 
59
96
  #{launch_prompt}
60
97
 
61
- #{inferno_prompt_cont if smart_app_launch == 'inferno'}
98
+ #{inferno_prompt_cont if smart_app_launch == 'ehr'}
62
99
 
63
100
  Then, Inferno will expect the SMART App to invoke the DTR Questionnaire Package operation by sending a POST
64
101
  request to
@@ -29,7 +29,7 @@ module DaVinciDTRTestKit
29
29
  assert input_params.present?, 'Request does not contain a recognized FHIR object'
30
30
  assert_resource_type(:parameters, resource: input_params)
31
31
  assert_valid_resource(resource: input_params,
32
- profile_url: 'http://hl7.org/fhir/us/davinci-dtr/StructureDefinition/dtr-qpackage-input-parameters')
32
+ profile_url: 'http://hl7.org/fhir/us/davinci-dtr/StructureDefinition/dtr-qpackage-input-parameters|2.0.1')
33
33
  end
34
34
  end
35
35
  end
@@ -22,7 +22,7 @@ module DaVinciDTRTestKit
22
22
  assert_resource_type(:questionnaire_response, resource: questionnaire_response)
23
23
 
24
24
  assert_valid_resource(resource: questionnaire_response,
25
- profile_url: 'http://hl7.org/fhir/us/davinci-dtr/StructureDefinition/dtr-questionnaireresponse')
25
+ profile_url: 'http://hl7.org/fhir/us/davinci-dtr/StructureDefinition/dtr-questionnaireresponse|2.0.1')
26
26
  end
27
27
  end
28
28
  end
@@ -21,6 +21,7 @@ module DaVinciDTRTestKit
21
21
  )
22
22
 
23
23
  run do
24
+ assert_valid_json(request.request_body)
24
25
  questionnaire_response = FHIR.from_contents(request.request_body)
25
26
  skip_if !questionnaire_response.present?, 'QuestionnaireResponse not received'
26
27
 
@@ -0,0 +1,127 @@
1
+ The Da Vinci DTR Test Kit Full EHR Suite validates the conformance of SMART apps
2
+ to the STU 2 version of the HL7® FHIR®
3
+ [Da Vinci Documentation Templates and Rules (DTR) Implementation Guide](https://hl7.org/fhir/us/davinci-dtr/STU2/).
4
+
5
+ ## Scope
6
+
7
+ These tests are a **DRAFT** intended to allow app implementers to perform
8
+ preliminary checks of their systems against DTR IG requirements and [provide
9
+ feedback](https://github.com/inferno-framework/davinci-dtr-test-kit/issues)
10
+ on the tests. Future versions of these tests may validate other
11
+ requirements and may change the test validation logic.
12
+
13
+ ## Test Methodology
14
+
15
+ Inferno will simulate a DTR payer server that will response to
16
+ requests for questionnaires for the EHR under test to interact with.
17
+ The EHR will be expected to initiate requests to Inferno to elicit responses. Over the
18
+ course of these interactions, Inferno will seek to observe conformant handling of
19
+ DTR workflows and requirements around the retrieval, completion, and storage of
20
+ questionnaires.
21
+
22
+ Tests within this suite are associated with specific questionnaires that the EHR will
23
+ demonstrate completion of. In each case, the EHR under test will initiate a request to
24
+ the payer server simulated by Inferno for a questionnaire using the
25
+ `$questionnaire-package` operation. Inferno will always return the specific questionnaire
26
+ for the test being executed regardless of the input provided by the EHR, though it must
27
+ be conformant. The EHR will then be asked to complete the questionnaire, including
28
+ - Pre-populating answers based on directives in the questionnaire
29
+ - Rendering the questionnaire for users and allowing them to make additional updates.
30
+ These tests can include specific directions on details to include in the completed
31
+ questionnaire.
32
+ - Storing the completed questionnaire for future use as a FHIR QuestionnaireResponse.
33
+
34
+ EHRs will be required to complete all questionnaires in the suite, which in aggregate
35
+ contain all questionnaire features that apps must support. Currently, the suite includes
36
+ one questionnaire:
37
+ 1. A fictious "dinner" questionnaire created for these tests. It tests basic
38
+ item rendering and pre-population.
39
+ Additional questionnaires will be added in the future.
40
+
41
+ All requests sent by the app will be checked
42
+ for conformance to the DTR IG requirements individually and used in aggregate to determine
43
+ whether required features and functionality are present. HL7® FHIR® resources are
44
+ validated with the Java validator using `tx.fhir.org` as the terminology server.
45
+
46
+ ## Running the Tests
47
+
48
+ ### Quick Start
49
+
50
+ In order to run these tests, EHRs must be configured to interact with Inferno's simulated
51
+ payer server endpoint. The endpoint will be `[URL prefix]/custom/dtr_full_ehr/fhir` where
52
+ `[URL prefix]` can be inferred from the URL of the test session which will be of the form
53
+ `[URL prefix]/dtr_full_ehr/[session id]`.
54
+
55
+ In order for Inferno to associate requests sent to locations under these base URLs with this session,
56
+ it needs to know the bearer token that the EHR will send on requests, for which
57
+ there are two options.
58
+
59
+ 1. If you want to choose your own bearer token, then
60
+ 1. Select the "2. Basic Workflows" test from the list on the left (or other target test).
61
+ 2. Click the '*Run All Tests*' button on the right.
62
+ 3. In the "access_token" field, enter the bearer token that will be sent by the client
63
+ under test (as part of the Authorization header - `Bearer <provided value>`).
64
+ 4. Click the '*Submit*' button at the bottom of the dialog.
65
+ 2. If you want to use a client_id to obtain an access token, then
66
+ 1. Click the '*Run All Tests*' button on the right.
67
+ 2. Provide the EHR's registered id "client_id" field of the input (NOTE, Inferno
68
+ doesn't support the registration API, so this must be obtained from another
69
+ system or configured manually).
70
+ 3. Click the '*Submit*' button at the bottom of the dialog.
71
+ 4. Make a token request that includes the specified client id to the
72
+ `[URL prefix]/custom/dtr_full_ehr/mock_auth/token` endpoint to get
73
+ an access token to use on the request of the requests.
74
+
75
+ In either case, the tests will continue from that point. Further executions of tests under
76
+ this session will also use the selected bearer token.
77
+
78
+ Note: authentication options for these tests have not been finalized and are subject to change.
79
+
80
+ ### Postman-based Demo
81
+
82
+ If you do not have a DTR Full EHR but would like to try the tests out, you can use
83
+ [this Postman collection](https://github.com/inferno-framework/davinci-dtr-test-kit/blob/main/config/DTR%20Full%20EHR%20Tests%20Postman%20Demo.postman_collection.json)
84
+ to make requests against Inferno. This does not include the capability to render and complete the
85
+ questionnaires, but does have samples of correctly and incorrectly completed QuestionnaireResponses.
86
+ To run the tests using this approach:
87
+
88
+ 1. Install [postman](https://www.postman.com/downloads/).
89
+ 1. Import [this Postman collection](https://github.com/inferno-framework/davinci-dtr-test-kit/blob/main/config/DTR%20Full%20EHR%20Tests%20Postman%20Demo.postman_collection.json).
90
+ 1. Start a Da Vinci DTR Full EHR Test Suite Session.
91
+ 1. Update the postman collection configuration variables found by opening the "DTR Full EHR
92
+ Tests Postman Demo" collection and selecting the "Variables" tab.
93
+ - **base_url**: corresponds to the where the test suite session is running. Defaults to
94
+ `inferno.healthit.gov`. If running in another location, see guidance on the "Overview" tab
95
+ of the postman collection.
96
+ - **access_token**: note the "Current value" (update if desired) for use later.
97
+ 1. Return to Inferno and in the test list at the left, select *2 Static Questionnaire Workflow*.
98
+ 1. Click the "Run All Tests" button in the upper right.
99
+ 1. Add the **access_token** configured in postman to the Inferno input with the same name
100
+ 1. Click the "Submit" button in Inferno.
101
+ 1. Attest that the EHR has launched its DTR workflow in Inferno by clicking the link for the **true** response.
102
+ 1. Once the next wait dialog has appeared within Inferno asking for a `$questionnaire-package`
103
+ request, use postman to submit the "Questionnaire Package for Dinner (Static)" request. Confirm
104
+ that the response that looks similar to the "Example Working Response" in postman
105
+ and click the link to continue the tests.
106
+ 1. Attest to the remainder of the tests as desired to get a sense for what is involved in testing
107
+ with an actual EHR implementation. To see what a valid QuestionnaireResponse looks like, see
108
+ the "Sample QuestionnaireResponse for Dinner (Static) ..." request in postman.
109
+
110
+ ## Limitations
111
+
112
+ The DTR IG is a complex specification and these tests currently validate conformance to only
113
+ a subset of IG requirements. Future versions of the test suite will test further
114
+ features. A few specific features of interest are listed below.
115
+
116
+ ### Heavy Reliance on Attestations
117
+
118
+ Currently, these test kits do not have access to the QuestionnaireResponse and so validation
119
+ that the EHR performed CQL calculations and generated a conformant QuestionnaireResponse
120
+ based on pre-population and manual answers is left to a user attestation rather than a
121
+ mechanical check. Some level of mechanical checks are expected to be added in the future.
122
+
123
+ ### Questionnaire Feature Coverage
124
+
125
+ Not all questionnaire features that are must support within the DTR IG are currently represented
126
+ in questionnaires tested by the IG. Adaptive questionnaires are a notable omission.
127
+ Additional questionnaires testing additional features will be added in the future.
@@ -81,9 +81,9 @@ If you would like to try out the tests but don't have a DTR payer server impleme
81
81
  you can run these tests against the DTR SMART Client test suite included in this test kit
82
82
  using the following steps:
83
83
  1. Start an Inferno session of the Da Vinci DTR SMART App Test Suite.
84
- 1. Select test 2.1.1 *Static Questionnaire Workflow* from the menu on the left.
84
+ 1. Select test 1.1.1 *Retrieving the Static Questionnaire* from the menu on the left.
85
85
  1. Click the "Run All Tests" button in the upper right.
86
- 1. In the "access_token" input, put `cnVuIHRvZ2V0aGVy`.
86
+ 1. In the "SMART App Launch" select `Standalone Launch` and in the "client_id" input, put `sample`.
87
87
  1. Click the "submit" button in the dialog that appears. The client tests will now be waiting for requests.
88
88
  1. Start an Inferno session of the DTR Payer Server test suite.
89
89
  1. Select test 1 *Static Questionnaire Package Retrieval* from the menu on the left.
@@ -1,7 +1,7 @@
1
1
  require_relative 'ext/inferno_core/runnable'
2
2
  require_relative 'ext/inferno_core/record_response_route'
3
3
  require_relative 'ext/inferno_core/request'
4
- require_relative 'client_groups/resp_assist_device/dtr_full_ehr_questionnaire_workflow_group'
4
+ require_relative 'client_groups/dinner_static/dtr_full_ehr_questionnaire_workflow_group'
5
5
  require_relative 'auth_groups/oauth2_authentication_group'
6
6
  require_relative 'mock_payer'
7
7
  require_relative 'version'
@@ -9,19 +9,11 @@ require_relative 'version'
9
9
  module DaVinciDTRTestKit
10
10
  class DTRFullEHRSuite < Inferno::TestSuite
11
11
  extend MockPayer
12
+ extend MockAuthServer
12
13
 
13
14
  id :dtr_full_ehr
14
15
  title 'Da Vinci DTR Full EHR Test Suite'
15
- description %(
16
- # Da Vinci DTR Full EHR Test Suite
17
-
18
- This suite validates that an EHR or other application can act
19
- as a full DTR application requesting questionnaires from a
20
- payer server and using local data to complete and store them.
21
- Inferno will act as payer server returning questionnaires
22
- in response to queries from the system under test and validating
23
- that they can be completed as expected.
24
- )
16
+ description File.read(File.join(__dir__, 'docs', 'dtr_full_ehr_suite_description_v201.md'))
25
17
 
26
18
  version VERSION
27
19
 
@@ -74,6 +66,6 @@ module DaVinciDTRTestKit
74
66
  end
75
67
 
76
68
  group from: :oauth2_authentication
77
- group from: :dtr_full_ehr_questionnaire_workflow
69
+ group from: :dtr_full_ehr_static_dinner_questionnaire_workflow
78
70
  end
79
71
  end
@@ -88,7 +88,7 @@ module DaVinciDTRTestKit
88
88
  end
89
89
 
90
90
  origin_extension = find_extension(target_item_answer,
91
- 'http://hl7.org/fhir/us/davinci-dtr/StructureDefinition/information-origin')
91
+ 'http://hl7.org/fhir/us/davinci-dtr/StructureDefinition/information-origin|2.0.1')
92
92
  source_extension = find_extension(origin_extension, 'source')
93
93
 
94
94
  unless source_extension.present?
@@ -134,7 +134,7 @@ module DaVinciDTRTestKit
134
134
 
135
135
  # check origin.source extension
136
136
  origin_extension = find_extension(answer,
137
- 'http://hl7.org/fhir/us/davinci-dtr/StructureDefinition/information-origin')
137
+ 'http://hl7.org/fhir/us/davinci-dtr/StructureDefinition/information-origin|2.0.1')
138
138
  source_extension = find_extension(origin_extension, 'source')
139
139
 
140
140
  if source_extension.present?
@@ -61,7 +61,7 @@ module DaVinciDTRTestKit
61
61
  DTRSmartAppSuite.extract_client_id_from_query_params(request)
62
62
  end
63
63
 
64
- record_response_route :post, EHR_AUTHORIZE_PATH, 'dtr_smart_app_authorize', method(:ehr_authorize),
64
+ record_response_route :post, EHR_AUTHORIZE_PATH, 'dtr_smart_app_ehr_authorize', method(:ehr_authorize),
65
65
  resumes: ->(_) { false } do |request|
66
66
  DTRSmartAppSuite.extract_client_id_from_form_params(request)
67
67
  end
@@ -23,7 +23,7 @@ module DaVinciDTRTestKit
23
23
  [
24
24
  'fixtures/dinner_static/questionnaire_dinner_order_static.json',
25
25
  'fixtures/dinner_static/questionnaire_response_dinner_order_static.json',
26
- ['dtr_smart_app_static_dinner_questionnaire_workflow']
26
+ ['dtr_smart_app_static_dinner_questionnaire_workflow', 'dtr_full_ehr_static_dinner_questionnaire_workflow']
27
27
  ],
28
28
  [
29
29
  'fixtures/dinner_adaptive/questionnaire_dinner_order_adaptive.json',
@@ -153,7 +153,7 @@
153
153
  },
154
154
  {
155
155
  "valueCoding": {
156
- "code": "Pickels"
156
+ "code": "Pickles"
157
157
  }
158
158
  },
159
159
  {
@@ -156,7 +156,7 @@
156
156
  },
157
157
  {
158
158
  "valueCoding": {
159
- "code": "Pickels"
159
+ "code": "Pickles"
160
160
  }
161
161
  },
162
162
  {
@@ -60,22 +60,20 @@ module DaVinciDTRTestKit
60
60
  token = JWT.encode({ inferno_client_id: client_id }, nil, 'none')
61
61
  response = { access_token: token, token_type: 'bearer', expires_in: 3600 }
62
62
  test_input = JSON.parse(test_result.input_json)
63
- smart_app_launch_input = test_input.find { |input| input['name'] == 'smart_app_launch' }
64
63
 
65
- if smart_app_launch_input.present? && smart_app_launch_input['value'] == 'inferno'
66
- fhir_context_input = test_input.find { |input| input['name'] == 'smart_fhir_context' }
67
- fhir_context_input_value = fhir_context_input['value'] if fhir_context_input.present?
68
- fhir_context = fhir_context_input_value || [
69
- { reference: 'Coverage/cov015' },
70
- { reference: 'DeviceRequest/devreqe0470' }
71
- ]
64
+ fhir_context_input = test_input.find { |input| input['name'] == 'smart_fhir_context' }
65
+ fhir_context_input_value = fhir_context_input['value'] if fhir_context_input.present?
66
+ begin
67
+ fhir_context = JSON.parse(fhir_context_input_value)
68
+ rescue StandardError
69
+ fhir_context = nil
70
+ end
71
+ response.merge!({ fhirContext: fhir_context }) if fhir_context
72
72
 
73
- smart_patient_input = test_input.find { |input| input['name'] == 'smart_patient_id' }
74
- smart_patient_input_value = smart_patient_input['value'] if smart_patient_input.present?
75
- smart_patient = smart_patient_input_value || 'pat015'
73
+ smart_patient_input = test_input.find { |input| input['name'] == 'smart_patient_id' }
74
+ smart_patient_input_value = smart_patient_input['value'] if smart_patient_input.present?
75
+ response.merge!({ patient: smart_patient_input_value }) if smart_patient_input_value
76
76
 
77
- response.merge!({ patient: smart_patient, fhirContext: fhir_context })
78
- end
79
77
  request.response_body = response.to_json
80
78
  request.response_headers = { 'Access-Control-Allow-Origin' => '*' }
81
79
  request.status = 200
@@ -102,7 +100,13 @@ module DaVinciDTRTestKit
102
100
  encoded_jwt = URI.decode_www_form(request.request_body).to_h['client_assertion']
103
101
  return unless encoded_jwt.present?
104
102
 
105
- jwt_payload = JWT.decode(encoded_jwt, nil, false)&.first # skip signature verification
103
+ jwt_payload =
104
+ begin
105
+ JWT.decode(encoded_jwt, nil, false)&.first # skip signature verification
106
+ rescue StandardError
107
+ nil
108
+ end
109
+
106
110
  jwt_payload['iss'] || jwt_payload['sub'] if jwt_payload.present?
107
111
  end
108
112
 
@@ -120,7 +124,13 @@ module DaVinciDTRTestKit
120
124
 
121
125
  def extract_client_id_from_bearer_token(request)
122
126
  token = extract_bearer_token(request)
123
- JWT.decode(token, nil, false)&.first&.dig('inferno_client_id')
127
+ jwt =
128
+ begin
129
+ JWT.decode(token, nil, false)
130
+ rescue StandardError
131
+ nil
132
+ end
133
+ jwt&.first&.dig('inferno_client_id')
124
134
  end
125
135
 
126
136
  # Header expected to be a bearer token of the form "Bearer: <token>"
@@ -49,9 +49,14 @@ module DaVinciDTRTestKit
49
49
  end
50
50
 
51
51
  # Respond with user-inputted resource if there is one that matches the request
52
- ehr_bundle_input = JSON.parse(test_result.input_json).find { |input| input['name'] == 'ehr_bundle' }
53
- ehr_bundle_input_value = ehr_bundle_input_value = ehr_bundle_input['value'] if ehr_bundle_input.present?
54
- ehr_bundle = FHIR.from_contents(ehr_bundle_input_value) if ehr_bundle_input_value.present?
52
+ begin
53
+ ehr_bundle_input = JSON.parse(test_result.input_json).find { |input| input['name'] == 'ehr_bundle' }
54
+ ehr_bundle_input_value = ehr_bundle_input_value = ehr_bundle_input['value'] if ehr_bundle_input.present?
55
+ ehr_bundle = FHIR.from_contents(ehr_bundle_input_value) if ehr_bundle_input_value.present?
56
+ rescue StandardError
57
+ ehr_bundle = nil
58
+ end
59
+
55
60
  if id.present? && ehr_bundle.present? && ehr_bundle.is_a?(FHIR::Bundle)
56
61
  matching_resource = ehr_bundle.entry&.find do |entry|
57
62
  entry.resource.is_a?(fhir_class) && entry.resource&.id == id
@@ -6,7 +6,7 @@ module DaVinciDTRTestKit
6
6
  id :dtr_v201_payer_adaptive_next_form_expressions_test
7
7
  title 'Questionnaire(s) contains items with expressions necessary for pre-population'
8
8
  description %(
9
- Inferno checks that the payer server response has appropriate expressions and that expressions are
9
+ Inferno checks that the payer server response to $next-question operation has appropriate expressions and that expressions are
10
10
  written in cql.
11
11
  )
12
12
 
@@ -3,7 +3,7 @@ module DaVinciDTRTestKit
3
3
  class PayerAdaptiveFormRequestTest < Inferno::Test
4
4
  include URLs
5
5
  include DaVinciDTRTestKit::ValidationTest
6
- title '[USER INPUT VALIDATION] Questionnaire Package request is valid'
6
+ title 'User Input Validation: Questionnaire Package request is valid'
7
7
  description %(
8
8
  This test validates the conformance of the client's request to the
9
9
  [DTR Questionnaire Package Input Parameters](http://hl7.org/fhir/us/davinci-dtr/StructureDefinition/dtr-qpackage-input-parameters)
@@ -13,32 +13,23 @@ module DaVinciDTRTestKit
13
13
  values. CodeableConcept element bindings will fail if none of their codings have a code/system belonging
14
14
  to the bound ValueSet. Quantity, Coding, and code element bindings will fail if their code/system are not found in
15
15
  the valueset.
16
-
17
- This test may process multiple resources, labeling messages with the corresponding tested resources
18
- in the order that they were received.
19
16
  )
20
17
  id :payer_server_adaptive_questionnaire_request_validation
21
18
 
22
19
  run do
23
20
  skip_if retrieval_method == 'Static', 'Performing only static flow tests - only one flow is required.'
21
+ profile_with_version = 'http://hl7.org/fhir/us/davinci-dtr/StructureDefinition/dtr-qpackage-input-parameters|2.0.1'
24
22
  if initial_adaptive_questionnaire_request.nil?
25
- resources = load_tagged_requests(QUESTIONNAIRE_TAG)
26
- using_manual_entry = false
23
+ requests = load_tagged_requests(QUESTIONNAIRE_TAG)
24
+ skip_if requests.blank?, 'No request resource received from the client.'
25
+ # making the assumption that only one request was made here - if there were multiple, we are only validating the first
26
+ resource_is_valid?(resource: FHIR.from_contents(requests[0].request[:body]), profile_url: profile_with_version)
27
27
  else
28
- resources = initial_adaptive_questionnaire_request
29
- using_manual_entry = true
28
+ request = FHIR.from_contents(initial_adaptive_questionnaire_request)
29
+ resource_is_valid?(resource: request, profile_url: profile_with_version)
30
30
  end
31
- skip_if resources.nil?, 'No request resources to validate.'
32
- perform_request_validation_test(
33
- resources,
34
- :parameters,
35
- 'http://hl7.org/fhir/us/davinci-dtr/StructureDefinition/dtr-qpackage-input-parameters',
36
- questionnaire_package_url,
37
- using_manual_entry
38
- )
39
- rescue Inferno::Exceptions::AssertionException => e
40
- msg = e.message.to_s.strip
41
- skip msg
31
+ errors_found = messages.any? { |message| message[:type] == 'error' }
32
+ skip_if errors_found, "Resource does not conform to the profile #{profile_with_version}"
42
33
  end
43
34
  end
44
35
  end
@@ -20,21 +20,21 @@ module DaVinciDTRTestKit
20
20
 
21
21
  run do
22
22
  skip_if retrieval_method == 'Static', 'Performing only static flow tests - only one flow is required.'
23
- test_passed = false
24
- profile_url = 'http://hl7.org/fhir/us/davinci-dtr/StructureDefinition/DTR-QPackageBundle'
23
+ test_passed = true
24
+ profile_url = 'http://hl7.org/fhir/us/davinci-dtr/StructureDefinition/DTR-QPackageBundle|2.0.1'
25
25
  assert !scratch[:adaptive_responses].nil?, 'No resources to validate.'
26
26
  scratch[:adaptive_responses].each_with_index do |resource, index|
27
27
  fhir_resource = FHIR.from_contents(resource.response[:body])
28
28
  fhir_resource.parameter.each do |param|
29
29
  resource_is_valid = validate_resource(param.resource, :bundle, profile_url, index)
30
- test_passed = true if resource_is_valid
30
+ test_passed = false unless resource_is_valid
31
31
  rescue StandardError
32
32
  next
33
33
  end
34
34
  end
35
- raise tests_failed[profile_url][0] if !test_passed && !tests_failed[profile_url].blank?
36
-
37
- messages.clear if test_passed
35
+ if !test_passed && !tests_failed[profile_url].blank?
36
+ assert test_passed, "Not all returned resources conform to the profile: #{profile_url}"
37
+ end
38
38
  end
39
39
  end
40
40
  end
@@ -20,23 +20,23 @@ module DaVinciDTRTestKit
20
20
 
21
21
  run do
22
22
  skip_if retrieval_method == 'Static', 'Performing only static flow tests - only one flow is required.'
23
- test_passed = false
24
- profile_url = 'http://hl7.org/fhir/us/davinci-dtr/StructureDefinition/dtr-questionnaire-adapt-search'
23
+ test_passed = true
24
+ profile_url = 'http://hl7.org/fhir/us/davinci-dtr/StructureDefinition/dtr-questionnaire-adapt-search|2.0.1'
25
25
  assert !scratch[:adaptive_responses].nil?, 'No resources to validate.'
26
26
  scratch[:adaptive_responses].each_with_index do |resource, index|
27
27
  fhir_resource = FHIR.from_contents(resource.response[:body])
28
28
  fhir_resource.parameter.each do |param|
29
29
  param.resource.entry.each do |entry|
30
30
  resource_is_valid = validate_resource(entry.resource, :questionnaire, profile_url, index)
31
- test_passed = true if resource_is_valid
31
+ test_passed = false unless resource_is_valid
32
32
  end
33
33
  rescue StandardError
34
34
  next
35
35
  end
36
36
  end
37
- raise tests_failed[profile_url][0] if !test_passed && !tests_failed[profile_url].blank?
38
-
39
- messages.clear if test_passed
37
+ if !test_passed && !tests_failed[profile_url].blank?
38
+ assert test_passed, "Not all returned resources conform to the profile: #{profile_url}"
39
+ end
40
40
  end
41
41
  end
42
42
  end