Search code examples
androidandroid-espressoandroid-architecture-componentsandroid-architecture-navigation

Problem with NavController when trying to run EspressoTest


I am getting this error:

IllegalStateException: View android.widget.LinearLayout{649700d V.E...... ......I. 0,0-0,0} does not have a NavController set

But this happens only on espresso tests. The code where the crash happens handles onBackPressed on my fragment:

val navController = Navigation.findNavController(view)//this line here
        requireActivity().onBackPressedDispatcher.addCallback(this, object : OnBackPressedCallback(true) {
            override fun handleOnBackPressed() {
                navController.popBackStack(R.id.homeFragment, false)
            }
        })

This is my Espresso Test:

    @Test
    fun testBackButton() {
        val mockNavController = mock(NavController::class.java)
        settingsFragmentScenario = launchFragmentInContainer()
        settingsFragmentScenario.onFragment {
            Navigation.setViewNavController(it.requireView(), mockNavController)
        }
        performClickOnViews(android.R.id.home)
        verify(mockNavController).navigate(R.id.home)
    }

If I remove my code on the fragment tests run without any error (except from what I assert wrong)

I did check: IllegalStateException: Link does not have a NavController set, but his/her problem is not same as mine.

PS: On production code this line doesn't crash


Solution

  • I managed to resolve this, by replacing:

    val navController = Navigation.findNavController(view)//this line here
            requireActivity().onBackPressedDispatcher.addCallback(this, object : OnBackPressedCallback(true) {
                override fun handleOnBackPressed() {
                    navController.popBackStack(R.id.homeFragment, false)
                }
            })
    

    With:

    requireActivity().onBackPressedDispatcher.addCallback(this, object : OnBackPressedCallback(true) {
                override fun handleOnBackPressed() {
                    view.findNavController().popBackStack(R.id.homeFragment, false)
                }
            })
    

    Explenation, the nav controller is set on the view in my test using setViewNavController, thus I had to change my production code :)