Files
swift-composable-architectu…/Tests/ComposableArchitectureTests/EffectRunTests.swift
Brandon Williams 2c93195c23 Prerelease 1.0 (#1929)
* Converted voice memos back to identified array

* update deps

* update docs for DismissEffect

* wip

* Add Sendable conformance to PresentationState (#2086)

* wip

* swift-format

* wip

* wip

* fix some warnings

* docs

* wip

* wip

* Catch some typos in Articles (#2088)

* wip

* wip

* wip

* wip

* wip

* wip

* wip

* wip

* docs

* wip

* wip

* docs

* wip

* wip

* wip

* wip

* docs

* docs

* wip

* wip

* wip

* wip

* wip

* wip

* wip

* Fix invalid states count for 3 optionals and typos (#2094)

* wip

* wip

* more dismisseffect docs

* fixed some references

* navigation doc corrections

* more nav docs

* fix cancellation tests in release mode

* wrap some tests in #if DEBUG since they are testing expected failures

* update UUIDs in tests to use shorter initializer

* fixed a todo

* wip

* fix merge errors

* wip

* fix

* wip

* wip

* fixing a bunch of todos

* get rid of rawvalue in StackElementID

* more todos

* NavLinkStore docs

* fix swift 5.6 stuff

* fix some standups tests

* fix

* clean up

* docs fix

* fixes

* wip

* 5.6 fix

* wip

* wip

* dont parallelize tests

* updated demo readmes

* wip

* Use ObservedObject instead of StateObject for alert/dialog modifiers.

* integration tests for bad dismissal behavior

* check for runtime warnings in every integration test

* wip

* wip

* wip

* fix

* wip

* wip

* wip

* wip

* wip

* wip

* Drop a bunch of Hashables.

* some nav bug fixes

* wip

* wip

* wip

* fix

* fix

* wip

* wip

* Simplify recording test.

* add concurrent async test

* fix

* wip

* Refact how detail dismisses itself.

* fix

* 5.6 fix

* wip

* wip

* wip

* wip

* Add TestStore.assert.

* Revert "Add TestStore.assert."

This reverts commit a892cccc66.

* add Ukrainian Readme.md (#2121)

* Add TestStore.assert. (#2123)

* Add TestStore.assert.

* wip

* Update Sources/ComposableArchitecture/TestStore.swift

Co-authored-by: Stephen Celis <stephen@stephencelis.com>

* Update Sources/ComposableArchitecture/Documentation.docc/Extensions/TestStore.md

Co-authored-by: Stephen Celis <stephen@stephencelis.com>

* fix tests

---------

Co-authored-by: Stephen Celis <stephen@stephencelis.com>

* Run swift-format

* push for store.finish and presentation

* wip

* move docs around

* wip

* wip

* wip

* wip

* wip

* wip

* wip

* wip

* wip

* wip

* wip

* wip

* wip

* wip

* Add case subscripts

* wip

* wip

* wip

* 5.7-only

* wip

* wip

* wip

* wip

* fix

* revert store.finish task cancellation

* wip

* wip

* wip

* wip

* wip

* wip

* wip

* wip

* wip

* wip

* wip

* wip

* wip

* wip

* wip

* wip

* wip

* wip

* wip

* wip

* add test for presentation scope

* wip

* wip

* wip

* wip

* wip

* cleanup

* wip

* wip

* wip

* wip

* wip

* wip

* wip

* wip

* wip

* wip

* wip

* wip

* Rename ReducerProtocol.swift to Reducer.swift (#2206)

* Hard-deprecate old SwitchStore initializers/overloads

* wip

* wip

* Resolve CaseStudies crash (#2258)

* wip

* wip

* wip

* wip

* wip

* wip

* wip

* wip

* Bump timeout for CI

* wip

* wip

---------

Co-authored-by: Jackson Utsch <jutechs@gmail.com>
Co-authored-by: Stephen Celis <stephen@stephencelis.com>
Co-authored-by: 유재호 <y73447jh@gmail.com>
Co-authored-by: Dmytro <barabashdmyto@gmail.com>
Co-authored-by: mbrandonw <mbrandonw@users.noreply.github.com>
2023-07-27 17:35:07 -07:00

172 lines
4.8 KiB
Swift

import Combine
import ComposableArchitecture
import XCTest
@MainActor
final class EffectRunTests: BaseTCATestCase {
func testRun() async {
struct State: Equatable {}
enum Action: Equatable { case tapped, response }
let store = TestStore(initialState: State()) {
Reduce<State, Action> { state, action in
switch action {
case .tapped:
return .run { send in await send(.response) }
case .response:
return .none
}
}
}
await store.send(.tapped)
await store.receive(.response)
}
func testRunCatch() async {
struct State: Equatable {}
enum Action: Equatable { case tapped, response }
let store = TestStore(initialState: State()) {
Reduce<State, Action> { state, action in
switch action {
case .tapped:
return .run { _ in
struct Failure: Error {}
throw Failure()
} catch: { _, send in
await send(.response)
}
case .response:
return .none
}
}
}
await store.send(.tapped)
await store.receive(.response)
}
#if DEBUG
func testRunUnhandledFailure() async {
var line: UInt!
XCTExpectFailure(nil, enabled: nil, strict: nil) {
$0.compactDescription == """
An "Effect.run" returned from "\(#fileID):\(line+1)" threw an unhandled error. …
EffectRunTests.Failure()
All non-cancellation errors must be explicitly handled via the "catch" parameter on \
"Effect.run", or via a "do" block.
"""
}
struct State: Equatable {}
enum Action: Equatable { case tapped, response }
let store = TestStore(initialState: State()) {
Reduce<State, Action> { state, action in
switch action {
case .tapped:
line = #line
return .run { send in
struct Failure: Error {}
throw Failure()
}
case .response:
return .none
}
}
}
// NB: We wait a long time here because XCTest failures take a long time to generate
await store.send(.tapped).finish(timeout: 5 * NSEC_PER_SEC)
}
#endif
func testRunCancellation() async {
enum CancelID { case response }
struct State: Equatable {}
enum Action: Equatable { case tapped, response }
let store = TestStore(initialState: State()) {
Reduce<State, Action> { state, action in
switch action {
case .tapped:
return .run { send in
Task.cancel(id: CancelID.response)
try Task.checkCancellation()
await send(.response)
}
.cancellable(id: CancelID.response)
case .response:
return .none
}
}
}
await store.send(.tapped).finish()
}
func testRunCancellationCatch() async {
enum CancelID { case responseA }
struct State: Equatable {}
enum Action: Equatable { case tapped, responseA, responseB }
let store = TestStore(initialState: State()) {
Reduce<State, Action> { state, action in
switch action {
case .tapped:
return .run { send in
Task.cancel(id: CancelID.responseA)
try Task.checkCancellation()
await send(.responseA)
} catch: { _, send in
await send(.responseB)
}
.cancellable(id: CancelID.responseA)
case .responseA, .responseB:
return .none
}
}
}
await store.send(.tapped).finish()
}
#if DEBUG
func testRunEscapeFailure() async {
XCTExpectFailure {
$0.compactDescription == """
An action was sent from a completed effect:
Action:
EffectRunTests.Action.response
Effect returned from:
EffectRunTests.Action.tap
Avoid sending actions using the 'send' argument from 'Effect.run' after the effect has \
completed. This can happen if you escape the 'send' argument in an unstructured context.
To fix this, make sure that your 'run' closure does not return until you're done \
calling 'send'.
"""
}
enum Action { case tap, response }
let queue = DispatchQueue.test
let store = Store(initialState: 0) {
Reduce<Int, Action> { _, action in
switch action {
case .tap:
return .run { send in
Task(priority: .userInitiated) {
try await queue.sleep(for: .seconds(1))
await send(.response)
}
}
case .response:
return .none
}
}
}
let viewStore = ViewStore(store, observe: { $0 })
await viewStore.send(.tap).finish()
await queue.advance(by: .seconds(1))
}
#endif
}