Mikolaj Leszczynski
09/06/2023, 6:52 AMGuilherme Delgado
09/06/2023, 11:34 AMJacob Rhoda
09/14/2023, 5:42 PMJacob Rhoda
09/20/2023, 8:55 PMsealed class FmisCropZonePickerState {
abstract val input: FmisCropZonePickerInput
data class Loading(override val input: FmisCropZonePickerInput) : FmisCropZonePickerState()
data class Error(
val cause: Throwable,
override val input: FmisCropZonePickerInput
) : FmisCropZonePickerState()
data class State(
override val input: FmisCropZonePickerInput,
val cropZones: List<FmisCropZone>,
val selectedCropZone: FmisCropZone?
) : FmisCropZonePickerState()
}
Mikolaj Leszczynski
09/22/2023, 9:46 AM6.1.0
has been released orbit multiplatform!!
https://github.com/orbit-mvi/orbit-mvi/releases/tag/6.1.0
This release contains minor refinements for the new testing framework APIS.Eslam Hussein
09/28/2023, 7:42 AMsealed class WidgetState {
class Success(val data: List<String>) : WidgetState()
object Loading : WidgetState()
class Error(errorMessage: String) : WidgetState()
}
any recommendation to using it like that in the open ticket https://github.com/orbit-mvi/orbit-mvi/issues/197Kshitij Patil
10/31/2023, 1:34 PM4.2.0
to 6.1.0
. Not able to find how we provide custom CoroutineDispatcher
for intents. Earlier, there used to be one parameter intentDispatcher
in the Container.Settings
class constructorJon Bailey
11/01/2023, 4:32 PMAfter waiting for 10s, the test coroutine is not completing, there were active child jobs: [JobImpl{Active}@5aaff0f4, JobImpl{Active}@2822da1c]
this is still using the old testing framework. But if I switch to the new testing framework then when I do awaitState()
no state is received and it gives an error with a 3s timeout. Is there anything obvious I'm missing?Jon Bailey
11/01/2023, 5:47 PMdata class ExampleState(val value: String = "")
class ExampleContainerHost(scope: CoroutineScope):
ContainerHost<ExampleState, Unit> {
// create a container
override val container = scope.container<ExampleState, Unit>(ExampleState())
fun doSomethingUseful() = intent {
reduce { ExampleState("foo") }
}
}
@Test
fun exampleTest() = runTest {
ExampleContainerHost(this).test(this) {
expectInitialState()
containerHost.doSomethingUseful()
expectState { copy("foo") }
}
}
If I change ExampleContainerHost(this).test(this) {
to ExampleContainerHost(GlobalScope).test(this) {
Then the test passes as expected. So I guess my question is what CoroutineScope is the container meant to be created with in a test? The new test docs just use ViewModels to create the ContainerHost.Jon Bailey
11/01/2023, 5:51 PMMikolaj Leszczynski
11/06/2023, 2:32 PMscope
to create the container and to run the test. This will create a deadlock. The solution here is to use backgroundScope
. Here is a rewritten version that should work (not tested):
data class ExampleState(val value: String = "")
class ExampleContainerHost(scope: CoroutineScope):
ContainerHost<ExampleState, Unit> {
// create a container
override val container = scope.container<ExampleState, Unit>(ExampleState())
fun doSomethingUseful() = intent {
reduce { ExampleState("foo") }
}
}
@Test
fun exampleTest() = runTest {
ExampleContainerHost(this.backgroundScope).test(this) { // < --- Pass backgroundScope to orbit factory f-n
expectInitialState()
containerHost.doSomethingUseful()
expectState { copy("foo") }
}
}
I guess this is mostly a missing documentation issue 🙂 I'll try to fix this soonMikolaj Leszczynski
11/06/2023, 2:44 PMMikolaj Leszczynski
11/06/2023, 2:46 PMrunTest
waits until all coroutines launched within its scope (i.e. the scope provided within the block) finish. If they don't it throws the above exception.Mikolaj Leszczynski
11/06/2023, 3:03 PMkotlinx.corountines.test
. I am pretty sure we didn't change anything in how the old test framework works in 6.x
- You can test this theory by using version 5.0.0
which has none of the recent test framework changes but has kotlin 1.7.10
As for Orbit 6.x
- we've tested this version in a large project with almost 3000 unit tests, mostly using the old testing framework - and we've only seen a few broken tests. Tests in this project were all based on the Android ViewModel - so we are not providing any custom scope
to the container host. My guess would be that most of the problems you're experiencing are a combination of changes in kotlinx.corountines.test
and the fact you're injecting the scope in tests.
Where this is important for Orbit - if you use the test scope to create the container, you are responsible for making sure there are no running intents at the end of the test.
Usually if you still have running intents at the end of the test it means you are collecting some long-running, infinite flow. We have a section in the docs on how to effectively test this.
But, TL;DR you have a few options:
1. Mock the flows out making them finite (preferable)
2. Cancel the intents collecting flows at the end of the test (only possible with the new testing framework thanks to intent jobs)
3. Cancel the container myContainerHost.container.cancel()
Overall I do recommend using the new testing framework as I think it fits much better into the coroutine testing workflow - but at the same time I know that it's not easy to refactor many old tests.
Please let me know if any of this helps and do come back to me if you keep having problems!! I'll try to help.Jacob Rhoda
11/17/2023, 9:00 PMdata class MyState(
val myProperty: String?
)
enum class MySideEffect
class MyViewModel(): ViewModel(), ContainerHost<MyState, MySideEffect> {
override val container: Container<MyState, MySideEffect> = container(MyState(""))
fun updateMyProperty(newValue: String?) = intent { reduce { state.copy(myProperty=newValue) } }
}
Cherrio LLC
11/21/2023, 10:43 AMBenoît
11/29/2023, 1:36 PMfun <S : Any> ContainerHost<S, *>.observeFlow(
flow: Flow<String>,
block: S.(String) -> S
) {
intent {
flow.collectLatest { data ->
reduce {
state.block(data)
}
}
}
}
Or is it better to do it in a CoroutineScope like this:
fun <S : Any> ContainerHost<S, *>.observeFlow(
flow: Flow<String>,
scope: CoroutineScope,
block: S.(String) -> S
) {
scope.launch {
flow.collectLatest { data ->
intent {
reduce {
state.block(data)
}
}
}
}
}
Mikolaj
12/07/2023, 9:29 AMawaitItem
and awaitState
in test framework? I did discover that when I use skipItems
or awaitItem
in a test followed by expectState {}
the state inside of expectState
block does not update. Is it desired behavior?Guilherme Delgado
12/09/2023, 8:34 PMJacob Rhoda
01/19/2024, 4:16 PMJacob Rhoda
01/22/2024, 7:13 PMMikolaj
01/24/2024, 2:31 PMMikolaj Leszczynski
02/16/2024, 2:20 PMMikolaj Leszczynski
02/21/2024, 11:02 AMMikolaj Leszczynski
02/21/2024, 11:02 AMGuilherme Delgado
02/26/2024, 10:51 PMGuilherme Delgado
02/26/2024, 10:51 PMvicky7230
03/14/2024, 12:17 PMvicky7230
03/15/2024, 7:09 AMreduce
thread safe?vicky7230
03/16/2024, 10:45 AM