Skip to content

Commit 5f294b9

Browse files
authored
Make TestStore.receive actually match the action predicate (#1780)
* Assert that TestStore.receive(...) actually calls its predicate * Fix TestStore.receive to respect its action predicate * Update TestStore failure tests to use new description strings
1 parent 626c35c commit 5f294b9

File tree

4 files changed

+68
-59
lines changed

4 files changed

+68
-59
lines changed

Sources/ComposableArchitecture/TestStore.swift

Lines changed: 30 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -1174,30 +1174,18 @@ extension TestStore where ScopedState: Equatable, Action: Equatable {
11741174
) {
11751175
self.receiveAction(
11761176
matching: { expectedAction == $0 },
1177-
failureMessage: "Expected to receive an action \(expectedAction), but didn't get one.",
1178-
onReceive: { receivedAction in
1179-
if expectedAction != receivedAction {
1180-
let difference = TaskResultDebugging.$emitRuntimeWarnings.withValue(false) {
1181-
diff(expectedAction, receivedAction, format: .proportional)
1182-
.map { "\($0.indent(by: 4))\n\n(Expected: −, Received: +)" }
1183-
?? """
1184-
Expected:
1185-
\(String(describing: expectedAction).indent(by: 2))
1186-
1187-
Received:
1188-
\(String(describing: receivedAction).indent(by: 2))
1189-
"""
1190-
}
1191-
1192-
XCTFailHelper(
1177+
failureMessage: #"Expected to receive an action "\#(expectedAction)", but didn't get one."#,
1178+
unexpectedActionDescription: { receivedAction in
1179+
TaskResultDebugging.$emitRuntimeWarnings.withValue(false) {
1180+
diff(expectedAction, receivedAction, format: .proportional)
1181+
.map { "\($0.indent(by: 4))\n\n(Expected: −, Received: +)" }
1182+
?? """
1183+
Expected:
1184+
\(String(describing: expectedAction).indent(by: 2))
1185+
1186+
Received:
1187+
\(String(describing: receivedAction).indent(by: 2))
11931188
"""
1194-
Received unexpected action: …
1195-
1196-
\(difference)
1197-
""",
1198-
file: file,
1199-
line: line
1200-
)
12011189
}
12021190
},
12031191
updateStateToExpectedResult,
@@ -1231,22 +1219,11 @@ extension TestStore where ScopedState: Equatable, Action: Equatable {
12311219
) {
12321220
self.receiveAction(
12331221
matching: matching,
1234-
failureMessage: "Expected to receive a matching action, but didn't get one.",
1235-
onReceive: { receivedAction in
1222+
failureMessage: "Expected to receive an action matching predicate, but didn't get one.",
1223+
unexpectedActionDescription: { receivedAction in
12361224
var action = ""
12371225
customDump(receivedAction, to: &action, indent: 2)
1238-
XCTFailHelper(
1239-
"""
1240-
Received action without asserting on payload:
1241-
1242-
\(action)
1243-
""",
1244-
overrideExhaustivity: self.exhaustivity == .on
1245-
? .off(showSkippedAssertions: true)
1246-
: self.exhaustivity,
1247-
file: file,
1248-
line: line
1249-
)
1226+
return action
12501227
},
12511228
updateStateToExpectedResult,
12521229
file: file,
@@ -1277,22 +1254,11 @@ extension TestStore where ScopedState: Equatable, Action: Equatable {
12771254
) {
12781255
self.receiveAction(
12791256
matching: { casePath.extract(from: $0) != nil },
1280-
failureMessage: "Expected to receive a matching action, but didn't get one.",
1281-
onReceive: { receivedAction in
1257+
failureMessage: "Expected to receive an action matching case path, but didn't get one.",
1258+
unexpectedActionDescription: { receivedAction in
12821259
var action = ""
12831260
customDump(receivedAction, to: &action, indent: 2)
1284-
XCTFailHelper(
1285-
"""
1286-
Received action without asserting on payload:
1287-
1288-
\(action)
1289-
""",
1290-
overrideExhaustivity: self.exhaustivity == .on
1291-
? .off(showSkippedAssertions: true)
1292-
: self.exhaustivity,
1293-
file: file,
1294-
line: line
1295-
)
1261+
return action
12961262
},
12971263
updateStateToExpectedResult,
12981264
file: file,
@@ -1569,16 +1535,14 @@ extension TestStore where ScopedState: Equatable, Action: Equatable {
15691535
private func receiveAction(
15701536
matching predicate: (Action) -> Bool,
15711537
failureMessage: @autoclosure () -> String,
1572-
onReceive: (Action) -> Void,
1538+
unexpectedActionDescription: (Action) -> String,
15731539
_ updateStateToExpectedResult: ((inout ScopedState) throws -> Void)?,
15741540
file: StaticString,
15751541
line: UInt
15761542
) {
15771543
guard !self.reducer.receivedActions.isEmpty else {
15781544
XCTFail(
1579-
"""
1580-
Expected to receive an action, but received none.
1581-
""",
1545+
failureMessage(),
15821546
file: file,
15831547
line: line
15841548
)
@@ -1622,7 +1586,17 @@ extension TestStore where ScopedState: Equatable, Action: Equatable {
16221586
}
16231587

16241588
let (receivedAction, state) = self.reducer.receivedActions.removeFirst()
1625-
onReceive(receivedAction)
1589+
if !predicate(receivedAction) {
1590+
XCTFailHelper(
1591+
"""
1592+
Received unexpected action: …
1593+
1594+
\(unexpectedActionDescription(receivedAction))
1595+
""",
1596+
file: file,
1597+
line: line
1598+
)
1599+
}
16261600
let expectedState = self.toScopedState(self.state)
16271601
do {
16281602
try self.expectedStateShouldMatch(

Tests/ComposableArchitectureTests/TestStoreFailureTests.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -216,7 +216,7 @@
216216
XCTExpectFailure {
217217
store.receive(.action)
218218
} issueMatcher: { issue in
219-
issue.compactDescription == "Expected to receive an action, but received none."
219+
issue.compactDescription == #"Expected to receive an action "action", but didn't get one."#
220220
}
221221
}
222222

Tests/ComposableArchitectureTests/TestStoreNonExhaustiveTests.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -606,7 +606,7 @@
606606

607607
XCTExpectFailure {
608608
$0.compactDescription == """
609-
Expected to receive a matching action, but didn't get one.
609+
Expected to receive an action matching case path, but didn't get one.
610610
"""
611611
}
612612

@@ -627,7 +627,7 @@
627627

628628
XCTExpectFailure {
629629
$0.compactDescription == """
630-
Expected to receive an action, but received none.
630+
Expected to receive an action matching case path, but didn't get one.
631631
"""
632632
}
633633

Tests/ComposableArchitectureTests/TestStoreTests.swift

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,41 @@ final class TestStoreTests: XCTestCase {
167167
}
168168
}
169169
}
170+
171+
func testReceiveActionMatchingPredicate() async {
172+
enum Action: Equatable {
173+
case noop, finished
174+
}
175+
176+
let reducer = Reduce<Int, Action> { state, action in
177+
switch action {
178+
case .noop:
179+
return EffectTask(value: .finished)
180+
case .finished:
181+
return .none
182+
}
183+
}
184+
185+
let store = TestStore(initialState: 0, reducer: reducer)
186+
187+
let predicateShouldBeCalledExpectation = expectation(description: "predicate should be called")
188+
await store.send(.noop)
189+
await store.receive { action in
190+
predicateShouldBeCalledExpectation.fulfill()
191+
return action == .finished
192+
}
193+
wait(for: [predicateShouldBeCalledExpectation], timeout: 0)
194+
195+
XCTExpectFailure {
196+
store.send(.noop)
197+
store.receive(.noop)
198+
}
199+
200+
XCTExpectFailure {
201+
store.send(.noop)
202+
store.receive { $0 == .noop }
203+
}
204+
}
170205
#endif
171206

172207
func testStateAccess() async {

0 commit comments

Comments
 (0)