android / android/architecture-samples

launchFragmentInHiltContainer doesn't work with navGraphViewModels

Open
#830 2 comments 3 reactions 0 assignees View on GitHub
Dominant language
Kotlin
Stars
45.8k
Forks
11.9k
PR merge metrics
No merged PRs in 30d

Description

Hi,
For test purposes I've modified the code of `launchFragmentInHiltContainer` to this:

```kotlin
const val THEME_EXTRAS =
"androidx.fragment.app.testing.FragmentScenario.EmptyFragmentActivity.THEME_EXTRAS_BUNDLE_KEY"

inline fun launchFragmentInHiltContainer(
fragmentArgs: Bundle? = null,
@StyleRes themeResId: Int = R.style.FragmentScenarioEmptyFragmentActivityTheme,
navHostController: TestNavHostController? = null,
crossinline action: Fragment.() -> Unit = {}
) {

val componentName = ComponentName(
ApplicationProvider.getApplicationContext(),
HiltTestActivity::class.java
)

val intent = Intent
.makeMainActivity(componentName)
.putExtra(THEME_EXTRAS, themeResId)

launch(intent).onActivity { activity ->

val fragment = activity
.supportFragmentManager
.fragmentFactory
.instantiate(Preconditions.checkNotNull(T::class.java.classLoader), T::class.java.name)
.also { it.arguments = fragmentArgs }

fragment.viewLifecycleOwnerLiveData.observeForever {
if (it != null) {
navHostController?.let { controller ->
controller.setGraph(R.navigation.nav_graph)
controller.setCurrentDestination(R.id.tasks_fragment_dest)
Navigation.setViewNavController(fragment.requireView(), controller)
}
}
}

activity.supportFragmentManager
.beginTransaction()
.add(android.R.id.content, fragment, "")
.commitNow()

fragment.action()
}
}
```

Then I've updated test designated for redirecting user to `add_edit_task_fragment_dest`:
```kotlin

@Test
fun clickAddTaskButton_navigateToAddEditFragment() {
// GIVEN - On the home screen
val navController = TestNavHostController(ApplicationProvider.getApplicationContext())
navController.setViewModelStore(ViewModelStore())
launchFragmentInHiltContainer(Bundle(), R.style.AppTheme, navController)

// WHEN - Click on the "+" button
onView(withId(R.id.add_task_fab)).perform(click())

// THEN - Verify that we navigate to the add screen
assertEquals(navController.currentDestination?.id, id.add_edit_task_fragment_dest)
}
```

In `TaskFragment` changed only the line with propagating view model lazily but using `navGraphViewModels` instead of `viewModels` like this:

```kotlin
private val viewModel
by navGraphViewModels(R.id.nav_graph) { defaultViewModelProviderFactory }

```
The all tests consisting of navigation just fails:

`IllegalStateException: Fragment TasksFragment{fe2ac75} (8c347050-d52e-4da4-ad2d-e4694c0ceb0f id=0x1020002 tag=) does not have a NavController set`

Any workarounds?

Contributor guide

Open the contributing guide

Research direction

Start with the launchFragmentInHiltContainer helper and the clickAddTaskButton_navigateToAddEditFragment navigation test, then inspect TaskFragment's navGraphViewModels setup. Run the navigation tests and compare the helper's NavController assignment with the fragment lifecycle. Done means the tests using navGraphViewModels pass without the "does not have a NavController set" exception.

Written by the indexing model from the issue text.

Assessment

Tech stack
android, kotlin
Domain
mobile, testing
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.