원클릭으로
workflow-testing
// Write unit tests for StatefulWorkflow and StatelessWorkflow using testRender and RenderTester. Use for workflow unit testing, render testing, expectWorker, expectWorkflow, action verification, or WorkflowOutput assertions.
// Write unit tests for StatefulWorkflow and StatelessWorkflow using testRender and RenderTester. Use for workflow unit testing, render testing, expectWorker, expectWorkflow, action verification, or WorkflowOutput assertions.
Extracts and manages AI context (skills, AGENTS.md) from workflow-kotlin library JARs. Use when setting up AI tooling for a workflow-kotlin project, updating skills after a library version change, or configuring agent-specific directories.
Create Square Workflow classes (StatefulWorkflow or StatelessWorkflow). Use when creating workflows, implementing state machines, handling async operations with Workers, or when user mentions "new workflow", "workflow", "state machine", or "StatefulWorkflow".
Create Square Workflow classes (StatefulWorkflow or StatelessWorkflow). Use when creating workflows, implementing state machines, handling async operations with Workers, or when user mentions "new workflow", "workflow", "state machine", or "StatefulWorkflow".
Write integration tests for Workflows using renderForTest and WorkflowTurbine. Use when testing full workflow runtime behavior, async operations, state changes over time, output emissions, multi-step user flows, or when user mentions "integration test", "renderForTest", or "WorkflowTurbine".
| name | workflow-testing |
| description | Write unit tests for StatefulWorkflow and StatelessWorkflow using testRender and RenderTester. Use for workflow unit testing, render testing, expectWorker, expectWorkflow, action verification, or WorkflowOutput assertions. |
Write unit tests for individual render passes using testRender and RenderTester. This API
fakes all children and workers, letting you test render logic in isolation.
For multi-step flows or async behavior, use renderForTest / WorkflowTurbine instead
(see the workflow-integration-testing skill).
import com.squareup.workflow1.WorkflowOutput
import com.squareup.workflow1.testing.expectWorker
import com.squareup.workflow1.testing.expectWorkflow
import com.squareup.workflow1.testing.testRender
import kotlin.test.Test
import kotlin.test.assertEquals
import kotlin.test.assertNull
class MyWorkflowTest {
private val workflow = MyWorkflow()
@Test fun `renders initial state correctly`() {
workflow.testRender(
props = MyProps("test"),
initialState = MyState.Initial
)
.render { rendering ->
assertEquals("test", rendering.title)
assertEquals(false, rendering.isLoading)
}
}
}
// StatefulWorkflow — provide props and state
workflow.testRender(props = myProps, initialState = myState)
// StatefulWorkflow — use workflow's initialState method (null snapshot)
workflow.testRender(props = myProps)
// StatelessWorkflow — props only
workflow.testRender(props = myProps)
workflow.testRender(props, state)
.render { rendering ->
// Assert on rendering properties
assertEquals("Hello", rendering.title)
assertTrue(rendering.isLoading)
// Optionally trigger an event handler (at most one per test)
rendering.onButtonClicked()
}
After triggering an event handler or receiving a child/worker output, verify the action:
// Option 1: Verify the action identity (for sealed class / enum actions)
.verifyAction { action ->
assertEquals(MyAction.LoadData, action)
}
// Option 2: Verify the action result (for inline / anonymous actions)
.verifyActionResult { newState, output ->
assertEquals(MyState.Loading, newState)
assertNull(output) // no output emitted
}
output is WorkflowOutput<OutputT>? — use output?.value to access the actual value,
or check assertNull(output) when no output is expected.
@Test fun `button click transitions to loading`() {
workflow.testRender(
props = MyProps("test"),
initialState = MyState.Initial
)
.render { rendering ->
rendering.onLoadClicked()
}
.verifyActionResult { newState, output ->
assertEquals(MyState.Loading, newState)
assertNull(output)
}
}
@Test fun `complete button emits finished output`() {
workflow.testRender(
props = MyProps("test"),
initialState = MyState.Done("result")
)
.render { rendering ->
rendering.onCompleteClicked()
}
.verifyActionResult { newState, output ->
assertEquals(MyOutput.Finished("result"), output?.value)
}
}
@Test fun `renders loading state without triggering action`() {
workflow.testRender(
props = MyProps("test"),
initialState = MyState.Loading
)
.render { rendering ->
// Just assert, don't trigger any event handler
assertTrue(rendering.isLoading)
assertEquals("Loading...", rendering.message)
}
}
All child workflows rendered by the workflow-under-test must be faked via providing expectations:
@Test fun `renders child workflow with correct props`() {
workflow.testRender(props = MyProps("123"), initialState = MyState.ShowChild)
.expectWorkflow(
workflowType = ChildWorkflow::class,
rendering = ChildScreen("faked"),
key = "", // default key, omit if not using keys
assertProps = { props ->
assertEquals("123", props.itemId)
}
)
.render { rendering ->
assertEquals("faked", rendering.childContent)
}
}
@Test fun `handles child workflow output`() {
workflow.testRender(props = MyProps("123"), initialState = MyState.ShowChild)
.expectWorkflow(
workflowType = ChildWorkflow::class,
rendering = ChildScreen("faked"),
output = WorkflowOutput(ChildOutput.Done("result"))
)
.render { rendering ->
// Don't trigger any event handler — child is emitting output
}
.verifyActionResult { newState, output ->
assertEquals(MyState.Complete("result"), newState)
}
}
Workers are optionally expected by default. Use requireExplicitWorkerExpectations() to
make all workers required.
import kotlin.reflect.typeOf
workflow.testRender(props, state)
.expectWorker(
workerType = typeOf<Worker<MyData>>(),
key = "fetchData"
)
.render { ... }
workflow.testRender(props, state)
.expectWorker(
workerClass = MyCustomWorker::class,
key = "fetch"
)
.render { ... }
workflow.testRender(props, state)
.expectWorkerOutputting(
outputType = typeOf<MyData>(),
key = "fetchData"
)
.render { ... }
workflow.testRender(props, state)
.expectWorker(
workerType = typeOf<Worker<MyData>>(),
key = "fetchData",
output = WorkflowOutput(MyData("result"))
)
.render { rendering ->
// Don't trigger event handlers — worker is emitting output
}
.verifyActionResult { newState, output ->
assertEquals(MyState.Loaded("result"), newState)
}
workflow.testRender(props, state)
.expectSideEffect(key = "analytics")
.render { ... }
Side effects are optionally expected by default.
Use requireExplicitSideEffectExpectations() to require all side effects be expected.
Test multiple sequential renders without the overhead of a full runtime:
@Test fun `multi-step flow`() {
workflow.testRender(props = MyProps("test"), initialState = MyState.Initial)
.render { rendering ->
rendering.onLoadClicked()
}
.verifyActionResult { newState, _ ->
assertEquals(MyState.Loading, newState)
}
// Continue with the new state from the previous action
.testNextRender()
.expectWorker(workerType = typeOf<Worker<Data>>(), key = "fetch")
.render { rendering ->
assertTrue(rendering.isLoading)
}
}
.testNextRenderWithProps(MyProps("updated"))
.render { rendering ->
assertEquals("updated", rendering.title)
}
Note: testNextRenderWithProps will call onPropsChanged if the workflow overrides it.
verifyActionResult for inline/anonymous actions (most common)verifyAction for sealed class or enum actions where you test the action typerequireExplicitWorkerExpectations() when you need to verify no unexpected workers run`button click transitions to loading`// Core testing API
import com.squareup.workflow1.testing.testRender
// Expectations
import com.squareup.workflow1.testing.expectWorkflow
import com.squareup.workflow1.testing.expectWorker
import com.squareup.workflow1.testing.expectWorkerOutputting
import com.squareup.workflow1.testing.expectSideEffect
// Output wrapper
import com.squareup.workflow1.WorkflowOutput
// For worker type matching
import kotlin.reflect.typeOf
import com.squareup.workflow1.Worker
// Assertions
import kotlin.test.Test
import kotlin.test.assertEquals
import kotlin.test.assertNull
import kotlin.test.assertTrue
launchForTestingFromStartWithrenderForTestlaunchForTestingWithrenderForTestWorkflowTestRuntimeWorkflowTurbineThese are deprecated integration test APIs. For integration testing, use the
workflow-integration-testing skill instead.