@@ -9,7 +9,6 @@ import kotlinx.coroutines.CoroutineExceptionHandler
9
9
import kotlinx.coroutines.CoroutineScope
10
10
import kotlinx.coroutines.Dispatchers.Unconfined
11
11
import kotlinx.coroutines.ExperimentalCoroutinesApi
12
- import kotlinx.coroutines.FlowPreview
13
12
import kotlinx.coroutines.cancel
14
13
import kotlinx.coroutines.channels.Channel
15
14
import kotlinx.coroutines.flow.MutableStateFlow
@@ -27,18 +26,14 @@ import kotlinx.coroutines.test.UnconfinedTestDispatcher
27
26
import kotlinx.coroutines.test.advanceUntilIdle
28
27
import kotlinx.coroutines.test.runCurrent
29
28
import okio.ByteString
29
+ import kotlin.test.Ignore
30
30
import kotlin.test.Test
31
31
32
- @OptIn(ExperimentalCoroutinesApi ::class , FlowPreview :: class , WorkflowExperimentalRuntime ::class )
32
+ @OptIn(ExperimentalCoroutinesApi ::class , WorkflowExperimentalRuntime ::class )
33
33
class RenderWorkflowInTest {
34
34
35
35
/* *
36
- * A [TestScope] that will not run until explicitly told to.
37
- */
38
- private lateinit var pausedTestScope: TestScope
39
-
40
- /* *
41
- * A [TestScope] that will automatically dispatch enqueued routines.
36
+ * lateinit so that we can get a fresh scope for each parameterized test run.
42
37
*/
43
38
private lateinit var testScope: TestScope
44
39
@@ -52,8 +47,7 @@ class RenderWorkflowInTest {
52
47
private val runtimeTestRunner = ParameterizedTestRunner <RuntimeConfig >()
53
48
54
49
private fun setup () {
55
- pausedTestScope = TestScope ()
56
- testScope = TestScope (UnconfinedTestDispatcher ())
50
+ testScope = TestScope ()
57
51
}
58
52
59
53
@Test fun initial_rendering_is_calculated_synchronously () {
@@ -67,7 +61,7 @@ class RenderWorkflowInTest {
67
61
68
62
val renderings = renderWorkflowIn(
69
63
workflow = workflow,
70
- scope = pausedTestScope ,
64
+ scope = testScope ,
71
65
props = props,
72
66
runtimeConfig = runtimeConfig
73
67
) {}
@@ -83,17 +77,18 @@ class RenderWorkflowInTest {
83
77
val props = MutableStateFlow (" foo" )
84
78
val workflow = Workflow .stateless<String , Nothing , String > { " props: $it " }
85
79
86
- pausedTestScope .cancel()
80
+ testScope .cancel()
87
81
val renderings = renderWorkflowIn(
88
82
workflow = workflow,
89
- scope = pausedTestScope ,
83
+ scope = testScope ,
90
84
props = props,
91
85
runtimeConfig = runtimeConfig
92
86
) {}
93
87
assertEquals(" props: foo" , renderings.value.rendering)
94
88
}
95
89
}
96
90
91
+ @Ignore // Deciding if we want this behavior or if side effects should start.
97
92
@Test
98
93
fun `side_effects_from_initial_rendering_in_root_workflow_are_never_started_when_scope_cancelled_before_start` () {
99
94
runtimeTestRunner.runParametrizedTest(
@@ -120,6 +115,7 @@ class RenderWorkflowInTest {
120
115
}
121
116
}
122
117
118
+ @Ignore // Deciding if we want this behavior.
123
119
@Test
124
120
fun `side_effects_from_initial_rendering_in_non_root_workflow_are_never_started_when_scope_cancelled_before_start` () {
125
121
runtimeTestRunner.runParametrizedTest(
@@ -364,12 +360,15 @@ class RenderWorkflowInTest {
364
360
) {
365
361
receivedOutputs + = it
366
362
}
363
+ testScope.advanceUntilIdle()
367
364
assertTrue(receivedOutputs.isEmpty())
368
365
369
366
trigger.trySend(" foo" ).isSuccess
367
+ testScope.advanceUntilIdle()
370
368
assertEquals(listOf (" foo" ), receivedOutputs)
371
369
372
370
trigger.trySend(" bar" ).isSuccess
371
+ testScope.advanceUntilIdle()
373
372
assertEquals(listOf (" foo" , " bar" ), receivedOutputs)
374
373
}
375
374
}
@@ -535,6 +534,7 @@ class RenderWorkflowInTest {
535
534
runtimeConfig = runtimeConfig
536
535
) {}
537
536
}
537
+ testScope.advanceUntilIdle()
538
538
assertTrue(sideEffectWasRan)
539
539
assertNotNull(cancellationException)
540
540
val realCause = generateSequence(cancellationException) { it.cause }
@@ -543,6 +543,7 @@ class RenderWorkflowInTest {
543
543
}
544
544
}
545
545
546
+ @Ignore // Deciding if we want this behavior, or if all side effects should at least start.
546
547
@Test
547
548
fun `side_effects_from_initial_rendering_in_non_root_workflow_are_never_started_when_initial_render_of_non_root_workflow_fails` () {
548
549
runtimeTestRunner.runParametrizedTest(
@@ -653,10 +654,12 @@ class RenderWorkflowInTest {
653
654
props = MutableStateFlow (Unit ),
654
655
runtimeConfig = runtimeConfig
655
656
) {}
657
+ testScope.advanceUntilIdle()
656
658
assertNull(cancellationException)
657
659
assertTrue(testScope.isActive)
658
660
659
661
testScope.cancel()
662
+ testScope.advanceUntilIdle()
660
663
assertTrue(cancellationException is CancellationException )
661
664
assertNull(cancellationException!! .cause)
662
665
}
@@ -716,10 +719,12 @@ class RenderWorkflowInTest {
716
719
props = MutableStateFlow (Unit ),
717
720
runtimeConfig = runtimeConfig
718
721
) {}
722
+ testScope.advanceUntilIdle()
719
723
assertNull(cancellationException)
720
724
assertTrue(testScope.isActive)
721
725
722
726
testScope.cancel(CancellationException (" fail!" , ExpectedException ()))
727
+ testScope.advanceUntilIdle()
723
728
assertTrue(cancellationException is CancellationException )
724
729
assertTrue(cancellationException!! .cause is ExpectedException )
725
730
}
@@ -766,17 +771,17 @@ class RenderWorkflowInTest {
766
771
}
767
772
val renderings = renderWorkflowIn(
768
773
workflow = workflow,
769
- scope = pausedTestScope ,
774
+ scope = testScope ,
770
775
props = MutableStateFlow (Unit ),
771
776
runtimeConfig = runtimeConfig
772
777
) {}
773
778
774
- pausedTestScope .launch {
779
+ testScope .launch {
775
780
renderings.collect { throw ExpectedException () }
776
781
}
777
782
assertNull(cancellationException)
778
783
779
- pausedTestScope .advanceUntilIdle()
784
+ testScope .advanceUntilIdle()
780
785
assertTrue(cancellationException is CancellationException )
781
786
assertTrue(cancellationException!! .cause is ExpectedException )
782
787
}
@@ -794,20 +799,20 @@ class RenderWorkflowInTest {
794
799
}
795
800
renderWorkflowIn(
796
801
workflow = workflow,
797
- scope = pausedTestScope ,
802
+ scope = testScope ,
798
803
props = MutableStateFlow (Unit ),
799
804
runtimeConfig = runtimeConfig
800
805
) {
801
806
throw ExpectedException ()
802
807
}
803
- assertTrue(pausedTestScope .isActive)
808
+ assertTrue(testScope .isActive)
804
809
805
810
trigger.complete(Unit )
806
- assertTrue(pausedTestScope .isActive)
811
+ assertTrue(testScope .isActive)
807
812
808
- pausedTestScope .advanceUntilIdle()
809
- pausedTestScope .runCurrent()
810
- assertFalse(pausedTestScope .isActive)
813
+ testScope .advanceUntilIdle()
814
+ testScope .runCurrent()
815
+ assertFalse(testScope .isActive)
811
816
}
812
817
}
813
818
@@ -834,20 +839,20 @@ class RenderWorkflowInTest {
834
839
835
840
renderWorkflowIn(
836
841
workflow = workflow,
837
- scope = pausedTestScope ,
842
+ scope = testScope ,
838
843
props = MutableStateFlow (Unit ),
839
844
runtimeConfig = runtimeConfig,
840
845
onOutput = { events + = " output($it )" }
841
846
)
842
847
.onEach { events + = " rendering(${it.rendering} )" }
843
- .launchIn(pausedTestScope )
844
- pausedTestScope .advanceUntilIdle()
845
- pausedTestScope .runCurrent()
848
+ .launchIn(testScope )
849
+ testScope .advanceUntilIdle()
850
+ testScope .runCurrent()
846
851
assertEquals(listOf (" rendering({no output})" ), events)
847
852
848
853
outputTrigger.complete(" output" )
849
- pausedTestScope .advanceUntilIdle()
850
- pausedTestScope .runCurrent()
854
+ testScope .advanceUntilIdle()
855
+ testScope .runCurrent()
851
856
assertEquals(
852
857
listOf (
853
858
" rendering({no output})" ,
@@ -974,6 +979,7 @@ class RenderWorkflowInTest {
974
979
val renderings = ras.map { it.rendering }
975
980
.produceIn(testScope)
976
981
982
+ testScope.advanceUntilIdle()
977
983
assertFailsWith<ExpectedException > {
978
984
renderings.tryReceive()
979
985
.getOrNull()
@@ -983,7 +989,6 @@ class RenderWorkflowInTest {
983
989
984
990
props.value + = 1
985
991
testScope.advanceUntilIdle()
986
- testScope.runCurrent()
987
992
988
993
assertFailsWith<ExpectedException > {
989
994
renderings.tryReceive()
0 commit comments