[#470] Migrate Home to ReducerProtocol (#487)

- Home migrated to ReducerProtocol
- unit and snapshot tests fixed
This commit is contained in:
Lukas Korba 2022-11-09 10:30:40 +01:00 committed by GitHub
parent 1e6397b950
commit 50f5faea06
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 279 additions and 522 deletions

View File

@ -6,6 +6,7 @@
//
import Foundation
import ComposableArchitecture
struct DiskSpaceChecker {
/// Free space on disk in bytes required to do sync
@ -28,3 +29,15 @@ struct DiskSpaceChecker {
}
}
}
private enum DiskSpaceCheckerKey: DependencyKey {
static let liveValue = WrappedDiskSpaceChecker.live
static let testValue = WrappedDiskSpaceChecker.mockEmptyDisk
}
extension DependencyValues {
var diskSpaceChecker: WrappedDiskSpaceChecker {
get { self[DiskSpaceCheckerKey.self] }
set { self[DiskSpaceCheckerKey.self] = newValue }
}
}

View File

@ -15,6 +15,7 @@ typealias AnyRecoveryPhraseValidationFlowReducer = AnyReducer<
typealias AnyWelcomeReducer = AnyReducer<WelcomeReducer.State, WelcomeReducer.Action, AppEnvironment>
typealias AnySandboxReducer = AnyReducer<SandboxReducer.State, SandboxReducer.Action, AppEnvironment>
typealias AnyOnboardingFlowReducer = AnyReducer<OnboardingFlowReducer.State, OnboardingFlowReducer.Action, AppEnvironment>
typealias AnyHomeReducer = AnyReducer<HomeReducer.State, HomeReducer.Action, AppEnvironment>
// MARK: - State
@ -30,7 +31,7 @@ struct AppState: Equatable {
}
var appInitializationState: InitializationState = .uninitialized
var homeState: HomeState
var homeState: HomeReducer.State
var onboardingState: OnboardingFlowReducer.State
var phraseValidationState: RecoveryPhraseValidationFlowReducer.State
var phraseDisplayState: RecoveryPhraseDisplayReducer.State
@ -59,7 +60,7 @@ enum AppAction: Equatable {
case deeplink(URL)
case deeplinkHome
case deeplinkSend(Zatoshi, String, String)
case home(HomeAction)
case home(HomeReducer.Action)
case initializeSDK
case nukeWallet
case onboarding(OnboardingFlowReducer.Action)
@ -368,25 +369,16 @@ extension AppReducer {
return .none
}
private static let homeReducer: AppReducer = HomeReducer.default.pullback(
private static let homeReducer: AppReducer = AnyHomeReducer { _ in
HomeReducer()
}
.pullback(
state: \AppState.homeState,
action: /AppAction.home,
environment: { environment in
HomeEnvironment(
audioServices: environment.audioServices,
derivationTool: environment.derivationTool,
diskSpaceChecker: environment.diskSpaceChecker,
feedbackGenerator: environment.feedbackGenerator,
mnemonic: environment.mnemonic,
scheduler: environment.scheduler,
SDKSynchronizer: environment.SDKSynchronizer,
walletStorage: environment.walletStorage,
zcashSDKEnvironment: environment.zcashSDKEnvironment
)
}
environment: { $0 }
)
private static let onboardingReducer: AppReducer = AnyOnboardingFlowReducer { _ in
OnboardingFlowReducer()
}

View File

@ -5,282 +5,212 @@ import ZcashLightClientKit
import UIKit
import AVFoundation
typealias HomeReducer = Reducer<HomeState, HomeAction, HomeEnvironment>
typealias HomeStore = Store<HomeState, HomeAction>
typealias HomeViewStore = ViewStore<HomeState, HomeAction>
typealias HomeStore = Store<HomeReducer.State, HomeReducer.Action>
typealias HomeViewStore = ViewStore<HomeReducer.State, HomeReducer.Action>
typealias AnyBalanceBreakdownReducer = AnyReducer<BalanceBreakdownReducer.State, BalanceBreakdownReducer.Action, HomeEnvironment>
typealias AnyScanReducer = AnyReducer<ScanReducer.State, ScanReducer.Action, HomeEnvironment>
typealias AnyWalletEventsFlowReducer = AnyReducer<WalletEventsFlowReducer.State, WalletEventsFlowReducer.Action, HomeEnvironment>
typealias AnyProfileReducer = AnyReducer<ProfileReducer.State, ProfileReducer.Action, HomeEnvironment>
typealias AnySendFlowReducer = AnyReducer<SendFlowReducer.State, SendFlowReducer.Action, HomeEnvironment>
struct HomeReducer: ReducerProtocol {
private enum CancelId {}
// MARK: State
struct HomeState: Equatable {
enum Route: Equatable {
case notEnoughFreeDiskSpace
case profile
case request
case send
case scan
case balanceBreakdown
}
var route: Route?
var balanceBreakdown: BalanceBreakdownReducer.State
var drawerOverlay: DrawerOverlay
var profileState: ProfileReducer.State
var requestState: RequestReducer.State
var requiredTransactionConfirmations = 0
var scanState: ScanReducer.State
var sendState: SendFlowReducer.State
var shieldedBalance: WalletBalance
var synchronizerStatusSnapshot: SyncStatusSnapshot
var walletEventsState: WalletEventsFlowReducer.State
// TODO [#311]: - Get the ZEC price from the SDK, https://github.com/zcash/secant-ios-wallet/issues/311
var zecPrice = Decimal(140.0)
var totalCurrencyBalance: Zatoshi {
Zatoshi.from(decimal: shieldedBalance.total.decimalValue.decimalValue * zecPrice)
}
var isDownloading: Bool {
if case .downloading = synchronizerStatusSnapshot.syncStatus {
return true
struct State: Equatable {
enum Route: Equatable {
case notEnoughFreeDiskSpace
case profile
case request
case send
case scan
case balanceBreakdown
}
return false
}
var isUpToDate: Bool {
if case .synced = synchronizerStatusSnapshot.syncStatus {
return true
var route: Route?
var balanceBreakdownState: BalanceBreakdownReducer.State
var drawerOverlay: DrawerOverlay
var profileState: ProfileReducer.State
var requestState: RequestReducer.State
var requiredTransactionConfirmations = 0
var scanState: ScanReducer.State
var sendState: SendFlowReducer.State
var shieldedBalance: WalletBalance
var synchronizerStatusSnapshot: SyncStatusSnapshot
var walletEventsState: WalletEventsFlowReducer.State
// TODO [#311]: - Get the ZEC price from the SDK, https://github.com/zcash/secant-ios-wallet/issues/311
var zecPrice = Decimal(140.0)
var totalCurrencyBalance: Zatoshi {
Zatoshi.from(decimal: shieldedBalance.total.decimalValue.decimalValue * zecPrice)
}
return false
}
}
// MARK: Action
enum HomeAction: Equatable {
case balanceBreakdown(BalanceBreakdownReducer.Action)
case debugMenuStartup
case onAppear
case onDisappear
case profile(ProfileReducer.Action)
case request(RequestReducer.Action)
case send(SendFlowReducer.Action)
case scan(ScanReducer.Action)
case synchronizerStateChanged(WrappedSDKSynchronizerState)
case walletEvents(WalletEventsFlowReducer.Action)
case updateDrawer(DrawerOverlay)
case updateRoute(HomeState.Route?)
case updateSynchronizerStatus
case updateWalletEvents([WalletEvent])
}
// MARK: Environment
struct HomeEnvironment {
let audioServices: WrappedAudioServices
let derivationTool: WrappedDerivationTool
let diskSpaceChecker: WrappedDiskSpaceChecker
let feedbackGenerator: WrappedFeedbackGenerator
let mnemonic: WrappedMnemonic
let scheduler: AnySchedulerOf<DispatchQueue>
let SDKSynchronizer: WrappedSDKSynchronizer
let walletStorage: WrappedWalletStorage
let zcashSDKEnvironment: ZCashSDKEnvironment
}
extension HomeEnvironment {
static let demo = HomeEnvironment(
audioServices: .silent,
derivationTool: .live(),
diskSpaceChecker: .mockEmptyDisk,
feedbackGenerator: .silent,
mnemonic: .mock,
scheduler: DispatchQueue.main.eraseToAnyScheduler(),
SDKSynchronizer: MockWrappedSDKSynchronizer(),
walletStorage: .throwing,
zcashSDKEnvironment: .testnet
)
}
// MARK: - Reducer
extension HomeReducer {
private struct CancelId: Hashable {}
static let `default` = HomeReducer.combine(
[
homeReducer,
walletEventsFlowReducer,
sendReducer,
scanReducer,
profileReducer,
balanceBreakdownReducer
]
)
private static let homeReducer = HomeReducer { state, action, environment in
switch action {
case .onAppear:
state.requiredTransactionConfirmations = environment.zcashSDKEnvironment.requiredTransactionConfirmations
if environment.diskSpaceChecker.hasEnoughFreeSpaceForSync() {
let syncEffect = environment.SDKSynchronizer.stateChanged
.map(HomeAction.synchronizerStateChanged)
.eraseToEffect()
.cancellable(id: CancelId(), cancelInFlight: true)
return .concatenate(Effect(value: .updateRoute(nil)), syncEffect)
} else {
return Effect(value: .updateRoute(.notEnoughFreeDiskSpace))
var isDownloading: Bool {
if case .downloading = synchronizerStatusSnapshot.syncStatus {
return true
}
case .onDisappear:
return Effect.cancel(id: CancelId())
case .synchronizerStateChanged(.synced):
return .merge(
environment.SDKSynchronizer.getAllClearedTransactions()
.receive(on: environment.scheduler)
.map(HomeAction.updateWalletEvents)
.eraseToEffect(),
Effect(value: .updateSynchronizerStatus)
)
case .synchronizerStateChanged(let synchronizerState):
return Effect(value: .updateSynchronizerStatus)
case .updateDrawer(let drawerOverlay):
state.drawerOverlay = drawerOverlay
state.walletEventsState.isScrollable = drawerOverlay == .full ? true : false
return .none
case .updateWalletEvents(let walletEvents):
return .none
case .updateSynchronizerStatus:
state.synchronizerStatusSnapshot = environment.SDKSynchronizer.statusSnapshot()
if let shieldedBalance = environment.SDKSynchronizer.latestScannedSynchronizerState?.shieldedBalance {
state.shieldedBalance = shieldedBalance
return false
}
var isUpToDate: Bool {
if case .synced = synchronizerStatusSnapshot.syncStatus {
return true
}
return .none
case .updateRoute(let route):
state.route = route
return .none
case .profile(.back):
state.route = nil
return .none
case .profile(.settings(.quickRescan)):
do {
try environment.SDKSynchronizer.rewind(.quick)
} catch {
// TODO [#221]: error we need to handle (https://github.com/zcash/secant-ios-wallet/issues/221)
}
state.route = nil
return .none
case .profile(.settings(.fullRescan)):
do {
try environment.SDKSynchronizer.rewind(.birthday)
} catch {
// TODO [#221]: error we need to handle (https://github.com/zcash/secant-ios-wallet/issues/221)
}
state.route = nil
return .none
case .profile(let action):
return .none
case .request(let action):
return .none
case .walletEvents(.updateRoute(.all)):
return state.drawerOverlay != .full ? Effect(value: .updateDrawer(.full)) : .none
case .walletEvents(.updateRoute(.latest)):
return state.drawerOverlay != .partial ? Effect(value: .updateDrawer(.partial)) : .none
case .walletEvents(let historyAction):
return .none
case .send(.updateRoute(.done)):
return Effect(value: .updateRoute(nil))
case .send(let action):
return .none
case .scan(.found(let code)):
environment.audioServices.systemSoundVibrate()
return Effect(value: .updateRoute(nil))
case .scan(let action):
return .none
case .balanceBreakdown(.onDisappear):
state.route = nil
return .none
case .balanceBreakdown:
return .none
case .debugMenuStartup:
return .none
return false
}
}
private static let walletEventsFlowReducer: HomeReducer = AnyWalletEventsFlowReducer { _ in
WalletEventsFlowReducer()
enum Action: Equatable {
case balanceBreakdown(BalanceBreakdownReducer.Action)
case debugMenuStartup
case onAppear
case onDisappear
case profile(ProfileReducer.Action)
case request(RequestReducer.Action)
case send(SendFlowReducer.Action)
case scan(ScanReducer.Action)
case synchronizerStateChanged(WrappedSDKSynchronizerState)
case walletEvents(WalletEventsFlowReducer.Action)
case updateDrawer(DrawerOverlay)
case updateRoute(HomeReducer.State.Route?)
case updateSynchronizerStatus
case updateWalletEvents([WalletEvent])
}
.pullback(
state: \HomeState.walletEventsState,
action: /HomeAction.walletEvents,
environment: { $0 }
)
private static let sendReducer: HomeReducer = AnySendFlowReducer { _ in
SendFlowReducer()
}
.pullback(
state: \HomeState.sendState,
action: /HomeAction.send,
environment: { $0 }
)
@Dependency(\.zcashSDKEnvironment) var zcashSDKEnvironment
@Dependency(\.sdkSynchronizer) var sdkSynchronizer
@Dependency(\.mainQueue) var mainQueue
@Dependency(\.diskSpaceChecker) var diskSpaceChecker
@Dependency(\.audioServices) var audioServices
private static let scanReducer: HomeReducer = AnyScanReducer { environment in
ScanReducer()
.dependency(\.uriParser, .live(uriParser: URIParser(derivationTool: environment.derivationTool)))
var body: some ReducerProtocol<State, Action> {
Scope(state: \.walletEventsState, action: /Action.walletEvents) {
WalletEventsFlowReducer()
}
Scope(state: \.sendState, action: /Action.send) {
SendFlowReducer()
}
Scope(state: \.scanState, action: /Action.scan) {
ScanReducer()
}
Scope(state: \.profileState, action: /Action.profile) {
ProfileReducer()
}
Scope(state: \.balanceBreakdownState, action: /Action.balanceBreakdown) {
BalanceBreakdownReducer()
}
Reduce { state, action in
switch action {
case .onAppear:
state.requiredTransactionConfirmations = zcashSDKEnvironment.requiredTransactionConfirmations
if diskSpaceChecker.hasEnoughFreeSpaceForSync() {
let syncEffect = sdkSynchronizer.stateChanged
.map(HomeReducer.Action.synchronizerStateChanged)
.eraseToEffect()
.cancellable(id: CancelId.self, cancelInFlight: true)
return .concatenate(Effect(value: .updateRoute(nil)), syncEffect)
} else {
return Effect(value: .updateRoute(.notEnoughFreeDiskSpace))
}
case .onDisappear:
return Effect.cancel(id: CancelId.self)
case .synchronizerStateChanged(.synced):
return .merge(
sdkSynchronizer.getAllClearedTransactions()
.receive(on: mainQueue)
.map(HomeReducer.Action.updateWalletEvents)
.eraseToEffect(),
Effect(value: .updateSynchronizerStatus)
)
case .synchronizerStateChanged:
return Effect(value: .updateSynchronizerStatus)
case .updateDrawer(let drawerOverlay):
state.drawerOverlay = drawerOverlay
state.walletEventsState.isScrollable = drawerOverlay == .full ? true : false
return .none
case .updateWalletEvents:
return .none
case .updateSynchronizerStatus:
state.synchronizerStatusSnapshot = sdkSynchronizer.statusSnapshot()
if let shieldedBalance = sdkSynchronizer.latestScannedSynchronizerState?.shieldedBalance {
state.shieldedBalance = shieldedBalance
}
return .none
case .updateRoute(let route):
state.route = route
return .none
case .profile(.back):
state.route = nil
return .none
case .profile(.settings(.quickRescan)):
do {
try sdkSynchronizer.rewind(.quick)
} catch {
// TODO [#221]: error we need to handle (https://github.com/zcash/secant-ios-wallet/issues/221)
}
state.route = nil
return .none
case .profile(.settings(.fullRescan)):
do {
try sdkSynchronizer.rewind(.birthday)
} catch {
// TODO [#221]: error we need to handle (https://github.com/zcash/secant-ios-wallet/issues/221)
}
state.route = nil
return .none
case .profile:
return .none
case .request:
return .none
case .walletEvents(.updateRoute(.all)):
return state.drawerOverlay != .full ? Effect(value: .updateDrawer(.full)) : .none
case .walletEvents(.updateRoute(.latest)):
return state.drawerOverlay != .partial ? Effect(value: .updateDrawer(.partial)) : .none
case .walletEvents:
return .none
case .send(.updateRoute(.done)):
return Effect(value: .updateRoute(nil))
case .send:
return .none
case .scan(.found):
audioServices.systemSoundVibrate()
return Effect(value: .updateRoute(nil))
case .scan:
return .none
case .balanceBreakdown(.onDisappear):
state.route = nil
return .none
case .balanceBreakdown:
return .none
case .debugMenuStartup:
return .none
}
}
}
.pullback(
state: \HomeState.scanState,
action: /HomeAction.scan,
environment: { $0 }
)
private static let profileReducer: HomeReducer = AnyProfileReducer { _ in
ProfileReducer()
}
.pullback(
state: \HomeState.profileState,
action: /HomeAction.profile,
environment: { $0 }
)
private static let balanceBreakdownReducer: HomeReducer = AnyBalanceBreakdownReducer { _ in
BalanceBreakdownReducer()
}
.pullback(
state: \HomeState.balanceBreakdown,
action: /HomeAction.balanceBreakdown,
environment: { $0 }
)
}
// MARK: - Store
@ -289,42 +219,42 @@ extension HomeStore {
func historyStore() -> WalletEventsFlowStore {
self.scope(
state: \.walletEventsState,
action: HomeAction.walletEvents
action: HomeReducer.Action.walletEvents
)
}
func profileStore() -> ProfileStore {
self.scope(
state: \.profileState,
action: HomeAction.profile
action: HomeReducer.Action.profile
)
}
func requestStore() -> RequestStore {
self.scope(
state: \.requestState,
action: HomeAction.request
action: HomeReducer.Action.request
)
}
func sendStore() -> SendFlowStore {
self.scope(
state: \.sendState,
action: HomeAction.send
action: HomeReducer.Action.send
)
}
func scanStore() -> ScanStore {
self.scope(
state: \.scanState,
action: HomeAction.scan
action: HomeReducer.Action.scan
)
}
func balanceBreakdownStore() -> BalanceBreakdownStore {
self.scope(
state: \.balanceBreakdown,
action: HomeAction.balanceBreakdown
state: \.balanceBreakdownState,
action: HomeReducer.Action.balanceBreakdown
)
}
}
@ -332,7 +262,7 @@ extension HomeStore {
// MARK: - ViewStore
extension HomeViewStore {
func bindingForRoute(_ route: HomeState.Route) -> Binding<Bool> {
func bindingForRoute(_ route: HomeReducer.State.Route) -> Binding<Bool> {
self.binding(
get: { $0.route == route },
send: { isActive in
@ -351,10 +281,10 @@ extension HomeViewStore {
// MARK: Placeholders
extension HomeState {
extension HomeReducer.State {
static var placeholder: Self {
.init(
balanceBreakdown: .placeholder,
balanceBreakdownState: .placeholder,
drawerOverlay: .partial,
profileState: .placeholder,
requestState: .placeholder,
@ -371,18 +301,7 @@ extension HomeStore {
static var placeholder: HomeStore {
HomeStore(
initialState: .placeholder,
reducer: .default,
environment: HomeEnvironment(
audioServices: .silent,
derivationTool: .live(),
diskSpaceChecker: .mockEmptyDisk,
feedbackGenerator: .silent,
mnemonic: .live,
scheduler: DispatchQueue.main.eraseToAnyScheduler(),
SDKSynchronizer: LiveWrappedSDKSynchronizer(),
walletStorage: .live(),
zcashSDKEnvironment: .testnet
)
reducer: HomeReducer()
)
}
}

View File

@ -2,7 +2,7 @@ import SwiftUI
import ComposableArchitecture
struct HomeView: View {
let store: Store<HomeState, HomeAction>
let store: Store<HomeReducer.State, HomeReducer.Action>
var body: some View {
WithViewStore(store) { viewStore in

View File

@ -7,6 +7,7 @@
import Foundation
import AVFoundation
import ComposableArchitecture
struct WrappedAudioServices {
let systemSoundVibrate: () -> Void
@ -21,3 +22,15 @@ extension WrappedAudioServices {
systemSoundVibrate: { }
)
}
private enum AudioServicesKey: DependencyKey {
static let liveValue = WrappedAudioServices.haptic
static let testValue = WrappedAudioServices.silent
}
extension DependencyValues {
var audioServices: WrappedAudioServices {
get { self[AudioServicesKey.self] }
set { self[AudioServicesKey.self] = newValue }
}
}

View File

@ -13,31 +13,13 @@ import ZcashLightClientKit
// swiftlint:disable type_body_length
class HomeTests: XCTestCase {
func testSynchronizerStateChanged_AnyButSynced() throws {
// setup the store and environment to be fully mocked
let testScheduler = DispatchQueue.test
let testEnvironment = HomeEnvironment(
audioServices: .silent,
derivationTool: .live(),
diskSpaceChecker: .mockEmptyDisk,
feedbackGenerator: .silent,
mnemonic: .mock,
scheduler: testScheduler.eraseToAnyScheduler(),
SDKSynchronizer: MockWrappedSDKSynchronizer(),
walletStorage: .throwing,
zcashSDKEnvironment: .testnet
)
let store = TestStore(
initialState: .placeholder,
reducer: HomeReducer.default,
environment: testEnvironment
reducer: HomeReducer()
)
store.send(.synchronizerStateChanged(.downloading))
testScheduler.advance(by: 0.01)
store.receive(.updateSynchronizerStatus)
}
@ -47,23 +29,11 @@ class HomeTests: XCTestCase {
func testSynchronizerStateChanged_Synced() throws {
// setup the store and environment to be fully mocked
let testScheduler = DispatchQueue.test
let testEnvironment = HomeEnvironment(
audioServices: .silent,
derivationTool: .live(),
diskSpaceChecker: .mockEmptyDisk,
feedbackGenerator: .silent,
mnemonic: .mock,
scheduler: testScheduler.eraseToAnyScheduler(),
SDKSynchronizer: MockWrappedSDKSynchronizer(),
walletStorage: .throwing,
zcashSDKEnvironment: .testnet
)
let store = TestStore(
initialState: .placeholder,
reducer: HomeReducer.default,
environment: testEnvironment
reducer: HomeReducer()
.dependency(\.mainQueue, testScheduler.eraseToAnyScheduler())
)
store.send(.synchronizerStateChanged(.synced))
@ -97,23 +67,8 @@ class HomeTests: XCTestCase {
}
func testWalletEventsPartial_to_FullDrawer() throws {
// setup the store and environment to be fully mocked
let testScheduler = DispatchQueue.test
let testEnvironment = HomeEnvironment(
audioServices: .silent,
derivationTool: .live(),
diskSpaceChecker: .mockEmptyDisk,
feedbackGenerator: .silent,
mnemonic: .mock,
scheduler: testScheduler.eraseToAnyScheduler(),
SDKSynchronizer: MockWrappedSDKSynchronizer(),
walletStorage: .throwing,
zcashSDKEnvironment: .testnet
)
let homeState = HomeState(
balanceBreakdown: .placeholder,
let homeState = HomeReducer.State(
balanceBreakdownState: .placeholder,
drawerOverlay: .partial,
profileState: .placeholder,
requestState: .placeholder,
@ -126,8 +81,7 @@ class HomeTests: XCTestCase {
let store = TestStore(
initialState: homeState,
reducer: HomeReducer.default,
environment: testEnvironment
reducer: HomeReducer()
)
store.send(.walletEvents(.updateRoute(.all))) { state in
@ -141,23 +95,8 @@ class HomeTests: XCTestCase {
}
func testWalletEventsFull_to_PartialDrawer() throws {
// setup the store and environment to be fully mocked
let testScheduler = DispatchQueue.test
let testEnvironment = HomeEnvironment(
audioServices: .silent,
derivationTool: .live(),
diskSpaceChecker: .mockEmptyDisk,
feedbackGenerator: .silent,
mnemonic: .mock,
scheduler: testScheduler.eraseToAnyScheduler(),
SDKSynchronizer: MockWrappedSDKSynchronizer(),
walletStorage: .throwing,
zcashSDKEnvironment: .testnet
)
let homeState = HomeState(
balanceBreakdown: .placeholder,
let homeState = HomeReducer.State(
balanceBreakdownState: .placeholder,
drawerOverlay: .full,
profileState: .placeholder,
requestState: .placeholder,
@ -170,8 +109,7 @@ class HomeTests: XCTestCase {
let store = TestStore(
initialState: homeState,
reducer: HomeReducer.default,
environment: testEnvironment
reducer: HomeReducer()
)
store.send(.walletEvents(.updateRoute(.latest))) { state in
@ -187,33 +125,15 @@ class HomeTests: XCTestCase {
/// The .onAppear action is important to register for the synchronizer state updates.
/// The integration tests make sure registrations and side effects are properly implemented.
func testOnAppear() throws {
// setup the store and environment to be fully mocked
let testScheduler = DispatchQueue.test
let testEnvironment = HomeEnvironment(
audioServices: .silent,
derivationTool: .live(),
diskSpaceChecker: .mockEmptyDisk,
feedbackGenerator: .silent,
mnemonic: .mock,
scheduler: testScheduler.eraseToAnyScheduler(),
SDKSynchronizer: MockWrappedSDKSynchronizer(),
walletStorage: .throwing,
zcashSDKEnvironment: .testnet
)
let store = TestStore(
initialState: .placeholder,
reducer: HomeReducer.default,
environment: testEnvironment
reducer: HomeReducer()
)
store.send(.onAppear) { state in
state.requiredTransactionConfirmations = 10
}
testScheduler.advance(by: 0.01)
// expected side effects as a result of .onAppear registration
store.receive(.updateRoute(nil))
store.receive(.synchronizerStateChanged(.unknown))
@ -225,33 +145,16 @@ class HomeTests: XCTestCase {
}
func testOnAppear_notEnoughSpaceOnDisk() throws {
// setup the store and environment to be fully mocked
let testScheduler = DispatchQueue.test
let testEnvironment = HomeEnvironment(
audioServices: .silent,
derivationTool: .live(),
diskSpaceChecker: .mockFullDisk,
feedbackGenerator: .silent,
mnemonic: .mock,
scheduler: testScheduler.eraseToAnyScheduler(),
SDKSynchronizer: MockWrappedSDKSynchronizer(),
walletStorage: .throwing,
zcashSDKEnvironment: .testnet
)
let store = TestStore(
initialState: .placeholder,
reducer: HomeReducer.default,
environment: testEnvironment
reducer: HomeReducer()
.dependency(\.diskSpaceChecker, .mockFullDisk)
)
store.send(.onAppear) { state in
state.requiredTransactionConfirmations = 10
}
testScheduler.advance(by: 0.01)
// expected side effects as a result of .onAppear registration
store.receive(.updateRoute(.notEnoughFreeDiskSpace)) { state in
state.route = .notEnoughFreeDiskSpace
@ -263,24 +166,9 @@ class HomeTests: XCTestCase {
}
func testQuickRescan_ResetToHomeScreen() throws {
// setup the store and environment to be fully mocked
let testScheduler = DispatchQueue.test
let testEnvironment = HomeEnvironment(
audioServices: .silent,
derivationTool: .live(),
diskSpaceChecker: .mockEmptyDisk,
feedbackGenerator: .silent,
mnemonic: .mock,
scheduler: testScheduler.eraseToAnyScheduler(),
SDKSynchronizer: MockWrappedSDKSynchronizer(),
walletStorage: .throwing,
zcashSDKEnvironment: .testnet
)
let homeState = HomeState(
let homeState = HomeReducer.State(
route: .profile,
balanceBreakdown: .placeholder,
balanceBreakdownState: .placeholder,
drawerOverlay: .full,
profileState: .placeholder,
requestState: .placeholder,
@ -293,8 +181,7 @@ class HomeTests: XCTestCase {
let store = TestStore(
initialState: homeState,
reducer: HomeReducer.default,
environment: testEnvironment
reducer: HomeReducer()
)
store.send(.profile(.settings(.quickRescan))) { state in
@ -303,24 +190,9 @@ class HomeTests: XCTestCase {
}
func testFullRescan_ResetToHomeScreen() throws {
// setup the store and environment to be fully mocked
let testScheduler = DispatchQueue.test
let testEnvironment = HomeEnvironment(
audioServices: .silent,
derivationTool: .live(),
diskSpaceChecker: .mockEmptyDisk,
feedbackGenerator: .silent,
mnemonic: .mock,
scheduler: testScheduler.eraseToAnyScheduler(),
SDKSynchronizer: MockWrappedSDKSynchronizer(),
walletStorage: .throwing,
zcashSDKEnvironment: .testnet
)
let homeState = HomeState(
let homeState = HomeReducer.State(
route: .profile,
balanceBreakdown: .placeholder,
balanceBreakdownState: .placeholder,
drawerOverlay: .full,
profileState: .placeholder,
requestState: .placeholder,
@ -333,8 +205,7 @@ class HomeTests: XCTestCase {
let store = TestStore(
initialState: homeState,
reducer: HomeReducer.default,
environment: testEnvironment
reducer: HomeReducer()
)
store.send(.profile(.settings(.fullRescan))) { state in

View File

@ -27,23 +27,9 @@ class HomeCircularProgressSnapshotTests: XCTestCase {
let balance = WalletBalance(verified: Zatoshi(15_345_000), total: Zatoshi(15_345_000))
let testScheduler = DispatchQueue.test
let testEnvironment = HomeEnvironment(
audioServices: .silent,
derivationTool: .live(),
diskSpaceChecker: .mockEmptyDisk,
feedbackGenerator: .silent,
mnemonic: .mock,
scheduler: testScheduler.eraseToAnyScheduler(),
SDKSynchronizer: SnapshotTestWrappedSDKSynchronizer(),
walletStorage: .throwing,
zcashSDKEnvironment: .testnet
)
let store = HomeStore(
initialState: .init(
balanceBreakdown: .placeholder,
balanceBreakdownState: .placeholder,
drawerOverlay: .partial,
profileState: .placeholder,
requestState: .placeholder,
@ -53,8 +39,8 @@ class HomeCircularProgressSnapshotTests: XCTestCase {
synchronizerStatusSnapshot: .default,
walletEventsState: .emptyPlaceHolder
),
reducer: .default,
environment: testEnvironment
reducer: HomeReducer()
.dependency(\.sdkSynchronizer, SnapshotTestWrappedSDKSynchronizer())
)
addAttachments(HomeView(store: store))
@ -76,23 +62,9 @@ class HomeCircularProgressSnapshotTests: XCTestCase {
let balance = WalletBalance(verified: 15_345_000, total: 15_345_000)
let testScheduler = DispatchQueue.test
let testEnvironment = HomeEnvironment(
audioServices: .silent,
derivationTool: .live(),
diskSpaceChecker: .mockEmptyDisk,
feedbackGenerator: .silent,
mnemonic: .mock,
scheduler: testScheduler.eraseToAnyScheduler(),
SDKSynchronizer: SnapshotTestWrappedSDKSynchronizer(),
walletStorage: .throwing,
zcashSDKEnvironment: .testnet
)
let store = HomeStore(
initialState: .init(
balanceBreakdown: .placeholder,
balanceBreakdownState: .placeholder,
drawerOverlay: .partial,
profileState: .placeholder,
requestState: .placeholder,
@ -102,8 +74,7 @@ class HomeCircularProgressSnapshotTests: XCTestCase {
synchronizerStatusSnapshot: .default,
walletEventsState: .emptyPlaceHolder
),
reducer: .default,
environment: testEnvironment
reducer: HomeReducer()
)
addAttachments(HomeView(store: store))
@ -118,23 +89,9 @@ class HomeCircularProgressSnapshotTests: XCTestCase {
let balance = WalletBalance(verified: 15_345_000, total: 15_345_000)
let testScheduler = DispatchQueue.test
let testEnvironment = HomeEnvironment(
audioServices: .silent,
derivationTool: .live(),
diskSpaceChecker: .mockEmptyDisk,
feedbackGenerator: .silent,
mnemonic: .mock,
scheduler: testScheduler.eraseToAnyScheduler(),
SDKSynchronizer: SnapshotTestWrappedSDKSynchronizer(),
walletStorage: .throwing,
zcashSDKEnvironment: .testnet
)
let store = HomeStore(
initialState: .init(
balanceBreakdown: .placeholder,
balanceBreakdownState: .placeholder,
drawerOverlay: .partial,
profileState: .placeholder,
requestState: .placeholder,
@ -144,8 +101,7 @@ class HomeCircularProgressSnapshotTests: XCTestCase {
synchronizerStatusSnapshot: .default,
walletEventsState: .emptyPlaceHolder
),
reducer: .default,
environment: testEnvironment
reducer: HomeReducer()
)
addAttachments(HomeView(store: store))

View File

@ -37,7 +37,7 @@ class HomeSnapshotTests: XCTestCase {
let store = HomeStore(
initialState: .init(
balanceBreakdown: .placeholder,
balanceBreakdownState: .placeholder,
drawerOverlay: .partial,
profileState: .placeholder,
requestState: .placeholder,
@ -47,8 +47,7 @@ class HomeSnapshotTests: XCTestCase {
synchronizerStatusSnapshot: .default,
walletEventsState: .init(walletEvents: IdentifiedArrayOf(uniqueElements: walletEvents))
),
reducer: .default,
environment: .demo
reducer: HomeReducer()
)
// landing home screen

View File

@ -10,7 +10,6 @@ import XCTest
import ComposableArchitecture
import ZcashLightClientKit
// swiftlint:disable type_body_length
class WalletEventsSnapshotTests: XCTestCase {
func testFullWalletEventsSnapshot() throws {
let transactionsHelper: [TransactionStateMockHelper] = [
@ -38,7 +37,7 @@ class WalletEventsSnapshotTests: XCTestCase {
let store = HomeStore(
initialState: .init(
balanceBreakdown: .placeholder,
balanceBreakdownState: .placeholder,
drawerOverlay: .partial,
profileState: .placeholder,
requestState: .placeholder,
@ -48,8 +47,7 @@ class WalletEventsSnapshotTests: XCTestCase {
synchronizerStatusSnapshot: .default,
walletEventsState: .init(walletEvents: IdentifiedArrayOf(uniqueElements: walletEvents))
),
reducer: .default,
environment: .demo
reducer: HomeReducer()
)
// landing home screen
@ -85,7 +83,7 @@ class WalletEventsSnapshotTests: XCTestCase {
let balance = WalletBalance(verified: 12_345_000, total: 12_345_000)
let store = HomeStore(
initialState: .init(
balanceBreakdown: .placeholder,
balanceBreakdownState: .placeholder,
drawerOverlay: .partial,
profileState: .placeholder,
requestState: .placeholder,
@ -95,8 +93,7 @@ class WalletEventsSnapshotTests: XCTestCase {
synchronizerStatusSnapshot: .default,
walletEventsState: .init(walletEvents: IdentifiedArrayOf(uniqueElements: [walletEvent]))
),
reducer: .default,
environment: .demo
reducer: HomeReducer()
)
ViewStore(store).send(.walletEvents(.updateRoute(.showWalletEvent(walletEvent))))
@ -133,7 +130,7 @@ class WalletEventsSnapshotTests: XCTestCase {
let balance = WalletBalance(verified: 12_345_000, total: 12_345_000)
let store = HomeStore(
initialState: .init(
balanceBreakdown: .placeholder,
balanceBreakdownState: .placeholder,
drawerOverlay: .partial,
profileState: .placeholder,
requestState: .placeholder,
@ -143,8 +140,7 @@ class WalletEventsSnapshotTests: XCTestCase {
synchronizerStatusSnapshot: .default,
walletEventsState: .init(walletEvents: IdentifiedArrayOf(uniqueElements: [walletEvent]))
),
reducer: .default,
environment: .demo
reducer: HomeReducer()
)
ViewStore(store).send(.walletEvents(.updateRoute(.showWalletEvent(walletEvent))))
@ -181,7 +177,7 @@ class WalletEventsSnapshotTests: XCTestCase {
let balance = WalletBalance(verified: 12_345_000, total: 12_345_000)
let store = HomeStore(
initialState: .init(
balanceBreakdown: .placeholder,
balanceBreakdownState: .placeholder,
drawerOverlay: .partial,
profileState: .placeholder,
requestState: .placeholder,
@ -191,8 +187,7 @@ class WalletEventsSnapshotTests: XCTestCase {
synchronizerStatusSnapshot: .default,
walletEventsState: .init(walletEvents: IdentifiedArrayOf(uniqueElements: [walletEvent]))
),
reducer: .default,
environment: .demo
reducer: HomeReducer()
)
let walletEventsState = WalletEventsFlowReducer.State(
@ -235,7 +230,7 @@ class WalletEventsSnapshotTests: XCTestCase {
let balance = WalletBalance(verified: 12_345_000, total: 12_345_000)
let store = HomeStore(
initialState: .init(
balanceBreakdown: .placeholder,
balanceBreakdownState: .placeholder,
drawerOverlay: .partial,
profileState: .placeholder,
requestState: .placeholder,
@ -245,8 +240,7 @@ class WalletEventsSnapshotTests: XCTestCase {
synchronizerStatusSnapshot: .default,
walletEventsState: .init(walletEvents: IdentifiedArrayOf(uniqueElements: [walletEvent]))
),
reducer: .default,
environment: .demo
reducer: HomeReducer()
)
ViewStore(store).send(.walletEvents(.updateRoute(.showWalletEvent(walletEvent))))