davinci_dtr_test_kit 0.16.0 → 0.16.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (76) hide show
  1. checksums.yaml +4 -4
  2. data/config/presets/full_ehr_postman_dinner_order_example.json.erb +41 -0
  3. data/config/presets/full_ehr_postman_respiratory_device_example.json +1 -1
  4. data/config/presets/smart_app_postman_dinner_order_example.json +8 -1
  5. data/config/presets/smart_app_postman_respiratory_device_example.json +1 -1
  6. data/lib/davinci_dtr_test_kit/certs/InfernoCA.key +52 -0
  7. data/lib/davinci_dtr_test_kit/certs/InfernoCA.pem +35 -0
  8. data/lib/davinci_dtr_test_kit/certs/TestKit.pem +32 -0
  9. data/lib/davinci_dtr_test_kit/certs/TestKitPrivateKey.key +28 -0
  10. data/lib/davinci_dtr_test_kit/client_groups/adaptive_questionnaire/custom/dtr_custom_next_question_response_validation_test.rb +95 -0
  11. data/lib/davinci_dtr_test_kit/client_groups/adaptive_questionnaire/custom/dtr_full_ehr_custom_adaptive_request_test.rb +87 -0
  12. data/lib/davinci_dtr_test_kit/client_groups/adaptive_questionnaire/custom/dtr_full_ehr_custom_adaptive_workflow_group.rb +136 -0
  13. data/lib/davinci_dtr_test_kit/client_groups/adaptive_questionnaire/custom/dtr_smart_app_custom_adaptive_request_test.rb +171 -0
  14. data/lib/davinci_dtr_test_kit/client_groups/adaptive_questionnaire/custom/dtr_smart_app_custom_adaptive_workflow_group.rb +146 -0
  15. data/lib/davinci_dtr_test_kit/client_groups/{dinner_adaptive → adaptive_questionnaire/dinner_order}/dtr_adaptive_next_question_retrieval_group.rb +3 -3
  16. data/lib/davinci_dtr_test_kit/client_groups/{dinner_adaptive → adaptive_questionnaire/dinner_order}/dtr_full_ehr_adaptive_dinner_workflow_group.rb +21 -11
  17. data/lib/davinci_dtr_test_kit/client_groups/{dinner_adaptive → adaptive_questionnaire/dinner_order}/dtr_full_ehr_adaptive_initial_retrieval_group.rb +6 -6
  18. data/lib/davinci_dtr_test_kit/client_groups/{dinner_adaptive → adaptive_questionnaire/dinner_order}/dtr_smart_app_adaptive_dinner_workflow_group.rb +5 -5
  19. data/lib/davinci_dtr_test_kit/client_groups/{dinner_adaptive → adaptive_questionnaire/dinner_order}/dtr_smart_app_adaptive_initial_retrieval_group.rb +5 -5
  20. data/lib/davinci_dtr_test_kit/client_groups/{dinner_adaptive → adaptive_questionnaire}/dtr_adaptive_next_question_request_test.rb +9 -24
  21. data/lib/davinci_dtr_test_kit/client_groups/{dinner_adaptive → adaptive_questionnaire}/dtr_adaptive_next_question_request_validation_test.rb +36 -17
  22. data/lib/davinci_dtr_test_kit/client_groups/adaptive_questionnaire/dtr_adaptive_response_validation_test.rb +130 -0
  23. data/lib/davinci_dtr_test_kit/client_groups/auth/dtr_client_payer_auth_smart_group.rb +29 -0
  24. data/lib/davinci_dtr_test_kit/client_groups/auth/dtr_client_payer_auth_udap_group.rb +29 -0
  25. data/lib/davinci_dtr_test_kit/client_groups/custom_static/dtr_full_ehr_custom_static_workflow_group.rb +15 -14
  26. data/lib/davinci_dtr_test_kit/client_groups/custom_static/dtr_smart_app_custom_static_workflow_group.rb +5 -5
  27. data/lib/davinci_dtr_test_kit/client_groups/dinner_static/dtr_full_ehr_static_dinner_workflow_group.rb +14 -10
  28. data/lib/davinci_dtr_test_kit/client_groups/dinner_static/dtr_smart_app_static_dinner_workflow_group.rb +1 -1
  29. data/lib/davinci_dtr_test_kit/client_groups/{dinner_adaptive → full_ehr}/dtr_full_ehr_adaptive_request_test.rb +11 -14
  30. data/lib/davinci_dtr_test_kit/client_groups/full_ehr/dtr_full_ehr_questionnaire_package_request_test.rb +9 -17
  31. data/lib/davinci_dtr_test_kit/client_groups/full_ehr/dtr_full_ehr_questionnaire_response_correctness_test.rb +10 -1
  32. data/lib/davinci_dtr_test_kit/client_groups/full_ehr/dtr_full_ehr_store_attestation_test.rb +3 -3
  33. data/lib/davinci_dtr_test_kit/client_groups/light_ehr/fhir_context_references_test.rb +4 -5
  34. data/lib/davinci_dtr_test_kit/client_groups/must_support/dtr_full_ehr_ms_questionnaire_package_request_test.rb +75 -0
  35. data/lib/davinci_dtr_test_kit/client_groups/must_support/dtr_full_ehr_questionnaire_must_support_group.rb +85 -0
  36. data/lib/davinci_dtr_test_kit/client_groups/must_support/dtr_must_support_attestation_test.rb +39 -0
  37. data/lib/davinci_dtr_test_kit/client_groups/must_support/dtr_questionnaire_must_support_test.rb +42 -0
  38. data/lib/davinci_dtr_test_kit/client_groups/must_support/dtr_smart_app_ms_questionnaire_package_request_test.rb +148 -0
  39. data/lib/davinci_dtr_test_kit/client_groups/must_support/dtr_smart_app_questionnaire_must_support_group.rb +85 -0
  40. data/lib/davinci_dtr_test_kit/client_groups/must_support/questionnaire_must_support_elements.rb +55 -0
  41. data/lib/davinci_dtr_test_kit/client_groups/payer_registration/configuration_display_smart_test.rb +35 -0
  42. data/lib/davinci_dtr_test_kit/client_groups/payer_registration/configuration_display_udap_test.rb +35 -0
  43. data/lib/davinci_dtr_test_kit/client_groups/payer_registration/dtr_client_registration_group.rb +48 -0
  44. data/lib/davinci_dtr_test_kit/client_groups/shared/dtr_custom_questionnaire_expressions_test.rb +36 -0
  45. data/lib/davinci_dtr_test_kit/client_groups/shared/dtr_custom_questionnaire_extensions_test.rb +32 -0
  46. data/lib/davinci_dtr_test_kit/client_groups/{custom_static → shared}/dtr_custom_questionnaire_libraries_test.rb +7 -2
  47. data/lib/davinci_dtr_test_kit/client_groups/{custom_static → shared}/dtr_custom_questionnaire_package_validation_test.rb +6 -2
  48. data/lib/davinci_dtr_test_kit/client_groups/shared/dtr_questionnaire_package_request_validation_test.rb +6 -2
  49. data/lib/davinci_dtr_test_kit/client_groups/shared/dtr_questionnaire_response_prepopulation_test.rb +7 -1
  50. data/lib/davinci_dtr_test_kit/client_groups/smart_app/dtr_smart_app_questionnaire_response_correctness_test.rb +4 -3
  51. data/lib/davinci_dtr_test_kit/descriptions.rb +8 -0
  52. data/lib/davinci_dtr_test_kit/docs/dtr_full_ehr_suite_description_v201.md +145 -78
  53. data/lib/davinci_dtr_test_kit/docs/dtr_smart_app_suite_description_v201.md +4 -3
  54. data/lib/davinci_dtr_test_kit/dtr_client_options.rb +13 -0
  55. data/lib/davinci_dtr_test_kit/dtr_full_ehr_suite.rb +47 -7
  56. data/lib/davinci_dtr_test_kit/dtr_questionnaire_response_validation.rb +33 -21
  57. data/lib/davinci_dtr_test_kit/dtr_smart_app_suite.rb +7 -4
  58. data/lib/davinci_dtr_test_kit/endpoints/mock_ehr.rb +1 -1
  59. data/lib/davinci_dtr_test_kit/endpoints/mock_payer/full_ehr_next_question_endpoint.rb +20 -1
  60. data/lib/davinci_dtr_test_kit/endpoints/mock_payer/full_ehr_questionnaire_package_endpoint.rb +21 -1
  61. data/lib/davinci_dtr_test_kit/endpoints/mock_payer/next_question_endpoint.rb +29 -4
  62. data/lib/davinci_dtr_test_kit/endpoints/mock_payer/questionnaire_package_endpoint.rb +1 -1
  63. data/lib/davinci_dtr_test_kit/endpoints/mock_udap_smart_server/token_endpoint.rb +36 -0
  64. data/lib/davinci_dtr_test_kit/requirements/davinci-dtr-test-kit_out_of_scope_requirements.csv +6 -5
  65. data/lib/davinci_dtr_test_kit/requirements/davinci-dtr-test-kit_requirements.csv +10 -9
  66. data/lib/davinci_dtr_test_kit/requirements/generated/davinci-dtr-test-kit_requirements_coverage.csv +21 -21
  67. data/lib/davinci_dtr_test_kit/urls.rb +21 -4
  68. data/lib/davinci_dtr_test_kit/version.rb +2 -2
  69. metadata +59 -21
  70. data/config/presets/full_ehr_postman_dinner_order_example_postman.json +0 -19
  71. data/lib/davinci_dtr_test_kit/client_groups/custom_static/dtr_custom_questionnaire_expressions_test.rb +0 -22
  72. data/lib/davinci_dtr_test_kit/client_groups/custom_static/dtr_custom_questionnaire_extensions_test.rb +0 -19
  73. data/lib/davinci_dtr_test_kit/client_groups/dinner_adaptive/dtr_adaptive_response_validation_test.rb +0 -68
  74. /data/lib/davinci_dtr_test_kit/client_groups/{dinner_adaptive → adaptive_questionnaire/dinner_order}/dtr_adaptive_completion_group.rb +0 -0
  75. /data/lib/davinci_dtr_test_kit/client_groups/{dinner_adaptive → adaptive_questionnaire/dinner_order}/dtr_adaptive_followup_questions_group.rb +0 -0
  76. /data/lib/davinci_dtr_test_kit/client_groups/{dinner_adaptive → smart_app}/dtr_smart_app_adaptive_request_test.rb +0 -0
@@ -0,0 +1,95 @@
1
+ module DaVinciDTRTestKit
2
+ class DTRCustomNextQuestionResponseValidationTest < Inferno::Test
3
+ id :dtr_custom_next_questionnaire_validation
4
+ title '[USER INPUT VERIFICATION] Custom Questionnaires for $next-question Responses are valid for this workflow'
5
+ description %(
6
+ Inferno will validate that the user-provided Questionnaire resources to be included in
7
+ each `$next-question` response are correct for this workflow.
8
+
9
+ The test verifies that:
10
+ 1. All provided Questionnaires have the same ID as the contained Questionnaire in the
11
+ `QuestionnaireResponse` of the `$next-question` request.
12
+ 2. Each provided Questionnaire includes all previously presented questions along with
13
+ the next question or set of questions.
14
+
15
+ If any of these conditions are not met, the test will fail.
16
+ )
17
+
18
+ input :custom_next_question_questionnaires,
19
+ title: 'Custom Questionnaire resources to include in each $next-question Response',
20
+ description: %(
21
+ Provide a JSON list of Questionnaire resources for Inferno to use when updating
22
+ the contained Questionnaire in the `QuestionnaireResponse` received in each
23
+ `$next-question` request.
24
+
25
+ Each `$next-question` request will correspond to the next item in the provided list,
26
+ and Inferno will replace the contained Questionnaire with the corresponding resource
27
+ before returning the updated `QuestionnaireResponse`.
28
+
29
+ The provided Questionnaires must contain the next question or set of questions in
30
+ sequence, ensuring a proper progression of the adaptive questionnaire workflow.
31
+ ),
32
+ type: 'textarea'
33
+
34
+ def next_request_tag
35
+ config.options[:next_tag]
36
+ end
37
+
38
+ def extract_link_ids(questionnaire_items)
39
+ questionnaire_items&.each_with_object([]) do |item, link_ids|
40
+ link_ids << item.linkId
41
+
42
+ link_ids.concat(extract_link_ids(item.item)) if item.item.present?
43
+ end
44
+ end
45
+
46
+ def validate_correctness_of_custom_next_questionnaire(custom_questionnaire, contained_questionnaire)
47
+ custom_items_link_ids = extract_link_ids(custom_questionnaire.item) || []
48
+ contained_items_link_ids = extract_link_ids(contained_questionnaire.item) || []
49
+ missing_items_ids = contained_items_link_ids - custom_items_link_ids
50
+
51
+ error_msg = %(
52
+ Custom Questionnaire must include all previous questions along with the next question or set of questions.
53
+ )
54
+ add_message('error', error_msg) if custom_items_link_ids.length <= contained_items_link_ids.length
55
+
56
+ error_msg = %(
57
+ Custom Questionnaire must include all previous questions. The following items are missing:
58
+ questions with Link ID `#{missing_items_ids.to_sentence}`.
59
+ )
60
+ add_message('error', error_msg) if missing_items_ids.present?
61
+ end
62
+
63
+ run do
64
+ load_tagged_requests next_request_tag
65
+ skip_if requests.blank?, 'A $next-question request must be made prior to running this test'
66
+ assert_valid_json custom_next_question_questionnaires, 'Custom $next-question Questionnaires is not valid JSON'
67
+
68
+ skip_if scratch[:contained_questionnaires].nil?, %(
69
+ Unable to validate user-provided Questionnaires: no valid `$next-question` requests
70
+ containing a Questionnaire were received.
71
+ )
72
+
73
+ custom_questionnaires = [JSON.parse(custom_next_question_questionnaires)].flatten
74
+ custom_questionnaires.each do |q|
75
+ custom_questionnaire = FHIR.from_contents(q.to_json)
76
+ assert custom_questionnaire, "The custom Questionnaire #{q[:id]} provided is not a valid FHIR resource"
77
+ assert_resource_type(:questionnaire, resource: custom_questionnaire)
78
+
79
+ contained_questionnaire = scratch[:contained_questionnaires].find { |cq| cq.id == custom_questionnaire.id }
80
+ assert contained_questionnaire, %(
81
+ Unable to validate the provided custom Questionnaire `#{q[:id]}`: no valid `$next-question` request
82
+ was found containing a Questionnaire with a matching ID.
83
+ )
84
+
85
+ validate_correctness_of_custom_next_questionnaire(custom_questionnaire, contained_questionnaire)
86
+ rescue Inferno::Exceptions::AssertionException => e
87
+ add_message('error', "Questionnaire `#{q[:id]}`: #{e.message}")
88
+ next
89
+ end
90
+
91
+ assert messages.none? { |message| message[:type] == 'error' },
92
+ 'Custom Questionnaire provided is not valid for this workflow'
93
+ end
94
+ end
95
+ end
@@ -0,0 +1,87 @@
1
+ require_relative '../../../descriptions'
2
+ require_relative '../../../urls'
3
+
4
+ module DaVinciDTRTestKit
5
+ class DTRFullEHRCustomAdaptiveRequestTest < Inferno::Test
6
+ include URLs
7
+
8
+ id :dtr_full_ehr_custom_adative_request
9
+ title 'Client can complete the DTR Adaptive Questionnaire workflow'
10
+ description %(
11
+ This test waits for client requests to retrieve and progress through an adaptive questionnaire workflow.
12
+
13
+ 1. **Questionnaire Package Request**: The client should invoke the `$questionnaire-package` operation
14
+ to retrieve the adaptive questionnaire package. Inferno will respond with the user-provided
15
+ empty adaptive questionnaire.
16
+
17
+ 2. **Next Question Requests**: The client should invoke the `$next-question` operation to request
18
+ the next set of questions. Inferno will respond sequentially with the next Questionnaire from
19
+ the user-provided list. If a `$next-question` request is received when the list is empty,
20
+ Inferno will mark the `QuestionnaireResponse` as completed.
21
+ )
22
+ verifies_requirements 'hl7.fhir.us.davinci-dtr_2.0.1@165', 'hl7.fhir.us.davinci-dtr_2.0.1@262',
23
+ 'hl7.fhir.us.davinci-dtr_2.0.1@264'
24
+
25
+ config options: { accepts_multiple_requests: true }
26
+
27
+ input :custom_questionnaire_package_response, :custom_next_question_questionnaires
28
+ input :client_id,
29
+ title: 'Client Id',
30
+ type: 'text',
31
+ optional: true,
32
+ locked: true,
33
+ description: INPUT_CLIENT_ID_LOCKED
34
+
35
+ run do
36
+ assert_valid_json(
37
+ custom_questionnaire_package_response,
38
+ 'Custom questionnaire package response is not a valid json'
39
+ )
40
+ assert_valid_json(custom_next_question_questionnaires, 'Custom next questionnaires input is not a valid json')
41
+
42
+ custom_qp = JSON.parse(custom_questionnaire_package_response)
43
+ custom_questionnaires = JSON.parse(custom_next_question_questionnaires)
44
+ assert custom_qp.present?, %(
45
+ Custom questionnaire package response is empty, please provide a custom questionnaire package response
46
+ for the $questionnaire-package request
47
+ )
48
+ assert custom_questionnaires.present?, %(
49
+ 'Custom questionnaires list is empty, please provide a list of Custom Questionnaire resources
50
+ to include in each $next-question Response.
51
+ )
52
+
53
+ wait(
54
+ identifier: client_id,
55
+ message: %(
56
+ ### Adaptive Questionnaire Workflow
57
+
58
+ 1. **Questionnaire Package Request**:
59
+ - Invoke the `$questionnaire-package` operation by sending a POST request to the following endpoint
60
+ to retrieve the adaptive questionnaire package:
61
+
62
+ `#{questionnaire_package_url}`
63
+
64
+ - Inferno will respond with the user-provided empty adaptive questionnaire.
65
+
66
+ 2. **Next Question Requests**:
67
+ - After receiving the questionnaire package, invoke the `$next-question` operation by sending
68
+ a POST request to the following endpoint:
69
+
70
+ `#{next_url}`
71
+
72
+ - Repeat this request **multiple times**, once for each Questionnaire provided in the user-supplied list.
73
+ - Inferno will sequentially respond with the corresponding Questionnaire from the list.
74
+ - If a `$next-question` request is received when the list is empty, Inferno will mark
75
+ the `QuestionnaireResponse` as completed.
76
+
77
+ Inferno will wait for all expected requests to be made.
78
+
79
+ ### Continuing the Tests
80
+
81
+ Once all required `$next-question` requests have been made,
82
+ [Click here](#{resume_pass_url}?token=#{client_id}) to continue.
83
+ )
84
+ )
85
+ end
86
+ end
87
+ end
@@ -0,0 +1,136 @@
1
+ require_relative '../../../tags'
2
+ require_relative '../../full_ehr/dtr_full_ehr_launch_attestation_test'
3
+ require_relative 'dtr_full_ehr_custom_adaptive_request_test'
4
+ require_relative '../../shared/dtr_questionnaire_package_request_validation_test'
5
+ require_relative '../dtr_adaptive_next_question_request_validation_test'
6
+ require_relative '../dtr_adaptive_response_validation_test'
7
+ require_relative '../../shared/dtr_custom_questionnaire_package_validation_test'
8
+ require_relative '../../shared/dtr_custom_questionnaire_libraries_test'
9
+ require_relative 'dtr_custom_next_question_response_validation_test'
10
+ require_relative '../../shared/dtr_custom_questionnaire_extensions_test'
11
+ require_relative '../../shared/dtr_custom_questionnaire_expressions_test'
12
+ require_relative '../../shared/dtr_prepopulation_attestation_test'
13
+ require_relative '../../shared/dtr_prepopulation_override_attestation_test'
14
+ require_relative '../../full_ehr/dtr_full_ehr_store_attestation_test'
15
+
16
+ module DaVinciDTRTestKit
17
+ class DTRFullEHRCustomAdaptiveWorkflowGroup < Inferno::TestGroup
18
+ id :dtr_full_ehr_custom_adaptive_workflow
19
+ title 'Adaptive Questionnaire Workflow'
20
+ description %(
21
+ This group validates that a DTR Full EHR client can perform a full DTR Adaptive Questionnaire workflow.
22
+ Testers will provide a custom adaptive Questionnaire package for the test, along with a list
23
+ (JSON array) of Questionnaires to be included in each `$next-question` response.
24
+
25
+ As part of this workflow, the Full EHR system must demonstrate its ability to:
26
+
27
+ 1. Request the Questionnaire using the `$questionnaire-package` operation.
28
+ 2. Support the tester in completing the questionnaire through multiple `$next-question` interactions, including:
29
+ - Rendering the questionnaire.
30
+ - Pre-populating answers into the questionnaire.
31
+ - Allowing the tester to manually enter responses, including overriding pre-populated answers.
32
+ 3. Complete and store the `QuestionnaireResponse` for future use.
33
+
34
+ Inferno will process `$next-question` requests dynamically:
35
+ - Each request will receive the next Questionnaire from the provided list.
36
+ - If a `$next-question` request is received when the list is empty, Inferno will mark
37
+ the `QuestionnaireResponse` as completed.
38
+
39
+ At least two answers should be pre-populated across all sets of questions.
40
+ )
41
+ run_as_group
42
+ config(
43
+ options: { form_type: 'adaptive', next_tag: "custom_#{CLIENT_NEXT_TAG}" },
44
+ inputs: {
45
+ custom_questionnaire_package_response: {
46
+ name: 'adaptive_custom_questionnaire_package_response',
47
+ title: 'Custom Questionnaire Package Response JSON for Adaptive form',
48
+ description: %(
49
+ A JSON PackageBundle may be provided here to replace Inferno's response to
50
+ the $questionnaire-package request. Note: Ensure that the questionnaire package
51
+ has an empty Adaptive Questionnaire.
52
+ )
53
+ }
54
+ }
55
+ )
56
+
57
+ group do
58
+ id :dtr_full_ehr_custom_adaptive_retrieval
59
+ title 'Retrieving the Adaptive Questionnaire'
60
+
61
+ # Test 0: attest to launch
62
+ test from: :dtr_full_ehr_launch_attest,
63
+ config: {
64
+ options: {
65
+ attestation_message: 'I attest that DTR has been launched in the context of a patient with data that will exercise pre-population logic in the provided static questionnaire resulting in at least 2 pre-populated answers.' # rubocop:disable Layout/LineLength
66
+ }
67
+ },
68
+ title: 'Launch DTR (Attestation)'
69
+ # Test 1: Recieve questionnaire-package and next-question requests
70
+ test from: :dtr_full_ehr_custom_adative_request
71
+ # Test 2: validate the $questionnaire-package request body
72
+ test from: :dtr_qp_request_validation
73
+ # Test 3: validate the $next-question requests body
74
+ test from: :dtr_adaptive_next_question_request_validation
75
+ # Test 4: validate the QuestionnaireResponse in the input parameter
76
+ test from: :dtr_adaptive_response_validation do
77
+ description %(
78
+ Verify that all submitted QuestionnaireResponse resources meet the following criteria:
79
+ - Conform to the [SDCQuestionnaireResponseAdapt](http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaireresponse-adapt).
80
+ - Include source extensions indicating whether answers were manually entered,
81
+ automatically pre-populated, or manually overridden (for `completed` QuestionnaireResponse).
82
+ - Provide answers for all required items in their contained Questionnaire.
83
+ )
84
+ input :custom_next_question_questionnaires
85
+ end
86
+ # Test 5: validate the user provided $questionnaire-package response
87
+ test from: :dtr_custom_qp_validation
88
+ # Test 6: verify the custom response has the necessary libraries for pre-population
89
+ test from: :dtr_custom_questionnaire_libraries
90
+ # Test 7: validate the user provided $next-question questionnaires
91
+ test from: :dtr_custom_next_questionnaire_validation
92
+ # Test 8: verify the custom responses has the necessary extensions for pre-population
93
+ test from: :dtr_custom_questionnaire_extensions do
94
+ title %(
95
+ [USER INPUT VERIFICATION] Custom Questionnaires for $next-question Responses contain extensions
96
+ necessary for pre-population
97
+ )
98
+ input :custom_next_question_questionnaires
99
+ end
100
+ # Test 9: verify custom responses has necessary expressions for pre-population
101
+ test from: :dtr_custom_questionnaire_expressions do
102
+ title %(
103
+ [USER INPUT VERIFICATION] Custom Questionnaires for $next-question Responses contain items with
104
+ expressions necessary for pre-population
105
+ )
106
+ input :custom_next_question_questionnaires
107
+ end
108
+ end
109
+
110
+ group do
111
+ title 'Attestation: Questionnaire Pre-Population and Rendering'
112
+ description %(
113
+ This group verifies that the tester has properly followed pre-population and rendering
114
+ directives while interacting with and filling out the questionnaire.
115
+
116
+ After retrieving and completing the questionnaire in their client system, the tester will
117
+ attest that:
118
+ 1. The questionnaire was pre-populated as expected, with at least two answers pre-populated
119
+ across all sets of questions.
120
+ 2. The questionnaire was rendered correctly according to its defined structure.
121
+ 3. They were able to manually enter responses, including overriding pre-populated answers.
122
+ )
123
+ test from: :dtr_prepopulation_attest
124
+ test from: :dtr_prepopulation_override_attest
125
+ end
126
+
127
+ group do
128
+ title 'Attestation: QuestionnaireResponse Completion and Storage'
129
+ description %(
130
+ The tester will attest to the completion of the questionnaire such that the results are stored for later use.
131
+ )
132
+
133
+ test from: :dtr_full_ehr_store_attest
134
+ end
135
+ end
136
+ end
@@ -0,0 +1,171 @@
1
+ require_relative '../../../urls'
2
+
3
+ module DaVinciDTRTestKit
4
+ class DTRSmartAppCustomAdaptiveRequestTest < Inferno::Test
5
+ include URLs
6
+
7
+ id :dtr_smart_app_custom_adative_request
8
+ title 'Client can complete the DTR Adaptive Questionnaire workflow'
9
+ description %(
10
+ This test waits for client requests to retrieve and progress through an adaptive questionnaire workflow.
11
+
12
+ 1. **Questionnaire Package Request**: The client should invoke the `$questionnaire-package` operation
13
+ to retrieve the adaptive questionnaire package. Inferno will respond with the user-provided
14
+ empty adaptive questionnaire.
15
+
16
+ 2. **Next Question Requests**: The client should invoke the `$next-question` operation to request
17
+ the next set of questions. Inferno will respond sequentially with the next Questionnaire from
18
+ the user-provided list. If a `$next-question` request is received when the list is empty,
19
+ Inferno will mark the `QuestionnaireResponse` as completed.
20
+ )
21
+ config options: { accepts_multiple_requests: true }
22
+ input :smart_app_launch,
23
+ type: 'radio',
24
+ title: 'SMART App Launch',
25
+ description: 'How will the DTR SMART App launch?',
26
+ options: { list_options: [{ label: 'EHR Launch from Inferno', value: 'ehr' },
27
+ { label: 'Standalone Launch', value: 'standalone' }] }
28
+ input :client_id
29
+ input :launch_uri,
30
+ optional: true,
31
+ description: 'Required if "Launch from Inferno" is selected'
32
+ input :adaptive_smart_patient_id,
33
+ optional: true,
34
+ title: 'SMART App Launch Patient ID (Custom Adaptive)',
35
+ type: 'text',
36
+ description: %(
37
+ Patient instance ID to be provided by Inferno as the patient as a part of the SMART App Launch.
38
+ ),
39
+ default: 'pat015'
40
+ input :adaptive_smart_fhir_context,
41
+ optional: true,
42
+ title: 'SMART App Launch fhirContext (Custom Adaptive)',
43
+ type: 'textarea',
44
+ description: %(
45
+ References to be provided by Inferno as the fhirContext as a part of the SMART App
46
+ Launch. These references help determine the behavior of the app. Referenced instances
47
+ may be provided in the "EHR-available resources" input.
48
+ ),
49
+ default: JSON.pretty_generate([{ reference: 'Coverage/cov015' },
50
+ { reference: 'DeviceRequest/devreqe0470' }])
51
+ input :adaptive_ehr_bundle,
52
+ optional: true,
53
+ title: 'EHR-available resources (Custom Adaptive)',
54
+ type: 'textarea',
55
+ description: %(
56
+ Resources available from the EHR needed to drive the custom adaptive workflow.
57
+ Formatted as a FHIR bundle that contains resources, each with an ID property populated. Each
58
+ instance present will be available for retrieval from Inferno at the endpoint:
59
+ <fhir-base>/<resource type>/<instance id>
60
+ )
61
+ input :custom_questionnaire_package_response, :custom_next_question_questionnaires
62
+
63
+ def example_client_jwt_payload_part
64
+ Base64.strict_encode64({ inferno_client_id: client_id }.to_json).delete('=')
65
+ end
66
+
67
+ run do
68
+ assert_valid_json(
69
+ custom_questionnaire_package_response,
70
+ 'Custom questionnaire package response is not a valid json'
71
+ )
72
+ assert_valid_json(custom_next_question_questionnaires, 'Custom next questionnaires input is not a valid json')
73
+
74
+ custom_qp = JSON.parse(custom_questionnaire_package_response)
75
+ custom_questionnaires = JSON.parse(custom_next_question_questionnaires)
76
+ assert custom_qp.present?, %(
77
+ Custom questionnaire package response is empty, please provide a custom questionnaire package response
78
+ for the $questionnaire-package request
79
+ )
80
+ assert custom_questionnaires.present?, %(
81
+ 'Custom questionnaires list is empty, please provide a list of Custom Questionnaire resources
82
+ to include in each $next-question Response.
83
+ )
84
+ # validate relevant inputs and provide warnings if they are bad
85
+ warning do
86
+ if adaptive_smart_fhir_context
87
+ assert_valid_json(adaptive_smart_fhir_context,
88
+ 'The **SMART App Launch fhirContext** input is not valid JSON, so it will not be included in
89
+ the access token response.')
90
+ end
91
+ end
92
+
93
+ warning do
94
+ if adaptive_ehr_bundle
95
+ assert_valid_json(adaptive_ehr_bundle,
96
+ 'The **EHR-available resources** input is not valid JSON, so no tester-specified instances
97
+ will be available to access from Inferno.')
98
+ assert(FHIR.from_contents(adaptive_ehr_bundle).is_a?(FHIR::Bundle),
99
+ 'The **EHR-available resources** input does not contain a FHIR Bundle, so no tester-specified instances
100
+ will be available to access from Inferno.')
101
+ end
102
+ end
103
+
104
+ launch_prompt = if smart_app_launch == 'ehr'
105
+ %(Launch the DTR SMART App from Inferno by right clicking
106
+ [this link](#{launch_uri}?iss=#{fhir_base_url}&launch=#{launch_uri})
107
+ and selecting "Open in new window" or "Open in new tab".)
108
+ else
109
+ %(Launch the SMART App from your EHR.)
110
+ end
111
+ inferno_prompt_cont = %(As the DTR app steps through the launch steps, Inferno will wait and respond to the app's
112
+ requests for SMART configuration, authorization and access token.)
113
+
114
+ wait(
115
+ identifier: client_id,
116
+ message: %(
117
+ ### SMART App Launch
118
+
119
+ #{launch_prompt}
120
+
121
+ #{inferno_prompt_cont if smart_app_launch == 'ehr'}
122
+
123
+ ### Adaptive Questionnaire Workflow
124
+
125
+ 1. **Questionnaire Package Request**:
126
+ - Invoke the `$questionnaire-package` operation by sending a POST request to the following endpoint
127
+ to retrieve the adaptive questionnaire package:
128
+
129
+ `#{questionnaire_package_url}`
130
+
131
+ - Inferno will respond with the user-provided empty adaptive questionnaire.
132
+
133
+ 2. **Next Question Requests**:
134
+ - After receiving the questionnaire package, invoke the `$next-question` operation by sending
135
+ a POST request to the following endpoint:
136
+
137
+ `#{next_url}`
138
+
139
+ - Repeat this request **multiple times**, once for each Questionnaire provided in the user-supplied list.
140
+ - Inferno will sequentially respond with the corresponding Questionnaire from the list.
141
+ - If a `$next-question` request is received when the list is empty, Inferno will mark
142
+ the `QuestionnaireResponse` as completed.
143
+
144
+ Inferno will wait for all expected requests to be made.
145
+
146
+ ### Pre-population
147
+
148
+ Inferno will then wait for the client to complete Questionnaire pre-population. The client should make FHIR
149
+ GET requests using service base path:
150
+
151
+ `#{fhir_base_url}`
152
+
153
+ ### Request Identification
154
+
155
+ In order to identify requests for this session, Inferno will look for
156
+ an `Authorization` header with value:
157
+
158
+ ```
159
+ Bearer eyJhbGciOiJub25lIn0.#{example_client_jwt_payload_part}.
160
+ ```
161
+
162
+ ### Continuing the Tests
163
+
164
+ When the DTR application has finished loading the Questionnaire,
165
+ including any clinical data requests to support pre-population,
166
+ [Click here](#{resume_pass_url}?client_id=#{client_id}) to continue.
167
+ )
168
+ )
169
+ end
170
+ end
171
+ end
@@ -0,0 +1,146 @@
1
+ require_relative '../../../tags'
2
+ require_relative 'dtr_smart_app_custom_adaptive_request_test'
3
+ require_relative '../../shared/dtr_questionnaire_package_request_validation_test'
4
+ require_relative '../dtr_adaptive_next_question_request_validation_test'
5
+ require_relative '../dtr_adaptive_response_validation_test'
6
+ require_relative '../../shared/dtr_custom_questionnaire_package_validation_test'
7
+ require_relative '../../shared/dtr_custom_questionnaire_libraries_test'
8
+ require_relative '../../shared/dtr_custom_questionnaire_extensions_test'
9
+ require_relative '../../shared/dtr_custom_questionnaire_expressions_test'
10
+ require_relative 'dtr_custom_next_question_response_validation_test'
11
+ require_relative '../../shared/dtr_prepopulation_attestation_test'
12
+ require_relative '../../shared/dtr_prepopulation_override_attestation_test'
13
+ require_relative '../../smart_app/dtr_smart_app_saving_questionnaire_response_group'
14
+ require_relative '../../shared/dtr_questionnaire_response_prepopulation_test'
15
+
16
+ module DaVinciDTRTestKit
17
+ class DTRSmartAppCustomAdaptiveWorkflowGroup < Inferno::TestGroup
18
+ id :dtr_smart_app_custom_adaptive_workflow
19
+ title 'Adaptive Questionnaire Workflow'
20
+ description %(
21
+ This group validates that a DTR SMART App client can perform a full DTR Adaptive Questionnaire workflow.
22
+ Testers will provide a custom adaptive Questionnaire package for the test, along with a list
23
+ (JSON array) of Questionnaires to be included in each `$next-question` response.
24
+
25
+ As part of this workflow, the SMART App system must demonstrate its ability to:
26
+
27
+ 1. Request the Questionnaire using the `$questionnaire-package` operation.
28
+ 2. Support the tester in completing the questionnaire through multiple `$next-question` interactions, including:
29
+ - Rendering the questionnaire.
30
+ - Pre-populating answers into the questionnaire.
31
+ - Allowing the tester to manually enter responses, including overriding pre-populated answers.
32
+ 3. Provide the completed `QuestionnaireResponse` with appropriate indicators for pre-populated
33
+ and manually-entered data.
34
+
35
+ Inferno will process `$next-question` requests dynamically:
36
+ - Each `$next-question` request will correspond to the next item in the provided list.
37
+ - Inferno will sequentially return the corresponding Questionnaire from the list.
38
+ - If a `$next-question` request is received when the list is empty, Inferno will mark
39
+ the `QuestionnaireResponse` as completed.
40
+
41
+ At least two answers should be pre-populated across all sets of questions.
42
+ )
43
+ run_as_group
44
+
45
+ config(
46
+ options: {
47
+ smart_app: true,
48
+ form_type: 'adaptive',
49
+ next_tag: "custom_#{CLIENT_NEXT_TAG}"
50
+ },
51
+ inputs: {
52
+ custom_questionnaire_package_response: {
53
+ name: 'adaptive_custom_questionnaire_package_response',
54
+ title: 'Custom Questionnaire Package Response JSON for Adaptive form',
55
+ description: %(
56
+ A JSON PackageBundle may be provided here to replace Inferno's response to
57
+ the $questionnaire-package request. Note: Ensure that the questionnaire package
58
+ has an empty Adaptive Questionnaire.
59
+ )
60
+ }
61
+ }
62
+ )
63
+
64
+ group do
65
+ id :dtr_smart_app_custom_adaptive_retrieval
66
+ title 'Retrieving the Adaptive Questionnaire'
67
+
68
+ # Test 1: wait for the $questionnaire-package request and initial $next-question request
69
+ test from: :dtr_smart_app_custom_adative_request
70
+ # Test 2: validate the $questionnaire-package request body
71
+ test from: :dtr_qp_request_validation
72
+ # Test 3: validate the $next-question request body
73
+ test from: :dtr_adaptive_next_question_request_validation
74
+ # Test 4: validate the QuestionnaireResponse in the input parameter
75
+ test from: :dtr_adaptive_response_validation do
76
+ description %(
77
+ Verify that all submitted QuestionnaireResponse resources meet the following criteria:
78
+ - Conform to the [SDCQuestionnaireResponseAdapt](http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaireresponse-adapt).
79
+ - Include source extensions indicating whether answers were manually entered,
80
+ automatically pre-populated, or manually overridden (for `completed` QuestionnaireResponse).
81
+ - Provide answers for all required items in their contained Questionnaire.
82
+ )
83
+ input :custom_next_question_questionnaires
84
+ end
85
+ # Test 5: validate the user provided $questionnaire-package response
86
+ test from: :dtr_custom_qp_validation
87
+ # Test 6: verify the custom response has the necessary libraries for pre-population
88
+ test from: :dtr_custom_questionnaire_libraries
89
+ # Test 7: validate the user provided $next-question questionnaire
90
+ test from: :dtr_custom_next_questionnaire_validation
91
+ # Test 8: verify the custom response has the necessaru extensions for pre-population
92
+ test from: :dtr_custom_questionnaire_extensions do
93
+ title %(
94
+ [USER INPUT VERIFICATION] Custom Questionnaires for $next-question Responses contain extensions
95
+ necessary for pre-population
96
+ )
97
+ input :custom_next_question_questionnaires
98
+ end
99
+ # Test 9: verify custom response has necessary expressions for pre-population
100
+ test from: :dtr_custom_questionnaire_expressions do
101
+ title %(
102
+ [USER INPUT VERIFICATION] Custom Questionnaires for $next-question Responses contain items with
103
+ expressions necessary for pre-population
104
+ )
105
+ input :custom_next_question_questionnaires
106
+ end
107
+ end
108
+
109
+ group do
110
+ title 'Attestation: Questionnaire Pre-Population and Rendering'
111
+ description %(
112
+ This group verifies that the tester has properly followed pre-population and rendering
113
+ directives while interacting with and filling out the questionnaire.
114
+
115
+ After retrieving and completing the questionnaire in their client system, the tester will
116
+ attest that:
117
+ 1. The questionnaire was pre-populated as expected, with at least two answers pre-populated
118
+ across all sets of questions.
119
+ 2. The questionnaire was rendered correctly according to its defined structure.
120
+ 3. They were able to manually enter responses, including overriding pre-populated answers.
121
+ )
122
+ test from: :dtr_prepopulation_attest
123
+ test from: :dtr_prepopulation_override_attest
124
+ end
125
+
126
+ group from: :dtr_smart_app_saving_qr do
127
+ config(
128
+ options: {
129
+ custom: true,
130
+ adaptive: true,
131
+ qr_profile_url: 'http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaireresponse-adapt'
132
+ }
133
+ )
134
+
135
+ test from: :dtr_qr_prepopulation,
136
+ uses_request: :questionnaire_response_save,
137
+ description: %(
138
+ The tester will complete the questionnaire such that a QuestionnaireResponse is
139
+ stored back into Inferno's EHR endpoint. The stored QuestionnaireResponse will be evaluated for:
140
+ - Has source extensions demonstrating answers that are manually entered,
141
+ automatically pre-populated, and manually overridden.
142
+ - Contains answers for all required items.
143
+ )
144
+ end
145
+ end
146
+ end
@@ -1,6 +1,6 @@
1
- require_relative 'dtr_adaptive_next_question_request_test'
2
- require_relative 'dtr_adaptive_next_question_request_validation_test'
3
- require_relative 'dtr_adaptive_response_validation_test'
1
+ require_relative '../dtr_adaptive_next_question_request_test'
2
+ require_relative '../dtr_adaptive_next_question_request_validation_test'
3
+ require_relative '../dtr_adaptive_response_validation_test'
4
4
 
5
5
  module DaVinciDTRTestKit
6
6
  class DTRAdaptiveNextQuestionRetrievalGroup < Inferno::TestGroup