Hi there, I am trying to test the label dispatchin...
# mvikotlin
c
Hi there, I am trying to test the label dispatching from Store, and I am not sure if this is a deadlock bug in MVIKotlin, or it is my own issue. So please let me explain what I have observed. I have a store like this:
Copy code
onIntent<LandingPageIntent.ToNextPage> {
  launch {
     ... some other suspend fun call
     publish(LandingPageToNextPageLabel)
     log.d { "Label sent" }
  }
Now I have two test cases in kotlintest. One has deadlock, another one doesn't. Here is the one with the deadlock:
Copy code
@Test
  fun normalFlowStucked() = runTest {
    // the labels Flow way will be stuck if running in single-threaded env like JS or single-threaded Dispatcher
    // However, from debugging, the label is actually dispatched, but for some reason, we can't receive it
    val job = launch {
      landingPageStore.labels.stateIn(CoroutineScope(coroutineContext)).collect {
        log.d { "Received $it" }
        assertEquals(LandingPageToNextPageLabel, it)
      }
    }

    landingPageStore.accept(LandingPageIntent.TextChanged("a change"))
    assertEquals("a change", landingPageStore.state.url)
    landingPageStore.accept(LandingPageIntent.ToNextPage)

    job.join()
  }
The test case can still print
"Label sent"
, but not
"Received LandingPageToNextPageLabel"
. This only happens if running in
jsTest
or in Android platform without specifying the
Dispatchers.Default
. Now here is another test case that uses
Channel
instead of `Flow`:
Copy code
@Test
  fun testNormalFlow1() = runTest {
    // Can't make Store.labels Flow way working in single-threaded env like JS or single-threaded Dispatcher
    val channel = Channel<LandingPageToNextPageLabel>()
    val scope = CoroutineScope(coroutineContext)

    landingPageStore.labels(observer {
      scope.launch {
        channel.send(it)
        log.d { "Received $it" }
      }
    })

    landingPageStore.accept(LandingPageIntent.TextChanged("a change"))
    assertEquals("a change", landingPageStore.state.url)
    landingPageStore.accept(LandingPageIntent.ToNextPage)

    val label = channel.receive()
    assertEquals(label, LandingPageToNextPageLabel)

    channel.close()
  }
This one runs successfully, no deadlock. The actual codes are open sourced at [here](https://github.com/CXwudi/realworld-compose-http4k-example-app/blob/master/conduit[…]onduit/frontend/logic/component/landing/LandingPageStoreTest.kt) and [here](https://github.com/CXwudi/realworld-compose-http4k-example-app/blob/master/conduit[…]uit/frontend/logic/component/landing/LandingPageStoreFactory.kt) for references So here are my questions: 1. Is the deadlock expected for the first test case? 2. Is the second test case a good way to test labels dispatching? If not, then what are some good way to test it?
a
This happens because
launch {}
is asynchronous. By the time the launch block is called, the
ToNextPage
intent has been already sent and processed, i.e. the label has been already emitted. Please see the example of testing labels with coroutines: https://github.com/arkivanov/MVIKotlin/blob/018af7c8efc25f4d5d47058b202be756a36511[…]tlin/sample/coroutines/shared/details/store/DetailsStoreTest.kt And the
Flow.test
extension function: https://github.com/arkivanov/MVIKotlin/blob/018af7c8efc25f4d5d47058b202be756a36511[…]otlin/com/arkivanov/mvikotlin/sample/coroutines/shared/Utils.kt
c
I see, that is a good idea to collect all labels into a list before asserting. Thanks for the examples
👍 1