Compose stops recomposing in tests
- Dominant language
- Kotlin
- Stars
- 2.2k
- Forks
- 116
- Avg merge
- 1h 36m
- Merged PRs (30d)
- 8
Description
In a weird combination of `StateFlow`, `backgroundScope`, `UnconfinedTestDispatcher`, `collectAsState()` and the `Immediate` recomposition mode the Compose runtime stops recomposing and Flows produced by Molecule stop sending events.
This test passes:
```
@Test
fun `something breaks`() = runTest {
val _strings = MutableStateFlow("one")
val strings: Flow = _strings
val molecule = (backgroundScope + UnconfinedTestDispatcher(testScheduler)).launchMolecule(RecompositionMode.Immediate) {
val string by strings.collectAsState("one")
string
}
molecule.test {
assertThat(awaitItem()).isEqualTo("one")
_strings.value = "two"
assertThat(awaitItem()).isEqualTo("two")
_strings.value = "three"
assertThat(awaitItem()).isEqualTo("three")
}
}
```
If I change the initial value to something else such as `collectAsState("abc")`, then only "one" from the StateFlow is emitted but no other value anymore even though the StateFlow value changes. The composable function only recomposes when the initial value of the `StateFlow` and the `collectAsState` function are equal. This seems to be the bug.
Changing the flow to a `MutableSharedFlow` fixes the issue, because there’s no default value. Removing the `UnconfinedTestDispatcher` also fixes the issue. In this case it emits the initial value from `collectAsState` first, then the default value from the `StateFlow` and then all other changes. Using the same initial values also resolves the bug (the problem here is that `StateFlow` is an implementation detail of the underlying API, this example is simplified). It only breaks when the initial values are different.
Contributor guide
No contributing guide indexed for this repository
Research direction
Start by running the provided runTest reproduction with StateFlow, backgroundScope, UnconfinedTestDispatcher, launchMolecule, RecompositionMode.Immediate, and collectAsState. Compare the differing and matching initial values, then trace why recomposition stops; done means later StateFlow changes emit consistently in the failing case.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- kotlin
- Domain
- testing
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100