Skip to content

Commit 5f34282

Browse files
Improve the RenderTester API.
- Cleans up the testing API exposed by `WorkflowIdentifier` and makes the type checking more precise. - Adds descriptions to expectations to allow for more readable error messages. - Adds `RenderTester` methods to match using arbitrary predicate functions. - Allows Workflow and side effect expectations to be non-exact – such expectations are optional, not required to be exclusive, and can match multiple times.
1 parent ab2afd8 commit 5f34282

File tree

10 files changed

+846
-291
lines changed

10 files changed

+846
-291
lines changed

workflow-core/api/workflow-core.api

+7-1
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,14 @@ public abstract interface annotation class com/squareup/workflow/ExperimentalWor
1111
}
1212

1313
public abstract interface class com/squareup/workflow/ImpostorWorkflow {
14+
public abstract fun describeRealIdentifier ()Ljava/lang/String;
1415
public abstract fun getRealIdentifier ()Lcom/squareup/workflow/WorkflowIdentifier;
1516
}
1617

18+
public final class com/squareup/workflow/ImpostorWorkflow$DefaultImpls {
19+
public static fun describeRealIdentifier (Lcom/squareup/workflow/ImpostorWorkflow;)Ljava/lang/String;
20+
}
21+
1722
public abstract class com/squareup/workflow/LifecycleWorker : com/squareup/workflow/Worker {
1823
public fun <init> ()V
1924
public fun doesSameWorkAs (Lcom/squareup/workflow/Worker;)Z
@@ -173,9 +178,10 @@ public final class com/squareup/workflow/WorkflowAction$Updater {
173178

174179
public final class com/squareup/workflow/WorkflowIdentifier {
175180
public static final field Companion Lcom/squareup/workflow/WorkflowIdentifier$Companion;
181+
public final fun describeRealIdentifier ()Ljava/lang/String;
176182
public fun equals (Ljava/lang/Object;)Z
183+
public final fun getRealIdentifierType ()Lkotlin/reflect/KAnnotatedElement;
177184
public fun hashCode ()I
178-
public final fun matchesActualIdentifierForTest (Lcom/squareup/workflow/WorkflowIdentifier;)Z
179185
public final fun toByteStringOrNull ()Lokio/ByteString;
180186
public fun toString ()Ljava/lang/String;
181187
}

workflow-core/src/main/java/com/squareup/workflow/ImpostorWorkflow.kt

+5
Original file line numberDiff line numberDiff line change
@@ -37,4 +37,9 @@ interface ImpostorWorkflow {
3737
* [Workflow] that this workflow wraps.
3838
*/
3939
val realIdentifier: WorkflowIdentifier
40+
41+
/**
42+
* Returns a string that describes how this workflow is related to [realIdentifier].
43+
*/
44+
fun describeRealIdentifier(): String? = null
4045
}

workflow-core/src/main/java/com/squareup/workflow/Workflow.kt

+3
Original file line numberDiff line numberDiff line change
@@ -146,5 +146,8 @@ fun <PropsT, OutputT, FromRenderingT, ToRenderingT>
146146
return transform(rendering)
147147
}
148148

149+
override fun describeRealIdentifier(): String? =
150+
"${this@mapRendering.identifier}.mapRendering()"
151+
149152
override fun toString(): String = "${this@mapRendering}.mapRendering()"
150153
}

workflow-core/src/main/java/com/squareup/workflow/WorkflowAction.kt

+7-1
Original file line numberDiff line numberDiff line change
@@ -176,7 +176,13 @@ interface WorkflowAction<in PropsT, StateT, out OutputT> {
176176
): WorkflowAction<PropsT, StateT, OutputT> =
177177
action({ "emitOutput($name, $output)" }) { setOutput(output) }
178178

179-
private val NO_ACTION = action<Any, Any, Any>({ "noAction" }) { }
179+
private val NO_ACTION = object : WorkflowAction<Any?, Any?, Any?> {
180+
override fun toString(): String = "WorkflowAction.noAction()"
181+
182+
override fun Updater<Any?, Any?, Any?>.apply() {
183+
// Noop
184+
}
185+
}
180186
}
181187
}
182188

workflow-core/src/main/java/com/squareup/workflow/WorkflowIdentifier.kt

