[408] Reduce dependency on TCA in the dependencies (#413)
Following dependencies refactored to await/async - RecoveryPhraseValidationFlowReducer - RecoveryPhraseDisplayStore - AppStore - UserPreferencesStorage - WrappedUserDefaults which allowed to reduce imports of Combine/TCA
This commit is contained in:
parent
4c36aa39a2
commit
558675aced
|
@ -6,7 +6,6 @@
|
||||||
//
|
//
|
||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
import ComposableArchitecture
|
|
||||||
|
|
||||||
/// Live implementation of the `UserPreferences` using User Defaults
|
/// Live implementation of the `UserPreferences` using User Defaults
|
||||||
/// according to https://developer.apple.com/documentation/foundation/userdefaults
|
/// according to https://developer.apple.com/documentation/foundation/userdefaults
|
||||||
|
@ -50,8 +49,8 @@ struct UserPreferencesStorage {
|
||||||
getValue(forKey: Constants.zcashActiveAppSessionFrom.rawValue, default: appSessionFrom)
|
getValue(forKey: Constants.zcashActiveAppSessionFrom.rawValue, default: appSessionFrom)
|
||||||
}
|
}
|
||||||
|
|
||||||
func setActiveAppSessionFrom(_ timeInterval: TimeInterval) -> Effect<Never, Never> {
|
func setActiveAppSessionFrom(_ timeInterval: TimeInterval) async {
|
||||||
setValue(timeInterval, forKey: Constants.zcashActiveAppSessionFrom.rawValue)
|
await setValue(timeInterval, forKey: Constants.zcashActiveAppSessionFrom.rawValue)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// What is the set up currency
|
/// What is the set up currency
|
||||||
|
@ -59,8 +58,8 @@ struct UserPreferencesStorage {
|
||||||
getValue(forKey: Constants.zcashCurrency.rawValue, default: convertedCurrency)
|
getValue(forKey: Constants.zcashCurrency.rawValue, default: convertedCurrency)
|
||||||
}
|
}
|
||||||
|
|
||||||
func setCurrency(_ string: String) -> Effect<Never, Never> {
|
func setCurrency(_ string: String) async {
|
||||||
setValue(string, forKey: Constants.zcashCurrency.rawValue)
|
await setValue(string, forKey: Constants.zcashCurrency.rawValue)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Whether the fiat conversion is on/off
|
/// Whether the fiat conversion is on/off
|
||||||
|
@ -68,8 +67,8 @@ struct UserPreferencesStorage {
|
||||||
getValue(forKey: Constants.zcashFiatConverted.rawValue, default: fiatConvertion)
|
getValue(forKey: Constants.zcashFiatConverted.rawValue, default: fiatConvertion)
|
||||||
}
|
}
|
||||||
|
|
||||||
func setIsFiatConverted(_ bool: Bool) -> Effect<Never, Never> {
|
func setIsFiatConverted(_ bool: Bool) async {
|
||||||
setValue(bool, forKey: Constants.zcashFiatConverted.rawValue)
|
await setValue(bool, forKey: Constants.zcashFiatConverted.rawValue)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Whether user finished recovery phrase backup test
|
/// Whether user finished recovery phrase backup test
|
||||||
|
@ -77,8 +76,8 @@ struct UserPreferencesStorage {
|
||||||
getValue(forKey: Constants.zcashRecoveryPhraseTestCompleted.rawValue, default: recoveryPhraseTestCompleted)
|
getValue(forKey: Constants.zcashRecoveryPhraseTestCompleted.rawValue, default: recoveryPhraseTestCompleted)
|
||||||
}
|
}
|
||||||
|
|
||||||
func setIsRecoveryPhraseTestCompleted(_ bool: Bool) -> Effect<Never, Never> {
|
func setIsRecoveryPhraseTestCompleted(_ bool: Bool) async {
|
||||||
setValue(bool, forKey: Constants.zcashRecoveryPhraseTestCompleted.rawValue)
|
await setValue(bool, forKey: Constants.zcashRecoveryPhraseTestCompleted.rawValue)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Whether the user has been autoshielded in the running session
|
/// Whether the user has been autoshielded in the running session
|
||||||
|
@ -86,17 +85,15 @@ struct UserPreferencesStorage {
|
||||||
getValue(forKey: Constants.zcashSessionAutoshielded.rawValue, default: sessionAutoshielded)
|
getValue(forKey: Constants.zcashSessionAutoshielded.rawValue, default: sessionAutoshielded)
|
||||||
}
|
}
|
||||||
|
|
||||||
func setIsSessionAutoshielded(_ bool: Bool) -> Effect<Never, Never> {
|
func setIsSessionAutoshielded(_ bool: Bool) async {
|
||||||
setValue(bool, forKey: Constants.zcashSessionAutoshielded.rawValue)
|
await setValue(bool, forKey: Constants.zcashSessionAutoshielded.rawValue)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Use carefully: Deletes all user preferences from the User Defaults
|
/// Use carefully: Deletes all user preferences from the User Defaults
|
||||||
func removeAll() -> Effect<Never, Never> {
|
func removeAll() async {
|
||||||
var removals: [Effect<Never, Never>] = []
|
for key in Constants.allCases {
|
||||||
|
await userDefaults.remove(key.rawValue)
|
||||||
Constants.allCases.forEach { removals.append(userDefaults.remove($0.rawValue)) }
|
}
|
||||||
|
|
||||||
return Effect.concatenate(removals)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -105,11 +102,9 @@ private extension UserPreferencesStorage {
|
||||||
userDefaults.objectForKey(forKey) as? Value ?? defaultIfNil
|
userDefaults.objectForKey(forKey) as? Value ?? defaultIfNil
|
||||||
}
|
}
|
||||||
|
|
||||||
func setValue<Value>(_ value: Value, forKey: String) -> Effect<Never, Never> {
|
func setValue<Value>(_ value: Value, forKey: String) async {
|
||||||
let effect = userDefaults.setValue(value, forKey)
|
await userDefaults.setValue(value, forKey)
|
||||||
_ = userDefaults.synchronize()
|
_ = await userDefaults.synchronize()
|
||||||
|
|
||||||
return effect
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -322,11 +322,12 @@ extension AppReducer {
|
||||||
// (https://github.com/zcash/secant-ios-wallet/issues/370)
|
// (https://github.com/zcash/secant-ios-wallet/issues/370)
|
||||||
return .none
|
return .none
|
||||||
}
|
}
|
||||||
do {
|
return .run { send in
|
||||||
return try process(url: url, with: environment)
|
do {
|
||||||
} catch {
|
await send(try await process(url: url, with: environment))
|
||||||
// TODO: error we need to handle, issue #221 (https://github.com/zcash/secant-ios-wallet/issues/221)
|
} catch {
|
||||||
return .none
|
// TODO: error we need to handle, issue #221 (https://github.com/zcash/secant-ios-wallet/issues/221)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
case .deeplinkHome:
|
case .deeplinkHome:
|
||||||
|
@ -391,7 +392,6 @@ extension AppReducer {
|
||||||
environment: { environment in
|
environment: { environment in
|
||||||
RecoveryPhraseValidationFlowEnvironment(
|
RecoveryPhraseValidationFlowEnvironment(
|
||||||
scheduler: environment.scheduler,
|
scheduler: environment.scheduler,
|
||||||
newPhrase: { Effect(value: .init(words: RecoveryPhrase.placeholder.words)) },
|
|
||||||
pasteboard: .test,
|
pasteboard: .test,
|
||||||
feedbackGenerator: .silent,
|
feedbackGenerator: .silent,
|
||||||
recoveryPhraseRandomizer: environment.recoveryPhraseRandomizer
|
recoveryPhraseRandomizer: environment.recoveryPhraseRandomizer
|
||||||
|
@ -405,7 +405,7 @@ extension AppReducer {
|
||||||
environment: { environment in
|
environment: { environment in
|
||||||
RecoveryPhraseDisplayEnvironment(
|
RecoveryPhraseDisplayEnvironment(
|
||||||
scheduler: environment.scheduler,
|
scheduler: environment.scheduler,
|
||||||
newPhrase: { Effect(value: .init(words: RecoveryPhrase.placeholder.words)) },
|
newPhrase: { .init(words: RecoveryPhrase.placeholder.words) },
|
||||||
pasteboard: .live,
|
pasteboard: .live,
|
||||||
feedbackGenerator: environment.feedbackGenerator
|
feedbackGenerator: environment.feedbackGenerator
|
||||||
)
|
)
|
||||||
|
@ -493,15 +493,15 @@ extension AppReducer {
|
||||||
throw SDKInitializationError.failed
|
throw SDKInitializationError.failed
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static func process(url: URL, with environment: AppEnvironment) throws -> Effect<AppAction, Never> {
|
static func process(url: URL, with environment: AppEnvironment) async throws -> AppAction {
|
||||||
let deeplink = try environment.deeplinkHandler.resolveDeeplinkURL(url, environment.derivationTool)
|
let deeplink = try environment.deeplinkHandler.resolveDeeplinkURL(url, environment.derivationTool)
|
||||||
|
|
||||||
switch deeplink {
|
switch deeplink {
|
||||||
case .home:
|
case .home:
|
||||||
return Effect(value: .deeplinkHome)
|
return .deeplinkHome
|
||||||
case let .send(amount, address, memo):
|
case let .send(amount, address, memo):
|
||||||
return Effect(value: .deeplinkSend(Zatoshi(amount), address, memo))
|
return .deeplinkSend(Zatoshi(amount), address, memo)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,14 +25,14 @@ enum RecoveryPhraseDisplayAction: Equatable {
|
||||||
case createPhrase
|
case createPhrase
|
||||||
case copyToBufferPressed
|
case copyToBufferPressed
|
||||||
case finishedPressed
|
case finishedPressed
|
||||||
case phraseResponse(Result<RecoveryPhrase, RecoveryPhraseError>)
|
case phraseResponse(RecoveryPhrase)
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - Environment
|
// MARK: - Environment
|
||||||
|
|
||||||
struct RecoveryPhraseDisplayEnvironment {
|
struct RecoveryPhraseDisplayEnvironment {
|
||||||
let scheduler: AnySchedulerOf<DispatchQueue>
|
let scheduler: AnySchedulerOf<DispatchQueue>
|
||||||
let newPhrase: () -> Effect<RecoveryPhrase, RecoveryPhraseError>
|
let newPhrase: () async throws -> RecoveryPhrase
|
||||||
let pasteboard: WrappedPasteboard
|
let pasteboard: WrappedPasteboard
|
||||||
let feedbackGenerator: WrappedFeedbackGenerator
|
let feedbackGenerator: WrappedFeedbackGenerator
|
||||||
}
|
}
|
||||||
|
@ -40,7 +40,7 @@ struct RecoveryPhraseDisplayEnvironment {
|
||||||
extension RecoveryPhraseDisplayEnvironment {
|
extension RecoveryPhraseDisplayEnvironment {
|
||||||
static let demo = Self(
|
static let demo = Self(
|
||||||
scheduler: DispatchQueue.main.eraseToAnyScheduler(),
|
scheduler: DispatchQueue.main.eraseToAnyScheduler(),
|
||||||
newPhrase: { Effect(value: .init(words: RecoveryPhrase.placeholder.words)) },
|
newPhrase: { .init(words: RecoveryPhrase.placeholder.words) },
|
||||||
pasteboard: .test,
|
pasteboard: .test,
|
||||||
feedbackGenerator: .silent
|
feedbackGenerator: .silent
|
||||||
)
|
)
|
||||||
|
@ -52,23 +52,27 @@ extension RecoveryPhraseDisplayReducer {
|
||||||
static let `default` = RecoveryPhraseDisplayReducer { state, action, environment in
|
static let `default` = RecoveryPhraseDisplayReducer { state, action, environment in
|
||||||
switch action {
|
switch action {
|
||||||
case .createPhrase:
|
case .createPhrase:
|
||||||
return environment.newPhrase()
|
return .run { send in
|
||||||
.receive(on: environment.scheduler)
|
do {
|
||||||
.catchToEffect(RecoveryPhraseDisplayAction.phraseResponse)
|
await send(.phraseResponse(try await environment.newPhrase()))
|
||||||
|
} catch {
|
||||||
|
// TODO: remove this when feature is implemented in https://github.com/zcash/secant-ios-wallet/issues/129
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
case .copyToBufferPressed:
|
case .copyToBufferPressed:
|
||||||
guard let phrase = state.phrase?.toString() else { return .none }
|
guard let phrase = state.phrase?.toString() else { return .none }
|
||||||
environment.pasteboard.setString(phrase)
|
environment.pasteboard.setString(phrase)
|
||||||
state.showCopyToBufferAlert = true
|
state.showCopyToBufferAlert = true
|
||||||
return .none
|
return .none
|
||||||
|
|
||||||
case .finishedPressed:
|
case .finishedPressed:
|
||||||
// TODO: remove this when feature is implemented in https://github.com/zcash/secant-ios-wallet/issues/47
|
// TODO: remove this when feature is implemented in https://github.com/zcash/secant-ios-wallet/issues/47
|
||||||
return .none
|
return .none
|
||||||
case let .phraseResponse(.success(phrase)):
|
|
||||||
|
case let .phraseResponse(phrase):
|
||||||
state.phrase = phrase
|
state.phrase = phrase
|
||||||
return .none
|
return .none
|
||||||
case .phraseResponse(.failure):
|
|
||||||
// TODO: remove this when feature is implemented in https://github.com/zcash/secant-ios-wallet/issues/129
|
|
||||||
return .none
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -112,7 +112,6 @@ enum RecoveryPhraseValidationFlowAction: Equatable {
|
||||||
|
|
||||||
struct RecoveryPhraseValidationFlowEnvironment {
|
struct RecoveryPhraseValidationFlowEnvironment {
|
||||||
let scheduler: AnySchedulerOf<DispatchQueue>
|
let scheduler: AnySchedulerOf<DispatchQueue>
|
||||||
let newPhrase: () -> Effect<RecoveryPhrase, RecoveryPhraseError>
|
|
||||||
let pasteboard: WrappedPasteboard
|
let pasteboard: WrappedPasteboard
|
||||||
let feedbackGenerator: WrappedFeedbackGenerator
|
let feedbackGenerator: WrappedFeedbackGenerator
|
||||||
let recoveryPhraseRandomizer: WrappedRecoveryPhraseRandomizer
|
let recoveryPhraseRandomizer: WrappedRecoveryPhraseRandomizer
|
||||||
|
@ -121,7 +120,6 @@ struct RecoveryPhraseValidationFlowEnvironment {
|
||||||
extension RecoveryPhraseValidationFlowEnvironment {
|
extension RecoveryPhraseValidationFlowEnvironment {
|
||||||
static let demo = Self(
|
static let demo = Self(
|
||||||
scheduler: DispatchQueue.main.eraseToAnyScheduler(),
|
scheduler: DispatchQueue.main.eraseToAnyScheduler(),
|
||||||
newPhrase: { Effect(value: .init(words: RecoveryPhrase.placeholder.words)) },
|
|
||||||
pasteboard: .test,
|
pasteboard: .test,
|
||||||
feedbackGenerator: .silent,
|
feedbackGenerator: .silent,
|
||||||
recoveryPhraseRandomizer: .live
|
recoveryPhraseRandomizer: .live
|
||||||
|
@ -129,7 +127,6 @@ extension RecoveryPhraseValidationFlowEnvironment {
|
||||||
|
|
||||||
static let live = Self(
|
static let live = Self(
|
||||||
scheduler: DispatchQueue.main.eraseToAnyScheduler(),
|
scheduler: DispatchQueue.main.eraseToAnyScheduler(),
|
||||||
newPhrase: { Effect(value: .init(words: RecoveryPhrase.placeholder.words)) },
|
|
||||||
pasteboard: .live,
|
pasteboard: .live,
|
||||||
feedbackGenerator: .haptic,
|
feedbackGenerator: .haptic,
|
||||||
recoveryPhraseRandomizer: .live
|
recoveryPhraseRandomizer: .live
|
||||||
|
|
|
@ -6,13 +6,12 @@
|
||||||
//
|
//
|
||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
import ComposableArchitecture
|
|
||||||
|
|
||||||
struct WrappedUserDefaults {
|
struct WrappedUserDefaults {
|
||||||
let objectForKey: (String) -> Any?
|
let objectForKey: @Sendable (String) -> Any?
|
||||||
let remove: (String) -> Effect<Never, Never>
|
let remove: @Sendable (String) async -> Void
|
||||||
let setValue: (Any?, String) -> Effect<Never, Never>
|
let setValue: @Sendable (Any?, String) async -> Void
|
||||||
let synchronize: () -> Bool
|
let synchronize: @Sendable () async -> Bool
|
||||||
}
|
}
|
||||||
|
|
||||||
extension WrappedUserDefaults {
|
extension WrappedUserDefaults {
|
||||||
|
@ -20,25 +19,17 @@ extension WrappedUserDefaults {
|
||||||
userDefaults: UserDefaults = .standard
|
userDefaults: UserDefaults = .standard
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self(
|
Self(
|
||||||
objectForKey: userDefaults.object(forKey:),
|
objectForKey: { userDefaults.object(forKey: $0) },
|
||||||
remove: { key in
|
remove: { userDefaults.removeObject(forKey: $0) },
|
||||||
.fireAndForget {
|
setValue: { userDefaults.set($0, forKey: $1) },
|
||||||
userDefaults.removeObject(forKey: key)
|
synchronize: { userDefaults.synchronize() }
|
||||||
}
|
|
||||||
},
|
|
||||||
setValue: { value, key in
|
|
||||||
.fireAndForget {
|
|
||||||
userDefaults.set(value, forKey: key)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
synchronize: userDefaults.synchronize
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
static let mock = WrappedUserDefaults(
|
static let mock = WrappedUserDefaults(
|
||||||
objectForKey: { _ in },
|
objectForKey: { _ in },
|
||||||
remove: { _ in .none },
|
remove: { _ in },
|
||||||
setValue: { _, _ in .none },
|
setValue: { _, _ in },
|
||||||
synchronize: { true }
|
synchronize: { true }
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,7 +35,7 @@ class RecoveryPhraseDisplayReducerTests: XCTestCase {
|
||||||
environment: .demo
|
environment: .demo
|
||||||
)
|
)
|
||||||
|
|
||||||
store.send(.phraseResponse(.success(.placeholder))) {
|
store.send(.phraseResponse(.placeholder)) {
|
||||||
$0.phrase = .placeholder
|
$0.phrase = .placeholder
|
||||||
$0.showCopyToBufferAlert = false
|
$0.showCopyToBufferAlert = false
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,8 +9,8 @@ import XCTest
|
||||||
@testable import secant_testnet
|
@testable import secant_testnet
|
||||||
import ComposableArchitecture
|
import ComposableArchitecture
|
||||||
import ZcashLightClientKit
|
import ZcashLightClientKit
|
||||||
import Combine
|
|
||||||
|
|
||||||
|
@MainActor
|
||||||
class DeeplinkTests: XCTestCase {
|
class DeeplinkTests: XCTestCase {
|
||||||
func testActionDeeplinkHome_SameRouteLevel() throws {
|
func testActionDeeplinkHome_SameRouteLevel() throws {
|
||||||
let testEnvironment = AppEnvironment.mock
|
let testEnvironment = AppEnvironment.mock
|
||||||
|
@ -73,7 +73,7 @@ class DeeplinkTests: XCTestCase {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func testDeeplinkRequest_homeURL() throws {
|
func testDeeplinkRequest_homeURL() async throws {
|
||||||
let synchronizer = TestWrappedSDKSynchronizer()
|
let synchronizer = TestWrappedSDKSynchronizer()
|
||||||
synchronizer.updateStateChanged(.synced)
|
synchronizer.updateStateChanged(.synced)
|
||||||
|
|
||||||
|
@ -107,14 +107,16 @@ class DeeplinkTests: XCTestCase {
|
||||||
return XCTFail("Deeplink: 'testDeeplinkRequest_homeURL' URL is expected to be valid.")
|
return XCTFail("Deeplink: 'testDeeplinkRequest_homeURL' URL is expected to be valid.")
|
||||||
}
|
}
|
||||||
|
|
||||||
store.send(.deeplink(url))
|
await store.send(.deeplink(url))
|
||||||
|
|
||||||
store.receive(.deeplinkHome) { state in
|
await store.receive(.deeplinkHome) { state in
|
||||||
state.route = .home
|
state.route = .home
|
||||||
}
|
}
|
||||||
|
|
||||||
|
await store.finish()
|
||||||
}
|
}
|
||||||
|
|
||||||
func testDeeplinkRequest_sendURL_amount() throws {
|
func testDeeplinkRequest_sendURL_amount() async throws {
|
||||||
let synchronizer = TestWrappedSDKSynchronizer()
|
let synchronizer = TestWrappedSDKSynchronizer()
|
||||||
synchronizer.updateStateChanged(.synced)
|
synchronizer.updateStateChanged(.synced)
|
||||||
|
|
||||||
|
@ -148,22 +150,24 @@ class DeeplinkTests: XCTestCase {
|
||||||
return XCTFail("Deeplink: 'testDeeplinkRequest_sendURL_amount' URL is expected to be valid.")
|
return XCTFail("Deeplink: 'testDeeplinkRequest_sendURL_amount' URL is expected to be valid.")
|
||||||
}
|
}
|
||||||
|
|
||||||
store.send(.deeplink(url))
|
await store.send(.deeplink(url))
|
||||||
|
|
||||||
let amount = Zatoshi(123_000_000)
|
let amount = Zatoshi(123_000_000)
|
||||||
let address = ""
|
let address = ""
|
||||||
let memo = ""
|
let memo = ""
|
||||||
|
|
||||||
store.receive(.deeplinkSend(amount, address, memo)) { state in
|
await store.receive(.deeplinkSend(amount, address, memo)) { state in
|
||||||
state.route = .home
|
state.route = .home
|
||||||
state.homeState.route = .send
|
state.homeState.route = .send
|
||||||
state.homeState.sendState.amount = amount
|
state.homeState.sendState.amount = amount
|
||||||
state.homeState.sendState.address = address
|
state.homeState.sendState.address = address
|
||||||
state.homeState.sendState.memoState.text = memo
|
state.homeState.sendState.memoState.text = memo
|
||||||
}
|
}
|
||||||
|
|
||||||
|
await store.finish()
|
||||||
}
|
}
|
||||||
|
|
||||||
func testDeeplinkRequest_sendURL_allFields() throws {
|
func testDeeplinkRequest_sendURL_allFields() async throws {
|
||||||
let synchronizer = TestWrappedSDKSynchronizer()
|
let synchronizer = TestWrappedSDKSynchronizer()
|
||||||
synchronizer.updateStateChanged(.synced)
|
synchronizer.updateStateChanged(.synced)
|
||||||
|
|
||||||
|
@ -197,18 +201,20 @@ class DeeplinkTests: XCTestCase {
|
||||||
return XCTFail("Deeplink: 'testDeeplinkRequest_sendURL_amount' URL is expected to be valid.")
|
return XCTFail("Deeplink: 'testDeeplinkRequest_sendURL_amount' URL is expected to be valid.")
|
||||||
}
|
}
|
||||||
|
|
||||||
store.send(.deeplink(url))
|
await store.send(.deeplink(url))
|
||||||
|
|
||||||
let amount = Zatoshi(123_000_000)
|
let amount = Zatoshi(123_000_000)
|
||||||
let address = "address"
|
let address = "address"
|
||||||
let memo = "some text"
|
let memo = "some text"
|
||||||
|
|
||||||
store.receive(.deeplinkSend(amount, address, memo)) { state in
|
await store.receive(.deeplinkSend(amount, address, memo)) { state in
|
||||||
state.route = .home
|
state.route = .home
|
||||||
state.homeState.route = .send
|
state.homeState.route = .send
|
||||||
state.homeState.sendState.amount = amount
|
state.homeState.sendState.amount = amount
|
||||||
state.homeState.sendState.address = address
|
state.homeState.sendState.address = address
|
||||||
state.homeState.sendState.memoState.text = memo
|
state.homeState.sendState.memoState.text = memo
|
||||||
}
|
}
|
||||||
|
|
||||||
|
await store.finish()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,7 +14,6 @@ class RecoveryPhraseValidationTests: XCTestCase {
|
||||||
|
|
||||||
let testEnvironment = RecoveryPhraseValidationFlowEnvironment(
|
let testEnvironment = RecoveryPhraseValidationFlowEnvironment(
|
||||||
scheduler: testScheduler.eraseToAnyScheduler(),
|
scheduler: testScheduler.eraseToAnyScheduler(),
|
||||||
newPhrase: { Effect(value: .init(words: RecoveryPhrase.placeholder.words)) },
|
|
||||||
pasteboard: .test,
|
pasteboard: .test,
|
||||||
feedbackGenerator: .silent,
|
feedbackGenerator: .silent,
|
||||||
recoveryPhraseRandomizer: .live
|
recoveryPhraseRandomizer: .live
|
||||||
|
|
|
@ -7,16 +7,13 @@
|
||||||
|
|
||||||
import XCTest
|
import XCTest
|
||||||
@testable import secant_testnet
|
@testable import secant_testnet
|
||||||
import Combine
|
|
||||||
|
|
||||||
class UserPreferencesStorageTests: XCTestCase {
|
class UserPreferencesStorageTests: XCTestCase {
|
||||||
private var cancellables: [AnyCancellable] = []
|
|
||||||
|
|
||||||
// swiftlint:disable:next implicitly_unwrapped_optional
|
// swiftlint:disable:next implicitly_unwrapped_optional
|
||||||
var storage: UserPreferencesStorage!
|
var storage: UserPreferencesStorage!
|
||||||
|
|
||||||
override func setUp() {
|
override func setUp() async throws {
|
||||||
super.setUp()
|
try await super.setUp()
|
||||||
|
|
||||||
guard let userDefaults = UserDefaults.init(suiteName: "test") else {
|
guard let userDefaults = UserDefaults.init(suiteName: "test") else {
|
||||||
XCTFail("UserPreferencesStorageTests: UserDefaults.init(suiteName: \"test\") failed to initialize")
|
XCTFail("UserPreferencesStorageTests: UserDefaults.init(suiteName: \"test\") failed to initialize")
|
||||||
|
@ -31,16 +28,12 @@ class UserPreferencesStorageTests: XCTestCase {
|
||||||
sessionAutoshielded: false,
|
sessionAutoshielded: false,
|
||||||
userDefaults: .live(userDefaults: userDefaults)
|
userDefaults: .live(userDefaults: userDefaults)
|
||||||
)
|
)
|
||||||
storage.removeAll()
|
await storage.removeAll()
|
||||||
.sink(receiveValue: { _ in })
|
|
||||||
.store(in: &cancellables)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override func tearDown() {
|
override func tearDown() async throws {
|
||||||
super.tearDown()
|
try await super.tearDown()
|
||||||
storage.removeAll()
|
await storage.removeAll()
|
||||||
.sink(receiveValue: { _ in })
|
|
||||||
.store(in: &cancellables)
|
|
||||||
storage = nil
|
storage = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -68,42 +61,32 @@ class UserPreferencesStorageTests: XCTestCase {
|
||||||
|
|
||||||
// MARK: - Set new values in the live UserDefaults environment
|
// MARK: - Set new values in the live UserDefaults environment
|
||||||
|
|
||||||
func testAppSessionFrom_setNewValue() throws {
|
func testAppSessionFrom_setNewValue() async throws {
|
||||||
storage.setActiveAppSessionFrom(87654321.0)
|
await storage.setActiveAppSessionFrom(87654321.0)
|
||||||
.sink(receiveValue: { _ in })
|
|
||||||
.store(in: &cancellables)
|
|
||||||
|
|
||||||
XCTAssertEqual(87654321.0, storage.activeAppSessionFrom, "User Preferences: `activeAppSessionFrom` default doesn't match.")
|
XCTAssertEqual(87654321.0, storage.activeAppSessionFrom, "User Preferences: `activeAppSessionFrom` default doesn't match.")
|
||||||
}
|
}
|
||||||
|
|
||||||
func testConvertedCurrency_setNewValue() throws {
|
func testConvertedCurrency_setNewValue() async throws {
|
||||||
storage.setCurrency("CZK")
|
await storage.setCurrency("CZK")
|
||||||
.sink(receiveValue: { _ in })
|
|
||||||
.store(in: &cancellables)
|
|
||||||
|
|
||||||
XCTAssertEqual("CZK", storage.currency, "User Preferences: `currency` default doesn't match.")
|
XCTAssertEqual("CZK", storage.currency, "User Preferences: `currency` default doesn't match.")
|
||||||
}
|
}
|
||||||
|
|
||||||
func testFiatConvertion_setNewValue() throws {
|
func testFiatConvertion_setNewValue() async throws {
|
||||||
storage.setIsFiatConverted(false)
|
await storage.setIsFiatConverted(false)
|
||||||
.sink(receiveValue: { _ in })
|
|
||||||
.store(in: &cancellables)
|
|
||||||
|
|
||||||
XCTAssertEqual(false, storage.isFiatConverted, "User Preferences: `isFiatConverted` default doesn't match.")
|
XCTAssertEqual(false, storage.isFiatConverted, "User Preferences: `isFiatConverted` default doesn't match.")
|
||||||
}
|
}
|
||||||
|
|
||||||
func testRecoveryPhraseTestCompleted_setNewValue() throws {
|
func testRecoveryPhraseTestCompleted_setNewValue() async throws {
|
||||||
storage.setIsRecoveryPhraseTestCompleted(false)
|
await storage.setIsRecoveryPhraseTestCompleted(false)
|
||||||
.sink(receiveValue: { _ in })
|
|
||||||
.store(in: &cancellables)
|
|
||||||
|
|
||||||
XCTAssertEqual(false, storage.isRecoveryPhraseTestCompleted, "User Preferences: `isRecoveryPhraseTestCompleted` default doesn't match.")
|
XCTAssertEqual(false, storage.isRecoveryPhraseTestCompleted, "User Preferences: `isRecoveryPhraseTestCompleted` default doesn't match.")
|
||||||
}
|
}
|
||||||
|
|
||||||
func testSessionAutoshielded_setNewValue() throws {
|
func testSessionAutoshielded_setNewValue() async throws {
|
||||||
storage.setIsSessionAutoshielded(true)
|
await storage.setIsSessionAutoshielded(true)
|
||||||
.sink(receiveValue: { _ in })
|
|
||||||
.store(in: &cancellables)
|
|
||||||
|
|
||||||
XCTAssertEqual(true, storage.isSessionAutoshielded, "User Preferences: `isSessionAutoshielded` default doesn't match.")
|
XCTAssertEqual(true, storage.isSessionAutoshielded, "User Preferences: `isSessionAutoshielded` default doesn't match.")
|
||||||
}
|
}
|
||||||
|
@ -113,8 +96,8 @@ class UserPreferencesStorageTests: XCTestCase {
|
||||||
func testAppSessionFrom_mocked() throws {
|
func testAppSessionFrom_mocked() throws {
|
||||||
let mockedUD = WrappedUserDefaults(
|
let mockedUD = WrappedUserDefaults(
|
||||||
objectForKey: { _ in 87654321.0 },
|
objectForKey: { _ in 87654321.0 },
|
||||||
remove: { _ in .none },
|
remove: { _ in },
|
||||||
setValue: { _, _ in .none },
|
setValue: { _, _ in },
|
||||||
synchronize: { true }
|
synchronize: { true }
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -133,8 +116,8 @@ class UserPreferencesStorageTests: XCTestCase {
|
||||||
func testConvertedCurrency_mocked() throws {
|
func testConvertedCurrency_mocked() throws {
|
||||||
let mockedUD = WrappedUserDefaults(
|
let mockedUD = WrappedUserDefaults(
|
||||||
objectForKey: { _ in "CZK" },
|
objectForKey: { _ in "CZK" },
|
||||||
remove: { _ in .none },
|
remove: { _ in },
|
||||||
setValue: { _, _ in .none },
|
setValue: { _, _ in },
|
||||||
synchronize: { true }
|
synchronize: { true }
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -153,8 +136,8 @@ class UserPreferencesStorageTests: XCTestCase {
|
||||||
func testFiatConvertion_mocked() throws {
|
func testFiatConvertion_mocked() throws {
|
||||||
let mockedUD = WrappedUserDefaults(
|
let mockedUD = WrappedUserDefaults(
|
||||||
objectForKey: { _ in false },
|
objectForKey: { _ in false },
|
||||||
remove: { _ in .none },
|
remove: { _ in },
|
||||||
setValue: { _, _ in .none },
|
setValue: { _, _ in },
|
||||||
synchronize: { true }
|
synchronize: { true }
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -173,8 +156,8 @@ class UserPreferencesStorageTests: XCTestCase {
|
||||||
func testRecoveryPhraseTestCompleted_mocked() throws {
|
func testRecoveryPhraseTestCompleted_mocked() throws {
|
||||||
let mockedUD = WrappedUserDefaults(
|
let mockedUD = WrappedUserDefaults(
|
||||||
objectForKey: { _ in false },
|
objectForKey: { _ in false },
|
||||||
remove: { _ in .none },
|
remove: { _ in },
|
||||||
setValue: { _, _ in .none },
|
setValue: { _, _ in },
|
||||||
synchronize: { true }
|
synchronize: { true }
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -193,8 +176,8 @@ class UserPreferencesStorageTests: XCTestCase {
|
||||||
func testSessionAutoshielded_mocked() throws {
|
func testSessionAutoshielded_mocked() throws {
|
||||||
let mockedUD = WrappedUserDefaults(
|
let mockedUD = WrappedUserDefaults(
|
||||||
objectForKey: { _ in true },
|
objectForKey: { _ in true },
|
||||||
remove: { _ in .none },
|
remove: { _ in },
|
||||||
setValue: { _, _ in .none },
|
setValue: { _, _ in },
|
||||||
synchronize: { true }
|
synchronize: { true }
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -212,7 +195,7 @@ class UserPreferencesStorageTests: XCTestCase {
|
||||||
|
|
||||||
// MARK: - Remove all keys from the live UD environment
|
// MARK: - Remove all keys from the live UD environment
|
||||||
|
|
||||||
func testRemoveAll() throws {
|
func testRemoveAll() async throws {
|
||||||
guard let userDefaults = UserDefaults.init(suiteName: "test") else {
|
guard let userDefaults = UserDefaults.init(suiteName: "test") else {
|
||||||
XCTFail("User Preferences: UserDefaults.init(suiteName: \"test\") failed to initialize")
|
XCTFail("User Preferences: UserDefaults.init(suiteName: \"test\") failed to initialize")
|
||||||
return
|
return
|
||||||
|
@ -224,9 +207,7 @@ class UserPreferencesStorageTests: XCTestCase {
|
||||||
}
|
}
|
||||||
|
|
||||||
// remove it
|
// remove it
|
||||||
storage?.removeAll()
|
await storage?.removeAll()
|
||||||
.sink(receiveValue: { _ in })
|
|
||||||
.store(in: &cancellables)
|
|
||||||
|
|
||||||
// check the presence
|
// check the presence
|
||||||
UserPreferencesStorage.Constants.allCases.forEach {
|
UserPreferencesStorage.Constants.allCases.forEach {
|
||||||
|
|
Loading…
Reference in New Issue