-
DescriptionConsider the following simple feature: struct CounterFeature: ReducerProtocol {
struct State: Equatable {
var count = 0
}
enum Action {
case direct
case indirect
}
var body: some ReducerProtocol<State, Action> {
Reduce { state, action in
switch action {
case .direct:
return EffectTask(value: .indirect)
case .indirect:
state.count += 1
}
return .none
}
}
} When using non-exhaustive tests, it seems not to be possible to observe the state-change that gets indirectly triggered by just sending the @MainActor
final class NonExhaustiveTest: XCTestCase {
func testNonExhaustive() async {
let store = TestStore(initialState: CounterFeature.State()) {
CounterFeature()
}
store.exhaustivity = .off
await store.send(.direct) {
$0.count = 1
}
// 1️⃣ ❌ testNonExhaustive(): A state change does not match expectation: …
//
// − CounterFeature.State(count: 1)
// + CounterFeature.State(count: 0)
//
// (Expected: −, Actual: +)
XCTAssertEqual(store.state.count, 1)
// 2️⃣ ❌ testNonExhaustive(): XCTAssertEqual failed: ("0") is not equal to ("1")
await store.finish(timeout: .seconds(1))
XCTAssertEqual(store.state.count, 1)
// 3️⃣ ❌ testNonExhaustive(): XCTAssertEqual failed: ("0") is not equal to ("1")
await store.receive(.indirect) {
$0.count = 1
}
// 4️⃣ ✅ This one passes.
}
} I understand that 1️⃣ and 2️⃣ fail, because the state is not yet updated. But I would expect that 3️⃣ would reflect the updated state. The documentation of
I definitely expected this to work and spent a long time debugging this in a more complex scenario. If the Checklist
Expected behaviorThe state-change should be observed in 3️⃣. Actual behaviorThe assertions at 1️⃣, 2️⃣ and 3️⃣ fail. Steps to reproduceSee the above sample-code. The Composable Architecture version information0.55.0 Destination operating systemiOS 16.4 Xcode version informationVersion 14.3.1 (14E300c) Swift Compiler version informationswift-driver version: 1.75.2 Apple Swift version 5.8.1 (swiftlang-5.8.0.124.5 clang-1403.0.22.11.100)
Target: arm64-apple-macosx13.0 |
Beta Was this translation helpful? Give feedback.
Replies: 1 comment 1 reply
-
Hi @andtie, the It seems what you are looking for is the await store.send(.direct)
await store.skipReceivedActions()
XCTAssertEqual(store.state.count, 1) // ✅ Since this is not an issue with the library I am going to convert it to a discussion, and feel free to follow up with any questions. |
Beta Was this translation helpful? Give feedback.
Hi @andtie, the
finish
method onTestStore
is specifically for waiting for inflight effects to finish, and really is just a kludge due to the flakiness of async tests in Swift in general. In your test, you don't have any inflight effects. The synchronous effect that deliversindirect
was processed right away.It seems what you are looking for is the
skipReceivedActions
, which does accomplish what you want:Since this is not an issue with the library I am going to convert it to a discussion, and feel free to follow up with any questions.