Files
swift-composable-architectu…/Tests/ComposableArchitectureTests/TestStoreFailureTests.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

278 lines
7.9 KiB
Swift
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#if DEBUG
import ComposableArchitecture
import XCTest
@MainActor
final class TestStoreFailureTests: BaseTCATestCase {
func testNoStateChangeFailure() async {
enum Action { case first, second }
let store = TestStore(initialState: 0) {
Reduce<Int, Action> { state, action in
switch action {
case .first: return .send(.second)
case .second: return .none
}
}
}
XCTExpectFailure {
$0.compactDescription == """
Expected state to change, but no change occurred.
The trailing closure made no observable modifications to state. If no change to state is \
expected, omit the trailing closure.
"""
}
await store.send(.first) { _ = $0 }
XCTExpectFailure {
$0.compactDescription == """
Expected state to change, but no change occurred.
The trailing closure made no observable modifications to state. If no change to state is \
expected, omit the trailing closure.
"""
}
await store.receive(.second) { _ = $0 }
}
func testStateChangeFailure() async {
struct State: Equatable { var count = 0 }
let store = TestStore(initialState: State()) {
Reduce<State, Void> { state, action in
state.count += 1
return .none
}
}
XCTExpectFailure {
$0.compactDescription == """
A state change does not match expectation: …
TestStoreFailureTests.State(count: 0)
+ TestStoreFailureTests.State(count: 1)
(Expected: , Actual: +)
"""
}
await store.send(()) { $0.count = 0 }
}
func testUnexpectedStateChangeOnSendFailure() async {
struct State: Equatable { var count = 0 }
let store = TestStore(initialState: State()) {
Reduce<State, Void> { state, action in
state.count += 1
return .none
}
}
XCTExpectFailure {
$0.compactDescription == """
State was not expected to change, but a change occurred: …
TestStoreFailureTests.State(count: 0)
+ TestStoreFailureTests.State(count: 1)
(Expected: , Actual: +)
"""
}
await store.send(())
}
func testUnexpectedStateChangeOnReceiveFailure() async {
struct State: Equatable { var count = 0 }
enum Action { case first, second }
let store = TestStore(initialState: State()) {
Reduce<State, Action> { state, action in
switch action {
case .first: return .send(.second)
case .second:
state.count += 1
return .none
}
}
}
await store.send(.first)
XCTExpectFailure {
$0.compactDescription == """
State was not expected to change, but a change occurred: …
TestStoreFailureTests.State(count: 0)
+ TestStoreFailureTests.State(count: 1)
(Expected: , Actual: +)
"""
}
await store.receive(.second)
}
func testReceivedActionAfterDeinit() async {
enum Action { case first, second }
let store = TestStore(initialState: 0) {
Reduce<Int, Action> { state, action in
switch action {
case .first: return .send(.second)
case .second: return .none
}
}
}
XCTExpectFailure {
$0.compactDescription == """
The store received 1 unexpected action after this one: …
Unhandled actions:
• .second
"""
}
await store.send(.first)
}
func testEffectInFlightAfterDeinit() async {
let store = TestStore(initialState: 0) {
Reduce<Int, Void> { state, action in
.run { _ in try await Task.never() }
}
}
XCTExpectFailure {
$0.compactDescription == """
An effect returned for this action is still running. It must complete before the end of \
the test. …
To fix, inspect any effects the reducer returns for this action and ensure that all of \
them complete by the end of the test. There are a few reasons why an effect may not have \
completed:
• If using async/await in your effect, it may need a little bit of time to properly \
finish. To fix you can simply perform "await store.finish()" at the end of your test.
• If an effect uses a clock/scheduler (via "receive(on:)", "delay", "debounce", etc.), \
make sure that you wait enough time for it to perform the effect. If you are using a \
test clock/scheduler, advance it so that the effects may complete, or consider using an \
immediate clock/scheduler to immediately perform the effect instead.
• If you are returning a long-living effect (timers, notifications, subjects, etc.), \
then make sure those effects are torn down by marking the effect ".cancellable" and \
returning a corresponding cancellation effect ("Effect.cancel") from another action, or, \
if your effect is driven by a Combine subject, send it a completion.
"""
}
await store.send(())
}
func testSendActionBeforeReceivingFailure() async {
enum Action { case first, second }
let store = TestStore(initialState: 0) {
Reduce<Int, Action> { state, action in
switch action {
case .first: return .send(.second)
case .second: return .none
}
}
}
await store.send(.first)
XCTExpectFailure {
$0.compactDescription == """
Must handle 1 received action before sending an action: …
Unhandled actions: [
[0]: .second
]
"""
}
await store.send(.first)
await store.receive(.second)
await store.receive(.second)
}
func testReceiveNonExistentActionFailure() async {
enum Action { case action }
let store = TestStore(initialState: 0) {
Reduce<Int, Action> { _, _ in .none }
}
XCTExpectFailure {
$0.compactDescription == """
Expected to receive the following action, but didn't: …
TestStoreFailureTests.Action.action
"""
}
await store.receive(.action)
}
func testReceiveUnexpectedActionFailure() async {
enum Action { case first, second }
let store = TestStore(initialState: 0) {
Reduce<Int, Action> { state, action in
switch action {
case .first:
return .send(.second)
case .second:
state += 1
return .none
}
}
}
await store.send(.first)
XCTExpectFailure {
$0.compactDescription == """
Received unexpected action: …
TestStoreFailureTests.Action.first
+ TestStoreFailureTests.Action.second
(Expected: , Received: +)
"""
}
await store.receive(.first)
}
func testModifyClosureThrowsErrorFailure() async {
let store = TestStore(initialState: 0) {
Reduce<Int, Void> { _, _ in .none }
}
XCTExpectFailure {
$0.compactDescription == "Threw error: SomeError()"
}
await store.send(()) { _ in
struct SomeError: Error {}
throw SomeError()
}
}
func testExpectedStateEqualityMustModify() async {
let store = TestStore(initialState: 0) {
Reduce<Int, Bool> { state, action in
switch action {
case true: return .send(false)
case false: return .none
}
}
}
await store.send(true)
await store.receive(false)
XCTExpectFailure()
await store.send(true) {
$0 = 0
}
XCTExpectFailure()
await store.receive(false) {
$0 = 0
}
}
}
#endif