davinci_dtr_test_kit 0.13.0 → 0.14.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (128) hide show
  1. checksums.yaml +4 -4
  2. data/lib/davinci_dtr_test_kit/client_groups/dinner_adaptive/dtr_adaptive_questionnaire_completion_group.rb +23 -0
  3. data/lib/davinci_dtr_test_kit/client_groups/dinner_adaptive/dtr_adaptive_questionnaire_followup_questions_group.rb +26 -0
  4. data/lib/davinci_dtr_test_kit/client_groups/dinner_adaptive/dtr_adaptive_questionnaire_next_question_request_test.rb +93 -0
  5. data/lib/davinci_dtr_test_kit/client_groups/dinner_adaptive/dtr_adaptive_questionnaire_next_question_request_validation_test.rb +62 -0
  6. data/lib/davinci_dtr_test_kit/client_groups/dinner_adaptive/dtr_adaptive_questionnaire_next_question_retrieval_group.rb +23 -0
  7. data/lib/davinci_dtr_test_kit/client_groups/dinner_adaptive/dtr_adaptive_questionnaire_response_validation_test.rb +66 -0
  8. data/lib/davinci_dtr_test_kit/client_groups/dinner_adaptive/dtr_full_ehr_adaptive_dinner_questionnaire_workflow_group.rb +76 -0
  9. data/lib/davinci_dtr_test_kit/client_groups/dinner_adaptive/dtr_full_ehr_adaptive_questionnaire_initial_retrieval_group.rb +27 -0
  10. data/lib/davinci_dtr_test_kit/client_groups/dinner_adaptive/dtr_full_ehr_adaptive_questionnaire_request_test.rb +63 -0
  11. data/lib/davinci_dtr_test_kit/client_groups/dinner_adaptive/dtr_smart_app_adaptive_questionnaire_initial_retrieval_group.rb +24 -0
  12. data/lib/davinci_dtr_test_kit/client_groups/dinner_adaptive/dtr_smart_app_adaptive_questionnaire_request_test.rb +148 -0
  13. data/lib/davinci_dtr_test_kit/client_groups/dinner_adaptive/dtr_smart_app_questionnaire_workflow_group.rb +75 -0
  14. data/lib/davinci_dtr_test_kit/client_groups/dinner_static/dtr_full_ehr_questionnaire_workflow_group.rb +22 -38
  15. data/lib/davinci_dtr_test_kit/client_groups/dinner_static/dtr_smart_app_dinner_questionnaire_package_request_test.rb +13 -16
  16. data/lib/davinci_dtr_test_kit/client_groups/dinner_static/dtr_smart_app_questionnaire_workflow_group.rb +9 -31
  17. data/lib/davinci_dtr_test_kit/client_groups/{dinner_static → full_ehr}/dtr_full_ehr_launch_attestation_test.rb +7 -6
  18. data/lib/davinci_dtr_test_kit/client_groups/{dinner_static → full_ehr}/dtr_full_ehr_prepopulation_attestation_test.rb +7 -7
  19. data/lib/davinci_dtr_test_kit/client_groups/{dinner_static → full_ehr}/dtr_full_ehr_prepopulation_override_attestation_test.rb +7 -7
  20. data/lib/davinci_dtr_test_kit/client_groups/{dinner_static/dtr_full_ehr_dinner_questionnaire_package_request_test.rb → full_ehr/dtr_full_ehr_questionnaire_package_request_test.rb} +2 -3
  21. data/lib/davinci_dtr_test_kit/client_groups/{dinner_static/dtr_full_ehr_dinner_static_questionnaire_response_conformance_test.rb → full_ehr/dtr_full_ehr_questionnaire_response_conformance_test.rb} +7 -3
  22. data/lib/davinci_dtr_test_kit/client_groups/{dinner_static/dtr_full_ehr_dinner_static_questionnaire_response_correctness_test.rb → full_ehr/dtr_full_ehr_questionnaire_response_correctness_test.rb} +14 -7
  23. data/lib/davinci_dtr_test_kit/client_groups/{dinner_static → full_ehr}/dtr_full_ehr_rendering_enabled_questions_attestation_test.rb +7 -7
  24. data/lib/davinci_dtr_test_kit/client_groups/full_ehr/dtr_full_ehr_saving_questionnaire_response_group.rb +29 -0
  25. data/lib/davinci_dtr_test_kit/client_groups/{dinner_static → full_ehr}/dtr_full_ehr_store_attestation_test.rb +7 -7
  26. data/lib/davinci_dtr_test_kit/client_groups/resp_assist_device/dtr_questionnaire_rendering_attestation_test.rb +7 -6
  27. data/lib/davinci_dtr_test_kit/client_groups/resp_assist_device/dtr_resp_questionnaire_package_request_test.rb +15 -18
  28. data/lib/davinci_dtr_test_kit/client_groups/shared/dtr_questionnaire_response_basic_conformance_test.rb +5 -1
  29. data/lib/davinci_dtr_test_kit/client_groups/shared/dtr_questionnaire_response_pre_population_test.rb +12 -5
  30. data/lib/davinci_dtr_test_kit/client_groups/{dinner_static → smart_app}/dtr_smart_app_prepopulation_attestation_test.rb +7 -7
  31. data/lib/davinci_dtr_test_kit/client_groups/{dinner_static → smart_app}/dtr_smart_app_prepopulation_override_attestation_test.rb +7 -6
  32. data/lib/davinci_dtr_test_kit/client_groups/{dinner_static → smart_app}/dtr_smart_app_questionnaire_response_save_test.rb +17 -7
  33. data/lib/davinci_dtr_test_kit/client_groups/{dinner_static → smart_app}/dtr_smart_app_rendering_enabled_questions_attestation_test.rb +7 -7
  34. data/lib/davinci_dtr_test_kit/client_groups/smart_app/dtr_smart_app_saving_questionnaire_response_group.rb +27 -0
  35. data/lib/davinci_dtr_test_kit/cql_test.rb +37 -140
  36. data/lib/davinci_dtr_test_kit/create_test.rb +25 -0
  37. data/lib/davinci_dtr_test_kit/docs/dtr_full_ehr_suite_description_v201.md +95 -37
  38. data/lib/davinci_dtr_test_kit/docs/dtr_light_ehr_suite_description_v201.md +15 -6
  39. data/lib/davinci_dtr_test_kit/docs/dtr_payer_server_suite_description_v201.md +32 -29
  40. data/lib/davinci_dtr_test_kit/docs/dtr_smart_app_suite_description_v201.md +48 -32
  41. data/lib/davinci_dtr_test_kit/dtr_full_ehr_suite.rb +13 -17
  42. data/lib/davinci_dtr_test_kit/dtr_light_ehr_suite.rb +67 -2
  43. data/lib/davinci_dtr_test_kit/dtr_payer_server_suite.rb +9 -20
  44. data/lib/davinci_dtr_test_kit/dtr_questionnaire_response_validation.rb +18 -10
  45. data/lib/davinci_dtr_test_kit/dtr_smart_app_suite.rb +32 -59
  46. data/lib/davinci_dtr_test_kit/endpoints/cors.rb +20 -0
  47. data/lib/davinci_dtr_test_kit/endpoints/mock_authorization/authorize_endpoint.rb +32 -0
  48. data/lib/davinci_dtr_test_kit/endpoints/mock_authorization/simple_token_endpoint.rb +19 -0
  49. data/lib/davinci_dtr_test_kit/endpoints/mock_authorization/token_endpoint.rb +116 -0
  50. data/lib/davinci_dtr_test_kit/endpoints/mock_authorization.rb +83 -0
  51. data/lib/davinci_dtr_test_kit/endpoints/mock_ehr/fhir_get_endpoint.rb +95 -0
  52. data/lib/davinci_dtr_test_kit/endpoints/mock_ehr/questionnaire_response_endpoint.rb +22 -0
  53. data/lib/davinci_dtr_test_kit/endpoints/mock_ehr.rb +25 -0
  54. data/lib/davinci_dtr_test_kit/endpoints/mock_payer/full_ehr_next_question_endpoint.rb +11 -0
  55. data/lib/davinci_dtr_test_kit/endpoints/mock_payer/full_ehr_questionnaire_package_endpoint.rb +11 -0
  56. data/lib/davinci_dtr_test_kit/endpoints/mock_payer/next_question_endpoint.rb +162 -0
  57. data/lib/davinci_dtr_test_kit/endpoints/mock_payer/next_question_proxy_endpoint.rb +36 -0
  58. data/lib/davinci_dtr_test_kit/endpoints/mock_payer/questionnaire_package_endpoint.rb +62 -0
  59. data/lib/davinci_dtr_test_kit/endpoints/mock_payer/questionnaire_package_proxy_endpoint.rb +38 -0
  60. data/lib/davinci_dtr_test_kit/endpoints/mock_payer.rb +36 -0
  61. data/lib/davinci_dtr_test_kit/fixtures/dinner_adaptive/dinner_order_adaptive_next_question_burrito.json +10 -2
  62. data/lib/davinci_dtr_test_kit/fixtures/dinner_adaptive/dinner_order_adaptive_next_question_hamburger.json +10 -2
  63. data/lib/davinci_dtr_test_kit/fixtures/dinner_adaptive/dinner_order_adaptive_next_question_initial.json +10 -2
  64. data/lib/davinci_dtr_test_kit/fixtures/dinner_adaptive/questionnaire_dinner_order_adaptive.json +4 -3
  65. data/lib/davinci_dtr_test_kit/fixtures.rb +24 -1
  66. data/lib/davinci_dtr_test_kit/payer_server_groups/adaptive_form_libraries_test.rb +2 -2
  67. data/lib/davinci_dtr_test_kit/payer_server_groups/adaptive_form_questionnaire_expressions_test.rb +4 -3
  68. data/lib/davinci_dtr_test_kit/payer_server_groups/adaptive_form_questionnaire_extensions_test.rb +3 -2
  69. data/lib/davinci_dtr_test_kit/payer_server_groups/adaptive_next_questionnaire_expressions_test.rb +6 -6
  70. data/lib/davinci_dtr_test_kit/payer_server_groups/adaptive_next_questionnaire_extensions_test.rb +6 -5
  71. data/lib/davinci_dtr_test_kit/payer_server_groups/payer_server_adaptive_group.rb +2 -2
  72. data/lib/davinci_dtr_test_kit/payer_server_groups/payer_server_adaptive_response_bundles_validation_test.rb +6 -9
  73. data/lib/davinci_dtr_test_kit/payer_server_groups/payer_server_adaptive_response_search_validation_test.rb +15 -12
  74. data/lib/davinci_dtr_test_kit/payer_server_groups/payer_server_adaptive_response_validation_test.rb +33 -23
  75. data/lib/davinci_dtr_test_kit/payer_server_groups/payer_server_next_response_complete_test.rb +4 -4
  76. data/lib/davinci_dtr_test_kit/payer_server_groups/payer_server_next_response_validation_test.rb +16 -12
  77. data/lib/davinci_dtr_test_kit/payer_server_groups/static_form_libraries_test.rb +2 -2
  78. data/lib/davinci_dtr_test_kit/payer_server_groups/static_form_questionnaire_expressions_test.rb +5 -4
  79. data/lib/davinci_dtr_test_kit/payer_server_groups/static_form_questionnaire_extensions_test.rb +4 -3
  80. data/lib/davinci_dtr_test_kit/payer_server_groups/static_form_response_validation_test.rb +32 -25
  81. data/lib/davinci_dtr_test_kit/profiles/communication_request/communication_request_read.rb +29 -0
  82. data/lib/davinci_dtr_test_kit/profiles/communication_request/communication_request_validation.rb +35 -0
  83. data/lib/davinci_dtr_test_kit/profiles/communication_request_group.rb +39 -0
  84. data/lib/davinci_dtr_test_kit/profiles/coverage/coverage_read.rb +29 -0
  85. data/lib/davinci_dtr_test_kit/profiles/coverage/coverage_validation.rb +35 -0
  86. data/lib/davinci_dtr_test_kit/profiles/coverage_group.rb +38 -0
  87. data/lib/davinci_dtr_test_kit/profiles/device_request/device_request_read.rb +29 -0
  88. data/lib/davinci_dtr_test_kit/profiles/device_request/device_request_validation.rb +35 -0
  89. data/lib/davinci_dtr_test_kit/profiles/device_request_group.rb +39 -0
  90. data/lib/davinci_dtr_test_kit/profiles/encounter/encounter_read.rb +29 -0
  91. data/lib/davinci_dtr_test_kit/profiles/encounter/encounter_validation.rb +35 -0
  92. data/lib/davinci_dtr_test_kit/profiles/encounter_group.rb +39 -0
  93. data/lib/davinci_dtr_test_kit/profiles/medication_request/medication_request_read.rb +29 -0
  94. data/lib/davinci_dtr_test_kit/profiles/medication_request/medication_request_validation.rb +35 -0
  95. data/lib/davinci_dtr_test_kit/profiles/medication_request_group.rb +39 -0
  96. data/lib/davinci_dtr_test_kit/profiles/nutrition_order/nutrition_order_read.rb +29 -0
  97. data/lib/davinci_dtr_test_kit/profiles/nutrition_order/nutrition_order_validation.rb +35 -0
  98. data/lib/davinci_dtr_test_kit/profiles/nutrition_order_group.rb +39 -0
  99. data/lib/davinci_dtr_test_kit/profiles/questionnaire_response/questionnaire_response_context_search.rb +35 -0
  100. data/lib/davinci_dtr_test_kit/profiles/questionnaire_response/questionnaire_response_create.rb +26 -0
  101. data/lib/davinci_dtr_test_kit/profiles/questionnaire_response/questionnaire_response_patient_search.rb +55 -0
  102. data/lib/davinci_dtr_test_kit/profiles/questionnaire_response/questionnaire_response_read.rb +22 -0
  103. data/lib/davinci_dtr_test_kit/profiles/questionnaire_response/questionnaire_response_update.rb +26 -0
  104. data/lib/davinci_dtr_test_kit/profiles/questionnaire_response/questionnaire_response_validation.rb +37 -0
  105. data/lib/davinci_dtr_test_kit/profiles/questionnaire_response_group.rb +66 -0
  106. data/lib/davinci_dtr_test_kit/profiles/service_request/service_request_read.rb +29 -0
  107. data/lib/davinci_dtr_test_kit/profiles/service_request/service_request_validation.rb +35 -0
  108. data/lib/davinci_dtr_test_kit/profiles/service_request_group.rb +39 -0
  109. data/lib/davinci_dtr_test_kit/profiles/task/task_create.rb +26 -0
  110. data/lib/davinci_dtr_test_kit/profiles/task/task_read.rb +29 -0
  111. data/lib/davinci_dtr_test_kit/profiles/task/task_update.rb +26 -0
  112. data/lib/davinci_dtr_test_kit/profiles/task/task_validation.rb +35 -0
  113. data/lib/davinci_dtr_test_kit/profiles/task_group.rb +52 -0
  114. data/lib/davinci_dtr_test_kit/profiles/vision_prescription/vision_prescription_read.rb +29 -0
  115. data/lib/davinci_dtr_test_kit/profiles/vision_prescription/vision_prescription_validation.rb +35 -0
  116. data/lib/davinci_dtr_test_kit/profiles/vision_prescription_group.rb +39 -0
  117. data/lib/davinci_dtr_test_kit/read_test.rb +22 -0
  118. data/lib/davinci_dtr_test_kit/tags.rb +5 -7
  119. data/lib/davinci_dtr_test_kit/update_test.rb +25 -0
  120. data/lib/davinci_dtr_test_kit/validation_test.rb +19 -4
  121. data/lib/davinci_dtr_test_kit/version.rb +1 -1
  122. metadata +110 -21
  123. data/lib/davinci_dtr_test_kit/ext/inferno_core/record_response_route.rb +0 -98
  124. data/lib/davinci_dtr_test_kit/ext/inferno_core/request.rb +0 -19
  125. data/lib/davinci_dtr_test_kit/ext/inferno_core/runnable.rb +0 -35
  126. data/lib/davinci_dtr_test_kit/mock_auth_server.rb +0 -228
  127. data/lib/davinci_dtr_test_kit/mock_ehr.rb +0 -105
  128. data/lib/davinci_dtr_test_kit/mock_payer.rb +0 -100
