diff --git a/ios/PolkadotVault.xcodeproj/project.pbxproj b/ios/PolkadotVault.xcodeproj/project.pbxproj index 135a3e1cf8..09aa07db70 100644 --- a/ios/PolkadotVault.xcodeproj/project.pbxproj +++ b/ios/PolkadotVault.xcodeproj/project.pbxproj @@ -313,6 +313,9 @@ 6DD9FF1628C8B85300FB6195 /* HorizontalActionsBottomModal.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6DD9FF1528C8B85300FB6195 /* HorizontalActionsBottomModal.swift */; }; 6DD9FF1928C8C9B000FB6195 /* Animations.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6DD9FF1828C8C9AF00FB6195 /* Animations.swift */; }; 6DDD01D32B9504D1000F53B3 /* KeychainBananaSplitQueryProviderTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6DDD01D22B9504D1000F53B3 /* KeychainBananaSplitQueryProviderTests.swift */; }; + 6DDD01D72B958372000F53B3 /* BananaSplitPassphraseModalViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6DDD01D62B958372000F53B3 /* BananaSplitPassphraseModalViewModelTests.swift */; }; + 6DDD01D92B958845000F53B3 /* BananaSplitActionModalViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6DDD01D82B958845000F53B3 /* BananaSplitActionModalViewModelTests.swift */; }; + 6DDD01DB2B9589B5000F53B3 /* BananaSplitQRCodeModalViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6DDD01DA2B9589B5000F53B3 /* BananaSplitQRCodeModalViewModelTests.swift */; }; 6DDD38B22B11C3C2000D2B62 /* SeedsMediatorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6DDD38B12B11C3C2000D2B62 /* SeedsMediatorTests.swift */; }; 6DDD38B72B1346C8000D2B62 /* KeyDetailsPublicKeyViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6DDD38B62B1346C8000D2B62 /* KeyDetailsPublicKeyViewModelTests.swift */; }; 6DDD38B92B134ADF000D2B62 /* MKeyDetails+Generate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6DDD38B82B134ADF000D2B62 /* MKeyDetails+Generate.swift */; }; @@ -745,6 +748,9 @@ 6DD9FF1528C8B85300FB6195 /* HorizontalActionsBottomModal.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HorizontalActionsBottomModal.swift; sourceTree = ""; }; 6DD9FF1828C8C9AF00FB6195 /* Animations.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Animations.swift; sourceTree = ""; }; 6DDD01D22B9504D1000F53B3 /* KeychainBananaSplitQueryProviderTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeychainBananaSplitQueryProviderTests.swift; sourceTree = ""; }; + 6DDD01D62B958372000F53B3 /* BananaSplitPassphraseModalViewModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BananaSplitPassphraseModalViewModelTests.swift; sourceTree = ""; }; + 6DDD01D82B958845000F53B3 /* BananaSplitActionModalViewModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BananaSplitActionModalViewModelTests.swift; sourceTree = ""; }; + 6DDD01DA2B9589B5000F53B3 /* BananaSplitQRCodeModalViewModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BananaSplitQRCodeModalViewModelTests.swift; sourceTree = ""; }; 6DDD38B12B11C3C2000D2B62 /* SeedsMediatorTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SeedsMediatorTests.swift; sourceTree = ""; }; 6DDD38B62B1346C8000D2B62 /* KeyDetailsPublicKeyViewModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeyDetailsPublicKeyViewModelTests.swift; sourceTree = ""; }; 6DDD38B82B134ADF000D2B62 /* MKeyDetails+Generate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "MKeyDetails+Generate.swift"; sourceTree = ""; }; @@ -2125,6 +2131,16 @@ path = KeyDetails; sourceTree = ""; }; + 6DDD01D52B958365000F53B3 /* BananaSplit */ = { + isa = PBXGroup; + children = ( + 6DDD01D62B958372000F53B3 /* BananaSplitPassphraseModalViewModelTests.swift */, + 6DDD01D82B958845000F53B3 /* BananaSplitActionModalViewModelTests.swift */, + 6DDD01DA2B9589B5000F53B3 /* BananaSplitQRCodeModalViewModelTests.swift */, + ); + path = BananaSplit; + sourceTree = ""; + }; 6DDD38B42B1346BB000D2B62 /* Screens */ = { isa = PBXGroup; children = ( @@ -2976,6 +2992,7 @@ 6DE48E932B1F0B96003094D5 /* AutoMockable+W.generated.swift in Sources */, 6DE48E2E2B1EB97C003094D5 /* AutoMockableHeader.swift in Sources */, 6DE48E902B1F0B96003094D5 /* AutoMockable+A.generated.swift in Sources */, + 6DDD01DB2B9589B5000F53B3 /* BananaSplitQRCodeModalViewModelTests.swift in Sources */, 6D8AF88A28BCC60600CF0AB2 /* KeychainSeedsQueryProviderTests.swift in Sources */, 6DB2E7C12B4BBAF7002387DE /* SettingsViewModelTests.swift in Sources */, 6D9856542B6A6B03002358D3 /* AirgapComponentTests.swift in Sources */, @@ -3008,6 +3025,7 @@ 6DE48E802B1F0B96003094D5 /* AutoMockable+P.generated.swift in Sources */, 6D9856732B716564002358D3 /* CreateDerivedKeyConfirmationViewModelTests.swift in Sources */, 6D80EB502B4EAD3E009C544B /* VerifierCertificateViewModelTests.swift in Sources */, + 6DDD01D72B958372000F53B3 /* BananaSplitPassphraseModalViewModelTests.swift in Sources */, 6D2C78B02B56EF55006431E3 /* SettingsBackupModalViewModelTests.swift in Sources */, 6D80EB522B4EB0B8009C544B /* MSufficientCryptoReady+Generate.swift in Sources */, 6DE48E8C2B1F0B96003094D5 /* AutoMockable+R.generated.swift in Sources */, @@ -3028,6 +3046,7 @@ 6DE48E972B1F0B96003094D5 /* AutoMockable+L.generated.swift in Sources */, 6D98566D2B716112002358D3 /* DerivationPathNameViewModelTests.swift in Sources */, 6DE48E852B1F0B96003094D5 /* AutoMockable+U.generated.swift in Sources */, + 6DDD01D92B958845000F53B3 /* BananaSplitActionModalViewModelTests.swift in Sources */, 6DAFCAFA2B0AE5C000DDD165 /* KeychainSeedsAccessAdapterTests.swift in Sources */, 6DB2E7CE2B4BC7F6002387DE /* NetworkSettingDetailsViewModelTests.swift in Sources */, 6DAB52E92B5E718D005FDBA8 /* LogsListViewModelTests.swift in Sources */, diff --git a/ios/PolkadotVaultTests/Screens/KeyDetails/BananaSplit/BananaSplitActionModalViewModelTests.swift b/ios/PolkadotVaultTests/Screens/KeyDetails/BananaSplit/BananaSplitActionModalViewModelTests.swift new file mode 100644 index 0000000000..7bcae7e444 --- /dev/null +++ b/ios/PolkadotVaultTests/Screens/KeyDetails/BananaSplit/BananaSplitActionModalViewModelTests.swift @@ -0,0 +1,101 @@ +// +// BananaSplitActionModalViewModelTests.swift +// PolkadotVaultTests +// +// Created by Krzysztof Rodak on 04/03/2024. +// + +import Combine +import Foundation +@testable import PolkadotVault +import SwiftUI +import XCTest + +final class BananaSplitActionModalViewModelTests: XCTestCase { + private var viewModel: BananaSplitActionModal.ViewModel! + private var isPresented: Bool = false + private var shouldPresentDeleteBackupWarningModal: Bool! + private var shouldPresentPassphraseModal: Bool! + + override func setUp() { + super.setUp() + isPresented = true + shouldPresentDeleteBackupWarningModal = false + shouldPresentPassphraseModal = false + viewModel = BananaSplitActionModal.ViewModel( + isPresented: Binding( + get: { self.isPresented }, + + set: { self.isPresented = $0 } + ), + shouldPresentDeleteBackupWarningModal: Binding( + get: { self.shouldPresentDeleteBackupWarningModal }, + set: { self.shouldPresentDeleteBackupWarningModal = $0 } + ), + shouldPresentPassphraseModal: Binding( + get: { self.shouldPresentPassphraseModal }, + set: { self.shouldPresentPassphraseModal = $0 } + ) + ) + } + + override func tearDown() { + shouldPresentDeleteBackupWarningModal = nil + shouldPresentPassphraseModal = nil + isPresented = false + viewModel = nil + super.tearDown() + } + + func testRemoveBackup_TriggerWarningModalAndDismiss() { + // Given + let expectation = expectation(description: "RemoveBackupDismissal") + + // When + viewModel.removeBackup() + + // Then + XCTAssertTrue(shouldPresentDeleteBackupWarningModal) + + DispatchQueue.main.asyncAfter(deadline: .now() + 1) { + XCTAssertFalse(self.isPresented) + expectation.fulfill() + } + + waitForExpectations(timeout: 2) + } + + func testShowPassphrase_TriggerPassphraseModalAndDismiss() { + // Given + let expectation = expectation(description: "ShowPassphraseDismissal") + + // When + viewModel.showPassphrase() + + // Then + XCTAssertTrue(shouldPresentPassphraseModal) + + DispatchQueue.main.asyncAfter(deadline: .now() + 1) { + XCTAssertFalse(self.isPresented) + expectation.fulfill() + } + + waitForExpectations(timeout: 2) + } + + func testDismissActionSheet_TriggersAnimationAndDismissal() { + // Given + let expectation = expectation(description: "AnimateDismissal") + + // When + viewModel.dismissActionSheet() + + // Then + DispatchQueue.main.asyncAfter(deadline: .now() + 1) { + XCTAssertFalse(self.isPresented) + expectation.fulfill() + } + + waitForExpectations(timeout: 2) + } +} diff --git a/ios/PolkadotVaultTests/Screens/KeyDetails/BananaSplit/BananaSplitPassphraseModalViewModelTests.swift b/ios/PolkadotVaultTests/Screens/KeyDetails/BananaSplit/BananaSplitPassphraseModalViewModelTests.swift new file mode 100644 index 0000000000..79ea709239 --- /dev/null +++ b/ios/PolkadotVaultTests/Screens/KeyDetails/BananaSplit/BananaSplitPassphraseModalViewModelTests.swift @@ -0,0 +1,93 @@ +// +// BananaSplitPassphraseModalViewModelTests.swift +// PolkadotVaultTests +// +// Created by Krzysztof Rodak on 04/03/2024. +// + +import Combine +import Foundation +@testable import PolkadotVault +import SwiftUI +import XCTest + +final class BananaSplitPassphraseModalViewModelTests: XCTestCase { + private var viewModel: BananaSplitPassphraseModal.ViewModel! + private var mediatorMock: KeychainBananaSplitAccessMediatingMock! + private var isPresented: Bool! + private var seedName: String! + + override func setUp() { + super.setUp() + seedName = "testSeed" + mediatorMock = KeychainBananaSplitAccessMediatingMock() + isPresented = true + } + + override func tearDown() { + viewModel = nil + mediatorMock = nil + seedName = nil + isPresented = nil + super.tearDown() + } + + func testInit_LoadsPassphraseOnSuccess() { + // Given + let expectedPassphrase = "loadedPassphrase" + mediatorMock + .retrieveBananaSplitPassphraseWithReturnValue = + .success(BananaSplitPassphrase(passphrase: expectedPassphrase)) + + // When + viewModel = BananaSplitPassphraseModal.ViewModel( + seedName: seedName, + isPresented: Binding(get: { self.isPresented }, set: { self.isPresented = $0 }), + bananaSplitMediator: mediatorMock + ) + + // Then + XCTAssertEqual(mediatorMock.retrieveBananaSplitPassphraseWithCallsCount, 1) + XCTAssertEqual(mediatorMock.retrieveBananaSplitPassphraseWithReceivedSeedName, [seedName]) + XCTAssertEqual(viewModel.passphrase, expectedPassphrase) + } + + func testInit_DoesNotLoadPassphraseOnFailure() { + // Given + mediatorMock.retrieveBananaSplitPassphraseWithReturnValue = .failure(.fetchError) + + // When + viewModel = BananaSplitPassphraseModal.ViewModel( + seedName: "testSeed", + isPresented: Binding(get: { self.isPresented }, set: { self.isPresented = $0 }), + bananaSplitMediator: mediatorMock + ) + + // Then + XCTAssertEqual(mediatorMock.retrieveBananaSplitPassphraseWithCallsCount, 1) + XCTAssertEqual(mediatorMock.retrieveBananaSplitPassphraseWithReceivedSeedName, ["testSeed"]) + XCTAssertEqual(viewModel.passphrase, "") + } + + func testDismissActionSheet_TriggersAnimationAndDismissal() { + // Given + let expectation = expectation(description: "AnimateDismissal") + mediatorMock.retrieveBananaSplitPassphraseWithReturnValue = .failure(.fetchError) + viewModel = BananaSplitPassphraseModal.ViewModel( + seedName: seedName, + isPresented: Binding(get: { self.isPresented }, set: { self.isPresented = $0 }), + bananaSplitMediator: mediatorMock + ) + + // When + viewModel.dismissActionSheet() + + // Then + DispatchQueue.main.asyncAfter(deadline: .now() + 1) { + XCTAssertFalse(self.isPresented) + expectation.fulfill() + } + + waitForExpectations(timeout: 2, handler: nil) + } +} diff --git a/ios/PolkadotVaultTests/Screens/KeyDetails/BananaSplit/BananaSplitQRCodeModalViewModelTests.swift b/ios/PolkadotVaultTests/Screens/KeyDetails/BananaSplit/BananaSplitQRCodeModalViewModelTests.swift new file mode 100644 index 0000000000..d243e287ac --- /dev/null +++ b/ios/PolkadotVaultTests/Screens/KeyDetails/BananaSplit/BananaSplitQRCodeModalViewModelTests.swift @@ -0,0 +1,106 @@ +// +// BananaSplitQRCodeModalViewModelTests.swift +// PolkadotVaultTests +// +// Created by Krzysztof Rodak on 04/03/2024. +// + +import Combine +import Foundation +@testable import PolkadotVault +import SwiftUI +import XCTest + +final class BananaSplitQRCodeModalViewModelTests: XCTestCase { + private var viewModel: BananaSplitQRCodeModalView.ViewModel! + private var mediatorMock: KeychainBananaSplitAccessMediatingMock! + private var completionAction: BananaSplitQRCodeModalView.OnCompletionAction? + private var testSeedName: String! + private var testBananaSplitBackup: BananaSplitBackup! + + override func setUp() { + super.setUp() + testSeedName = "testSeed" + testBananaSplitBackup = BananaSplitBackup(qrCodes: [[10]]) + mediatorMock = KeychainBananaSplitAccessMediatingMock() + viewModel = BananaSplitQRCodeModalView.ViewModel( + seedName: testSeedName, + bananaSplitBackup: testBananaSplitBackup, + bananaSplitMediator: mediatorMock, + onCompletion: { [weak self] action in + self?.completionAction = action + } + ) + } + + override func tearDown() { + testSeedName = nil + testBananaSplitBackup = nil + viewModel = nil + mediatorMock = nil + completionAction = nil + super.tearDown() + } + + func testOnMoreButtonTap_PresentsActionSheet() { + // When + viewModel.onMoreButtonTap() + + // Then + XCTAssertTrue(viewModel.isPresentingActionSheet) + } + + func testOnCloseTap_CompletesWithClose() { + // When + viewModel.onCloseTap() + + // Then + XCTAssertEqual(completionAction, .close) + } + + func testCheckForActionsPresentation_PresentsPassphraseModal() { + // Given + viewModel.shouldPresentPassphraseModal = true + + // When + viewModel.checkForActionsPresentation() + + // Then + XCTAssertTrue(viewModel.isPresentingPassphraseModal) + } + + func testCheckForActionsPresentation_PresentsDeleteBackupWarningModal() { + // Given + viewModel.shouldPresentDeleteBackupWarningModal = true + + // When + viewModel.checkForActionsPresentation() + + // Then + XCTAssertTrue(viewModel.isPresentingDeleteBackupWarningModal) + } + + func testOnDeleteBackupTap_DeletesBackupSuccessfully() { + // Given + mediatorMock.removeBananaSplitBackupSeedNameReturnValue = .success(()) + + // When + viewModel.onDeleteBackupTap() + + // Then + XCTAssertEqual(completionAction, .backupDeleted) + } + + func testOnDeleteBackupTap_FailsToDeleteBackup() { + // Given + let expectedError = KeychainError.checkError + mediatorMock.removeBananaSplitBackupSeedNameReturnValue = .failure(expectedError) + + // When + viewModel.onDeleteBackupTap() + + // Then + XCTAssertTrue(viewModel.isPresentingError) + XCTAssertEqual(viewModel.presentableError, .alertError(message: expectedError.localizedDescription)) + } +}