Skip to content
Snippets Groups Projects
Commit 6d8016da authored by Dariusz Rybicki's avatar Dariusz Rybicki
Browse files

Migrate ContactLookupFeature to ReducerProtocol

parent 461c4734
No related branches found
No related tags found
2 merge requests!126Migrate example app to ComposableArchitecture's ReducerProtocol,!102Release 1.0.0
import ComposableArchitecture
import Foundation
import XCTestDynamicOverlay
import XXClient
import XXMessengerClient
public struct ContactLookupComponent: ReducerProtocol {
public struct State: Equatable {
public init(
id: Data,
isLookingUp: Bool = false,
failure: String? = nil
) {
self.id = id
self.isLookingUp = isLookingUp
self.failure = failure
}
public var id: Data
public var isLookingUp: Bool
public var failure: String?
}
public enum Action: Equatable {
case lookupTapped
case didLookup(XXClient.Contact)
case didFail(NSError)
}
@Dependency(\.appDependencies.messenger) var messenger
@Dependency(\.appDependencies.mainQueue) var mainQueue
@Dependency(\.appDependencies.bgQueue) var bgQueue
public func reduce(into state: inout State, action: Action) -> EffectTask<Action> {
switch action {
case .lookupTapped:
state.isLookingUp = true
state.failure = nil
return Effect.result { [state] in
do {
let contact = try messenger.lookupContact(id: state.id)
return .success(.didLookup(contact))
} catch {
return .success(.didFail(error as NSError))
}
}
.subscribe(on: bgQueue)
.receive(on: mainQueue)
.eraseToEffect()
case .didLookup(_):
state.isLookingUp = false
state.failure = nil
return .none
case .didFail(let error):
state.isLookingUp = false
state.failure = error.localizedDescription
return .none
}
}
}
import ComposableArchitecture
import Foundation
import XCTestDynamicOverlay
import XXClient
import XXMessengerClient
public struct ContactLookupState: Equatable {
public init(
id: Data,
isLookingUp: Bool = false,
failure: String? = nil
) {
self.id = id
self.isLookingUp = isLookingUp
self.failure = failure
}
public var id: Data
public var isLookingUp: Bool
public var failure: String?
}
public enum ContactLookupAction: Equatable {
case lookupTapped
case didLookup(XXClient.Contact)
case didFail(NSError)
}
public struct ContactLookupEnvironment {
public init(
messenger: Messenger,
mainQueue: AnySchedulerOf<DispatchQueue>,
bgQueue: AnySchedulerOf<DispatchQueue>
) {
self.messenger = messenger
self.mainQueue = mainQueue
self.bgQueue = bgQueue
}
public var messenger: Messenger
public var mainQueue: AnySchedulerOf<DispatchQueue>
public var bgQueue: AnySchedulerOf<DispatchQueue>
}
#if DEBUG
extension ContactLookupEnvironment {
public static let unimplemented = ContactLookupEnvironment(
messenger: .unimplemented,
mainQueue: .unimplemented,
bgQueue: .unimplemented
)
}
#endif
public let contactLookupReducer = Reducer<ContactLookupState, ContactLookupAction, ContactLookupEnvironment>
{ state, action, env in
switch action {
case .lookupTapped:
state.isLookingUp = true
state.failure = nil
return Effect.result { [state] in
do {
let contact = try env.messenger.lookupContact(id: state.id)
return .success(.didLookup(contact))
} catch {
return .success(.didFail(error as NSError))
}
}
.subscribe(on: env.bgQueue)
.receive(on: env.mainQueue)
.eraseToEffect()
case .didLookup(_):
state.isLookingUp = false
state.failure = nil
return .none
case .didFail(let error):
state.isLookingUp = false
state.failure = error.localizedDescription
return .none
}
}
......@@ -3,14 +3,14 @@ import ComposableArchitecture
import SwiftUI
public struct ContactLookupView: View {
public init(store: Store<ContactLookupState, ContactLookupAction>) {
public init(store: StoreOf<ContactLookupComponent>) {
self.store = store
}
let store: Store<ContactLookupState, ContactLookupAction>
let store: StoreOf<ContactLookupComponent>
struct ViewState: Equatable {
init(state: ContactLookupState) {
init(state: ContactLookupComponent.State) {
id = state.id
isLookingUp = state.isLookingUp
failure = state.failure
......@@ -64,11 +64,10 @@ public struct ContactLookupView_Previews: PreviewProvider {
public static var previews: some View {
NavigationView {
ContactLookupView(store: Store(
initialState: ContactLookupState(
initialState: ContactLookupComponent.State(
id: "1234".data(using: .utf8)!
),
reducer: .empty,
environment: ()
reducer: EmptyReducer()
))
}
}
......
......@@ -3,20 +3,19 @@ import XCTest
import XXClient
@testable import ContactLookupFeature
final class ContactLookupFeatureTests: XCTestCase {
final class ContactLookupComponentTests: XCTestCase {
func testLookup() {
let id: Data = "1234".data(using: .utf8)!
var didLookupId: [Data] = []
let lookedUpContact = Contact.unimplemented("123data".data(using: .utf8)!)
let store = TestStore(
initialState: ContactLookupState(id: id),
reducer: contactLookupReducer,
environment: .unimplemented
initialState: ContactLookupComponent.State(id: id),
reducer: ContactLookupComponent()
)
store.environment.mainQueue = .immediate
store.environment.bgQueue = .immediate
store.environment.messenger.lookupContact.run = { id in
store.dependencies.appDependencies.mainQueue = .immediate
store.dependencies.appDependencies.bgQueue = .immediate
store.dependencies.appDependencies.messenger.lookupContact.run = { id in
didLookupId.append(id)
return lookedUpContact
}
......@@ -39,13 +38,12 @@ final class ContactLookupFeatureTests: XCTestCase {
let failure = NSError(domain: "test", code: 0)
let store = TestStore(
initialState: ContactLookupState(id: id),
reducer: contactLookupReducer,
environment: .unimplemented
initialState: ContactLookupComponent.State(id: id),
reducer: ContactLookupComponent()
)
store.environment.mainQueue = .immediate
store.environment.bgQueue = .immediate
store.environment.messenger.lookupContact.run = { _ in throw failure }
store.dependencies.appDependencies.mainQueue = .immediate
store.dependencies.appDependencies.bgQueue = .immediate
store.dependencies.appDependencies.messenger.lookupContact.run = { _ in throw failure }
store.send(.lookupTapped) {
$0.isLookingUp = true
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment