Skip to content

Commit

Permalink
--wip-- [skip ci]
Browse files Browse the repository at this point in the history
  • Loading branch information
shobhitagarwal1612 committed Dec 19, 2024
1 parent 459bee0 commit 2adc6a8
Show file tree
Hide file tree
Showing 4 changed files with 107 additions and 31 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import androidx.compose.material3.TextField
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.testTag
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.AnnotatedString
import androidx.compose.ui.tooling.preview.Preview
Expand All @@ -46,15 +47,19 @@ fun MultipleChoiceItemView(
toggleItem: (item: MultipleChoiceItem) -> Unit = {},
otherValueChanged: (text: String) -> Unit = {},
) {
Column {
Column(modifier = modifier.testTag(MultipleChoiceTestTags.MULTIPLE_CHOICE_ITEM)) {
Row(modifier.fillMaxWidth(), verticalAlignment = Alignment.CenterVertically) {
when (item.cardinality) {
MultipleChoice.Cardinality.SELECT_ONE -> {
RadioButton(selected = item.isSelected, onClick = { toggleItem(item) })
}

MultipleChoice.Cardinality.SELECT_MULTIPLE -> {
Checkbox(checked = item.isSelected, onCheckedChange = { toggleItem(item) })
Checkbox(
checked = item.isSelected,
onCheckedChange = { toggleItem(item) },
modifier = Modifier.testTag(MultipleChoiceTestTags.SELECT_MULTIPLE_CHECKBOX),
)
}
}

Expand All @@ -72,6 +77,7 @@ fun MultipleChoiceItemView(
value = item.otherText,
textStyle = MaterialTheme.typography.bodyLarge,
onValueChange = { otherValueChanged(it) },
modifier = Modifier.testTag(MultipleChoiceTestTags.OTHER_INPUT_TEXT),
)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import androidx.compose.runtime.getValue
import androidx.compose.runtime.livedata.observeAsState
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.ComposeView
import androidx.compose.ui.platform.testTag
import androidx.lifecycle.asLiveData
import com.google.android.ground.ui.datacollection.components.TaskView
import com.google.android.ground.ui.datacollection.components.TaskViewFactory
Expand All @@ -49,7 +50,7 @@ class MultipleChoiceTaskFragment : AbstractTaskFragment<MultipleChoiceTaskViewMo
private fun ShowMultipleChoiceItems() {
val list by viewModel.itemsFlow.asLiveData().observeAsState()
list?.let { items ->
LazyColumn(Modifier.fillMaxSize()) {
LazyColumn(Modifier.fillMaxSize().testTag(MultipleChoiceTestTags.MULTIPLE_CHOICE_LIST)) {
items(items) { item ->
MultipleChoiceItemView(
item = item,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package com.google.android.ground.ui.datacollection.tasks.multiplechoice

object MultipleChoiceTestTags {

const val MULTIPLE_CHOICE_LIST = "multiple choice items test tag"
const val MULTIPLE_CHOICE_ITEM = "multiple choice item test tag"
const val OTHER_INPUT_TEXT = "other input test tag"
const val SELECT_MULTIPLE_CHECKBOX = "select multiple test tag"
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,22 @@
package com.google.android.ground.ui.datacollection.tasks.multiplechoice

import android.content.Context
import android.widget.RadioButton
import androidx.compose.ui.semantics.Role
import androidx.compose.ui.semantics.SemanticsProperties
import androidx.compose.ui.semantics.getOrNull
import androidx.compose.ui.test.SemanticsMatcher
import androidx.compose.ui.test.assertIsDisplayed
import androidx.compose.ui.test.assertIsNotSelected
import androidx.compose.ui.test.assertIsSelected
import androidx.compose.ui.test.hasText
import androidx.compose.ui.test.onNodeWithTag
import androidx.compose.ui.test.onNodeWithText
import androidx.compose.ui.test.performClick
import androidx.compose.ui.test.performScrollToNode
import androidx.compose.ui.test.performTextInput
import androidx.test.espresso.Espresso.onView
import androidx.test.espresso.action.ViewActions.click
import androidx.test.espresso.assertion.ViewAssertions.matches
import androidx.test.espresso.matcher.ViewMatchers.hasChildCount
import androidx.test.espresso.matcher.ViewMatchers.isChecked
import androidx.test.espresso.matcher.ViewMatchers.isDisplayed
import androidx.test.espresso.matcher.ViewMatchers.isNotChecked
Expand All @@ -37,15 +48,13 @@ import com.google.android.ground.ui.common.ViewModelFactory
import com.google.android.ground.ui.datacollection.DataCollectionViewModel
import com.google.android.ground.ui.datacollection.components.ButtonAction
import com.google.android.ground.ui.datacollection.tasks.BaseTaskFragmentTest
import com.google.android.material.checkbox.MaterialCheckBox
import com.google.common.truth.Truth.assertThat
import dagger.hilt.android.qualifiers.ApplicationContext
import dagger.hilt.android.testing.BindValue
import dagger.hilt.android.testing.HiltAndroidTest
import javax.inject.Inject
import kotlinx.collections.immutable.persistentListOf
import org.hamcrest.Matchers.allOf
import org.hamcrest.Matchers.instanceOf
import org.junit.Assert.assertThrows
import org.junit.Test
import org.junit.runner.RunWith
Expand Down Expand Up @@ -103,18 +112,20 @@ class MultipleChoiceTaskFragmentTest :
task.copy(multipleChoice = MultipleChoice(options, MultipleChoice.Cardinality.SELECT_ONE)),
)

onView(withId(R.id.select_option_list)).check(matches(allOf(isDisplayed(), hasChildCount(2))))
onView(withText("Option 1"))
.check(matches(allOf(isDisplayed(), instanceOf(RadioButton::class.java))))
composeTestRule
.onNodeWithTag(MultipleChoiceTestTags.MULTIPLE_CHOICE_LIST)
.performScrollToNode(hasText("Option 1"))
.performScrollToNode(hasText("Option 2"))
.assertIsDisplayed()
}

@Test
fun `allows only one selection for SELECT_ONE cardinality`() = runWithTestDispatcher {
val multipleChoice = MultipleChoice(options, MultipleChoice.Cardinality.SELECT_ONE)
setupTaskFragment<MultipleChoiceTaskFragment>(job, task.copy(multipleChoice = multipleChoice))

onView(withText("Option 1")).perform(click())
onView(withText("Option 2")).perform(click())
composeTestRule.onNodeWithText("Option 1").performClick()
composeTestRule.onNodeWithText("Option 2").performClick()

hasValue(MultipleChoiceTaskData(multipleChoice, listOf("option id 2")))
runner().assertButtonIsEnabled("Next")
Expand All @@ -129,18 +140,20 @@ class MultipleChoiceTaskFragmentTest :
),
)

onView(withId(R.id.select_option_list)).check(matches(allOf(isDisplayed(), hasChildCount(2))))
onView(withText("Option 1"))
.check(matches(allOf(isDisplayed(), instanceOf(MaterialCheckBox::class.java))))
composeTestRule
.onNodeWithTag(MultipleChoiceTestTags.MULTIPLE_CHOICE_LIST)
.performScrollToNode(hasText("Option 1"))
.performScrollToNode(hasText("Option 2"))
.assertIsDisplayed()
}

@Test
fun `allows multiple selection for SELECT_MULTIPLE cardinality`() = runWithTestDispatcher {
val multipleChoice = MultipleChoice(options, MultipleChoice.Cardinality.SELECT_MULTIPLE)
setupTaskFragment<MultipleChoiceTaskFragment>(job, task.copy(multipleChoice = multipleChoice))

onView(withText("Option 1")).perform(click())
onView(withText("Option 2")).perform(click())
composeTestRule.onNodeWithText("Option 1").performClick()
composeTestRule.onNodeWithText("Option 2").performClick()

hasValue(MultipleChoiceTaskData(multipleChoice, listOf("option id 1", "option id 2")))
runner().assertButtonIsEnabled("Next")
Expand All @@ -155,27 +168,71 @@ class MultipleChoiceTaskFragmentTest :
)
val userInput = "User inputted text"

onView(withText("Other")).perform(click())
onView(allOf(isDisplayed(), withId(R.id.user_response_text)))
.perform(CustomViewActions.forceTypeText(userInput))

onView(withText("Other")).check(matches(isChecked()))
composeTestRule.onNodeWithText("Other").performClick()
composeTestRule
.onNodeWithTag(MultipleChoiceTestTags.OTHER_INPUT_TEXT)
.assertIsDisplayed()
.performTextInput(userInput)
// onView(allOf(isDisplayed(), withId(R.id.user_response_text)))
// .perform(CustomViewActions.forceTypeText(userInput))

// val string =
//
// error(
//
// composeTestRule.onNodeWithTag(MultipleChoiceTestTags.MULTIPLE_CHOICE_LIST).printToString()
// )

// composeTestRule.onRoot().printToLog("hello")

// composeTestRule.onNode(isSelectable()).assertIsSelected()

// composeTestRule.onNode(withRole(Role.Checkbox).and(hasText("Other"))).assertIsDisplayed()
composeTestRule.onNode(hasText("Other")).assertIsDisplayed()
// .onSibling()

// .onNodeWithTag(MultipleChoiceTestTags.MULTIPLE_CHOICE_LIST)
// .performScrollToNode(hasText("Other"))
// .assertIsDisplayed()
// .onChild()
// .assertIsSelected()
// .onNode(hasText("Other") and
// hasTestTag(MultipleChoiceTestTags.SELECT_MULTIPLE_CHECKBOX))
// .assertIsDisplayed()
// .assertIsSelected()
// composeTestRule.onNodeWithText("Other").assertIsSelected()
// onView(withText("Other")).check(matches(isChecked()))
hasValue(MultipleChoiceTaskData(multipleChoice, listOf("[ $userInput ]")))
runner().assertButtonIsEnabled("Next")
}

fun withRole(role: Role) =
SemanticsMatcher("${SemanticsProperties.Role.name} contains '$role'") {
val roleProperty = it.config.getOrNull(SemanticsProperties.Role) ?: false
roleProperty == role
}

@Test
fun `selects other option on text input and deselects other radio inputs`() =
runWithTestDispatcher {
val multipleChoice = MultipleChoice(options, MultipleChoice.Cardinality.SELECT_ONE, true)
setupTaskFragment<MultipleChoiceTaskFragment>(job, task.copy(multipleChoice = multipleChoice))
onView(withText("Option 1")).perform(click())
onView(withText("Other")).check(matches(isNotChecked()))

composeTestRule.onNodeWithText("Option 1").performClick()
composeTestRule.onNodeWithText("Other").assertIsNotSelected()
// onView(withText("Option 1")).perform(click())
// onView(withText("Other")).check(matches(isNotChecked()))
val userInput = "A"
onView(allOf(isDisplayed(), withId(R.id.user_response_text)))
.perform(CustomViewActions.forceTypeText(userInput))
onView(withText("Option 1")).check(matches(isNotChecked()))
onView(withText("Other")).check(matches(isChecked()))
composeTestRule
.onNodeWithTag(MultipleChoiceTestTags.OTHER_INPUT_TEXT)
.assertIsDisplayed()
.performTextInput(userInput)
// onView(allOf(isDisplayed(), withId(R.id.user_response_text)))
// .perform(CustomViewActions.forceTypeText(userInput))
composeTestRule.onNodeWithText("Option 1").assertIsNotSelected()
// onView(withText("Option 1")).check(matches(isNotChecked()))
composeTestRule.onNodeWithText("Other").assertIsSelected()
// onView(withText("Other")).check(matches(isChecked()))
hasValue(MultipleChoiceTaskData(multipleChoice, listOf("[ $userInput ]")))
}

Expand Down Expand Up @@ -317,9 +374,12 @@ class MultipleChoiceTaskFragmentTest :
task.copy(multipleChoice = multipleChoice, isRequired = true),
)

onView(withText("Other")).perform(click())
onView(allOf(isDisplayed(), withId(R.id.user_response_text)))
.perform(CustomViewActions.forceTypeText(""))
composeTestRule.onNodeWithText("Other").performClick()

composeTestRule
.onNodeWithTag(MultipleChoiceTestTags.OTHER_INPUT_TEXT)
.assertIsDisplayed()
.performTextInput("")

hasValue(null)
runner().assertButtonIsDisabled("Next")
Expand Down

0 comments on commit 2adc6a8

Please sign in to comment.