@@ -10,6 +10,7 @@ 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
+ config options: { accepts_multiple_requests: true }
13
14
  input :smart_app_launch,
14
15
  type: 'radio',
15
16
  title: 'SMART App Launch',
@@ -20,38 +21,34 @@ module DaVinciDTRTestKit
20
21
  input :launch_uri,
21
22
  optional: true,
22
23
  description: 'Required if "Launch from Inferno" is selected'
23
- input :smart_patient_id,
24
+ input :resp_smart_patient_id,
24
25
  optional: true,
25
26
  title: 'SMART App Launch Patient ID (Respiratory Assist Device)',
26
27
  type: 'text',
27
28
  description: %(
28
- Patient instance `id` to be provided by Inferno as the `patient` as a part of the SMART App
29
- Launch.
29
+ Patient instance ID to be provided by Inferno as the patient as a part of the SMART App Launch.
30
30
  ),
31
31
  default: 'pat015'
32
- input :smart_fhir_context,
32
+ input :resp_smart_fhir_context,
33
33
  optional: true,
34
34
  title: 'SMART App Launch fhirContext (Respiratory Assist Device)',
35
35
  type: 'textarea',
36
36
  description: %(
37
- References to be provided by Inferno as the `fhirContext` as a part of the SMART App
37
+ References to be provided by Inferno as the fhirContext as a part of the SMART App
38
38
  Launch. These references help determine the behavior of the app. Referenced instances
39
39
  may be provided in the "EHR-available resources" input.
40
40
  ),
41
41
  default: JSON.pretty_generate([{ reference: 'Coverage/cov015' },
42
42
  { reference: 'DeviceRequest/devreqe0470' }])
43
- input :ehr_bundle,
43
+ input :resp_ehr_bundle,
44
44
  optional: true,
45
45
  title: 'EHR-available resources (Respiratory Assist Device)',
46
46
  type: 'textarea',
47
47
  description: %(
48
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
- ```
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
+ <fhir-base>/<resource type>/<instance id>
55
52
  )
56
53
 
57
54
  def example_client_jwt_payload_part
@@ -61,19 +58,19 @@ module DaVinciDTRTestKit
61
58
  run do
62
59
  # validate relevant inputs and provide warnings if they are bad
63
60
  warning do
64
- if smart_fhir_context
65
- assert_valid_json(smart_fhir_context,
61
+ if resp_smart_fhir_context
62
+ assert_valid_json(resp_smart_fhir_context,
66
63
  'The **SMART App Launch fhirContext** input is not valid JSON, so it will not be included in
67
64
  the access token response.')
68
65
  end
69
66
  end
70
67
 
71
68
  warning do
72
- if ehr_bundle
73
- assert_valid_json(ehr_bundle,
69
+ if resp_ehr_bundle
70
+ assert_valid_json(resp_ehr_bundle,
74
71
  'The **EHR-available resources** input is not valid JSON, so no tester-specified instances
75
72
  will be available to access from Inferno.')
76
- assert(FHIR.from_contents(ehr_bundle).is_a?(FHIR::Bundle),
73
+ assert(FHIR.from_contents(resp_ehr_bundle).is_a?(FHIR::Bundle),
77
74
  'The **EHR-available resources** input does not contain a FHIR Bundle, so no tester-specified instances
78
75
  will be available to access from Inferno.')
79
76
  end
@@ -117,7 +114,7 @@ module DaVinciDTRTestKit
117
114
  an `Authorization` header with value:
118
115
 
119
116
  ```
120
- Bearer eyJhbGcmOiJub25lIn0.#{example_client_jwt_payload_part}.
117
+ Bearer eyJhbGciOiJub25lIn0.#{example_client_jwt_payload_part}.
121
118
  ```
122
119
 
123
120
  ### Continuing the Tests
@@ -14,11 +14,15 @@ module DaVinciDTRTestKit
14
14
  to the DTR Questionnaire Response resource profile.
15
15
  )
16
16
 
17
+ def profile_url
18
+ config.options[:qr_profile_url]
19
+ end
20
+
17
21
  run do
18
22
  assert request.url == questionnaire_response_url,
19
23
  "Request made to wrong URL: #{request.url}. Should instead be to #{questionnaire_response_url}"
20
24
 
21
- verify_basic_conformance(request.request_body)
25
+ verify_basic_conformance(request.request_body, profile_url)
22
26
  end
23
27
  end
24
28
  end
@@ -1,5 +1,3 @@
1
- # frozen_string_literal: true
2
-
3
1
  require_relative '../../dtr_questionnaire_response_validation'
4
2
  require_relative '../../fixtures'
5
3
 
@@ -27,9 +25,18 @@ module DaVinciDTRTestKit
27
25
  questionnaire_response_json = request.request_body
28
26
  check_is_questionnaire_response(questionnaire_response_json)
29
27
  questionnaire_response = FHIR.from_contents(questionnaire_response_json)
30
- questionnaire = Fixtures.questionnaire_for_test(id)
31
- response_template = Fixtures.questionnaire_response_for_test(id)
32
- validate_questionnaire_pre_population(questionnaire, response_template, questionnaire_response)
28
+ if config.options[:adaptive]
29
+ questionnaire = questionnaire_response.contained.find { |res| res.resourceType == 'Questionnaire' }
30
+ assert questionnaire, 'Adaptive QuestionnaireResponse must have a contained Questionnaire resource.'
31
+ check_origin_sources(questionnaire.item, questionnaire_response.item, expected_overrides: ['PBD.2'])
32
+ required_link_ids = extract_required_link_ids(questionnaire.item)
33
+ check_answer_presence(questionnaire_response.item, required_link_ids)
34
+ assert(messages.none? { |m| m[:type] == 'error' }, 'QuestionnaireResponse is not correct, see error message(s)')
35
+ else
36
+ questionnaire = Fixtures.questionnaire_for_test(id)
37
+ response_template = Fixtures.questionnaire_response_for_test(id)
38
+ validate_questionnaire_pre_population(questionnaire, response_template, questionnaire_response)
39
+ end
33
40
  end
34
41
  end
35
42
  end
@@ -1,27 +1,27 @@
1
+ require 'securerandom'
1
2
  require_relative '../../urls'
2
3
 
3
4
  module DaVinciDTRTestKit
4
- class DTRSmartAppStaticDinnerPrepopulationAttestationTest < Inferno::Test
5
+ class DTRSmartAppPrepopulationAttestationTest < Inferno::Test
5
6
  include URLs
6
7
 
7
- id :dtr_smart_app_dinner_static_rendering_prepopulation_attestation
8
+ id :dtr_smart_app_prepopulation_attestation
8
9
  title 'Check that the client pre-populates the questionnaire (Attestation)'
9
10
  description %(
10
11
  Validate that pre-population of patient name information occurs as expected.
11
12
  )
12
- input :client_id
13
-
14
13
  run do
14
+ random_id = SecureRandom.uuid
15
15
  wait(
16
- identifier: client_id,
16
+ identifier: random_id,
17
17
  message: %(
18
18
  I attest that the client application pre-populates the following questions with the respective values:
19
19
  - Last Name: Oster
20
20
  - First Name: William
21
21
 
22
- [Click here](#{resume_pass_url}?client_id=#{client_id}) if the above statement is **true**.
22
+ [Click here](#{resume_pass_url}?client_id=#{random_id}) if the above statement is **true**.
23
23
 
24
- [Click here](#{resume_fail_url}?client_id=#{client_id}) if the above statement is **false**.
24
+ [Click here](#{resume_fail_url}?client_id=#{random_id}) if the above statement is **false**.
25
25
  )
26
26
  )
27
27
  end
@@ -1,28 +1,29 @@
1
+ require 'securerandom'
1
2
  require_relative '../../urls'
2
3
 
3
4
  module DaVinciDTRTestKit
4
- class DTRSmartAppStaticDinnerPrepopulationOverrideAttestationTest < Inferno::Test
5
+ class DTRSmartAppPrepopulationOverrideAttestationTest < Inferno::Test
5
6
  include URLs
6
7
 
7
- id :dtr_smart_app_dinner_static_prepopulation_override_attestation
8
+ id :dtr_smart_app_prepopulation_override_attestation
8
9
  title 'Validate the user can override pre-populated data (Attestation)'
9
10
  description %(
10
11
  Validate that the user can edit a pre-populated item and replace it with another value.
11
12
  )
12
- input :client_id
13
13
 
14
14
  run do
15
+ random_id = SecureRandom.uuid
15
16
  wait(
16
- identifier: client_id,
17
+ identifier: random_id,
17
18
  message: %(
18
19
  I attest that
19
20
 
20
21
  1. The client pre-populated an answer for question 'Location'.
21
22
  2. I have changed the answer to a different value.
22
23
 
23
- [Click here](#{resume_pass_url}?client_id=#{client_id}) if the above statement is **true**.
24
+ [Click here](#{resume_pass_url}?client_id=#{random_id}) if the above statement is **true**.
24
25
 
25
- [Click here](#{resume_fail_url}?client_id=#{client_id}) if the above statement is **false**.
26
+ [Click here](#{resume_fail_url}?client_id=#{random_id}) if the above statement is **false**.
26
27
  )
27
28
  )
28
29
  end
@@ -1,30 +1,40 @@
1
1
  require_relative '../../urls'
2
2
 
3
3
  module DaVinciDTRTestKit
4
- class DTRSmartAppStaticDinnerQuestionnaireResponseSaveTest < Inferno::Test
4
+ class DTRSmartAppQuestionnaireResponseSaveTest < Inferno::Test
5
5
  include URLs
6
6
 
7
- id :dtr_smart_app_static_dinner_questionnaire_response_save
7
+ id :dtr_smart_app_questionnaire_response_save
8
8
  title 'Save the QuestionnaireResponse after completing it'
9
9
  description %(
10
10
  Inferno, acting as the EHR, will wait for a request to save the QuestionnaireResponse from the client.
11
11
  )
12
12
  input :client_id
13
13
 
14
- run do
15
- wait(
16
- identifier: client_id,
17
- message: %(
14
+ def prompt
15
+ if config.options[:adaptive]
16
+ 'Store the completed questionnaire back into the EHR.'
17
+ else
18
+ <<~DESCRIPTION
18
19
  Complete the questionnaire, leaving the following items unmodified, because a subsequent test will expect
19
20
  their pre-populated values:
20
21
 
21
22
  - First Name
22
23
  - Last Name
24
+ DESCRIPTION
25
+ end
26
+ end
27
+
28
+ run do
29
+ wait(
30
+ identifier: client_id,
31
+ message: <<~MESSAGE
32
+ #{prompt}
23
33
 
24
34
  Inferno will wait for a POST request at:
25
35
 
26
36
  `#{questionnaire_response_url}`
27
- )
37
+ MESSAGE
28
38
  )
