[301] Import Wallet does not have a Birthday input field (#328)
- added words counter X/24 - added input for the birthday - all kinds of validity check implemented - unit tests for the whole import wallet business logic implemented [301] Import Wallet does not have a Birthday input field (328) - support for the birthday to be optional input [301] Import Wallet does not have a Birthday input field (328) - Int -> BlockHeight refactor
This commit is contained in:
parent
4cc7737b21
commit
c40b9660e3
|
@ -100,6 +100,7 @@
|
|||
9E2F1C8C280ED6A7004E65FE /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 9E2F1C8B280ED6A7004E65FE /* LaunchScreen.storyboard */; };
|
||||
9E2F1C8F280EDE09004E65FE /* Drawer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E2F1C8E280EDE09004E65FE /* Drawer.swift */; };
|
||||
9E37A2B827C8F59F00AE57B3 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 9E37A2B727C8F59F00AE57B3 /* Localizable.strings */; };
|
||||
9E391124283E4CAC0073DD9A /* ImportWalletTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E391123283E4CAC0073DD9A /* ImportWalletTests.swift */; };
|
||||
9E4DC6E027C409A100E657F4 /* NeumorphicDesignModifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E4DC6DF27C409A100E657F4 /* NeumorphicDesignModifier.swift */; };
|
||||
9E4DC6E227C4C6B700E657F4 /* SecantButtonStyles.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E4DC6E127C4C6B700E657F4 /* SecantButtonStyles.swift */; };
|
||||
9E5BF63F2819542C00BA3F17 /* TransactionHistoryTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E5BF63E2819542C00BA3F17 /* TransactionHistoryTests.swift */; };
|
||||
|
@ -289,6 +290,7 @@
|
|||
9E2F1C8B280ED6A7004E65FE /* LaunchScreen.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = LaunchScreen.storyboard; sourceTree = "<group>"; };
|
||||
9E2F1C8E280EDE09004E65FE /* Drawer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Drawer.swift; sourceTree = "<group>"; };
|
||||
9E37A2B727C8F59F00AE57B3 /* Localizable.strings */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; path = Localizable.strings; sourceTree = "<group>"; };
|
||||
9E391123283E4CAC0073DD9A /* ImportWalletTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImportWalletTests.swift; sourceTree = "<group>"; };
|
||||
9E4DC6DF27C409A100E657F4 /* NeumorphicDesignModifier.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NeumorphicDesignModifier.swift; sourceTree = "<group>"; };
|
||||
9E4DC6E127C4C6B700E657F4 /* SecantButtonStyles.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecantButtonStyles.swift; sourceTree = "<group>"; };
|
||||
9E5BF63B2818305D00BA3F17 /* TransactionState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TransactionState.swift; sourceTree = "<group>"; };
|
||||
|
@ -476,6 +478,7 @@
|
|||
0D4E7A1926B364180058B01E /* secantTests */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
9E391122283E4C970073DD9A /* ImportWalletTests */,
|
||||
9E01F8262833CD84000EFC57 /* ScanTests */,
|
||||
9E5BF642281FEC8700BA3F17 /* SendTests */,
|
||||
9E5BF63D281953F900BA3F17 /* TransactionHistoryTests */,
|
||||
|
@ -746,6 +749,14 @@
|
|||
path = Drawer;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
9E391122283E4C970073DD9A /* ImportWalletTests */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
9E391123283E4CAC0073DD9A /* ImportWalletTests.swift */,
|
||||
);
|
||||
path = ImportWalletTests;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
9E5BF63D281953F900BA3F17 /* TransactionHistoryTests */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
|
@ -1397,6 +1408,7 @@
|
|||
9E5BF644281FEC9900BA3F17 /* SendTests.swift in Sources */,
|
||||
0D1C1AA327611EFD0004AF6A /* RecoveryPhraseDisplayReducerTests.swift in Sources */,
|
||||
9EAFEB822805793200199FC9 /* AppReducerTests.swift in Sources */,
|
||||
9E391124283E4CAC0073DD9A /* ImportWalletTests.swift in Sources */,
|
||||
9E5BF63F2819542C00BA3F17 /* TransactionHistoryTests.swift in Sources */,
|
||||
0D4E7A1B26B364180058B01E /* secantTests.swift in Sources */,
|
||||
0DFE93E6272CB6F7000FCCA5 /* RecoveryPhraseValidationTests.swift in Sources */,
|
||||
|
|
|
@ -14,6 +14,7 @@ fileprivate enum ZcashSDKConstants {
|
|||
static let endpointTestnetAddress = "lightwalletd.testnet.electriccoin.co"
|
||||
static let endpointPort = 9067
|
||||
static let defaultBlockHeight = 1_629_724
|
||||
static let mnemonicWordsMaxCount = 24
|
||||
}
|
||||
|
||||
struct ZCashSDKEnvironment {
|
||||
|
@ -21,6 +22,7 @@ struct ZCashSDKEnvironment {
|
|||
let endpoint: LightWalletEndpoint
|
||||
let lightWalletService: LightWalletService
|
||||
let network: ZcashNetwork
|
||||
let mnemonicWordsMaxCount: Int
|
||||
let isMainnet: () -> Bool
|
||||
}
|
||||
|
||||
|
@ -32,6 +34,7 @@ extension ZCashSDKEnvironment {
|
|||
endpoint: LightWalletEndpoint(address: ZcashSDKConstants.endpointMainnetAddress, port: ZcashSDKConstants.endpointPort)
|
||||
),
|
||||
network: ZcashNetworkBuilder.network(for: .mainnet),
|
||||
mnemonicWordsMaxCount: ZcashSDKConstants.mnemonicWordsMaxCount,
|
||||
isMainnet: { true }
|
||||
)
|
||||
|
||||
|
@ -42,6 +45,7 @@ extension ZCashSDKEnvironment {
|
|||
endpoint: LightWalletEndpoint(address: ZcashSDKConstants.endpointTestnetAddress, port: ZcashSDKConstants.endpointPort)
|
||||
),
|
||||
network: ZcashNetworkBuilder.network(for: .testnet),
|
||||
mnemonicWordsMaxCount: ZcashSDKConstants.mnemonicWordsMaxCount,
|
||||
isMainnet: { false }
|
||||
)
|
||||
}
|
||||
|
|
|
@ -17,6 +17,26 @@ typealias ImportWalletViewStore = ViewStore<ImportWalletState, ImportWalletActio
|
|||
struct ImportWalletState: Equatable {
|
||||
@BindableState var alert: AlertState<ImportWalletAction>?
|
||||
@BindableState var importedSeedPhrase: String = ""
|
||||
@BindableState var birthdayHeight: String = ""
|
||||
var wordsCount = 0
|
||||
var maxWordsCount = 0
|
||||
var isValidMnemonic = false
|
||||
var isValidNumberOfWords = false
|
||||
var birthdayHeightValue: BlockHeight?
|
||||
|
||||
var mnemonicStatus: String {
|
||||
if isValidMnemonic {
|
||||
return "VALID SEED PHRASE"
|
||||
} else {
|
||||
return "\(wordsCount)/\(maxWordsCount)"
|
||||
}
|
||||
}
|
||||
|
||||
var isValidForm: Bool {
|
||||
isValidMnemonic &&
|
||||
(birthdayHeight.isEmpty ||
|
||||
(!birthdayHeight.isEmpty && birthdayHeightValue != nil))
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Action
|
||||
|
@ -24,9 +44,10 @@ struct ImportWalletState: Equatable {
|
|||
enum ImportWalletAction: Equatable, BindableAction {
|
||||
case binding(BindingAction<ImportWalletState>)
|
||||
case dismissAlert
|
||||
case importRecoveryPhrase
|
||||
case restoreWallet
|
||||
case importPrivateOrViewingKey
|
||||
case initializeSDK
|
||||
case onAppear
|
||||
case successfullyRecovered
|
||||
}
|
||||
|
||||
|
@ -57,6 +78,31 @@ extension ImportWalletEnvironment {
|
|||
extension ImportWalletReducer {
|
||||
static let `default` = ImportWalletReducer { state, action, environment in
|
||||
switch action {
|
||||
case .onAppear:
|
||||
state.maxWordsCount = environment.zcashSDKEnvironment.mnemonicWordsMaxCount
|
||||
return .none
|
||||
|
||||
case .binding(\.$importedSeedPhrase):
|
||||
state.wordsCount = state.importedSeedPhrase.split(separator: " ").count
|
||||
state.isValidNumberOfWords = state.wordsCount == state.maxWordsCount
|
||||
// is the mnemonic valid one?
|
||||
do {
|
||||
try environment.mnemonic.isValid(state.importedSeedPhrase)
|
||||
} catch {
|
||||
state.isValidMnemonic = false
|
||||
return .none
|
||||
}
|
||||
state.isValidMnemonic = true
|
||||
return .none
|
||||
|
||||
case .binding(\.$birthdayHeight):
|
||||
if let birthdayHeight = BlockHeight(state.birthdayHeight), birthdayHeight >= environment.zcashSDKEnvironment.defaultBirthday {
|
||||
state.birthdayHeightValue = birthdayHeight
|
||||
} else {
|
||||
state.birthdayHeightValue = nil
|
||||
}
|
||||
return .none
|
||||
|
||||
case .binding:
|
||||
return .none
|
||||
|
||||
|
@ -64,13 +110,13 @@ extension ImportWalletReducer {
|
|||
state.alert = nil
|
||||
return .none
|
||||
|
||||
case .importRecoveryPhrase:
|
||||
case .restoreWallet:
|
||||
do {
|
||||
// validate the seed
|
||||
try environment.mnemonic.isValid(state.importedSeedPhrase)
|
||||
|
||||
// store it to the keychain
|
||||
let birthday = environment.zcashSDKEnvironment.defaultBirthday
|
||||
var birthday = state.birthdayHeightValue ?? environment.zcashSDKEnvironment.defaultBirthday
|
||||
try environment.walletStorage.importWallet(state.importedSeedPhrase, birthday, .english, false)
|
||||
|
||||
// update the backup phrase validation flag
|
||||
|
@ -118,9 +164,9 @@ extension ImportWalletReducer {
|
|||
// MARK: - Placeholders
|
||||
|
||||
extension ImportWalletState {
|
||||
static let placeholder = ImportWalletState(importedSeedPhrase: "")
|
||||
static let placeholder = ImportWalletState()
|
||||
|
||||
static let live = ImportWalletState(importedSeedPhrase: "")
|
||||
static let live = ImportWalletState()
|
||||
}
|
||||
|
||||
extension ImportWalletStore {
|
||||
|
|
|
@ -33,14 +33,30 @@ struct ImportWalletView: View {
|
|||
}
|
||||
.padding(18)
|
||||
|
||||
ImportSeedEditor(store: store)
|
||||
.frame(width: nil, height: 200, alignment: .center)
|
||||
ZStack {
|
||||
ImportSeedEditor(store: store)
|
||||
|
||||
Button("importWallet.button.importPhrase") {
|
||||
viewStore.send(.importRecoveryPhrase)
|
||||
mnemonicStatus(viewStore)
|
||||
}
|
||||
.frame(width: nil, height: 200, alignment: .center)
|
||||
|
||||
VStack {
|
||||
Text("importWallet.birthday.description")
|
||||
.paragraphText()
|
||||
|
||||
TextField("importWallet.birthday.placeholder", text: viewStore.binding(\.$birthdayHeight))
|
||||
.keyboardType(.numberPad)
|
||||
.autocapitalization(.none)
|
||||
.importSeedEditorModifier()
|
||||
}
|
||||
.padding(28)
|
||||
|
||||
Button("importWallet.button.restoreWallet") {
|
||||
viewStore.send(.restoreWallet)
|
||||
}
|
||||
.activeButtonStyle
|
||||
.importWalletButtonLayout()
|
||||
.disabled(!viewStore.isValidForm)
|
||||
|
||||
Button("importWallet.button.importPrivateKey") {
|
||||
viewStore.send(.importPrivateOrViewingKey)
|
||||
|
@ -53,11 +69,33 @@ struct ImportWalletView: View {
|
|||
.navigationBarHidden(true)
|
||||
.applyScreenBackground()
|
||||
.scrollableWhenScaledUp()
|
||||
.onAppear(perform: { viewStore.send(.onAppear) })
|
||||
.alert(self.store.scope(state: \.alert), dismiss: .dismissAlert)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension ImportWalletView {
|
||||
func mnemonicStatus(_ viewStore: ImportWalletViewStore) -> some View {
|
||||
VStack {
|
||||
Spacer()
|
||||
HStack {
|
||||
Spacer()
|
||||
Text(viewStore.mnemonicStatus)
|
||||
.font(.custom(FontFamily.Rubik.regular.name, size: 14))
|
||||
.foregroundColor(
|
||||
viewStore.isValidNumberOfWords ?
|
||||
Asset.Colors.Text.validMnemonic.color :
|
||||
Asset.Colors.Text.heading.color
|
||||
)
|
||||
.padding(.trailing, 35)
|
||||
.padding(.bottom, 15)
|
||||
.zIndex(1)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// swiftlint:disable:next private_over_fileprivate strict_fileprivate
|
||||
fileprivate struct ImportWalletButtonLayout: ViewModifier {
|
||||
func body(content: Content) -> some View {
|
||||
|
|
|
@ -0,0 +1,38 @@
|
|||
{
|
||||
"colors" : [
|
||||
{
|
||||
"color" : {
|
||||
"color-space" : "srgb",
|
||||
"components" : {
|
||||
"alpha" : "1.000",
|
||||
"blue" : "0x16",
|
||||
"green" : "0xAF",
|
||||
"red" : "0x11"
|
||||
}
|
||||
},
|
||||
"idiom" : "universal"
|
||||
},
|
||||
{
|
||||
"appearances" : [
|
||||
{
|
||||
"appearance" : "luminosity",
|
||||
"value" : "dark"
|
||||
}
|
||||
],
|
||||
"color" : {
|
||||
"color-space" : "srgb",
|
||||
"components" : {
|
||||
"alpha" : "1.000",
|
||||
"blue" : "0x16",
|
||||
"green" : "0xAF",
|
||||
"red" : "0x11"
|
||||
}
|
||||
},
|
||||
"idiom" : "universal"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
|
@ -111,6 +111,7 @@ internal enum Asset {
|
|||
internal static let regular = ColorAsset(name: "Regular")
|
||||
internal static let secondaryButtonText = ColorAsset(name: "SecondaryButtonText")
|
||||
internal static let titleText = ColorAsset(name: "TitleText")
|
||||
internal static let validMnemonic = ColorAsset(name: "ValidMnemonic")
|
||||
internal static let captionText = ColorAsset(name: "captionText")
|
||||
internal static let captionTextShadow = ColorAsset(name: "captionTextShadow")
|
||||
internal static let highlightedSuperscriptText = ColorAsset(name: "highlightedSuperscriptText")
|
||||
|
|
|
@ -52,8 +52,11 @@
|
|||
// MARK: - Import Wallet Screen
|
||||
"importWallet.title" = "Wallet Import";
|
||||
"importWallet.description" = "You can import your backed up wallet by entering your backup recovery phrase (aka seed phrase) now.";
|
||||
"importWallet.button.importPhrase" = "Import Recovery Phrase";
|
||||
"importWallet.button.restoreWallet" = "Restore wallet";
|
||||
"importWallet.button.importPrivateKey" = "Import a private or viewing key";
|
||||
"importWallet.birthday.description" = "Add your wallet's birthday to sync up quicker. Leave it blank if you don't know it.";
|
||||
"importWallet.birthday.placeholder" = "Enter birthday height";
|
||||
|
||||
|
||||
// MARK: - Home Screen
|
||||
"home.request" = "Request ZEC";
|
||||
|
|
|
@ -22,7 +22,8 @@ struct ImportSeedEditor: View {
|
|||
TextEditor(text: viewStore.binding(\.$importedSeedPhrase))
|
||||
.autocapitalization(.none)
|
||||
.importSeedEditorModifier()
|
||||
.padding(28)
|
||||
.padding(.horizontal, 28)
|
||||
.padding(.vertical, 10)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,432 @@
|
|||
//
|
||||
// ImportWalletTests.swift
|
||||
// secantTests
|
||||
//
|
||||
// Created by Lukáš Korba on 25.05.2022.
|
||||
//
|
||||
|
||||
import XCTest
|
||||
@testable import secant_testnet
|
||||
import ComposableArchitecture
|
||||
|
||||
// swiftlint:disable type_body_length
|
||||
class ImportWalletTests: XCTestCase {
|
||||
func testOnAppear() throws {
|
||||
let testEnvironment = ImportWalletEnvironment(
|
||||
mnemonic: .mock,
|
||||
walletStorage: .throwing,
|
||||
zcashSDKEnvironment: .testnet
|
||||
)
|
||||
|
||||
let store = TestStore(
|
||||
initialState: .placeholder,
|
||||
reducer: ImportWalletReducer.default,
|
||||
environment: testEnvironment
|
||||
)
|
||||
|
||||
store.send(.onAppear) { state in
|
||||
state.maxWordsCount = 24
|
||||
}
|
||||
}
|
||||
|
||||
func testWordsCount() throws {
|
||||
let testEnvironment = ImportWalletEnvironment(
|
||||
mnemonic: .live,
|
||||
walletStorage: .throwing,
|
||||
zcashSDKEnvironment: .testnet
|
||||
)
|
||||
|
||||
let store = TestStore(
|
||||
initialState: .placeholder,
|
||||
reducer: ImportWalletReducer.default,
|
||||
environment: testEnvironment
|
||||
)
|
||||
|
||||
store.send(.binding(.set(\.$importedSeedPhrase, "one two three"))) { state in
|
||||
state.importedSeedPhrase = "one two three"
|
||||
state.wordsCount = 3
|
||||
state.isValidMnemonic = false
|
||||
}
|
||||
}
|
||||
|
||||
func testMaxWordsInvalidMnemonic() throws {
|
||||
let testEnvironment = ImportWalletEnvironment(
|
||||
mnemonic: .live,
|
||||
walletStorage: .throwing,
|
||||
zcashSDKEnvironment: .testnet
|
||||
)
|
||||
|
||||
let store = TestStore(
|
||||
initialState: ImportWalletState(maxWordsCount: 24),
|
||||
reducer: ImportWalletReducer.default,
|
||||
environment: testEnvironment
|
||||
)
|
||||
|
||||
store.send(.binding(.set(\.$importedSeedPhrase, "a a a a a a a a a a a a a a a a a a a a a a a a"))) { state in
|
||||
state.importedSeedPhrase = "a a a a a a a a a a a a a a a a a a a a a a a a"
|
||||
state.wordsCount = 24
|
||||
state.isValidNumberOfWords = true
|
||||
state.isValidMnemonic = false
|
||||
}
|
||||
}
|
||||
|
||||
func testValidMnemonic() throws {
|
||||
let testEnvironment = ImportWalletEnvironment(
|
||||
mnemonic: .live,
|
||||
walletStorage: .throwing,
|
||||
zcashSDKEnvironment: .testnet
|
||||
)
|
||||
|
||||
let store = TestStore(
|
||||
initialState: ImportWalletState(maxWordsCount: 24),
|
||||
reducer: ImportWalletReducer.default,
|
||||
environment: testEnvironment
|
||||
)
|
||||
|
||||
store.send(
|
||||
.binding(
|
||||
.set(
|
||||
\.$importedSeedPhrase,
|
||||
"""
|
||||
still champion voice habit trend flight \
|
||||
survey between bitter process artefact blind \
|
||||
carbon truly provide dizzy crush flush \
|
||||
breeze blouse charge solid fish spread
|
||||
"""
|
||||
)
|
||||
)
|
||||
) { state in
|
||||
state.importedSeedPhrase = """
|
||||
still champion voice habit trend flight \
|
||||
survey between bitter process artefact blind \
|
||||
carbon truly provide dizzy crush flush \
|
||||
breeze blouse charge solid fish spread
|
||||
"""
|
||||
state.wordsCount = 24
|
||||
state.isValidNumberOfWords = true
|
||||
state.isValidMnemonic = true
|
||||
}
|
||||
}
|
||||
|
||||
func testInvalidBirthdayHeight_lessThanDefault() throws {
|
||||
let testEnvironment = ImportWalletEnvironment(
|
||||
mnemonic: .mock,
|
||||
walletStorage: .throwing,
|
||||
zcashSDKEnvironment: .testnet
|
||||
)
|
||||
|
||||
let store = TestStore(
|
||||
initialState: .placeholder,
|
||||
reducer: ImportWalletReducer.default,
|
||||
environment: testEnvironment
|
||||
)
|
||||
|
||||
store.send(.binding(.set(\.$birthdayHeight, "1600000"))) { state in
|
||||
state.birthdayHeight = "1600000"
|
||||
}
|
||||
}
|
||||
|
||||
func testInvalidBirthdayHeight_invalidInput() throws {
|
||||
let testEnvironment = ImportWalletEnvironment(
|
||||
mnemonic: .mock,
|
||||
walletStorage: .throwing,
|
||||
zcashSDKEnvironment: .testnet
|
||||
)
|
||||
|
||||
let store = TestStore(
|
||||
initialState: .placeholder,
|
||||
reducer: ImportWalletReducer.default,
|
||||
environment: testEnvironment
|
||||
)
|
||||
|
||||
store.send(.binding(.set(\.$birthdayHeight, "abc"))) { state in
|
||||
state.birthdayHeight = "abc"
|
||||
}
|
||||
}
|
||||
|
||||
func testInvalidBirthdayHeight_validInput() throws {
|
||||
let testEnvironment = ImportWalletEnvironment(
|
||||
mnemonic: .mock,
|
||||
walletStorage: .throwing,
|
||||
zcashSDKEnvironment: .testnet
|
||||
)
|
||||
|
||||
let store = TestStore(
|
||||
initialState: .placeholder,
|
||||
reducer: ImportWalletReducer.default,
|
||||
environment: testEnvironment
|
||||
)
|
||||
|
||||
store.send(.binding(.set(\.$birthdayHeight, "1700000"))) { state in
|
||||
state.birthdayHeight = "1700000"
|
||||
state.birthdayHeightValue = 1_700_000
|
||||
}
|
||||
}
|
||||
|
||||
func testDismissAlert() throws {
|
||||
let testEnvironment = ImportWalletEnvironment(
|
||||
mnemonic: .mock,
|
||||
walletStorage: .throwing,
|
||||
zcashSDKEnvironment: .testnet
|
||||
)
|
||||
|
||||
let store = TestStore(
|
||||
initialState:
|
||||
ImportWalletState(
|
||||
alert: AlertState(
|
||||
title: TextState("Success"),
|
||||
message: TextState("The wallet has been successfully recovered."),
|
||||
dismissButton: .default(
|
||||
TextState("Ok"),
|
||||
action: .send(.successfullyRecovered)
|
||||
)
|
||||
)
|
||||
),
|
||||
reducer: ImportWalletReducer.default,
|
||||
environment: testEnvironment
|
||||
)
|
||||
|
||||
store.send(.dismissAlert) { state in
|
||||
state.alert = nil
|
||||
}
|
||||
}
|
||||
|
||||
func testFormValidity_validBirthday_invalidMnemonic() throws {
|
||||
let testEnvironment = ImportWalletEnvironment(
|
||||
mnemonic: .live,
|
||||
walletStorage: .throwing,
|
||||
zcashSDKEnvironment: .testnet
|
||||
)
|
||||
|
||||
let store = TestStore(
|
||||
initialState: ImportWalletState(maxWordsCount: 24),
|
||||
reducer: ImportWalletReducer.default,
|
||||
environment: testEnvironment
|
||||
)
|
||||
|
||||
store.send(.binding(.set(\.$birthdayHeight, "1700000"))) { state in
|
||||
state.birthdayHeight = "1700000"
|
||||
state.birthdayHeightValue = 1_700_000
|
||||
}
|
||||
|
||||
store.send(.binding(.set(\.$importedSeedPhrase, "a a a a a a a a a a a a a a a a a a a a a a a a"))) { state in
|
||||
state.importedSeedPhrase = "a a a a a a a a a a a a a a a a a a a a a a a a"
|
||||
state.wordsCount = 24
|
||||
state.isValidNumberOfWords = true
|
||||
state.isValidMnemonic = false
|
||||
XCTAssertFalse(
|
||||
state.isValidForm,
|
||||
"Import Wallet tests: `testFormValidity_validBirthday_validMnemonic` is expected to be false but it is \(state.isValidForm)"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
func testFormValidity_invalidBirthday_invalidMnemonic() throws {
|
||||
let testEnvironment = ImportWalletEnvironment(
|
||||
mnemonic: .live,
|
||||
walletStorage: .throwing,
|
||||
zcashSDKEnvironment: .testnet
|
||||
)
|
||||
|
||||
let store = TestStore(
|
||||
initialState: ImportWalletState(maxWordsCount: 24),
|
||||
reducer: ImportWalletReducer.default,
|
||||
environment: testEnvironment
|
||||
)
|
||||
|
||||
store.send(.binding(.set(\.$birthdayHeight, "1600000"))) { state in
|
||||
state.birthdayHeight = "1600000"
|
||||
}
|
||||
|
||||
store.send(.binding(.set(\.$importedSeedPhrase, "a a a a a a a a a a a a a a a a a a a a a a a a"))) { state in
|
||||
state.importedSeedPhrase = "a a a a a a a a a a a a a a a a a a a a a a a a"
|
||||
state.wordsCount = 24
|
||||
state.isValidNumberOfWords = true
|
||||
state.isValidMnemonic = false
|
||||
XCTAssertFalse(
|
||||
state.isValidForm,
|
||||
"Import Wallet tests: `testFormValidity_validBirthday_validMnemonic` is expected to be false but it is \(state.isValidForm)"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
func testFormValidity_invalidBirthday_validMnemonic() throws {
|
||||
let testEnvironment = ImportWalletEnvironment(
|
||||
mnemonic: .live,
|
||||
walletStorage: .throwing,
|
||||
zcashSDKEnvironment: .testnet
|
||||
)
|
||||
|
||||
let store = TestStore(
|
||||
initialState: ImportWalletState(maxWordsCount: 24),
|
||||
reducer: ImportWalletReducer.default,
|
||||
environment: testEnvironment
|
||||
)
|
||||
|
||||
store.send(.binding(.set(\.$birthdayHeight, "1600000"))) { state in
|
||||
state.birthdayHeight = "1600000"
|
||||
}
|
||||
|
||||
store.send(
|
||||
.binding(
|
||||
.set(
|
||||
\.$importedSeedPhrase,
|
||||
"""
|
||||
still champion voice habit trend flight \
|
||||
survey between bitter process artefact blind \
|
||||
carbon truly provide dizzy crush flush \
|
||||
breeze blouse charge solid fish spread
|
||||
"""
|
||||
)
|
||||
)
|
||||
) { state in
|
||||
state.importedSeedPhrase = """
|
||||
still champion voice habit trend flight \
|
||||
survey between bitter process artefact blind \
|
||||
carbon truly provide dizzy crush flush \
|
||||
breeze blouse charge solid fish spread
|
||||
"""
|
||||
state.wordsCount = 24
|
||||
state.isValidNumberOfWords = true
|
||||
state.isValidMnemonic = true
|
||||
XCTAssertFalse(
|
||||
state.isValidForm,
|
||||
"Import Wallet tests: `testFormValidity_validBirthday_validMnemonic` is expected to be false but it is \(state.isValidForm)"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
func testFormValidity_validBirthday_validMnemonic() throws {
|
||||
let testEnvironment = ImportWalletEnvironment(
|
||||
mnemonic: .live,
|
||||
walletStorage: .throwing,
|
||||
zcashSDKEnvironment: .testnet
|
||||
)
|
||||
|
||||
let store = TestStore(
|
||||
initialState: ImportWalletState(maxWordsCount: 24),
|
||||
reducer: ImportWalletReducer.default,
|
||||
environment: testEnvironment
|
||||
)
|
||||
|
||||
store.send(.binding(.set(\.$birthdayHeight, "1700000"))) { state in
|
||||
state.birthdayHeight = "1700000"
|
||||
state.birthdayHeightValue = 1_700_000
|
||||
}
|
||||
|
||||
store.send(
|
||||
.binding(
|
||||
.set(
|
||||
\.$importedSeedPhrase,
|
||||
"""
|
||||
still champion voice habit trend flight \
|
||||
survey between bitter process artefact blind \
|
||||
carbon truly provide dizzy crush flush \
|
||||
breeze blouse charge solid fish spread
|
||||
"""
|
||||
)
|
||||
)
|
||||
) { state in
|
||||
state.importedSeedPhrase = """
|
||||
still champion voice habit trend flight \
|
||||
survey between bitter process artefact blind \
|
||||
carbon truly provide dizzy crush flush \
|
||||
breeze blouse charge solid fish spread
|
||||
"""
|
||||
state.wordsCount = 24
|
||||
state.isValidNumberOfWords = true
|
||||
state.isValidMnemonic = true
|
||||
XCTAssertTrue(
|
||||
state.isValidForm,
|
||||
"Import Wallet tests: `testFormValidity_validBirthday_validMnemonic` is expected to be true but it is \(state.isValidForm)"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
func testFormValidity_noBirthday_validMnemonic() throws {
|
||||
let testEnvironment = ImportWalletEnvironment(
|
||||
mnemonic: .live,
|
||||
walletStorage: .throwing,
|
||||
zcashSDKEnvironment: .testnet
|
||||
)
|
||||
|
||||
let store = TestStore(
|
||||
initialState: ImportWalletState(maxWordsCount: 24),
|
||||
reducer: ImportWalletReducer.default,
|
||||
environment: testEnvironment
|
||||
)
|
||||
|
||||
store.send(
|
||||
.binding(
|
||||
.set(
|
||||
\.$importedSeedPhrase,
|
||||
"""
|
||||
still champion voice habit trend flight \
|
||||
survey between bitter process artefact blind \
|
||||
carbon truly provide dizzy crush flush \
|
||||
breeze blouse charge solid fish spread
|
||||
"""
|
||||
)
|
||||
)
|
||||
) { state in
|
||||
state.importedSeedPhrase = """
|
||||
still champion voice habit trend flight \
|
||||
survey between bitter process artefact blind \
|
||||
carbon truly provide dizzy crush flush \
|
||||
breeze blouse charge solid fish spread
|
||||
"""
|
||||
state.wordsCount = 24
|
||||
state.isValidNumberOfWords = true
|
||||
state.isValidMnemonic = true
|
||||
XCTAssertTrue(
|
||||
state.isValidForm,
|
||||
"Import Wallet tests: `testFormValidity_validBirthday_validMnemonic` is expected to be true but it is \(state.isValidForm)"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
func testRestoreWallet() throws {
|
||||
var storage = WalletStorage(secItem: .live)
|
||||
storage.zcashStoredWalletPrefix = "test_importWallet_"
|
||||
storage.deleteData(forKey: WalletStorage.Constants.zcashStoredWallet)
|
||||
|
||||
let testEnvironment = ImportWalletEnvironment(
|
||||
mnemonic: .live,
|
||||
walletStorage: .live(walletStorage: storage),
|
||||
zcashSDKEnvironment: .testnet
|
||||
)
|
||||
|
||||
let store = TestStore(
|
||||
initialState: ImportWalletState(
|
||||
alert: nil,
|
||||
importedSeedPhrase: """
|
||||
still champion voice habit trend flight \
|
||||
survey between bitter process artefact blind \
|
||||
carbon truly provide dizzy crush flush \
|
||||
breeze blouse charge solid fish spread
|
||||
""",
|
||||
birthdayHeight: "1700000",
|
||||
wordsCount: 24,
|
||||
maxWordsCount: 24,
|
||||
isValidMnemonic: true,
|
||||
isValidNumberOfWords: true,
|
||||
birthdayHeightValue: 1_700_000
|
||||
),
|
||||
reducer: ImportWalletReducer.default,
|
||||
environment: testEnvironment
|
||||
)
|
||||
|
||||
store.send(.restoreWallet) { state in
|
||||
state.alert = AlertState(
|
||||
title: TextState("Success"),
|
||||
message: TextState("The wallet has been successfully recovered."),
|
||||
dismissButton: .default(
|
||||
TextState("Ok"),
|
||||
action: .send(.successfullyRecovered)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
store.receive(.initializeSDK)
|
||||
}
|
||||
}
|
|
@ -20,7 +20,7 @@ class SendTests: XCTestCase {
|
|||
|
||||
override func setUp() {
|
||||
super.setUp()
|
||||
storage.zcashStoredWalletPrefix = "test_"
|
||||
storage.zcashStoredWalletPrefix = "test_send_"
|
||||
storage.deleteData(forKey: WalletStorage.Constants.zcashStoredWallet)
|
||||
}
|
||||
|
||||
|
|
|
@ -30,7 +30,7 @@ class WalletStorageTests: XCTestCase {
|
|||
|
||||
override func setUp() {
|
||||
super.setUp()
|
||||
storage.zcashStoredWalletPrefix = "test_"
|
||||
storage.zcashStoredWalletPrefix = "test_walletStorage_"
|
||||
deleteData(forKey: WalletStorage.Constants.zcashStoredWallet)
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue