1
1
import Combine
2
2
import ComposableArchitecture
3
+ @_spi ( Concurrency) import Dependencies
3
4
import XCTest
4
5
5
6
@MainActor
@@ -43,34 +44,36 @@ final class EffectRunTests: BaseTCATestCase {
43
44
44
45
#if DEBUG
45
46
func testRunUnhandledFailure( ) async {
46
- var line : UInt !
47
- XCTExpectFailure ( nil , enabled: nil , strict: nil ) {
48
- $0. compactDescription == """
47
+ await withMainSerialExecutor {
48
+ var line : UInt !
49
+ XCTExpectFailure ( nil , enabled: nil , strict: nil ) {
50
+ $0. compactDescription == """
49
51
An " EffectTask.run " returned from " \( #fileID) : \( line+ 1 ) " threw an unhandled error. …
50
52
51
53
EffectRunTests.Failure()
52
54
53
55
All non-cancellation errors must be explicitly handled via the " catch " parameter on \
54
56
" EffectTask.run " , or via a " do " block.
55
57
"""
56
- }
57
- struct State : Equatable { }
58
- enum Action : Equatable { case tapped, response }
59
- let reducer = Reduce < State , Action > { state, action in
60
- switch action {
61
- case . tapped:
62
- line = #line
63
- return . run { send in
64
- struct Failure : Error { }
65
- throw Failure ( )
58
+ }
59
+ struct State : Equatable { }
60
+ enum Action : Equatable { case tapped, response }
61
+ let reducer = Reduce < State , Action > { state, action in
62
+ switch action {
63
+ case . tapped:
64
+ line = #line
65
+ return . run { send in
66
+ struct Failure : Error { }
67
+ throw Failure ( )
68
+ }
69
+ case . response:
70
+ return . none
66
71
}
67
- case . response:
68
- return . none
69
72
}
73
+ let store = TestStore ( initialState: State ( ) , reducer: reducer)
74
+ // NB: We wait a long time here because XCTest failures take a long time to generate
75
+ await store. send ( . tapped) . finish ( timeout: 5 * NSEC_PER_SEC)
70
76
}
71
- let store = TestStore ( initialState: State ( ) , reducer: reducer)
72
- // NB: We wait a long time here because XCTest failures take a long time to generate
73
- await store. send ( . tapped) . finish ( timeout: 5 * NSEC_PER_SEC)
74
77
}
75
78
#endif
76
79
@@ -120,8 +123,9 @@ final class EffectRunTests: BaseTCATestCase {
120
123
121
124
#if DEBUG
122
125
func testRunEscapeFailure( ) async throws {
123
- XCTExpectFailure {
124
- $0. compactDescription == """
126
+ try await withMainSerialExecutor {
127
+ XCTExpectFailure {
128
+ $0. compactDescription == """
125
129
An action was sent from a completed effect:
126
130
127
131
Action:
@@ -136,32 +140,33 @@ final class EffectRunTests: BaseTCATestCase {
136
140
To fix this, make sure that your 'run' closure does not return until you're done calling \
137
141
'send'.
138
142
"""
139
- }
143
+ }
140
144
141
- enum Action { case tap, response }
145
+ enum Action { case tap, response }
142
146
143
- let queue = DispatchQueue . test
147
+ let queue = DispatchQueue . test
144
148
145
- let store = Store (
146
- initialState: 0 ,
147
- reducer: Reduce< Int, Action> { _, action in
148
- switch action {
149
- case . tap:
150
- return . run { send in
151
- Task ( priority: . userInitiated) {
152
- try await queue. sleep ( for: . seconds( 1 ) )
153
- await send ( . response)
149
+ let store = Store (
150
+ initialState: 0 ,
151
+ reducer: Reduce< Int, Action> { _, action in
152
+ switch action {
153
+ case . tap:
154
+ return . run { send in
155
+ Task ( priority: . userInitiated) {
156
+ try await queue. sleep ( for: . seconds( 1 ) )
157
+ await send ( . response)
158
+ }
154
159
}
160
+ case . response:
161
+ return . none
155
162
}
156
- case . response:
157
- return . none
158
163
}
159
- }
160
- )
164
+ )
161
165
162
- let viewStore = ViewStore ( store, observe: { $0 } )
163
- await viewStore. send ( . tap) . finish ( )
164
- await queue. advance ( by: . seconds( 1 ) )
166
+ let viewStore = ViewStore ( store, observe: { $0 } )
167
+ await viewStore. send ( . tap) . finish ( )
168
+ await queue. advance ( by: . seconds( 1 ) )
169
+ }
165
170
}
166
171
167
172
func testRunEscapeFailurePublisher( ) async throws {
0 commit comments