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
@@ -1,3 +1,4 @@
1
+ require_relative '../../descriptions'
1
2
  require_relative '../../urls'
2
3
 
3
4
  module DaVinciDTRTestKit
@@ -12,16 +13,16 @@ module DaVinciDTRTestKit
12
13
  )
13
14
  verifies_requirements 'hl7.fhir.us.davinci-dtr_2.0.1@165', 'hl7.fhir.us.davinci-dtr_2.0.1@262'
14
15
 
15
- input :access_token,
16
- description: %(
17
- `Bearer` token that the client under test will send in the
18
- `Authorization` header of each HTTP request to Inferno. Inferno
19
- will look for this value to associate requests with this session.
20
- )
16
+ input :client_id,
17
+ title: 'Client Id',
18
+ type: 'text',
19
+ optional: true,
20
+ locked: true,
21
+ description: INPUT_CLIENT_ID_LOCKED
21
22
 
22
23
  run do
23
24
  wait(
24
- identifier: access_token,
25
+ identifier: client_id,
25
26
  message: %(
26
27
  ### Questionnaire Package
27
28
 
@@ -32,19 +33,10 @@ module DaVinciDTRTestKit
32
33
 
33
34
  A questionnaire package generated by Inferno will be returned.
34
35
 
35
- ### Request Identification
36
-
37
- In order to identify requests for this session, Inferno will look for
38
- an `Authorization` header with value:
39
-
40
- ```
41
- Bearer #{access_token}
42
- ```
43
-
44
36
  ### Continuing the Tests
45
37
 
46
38
  When the DTR application has finished loading the Questionnaire
47
- [Click here](#{resume_pass_url}?token=#{access_token}) to continue.
39
+ [Click here](#{resume_pass_url}?token=#{client_id}) to continue.
48
40
  )
49
41
  )
50
42
  end
@@ -17,10 +17,19 @@ module DaVinciDTRTestKit
17
17
  )
18
18
  verifies_requirements 'hl7.fhir.us.davinci-dtr_2.0.1@209', 'hl7.fhir.us.davinci-dtr_2.0.1@210'
19
19
 
20
+ input :custom_questionnaire_package_response,
21
+ title: 'Custom Questionnaire Package Response JSON',
22
+ description: %(
23
+ The custom $questionnaire-package response used in the previous tests, if provided.
24
+ ),
25
+ type: 'textarea',
26
+ optional: true,
27
+ locked: true
28
+
20
29
  run do
21
30
  skip_if questionnaire_response.blank?, 'Completed QuestionnaireResponse input was blank'
22
31
 
23
- validate_questionnaire_response_correctness(questionnaire_response, try(:custom_questionnaire_package_response))
32
+ validate_questionnaire_response_correctness(questionnaire_response, custom_questionnaire_package_response)
24
33
  end
25
34
  end
26
35
  end
@@ -16,14 +16,14 @@ module DaVinciDTRTestKit
16
16
  random_id = SecureRandom.uuid
17
17
  wait(
18
18
  identifier: random_id,
19
- message: %(
20
- I attest that the questionnaire has been completed and stored within the EHR for future
19
+ message: <<~MESSAGE
20
+ I attest that questionnaires have been completed and stored within the EHR for future
21
21
  use and export as a FHIR QuestionnaireResponse instance.
22
22
 
23
23
  [Click here](#{resume_pass_url}?token=#{random_id}) if the above statement is **true**.
24
24
 
25
25
  [Click here](#{resume_fail_url}?token=#{random_id}) if the above statement is **false**.
26
- )
26
+ MESSAGE
27
27
  )
28
28
  end
29
29
  end
@@ -37,9 +37,8 @@ module DaVinciDTRTestKit
37
37
  %(fhirContext not present on the passed launch context, skipping test.))
38
38
 
39
39
  context_reference = token_response_params['fhirContext'].filter do |c|
40
- c.split('/')[0] == 'DeviceRequest' || c.split('/')[0] == 'ServiceRequest' ||
41
- c.split('/')[0] == 'CommunicationRequest' || c.split('/')[0] == 'MedicationRequest' ||
42
- c.split('/')[0] == 'Encounter' || c.split('/')[0] == 'Task' || c.split('/')[0] == 'QuestionnaireResponse'
40
+ ['DeviceRequest', 'ServiceRequest', 'CommunicationRequest', 'MedicationRequest', 'Encounter', 'Task',
41
+ 'QuestionnaireResponse'].include?(c.split('/')[0])
43
42
  end
44
43
 
45
44
  assert context_reference.present?,
@@ -49,11 +48,11 @@ module DaVinciDTRTestKit
49
48
  assert context_reference_amount == 1,
50
49
  'fhirContext should only contain one CRD-type request, QuestionnaireResponse, or Task'
51
50
 
52
- crd_request_array = [(context_reference[0]).split('/')[1]]
51
+ crd_request_array = [context_reference[0].split('/')[1]]
53
52
  assert crd_request_array.present?,
54
53
  'fhirContext does not contain a CRD-type request, QuestionnaireResponse, or Task resource in proper format'
55
54
 
56
- perform_read_test(crd_request_array, (context_reference[0]).split('/')[0])
55
+ perform_read_test(crd_request_array, context_reference[0].split('/')[0])
57
56
  end
58
57
  end
59
58
  end
@@ -0,0 +1,75 @@
1
+ require_relative '../../descriptions'
2
+ require_relative '../../urls'
3
+ require_relative 'questionnaire_must_support_elements'
4
+
5
+ module DaVinciDTRTestKit
6
+ class DTRFullEHRMSQuestionnairePackageRequestTest < Inferno::Test
7
+ include URLs
8
+ include QuestionnaireMustSupportElements
9
+
10
+ id :dtr_full_ehr_ms_qp_request
11
+ title 'Invoke the Questionnaire Package Operation and Demonstrate mustSupport Handling'
12
+ description <<~DESCRIPTION
13
+ Inferno will wait for a DTR Questionnaire package request from the client. Upon receipt,
14
+ Inferno will return the user-provided Questionnaire package as the response to the $questionnaire-package request.
15
+
16
+ Afterward, Inferno will wait for the user to visually demonstrate support (via UI cues or guidance)
17
+ for the following mustSupport elements, as defined in the [DTR Standard Questionnaire profile](http://hl7.org/fhir/us/davinci-dtr/StructureDefinition/dtr-std-questionnaire):
18
+
19
+ #{STATIC_QUESTIONNAIRE.map { |el| "- #{el}" }.join("\n")}
20
+ DESCRIPTION
21
+ config options: { accepts_multiple_requests: true }
22
+ verifies_requirements 'hl7.fhir.us.davinci-dtr_2.0.1@165', 'hl7.fhir.us.davinci-dtr_2.0.1@262'
23
+ input :custom_questionnaire_package_response
24
+ input :client_id,
25
+ title: 'Client Id',
26
+ type: 'text',
27
+ optional: true,
28
+ locked: true,
29
+ description: INPUT_CLIENT_ID_LOCKED
30
+
31
+ run do
32
+ assert_valid_json(
33
+ custom_questionnaire_package_response,
34
+ 'Custom questionnaire package response is not a valid json'
35
+ )
36
+
37
+ custom_qp = JSON.parse(custom_questionnaire_package_response)
38
+ assert custom_qp.present?, %(
39
+ Custom questionnaire package response is empty, please provide a custom questionnaire package response
40
+ for the $questionnaire-package request
41
+ )
42
+
43
+ wait(
44
+ identifier: client_id,
45
+ timeout: 1800,
46
+ message: <<~MESSAGE
47
+ ### Questionnaire Package
48
+
49
+ Inferno will wait for the Full EHR to invoke the DTR Questionnaire Package operation by sending a POST
50
+ request to
51
+
52
+ `#{questionnaire_package_url}`
53
+
54
+ Inferno will return the **user-provided Questionnaire package** in the response.
55
+
56
+ ### MustSupport Elements Visual Inspection
57
+
58
+ After the Questionnaire package is loaded, complete the form(s) within the client system and
59
+ **visually inspect** that the application correctly supports all mustSupport elements as defined in the
60
+ [DTR Standard Questionnaire profile](http://hl7.org/fhir/us/davinci-dtr/StructureDefinition/dtr-std-questionnaire).
61
+ Support should be demonstrated via visual cues, UI behavior, or other relevant indicators.
62
+
63
+ The mustSupport elements include:
64
+
65
+ #{STATIC_QUESTIONNAIRE.map { |el| "- #{el}" }.join("\n")}
66
+
67
+ ### Continuing the Tests
68
+
69
+ Once the Questionnaire has been loaded and the visual inspection is complete,
70
+ [Click here](#{resume_pass_url}?token=#{client_id}) to continue.
71
+ MESSAGE
72
+ )
73
+ end
74
+ end
75
+ end
@@ -0,0 +1,85 @@
1
+ require_relative '../../urls'
2
+ require_relative 'dtr_full_ehr_ms_questionnaire_package_request_test'
3
+ require_relative '../shared/dtr_questionnaire_package_request_validation_test'
4
+ require_relative '../shared/dtr_custom_questionnaire_package_validation_test'
5
+ require_relative 'dtr_must_support_attestation_test'
6
+ require_relative 'dtr_questionnaire_must_support_test'
7
+ require_relative 'questionnaire_must_support_elements'
8
+
9
+ module DaVinciDTRTestKit
10
+ class DTRFullEHRQuestionnaireMustSupportGroup < Inferno::TestGroup
11
+ include QuestionnaireMustSupportElements
12
+
13
+ id :dtr_full_ehr_questionnaire_ms
14
+ title 'Demonstrate Questionnaire Element Support'
15
+ description %(
16
+ ### Questionnaire Package Request and mustSupport Visual Inspection
17
+
18
+ During this test, Inferno will wait for the client system to request the questionnaire(s) using the
19
+ `$questionnaire-package` operation and will return the user-provided Questionnaire package for the
20
+ tester to complete.
21
+
22
+ The tester will then demonstrate that the client system supports the
23
+ `mustSupport` elements defined in the [DTR Standard Questionnaire](http://hl7.org/fhir/us/davinci-dtr/StructureDefinition/dtr-std-questionnaire)
24
+ profile through visual inspection (e.g., rendering, UI behavior, or guidance).
25
+
26
+ Since there are no non-required `mustSupport` elements defined in the [DTR Adaptive Questionnaire]('http://hl7.org/fhir/us/davinci-dtr/StructureDefinition/dtr-questionnaire-adapt')
27
+ profile that are not present in the DTR Standard Questionnaire profile, demonstrating that the client
28
+ system supports DTR Standard Questionnaire `mustSupport` elements plus an adaptive questionnaire workflow
29
+ is sufficient to show that DTR Adaptive Questionnaire `mustSupport` elements are supported.
30
+
31
+ ### Profile Validation
32
+
33
+ Inferno will validate that:
34
+ - The $questionnaire-package request conforms to [DTR Questionnaire Package Input Parameters](http://hl7.org/fhir/us/davinci-dtr/StructureDefinition/dtr-qpackage-input-parameters)
35
+ - The response to the `$questionnaire-package` operation conforms to the [Questionnaire Package
36
+ operation definition](https://hl7.org/fhir/us/davinci-dtr/STU2/OperationDefinition-questionnaire-package.html).
37
+
38
+ ### Must Support
39
+
40
+ Each profile contains elements marked as "must support". Inferno expects to see each of
41
+ these elements at least once. If at least one cannot be found, the test will skip.
42
+ The test will look through the Questionnaire resources provided for these elements.
43
+ )
44
+ run_as_group
45
+ config(
46
+ options: {
47
+ questionnaire_package_tag: "ms_static_#{QUESTIONNAIRE_PACKAGE_TAG}"
48
+ },
49
+ inputs: {
50
+ custom_questionnaire_package_response: {
51
+ name: 'ms_custom_questionnaire_package_response',
52
+ title: 'Custom Questionnaire Package Response JSON for Must Support tests',
53
+ description: %(
54
+ Provide a JSON `$questionnaire-package` response (a FHIR Parameters resource)
55
+ containing one or more `PackageBundle` entries. Inferno will return this as
56
+ the response to the `$questionnaire-package` request.
57
+ The Questionnaire in each `PackageBundle` **must include all `mustSupport` elements**
58
+ as defined in the DTR Standard Questionnaire profile.
59
+ )
60
+
61
+ }
62
+ }
63
+ )
64
+
65
+ # Test 1: wait for the $questionnaire-package request
66
+ test from: :dtr_full_ehr_ms_qp_request
67
+ # Test 2: validate the $questionnaire-package body
68
+ test from: :dtr_qp_request_validation
69
+ # Test 3: validate the user provided $questionnaire-package response
70
+ test from: :dtr_custom_qp_validation
71
+ # Test 4: must support test
72
+ test from: :dtr_questionnaire_must_support,
73
+ title: '[USER INPUT VALIDATION] All must support elements are provided in the static Questionnaire resources provided', # rubocop:disable Layout/LineLength
74
+ description: <<~DESCRIPTION
75
+ The DTR client SHALL be able to handle all `mustSupport` elements defined in the
76
+ [DTR Standard Questionnaire](http://hl7.org/fhir/us/davinci-dtr/StructureDefinition/dtr-std-questionnaire)
77
+ profile. This test will look through the provided Questionnaire resources for the following
78
+ must support elements:
79
+
80
+ #{STATIC_QUESTIONNAIRE.map { |el| "- #{el}" }.join("\n")}
81
+ DESCRIPTION
82
+ # Test 5: attest client system can handle `mustSupport` elements
83
+ test from: :dtr_must_support_attest
84
+ end
85
+ end
@@ -0,0 +1,39 @@
1
+ require 'securerandom'
2
+ require_relative '../../urls'
3
+ module DaVinciDTRTestKit
4
+ class DTRMustSupportAttestationTest < Inferno::Test
5
+ include URLs
6
+ id :dtr_must_support_attest
7
+ title 'Support for mustSupport Elements in Questionnaire (Attestation)'
8
+ description %(
9
+ The DTR client SHALL be able to handle all `mustSupport` elements defined in the Questionnaire profile.
10
+
11
+ The tester attests that the client has:
12
+ - Successfully requested, rendered, and completed each of the provided questionnaires.
13
+ - Presented appropriate visual cues or guidance wherever `mustSupport` elements affect expected user actions.
14
+ )
15
+ verifies_requirements 'hl7.fhir.us.davinci-dtr_2.0.1@15', 'hl7.fhir.us.davinci-dtr_2.0.1@16',
16
+ 'hl7.fhir.us.davinci-dtr_2.0.1@65', 'hl7.fhir.us.davinci-dtr_2.0.1@66',
17
+ 'hl7.fhir.us.davinci-dtr_2.0.1@206'
18
+
19
+ run do
20
+ random_id = SecureRandom.uuid
21
+ wait(
22
+ identifier: random_id,
23
+ message: %(
24
+ I attest that the client application successfully handled all `mustSupport` elements
25
+ defined in the [DTR Standard Questionnaire profile](http://hl7.org/fhir/us/davinci-dtr/StructureDefinition/dtr-std-questionnaire|2.0.1)
26
+ by, and therefore is capable of successfully handling all `mustSupport` elements defined in the
27
+ [DTR Adaptive Questionnaire profile](http://hl7.org/fhir/us/davinci-dtr/StructureDefinition/dtr-questionnaire-adapt|2.0.1):
28
+
29
+ - Requesting, rendering, and completing each of the provided questionnaires.
30
+ - Displaying appropriate visual cues or guidance where `mustSupport` elements impact expected user actions.
31
+
32
+ [Click here](#{resume_pass_url}?token=#{random_id}) if the above statement is **true**.
33
+
34
+ [Click here](#{resume_fail_url}?token=#{random_id}) if the above statement is **false**.
35
+ )
36
+ )
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,42 @@
1
+ require_relative '../../cql_test'
2
+
3
+ module DaVinciDTRTestKit
4
+ class DTRQuestionnaireMustSupportTes < Inferno::Test
5
+ include DaVinciDTRTestKit::CQLTest
6
+ id :dtr_questionnaire_must_support
7
+ verifies_requirements 'hl7.fhir.us.davinci-dtr_2.0.1@15', 'hl7.fhir.us.davinci-dtr_2.0.1@65',
8
+ 'hl7.fhir.us.davinci-dtr_2.0.1@66', 'hl7.fhir.us.davinci-dtr_2.0.1@206'
9
+
10
+ def form_type
11
+ config.options[:form_type] || 'static'
12
+ end
13
+
14
+ def profile_url
15
+ if form_type == 'adaptive'
16
+ 'http://hl7.org/fhir/us/davinci-dtr/StructureDefinition/dtr-questionnaire-adapt'
17
+ else
18
+ 'http://hl7.org/fhir/us/davinci-dtr/StructureDefinition/dtr-std-questionnaire'
19
+ end
20
+ end
21
+
22
+ run do
23
+ questionnaires = nil
24
+ if form_type == 'static'
25
+ skip_if scratch[:"#{form_type}_questionnaire_bundles"].blank?,
26
+ 'No questionnaire bundle found in the custom Questionnaire Package response'
27
+
28
+ questionnaires = extract_questionnaires_from_bundles(scratch[:"#{form_type}_questionnaire_bundles"])
29
+ else
30
+ assert_valid_json custom_next_question_questionnaires,
31
+ 'Custom $next-question questionnaires not valid JSON'
32
+ custom_questionnaires = [JSON.parse(custom_next_question_questionnaires)].flatten.compact
33
+ questionnaires = custom_questionnaires.map { |q| FHIR.from_contents(q.to_json) }.compact
34
+ end
35
+
36
+ skip_if questionnaires.blank? || questionnaires.none? { |q| q.is_a?(FHIR::Questionnaire) },
37
+ 'No Questionnaire resources found.'
38
+
39
+ skip { assert_must_support_elements_present(questionnaires, profile_url) }
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,148 @@
1
+ require 'base64'
2
+ require_relative '../../urls'
3
+ require_relative 'questionnaire_must_support_elements'
4
+
5
+ module DaVinciDTRTestKit
6
+ class DTRSmartAppMSQuestionnairePackageRequestTest < Inferno::Test
7
+ include URLs
8
+ include QuestionnaireMustSupportElements
9
+
10
+ id :dtr_smart_app_ms_qp_request
11
+ title 'Invoke the Questionnaire Package Operation and Demonstrate mustSupport Handling'
12
+ description <<~DESCRIPTION
13
+ Inferno will wait for a DTR Questionnaire package request from the client. Upon receipt,
14
+ Inferno will return the user-provided Questionnaire package as the response to the $questionnaire-package request.
15
+
16
+ Afterward, Inferno will wait for the user to visually demonstrate support (via UI cues or guidance)
17
+ for the following mustSupport elements, as defined in the [DTR Standard Questionnaire profile](http://hl7.org/fhir/us/davinci-dtr/StructureDefinition/dtr-std-questionnaire):
18
+
19
+ #{STATIC_QUESTIONNAIRE.map { |el| "- #{el}" }.join("\n")}
20
+ DESCRIPTION
21
+ config options: { accepts_multiple_requests: true }
22
+
23
+ input :custom_questionnaire_package_response
24
+ input :smart_app_launch,
25
+ type: 'radio',
26
+ title: 'SMART App Launch',
27
+ description: 'How will the DTR SMART App launch?',
28
+ options: { list_options: [{ label: 'EHR Launch from Inferno', value: 'ehr' },
29
+ { label: 'Standalone Launch', value: 'standalone' }] }
30
+ input :client_id
31
+ input :launch_uri,
32
+ optional: true,
33
+ description: 'Required if "Launch from Inferno" is selected'
34
+ input :static_smart_patient_id,
35
+ optional: true,
36
+ title: 'SMART App Launch Patient ID',
37
+ type: 'text',
38
+ description: %(
39
+ Patient instance ID to be provided by Inferno as the patient as a part of the SMART App Launch.
40
+ ),
41
+ default: 'pat015'
42
+ input :ms_static_smart_fhir_context,
43
+ optional: true,
44
+ title: 'SMART App Launch fhirContext for mustSupport Test',
45
+ type: 'textarea',
46
+ description: %(
47
+ References to be provided by Inferno as the fhirContext as a part of the SMART App
48
+ Launch. These references help determine the behavior of the app. Referenced instances
49
+ may be provided in the "EHR-available resources" input.
50
+ ),
51
+ default: JSON.pretty_generate([{ reference: 'Coverage/cov015' },
52
+ { reference: 'DeviceRequest/devreqe0470' }])
53
+ input :ms_static_ehr_bundle,
54
+ optional: true,
55
+ title: 'EHR-available resources for mustSupport test',
56
+ type: 'textarea',
57
+ description: %(
58
+ Resources available from the EHR needed to drive this workflow.
59
+ Formatted as a FHIR bundle that contains resources, each with an ID property populated. Each
60
+ instance present will be available for retrieval from Inferno at the endpoint:
61
+ <fhir-base>/<resource type>/<instance id>
62
+ )
63
+
64
+ def example_client_jwt_payload_part
65
+ Base64.strict_encode64({ inferno_client_id: client_id }.to_json).delete('=')
66
+ end
67
+
68
+ run do
69
+ assert_valid_json(
70
+ custom_questionnaire_package_response,
71
+ 'Custom questionnaire package response is not a valid json'
72
+ )
73
+
74
+ custom_qp = JSON.parse(custom_questionnaire_package_response)
75
+ assert custom_qp.present?, %(
76
+ Custom questionnaire package response is empty, please provide a custom questionnaire package response
77
+ for the $questionnaire-package request
78
+ )
79
+ # validate relevant inputs and provide warnings if they are bad
80
+ warning do
81
+ if ms_static_smart_fhir_context
82
+ assert_valid_json(ms_static_smart_fhir_context,
83
+ 'The **SMART App Launch fhirContext** input is not valid JSON, so it will not be included in
84
+ the access token response.')
85
+ end
86
+ end
87
+
88
+ launch_prompt = if smart_app_launch == 'ehr'
89
+ %(Launch the DTR SMART App from Inferno by right clicking
90
+ [this link](#{launch_uri}?iss=#{fhir_base_url}&launch=#{launch_uri})
91
+ and selecting "Open in new window" or "Open in new tab".)
92
+ else
93
+ %(Launch the SMART App from your EHR.)
94
+ end
95
+ inferno_prompt_cont = %(As the DTR app steps through the launch steps, Inferno will wait and respond to the app's
96
+ requests for SMART configuration, authorization and access token.)
97
+
98
+ wait(
99
+ identifier: client_id,
100
+ timeout: 1800,
101
+ message: <<~MESSAGE
102
+ ### SMART APP Lauch and Questionnaire Package
103
+
104
+ #{launch_prompt}
105
+
106
+ #{inferno_prompt_cont if smart_app_launch == 'ehr'}
107
+
108
+ Then, Inferno will wait for the SMART APP to invoke the DTR Questionnaire Package operation by sending a POST
109
+ request to
110
+
111
+ `#{questionnaire_package_url}`
112
+
113
+ Inferno will return the **user-provided Questionnaire package** in the response.
114
+
115
+ ### Pre-population and MustSupport Elements Visual Inspection
116
+
117
+ After the Questionnaire package is loaded, Inferno will wait for the client to
118
+ complete Questionnaire pre-population. The client should make FHIR GET requests using service base path:
119
+
120
+ `#{fhir_base_url}`
121
+
122
+ The tester will complete the form(s) within the client system and
123
+ **visually inspect** that the application correctly supports all mustSupport elements as defined in the
124
+ [DTR Standard Questionnaire profile](http://hl7.org/fhir/us/davinci-dtr/StructureDefinition/dtr-std-questionnaire).
125
+ Support should be demonstrated via visual cues, UI behavior, or other relevant indicators.
126
+
127
+ The mustSupport elements include:
128
+
129
+ #{STATIC_QUESTIONNAIRE.map { |el| "- #{el}" }.join("\n")}
130
+
131
+ ### Request Identification
132
+
133
+ In order to identify requests for this session, Inferno will look for
134
+ an `Authorization` header with value:
135
+
136
+ ```
137
+ Bearer eyJhbGciOiJub25lIn0.#{example_client_jwt_payload_part}.
138
+ ```
139
+
140
+ ### Continuing the Tests
141
+
142
+ Once the Questionnaire has been loaded and the visual inspection is complete,
143
+ [Click here](#{resume_pass_url}?client_id=#{client_id}) to continue.
144
+ MESSAGE
145
+ )
146
+ end
147
+ end
148
+ end
@@ -0,0 +1,85 @@
1
+ require_relative '../../urls'
2
+ require_relative 'dtr_smart_app_ms_questionnaire_package_request_test'
3
+ require_relative '../shared/dtr_questionnaire_package_request_validation_test'
4
+ require_relative '../shared/dtr_custom_questionnaire_package_validation_test'
5
+ require_relative 'dtr_questionnaire_must_support_test'
6
+ require_relative 'dtr_must_support_attestation_test'
7
+ require_relative 'questionnaire_must_support_elements'
8
+
9
+ module DaVinciDTRTestKit
10
+ class DTRSmartAppQuestionnaireMustSupportGroup < Inferno::TestGroup
11
+ include QuestionnaireMustSupportElements
12
+
13
+ id :dtr_smart_app_questionnaire_ms
14
+ title 'Demonstrate Questionnaire Element Support'
15
+ description %(
16
+ ### Questionnaire Package Request and mustSupport Visual Inspection
17
+
18
+ During this test, Inferno will wait for the client system to request the questionnaire(s) using the
19
+ `$questionnaire-package` operation and will return the user-provided Questionnaire package for the
20
+ tester to complete.
21
+
22
+ The tester will then demonstrate that the client system supports the
23
+ `mustSupport` elements defined in the [DTR Standard Questionnaire](http://hl7.org/fhir/us/davinci-dtr/StructureDefinition/dtr-std-questionnaire)
24
+ profile through visual inspection (e.g., rendering, UI behavior, or guidance).
25
+
26
+ Since there are no non-required `mustSupport` elements defined in the [DTR Adaptive Questionnaire]('http://hl7.org/fhir/us/davinci-dtr/StructureDefinition/dtr-questionnaire-adapt')
27
+ profile that are not present in the DTR Standard Questionnaire profile, demonstrating that the client
28
+ system supports DTR Standard Questionnaire `mustSupport` elements plus an adaptive questionnaire workflow
29
+ is sufficient to show that DTR Adaptive Questionnaire `mustSupport` elements are supported.
30
+
31
+ ### Profile Validation
32
+
33
+ Inferno will validate that:
34
+ - The $questionnaire-package request conforms to [DTR Questionnaire Package Input Parameters](http://hl7.org/fhir/us/davinci-dtr/StructureDefinition/dtr-qpackage-input-parameters)
35
+ - The response to the `$questionnaire-package` operation conforms to the [Questionnaire Package
36
+ operation definition](https://hl7.org/fhir/us/davinci-dtr/STU2/OperationDefinition-questionnaire-package.html).
37
+
38
+ ### Must Support
39
+
40
+ Each profile contains elements marked as "must support". Inferno expects to see each of
41
+ these elements at least once. If at least one cannot be found, the test will skip.
42
+ The test will look through the Questionnaire resources provided for these elements.
43
+ )
44
+ run_as_group
45
+ config(
46
+ options: {
47
+ questionnaire_package_tag: "ms_static_#{QUESTIONNAIRE_PACKAGE_TAG}"
48
+ },
49
+ inputs: {
50
+ custom_questionnaire_package_response: {
51
+ name: 'ms_custom_questionnaire_package_response',
52
+ title: 'Custom Questionnaire Package Response JSON for Must Support tests',
53
+ description: %(
54
+ Provide a JSON `$questionnaire-package` response (a FHIR Parameters resource)
55
+ containing one or more `PackageBundle` entries. Inferno will return this as
56
+ the response to the `$questionnaire-package` request.
57
+ The Questionnaire in each `PackageBundle` **must include all `mustSupport` elements**
58
+ as defined in the DTR Standard Questionnaire profile.
59
+ )
60
+
61
+ }
62
+ }
63
+ )
64
+
65
+ # Test 1: wait for the $questionnaire-package request
66
+ test from: :dtr_smart_app_ms_qp_request
67
+ # Test 2: validate the $questionnaire-package body
68
+ test from: :dtr_qp_request_validation
69
+ # Test 3: validate the user provided $questionnaire-package response
70
+ test from: :dtr_custom_qp_validation
71
+ # Test 4: must support test
72
+ test from: :dtr_questionnaire_must_support,
73
+ title: '[USER INPUT VALIDATION] All must support elements are provided in the static Questionnaire resources provided', # rubocop:disable Layout/LineLength
74
+ description: <<~DESCRIPTION
75
+ The DTR client SHALL be able to handle all `mustSupport` elements defined in the
76
+ [DTR Standard Questionnaire](http://hl7.org/fhir/us/davinci-dtr/StructureDefinition/dtr-std-questionnaire)
77
+ profile. This test will look through the provided Questionnaire resources for the following
78
+ must support elements:
79
+
80
+ #{STATIC_QUESTIONNAIRE.map { |el| "- #{el}" }.join("\n")}
81
+ DESCRIPTION
82
+ # Test 5: attest client system can handle `mustSupport` elements
83
+ test from: :dtr_must_support_attest
84
+ end
85
+ end
@@ -0,0 +1,55 @@
1
+ module DaVinciDTRTestKit
2
+ module QuestionnaireMustSupportElements
3
+ STATIC_QUESTIONNAIRE = [
4
+ 'Questionnaire.url',
5
+ 'Questionnaire.version',
6
+ 'Questionnaire.title',
7
+ 'Questionnaire.status',
8
+ 'Questionnaire.subjectType',
9
+ 'Questionnaire.effectivePeriod',
10
+ 'Questionnaire.item',
11
+ 'Questionnaire.item.linkId',
12
+ 'Questionnaire.item.prefix',
13
+ 'Questionnaire.item.text',
14
+ 'Questionnaire.item.type',
15
+ 'Questionnaire.item.enableWhen',
16
+ 'Questionnaire.item.enableBehavior',
17
+ 'Questionnaire.item.required',
18
+ 'Questionnaire.item.repeats',
19
+ 'Questionnaire.item.readOnly',
20
+ 'Questionnaire.item.maxLength',
21
+ 'Questionnaire.item.answerValueSet',
22
+ 'Questionnaire.item.answerOption',
23
+ 'Questionnaire.item.answerOption.value[x]',
24
+ 'Questionnaire.item.initial',
25
+ 'Questionnaire.item.initial.value[x]',
26
+ 'Questionnaire.item.item',
27
+ 'Questionnaire.extension:terminologyServer',
28
+ 'Questionnaire.extension:performerType',
29
+ 'Questionnaire.extension:assemble-expectation',
30
+ 'Questionnaire.extension:entryMode',
31
+ 'Questionnaire.extension:signatureRequired',
32
+ 'Questionnaire.extension:cqf-library',
33
+ 'Questionnaire.extension:launchContext',
34
+ 'Questionnaire.extension:variable',
35
+ 'Questionnaire.extension:itemPopulationContext',
36
+ 'Questionnaire.item.extension:itemHidden',
37
+ 'Questionnaire.item.extension:itemControl',
38
+ 'Questionnaire.item.extension:supportLink',
39
+ 'Questionnaire.item.extension:mimeType',
40
+ 'Questionnaire.item.extension:unitOption',
41
+ 'Questionnaire.item.extension:unitValueSet',
42
+ 'Questionnaire.item.extension:referenceResource',
43
+ 'Questionnaire.item.extension:referenceProfile',
44
+ 'Questionnaire.item.extension:candidateExpression',
45
+ 'Questionnaire.item.extension:lookupQuestionnaire',
46
+ 'Questionnaire.item.extension:initialExpression',
47
+ 'Questionnaire.item.extension:calculatedExpression',
48
+ 'Questionnaire.item.extension:enableWhenExpression',
49
+ 'Questionnaire.item.extension:contextExpression',
50
+ 'Questionnaire.item.text.extension:itemTextRenderingXhtml',
51
+ 'Questionnaire.item.answerOption.extension:optionExclusive',
52
+ 'Questionnaire.item.answerOption.value[x].extension:answerOptionRenderingXhtml'
53
+ ].freeze
54
+ end
55
+ end