@@ -103,6 +103,8 @@ internal class RealRenderTester<PropsT, StateT, OutputT, RenderingT>(
103103 }
104104 }
105105
106+ private var frozen = false
107+
106108 private var explicitWorkerExpectationsRequired: Boolean = false
107109 private var explicitSideEffectExpectationsRequired: Boolean = false
108110 private val stateAndOutput: Pair <StateT , WorkflowOutput <OutputT >? > by lazy {
@@ -151,12 +153,13 @@ internal class RealRenderTester<PropsT, StateT, OutputT, RenderingT>(
151153 expectSideEffect(description = " unexpected side effect" , exactMatch = false ) { true }
152154 }
153155
156+ frozen = false
154157 // Clone the expectations to run a "dry" render pass.
155158 val noopContext = deepCloneForRender()
156159 workflow.render(props, state, RenderContext (noopContext, workflow))
157-
158- workflow.render(props, state, RenderContext ( this , workflow))
159- . also ( block)
160+ val rendering = workflow.render(props, state, RenderContext ( this , workflow))
161+ frozen = true
162+ block(rendering )
160163
161164 // Ensure all exact matches were consumed.
162165 val unconsumedExactMatches = expectations.filter {
@@ -184,6 +187,7 @@ internal class RealRenderTester<PropsT, StateT, OutputT, RenderingT>(
184187 key : String ,
185188 handler : (ChildOutputT ) -> WorkflowAction <PropsT , StateT , OutputT >
186189 ): ChildRenderingT {
190+ checkNotFrozen { " renderChild(${child.identifier} )" }
187191 val identifierPair = Pair (child.identifier, key)
188192 require(identifierPair !in renderedChildren) {
189193 " Expected keys to be unique for ${child.identifier} : key=\" $key \" "
@@ -244,6 +248,7 @@ internal class RealRenderTester<PropsT, StateT, OutputT, RenderingT>(
244248 key : String ,
245249 sideEffect : suspend CoroutineScope .() -> Unit
246250 ) {
251+ checkNotFrozen { " runningSideEffect($key )" }
247252 require(key !in ranSideEffects) { " Expected side effect keys to be unique: \" $key \" " }
248253 ranSideEffects + = key
249254
@@ -279,6 +284,7 @@ internal class RealRenderTester<PropsT, StateT, OutputT, RenderingT>(
279284 vararg inputs : Any? ,
280285 calculation : () -> ResultT
281286 ): ResultT {
287+ checkNotFrozen { " remember($key )" }
282288 val mapKey = TestRememberKey (key, resultType, inputs.asList())
283289 check(rememberSet.add(mapKey)) {
284290 " Expected combination of key, inputs and result type to be unique: \" $key \" "
@@ -297,6 +303,12 @@ internal class RealRenderTester<PropsT, StateT, OutputT, RenderingT>(
297303 }
298304
299305 override fun send (value : WorkflowAction <PropsT , StateT , OutputT >) {
306+ if (! frozen) {
307+ throw UnsupportedOperationException (
308+ " Expected sink to not be sent to until after the render pass. " +
309+ " Received action: ${value.debuggingName} "
310+ )
311+ }
300312 checkNoOutputs()
301313 check(processedAction == null ) {
302314 " Tried to send action to sink after another action was already processed:\n " +
@@ -363,6 +375,11 @@ internal class RealRenderTester<PropsT, StateT, OutputT, RenderingT>(
363375 expectationsWithOutputs.joinToString(separator = " \n " ) { " $it " }
364376 }
365377 }
378+
379+ private fun checkNotFrozen (reason : () -> String = { "" }) = check(! frozen) {
380+ " RenderContext cannot be used after render method returns" +
381+ " ${reason().takeUnless { it.isBlank() }?.let { " ($it )" }} "
382+ }
366383}
367384
368385internal fun createRenderChildInvocation (
0 commit comments