|
168 | 168 | /// not expect it would cause a test failure. |
169 | 169 | /// |
170 | 170 | public final class TestStore<State, LocalState, Action, LocalAction, Environment> { |
| 171 | + /// The current environment. |
| 172 | + /// |
| 173 | + /// The environment can be modified throughout a test store's lifecycle in order to influence |
| 174 | + /// how it produces effects. |
171 | 175 | public var environment: Environment |
172 | 176 |
|
| 177 | + /// The current state. |
| 178 | + /// |
| 179 | + /// When read from a trailing closure assertion in ``send`` or ``receive``, it will equal the |
| 180 | + /// `inout` state passed to the closure. |
| 181 | + public private(set) var state: State |
| 182 | + |
173 | 183 | private let file: StaticString |
174 | 184 | private let fromLocalAction: (LocalAction) -> Action |
175 | 185 | private var line: UInt |
176 | 186 | private var inFlightEffects: Set<LongLivingEffect> = [] |
177 | 187 | var receivedActions: [(action: Action, state: State)] = [] |
178 | 188 | private let reducer: Reducer<State, Action, Environment> |
179 | | - public private(set) var state: State |
180 | 189 | private var store: Store<State, TestAction>! |
181 | 190 | private let toLocalState: (State) -> LocalState |
182 | 191 |
|
|
335 | 344 | } |
336 | 345 |
|
337 | 346 | extension TestStore where LocalState: Equatable { |
| 347 | + /// Sends an action to the store and asserts when state changes. |
| 348 | + /// |
| 349 | + /// - Parameters: |
| 350 | + /// - action: An action. |
| 351 | + /// - updateExpectingResult: A closure that asserts state changed by sending the action to the |
| 352 | + /// store. The mutable state sent to this closure must be modified to match the state of the |
| 353 | + /// store after processing the given action. Do not provide a closure if no change is |
| 354 | + /// expected. |
338 | 355 | public func send( |
339 | 356 | _ action: LocalAction, |
| 357 | + _ updateExpectingResult: ((inout LocalState) throws -> Void)? = nil, |
340 | 358 | file: StaticString = #file, |
341 | | - line: UInt = #line, |
342 | | - _ update: ((inout LocalState) throws -> Void)? = nil |
| 359 | + line: UInt = #line |
343 | 360 | ) { |
344 | 361 | if !self.receivedActions.isEmpty { |
345 | 362 | var actions = "" |
|
364 | 381 |
|
365 | 382 | try self.expectedStateShouldChange( |
366 | 383 | expected: &expectedState, |
367 | | - update: update, |
| 384 | + modify: updateExpectingResult, |
368 | 385 | file: file, |
369 | 386 | line: line |
370 | 387 | ) |
|
384 | 401 |
|
385 | 402 | private func expectedStateShouldChange( |
386 | 403 | expected: inout LocalState, |
387 | | - update: ((inout LocalState) throws -> Void)? = nil, |
| 404 | + modify: ((inout LocalState) throws -> Void)? = nil, |
388 | 405 | file: StaticString, |
389 | 406 | line: UInt |
390 | 407 | ) throws { |
391 | | - guard let update = update else { return } |
| 408 | + guard let modify = modify else { return } |
392 | 409 | let current = expected |
393 | | - try update(&expected) |
| 410 | + try modify(&expected) |
394 | 411 | if expected == current { |
395 | 412 | XCTFail( |
396 | 413 | """ |
397 | | - Expected to modify the expected state, but no change occurred. |
| 414 | + Expected state to change, but no change occurred. |
398 | 415 |
|
399 | | - Ensure that the state was modified or remove the closure to assert no change. |
| 416 | + The trailing closure made no observable modifications to state. If no change to state is \ |
| 417 | + expected, omit the trailing closure. |
400 | 418 | """, |
401 | 419 | file: file, line: line |
402 | 420 | ) |
|
435 | 453 | } |
436 | 454 |
|
437 | 455 | extension TestStore where LocalState: Equatable, Action: Equatable { |
| 456 | + /// Asserts an action was received from an effect and asserts when state changes. |
| 457 | + /// |
| 458 | + /// - Parameters: |
| 459 | + /// - expectedAction: An action expected from an effect. |
| 460 | + /// - updateExpectingResult: A closure that asserts state changed by sending the action to the |
| 461 | + /// store. The mutable state sent to this closure must be modified to match the state of the |
| 462 | + /// store after processing the given action. Do not provide a closure if no change is |
| 463 | + /// expected. |
438 | 464 | public func receive( |
439 | 465 | _ expectedAction: Action, |
| 466 | + _ updateExpectingResult: ((inout LocalState) throws -> Void)? = nil, |
440 | 467 | file: StaticString = #file, |
441 | | - line: UInt = #line, |
442 | | - _ update: ((inout LocalState) throws -> Void)? = nil |
| 468 | + line: UInt = #line |
443 | 469 | ) { |
444 | 470 | guard !self.receivedActions.isEmpty else { |
445 | 471 | XCTFail( |
|
476 | 502 | do { |
477 | 503 | try self.expectedStateShouldChange( |
478 | 504 | expected: &expectedState, |
479 | | - update: update, |
| 505 | + modify: updateExpectingResult, |
480 | 506 | file: file, |
481 | 507 | line: line |
482 | 508 | ) |
|
0 commit comments