Jose Garcia
Jose Garcia

Reputation: 158

Espresso test, click on Chip view not working

I have a ChipGroup containing some Chip views that when checked, display some TextViews and SeekBars. I am trying to test this using Espresso and I am getting odd results.

Because the following test failed: (Test1)

@Test
fun whenEuropeChipIsSelected_DisplaySeekBarsAndTextViews() {
    launchFragmentInContainer<GameConfigSurvivalFragment>()

    onView(withId(R.id.europeSurvChip)).perform(click())

    onView(withId(R.id.countriesNumberSeekBar)).check(matches(isDisplayed()))
    onView(withId(R.id.selectCountriesNumberTv)).check(matches(isDisplayed()))
    onView(withId(R.id.selectedCountriesTV)).check(matches(isDisplayed()))
    onView(withId(R.id.timeLimitSeekBar)).check(matches(isDisplayed()))
    onView(withId(R.id.timeLimitTv)).check(matches(isDisplayed()))
    onView(withId(R.id.selectTimeLimitTv)).check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
}

I created the following simple test to see what is happening: (Test2) which is also failing. (See stack trace below)

@Test
fun whenEuropeChipIsClicked_CheckIsSelected() {
    launchFragmentInContainer<GameConfigSurvivalFragment>()

    onView(withId(R.id.europeSurvChip)).perform(click())

    onView(withId(R.id.europeSurvChip)).check(matches(isChecked()))
}

Some of my production code for this feature looks like this and I inserted some logs to see what is the state of the chip when I click on the chip:

binding.europeSurvChip.setOnCheckedChangeListener { isChecked ->
        if (isChecked) {
            counter.value = counter.value!!.plus(Europe.totalCountries)
            continentsList.add(Europe)
            Log.d("ChipSelected", "EuropeChipSelected: isChecked: ${europeSurvChip.isChecked}")
        } else {
            counter.value = counter.value!!.minus(Europe.totalCountries)
            continentsList.remove(Europe)
            Log.d("ChipSelected", "EuropeChipSelected: isChecked: ${europeSurvChip.isChecked}")
        }
    }

While testing the selection of the Chip manually on the emulator I achieve the intended result, and I can see on the log that the Chip is checked and unchecked. However, the Espresso tests I created never pass. Manually testing everything works as expected and the Seekbars and TextViews are displayed as well as the Chip button being checked.

I disabled animations as other questions suggested it to people suffering from Espresso's click() method not working properly.

Any idea what am I doing wrong? (everything is happening in the main thread)

Ideas I feel not confident about:


Test2's stacktrace

    E/TestRunner: failed: whenEuropeChipIsClicked_CheckIsSelected(com.example.capitalcityquizktx.ui.survivalmode.config.GameConfigSurvivalFragmentTest)
    ----- begin exception -----
E/TestRunner: androidx.test.espresso.base.DefaultFailureHandler$AssertionFailedWithCauseError: 'with checkbox state: is <true>' doesn't match the selected view.
    Expected: with checkbox state: is <true>
         Got: "Chip{id=2131230840, res-name=europeSurvChip, visibility=VISIBLE, width=315, height=88, has-focus=false, has-focusable=true, has-window-focus=true, is-clickable=false, is-enabled=true, is-focused=false, is-focusable=true, is-layout-requested=false, is-selected=false, layout-params=android.widget.TableRow$LayoutParams@b19ff14, tag=null, root-is-layout-requested=false, has-input-connection=false, x=11.0, y=11.0, text=Europe, input-type=0, ime-target=false, has-links=false, is-checked=false}"

        at dalvik.system.VMStack.getThreadStackTrace(Native Method)
        at java.lang.Thread.getStackTrace(Thread.java:1720)
        at androidx.test.espresso.base.DefaultFailureHandler.getUserFriendlyError(DefaultFailureHandler.java:94)
        at androidx.test.espresso.base.DefaultFailureHandler.handle(DefaultFailureHandler.java:57)
        at androidx.test.espresso.ViewInteraction.waitForAndHandleInteractionResults(ViewInteraction.java:318)
        at androidx.test.espresso.ViewInteraction.check(ViewInteraction.java:300)
        at com.example.capitalcityquizktx.ui.survivalmode.config.GameConfigSurvivalFragmentTest.whenEuropeChipIsClicked_CheckIsSelected(GameConfigSurvivalFragmentTest.kt:63)
        at java.lang.reflect.Method.invoke(Native Method)
        at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
        at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
        at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
        at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
        at androidx.test.internal.runner.junit4.statement.RunBefores.evaluate(RunBefores.java:80)
        at androidx.test.internal.runner.junit4.statement.RunAfters.evaluate(RunAfters.java:61)
        at androidx.test.rule.ActivityTestRule$ActivityStatement.evaluate(ActivityTestRule.java:527)
        at org.junit.rules.RunRules.evaluate(RunRules.java:20)
        at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
        at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
        at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
        at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
        at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
        at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
        at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
        at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
        at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
        at androidx.test.ext.junit.runners.AndroidJUnit4.run(AndroidJUnit4.java:104)
        at org.junit.runners.Suite.runChild(Suite.java:128)
        at org.junit.runners.Suite.runChild(Suite.java:27)
        at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
        at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
        at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
        at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
        at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
        at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
        at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
        at org.junit.runner.JUnitCore.run(JUnitCore.java:115)
        at androidx.test.internal.runner.TestExecutor.execute(TestExecutor.java:56)
        at androidx.test.runner.AndroidJUnitRunner.onStart(AndroidJUnitRunner.java:388)
        at android.app.Instrumentation$InstrumentationThread.run(Instrumentation.java:2189)
     Caused by: junit.framework.AssertionFailedError: 'with checkbox state: is <true>' doesn't match the selected view.
    Expected: with checkbox state: is <true>
         Got: "Chip{id=2131230840, res-name=europeSurvChip, visibility=VISIBLE, width=315, height=88, has-focus=false, has-focusable=true, has-window-focus=true, is-clickable=false, is-enabled=true, is-focused=false, is-focusable=true, is-layou
    ----- end exception -----

