vitaliy
10/26/2020, 5:26 PMBroadcastChannel
and Flow
. Essentially I’m looking for the navigate
to behave like rx PublishSubject
.
Issue: since navigate
flow is created from the channel, firstOrNull()
on it never finishes. I’m pretty new to coroutines and I will appreciate if somebody can have a look. Thanks!
import io.kotest.matchers.shouldBe
import kotlinx.coroutines.channels.BroadcastChannel
import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.flow.asFlow
import kotlinx.coroutines.flow.firstOrNull
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
import org.junit.jupiter.api.Test
class RetainStateTest {
val navigateChannel = BroadcastChannel<List<String>>(Channel.BUFFERED)
val navigate = navigateChannel.asFlow()
val data = listOf("blah", "foo")
@Test
fun `should not retain state`() {
runBlocking {
val jobPrecondition = launch {
navigate.firstOrNull() shouldBe data
}
navigateChannel.send(data)
jobPrecondition.join()
val job = launch {
navigate.firstOrNull() shouldBe null
}
job.join()
}
}
}
Zach Klippenstein (he/him) [MOD]
10/26/2020, 5:29 PMPublishSubject
have the same issue here? It would wait indefinitely for something to be sent to the subject, and would only return null if the subject was completed before something was sent to it.bezrukov
10/26/2020, 5:29 PMfirstOrNull()
is launched after send
call.
To fix it, you can call yield()
after launch. OR launch first coroutine with start = Undispatched.
To receive null, flow should complete, to achieve this, you need to close navigateChannel
vitaliy
10/26/2020, 5:30 PMPublishSubject
I will be able to check if it does not emit anything and it would be enough.start = CoroutineStart.UNDISPATCHED
solves it indeed, thanks!. Is there any other trick I can do in the second coroutine to verify, that there is nothing there for me?Zach Klippenstein (he/him) [MOD]
10/26/2020, 5:36 PMnavigate.test()
). You can do something similar with flows by launching a coroutine at the start of your test that collects to a channel, then you can peek into the channel to see if anything was emitted since the last check by calling poll()
.vitaliy
10/26/2020, 5:42 PMZach Klippenstein (he/him) [MOD]
10/26/2020, 5:59 PMbezrukov
10/26/2020, 6:12 PMIs there any other trick I can do in the second coroutine to verify, that there is nothing there for me?As I said you need to call
navigateChannel.close()
before last join. Another option (but it's weird) is to use withTimeoutvitaliy
10/26/2020, 6:14 PMbezrukov
10/26/2020, 6:18 PMfirstOrError
/ firstOrDefault
, and to make them work (throw an error or return default value) subject needs to be completed via subject.onCompletevitaliy
10/27/2020, 11:14 AM