[#450] Migrate WalletEvents to ReducerProtocol (#457)

- WalletEvents migrated to ReducerProtocol
- unit and snapshot tests fixed
- some code cleanup, refactor and re-ordered
- WalletEvents refactored to WalletEventsReducer
This commit is contained in:
Lukas Korba 2022-11-05 07:14:44 +01:00 committed by GitHub
parent d6cb429372
commit 53011ff4c8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 103 additions and 178 deletions

View File

@ -25,9 +25,6 @@ struct BalanceBreakdownReducer: ReducerProtocol {
} }
} }
@Dependency(\.numberFormatter) var numberFormatter
@Dependency(\.sdkSynchronizer) var sdkSynchronizer
enum Action: Equatable { enum Action: Equatable {
case onAppear case onAppear
case onDisappear case onDisappear
@ -35,6 +32,9 @@ struct BalanceBreakdownReducer: ReducerProtocol {
case updateLatestBlock case updateLatestBlock
case updateSynchronizerStatus case updateSynchronizerStatus
} }
@Dependency(\.numberFormatter) var numberFormatter
@Dependency(\.sdkSynchronizer) var sdkSynchronizer
func reduce(into state: inout State, action: Action) -> ComposableArchitecture.EffectTask<Action> { func reduce(into state: inout State, action: Action) -> ComposableArchitecture.EffectTask<Action> {
switch action { switch action {

View File

@ -11,6 +11,7 @@ typealias HomeViewStore = ViewStore<HomeState, HomeAction>
typealias AnyBalanceBreakdownReducer = AnyReducer<BalanceBreakdownReducer.State, BalanceBreakdownReducer.Action, HomeEnvironment> typealias AnyBalanceBreakdownReducer = AnyReducer<BalanceBreakdownReducer.State, BalanceBreakdownReducer.Action, HomeEnvironment>
typealias AnyScanReducer = AnyReducer<ScanReducer.State, ScanReducer.Action, HomeEnvironment> typealias AnyScanReducer = AnyReducer<ScanReducer.State, ScanReducer.Action, HomeEnvironment>
typealias AnyWalletEventsFlowReducer = AnyReducer<WalletEventsFlowReducer.State, WalletEventsFlowReducer.Action, HomeEnvironment>
// MARK: State // MARK: State
@ -35,7 +36,7 @@ struct HomeState: Equatable {
var sendState: SendFlowState var sendState: SendFlowState
var shieldedBalance: WalletBalance var shieldedBalance: WalletBalance
var synchronizerStatusSnapshot: SyncStatusSnapshot var synchronizerStatusSnapshot: SyncStatusSnapshot
var walletEventsState: WalletEventsFlowState var walletEventsState: WalletEventsFlowReducer.State
// TODO [#311]: - Get the ZEC price from the SDK, https://github.com/zcash/secant-ios-wallet/issues/311 // TODO [#311]: - Get the ZEC price from the SDK, https://github.com/zcash/secant-ios-wallet/issues/311
var zecPrice = Decimal(140.0) var zecPrice = Decimal(140.0)
@ -70,7 +71,7 @@ enum HomeAction: Equatable {
case send(SendFlowAction) case send(SendFlowAction)
case scan(ScanReducer.Action) case scan(ScanReducer.Action)
case synchronizerStateChanged(WrappedSDKSynchronizerState) case synchronizerStateChanged(WrappedSDKSynchronizerState)
case walletEvents(WalletEventsFlowAction) case walletEvents(WalletEventsFlowReducer.Action)
case updateDrawer(DrawerOverlay) case updateDrawer(DrawerOverlay)
case updateRoute(HomeState.Route?) case updateRoute(HomeState.Route?)
case updateSynchronizerStatus case updateSynchronizerStatus
@ -113,7 +114,7 @@ extension HomeReducer {
static let `default` = HomeReducer.combine( static let `default` = HomeReducer.combine(
[ [
homeReducer, homeReducer,
historyReducer, walletEventsFlowReducer,
sendReducer, sendReducer,
scanReducer, scanReducer,
profileReducer, profileReducer,
@ -233,17 +234,13 @@ extension HomeReducer {
} }
} }
private static let historyReducer: HomeReducer = WalletEventsFlowReducer.default.pullback( private static let walletEventsFlowReducer: HomeReducer = AnyWalletEventsFlowReducer { _ in
WalletEventsFlowReducer()
}
.pullback(
state: \HomeState.walletEventsState, state: \HomeState.walletEventsState,
action: /HomeAction.walletEvents, action: /HomeAction.walletEvents,
environment: { environment in environment: { $0 }
WalletEventsFlowEnvironment(
pasteboard: .live,
scheduler: environment.scheduler,
SDKSynchronizer: environment.SDKSynchronizer,
zcashSDKEnvironment: environment.zcashSDKEnvironment
)
}
) )
private static let sendReducer: HomeReducer = SendFlowReducer.default.pullback( private static let sendReducer: HomeReducer = SendFlowReducer.default.pullback(

View File

@ -37,10 +37,6 @@ struct ImportWalletReducer: ReducerProtocol {
} }
} }
@Dependency(\.zcashSDKEnvironment) var zcashSDKEnvironment
@Dependency(\.mnemonic) var mnemonic
@Dependency(\.walletStorage) var walletStorage
enum Action: Equatable, BindableAction { enum Action: Equatable, BindableAction {
case binding(BindingAction<ImportWalletReducer.State>) case binding(BindingAction<ImportWalletReducer.State>)
case dismissAlert case dismissAlert
@ -50,7 +46,11 @@ struct ImportWalletReducer: ReducerProtocol {
case onAppear case onAppear
case successfullyRecovered case successfullyRecovered
} }
@Dependency(\.zcashSDKEnvironment) var zcashSDKEnvironment
@Dependency(\.mnemonic) var mnemonic
@Dependency(\.walletStorage) var walletStorage
var body: some ReducerProtocol<State, Action> { var body: some ReducerProtocol<State, Action> {
BindingReducer() BindingReducer()

View File

@ -38,11 +38,6 @@ struct RecoveryPhraseValidationFlowReducer: ReducerProtocol {
return resultingPhrase == phrase.words return resultingPhrase == phrase.words
} }
} }
@Dependency(\.randomPhrase) var randomPhrase
@Dependency(\.mainQueue) var mainQueue
@Dependency(\.pasteboard) var pasteboard
@Dependency(\.feedbackGenerator) var feedbackGenerator
enum Action: Equatable { enum Action: Equatable {
case updateRoute(RecoveryPhraseValidationFlowReducer.State.Route?) case updateRoute(RecoveryPhraseValidationFlowReducer.State.Route?)
@ -55,6 +50,12 @@ struct RecoveryPhraseValidationFlowReducer: ReducerProtocol {
case displayBackedUpPhrase case displayBackedUpPhrase
} }
@Dependency(\.randomPhrase) var randomPhrase
@Dependency(\.mainQueue) var mainQueue
@Dependency(\.pasteboard) var pasteboard
@Dependency(\.feedbackGenerator) var feedbackGenerator
// swiftlint:disable:next cyclomatic_complexity // swiftlint:disable:next cyclomatic_complexity
func reduce(into state: inout State, action: Action) -> ComposableArchitecture.EffectTask<Action> { func reduce(into state: inout State, action: Action) -> ComposableArchitecture.EffectTask<Action> {
switch action { switch action {

View File

@ -16,7 +16,7 @@ struct SandboxState: Equatable {
case scan case scan
case request case request
} }
var walletEventsState: WalletEventsFlowState var walletEventsState: WalletEventsFlowReducer.State
var profileState: ProfileState var profileState: ProfileState
var route: Route? var route: Route?
} }
@ -25,7 +25,7 @@ struct SandboxState: Equatable {
enum SandboxAction: Equatable { enum SandboxAction: Equatable {
case updateRoute(SandboxState.Route?) case updateRoute(SandboxState.Route?)
case walletEvents(WalletEventsFlowAction) case walletEvents(WalletEventsFlowReducer.Action)
case profile(ProfileAction) case profile(ProfileAction)
case reset case reset
} }
@ -42,20 +42,12 @@ extension SandboxReducer {
case let .updateRoute(route): case let .updateRoute(route):
state.route = route state.route = route
return .none return .none
case let .walletEvents(walletEventsAction): case let .walletEvents(walletEventsAction):
return WalletEventsFlowReducer return WalletEventsFlowReducer()
.default .reduce(into: &state.walletEventsState, action: walletEventsAction)
.run(
&state.walletEventsState,
walletEventsAction,
WalletEventsFlowEnvironment(
pasteboard: .live,
scheduler: DispatchQueue.main.eraseToAnyScheduler(),
SDKSynchronizer: LiveWrappedSDKSynchronizer(),
zcashSDKEnvironment: .testnet
)
)
.map(SandboxAction.walletEvents) .map(SandboxAction.walletEvents)
case let .profile(profileAction): case let .profile(profileAction):
return ProfileReducer return ProfileReducer
.default .default
@ -65,6 +57,7 @@ extension SandboxReducer {
environment: { _ in ProfileEnvironment.live } environment: { _ in ProfileEnvironment.live }
) )
.run(&state, action, ()) .run(&state, action, ())
case .reset: case .reset:
return .none return .none
} }
@ -95,14 +88,14 @@ extension SandboxViewStore {
func toggleSelectedTransaction() { func toggleSelectedTransaction() {
let isAlreadySelected = (self.selectedTranactionID != nil) let isAlreadySelected = (self.selectedTranactionID != nil)
let walletEvent = self.walletEventsState.walletEvents[5] let walletEvent = self.walletEventsState.walletEvents[5]
let newRoute = isAlreadySelected ? nil : WalletEventsFlowState.Route.showWalletEvent(walletEvent) let newRoute = isAlreadySelected ? nil : WalletEventsFlowReducer.State.Route.showWalletEvent(walletEvent)
send(.walletEvents(.updateRoute(newRoute))) send(.walletEvents(.updateRoute(newRoute)))
} }
var selectedTranactionID: String? { var selectedTranactionID: String? {
self.walletEventsState self.walletEventsState
.route .route
.flatMap(/WalletEventsFlowState.Route.showWalletEvent) .flatMap(/WalletEventsFlowReducer.State.Route.showWalletEvent)
.map(\.id) .map(\.id)
} }

View File

@ -2,80 +2,70 @@ import ComposableArchitecture
import SwiftUI import SwiftUI
import ZcashLightClientKit import ZcashLightClientKit
typealias WalletEventsFlowReducer = Reducer<WalletEventsFlowState, WalletEventsFlowAction, WalletEventsFlowEnvironment> typealias WalletEventsFlowStore = Store<WalletEventsFlowReducer.State, WalletEventsFlowReducer.Action>
typealias WalletEventsFlowStore = Store<WalletEventsFlowState, WalletEventsFlowAction> typealias WalletEventsFlowViewStore = ViewStore<WalletEventsFlowReducer.State, WalletEventsFlowReducer.Action>
typealias WalletEventsFlowViewStore = ViewStore<WalletEventsFlowState, WalletEventsFlowAction>
// MARK: - State struct WalletEventsFlowReducer: ReducerProtocol {
private enum CancelId {}
struct WalletEventsFlowState: Equatable { struct State: Equatable {
enum Route: Equatable { enum Route: Equatable {
case latest case latest
case all case all
case showWalletEvent(WalletEvent) case showWalletEvent(WalletEvent)
}
var route: Route?
@BindableState var alert: AlertState<WalletEventsFlowReducer.Action>?
var latestMinedHeight: BlockHeight?
var isScrollable = false
var requiredTransactionConfirmations = 0
var walletEvents = IdentifiedArrayOf<WalletEvent>.placeholder
var selectedWalletEvent: WalletEvent?
} }
var route: Route? enum Action: Equatable {
case copyToPastboard(String)
@BindableState var alert: AlertState<WalletEventsFlowAction>? case dismissAlert
var latestMinedHeight: BlockHeight? case onAppear
var isScrollable = false case onDisappear
var requiredTransactionConfirmations = 0 case openBlockExplorer(URL?)
var walletEvents = IdentifiedArrayOf<WalletEvent>.placeholder case updateRoute(WalletEventsFlowReducer.State.Route?)
var selectedWalletEvent: WalletEvent? case replyTo(String)
} case synchronizerStateChanged(WrappedSDKSynchronizerState)
case updateWalletEvents([WalletEvent])
// MARK: - Action case warnBeforeLeavingApp(URL?)
}
enum WalletEventsFlowAction: Equatable {
case copyToPastboard(String)
case dismissAlert
case onAppear
case onDisappear
case openBlockExplorer(URL?)
case updateRoute(WalletEventsFlowState.Route?)
case replyTo(String)
case synchronizerStateChanged(WrappedSDKSynchronizerState)
case updateWalletEvents([WalletEvent])
case warnBeforeLeavingApp(URL?)
}
// MARK: - Environment
struct WalletEventsFlowEnvironment {
let pasteboard: WrappedPasteboard
let scheduler: AnySchedulerOf<DispatchQueue>
let SDKSynchronizer: WrappedSDKSynchronizer
let zcashSDKEnvironment: ZCashSDKEnvironment
}
// MARK: - Reducer
extension WalletEventsFlowReducer {
private struct CancelId: Hashable {}
static let `default` = WalletEventsFlowReducer { state, action, environment in @Dependency(\.pasteboard) var pasteboard
@Dependency(\.mainQueue) var mainQueue
@Dependency(\.sdkSynchronizer) var sdkSynchronizer
@Dependency(\.zcashSDKEnvironment) var zcashSDKEnvironment
// swiftlint:disable:next cyclomatic_complexity
func reduce(into state: inout State, action: Action) -> ComposableArchitecture.EffectTask<Action> {
switch action { switch action {
case .onAppear: case .onAppear:
state.requiredTransactionConfirmations = environment.zcashSDKEnvironment.requiredTransactionConfirmations state.requiredTransactionConfirmations = zcashSDKEnvironment.requiredTransactionConfirmations
return environment.SDKSynchronizer.stateChanged return sdkSynchronizer.stateChanged
.map(WalletEventsFlowAction.synchronizerStateChanged) .map(WalletEventsFlowReducer.Action.synchronizerStateChanged)
.eraseToEffect() .eraseToEffect()
.cancellable(id: CancelId(), cancelInFlight: true) .cancellable(id: CancelId.self, cancelInFlight: true)
case .onDisappear: case .onDisappear:
return Effect.cancel(id: CancelId()) return Effect.cancel(id: CancelId.self)
case .synchronizerStateChanged(.synced): case .synchronizerStateChanged(.synced):
if let latestMinedHeight = environment.SDKSynchronizer.synchronizer?.latestScannedHeight { if let latestMinedHeight = sdkSynchronizer.synchronizer?.latestScannedHeight {
state.latestMinedHeight = latestMinedHeight state.latestMinedHeight = latestMinedHeight
} }
return environment.SDKSynchronizer.getAllTransactions() return sdkSynchronizer.getAllTransactions()
.receive(on: environment.scheduler) .receive(on: mainQueue)
.map(WalletEventsFlowAction.updateWalletEvents) .map(WalletEventsFlowReducer.Action.updateWalletEvents)
.eraseToEffect() .eraseToEffect()
case .synchronizerStateChanged(let synchronizerState): case .synchronizerStateChanged:
return .none return .none
case .updateWalletEvents(let walletEvents): case .updateWalletEvents(let walletEvents):
@ -99,10 +89,10 @@ extension WalletEventsFlowReducer {
return .none return .none
case .copyToPastboard(let value): case .copyToPastboard(let value):
environment.pasteboard.setString(value) pasteboard.setString(value)
return .none return .none
case .replyTo(let address): case .replyTo:
return .none return .none
case .dismissAlert: case .dismissAlert:
@ -140,7 +130,7 @@ extension WalletEventsFlowReducer {
// MARK: - ViewStore // MARK: - ViewStore
extension WalletEventsFlowViewStore { extension WalletEventsFlowViewStore {
private typealias Route = WalletEventsFlowState.Route private typealias Route = WalletEventsFlowReducer.State.Route
func bindingForSelectedWalletEvent(_ walletEvent: WalletEvent?) -> Binding<Bool> { func bindingForSelectedWalletEvent(_ walletEvent: WalletEvent?) -> Binding<Bool> {
self.binding( self.binding(
@ -149,14 +139,14 @@ extension WalletEventsFlowViewStore {
return false return false
} }
return $0.route.map(/WalletEventsFlowState.Route.showWalletEvent) == walletEvent return $0.route.map(/WalletEventsFlowReducer.State.Route.showWalletEvent) == walletEvent
}, },
send: { isActive in send: { isActive in
guard let walletEvent = walletEvent else { guard let walletEvent = walletEvent else {
return WalletEventsFlowAction.updateRoute(nil) return WalletEventsFlowReducer.Action.updateRoute(nil)
} }
return WalletEventsFlowAction.updateRoute( isActive ? WalletEventsFlowState.Route.showWalletEvent(walletEvent) : nil) return WalletEventsFlowReducer.Action.updateRoute( isActive ? WalletEventsFlowReducer.State.Route.showWalletEvent(walletEvent) : nil)
} }
) )
} }
@ -188,7 +178,7 @@ extension TransactionState {
} }
} }
extension WalletEventsFlowState { extension WalletEventsFlowReducer.State {
static var placeHolder: Self { static var placeHolder: Self {
.init(walletEvents: .placeholder) .init(walletEvents: .placeholder)
} }
@ -199,16 +189,11 @@ extension WalletEventsFlowState {
} }
extension WalletEventsFlowStore { extension WalletEventsFlowStore {
static var placeholder: Store<WalletEventsFlowState, WalletEventsFlowAction> { static var placeholder: Store<WalletEventsFlowReducer.State, WalletEventsFlowReducer.Action> {
return Store( return Store(
initialState: .placeHolder, initialState: .placeHolder,
reducer: .default, reducer: WalletEventsFlowReducer()
environment: WalletEventsFlowEnvironment( .dependency(\.zcashSDKEnvironment, .testnet)
pasteboard: .live,
scheduler: DispatchQueue.main.eraseToAnyScheduler(),
SDKSynchronizer: LiveWrappedSDKSynchronizer(),
zcashSDKEnvironment: .testnet
)
) )
} }
} }

View File

@ -99,19 +99,10 @@ class WalletEventsSnapshotTests: XCTestCase {
environment: .demo environment: .demo
) )
// wallet event detail
let testEnvironment = WalletEventsFlowEnvironment(
pasteboard: .test,
scheduler: DispatchQueue.test.eraseToAnyScheduler(),
SDKSynchronizer: TestWrappedSDKSynchronizer(),
zcashSDKEnvironment: .testnet
)
ViewStore(store).send(.walletEvents(.updateRoute(.showWalletEvent(walletEvent)))) ViewStore(store).send(.walletEvents(.updateRoute(.showWalletEvent(walletEvent))))
let walletEventsStore = WalletEventsFlowStore( let walletEventsStore = WalletEventsFlowStore(
initialState: .placeHolder, initialState: .placeHolder,
reducer: .default, reducer: WalletEventsFlowReducer()
environment: testEnvironment
) )
addAttachments( addAttachments(
@ -156,19 +147,10 @@ class WalletEventsSnapshotTests: XCTestCase {
environment: .demo environment: .demo
) )
// wallet event detail
let testEnvironment = WalletEventsFlowEnvironment(
pasteboard: .test,
scheduler: DispatchQueue.test.eraseToAnyScheduler(),
SDKSynchronizer: TestWrappedSDKSynchronizer(),
zcashSDKEnvironment: .testnet
)
ViewStore(store).send(.walletEvents(.updateRoute(.showWalletEvent(walletEvent)))) ViewStore(store).send(.walletEvents(.updateRoute(.showWalletEvent(walletEvent))))
let walletEventsStore = WalletEventsFlowStore( let walletEventsStore = WalletEventsFlowStore(
initialState: .placeHolder, initialState: .placeHolder,
reducer: .default, reducer: WalletEventsFlowReducer()
environment: testEnvironment
) )
addAttachments( addAttachments(
@ -213,15 +195,7 @@ class WalletEventsSnapshotTests: XCTestCase {
environment: .demo environment: .demo
) )
// wallet event detail let walletEventsState = WalletEventsFlowReducer.State(
let testEnvironment = WalletEventsFlowEnvironment(
pasteboard: .test,
scheduler: DispatchQueue.test.eraseToAnyScheduler(),
SDKSynchronizer: TestWrappedSDKSynchronizer(),
zcashSDKEnvironment: .testnet
)
let walletEventsState = WalletEventsFlowState(
requiredTransactionConfirmations: 10, requiredTransactionConfirmations: 10,
walletEvents: .placeholder walletEvents: .placeholder
) )
@ -229,8 +203,7 @@ class WalletEventsSnapshotTests: XCTestCase {
ViewStore(store).send(.walletEvents(.updateRoute(.showWalletEvent(walletEvent)))) ViewStore(store).send(.walletEvents(.updateRoute(.showWalletEvent(walletEvent))))
let walletEventsStore = WalletEventsFlowStore( let walletEventsStore = WalletEventsFlowStore(
initialState: walletEventsState, initialState: walletEventsState,
reducer: .default, reducer: WalletEventsFlowReducer()
environment: testEnvironment
) )
addAttachments( addAttachments(
@ -276,19 +249,10 @@ class WalletEventsSnapshotTests: XCTestCase {
environment: .demo environment: .demo
) )
// wallet event detail
let testEnvironment = WalletEventsFlowEnvironment(
pasteboard: .test,
scheduler: DispatchQueue.test.eraseToAnyScheduler(),
SDKSynchronizer: TestWrappedSDKSynchronizer(),
zcashSDKEnvironment: .testnet
)
ViewStore(store).send(.walletEvents(.updateRoute(.showWalletEvent(walletEvent)))) ViewStore(store).send(.walletEvents(.updateRoute(.showWalletEvent(walletEvent))))
let walletEventsStore = WalletEventsFlowStore( let walletEventsStore = WalletEventsFlowStore(
initialState: .placeHolder, initialState: .placeHolder,
reducer: .default, reducer: WalletEventsFlowReducer()
environment: testEnvironment
) )
addAttachments( addAttachments(

View File

@ -13,22 +13,14 @@ import ZcashLightClientKit
class WalletEventsTests: XCTestCase { class WalletEventsTests: XCTestCase {
static let testScheduler = DispatchQueue.test static let testScheduler = DispatchQueue.test
let testEnvironment = WalletEventsFlowEnvironment(
pasteboard: .test,
scheduler: testScheduler.eraseToAnyScheduler(),
SDKSynchronizer: TestWrappedSDKSynchronizer(),
zcashSDKEnvironment: .testnet
)
func testSynchronizerSubscription() throws { func testSynchronizerSubscription() throws {
let store = TestStore( let store = TestStore(
initialState: WalletEventsFlowState( initialState: WalletEventsFlowReducer.State(
route: .latest, route: .latest,
isScrollable: true, isScrollable: true,
walletEvents: [] walletEvents: []
), ),
reducer: WalletEventsFlowReducer.default, reducer: WalletEventsFlowReducer()
environment: testEnvironment
) )
store.send(.onAppear) { state in store.send(.onAppear) { state in
@ -78,13 +70,14 @@ class WalletEventsTests: XCTestCase {
let identifiedWalletEvents = IdentifiedArrayOf(uniqueElements: walletEvents) let identifiedWalletEvents = IdentifiedArrayOf(uniqueElements: walletEvents)
let store = TestStore( let store = TestStore(
initialState: WalletEventsFlowState( initialState: WalletEventsFlowReducer.State(
route: .latest, route: .latest,
isScrollable: true, isScrollable: true,
walletEvents: identifiedWalletEvents walletEvents: identifiedWalletEvents
), ),
reducer: WalletEventsFlowReducer.default, reducer: WalletEventsFlowReducer()
environment: testEnvironment .dependency(\.sdkSynchronizer, TestWrappedSDKSynchronizer())
.dependency(\.mainQueue, WalletEventsTests.testScheduler.eraseToAnyScheduler())
) )
store.send(.synchronizerStateChanged(.synced)) store.send(.synchronizerStateChanged(.synced))
@ -107,21 +100,13 @@ class WalletEventsTests: XCTestCase {
func testCopyToPasteboard() throws { func testCopyToPasteboard() throws {
let pasteboard = WrappedPasteboard.test let pasteboard = WrappedPasteboard.test
let testEnvironment = WalletEventsFlowEnvironment(
pasteboard: pasteboard,
scheduler: DispatchQueue.test.eraseToAnyScheduler(),
SDKSynchronizer: TestWrappedSDKSynchronizer(),
zcashSDKEnvironment: .testnet
)
let store = TestStore( let store = TestStore(
initialState: WalletEventsFlowState( initialState: WalletEventsFlowReducer.State(
route: .latest, route: .latest,
isScrollable: true, isScrollable: true,
walletEvents: [] walletEvents: []
), ),
reducer: WalletEventsFlowReducer.default, reducer: WalletEventsFlowReducer()
environment: testEnvironment
) )
let testText = "test text" let testText = "test text"