Test1's stackTrace

    E/TestRunner: failed: whenEuropeChipIsSelected_DisplaySeekBarsAndTextViews_numberOfCountriesAndTimeLimit(com.example.capitalcityquizktx.ui.survivalmode.config.GameConfigSurvivalFragmentTest)
    ----- begin exception -----
E/TestRunner: androidx.test.espresso.base.DefaultFailureHandler$AssertionFailedWithCauseError: 'is displayed on the screen to the user' doesn't match the selected view.
    Expected: is displayed on the screen to the user
         Got: "SeekBar{id=2131230817, res-name=countriesNumberSeekBar, visibility=GONE, width=0, height=0, has-focus=false, has-focusable=false, has-window-focus=true, is-clickable=false, is-enabled=true, is-focused=false, is-focusable=true, is-layout-requested=true, is-selected=false, layout-params=androidx.constraintlayout.widget.ConstraintLayout$LayoutParams@1f49905, tag=null, root-is-layout-requested=false, has-input-connection=false, x=0.0, y=0.0}"

        at dalvik.system.VMStack.getThreadStackTrace(Native Method)
        at java.lang.Thread.getStackTrace(Thread.java:1720)
        at androidx.test.espresso.base.DefaultFailureHandler.getUserFriendlyError(DefaultFailureHandler.java:94)
        at androidx.test.espresso.base.DefaultFailureHandler.handle(DefaultFailureHandler.java:57)
        at androidx.test.espresso.ViewInteraction.waitForAndHandleInteractionResults(ViewInteraction.java:318)
        at androidx.test.espresso.ViewInteraction.check(ViewInteraction.java:300)
        at com.example.capitalcityquizktx.ui.survivalmode.config.GameConfigSurvivalFragmentTest.whenEuropeChipIsSelected_DisplaySeekBarsAndTextViews_numberOfCountriesAndTimeLimit(GameConfigSurvivalFragmentTest.kt:49)
        at java.lang.reflect.Method.invoke(Native Method)
        at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
        at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
        at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
        at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
        at androidx.test.internal.runner.junit4.statement.RunBefores.evaluate(RunBefores.java:80)
        at androidx.test.internal.runner.junit4.statement.RunAfters.evaluate(RunAfters.java:61)
        at androidx.test.rule.ActivityTestRule$ActivityStatement.evaluate(ActivityTestRule.java:527)
        at org.junit.rules.RunRules.evaluate(RunRules.java:20)
        at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
        at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
        at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
        at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
        at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
        at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
        at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
        at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
        at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
        at androidx.test.ext.junit.runners.AndroidJUnit4.run(AndroidJUnit4.java:104)
        at org.junit.runners.Suite.runChild(Suite.java:128)
        at org.junit.runners.Suite.runChild(Suite.java:27)
        at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
        at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
        at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
        at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
        at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
        at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
        at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
        at org.junit.runner.JUnitCore.run(JUnitCore.java:115)
        at androidx.test.internal.runner.TestExecutor.execute(TestExecutor.java:56)
        at androidx.test.runner.AndroidJUnitRunner.onStart(AndroidJUnitRunner.java:388)
        at android.app.Instrumentation$InstrumentationThread.run(Instrumentation.java:2189)
     Caused by: junit.framework.AssertionFailedError: 'is displayed on the screen to the user' doesn't match the selected view.
    Expected: is displayed on the screen to the user
         Got: "SeekBar{id=2131230817, res-name=countriesNumberSeekBar, visibility=GONE, width=0, height=0, has-focus=false, has-focusable=false, has-window-focus=true, is-clickable=false, is-enabled=true, is-focused=fals
    ----- end exception -----