+24-31
Original file line numberDiff line numberDiff line change
@@ -55,11 +55,13 @@ import kotlin.reflect.KType
5555
* [unsnapshottableIdentifier].
5656
* @param proxiedIdentifier An optional identifier from [ImpostorWorkflow.realIdentifier] that will
5757
* be used to further narrow the scope of this identifier.
58+
* @param description Implementation of [describeRealIdentifier].
5859
*/
5960
@ExperimentalWorkflowApi
6061
class WorkflowIdentifier internal constructor(
6162
private val type: KAnnotatedElement,
62-
private val proxiedIdentifier: WorkflowIdentifier? = null
63+
private val proxiedIdentifier: WorkflowIdentifier? = null,
64+
private val description: (() -> String?)? = null
6365
) {
6466
init {
6567
require(
@@ -77,14 +79,6 @@ class WorkflowIdentifier internal constructor(
7779

7880
private val proxiedIdentifiers = generateSequence(this) { it.proxiedIdentifier }
7981

80-
private val realIdentifierClass: KClass<*>
81-
get() = when (val realType = proxiedIdentifiers.last().type) {
82-
is KClass<*> -> realType
83-
// This cast guaranteed to succeed by the check in init.
84-
is KType -> realType.classifier as KClass<*>
85-
else -> error("Invalid WorkflowIdentifier type: $realType")
86-
}
87-
8882
/**
8983
* If this identifier is snapshottable, returns the serialized form of the identifier.
9084
* If it is not snapshottable, returns null.
@@ -110,6 +104,21 @@ class WorkflowIdentifier internal constructor(
110104
}
111105
}
112106

107+
/**
108+
* Returns either a [KClass] or [KType] representing the "real" type that this identifier
109+
* identifies – i.e. which is not an [ImpostorWorkflow].
110+
*/
111+
@TestOnly
112+
fun getRealIdentifierType(): KAnnotatedElement = proxiedIdentifiers.last().type
113+
114+
/**
115+
* If this identifier identifies an [ImpostorWorkflow], returns the result of that workflow's
116+
* [ImpostorWorkflow.describeRealIdentifier] method, otherwise returns null.
117+
*
118+
* Use [toString] to get a complete representation of this identifier.
119+
*/
120+
fun describeRealIdentifier(): String? = description?.invoke()
121+
113122
/**
114123
* Returns a description of this identifier including the name of its workflow type and any
115124
* [ImpostorWorkflow.realIdentifier]s.
@@ -131,25 +140,6 @@ class WorkflowIdentifier internal constructor(
131140
return result
132141
}
133142

134-
/**
135-
* Returns true if and only if both this identifier and [actual] have leaf real identifiers that
136-
* have the following relationship:
137-
*
138-
* - where the "leaf real identifier" is the last [ImpostorWorkflow.realIdentifier] in the chain
139-
* of [ImpostorWorkflow] identifiers that does not identify an [ImpostorWorkflow] itself,
140-
* - [actual]'s leaf identifier is the same type as, or a subtype of, this identifier's leaf
141-
* identifier.
142-
*
143-
* This predicate can be used for unit tests to assert that a workflow rendered a particular
144-
* child workflow, given a supertype of that child workflow.
145-
*/
146-
@TestOnly
147-
fun matchesActualIdentifierForTest(actual: WorkflowIdentifier): Boolean {
148-
val myId = realIdentifierClass.java
149-
val actualId = actual.realIdentifierClass.java
150-
return myId.isAssignableFrom(actualId)
151-
}
152-
153143
companion object {
154144
private const val NO_PROXY_IDENTIFIER_TAG = 0.toByte()
155145
private const val PROXY_IDENTIFIER_TAG = 1.toByte()
@@ -188,8 +178,12 @@ class WorkflowIdentifier internal constructor(
188178
@ExperimentalWorkflowApi
189179
val Workflow<*, *, *>.identifier: WorkflowIdentifier
190180
get() {
191-
val proxiedIdentifier = (this as? ImpostorWorkflow)?.realIdentifier
192-
return WorkflowIdentifier(type = this::class, proxiedIdentifier = proxiedIdentifier)
181+
val maybeImpostor = this as? ImpostorWorkflow
182+
return WorkflowIdentifier(
183+
type = this::class,
184+
proxiedIdentifier = maybeImpostor?.realIdentifier,
185+
description = maybeImpostor?.let { it::describeRealIdentifier }
186+
)
193187
}
194188

195189
/**
@@ -203,7 +197,6 @@ val Workflow<*, *, *>.identifier: WorkflowIdentifier
203197
* types.**
204198
*/
205199
@ExperimentalWorkflowApi
206-
@Suppress("unused")
207200
fun unsnapshottableIdentifier(type: KType): WorkflowIdentifier = WorkflowIdentifier(type)
208201

209202
/**

workflow-core/src/test/java/com/squareup/workflow/WorkflowIdentifierTest.kt

+19-44
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,8 @@ import kotlin.reflect.typeOf
2222
import kotlin.test.Test
2323
import kotlin.test.assertEquals
2424
import kotlin.test.assertFailsWith
25-
import kotlin.test.assertFalse
2625
import kotlin.test.assertNotEquals
2726
import kotlin.test.assertNull
28-
import kotlin.test.assertTrue
2927

3028
@OptIn(ExperimentalWorkflowApi::class, ExperimentalStdlibApi::class)
3129
class WorkflowIdentifierTest {
@@ -47,6 +45,11 @@ class WorkflowIdentifierTest {
4745
)
4846
}
4947

48+
@Test fun `impostor identifier description`() {
49+
val id = TestImpostor1(TestWorkflow1).identifier
50+
assertEquals("TestImpostor1(TestWorkflow1)", id.describeRealIdentifier())
51+
}
52+
5053
@Test fun `restored identifier toString`() {
5154
val id = TestWorkflow1.identifier
5255
val serializedId = id.toByteStringOrNull()!!
@@ -243,53 +246,24 @@ class WorkflowIdentifierTest {
243246
assertNotEquals(instanceId, classId)
244247
}
245248

246-
@Test fun `matchesActualIdentifierForTest() matches same workflow class`() {
247-
val id1 = TestWorkflow1.identifier
248-
val id2 = TestWorkflow1.identifier
249-
assertTrue(id1.matchesActualIdentifierForTest(id2))
250-
assertTrue(id2.matchesActualIdentifierForTest(id1))
251-
}
252-
253-
@Test fun `matchesActualIdentifierForTest() doesn't match different workflow types`() {
254-
val id1 = TestWorkflow1.identifier
255-
val id2 = TestWorkflow2.identifier
256-
assertFalse(id1.matchesActualIdentifierForTest(id2))
257-
}
258-
259-
@Test fun `matchesActualIdentifierForTest() matches subclass`() {
260-
val parentId = Parent::class.workflowIdentifier
261-
val childId = Child.identifier
262-
assertTrue(parentId.matchesActualIdentifierForTest(childId))
263-
}
264-
265-
@Test fun `matchesActualIdentifierForTest() doesn't match superclass`() {
266-
val parentId = Parent::class.workflowIdentifier
267-
val childId = Child.identifier
268-
assertFalse(childId.matchesActualIdentifierForTest(parentId))
249+
@Test fun `getRealIdentifierType() returns self for non-impostor workflow`() {
250+
val id = TestWorkflow1.identifier
251+
assertEquals(TestWorkflow1::class, id.getRealIdentifierType())
269252
}
270253

271-
@Test
272-
fun `matchesActualIdentifierForTest() matches impostor identifiers with same proxied identifiers`() {
273-
val id1 = TestImpostor1(TestWorkflow1).identifier
274-
val id2 = TestImpostor1(TestWorkflow1).identifier
275-
assertTrue(id1.matchesActualIdentifierForTest(id2))
276-
assertTrue(id2.matchesActualIdentifierForTest(id1))
254+
@Test fun `getRealIdentifierType() returns real identifier for impostor workflow`() {
255+
val id = TestImpostor1(TestWorkflow1).identifier
256+
assertEquals(TestWorkflow1::class, id.getRealIdentifierType())
277257
}
278258

279-
@Test
280-
fun `matchesActualIdentifierForTest() matches different impostor identifiers with same proxied identifier`() {
281-
val id1 = TestImpostor1(TestWorkflow1).identifier
282-
val id2 = TestImpostor2(TestWorkflow1).identifier
283-
assertTrue(id1.matchesActualIdentifierForTest(id2))
284-
assertTrue(id2.matchesActualIdentifierForTest(id1))
259+
@Test fun `getRealIdentifierType() returns leaf real identifier for impostor workflow chain`() {
260+
val id = TestImpostor2(TestImpostor1(TestWorkflow1)).identifier
261+
assertEquals(TestWorkflow1::class, id.getRealIdentifierType())
285262
}
286263

287-
@Test
288-
fun `matchesActualIdentifierForTest() doesn't match impostor identifiers with different proxied identifiers`() {
289-
val id1 = TestImpostor1(TestWorkflow1).identifier
290-
val id2 = TestImpostor1(TestWorkflow2).identifier
291-
assertFalse(id1.matchesActualIdentifierForTest(id2))
292-
assertFalse(id2.matchesActualIdentifierForTest(id1))
264+
@Test fun `getRealIdentifierType() returns KType of unsnapshottable identifier`() {
265+
val id = TestUnsnapshottableImpostor(typeOf<List<String>>()).identifier
266+
assertEquals(typeOf<List<String>>(), id.getRealIdentifierType())
293267
}
294268

295269
private object TestWorkflow1 : Workflow<Nothing, Nothing, Nothing> {
@@ -303,9 +277,10 @@ class WorkflowIdentifierTest {
303277
}
304278

305279
private class TestImpostor1(
306-
proxied: Workflow<*, *, *>
280+
private val proxied: Workflow<*, *, *>
307281
) : Workflow<Nothing, Nothing, Nothing>, ImpostorWorkflow {
308282
override val realIdentifier: WorkflowIdentifier = proxied.identifier
283+
override fun describeRealIdentifier(): String? = "TestImpostor1(${proxied::class.simpleName})"
309284
override fun asStatefulWorkflow(): StatefulWorkflow<Nothing, *, Nothing, Nothing> =
310285
throw NotImplementedError()
311286
}

workflow-testing/api/workflow-testing.api

+45-10
Original file line numberDiff line numberDiff line change
@@ -13,24 +13,59 @@ public abstract interface class com/squareup/workflow/testing/RenderTestResult {
1313
}
1414

1515
public abstract interface class com/squareup/workflow/testing/RenderTester {
16-
public abstract fun expectSideEffect (Ljava/lang/String;)Lcom/squareup/workflow/testing/RenderTester;
17-
public abstract fun expectWorker (Lkotlin/jvm/functions/Function1;Ljava/lang/String;Lcom/squareup/workflow/WorkflowOutput;)Lcom/squareup/workflow/testing/RenderTester;
18-
public abstract fun expectWorkflow (Lcom/squareup/workflow/WorkflowIdentifier;Ljava/lang/Object;Ljava/lang/String;Lkotlin/jvm/functions/Function1;Lcom/squareup/workflow/WorkflowOutput;)Lcom/squareup/workflow/testing/RenderTester;
19-
public abstract fun expectWorkflow (Lkotlin/reflect/KClass;Ljava/lang/Object;Ljava/lang/String;Lkotlin/jvm/functions/Function1;Lcom/squareup/workflow/WorkflowOutput;)Lcom/squareup/workflow/testing/RenderTester;
16+
public abstract fun expectSideEffect (Ljava/lang/String;ZLkotlin/jvm/functions/Function1;)Lcom/squareup/workflow/testing/RenderTester;
17+
public abstract fun expectWorker (Lkotlin/jvm/functions/Function1;Ljava/lang/String;Lcom/squareup/workflow/WorkflowOutput;Ljava/lang/String;)Lcom/squareup/workflow/testing/RenderTester;
18+
public abstract fun expectWorkflow (Lcom/squareup/workflow/WorkflowIdentifier;Ljava/lang/Object;Ljava/lang/String;Lkotlin/jvm/functions/Function1;Lcom/squareup/workflow/WorkflowOutput;Ljava/lang/String;)Lcom/squareup/workflow/testing/RenderTester;
19+
public abstract fun expectWorkflow (Ljava/lang/String;ZLkotlin/jvm/functions/Function1;)Lcom/squareup/workflow/testing/RenderTester;
20+
public abstract fun expectWorkflow (Lkotlin/reflect/KClass;Ljava/lang/Object;Ljava/lang/String;Lkotlin/jvm/functions/Function1;Lcom/squareup/workflow/WorkflowOutput;Ljava/lang/String;)Lcom/squareup/workflow/testing/RenderTester;
2021
public abstract fun render (Lkotlin/jvm/functions/Function1;)Lcom/squareup/workflow/testing/RenderTestResult;
2122
}
2223

24+
public abstract class com/squareup/workflow/testing/RenderTester$ChildWorkflowMatch {
25+
}
26+
27+
public final class com/squareup/workflow/testing/RenderTester$ChildWorkflowMatch$Matched : com/squareup/workflow/testing/RenderTester$ChildWorkflowMatch {
28+
public fun <init> (Ljava/lang/Object;Lcom/squareup/workflow/WorkflowOutput;)V
29+
public synthetic fun <init> (Ljava/lang/Object;Lcom/squareup/workflow/WorkflowOutput;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
30+
public final fun getChildRendering ()Ljava/lang/Object;
31+
public final fun getOutput ()Lcom/squareup/workflow/WorkflowOutput;
32+
}
33+
34+
public final class com/squareup/workflow/testing/RenderTester$ChildWorkflowMatch$NotMatched : com/squareup/workflow/testing/RenderTester$ChildWorkflowMatch {
35+
public static final field INSTANCE Lcom/squareup/workflow/testing/RenderTester$ChildWorkflowMatch$NotMatched;
36+
}
37+
2338
public final class com/squareup/workflow/testing/RenderTester$DefaultImpls {
24-
public static synthetic fun expectWorker$default (Lcom/squareup/workflow/testing/RenderTester;Lkotlin/jvm/functions/Function1;Ljava/lang/String;Lcom/squareup/workflow/WorkflowOutput;ILjava/lang/Object;)Lcom/squareup/workflow/testing/RenderTester;
25-
public static fun expectWorkflow (Lcom/squareup/workflow/testing/RenderTester;Lkotlin/reflect/KClass;Ljava/lang/Object;Ljava/lang/String;Lkotlin/jvm/functions/Function1;Lcom/squareup/workflow/WorkflowOutput;)Lcom/squareup/workflow/testing/RenderTester;
26-
public static synthetic fun expectWorkflow$default (Lcom/squareup/workflow/testing/RenderTester;Lcom/squareup/workflow/WorkflowIdentifier;Ljava/lang/Object;Ljava/lang/String;Lkotlin/jvm/functions/Function1;Lcom/squareup/workflow/WorkflowOutput;ILjava/lang/Object;)Lcom/squareup/workflow/testing/RenderTester;
27-
public static synthetic fun expectWorkflow$default (Lcom/squareup/workflow/testing/RenderTester;Lkotlin/reflect/KClass;Ljava/lang/Object;Ljava/lang/String;Lkotlin/jvm/functions/Function1;Lcom/squareup/workflow/WorkflowOutput;ILjava/lang/Object;)Lcom/squareup/workflow/testing/RenderTester;
39+
public static synthetic fun expectSideEffect$default (Lcom/squareup/workflow/testing/RenderTester;Ljava/lang/String;ZLkotlin/jvm/functions/Function1;ILjava/lang/Object;)Lcom/squareup/workflow/testing/RenderTester;
40+
public static synthetic fun expectWorker$default (Lcom/squareup/workflow/testing/RenderTester;Lkotlin/jvm/functions/Function1;Ljava/lang/String;Lcom/squareup/workflow/WorkflowOutput;Ljava/lang/String;ILjava/lang/Object;)Lcom/squareup/workflow/testing/RenderTester;
41+
public static fun expectWorkflow (Lcom/squareup/workflow/testing/RenderTester;Lcom/squareup/workflow/WorkflowIdentifier;Ljava/lang/Object;Ljava/lang/String;Lkotlin/jvm/functions/Function1;Lcom/squareup/workflow/WorkflowOutput;Ljava/lang/String;)Lcom/squareup/workflow/testing/RenderTester;
42+
public static fun expectWorkflow (Lcom/squareup/workflow/testing/RenderTester;Lkotlin/reflect/KClass;Ljava/lang/Object;Ljava/lang/String;Lkotlin/jvm/functions/Function1;Lcom/squareup/workflow/WorkflowOutput;Ljava/lang/String;)Lcom/squareup/workflow/testing/RenderTester;
43+
public static synthetic fun expectWorkflow$default (Lcom/squareup/workflow/testing/RenderTester;Lcom/squareup/workflow/WorkflowIdentifier;Ljava/lang/Object;Ljava/lang/String;Lkotlin/jvm/functions/Function1;Lcom/squareup/workflow/WorkflowOutput;Ljava/lang/String;ILjava/lang/Object;)Lcom/squareup/workflow/testing/RenderTester;
44+
public static synthetic fun expectWorkflow$default (Lcom/squareup/workflow/testing/RenderTester;Ljava/lang/String;ZLkotlin/jvm/functions/Function1;ILjava/lang/Object;)Lcom/squareup/workflow/testing/RenderTester;
45+
public static synthetic fun expectWorkflow$default (Lcom/squareup/workflow/testing/RenderTester;Lkotlin/reflect/KClass;Ljava/lang/Object;Ljava/lang/String;Lkotlin/jvm/functions/Function1;Lcom/squareup/workflow/WorkflowOutput;Ljava/lang/String;ILjava/lang/Object;)Lcom/squareup/workflow/testing/RenderTester;
2846
public static synthetic fun render$default (Lcom/squareup/workflow/testing/RenderTester;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)Lcom/squareup/workflow/testing/RenderTestResult;
2947
}
3048

49+
public final class com/squareup/workflow/testing/RenderTester$RenderChildInvocation {
50+
public fun <init> (Lcom/squareup/workflow/Workflow;Ljava/lang/Object;Lkotlin/reflect/KTypeProjection;Lkotlin/reflect/KTypeProjection;Ljava/lang/String;)V
51+
public final fun getOutputType ()Lkotlin/reflect/KTypeProjection;
52+
public final fun getProps ()Ljava/lang/Object;
53+
public final fun getRenderKey ()Ljava/lang/String;
54+
public final fun getRenderingType ()Lkotlin/reflect/KTypeProjection;
55+
public final fun getWorkflow ()Lcom/squareup/workflow/Workflow;
56+
}
57+
58+
public final class com/squareup/workflow/testing/RenderTester$SideEffectMatch : java/lang/Enum {
59+
public static final field MATCH Lcom/squareup/workflow/testing/RenderTester$SideEffectMatch;
60+
public static final field NOT_MATCHED Lcom/squareup/workflow/testing/RenderTester$SideEffectMatch;
61+
public static fun valueOf (Ljava/lang/String;)Lcom/squareup/workflow/testing/RenderTester$SideEffectMatch;
62+
public static fun values ()[Lcom/squareup/workflow/testing/RenderTester$SideEffectMatch;
63+
}
64+
3165
public final class com/squareup/workflow/testing/RenderTesterKt {
32-
public static final fun expectWorker (Lcom/squareup/workflow/testing/RenderTester;Lcom/squareup/workflow/Worker;Ljava/lang/String;Lcom/squareup/workflow/WorkflowOutput;)Lcom/squareup/workflow/testing/RenderTester;
33-
public static synthetic fun expectWorker$default (Lcom/squareup/workflow/testing/RenderTester;Lcom/squareup/workflow/Worker;Ljava/lang/String;Lcom/squareup/workflow/WorkflowOutput;ILjava/lang/Object;)Lcom/squareup/workflow/testing/RenderTester;
66+
public static final fun expectSideEffect (Lcom/squareup/workflow/testing/RenderTester;Ljava/lang/String;)Lcom/squareup/workflow/testing/RenderTester;
67+
public static final fun expectWorker (Lcom/squareup/workflow/testing/RenderTester;Lcom/squareup/workflow/Worker;Ljava/lang/String;Lcom/squareup/workflow/WorkflowOutput;Ljava/lang/String;)Lcom/squareup/workflow/testing/RenderTester;
68+
public static synthetic fun expectWorker$default (Lcom/squareup/workflow/testing/RenderTester;Lcom/squareup/workflow/Worker;Ljava/lang/String;Lcom/squareup/workflow/WorkflowOutput;Ljava/lang/String;ILjava/lang/Object;)Lcom/squareup/workflow/testing/RenderTester;
3469
public static final fun renderTester (Lcom/squareup/workflow/StatefulWorkflow;Ljava/lang/Object;Ljava/lang/Object;)Lcom/squareup/workflow/testing/RenderTester;
3570
public static final fun renderTester (Lcom/squareup/workflow/Workflow;Ljava/lang/Object;)Lcom/squareup/workflow/testing/RenderTester;
3671
public static final fun testRender (Lcom/squareup/workflow/StatefulWorkflow;Ljava/lang/Object;Ljava/lang/Object;)Lcom/squareup/workflow/testing/RenderTester;

0 commit comments

Comments
 (0)