Skip to content

Commit

Permalink
Added Support for optionExclusive Extension in Popup (#2438)
Browse files Browse the repository at this point in the history
* Added Support for optionExclusive Extension in Popup

* Added Test Cases for optionExclusive Extension in Popup

* Added Other Test Cases for optionExclusive Extension in Popup

* Update Code Formatting to Fix Build Error

* Less Answer Option Items to Avoid Failure of Test Cases
  • Loading branch information
asad-zaman authored Mar 7, 2024
1 parent ac5fd62 commit 7862d25
Show file tree
Hide file tree
Showing 2 changed files with 238 additions and 4 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2023 Google LLC
* Copyright 2023-2024 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -35,6 +35,7 @@ import com.google.android.fhir.datacapture.R
import com.google.android.fhir.datacapture.extensions.DisplayItemControlType
import com.google.android.fhir.datacapture.extensions.EXTENSION_ITEM_CONTROL_SYSTEM
import com.google.android.fhir.datacapture.extensions.EXTENSION_ITEM_CONTROL_URL
import com.google.android.fhir.datacapture.extensions.EXTENSION_OPTION_EXCLUSIVE_URL
import com.google.android.fhir.datacapture.extensions.ItemControlTypes
import com.google.android.fhir.datacapture.test.TestActivity
import com.google.android.fhir.datacapture.test.utilities.assertQuestionnaireResponseAtIndex
Expand All @@ -52,6 +53,7 @@ import com.google.android.material.textfield.TextInputLayout
import com.google.common.truth.StringSubject
import com.google.common.truth.Truth.assertThat
import org.hamcrest.Matchers.not
import org.hl7.fhir.r4.model.BooleanType
import org.hl7.fhir.r4.model.CodeableConcept
import org.hl7.fhir.r4.model.Coding
import org.hl7.fhir.r4.model.Extension
Expand Down Expand Up @@ -101,6 +103,136 @@ class QuestionnaireItemDialogMultiSelectViewHolderFactoryEspressoTest {
assertQuestionnaireResponseAtIndex(answerHolder!!, "Coding 1", "Coding 3", "Coding 5")
}

@Test
fun multipleChoice_selectMultiple_selectExclusive_clickSave_shouldSaveOnlyExclusiveOption() {
var answerHolder: List<QuestionnaireResponse.QuestionnaireResponseItemAnswerComponent>? = null
val questionnaireViewItem =
QuestionnaireViewItem(
answerOptions(true, "Coding 1", "Coding 2", "Coding 3")
.addAnswerOption(
Questionnaire.QuestionnaireItemAnswerOptionComponent().apply {
value = Coding().apply { display = "Coding Exclusive" }
extension = listOf(Extension(EXTENSION_OPTION_EXCLUSIVE_URL, BooleanType(true)))
},
),
responseOptions(),
validationResult = NotValidated,
answersChangedCallback = { _, _, answers, _ -> answerHolder = answers },
)

runOnUI { viewHolder.bind(questionnaireViewItem) }

endIconClickInTextInputLayout(R.id.multi_select_summary_holder)
clickOnTextInDialog("Coding 1")
clickOnText("Coding 3")
clickOnText("Coding Exclusive")
clickOnText("Save")

assertDisplayedText().isEqualTo("Coding Exclusive")
assertQuestionnaireResponseAtIndex(answerHolder!!, "Coding Exclusive")
}

@Test
fun multipleChoice_selectExclusive_selectMultiple_clickSave_shouldSaveWithoutExclusiveOption() {
var answerHolder: List<QuestionnaireResponse.QuestionnaireResponseItemAnswerComponent>? = null
val questionnaireViewItem =
QuestionnaireViewItem(
answerOptions(true, "Coding 1", "Coding 2", "Coding 3")
.addAnswerOption(
Questionnaire.QuestionnaireItemAnswerOptionComponent().apply {
value = Coding().apply { display = "Coding Exclusive" }
extension = listOf(Extension(EXTENSION_OPTION_EXCLUSIVE_URL, BooleanType(true)))
},
),
responseOptions(),
validationResult = NotValidated,
answersChangedCallback = { _, _, answers, _ -> answerHolder = answers },
)

runOnUI { viewHolder.bind(questionnaireViewItem) }

endIconClickInTextInputLayout(R.id.multi_select_summary_holder)
clickOnTextInDialog("Coding Exclusive")
clickOnText("Coding 1")
clickOnText("Coding 3")
clickOnText("Save")

assertDisplayedText().isEqualTo("Coding 1, Coding 3")
assertQuestionnaireResponseAtIndex(answerHolder!!, "Coding 1", "Coding 3")
}

@Test
fun multipleChoice_multipleOptionExclusive_selectMultiple_selectExclusive1_selectExclusive2_clickSave_shouldSaveOnlyLastSelectedExclusiveOption() {
var answerHolder: List<QuestionnaireResponse.QuestionnaireResponseItemAnswerComponent>? = null
val questionnaireViewItem =
QuestionnaireViewItem(
answerOptions(true, "Coding 1", "Coding 2", "Coding 3")
.addAnswerOption(
Questionnaire.QuestionnaireItemAnswerOptionComponent().apply {
value = Coding().apply { display = "Coding Exclusive 1" }
extension = listOf(Extension(EXTENSION_OPTION_EXCLUSIVE_URL, BooleanType(true)))
},
)
.addAnswerOption(
Questionnaire.QuestionnaireItemAnswerOptionComponent().apply {
value = Coding().apply { display = "Coding Exclusive 2" }
extension = listOf(Extension(EXTENSION_OPTION_EXCLUSIVE_URL, BooleanType(true)))
},
),
responseOptions(),
validationResult = NotValidated,
answersChangedCallback = { _, _, answers, _ -> answerHolder = answers },
)

runOnUI { viewHolder.bind(questionnaireViewItem) }

endIconClickInTextInputLayout(R.id.multi_select_summary_holder)
clickOnTextInDialog("Coding 1")
clickOnText("Coding 3")
clickOnText("Coding Exclusive 1")
clickOnText("Coding Exclusive 2")
clickOnText("Save")

assertDisplayedText().isEqualTo("Coding Exclusive 2")
assertQuestionnaireResponseAtIndex(answerHolder!!, "Coding Exclusive 2")
}

@Test
fun multipleChoice_multipleOptionExclusive_selectExclusive1_selectExclusive2_selectMultiple_clickSave_shouldSaveWithoutAnyExclusiveOption() {
var answerHolder: List<QuestionnaireResponse.QuestionnaireResponseItemAnswerComponent>? = null
val questionnaireViewItem =
QuestionnaireViewItem(
answerOptions(true, "Coding 1", "Coding 2", "Coding 3")
.addAnswerOption(
Questionnaire.QuestionnaireItemAnswerOptionComponent().apply {
value = Coding().apply { display = "Coding Exclusive 1" }
extension = listOf(Extension(EXTENSION_OPTION_EXCLUSIVE_URL, BooleanType(true)))
},
)
.addAnswerOption(
Questionnaire.QuestionnaireItemAnswerOptionComponent().apply {
value = Coding().apply { display = "Coding Exclusive 2" }
extension = listOf(Extension(EXTENSION_OPTION_EXCLUSIVE_URL, BooleanType(true)))
},
),
responseOptions(),
validationResult = NotValidated,
answersChangedCallback = { _, _, answers, _ -> answerHolder = answers },
)

runOnUI { viewHolder.bind(questionnaireViewItem) }

endIconClickInTextInputLayout(R.id.multi_select_summary_holder)
clickOnTextInDialog("Coding Exclusive 1")
clickOnTextInDialog("Coding Exclusive 2")
clickOnText("Coding 1")
clickOnText("Coding 3")
clickOnText("Save")

assertDisplayedText().isEqualTo("Coding 1, Coding 3")
assertQuestionnaireResponseAtIndex(answerHolder!!, "Coding 1", "Coding 3")
}

@Test
fun multipleChoice_SelectNothing_clickSave_shouldSaveNothing() {
val questionnaireViewItem =
Expand Down Expand Up @@ -364,6 +496,91 @@ class QuestionnaireItemDialogMultiSelectViewHolderFactoryEspressoTest {
onView(withId(R.id.add_another)).check(matches(isDisplayed()))
}

@Test
@SdkSuppress(minSdkVersion = 33)
fun selectOther_selectExclusive_shouldHideAddAnotherAnswer() {
val questionnaireItem =
answerOptions(
true,
"Coding 1",
"Coding 2",
"Coding 3",
"Coding 4",
"Coding 5",
"Coding 6",
"Coding 7",
"Coding 8",
)
.addAnswerOption(
Questionnaire.QuestionnaireItemAnswerOptionComponent().apply {
value = Coding().apply { display = "Coding Exclusive" }
extension = listOf(Extension(EXTENSION_OPTION_EXCLUSIVE_URL, BooleanType(true)))
},
)

questionnaireItem.addExtension(openChoiceType)
val questionnaireViewItem =
QuestionnaireViewItem(
questionnaireItem,
responseOptions(),
validationResult = NotValidated,
answersChangedCallback = { _, _, _, _ -> },
)

runOnUI { viewHolder.bind(questionnaireViewItem) }

endIconClickInTextInputLayout(R.id.multi_select_summary_holder)
onView(withId(R.id.recycler_view))
.perform(RecyclerViewActions.scrollToPosition<RecyclerView.ViewHolder>(9))
clickOnTextInDialog("Other")
clickOnTextInDialog("Coding Exclusive")
onView(withId(R.id.add_another)).check(doesNotExist())
}

@Test
@SdkSuppress(minSdkVersion = 33)
fun selectOther_clickAddAnotherAnswer_selectExclusive_shouldHideAddAnotherAnswerWithEditText() {
val questionnaireItem =
answerOptions(
true,
"Coding 1",
"Coding 2",
"Coding 3",
"Coding 4",
"Coding 5",
"Coding 6",
"Coding 7",
"Coding 8",
)
.addAnswerOption(
Questionnaire.QuestionnaireItemAnswerOptionComponent().apply {
value = Coding().apply { display = "Coding Exclusive" }
extension = listOf(Extension(EXTENSION_OPTION_EXCLUSIVE_URL, BooleanType(true)))
},
)

questionnaireItem.addExtension(openChoiceType)
val questionnaireViewItem =
QuestionnaireViewItem(
questionnaireItem,
responseOptions(),
validationResult = NotValidated,
answersChangedCallback = { _, _, _, _ -> },
)

runOnUI { viewHolder.bind(questionnaireViewItem) }

endIconClickInTextInputLayout(R.id.multi_select_summary_holder)
onView(withId(R.id.recycler_view))
.perform(RecyclerViewActions.scrollToPosition<RecyclerView.ViewHolder>(9))
clickOnTextInDialog("Other")
onView(withId(R.id.add_another)).perform(delayMainThread())
onView(withId(R.id.add_another)).perform(click())
clickOnTextInDialog("Coding Exclusive")
onView(withId(R.id.add_another)).check(doesNotExist())
onView(withId(R.id.edit_text)).check(doesNotExist())
}

@Test
fun shouldHideErrorTextviewInHeader() {
val questionnaireItem = answerOptions(true, "Coding 1")
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2022-2023 Google LLC
* Copyright 2022-2024 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -40,6 +40,7 @@ import androidx.recyclerview.widget.ListAdapter
import androidx.recyclerview.widget.RecyclerView
import com.google.android.fhir.datacapture.R
import com.google.android.fhir.datacapture.extensions.itemAnswerOptionImage
import com.google.android.fhir.datacapture.extensions.optionExclusive
import com.google.android.fhir.datacapture.views.factories.OptionSelectOption
import com.google.android.fhir.datacapture.views.factories.QuestionnaireItemDialogSelectViewModel
import com.google.android.fhir.datacapture.views.factories.SelectedOptions
Expand Down Expand Up @@ -263,6 +264,8 @@ private class OptionSelectAdapter(val multiSelectEnabled: Boolean) :
* if "Other" was just deselected, or adding them if "Other" was just selected).
*/
private fun submitSelectedChange(position: Int, selected: Boolean) {
val selectedItem = currentList[position]

val newList: List<OptionSelectRow> =
currentList
.mapIndexed { index, row ->
Expand All @@ -272,8 +275,22 @@ private class OptionSelectAdapter(val multiSelectEnabled: Boolean) :
} else {
// This is some other row
if (multiSelectEnabled) {
// In multi-select mode, the other rows don't need to change
row
// In multi-select mode,
if (
selected &&
((selectedItem is OptionSelectRow.Option &&
selectedItem.option.item.optionExclusive) ||
(row is OptionSelectRow.Option && row.option.item.optionExclusive))
) {
// if the selected answer option has optionExclusive extension, then deselect other
// answer options.
// or if the selected answer option does not have optionExclusive extension, then
// deselect optionExclusive answer option.
row.withSelectedState(selected = false) ?: row
} else {
// the other rows don't need to change
row
}
} else {
// In single-select mode, we need to disable all of the other rows
row.withSelectedState(selected = false) ?: row
Expand Down

0 comments on commit 7862d25

Please sign in to comment.