Skip to content

Commit 7145a81

Browse files
committed
Use proportional diffing for TestStore failures (#742)
* Use proportional diffing for TestStore failures * wip * wip
1 parent 22947f3 commit 7145a81

File tree

2 files changed

+93
-93
lines changed

2 files changed

+93
-93
lines changed

Sources/ComposableArchitecture/TestSupport/TestStore.swift

Lines changed: 88 additions & 88 deletions
Original file line numberDiff line numberDiff line change
@@ -38,45 +38,45 @@
3838
///
3939
/// For example, given a simple counter reducer:
4040
///
41-
/// ```swift
42-
/// struct CounterState {
43-
/// var count = 0
44-
/// }
45-
///
46-
/// enum CounterAction: Equatable {
47-
/// case decrementButtonTapped
48-
/// case incrementButtonTapped
49-
/// }
50-
///
51-
/// let counterReducer = Reducer<CounterState, CounterAction, Void> { state, action, _ in
52-
/// switch action {
53-
/// case .decrementButtonTapped:
54-
/// state.count -= 1
55-
/// return .none
56-
///
57-
/// case .incrementButtonTapped:
58-
/// state.count += 1
59-
/// return .none
60-
/// }
61-
/// }
62-
/// ```
41+
/// ```swift
42+
/// struct CounterState {
43+
/// var count = 0
44+
/// }
45+
///
46+
/// enum CounterAction: Equatable {
47+
/// case decrementButtonTapped
48+
/// case incrementButtonTapped
49+
/// }
50+
///
51+
/// let counterReducer = Reducer<CounterState, CounterAction, Void> { state, action, _ in
52+
/// switch action {
53+
/// case .decrementButtonTapped:
54+
/// state.count -= 1
55+
/// return .none
56+
///
57+
/// case .incrementButtonTapped:
58+
/// state.count += 1
59+
/// return .none
60+
/// }
61+
/// }
62+
/// ```
6363
///
6464
/// One can assert against its behavior over time:
6565
///
66-
/// ```swift
67-
/// class CounterTests: XCTestCase {
68-
/// func testCounter() {
69-
/// let store = TestStore(
70-
/// initialState: .init(count: 0), // GIVEN counter state of 0
71-
/// reducer: counterReducer,
72-
/// environment: ()
73-
/// )
74-
/// store.send(.incrementButtonTapped) { // WHEN the increment button is tapped
75-
/// $0.count = 1 // THEN the count should be 1
76-
/// }
77-
/// }
66+
/// ```swift
67+
/// class CounterTests: XCTestCase {
68+
/// func testCounter() {
69+
/// let store = TestStore(
70+
/// initialState: .init(count: 0), // GIVEN counter state of 0
71+
/// reducer: counterReducer,
72+
/// environment: ()
73+
/// )
74+
/// store.send(.incrementButtonTapped) { // WHEN the increment button is tapped
75+
/// $0.count = 1 // THEN the count should be 1
7876
/// }
79-
/// ```
77+
/// }
78+
/// }
79+
/// ```
8080
///
8181
/// Note that in the trailing closure of `.send(.incrementButtonTapped)` we are given a single
8282
/// mutable value of the state before the action was sent, and it is our job to mutate the value
@@ -86,81 +86,81 @@
8686
/// ``Effect/debounce(id:for:scheduler:options:)`` operator to wait for the user to stop typing
8787
/// before making a network request:
8888
///
89-
/// ```swift
90-
/// struct SearchState: Equatable {
91-
/// var query = ""
92-
/// var results: [String] = []
93-
/// }
89+
/// ```swift
90+
/// struct SearchState: Equatable {
91+
/// var query = ""
92+
/// var results: [String] = []
93+
/// }
9494
///
95-
/// enum SearchAction: Equatable {
96-
/// case queryChanged(String)
97-
/// case response([String])
98-
/// }
95+
/// enum SearchAction: Equatable {
96+
/// case queryChanged(String)
97+
/// case response([String])
98+
/// }
9999
///
100-
/// struct SearchEnvironment {
100+
/// struct SearchEnvironment {
101101
/// var mainQueue: DateScheduler
102-
/// var request: (String) -> Effect<[String], Never>
103-
/// }
102+
/// var request: (String) -> Effect<[String], Never>
103+
/// }
104104
///
105-
/// let searchReducer = Reducer<SearchState, SearchAction, SearchEnvironment> {
106-
/// state, action, environment in
105+
/// let searchReducer = Reducer<SearchState, SearchAction, SearchEnvironment> {
106+
/// state, action, environment in
107107
///
108-
/// struct SearchId: Hashable {}
108+
/// struct SearchId: Hashable {}
109109
///
110-
/// switch action {
111-
/// case let .queryChanged(query):
112-
/// state.query = query
113-
/// return environment.request(self.query)
110+
/// switch action {
111+
/// case let .queryChanged(query):
112+
/// state.query = query
113+
/// return environment.request(self.query)
114114
/// .debounce(id: SearchId(), interval: 0.5, scheduler: environment.mainQueue)
115115
///
116-
/// case let .response(results):
117-
/// state.results = results
118-
/// return .none
119-
/// }
116+
/// case let .response(results):
117+
/// state.results = results
118+
/// return .none
120119
/// }
120+
/// }
121121
/// ```
122122
///
123123
/// It can be fully tested by controlling the environment's scheduler and effect:
124124
///
125-
/// ```swift
126-
/// // Create a test dispatch scheduler to control the timing of effects
125+
/// ```swift
126+
/// // Create a test dispatch scheduler to control the timing of effects
127127
/// let scheduler = TestScheduler()
128128
///
129-
/// let store = TestStore(
130-
/// initialState: SearchState(),
131-
/// reducer: searchReducer,
132-
/// environment: SearchEnvironment(
129+
/// let store = TestStore(
130+
/// initialState: SearchState(),
131+
/// reducer: searchReducer,
132+
/// environment: SearchEnvironment(
133133
/// mainQueue: scheduler,
134-
/// // Simulate a search response with one item
135-
/// request: { _ in Effect(value: ["Composable Architecture"]) }
136-
/// )
137-
/// )
138-
///
139-
/// // Change the query
140-
/// store.send(.searchFieldChanged("c") {
141-
/// // Assert that state updates accordingly
142-
/// $0.query = "c"
143-
/// }
144-
///
145-
/// // Advance the scheduler by a period shorter than the debounce
134+
/// // Simulate a search response with one item
135+
/// request: { _ in Effect(value: ["Composable Architecture"]) }
136+
/// )
137+
/// )
138+
///
139+
/// // Change the query
140+
/// store.send(.searchFieldChanged("c") {
141+
/// // Assert that state updates accordingly
142+
/// $0.query = "c"
143+
/// }
144+
///
145+
/// // Advance the scheduler by a period shorter than the debounce
146146
/// scheduler.advance(by: .millseconds(250))
147147
///
148-
/// // Change the query again
149-
/// store.send(.searchFieldChanged("co") {
150-
/// $0.query = "co"
151-
/// }
148+
/// // Change the query again
149+
/// store.send(.searchFieldChanged("co") {
150+
/// $0.query = "co"
151+
/// }
152152
///
153-
/// // Advance the scheduler by a period shorter than the debounce
153+
/// // Advance the scheduler by a period shorter than the debounce
154154
/// scheduler.advance(by: .millseconds(250))
155-
/// // Advance the scheduler to the debounce
155+
/// // Advance the scheduler to the debounce
156156
/// scheduler.advance(by: .millseconds(250))
157157
///
158-
/// // Assert that the expected response is received
159-
/// store.receive(.response(["Composable Architecture"])) {
160-
/// // Assert that state updates accordingly
161-
/// $0.results = ["Composable Architecture"]
162-
/// }
163-
/// ```
158+
/// // Assert that the expected response is received
159+
/// store.receive(.response(["Composable Architecture"])) {
160+
/// // Assert that state updates accordingly
161+
/// $0.results = ["Composable Architecture"]
162+
/// }
163+
/// ```
164164
///
165165
/// This test is proving that the debounced network requests are correctly canceled when we do not
166166
/// wait longer than the 0.5 seconds, because if it wasn't and it delivered an action when we did

Tests/ComposableArchitectureTests/EffectTests.swift

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -180,7 +180,7 @@ final class EffectTests: XCTestCase {
180180
return 42
181181
}
182182
.startWithValues { result = $0 }
183-
self.wait(for: [expectation], timeout: 0)
183+
self.wait(for: [expectation], timeout: 1)
184184
XCTAssertEqual(result, 42)
185185
}
186186

@@ -199,12 +199,12 @@ final class EffectTests: XCTestCase {
199199
result = error
200200
},
201201
value: { _ in
202-
XCTFail()
203-
}
202+
XCTFail()
203+
}
204204
).logEvents()
205205
.start()
206206

207-
self.wait(for: [expectation], timeout: 0)
207+
self.wait(for: [expectation], timeout: 0)
208208
XCTAssertNotNil(result)
209209
disposable.dispose()
210210
}
@@ -231,7 +231,7 @@ final class EffectTests: XCTestCase {
231231
value: { _ in XCTFail() }
232232
).start()
233233

234-
self.wait(for: [expectation], timeout: 0.2)
234+
self.wait(for: [expectation], timeout: 1)
235235
}
236236
#endif
237237
}

0 commit comments

Comments
 (0)