Skip to content

Commit ffcbe63

Browse files
committed
Update demos to use failing environments (#650)
1 parent 35b19f5 commit ffcbe63

File tree

23 files changed

+369
-388
lines changed

23 files changed

+369
-388
lines changed

Examples/CaseStudies/SwiftUICaseStudies/00-Core.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -202,7 +202,7 @@ let rootReducer = Reducer<RootState, RootAction, RootEnvironment>.combine(
202202
.init(
203203
date: env.date,
204204
environment: .init(fetchNumber: env.fetchNumber),
205-
mainQueue: { env.mainQueue },
205+
mainQueue: env.mainQueue,
206206
uuid: env.uuid
207207
)
208208
}

Examples/CaseStudies/SwiftUICaseStudies/03-Effects-SystemEnvironment.swift

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ let multipleDependenciesReducer = Reducer<
4747
switch action {
4848
case .alertButtonTapped:
4949
return Effect(value: .alertDelayReceived)
50-
.delay(1, on: environment.mainQueue())
50+
.delay(1, on: environment.mainQueue)
5151

5252
case .alertDelayReceived:
5353
state.alert = .init(title: .init("Here's an alert after a delay!"))
@@ -158,7 +158,7 @@ struct MultipleDependenciesView_Previews: PreviewProvider {
158158
struct SystemEnvironment<Environment> {
159159
var date: () -> Date
160160
var environment: Environment
161-
var mainQueue: () -> DateScheduler
161+
var mainQueue: DateScheduler
162162
var uuid: () -> UUID
163163

164164
subscript<Dependency>(
@@ -176,7 +176,7 @@ struct SystemEnvironment<Environment> {
176176
Self(
177177
date: Date.init,
178178
environment: environment,
179-
mainQueue: { QueueScheduler.main },
179+
mainQueue: .main,
180180
uuid: UUID.init
181181
)
182182
}
@@ -195,17 +195,25 @@ struct SystemEnvironment<Environment> {
195195
}
196196

197197
#if DEBUG
198+
import XCTestDynamicOverlay
199+
198200
extension SystemEnvironment {
199-
static func mock(
200-
date: @escaping () -> Date = { fatalError("date dependency is unimplemented.") },
201+
static func failing(
202+
date: @escaping () -> Date = {
203+
XCTFail("date dependency is unimplemented.")
204+
return Date()
205+
},
201206
environment: Environment,
202-
mainQueue: @escaping () -> DateScheduler = { fatalError() },
203-
uuid: @escaping () -> UUID = { fatalError("UUID dependency is unimplemented.") }
207+
mainQueue: AnySchedulerOf<DispatchQueue> = .failing,
208+
uuid: @escaping () -> UUID = {
209+
XCTFail("UUID dependency is unimplemented.")
210+
return UUID()
211+
}
204212
) -> Self {
205213
Self(
206214
date: date,
207215
environment: environment,
208-
mainQueue: { mainQueue() },
216+
mainQueue: mainQueue,
209217
uuid: uuid
210218
)
211219
}

Examples/CaseStudies/SwiftUICaseStudiesTests/02-Effects-WebSocketTests.swift

Lines changed: 34 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -9,17 +9,18 @@ class WebSocketTests: XCTestCase {
99
let socketSubject = Signal<WebSocketClient.Action, Never>.pipe()
1010
let receiveSubject = Signal<WebSocketClient.Message, NSError>.pipe()
1111

12+
var webSocket = WebSocketClient.failing
13+
webSocket.open = { _, _, _ in socketSubject.eraseToEffect() }
14+
webSocket.receive = { _ in receiveSubject.eraseToEffect() }
15+
webSocket.send = { _, _ in Effect(value: nil) }
16+
webSocket.sendPing = { _ in .none }
17+
1218
let store = TestStore(
1319
initialState: .init(),
1420
reducer: webSocketReducer,
1521
environment: WebSocketEnvironment(
1622
mainQueue: ImmediateScheduler(),
17-
webSocket: .mock(
18-
open: { _, _, _ in socketSubject.output.producer },
19-
receive: { _ in receiveSubject.output.producer },
20-
send: { _, _ in Effect(value: nil) },
21-
sendPing: { _ in .none }
22-
)
23+
webSocket: webSocket
2324
)
2425
)
2526

@@ -57,17 +58,18 @@ class WebSocketTests: XCTestCase {
5758
let socketSubject = Signal<WebSocketClient.Action, Never>.pipe()
5859
let receiveSubject = Signal<WebSocketClient.Message, NSError>.pipe()
5960

61+
var webSocket = WebSocketClient.failing
62+
webSocket.open = { _, _, _ in socketSubject.eraseToEffect() }
63+
webSocket.receive = { _ in receiveSubject.eraseToEffect() }
64+
webSocket.send = { _, _ in Effect(value: NSError(domain: "", code: 1)) }
65+
webSocket.sendPing = { _ in .none }
66+
6067
let store = TestStore(
6168
initialState: .init(),
6269
reducer: webSocketReducer,
6370
environment: WebSocketEnvironment(
6471
mainQueue: ImmediateScheduler(),
65-
webSocket: .mock(
66-
open: { _, _, _ in socketSubject.output.producer },
67-
receive: { _ in receiveSubject.output.producer },
68-
send: { _, _ in Effect(value: NSError(domain: "", code: 1)) },
69-
sendPing: { _ in .none }
70-
)
72+
webSocket: webSocket
7173
)
7274
)
7375

@@ -101,19 +103,20 @@ class WebSocketTests: XCTestCase {
101103
let socketSubject = Signal<WebSocketClient.Action, Never>.pipe()
102104
let pingSubject = Signal<NSError?, Never>.pipe()
103105

104-
let scheduler = TestScheduler()
106+
var webSocket = WebSocketClient.failing
107+
webSocket.open = { _, _, _ in socketSubject.eraseToEffect() }
108+
webSocket.receive = { _ in .none }
109+
webSocket.sendPing = { _ in pingSubject.eraseToEffect() }
110+
111+
let scheduler = DispatchQueue.test
105112
let store = TestStore(
106113
initialState: .init(),
107114
reducer: webSocketReducer,
108115
environment: WebSocketEnvironment(
109116
mainQueue: scheduler,
110-
webSocket: .mock(
111-
open: { _, _, _ in socketSubject.output.producer },
112-
receive: { _ in .none },
113-
sendPing: { _ in pingSubject.output.producer }
117+
webSocket: webSocket
114118
)
115119
)
116-
)
117120

118121
store.send(.connectButtonTapped) {
119122
$0.connectivityState = .connecting
@@ -138,17 +141,18 @@ class WebSocketTests: XCTestCase {
138141
func testWebSocketConnectError() {
139142
let socketSubject = Signal<WebSocketClient.Action, Never>.pipe()
140143

144+
var webSocket = WebSocketClient.failing
145+
webSocket.cancel = { _, _, _ in .fireAndForget { socketSubject.send(completion: .finished) } }
146+
webSocket.open = { _, _, _ in socketSubject.eraseToEffect() }
147+
webSocket.receive = { _ in .none }
148+
webSocket.sendPing = { _ in .none }
149+
141150
let store = TestStore(
142151
initialState: .init(),
143152
reducer: webSocketReducer,
144153
environment: WebSocketEnvironment(
145154
mainQueue: ImmediateScheduler(),
146-
webSocket: .mock(
147-
cancel: { _, _, _ in .fireAndForget { socketSubject.input.sendCompleted() } },
148-
open: { _, _, _ in socketSubject.output.producer },
149-
receive: { _ in .none },
150-
sendPing: { _ in .none }
151-
)
155+
webSocket: webSocket
152156
)
153157
)
154158

@@ -164,25 +168,11 @@ class WebSocketTests: XCTestCase {
164168
}
165169

166170
extension WebSocketClient {
167-
static func mock(
168-
cancel: @escaping (AnyHashable, URLSessionWebSocketTask.CloseCode, Data?) -> Effect<
169-
Never, Never
170-
> = { _, _, _ in fatalError() },
171-
open: @escaping (AnyHashable, URL, [String]) -> Effect<Action, Never> = { _, _, _ in
172-
fatalError()
173-
},
174-
receive: @escaping (AnyHashable) -> Effect<Message, NSError> = { _ in fatalError() },
175-
send: @escaping (AnyHashable, URLSessionWebSocketTask.Message) -> Effect<NSError?, Never> = {
176-
_, _ in fatalError()
177-
},
178-
sendPing: @escaping (AnyHashable) -> Effect<NSError?, Never> = { _ in fatalError() }
179-
) -> Self {
180-
Self(
181-
cancel: cancel,
182-
open: open,
183-
receive: receive,
184-
send: send,
185-
sendPing: sendPing
171+
static let failing = Self(
172+
cancel: { _, _, _ in .failing("WebSocketClient.cancel") },
173+
open: { _, _, _ in .failing("WebSocketClient.open") },
174+
receive: { _ in .failing("WebSocketClient.receive") },
175+
send: { _, _ in .failing("WebSocketClient.send") },
176+
sendPing: { _ in .failing("WebSocketClient.sendPing") }
186177
)
187178
}
188-
}

Examples/CaseStudies/SwiftUICaseStudiesTests/04-HigherOrderReducers-ReusableOfflineDownloadsTests.swift

Lines changed: 32 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,9 @@ class ReusableComponentsDownloadComponentTests: XCTestCase {
1818
let scheduler = TestScheduler()
1919

2020
func testDownloadFlow() {
21+
var downloadClient = DownloadClient.failing
22+
downloadClient.download = { _, _ in self.downloadSubject.eraseToEffect() }
23+
2124
let store = TestStore(
2225
initialState: DownloadComponentState(
2326
id: 1,
@@ -26,9 +29,7 @@ class ReusableComponentsDownloadComponentTests: XCTestCase {
2629
),
2730
reducer: reducer,
2831
environment: DownloadComponentEnvironment(
29-
downloadClient: .mock(
30-
download: { _, _ in self.downloadSubject.output.producer }
31-
),
32+
downloadClient: downloadClient,
3233
mainQueue: self.scheduler
3334
)
3435
)
@@ -53,6 +54,9 @@ class ReusableComponentsDownloadComponentTests: XCTestCase {
5354
}
5455

5556
func testDownloadThrottling() {
57+
var downloadClient = DownloadClient.failing
58+
downloadClient.download = { _, _ in self.downloadSubject.eraseToEffect() }
59+
5660
let store = TestStore(
5761
initialState: DownloadComponentState(
5862
id: 1,
@@ -61,9 +65,7 @@ class ReusableComponentsDownloadComponentTests: XCTestCase {
6165
),
6266
reducer: reducer,
6367
environment: DownloadComponentEnvironment(
64-
downloadClient: .mock(
65-
download: { _, _ in self.downloadSubject.output.producer }
66-
),
68+
downloadClient: downloadClient,
6769
mainQueue: self.scheduler
6870
)
6971
)
@@ -92,6 +94,12 @@ class ReusableComponentsDownloadComponentTests: XCTestCase {
9294
}
9395

9496
func testCancelDownloadFlow() {
97+
var downloadClient = DownloadClient.failing
98+
downloadClient.cancel = { _ in
99+
.fireAndForget { self.downloadSubject.send(completion: .finished) }
100+
}
101+
downloadClient.download = { _, _ in self.downloadSubject.eraseToEffect() }
102+
95103
let store = TestStore(
96104
initialState: DownloadComponentState(
97105
id: 1,
@@ -100,10 +108,7 @@ class ReusableComponentsDownloadComponentTests: XCTestCase {
100108
),
101109
reducer: reducer,
102110
environment: DownloadComponentEnvironment(
103-
downloadClient: .mock(
104-
cancel: { _ in .fireAndForget { self.downloadSubject.input.sendCompleted() } },
105-
download: { _, _ in self.downloadSubject.output.producer }
106-
),
111+
downloadClient: downloadClient,
107112
mainQueue: self.scheduler
108113
)
109114
)
@@ -129,6 +134,12 @@ class ReusableComponentsDownloadComponentTests: XCTestCase {
129134
}
130135

131136
func testDownloadFinishesWhileTryingToCancel() {
137+
var downloadClient = DownloadClient.failing
138+
downloadClient.cancel = { _ in
139+
.fireAndForget { self.downloadSubject.send(completion: .finished) }
140+
}
141+
downloadClient.download = { _, _ in self.downloadSubject.eraseToEffect() }
142+
132143
let store = TestStore(
133144
initialState: DownloadComponentState(
134145
id: 1,
@@ -137,10 +148,7 @@ class ReusableComponentsDownloadComponentTests: XCTestCase {
137148
),
138149
reducer: reducer,
139150
environment: DownloadComponentEnvironment(
140-
downloadClient: .mock(
141-
cancel: { _ in .fireAndForget { self.downloadSubject.input.sendCompleted() } },
142-
download: { _, _ in self.downloadSubject.output.producer }
143-
),
151+
downloadClient: downloadClient,
144152
mainQueue: self.scheduler
145153
)
146154
)
@@ -168,6 +176,12 @@ class ReusableComponentsDownloadComponentTests: XCTestCase {
168176
}
169177

170178
func testDeleteDownloadFlow() {
179+
var downloadClient = DownloadClient.failing
180+
downloadClient.cancel = { _ in
181+
.fireAndForget { self.downloadSubject.send(completion: .finished) }
182+
}
183+
downloadClient.download = { _, _ in self.downloadSubject.eraseToEffect() }
184+
171185
let store = TestStore(
172186
initialState: DownloadComponentState(
173187
id: 1,
@@ -176,10 +190,7 @@ class ReusableComponentsDownloadComponentTests: XCTestCase {
176190
),
177191
reducer: reducer,
178192
environment: DownloadComponentEnvironment(
179-
downloadClient: .mock(
180-
cancel: { _ in .fireAndForget { self.downloadSubject.input.sendCompleted() } },
181-
download: { _, _ in self.downloadSubject.output.producer }
182-
),
193+
downloadClient: downloadClient,
183194
mainQueue: self.scheduler
184195
)
185196
)
@@ -200,13 +211,8 @@ class ReusableComponentsDownloadComponentTests: XCTestCase {
200211
}
201212

202213
extension DownloadClient {
203-
static func mock(
204-
cancel: @escaping (AnyHashable) -> Effect<Never, Never> = { _ in fatalError() },
205-
download: @escaping (AnyHashable, URL) -> Effect<Action, Error> = { _, _ in fatalError() }
206-
) -> Self {
207-
Self(
208-
cancel: cancel,
209-
download: download
214+
static let failing = Self(
215+
cancel: { _ in .failing("DownloadClient.cancel") },
216+
download: { _, _ in .failing("DownloadClient.download") }
210217
)
211218
}
212-
}

Examples/Search/Search/WeatherClient.swift

Lines changed: 4 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -67,17 +67,10 @@ extension WeatherClient {
6767
// MARK: - Mock API implementations
6868

6969
extension WeatherClient {
70-
static func mock(
71-
searchLocation: @escaping (String) -> Effect<[Location], Failure> = { _ in
72-
fatalError("Unmocked")
73-
},
74-
weather: @escaping (Int) -> Effect<LocationWeather, Failure> = { _ in fatalError("Unmocked") }
75-
) -> Self {
76-
Self(
77-
searchLocation: searchLocation,
78-
weather: weather
79-
)
80-
}
70+
static let failing = Self(
71+
searchLocation: { _ in .failing("WeatherClient.searchLocation") },
72+
weather: { _ in .failing("WeatherClient.weather") }
73+
)
8174
}
8275

8376
// MARK: - Private helpers

0 commit comments

Comments
 (0)