From fccbe606f3b49ed556ca938359451ab36e9b8ef5 Mon Sep 17 00:00:00 2001 From: Dariusz Rybicki <dariusz@elixxir.io> Date: Wed, 3 Aug 2022 13:24:08 +0100 Subject: [PATCH] Update LandingFeature --- Example/example-app/Package.swift | 4 + .../LandingFeature/LandingFeature.swift | 107 ++++++------ .../Sources/LandingFeature/LandingView.swift | 30 ++-- .../LandingFeatureTests.swift | 158 +++++++++--------- 4 files changed, 148 insertions(+), 151 deletions(-) diff --git a/Example/example-app/Package.swift b/Example/example-app/Package.swift index 64bcd4ba..1d3dc343 100644 --- a/Example/example-app/Package.swift +++ b/Example/example-app/Package.swift @@ -140,6 +140,10 @@ let package = Package( name: "ElixxirDAppsSDK", package: "elixxir-dapps-sdk-swift" ), + .product( + name: "XCTestDynamicOverlay", + package: "xctest-dynamic-overlay" + ), ], swiftSettings: swiftSettings ), diff --git a/Example/example-app/Sources/LandingFeature/LandingFeature.swift b/Example/example-app/Sources/LandingFeature/LandingFeature.swift index 511b1107..f8fa2d9d 100644 --- a/Example/example-app/Sources/LandingFeature/LandingFeature.swift +++ b/Example/example-app/Sources/LandingFeature/LandingFeature.swift @@ -2,58 +2,59 @@ import Combine import ComposableArchitecture import ElixxirDAppsSDK import ErrorFeature +import XCTestDynamicOverlay public struct LandingState: Equatable { public init( id: UUID, - hasStoredClient: Bool = false, - isMakingClient: Bool = false, - isRemovingClient: Bool = false, + hasStoredCmix: Bool = false, + isMakingCmix: Bool = false, + isRemovingCmix: Bool = false, error: ErrorState? = nil ) { self.id = id - self.hasStoredClient = hasStoredClient - self.isMakingClient = isMakingClient - self.isRemovingClient = isRemovingClient + self.hasStoredCmix = hasStoredCmix + self.isMakingCmix = isMakingCmix + self.isRemovingCmix = isRemovingCmix self.error = error } var id: UUID - var hasStoredClient: Bool - var isMakingClient: Bool - var isRemovingClient: Bool + var hasStoredCmix: Bool + var isMakingCmix: Bool + var isRemovingCmix: Bool var error: ErrorState? } public enum LandingAction: Equatable { case viewDidLoad - case makeClient - case didMakeClient - case didFailMakingClient(NSError) - case removeStoredClient - case didRemoveStoredClient - case didFailRemovingStoredClient(NSError) + case makeCmix + case didMakeCmix + case didFailMakingCmix(NSError) + case removeStoredCmix + case didRemoveStoredCmix + case didFailRemovingStoredCmix(NSError) case didDismissError case error(ErrorAction) } public struct LandingEnvironment { public init( - clientStorage: ClientStorage, - setClient: @escaping (Client) -> Void, + cmixManager: CmixManager, + setCmix: @escaping (Cmix) -> Void, bgScheduler: AnySchedulerOf<DispatchQueue>, mainScheduler: AnySchedulerOf<DispatchQueue>, error: ErrorEnvironment ) { - self.clientStorage = clientStorage - self.setClient = setClient + self.cmixManager = cmixManager + self.setCmix = setCmix self.bgScheduler = bgScheduler self.mainScheduler = mainScheduler self.error = error } - public var clientStorage: ClientStorage - public var setClient: (Client) -> Void + public var cmixManager: CmixManager + public var setCmix: (Cmix) -> Void public var bgScheduler: AnySchedulerOf<DispatchQueue> public var mainScheduler: AnySchedulerOf<DispatchQueue> public var error: ErrorEnvironment @@ -63,60 +64,60 @@ public let landingReducer = Reducer<LandingState, LandingAction, LandingEnvironm { state, action, env in switch action { case .viewDidLoad: - state.hasStoredClient = env.clientStorage.hasStoredClient() + state.hasStoredCmix = env.cmixManager.hasStorage() return .none - case .makeClient: - state.isMakingClient = true + case .makeCmix: + state.isMakingCmix = true return Effect.future { fulfill in do { - if env.clientStorage.hasStoredClient() { - env.setClient(try env.clientStorage.loadClient()) + if env.cmixManager.hasStorage() { + env.setCmix(try env.cmixManager.load()) } else { - env.setClient(try env.clientStorage.createClient()) + env.setCmix(try env.cmixManager.create()) } - fulfill(.success(.didMakeClient)) + fulfill(.success(.didMakeCmix)) } catch { - fulfill(.success(.didFailMakingClient(error as NSError))) + fulfill(.success(.didFailMakingCmix(error as NSError))) } } .subscribe(on: env.bgScheduler) .receive(on: env.mainScheduler) .eraseToEffect() - case .didMakeClient: - state.isMakingClient = false - state.hasStoredClient = env.clientStorage.hasStoredClient() + case .didMakeCmix: + state.isMakingCmix = false + state.hasStoredCmix = env.cmixManager.hasStorage() return .none - case .didFailMakingClient(let error): - state.isMakingClient = false - state.hasStoredClient = env.clientStorage.hasStoredClient() + case .didFailMakingCmix(let error): + state.isMakingCmix = false + state.hasStoredCmix = env.cmixManager.hasStorage() state.error = ErrorState(error: error) return .none - case .removeStoredClient: - state.isRemovingClient = true + case .removeStoredCmix: + state.isRemovingCmix = true return Effect.future { fulfill in do { - try env.clientStorage.removeClient() - fulfill(.success(.didRemoveStoredClient)) + try env.cmixManager.remove() + fulfill(.success(.didRemoveStoredCmix)) } catch { - fulfill(.success(.didFailRemovingStoredClient(error as NSError))) + fulfill(.success(.didFailRemovingStoredCmix(error as NSError))) } } .subscribe(on: env.bgScheduler) .receive(on: env.mainScheduler) .eraseToEffect() - case .didRemoveStoredClient: - state.isRemovingClient = false - state.hasStoredClient = env.clientStorage.hasStoredClient() + case .didRemoveStoredCmix: + state.isRemovingCmix = false + state.hasStoredCmix = env.cmixManager.hasStorage() return .none - case .didFailRemovingStoredClient(let error): - state.isRemovingClient = false - state.hasStoredClient = env.clientStorage.hasStoredClient() + case .didFailRemovingStoredCmix(let error): + state.isRemovingCmix = false + state.hasStoredCmix = env.cmixManager.hasStorage() state.error = ErrorState(error: error) return .none @@ -133,14 +134,12 @@ public let landingReducer = Reducer<LandingState, LandingAction, LandingEnvironm environment: \.error ) -#if DEBUG extension LandingEnvironment { - public static let failing = LandingEnvironment( - clientStorage: .failing, - setClient: { _ in fatalError() }, - bgScheduler: .failing, - mainScheduler: .failing, - error: .failing + public static let unimplemented = LandingEnvironment( + cmixManager: .unimplemented, + setCmix: XCTUnimplemented("\(Self.self).setCmix"), + bgScheduler: .unimplemented, + mainScheduler: .unimplemented, + error: .unimplemented ) } -#endif diff --git a/Example/example-app/Sources/LandingFeature/LandingView.swift b/Example/example-app/Sources/LandingFeature/LandingView.swift index 4a45669a..f52aeebb 100644 --- a/Example/example-app/Sources/LandingFeature/LandingView.swift +++ b/Example/example-app/Sources/LandingFeature/LandingView.swift @@ -11,19 +11,19 @@ public struct LandingView: View { let store: Store<LandingState, LandingAction> struct ViewState: Equatable { - let hasStoredClient: Bool - let isMakingClient: Bool - let isRemovingClient: Bool + let hasStoredCmix: Bool + let isMakingCmix: Bool + let isRemovingCmix: Bool init(state: LandingState) { - hasStoredClient = state.hasStoredClient - isMakingClient = state.isMakingClient - isRemovingClient = state.isRemovingClient + hasStoredCmix = state.hasStoredCmix + isMakingCmix = state.isMakingCmix + isRemovingCmix = state.isRemovingCmix } var isLoading: Bool { - isMakingClient || - isRemovingClient + isMakingCmix || + isRemovingCmix } } @@ -31,25 +31,25 @@ public struct LandingView: View { WithViewStore(store.scope(state: ViewState.init)) { viewStore in Form { Button { - viewStore.send(.makeClient) + viewStore.send(.makeCmix) } label: { HStack { - Text(viewStore.hasStoredClient ? "Load stored client" : "Create new client") + Text(viewStore.hasStoredCmix ? "Load stored cMix" : "Create new cMix") Spacer() - if viewStore.isMakingClient { + if viewStore.isMakingCmix { ProgressView() } } } - if viewStore.hasStoredClient { + if viewStore.hasStoredCmix { Button(role: .destructive) { - viewStore.send(.removeStoredClient) + viewStore.send(.removeStoredCmix) } label: { HStack { - Text("Remove stored client") + Text("Remove stored cMix") Spacer() - if viewStore.isRemovingClient { + if viewStore.isRemovingCmix { ProgressView() } } diff --git a/Example/example-app/Tests/LandingFeatureTests/LandingFeatureTests.swift b/Example/example-app/Tests/LandingFeatureTests/LandingFeatureTests.swift index c5b56f98..cb52fb7b 100644 --- a/Example/example-app/Tests/LandingFeatureTests/LandingFeatureTests.swift +++ b/Example/example-app/Tests/LandingFeatureTests/LandingFeatureTests.swift @@ -5,183 +5,177 @@ import XCTest final class LandingFeatureTests: XCTestCase { func testViewDidLoad() throws { - var env = LandingEnvironment.failing - env.clientStorage.hasStoredClient = { true } - let store = TestStore( initialState: LandingState(id: UUID()), reducer: landingReducer, - environment: env + environment: .unimplemented ) + store.environment.cmixManager.hasStorage.run = { true } + store.send(.viewDidLoad) { - $0.hasStoredClient = true + $0.hasStoredCmix = true } } - func testCreateClient() { - var hasStoredClient = false - var didSetClient = false + func testCreateCmix() { + var hasStoredCmix = false + var didSetCmix = false let bgScheduler = DispatchQueue.test let mainScheduler = DispatchQueue.test - var env = LandingEnvironment.failing - env.clientStorage.hasStoredClient = { hasStoredClient } - env.clientStorage.createClient = { .failing } - env.setClient = { _ in didSetClient = true } - env.bgScheduler = bgScheduler.eraseToAnyScheduler() - env.mainScheduler = mainScheduler.eraseToAnyScheduler() - let store = TestStore( initialState: LandingState(id: UUID()), reducer: landingReducer, - environment: env + environment: .unimplemented ) - store.send(.makeClient) { - $0.isMakingClient = true + store.environment.cmixManager.hasStorage.run = { hasStoredCmix } + store.environment.cmixManager.create.run = { .unimplemented } + store.environment.setCmix = { _ in didSetCmix = true } + store.environment.bgScheduler = bgScheduler.eraseToAnyScheduler() + store.environment.mainScheduler = mainScheduler.eraseToAnyScheduler() + + store.send(.makeCmix) { + $0.isMakingCmix = true } bgScheduler.advance() - XCTAssertTrue(didSetClient) + XCTAssertTrue(didSetCmix) - hasStoredClient = true + hasStoredCmix = true mainScheduler.advance() - store.receive(.didMakeClient) { - $0.isMakingClient = false - $0.hasStoredClient = true + store.receive(.didMakeCmix) { + $0.isMakingCmix = false + $0.hasStoredCmix = true } } - func testLoadStoredClient() { - var didSetClient = false + func testLoadStoredCmix() { + var didSetCmix = false let bgScheduler = DispatchQueue.test let mainScheduler = DispatchQueue.test - var env = LandingEnvironment.failing - env.clientStorage.hasStoredClient = { true } - env.clientStorage.loadClient = { .failing } - env.setClient = { _ in didSetClient = true } - env.bgScheduler = bgScheduler.eraseToAnyScheduler() - env.mainScheduler = mainScheduler.eraseToAnyScheduler() - let store = TestStore( initialState: LandingState(id: UUID()), reducer: landingReducer, - environment: env + environment: .unimplemented ) - store.send(.makeClient) { - $0.isMakingClient = true + store.environment.cmixManager.hasStorage.run = { true } + store.environment.cmixManager.load.run = { .unimplemented } + store.environment.setCmix = { _ in didSetCmix = true } + store.environment.bgScheduler = bgScheduler.eraseToAnyScheduler() + store.environment.mainScheduler = mainScheduler.eraseToAnyScheduler() + + store.send(.makeCmix) { + $0.isMakingCmix = true } bgScheduler.advance() - XCTAssertTrue(didSetClient) + XCTAssertTrue(didSetCmix) mainScheduler.advance() - store.receive(.didMakeClient) { - $0.isMakingClient = false - $0.hasStoredClient = true + store.receive(.didMakeCmix) { + $0.isMakingCmix = false + $0.hasStoredCmix = true } } - func testMakeClientFailure() { + func testMakeCmixFailure() { let error = NSError(domain: "test", code: 1234) let bgScheduler = DispatchQueue.test let mainScheduler = DispatchQueue.test - var env = LandingEnvironment.failing - env.clientStorage.hasStoredClient = { false } - env.clientStorage.createClient = { throw error } - env.bgScheduler = bgScheduler.eraseToAnyScheduler() - env.mainScheduler = mainScheduler.eraseToAnyScheduler() - let store = TestStore( initialState: LandingState(id: UUID()), reducer: landingReducer, - environment: env + environment: .unimplemented ) - store.send(.makeClient) { - $0.isMakingClient = true + store.environment.cmixManager.hasStorage.run = { false } + store.environment.cmixManager.create.run = { throw error } + store.environment.bgScheduler = bgScheduler.eraseToAnyScheduler() + store.environment.mainScheduler = mainScheduler.eraseToAnyScheduler() + + store.send(.makeCmix) { + $0.isMakingCmix = true } bgScheduler.advance() mainScheduler.advance() - store.receive(.didFailMakingClient(error)) { - $0.isMakingClient = false - $0.hasStoredClient = false + store.receive(.didFailMakingCmix(error)) { + $0.isMakingCmix = false + $0.hasStoredCmix = false $0.error = ErrorState(error: error) } } - func testRemoveStoredClient() { - var hasStoredClient = true - var didRemoveClient = false + func testRemoveStoredCmix() { + var hasStoredCmix = true + var didRemoveCmix = false let bgScheduler = DispatchQueue.test let mainScheduler = DispatchQueue.test - var env = LandingEnvironment.failing - env.clientStorage.hasStoredClient = { hasStoredClient } - env.clientStorage.removeClient = { didRemoveClient = true } - env.bgScheduler = bgScheduler.eraseToAnyScheduler() - env.mainScheduler = mainScheduler.eraseToAnyScheduler() - let store = TestStore( initialState: LandingState(id: UUID()), reducer: landingReducer, - environment: env + environment: .unimplemented ) - store.send(.removeStoredClient) { - $0.isRemovingClient = true + store.environment.cmixManager.hasStorage.run = { hasStoredCmix } + store.environment.cmixManager.remove.run = { didRemoveCmix = true } + store.environment.bgScheduler = bgScheduler.eraseToAnyScheduler() + store.environment.mainScheduler = mainScheduler.eraseToAnyScheduler() + + store.send(.removeStoredCmix) { + $0.isRemovingCmix = true } bgScheduler.advance() - XCTAssertTrue(didRemoveClient) + XCTAssertTrue(didRemoveCmix) - hasStoredClient = false + hasStoredCmix = false mainScheduler.advance() - store.receive(.didRemoveStoredClient) { - $0.isRemovingClient = false - $0.hasStoredClient = false + store.receive(.didRemoveStoredCmix) { + $0.isRemovingCmix = false + $0.hasStoredCmix = false } } - func testRemoveStoredClientFailure() { + func testRemoveStoredCmixFailure() { let error = NSError(domain: "test", code: 1234) let bgScheduler = DispatchQueue.test let mainScheduler = DispatchQueue.test - var env = LandingEnvironment.failing - env.clientStorage.hasStoredClient = { true } - env.clientStorage.removeClient = { throw error } - env.bgScheduler = bgScheduler.eraseToAnyScheduler() - env.mainScheduler = mainScheduler.eraseToAnyScheduler() - let store = TestStore( initialState: LandingState(id: UUID()), reducer: landingReducer, - environment: env + environment: .unimplemented ) - store.send(.removeStoredClient) { - $0.isRemovingClient = true + store.environment.cmixManager.hasStorage.run = { true } + store.environment.cmixManager.remove.run = { throw error } + store.environment.bgScheduler = bgScheduler.eraseToAnyScheduler() + store.environment.mainScheduler = mainScheduler.eraseToAnyScheduler() + + store.send(.removeStoredCmix) { + $0.isRemovingCmix = true } bgScheduler.advance() mainScheduler.advance() - store.receive(.didFailRemovingStoredClient(error)) { - $0.isRemovingClient = false - $0.hasStoredClient = true + store.receive(.didFailRemovingStoredCmix(error)) { + $0.isRemovingCmix = false + $0.hasStoredCmix = true $0.error = ErrorState(error: error) } } -- GitLab