29
39
  end
30
40
  end
@@ -1,28 +1,28 @@
1
+ require 'securerandom'
1
2
  require_relative '../../urls'
2
3
 
3
4
  module DaVinciDTRTestKit
4
- class DTRSmartAppStaticDinnerRenderingAttestationTest < Inferno::Test
5
+ class DTRSmartAppRenderingEnabledQuestionsAttestationTest < Inferno::Test
5
6
  include URLs
6
7
 
7
- id :dtr_smart_app_dinner_static_rendering_enabledQs_attestation
8
+ id :dtr_smart_app_rendering_enabled_questions_attestation
8
9
  title 'Check that the client renders enabled questions appropriately (Attestation)'
9
10
  description %(
10
11
  Validate that the rendering of the questionnaire includes only the "What would you like on..."
11
12
  question appropriate for the dinner selection, if made.
12
13
  )
13
- input :client_id
14
-
15
14
  run do
15
+ random_id = SecureRandom.uuid
16
16
  wait(
17
- identifier: client_id,
17
+ identifier: random_id,
18
18
  message: %(
19
19
  I attest that the client application does not display any "What would you like on..."
20
20
  questions until I have selected a dinner choice and then only displays the
21
21
  "What would you like on..." question relevant for the dinner request:
22
22
 
23
- [Click here](#{resume_pass_url}?client_id=#{client_id}) if the above statement is **true**.
23
+ [Click here](#{resume_pass_url}?client_id=#{random_id}) if the above statement is **true**.
24
24
 
25
- [Click here](#{resume_fail_url}?client_id=#{client_id}) if the above statement is **false**.
25
+ [Click here](#{resume_fail_url}?client_id=#{random_id}) if the above statement is **false**.
26
26
  )
27
27
  )
28
28
  end
@@ -0,0 +1,27 @@
1
+ require_relative 'dtr_smart_app_questionnaire_response_save_test'
2
+ require_relative '../shared/dtr_questionnaire_response_basic_conformance_test'
3
+ require_relative '../shared/dtr_questionnaire_response_pre_population_test'
4
+
5
+ module DaVinciDTRTestKit
6
+ class DTRSmartAppSavingQuestionnaireResponseGroup < Inferno::TestGroup
7
+ id :dtr_smart_app_saving_questionnaire_response
8
+ title 'Saving the QuestionnaireResponse'
9
+ description %(
10
+ The tester will complete the questionnaire such that a QuestionnaireResponse is stored
11
+ back into Inferno's EHR endpoint. The stored QuestionnaireResponse will be evaluated for
12
+ conformance, completeness, and correct indicators on pre-populated and manually-overriden
13
+ items.
14
+ )
15
+ run_as_group
16
+
17
+ # Test 1: wait for a QuestionnaireResponse
18
+ test from: :dtr_smart_app_questionnaire_response_save,
19
+ receives_request: :questionnaire_response_save
20
+ # Test 2: validate basic conformance of the QuestionnaireResponse
21
+ test from: :dtr_questionnaire_response_basic_conformance,
22
+ uses_request: :questionnaire_response_save
23
+ # Test 3: validate workflow-specific details such as pre-population and overrides
24
+ test from: :dtr_questionnaire_response_pre_population,
25
+ uses_request: :questionnaire_response_save
26
+ end
27
+ end
@@ -48,53 +48,10 @@ module DaVinciDTRTestKit
48
48
  extension_presence.each_key { |k| extension_presence[k] = false }
49
49
  end
50
50
 
51
- def evaluate_responses_extensions(resource)
52
- found_questionnaire = false
53
- resource.each do |individual_resource|
54
- next unless individual_resource.resourceType == 'QuestionnaireResponse'
55
-
56
- individual_resource.contained.each_with_index do |questionnaire, q_index|
57
- # Do out put parameters have a bundle?
58
- next unless questionnaire.resourceType == 'Questionnaire'
59
-
60
- # check the libraries first so references in questionnaires can be checked after
61
- found_questionnaire = true
62
- check_questionnaire_extensions(questionnaire, q_index)
63
- end
64
- end
65
- found_questionnaire
66
- end
67
-
68
- def evaluate_parameters_extensions(resource)
69
- found_questionnaire = false
70
- resource.parameter.each do |param|
71
- # Do out put parameters have a bundle?
72
- next unless param.resource.resourceType == 'Bundle'
73
-
74
- param.resource.entry.each_with_index do |entry, q_index|
75
- # check questionnaire extensions
76
- next unless entry.resource.resourceType == 'Questionnaire'
77
-
78
- found_questionnaire = true
79
- check_questionnaire_extensions(entry.resource, q_index)
80
- ## NEED TO FIGURE OUT HOW TO FAIL TEST WHEN POORLY FORMATTED EXPRESSIONS FOUND
81
- end
82
- end
83
- found_questionnaire
84
- end
85
-
86
- # extensions
87
- def questionnaire_extensions_test(response)
88
- resource = process_response(response)
89
- assert !resource.nil?, 'Response is null or not a valid type.'
90
- found_questionnaire = false
91
- if resource.instance_of? Array
92
- found_questionnaire = evaluate_responses_extensions(resource)
93
- elsif resource.resourceType == 'Parameters'
94
- found_questionnaire = evaluate_parameters_extensions(resource)
95
- end
51
+ def verify_questionnaire_extensions(questionnaires)
52
+ assert questionnaires&.any? && questionnaires.all? { |q| q.is_a? FHIR::Questionnaire }, 'No questionnaires found.'
53
+ questionnaires.each_with_index { |q, q_index| check_questionnaire_extensions(q, q_index) }
96
54
  check_library_references
97
- assert found_questionnaire, 'No questionnaires found.'
98
55
  assert extension_presence.value?(true), 'No extensions found. Questionnaire must demonstrate prepopulation.'
99
56
  assert cql_presence['variable'], 'Variable expression logic not written in CQL.'
100
57
  assert cql_presence['launch_context'], 'Launch context expression logic not written in CQL.'
@@ -140,53 +97,11 @@ module DaVinciDTRTestKit
140
97
  assert misformatted_expressions.compact.empty?, 'Expression in questionnaire misformatted.'
141
98
  end
142
99
 
143
- # items
144
- def evaluate_responses_items(resource)
145
- found_questionnaire = false
146
- resource.each_with_index do |individual_resource, q_index|
147
- next unless individual_resource.resourceType == 'QuestionnaireResponse'
148
-
149
- individual_resource.contained.each do |questionnaire|
150
- next unless questionnaire.resourceType == 'Questionnaire'
100
+ def verify_questionnaire_items(questionnaires, final_cql_test: false)
101
+ assert questionnaires&.any? && questionnaires.all? { |q| q.is_a? FHIR::Questionnaire }, 'No questionnaires found.'
102
+ questionnaires.each_with_index { |q, q_index| check_questionnaire_items(q, q_index) }
151
103
 
152
- # check the libraries first so references in questionnaires can be checked after
153
- found_questionnaire = true
154
- check_questionnaire_items(questionnaire, q_index)
155
- end
156
- end
157
- found_questionnaire
158
- end
159
-
160
- def evaluate_parameters_items(resource)
161
- found_bundle = found_questionnaire = false
162
- resource.parameter.each do |param|
163
- next unless param.resource.resourceType == 'Bundle'
164
-
165
- found_bundle = true
166
- # check the libraries first so references in questionnaires can be checked after
167
- param.resource.entry.each_with_index do |entry, q_index|
168
- if entry.resource.resourceType == 'Questionnaire'
169
- found_questionnaire = true
170
- check_questionnaire_items(entry.resource, q_index)
171
- end
172
- end
173
- end
174
- [found_bundle, found_questionnaire]
175
- end
176
-
177
- def questionnaire_items_test(response, final_cql_test)
178
- resource = process_response(response)
179
- assert !resource.nil?, 'Response is null or not a valid type.'
180
- found_questionnaire = false
181
- # are extensions present in any questionnaire?
182
- if resource.instance_of? Array
183
- found_questionnaire = evaluate_responses_items(resource)
184
- elsif resource.resourceType == 'Parameters'
185
- found_bundle, found_questionnaire = evaluate_parameters_items(resource)
186
- assert found_bundle, 'No questionnaire bundles found.'
187
- end
188
104
  begin
189
- assert found_questionnaire, 'No questionnaires found.'
190
105
  assert !found_non_cql_expression, 'Found non-cql expression.'
191
106
  assert extension_presence.value?(true), 'No extensions found. Questionnaire must demonstrate prepopulation.'
192
107
  assert cql_presence['init_expression'], 'Initial expression logic not written in CQL.'
@@ -281,12 +196,12 @@ module DaVinciDTRTestKit
281
196
  assert misformatted_expressions.compact.to_set.empty?, 'Expression in questionnaire misformatted.'
282
197
  end
283
198
 
284
- def evaluate_library(entry, lib_index)
199
+ def evaluate_library(library)
285
200
  found_cql = found_elm = false
286
- entry.resource.content.each do |content|
201
+ library.content.each do |content|
287
202
  if content.data.nil?
288
203
  messages << { type: 'info',
289
- message: format_markdown("[library #{lib_index + 1}] content element included no data.") }
204
+ message: format_markdown("[library #{library.url}] content element included no data.") }
290
205
  end
291
206
  if content.contentType == 'text/cql'
292
207
  found_cql = true
@@ -294,42 +209,30 @@ module DaVinciDTRTestKit
294
209
  found_elm = true
295
210
  else
296
211
  messages << { type: 'info',
297
- message: format_markdown("[library #{lib_index + 1}] has non-cql/elm content.") }
212
+ message: format_markdown("[library #{library.url}] has non-cql/elm content.") }
298
213
  true
299
214
  end
300
- next unless library_names.include? entry.resource.name
215
+ next unless library_names.include? library.name
301
216
 
302
217
  found_duplicate_library_name = true
303
- messages << { type: 'info', message: format_markdown("[library #{lib_index + 1}] has a name,
304
- #{entry.resource.name}, that is already included in the bundle.") }
218
+ messages << { type: 'info', message: format_markdown("[library #{library.url}] has a name,
219
+ #{library.name}, that is already included in the bundle.") }
305
220
  assert !found_duplicate_library_name, 'Found duplicate library names - all names must be unique.'
306
221
  end
307
- assert found_cql, "[library #{lib_index + 1}] does not include CQL."
308
- assert found_elm, "[library #{lib_index + 1}] does not include ELM."
222
+ assert found_cql, "[library #{library.url}] does not include CQL."
223
+ assert found_elm, "[library #{library.url}] does not include ELM."
309
224
  end
310
225
 
311
- def check_libraries(payer_response)
312
- resource = process_response(payer_response)
313
- assert !resource.nil?, 'Response is null or not a valid type.'
314
- found_bundle = found_libraries = false
315
- # are extensions present in any questionnaire?
316
- resource.parameter.each do |param|
317
- # Do out put parameters have a bundle?
318
- next unless param.resource.resourceType == 'Bundle'
319
-
320
- found_bundle = true
321
- # check the libraries first so references in questionnaires can be checked after
322
- param.resource.entry.each_with_index do |entry, index|
323
- next unless entry.resource.resourceType == 'Library'
324
-
325
- found_libraries = true
326
- library_urls.add(entry.resource.url) unless entry.resource.url.nil?
327
- evaluate_library(entry, index)
328
- library_names.add(entry.resource.name)
329
- end
330
- assert found_libraries, 'No Libraries found.'
226
+ def check_libraries(questionnaire_bundles)
227
+ libraries = extract_libraries_from_bundles(questionnaire_bundles)
228
+
229
+ assert libraries.any?, 'No Libraries found.'
230
+
231
+ libraries.each do |lib|
232
+ library_urls.add(lib.url) unless lib.url.nil?
233
+ evaluate_library(lib)
234
+ library_names.add(lib.name)
331
235
  end
332
- assert found_bundle, 'No questionnaire bundles found.'
333
236
  end
334
237
 
335
238
  def check_library_references
@@ -405,28 +308,22 @@ module DaVinciDTRTestKit
405
308
  end
406
309
  end
407
310
 
408
- def q_responses(response)
409
- questionnaire_responses = []
410
- response.each do |resource|
411
- fhir_resource = FHIR.from_contents(resource.response_body)
412
- questionnaire_responses << fhir_resource if fhir_resource.resourceType == 'QuestionnaireResponse'
413
- next unless resource.instance_of? Inferno::Entities::Request
414
-
415
- if fhir_resource.resourceType == 'Questionnaire' || fhir_resource.resourceType == 'Parameters'
416
- return fhir_resource
417
- end
418
- end
419
- questionnaire_responses
311
+ def extract_contained_questionnaires(questionnaire_responses)
312
+ questionnaire_responses&.filter_map do |qr|
313
+ qr.contained&.filter { |resource| resource.is_a?(FHIR::Questionnaire) }
314
+ end&.flatten&.compact
420
315
  end
421
316
 
422
- def process_response(response)
423
- if response.instance_of?(FHIR::Parameters) || response.instance_of?(FHIR::QuestionnaireResponse)
424
- return response
425
- elsif response.instance_of? Array
426
- return q_responses(response)
427
- end
317
+ def extract_questionnaires_from_bundles(questionnaire_bundles)
318
+ questionnaire_bundles.filter_map do |qb|
319
+ qb.entry.filter_map { |entry| entry.resource if entry.resource.is_a?(FHIR::Questionnaire) }
320
+ end&.flatten&.compact
321
+ end
428
322
 
429
- nil
323
+ def extract_libraries_from_bundles(questionnaire_bundles)
324
+ questionnaire_bundles.filter_map do |qb|
325
+ qb.entry.filter_map { |entry| entry.resource if entry&.resource.is_a?(FHIR::Library) }
326
+ end&.flatten&.compact
430
327
  end
431
328
  end
432
329
  end
@@ -0,0 +1,25 @@
1
+ module DaVinciDTRTestKit
2
+ module CreateTest
3
+ def perform_create_test(create_resources, resource_type)
4
+ skip_if(create_resources.blank?, "No `#{resource_type}` resources to create provided, skipping test.")
5
+ assert_valid_json(create_resources)
6
+ create_resources_list = JSON.parse(create_resources)
7
+ skip_if(!create_resources_list.is_a?(Array), 'Resources to create not inputted in list format, skipping test.')
8
+
9
+ valid_create_resources =
10
+ create_resources_list
11
+ .compact_blank
12
+ .map { |resource| FHIR.from_contents(resource.to_json) }
13
+ .select { |resource| resource.resourceType == resource_type }
14
+ .select { |resource| resource_is_valid?(resource:) }
15
+
16
+ skip_if(valid_create_resources.blank?,
17
+ %(No valid #{resource_type} resources were provided to send in Create requests, skipping test.))
18
+
19
+ valid_create_resources.each do |create_resource|
20
+ fhir_create(create_resource)
21
+ assert_response_status(201)
22
+ end
23
+ end
24
+ end
25
+ end