Skip to content

Commit aab735b

Browse files
authored
Exhaustive RenderTester state assertion (#238)
- Before: To perform exhaustive state assertions with a RenderTester you have to manually keep track of the initial state. - After: Added RenderTesterResult/assertState which makes it easy to perform exhaustive state assertions by mutating the initial state
1 parent d5f33e4 commit aab735b

File tree

4 files changed

+35
-1
lines changed

4 files changed

+35
-1
lines changed

WorkflowTesting/Sources/RenderTesterResult.swift

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,13 @@ import XCTest
2020
/// The result of a `RenderTester` rendering. Used to verify state, output, and actions that were produced as a result of
2121
/// actions performed during the render (such as child workflow output being produced).
2222
public struct RenderTesterResult<WorkflowType: Workflow> {
23+
let initialState: WorkflowType.State
2324
let state: WorkflowType.State
2425
let appliedAction: AppliedAction<WorkflowType>?
2526
let output: WorkflowType.Output?
2627

27-
internal init(state: WorkflowType.State, appliedAction: AppliedAction<WorkflowType>?, output: WorkflowType.Output?) {
28+
internal init(initialState: WorkflowType.State, state: WorkflowType.State, appliedAction: AppliedAction<WorkflowType>?, output: WorkflowType.Output?) {
29+
self.initialState = initialState
2830
self.state = state
2931
self.appliedAction = appliedAction
3032
self.output = output
@@ -120,6 +122,22 @@ extension RenderTesterResult where WorkflowType.State: Equatable {
120122
XCTAssertEqual(state, expectedState, file: file, line: line)
121123
return self
122124
}
125+
126+
/// Exhaustive state testing against the initial state.
127+
/// - Parameters:
128+
/// - modifications: A function that receives the initial state
129+
/// and is expected to mutate it to match the new state.
130+
@discardableResult
131+
public func assertStateModifications(
132+
file: StaticString = #file,
133+
line: UInt = #line,
134+
_ modifications: (inout WorkflowType.State) throws -> Void
135+
) rethrows -> RenderTesterResult<WorkflowType> {
136+
var initialState = self.initialState
137+
try modifications(&initialState)
138+
XCTAssertEqual(state, initialState, "Expected state does not match", file: file, line: line)
139+
return self
140+
}
123141
}
124142

125143
extension RenderTesterResult where WorkflowType.Output: Equatable {

WorkflowTesting/Sources/WorkflowRenderTester.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -275,6 +275,7 @@ public struct RenderTester<WorkflowType: Workflow> {
275275
try assertions(rendering)
276276

277277
return RenderTesterResult<WorkflowType>(
278+
initialState: state,
278279
state: contextImplementation.state,
279280
appliedAction: contextImplementation.appliedAction,
280281
output: contextImplementation.producedOutput

WorkflowTesting/Tests/WorkflowRenderTesterFailureTests.swift

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -340,6 +340,18 @@ final class WorkflowRenderTesterFailureTests: XCTestCase {
340340
}
341341
}
342342
}
343+
344+
func test_assertState() {
345+
let result = TestWorkflow()
346+
.renderTester(initialState: .idle)
347+
.render { _ in }
348+
349+
expectingFailure("Expected state does not match") {
350+
result.assertStateModifications { state in
351+
state = .sideEffect(key: "nah")
352+
}
353+
}
354+
}
343355
}
344356

345357
private struct TestWorkflow: Workflow {

WorkflowTesting/Tests/WorkflowRenderTesterTests.swift

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,9 @@ final class WorkflowRenderTesterTests: XCTestCase {
185185
.verifyState { state in
186186
XCTAssertEqual("Failed", state.text)
187187
}
188+
.assertStateModifications { state in
189+
state.text = "Failed"
190+
}
188191
}
189192
}
190193

0 commit comments

Comments
 (0)