Production code class. (It works as intended):

class GameConfigSurvivalFragment : Fragment(),
GameConfigSurvivalView {

override val continentsList = MutableLiveData<List<Continent>>().default(arrayListOf())
private val displayTimeLimitSeekBar = MutableLiveData<Boolean>().default(false)
private val displayQuestionNumberSeekBar = MutableLiveData<Boolean>().default(false)

override fun showQuestionsNumberSelection() {
    displayQuestionNumberSeekBar.value = true
}

override fun showTimeLimitSelection() {
    displayTimeLimitSeekBar.value = true
}

override fun hideQuestionsNumberSelection() {
    displayQuestionNumberSeekBar.value = false
}

override fun hideTimeLimitSelection() {
    displayTimeLimitSeekBar.value = false
}

override fun onCreateView(
    inflater: LayoutInflater, container: ViewGroup?,
    savedInstanceState: Bundle?
): View? {
    val binding: GameConfigSurvivalFragmentBinding = inflate(
        inflater, R.layout.game_config_survival_fragment, container, false
    )

    val presenter = GameConfigSurvivalPresenter(this)
    presenter.receiveContinentSelection()

    //Minimum amount of seconds that will be added to timeLimitSeekbar
    val minTimeLimit = 5

    // This counter is used to count the amount of countries to set up the seekBar acording to its value
    val counter = MutableLiveData<Int>()
    counter.value = 0

    // This val is used to gather information about the number of chips that are checked
    // in order to show the seekBar if there are any of them checked
    val continentsSelected = MutableLiveData<Int>()
    continentsSelected.value = 0

    displayQuestionNumberSeekBar.observe(this,
        Observer { displayIt ->
            if (displayIt){
                binding.selectCountriesNumberTv.isVisible = true
                binding.countriesNumberSeekBar.isVisible = true
                binding.selectedCountriesTV.isVisible = true
                binding.countriesNumberSeekBar.max = counter.value!!
                binding.countriesNumberSeekBar.progress = binding.countriesNumberSeekBar.max
            }else{
                binding.selectCountriesNumberTv.isVisible = false
                binding.countriesNumberSeekBar.isVisible = false
                binding.selectedCountriesTV.isVisible = false
            }
        })

    displayTimeLimitSeekBar.observe(this,
        Observer { displayIt ->
            if (displayIt){
                binding.selectTimeLimitTv.isVisible = true
                binding.timeLimitSeekBar.isVisible = true
                binding.timeLimitTv.isVisible = true
            }else{
                binding.selectTimeLimitTv.isVisible = false
                binding.timeLimitSeekBar.isVisible = false
                binding.timeLimitTv.isVisible = false
            }
        })

    /* The following listeners check the state of the chips whether they are checked or not,
    in order to count the number of countries and to count the number of continents selected */

    binding.europeSurvChip.setOnCheckedChangeListener { buttonView, isChecked ->
        if (isChecked) {
            counter.value = counter.value!!.plus(Europe.totalCountries)
            continentsList.add(Europe)
            Log.d("ChipSelected", "EuropeChipSelected: isChecked: ${europeSurvChip.isChecked}")
        } else {
            counter.value = counter.value!!.minus(Europe.totalCountries)
            continentsList.remove(Europe)
            Log.d("ChipSelected", "EuropeChipSelected: isChecked: ${europeSurvChip.isChecked}")
        }
    }

    return binding.root
  }
}

Upvotes: 0

Views: 1083

Answers (1)

Jose Garcia
Jose Garcia

Reputation: 158

Fixed it by making the Chip clickable and checkable in the XML file.

I am guessing it was made clickable and checkable programmatically somewhere in the code.

Upvotes: 1

Related Questions