mirror of
https://github.com/pointfreeco/swift-composable-architecture.git
synced 2025-12-24 12:14:25 +01:00
* 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>
159 lines
4.1 KiB
Swift
159 lines
4.1 KiB
Swift
import Combine
|
|
import CombineSchedulers
|
|
import ComposableArchitecture
|
|
import XCTest
|
|
|
|
@MainActor
|
|
final class ComposableArchitectureTests: BaseTCATestCase {
|
|
var cancellables: Set<AnyCancellable> = []
|
|
|
|
func testScheduling() async {
|
|
struct Counter: Reducer {
|
|
typealias State = Int
|
|
enum Action: Equatable {
|
|
case incrAndSquareLater
|
|
case incrNow
|
|
case squareNow
|
|
}
|
|
@Dependency(\.mainQueue) var mainQueue
|
|
func reduce(into state: inout State, action: Action) -> Effect<Action> {
|
|
switch action {
|
|
case .incrAndSquareLater:
|
|
return .run { send in
|
|
await withThrowingTaskGroup(of: Void.self) { group in
|
|
group.addTask {
|
|
try await self.mainQueue.sleep(for: .seconds(2))
|
|
await send(.incrNow)
|
|
}
|
|
group.addTask {
|
|
try await self.mainQueue.sleep(for: .seconds(1))
|
|
await send(.squareNow)
|
|
}
|
|
group.addTask {
|
|
try await self.mainQueue.sleep(for: .seconds(2))
|
|
await send(.squareNow)
|
|
}
|
|
}
|
|
}
|
|
case .incrNow:
|
|
state += 1
|
|
return .none
|
|
case .squareNow:
|
|
state *= state
|
|
return .none
|
|
}
|
|
}
|
|
}
|
|
|
|
let mainQueue = DispatchQueue.test
|
|
|
|
let store = TestStore(initialState: 2) {
|
|
Counter()
|
|
} withDependencies: {
|
|
$0.mainQueue = mainQueue.eraseToAnyScheduler()
|
|
}
|
|
|
|
await store.send(.incrAndSquareLater)
|
|
await mainQueue.advance(by: 1)
|
|
await store.receive(.squareNow) { $0 = 4 }
|
|
await mainQueue.advance(by: 1)
|
|
await store.receive(.incrNow) { $0 = 5 }
|
|
await store.receive(.squareNow) { $0 = 25 }
|
|
|
|
await store.send(.incrAndSquareLater)
|
|
await mainQueue.advance(by: 2)
|
|
await store.receive(.squareNow) { $0 = 625 }
|
|
await store.receive(.incrNow) { $0 = 626 }
|
|
await store.receive(.squareNow) { $0 = 391876 }
|
|
}
|
|
|
|
func testSimultaneousWorkOrdering() {
|
|
let mainQueue = DispatchQueue.test
|
|
|
|
var values: [Int] = []
|
|
mainQueue.schedule(after: mainQueue.now, interval: 1) { values.append(1) }
|
|
.store(in: &self.cancellables)
|
|
mainQueue.schedule(after: mainQueue.now, interval: 2) { values.append(42) }
|
|
.store(in: &self.cancellables)
|
|
|
|
XCTAssertEqual(values, [])
|
|
mainQueue.advance()
|
|
XCTAssertEqual(values, [1, 42])
|
|
mainQueue.advance(by: 2)
|
|
XCTAssertEqual(values, [1, 42, 1, 1, 42])
|
|
}
|
|
|
|
func testLongLivingEffects() async {
|
|
enum Action { case end, incr, start }
|
|
|
|
let effect = AsyncStream.makeStream(of: Void.self)
|
|
|
|
let store = TestStore(initialState: 0) {
|
|
Reduce<Int, Action> { state, action in
|
|
switch action {
|
|
case .end:
|
|
return .run { _ in
|
|
effect.continuation.finish()
|
|
}
|
|
case .incr:
|
|
state += 1
|
|
return .none
|
|
case .start:
|
|
return .run { send in
|
|
for await _ in effect.stream {
|
|
await send(.incr)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
await store.send(.start)
|
|
await store.send(.incr) { $0 = 1 }
|
|
effect.continuation.yield()
|
|
await store.receive(.incr) { $0 = 2 }
|
|
await store.send(.end)
|
|
}
|
|
|
|
func testCancellation() async {
|
|
let mainQueue = DispatchQueue.test
|
|
|
|
enum Action: Equatable {
|
|
case cancel
|
|
case incr
|
|
case response(Int)
|
|
}
|
|
|
|
let store = TestStore(initialState: 0) {
|
|
Reduce<Int, Action> { state, action in
|
|
enum CancelID { case sleep }
|
|
|
|
switch action {
|
|
case .cancel:
|
|
return .cancel(id: CancelID.sleep)
|
|
|
|
case .incr:
|
|
state += 1
|
|
return .run { [state] send in
|
|
try await mainQueue.sleep(for: .seconds(1))
|
|
await send(.response(state * state))
|
|
}
|
|
.cancellable(id: CancelID.sleep)
|
|
|
|
case let .response(value):
|
|
state = value
|
|
return .none
|
|
}
|
|
}
|
|
}
|
|
|
|
await store.send(.incr) { $0 = 1 }
|
|
await mainQueue.advance(by: .seconds(1))
|
|
await store.receive(.response(1))
|
|
|
|
await store.send(.incr) { $0 = 2 }
|
|
await store.send(.cancel)
|
|
await store.finish()
|
|
}
|
|
}
|