mirror of
https://github.com/bitwarden/ios.git
synced 2025-12-15 14:00:25 -06:00
243 lines
8.9 KiB
Swift
243 lines
8.9 KiB
Swift
import TestHelpers
|
|
import XCTest
|
|
|
|
@testable import BitwardenShared
|
|
|
|
class AttachmentsProcessorTests: BitwardenTestCase {
|
|
// MARK: Properties
|
|
|
|
var coordinator: MockCoordinator<VaultItemRoute, VaultItemEvent>!
|
|
var errorReporter: MockErrorReporter!
|
|
var subject: AttachmentsProcessor!
|
|
var vaultRepository: MockVaultRepository!
|
|
|
|
// MARK: Setup & Teardown
|
|
|
|
override func setUp() {
|
|
super.setUp()
|
|
|
|
coordinator = MockCoordinator()
|
|
errorReporter = MockErrorReporter()
|
|
vaultRepository = MockVaultRepository()
|
|
|
|
subject = AttachmentsProcessor(
|
|
coordinator: coordinator.asAnyCoordinator(),
|
|
services: ServiceContainer.withMocks(
|
|
errorReporter: errorReporter,
|
|
vaultRepository: vaultRepository
|
|
),
|
|
state: AttachmentsState()
|
|
)
|
|
}
|
|
|
|
override func tearDown() {
|
|
super.tearDown()
|
|
|
|
coordinator = nil
|
|
errorReporter = nil
|
|
subject = nil
|
|
vaultRepository = nil
|
|
}
|
|
|
|
// MARK: Tests
|
|
|
|
/// `fileSelectionCompleted()` updates the state with the new file values.
|
|
@MainActor
|
|
func test_fileSelectionCompleted() {
|
|
let data = Data("data".utf8)
|
|
subject.fileSelectionCompleted(fileName: "exampleFile.txt", data: data)
|
|
XCTAssertEqual(subject.state.fileName, "exampleFile.txt")
|
|
XCTAssertEqual(subject.state.fileData, data)
|
|
}
|
|
|
|
/// `perform(_:)` with `.loadPremiumStatus` loads the premium status and displays an alert if necessary.
|
|
@MainActor
|
|
func test_perform_loadPremiumStatus() async throws {
|
|
vaultRepository.doesActiveAccountHavePremiumResult = .success(false)
|
|
|
|
await subject.perform(.loadPremiumStatus)
|
|
|
|
XCTAssertFalse(subject.state.hasPremium)
|
|
XCTAssertEqual(coordinator.alertShown.last, .defaultAlert(title: Localizations.premiumRequired))
|
|
}
|
|
|
|
/// `perform(_:)` with `.loadPremiumStatus` records any errors.
|
|
@MainActor
|
|
func test_perform_loadPremiumStatus_error() async throws {
|
|
vaultRepository.doesActiveAccountHavePremiumResult = .failure(BitwardenTestError.example)
|
|
|
|
await subject.perform(.loadPremiumStatus)
|
|
|
|
XCTAssertFalse(subject.state.hasPremium)
|
|
XCTAssertEqual(coordinator.alertShown.last, .defaultAlert(title: Localizations.anErrorHasOccurred))
|
|
XCTAssertEqual(errorReporter.errors.last as? BitwardenTestError, .example)
|
|
}
|
|
|
|
/// `perform(_:)` with `.save` saves the attachment and updates the view.
|
|
@MainActor
|
|
func test_perform_save() async throws {
|
|
subject.state.cipher = .fixture()
|
|
subject.state.fileName = "only cool people can see this file.txt"
|
|
subject.state.fileData = Data()
|
|
subject.state.hasPremium = true
|
|
|
|
await subject.perform(.save)
|
|
|
|
XCTAssertEqual(vaultRepository.saveAttachmentFileName, "only cool people can see this file.txt")
|
|
XCTAssertEqual(subject.state.cipher, .fixture())
|
|
XCTAssertNil(subject.state.fileName)
|
|
XCTAssertNil(subject.state.fileData)
|
|
XCTAssertEqual(subject.state.toast, Toast(title: Localizations.attachementAdded))
|
|
}
|
|
|
|
/// `perform(_:)` with `.save` handles any errors.
|
|
@MainActor
|
|
func test_perform_save_error() async throws {
|
|
subject.state.cipher = .fixture()
|
|
subject.state.fileName = "only cool people can see this file.txt"
|
|
subject.state.fileData = Data()
|
|
subject.state.hasPremium = true
|
|
vaultRepository.saveAttachmentResult = .failure(BitwardenTestError.example)
|
|
|
|
await subject.perform(.save)
|
|
|
|
XCTAssertEqual(coordinator.alertShown.last, .networkResponseError(BitwardenTestError.example))
|
|
XCTAssertEqual(errorReporter.errors.last as? BitwardenTestError, .example)
|
|
}
|
|
|
|
/// `perform(_:)` with `.save` displays an error if the user doesn't have premium.
|
|
@MainActor
|
|
func test_perform_save_noFile() async throws {
|
|
subject.state.hasPremium = false
|
|
|
|
await subject.perform(.save)
|
|
|
|
XCTAssertEqual(
|
|
coordinator.alertShown.last,
|
|
.inputValidationAlert(error: .init(message: Localizations.validationFieldRequired(Localizations.file)))
|
|
)
|
|
}
|
|
|
|
/// `perform(_:)` with `.save` displays an error if the user doesn't have premium.
|
|
@MainActor
|
|
func test_perform_save_noPremium() async throws {
|
|
subject.state.fileName = "only cool people can see this file.txt"
|
|
subject.state.hasPremium = false
|
|
|
|
await subject.perform(.save)
|
|
|
|
XCTAssertEqual(
|
|
coordinator.alertShown.last,
|
|
.defaultAlert(
|
|
title: Localizations.anErrorHasOccurred,
|
|
message: Localizations.premiumRequired
|
|
)
|
|
)
|
|
}
|
|
|
|
/// `perform(_:)` with `.save` shows an alert if the file is too large.
|
|
@MainActor
|
|
func test_perform_save_tooLarge() async throws {
|
|
subject.state.fileName = "only cool people can see this file.txt"
|
|
subject.state.fileData = Data(count: 104_857_601)
|
|
subject.state.hasPremium = true
|
|
|
|
await subject.perform(.save)
|
|
|
|
XCTAssertEqual(
|
|
coordinator.alertShown.last,
|
|
.defaultAlert(title: Localizations.anErrorHasOccurred, message: Localizations.maxFileSize)
|
|
)
|
|
}
|
|
|
|
/// `receive(_:)` with `.chooseFilePressed` navigates to the document browser.
|
|
@MainActor
|
|
func test_receive_chooseFilePressed() async throws {
|
|
subject.receive(.chooseFilePressed)
|
|
|
|
let alert = try XCTUnwrap(coordinator.alertShown.last)
|
|
|
|
try await alert.tapAction(title: Localizations.browse)
|
|
XCTAssertEqual(coordinator.routes.last, .fileSelection(.file))
|
|
XCTAssertIdentical(coordinator.contexts.last as? FileSelectionDelegate, subject)
|
|
|
|
try await alert.tapAction(title: Localizations.camera)
|
|
XCTAssertEqual(coordinator.routes.last, .fileSelection(.camera))
|
|
XCTAssertIdentical(coordinator.contexts.last as? FileSelectionDelegate, subject)
|
|
|
|
try await alert.tapAction(title: Localizations.photos)
|
|
XCTAssertEqual(coordinator.routes.last, .fileSelection(.photo))
|
|
XCTAssertIdentical(coordinator.contexts.last as? FileSelectionDelegate, subject)
|
|
}
|
|
|
|
/// `.receive(_:)` with `.deletePressed(_)` presents the confirm alert and deletes the attachment.
|
|
@MainActor
|
|
func test_receive_deletePressed() async throws {
|
|
subject.state.cipher = .fixture()
|
|
|
|
subject.receive(.deletePressed(.fixture()))
|
|
|
|
// Confirm on the alert.
|
|
let confirmAction = try XCTUnwrap(coordinator.alertShown.last?.alertActions.first)
|
|
await confirmAction.handler?(confirmAction, [])
|
|
|
|
// Verify the results.
|
|
XCTAssertEqual(coordinator.loadingOverlaysShown.last?.title, Localizations.deleting)
|
|
XCTAssertFalse(coordinator.isLoadingOverlayShowing)
|
|
XCTAssertEqual(vaultRepository.deleteAttachmentId, "1")
|
|
XCTAssertEqual(subject.state.toast, Toast(title: Localizations.attachmentDeleted))
|
|
}
|
|
|
|
/// `.receive(_:)` with `.deletePressed(_)` handles any errors.
|
|
@MainActor
|
|
func test_receive_deletePressed_error() async throws {
|
|
subject.state.cipher = .fixture()
|
|
vaultRepository.deleteAttachmentResult = .failure(BitwardenTestError.example)
|
|
|
|
subject.receive(.deletePressed(.fixture()))
|
|
|
|
// Confirm on the alert.
|
|
let confirmAction = try XCTUnwrap(coordinator.alertShown.last?.alertActions.first)
|
|
await confirmAction.handler?(confirmAction, [])
|
|
|
|
// Verify the results.
|
|
XCTAssertEqual(coordinator.alertShown.last, .networkResponseError(BitwardenTestError.example))
|
|
XCTAssertEqual(errorReporter.errors.last as? BitwardenTestError, .example)
|
|
}
|
|
|
|
/// `.receive(_:)` with `.deletePressed(_)` throws an error if either element is missing its id.
|
|
@MainActor
|
|
func test_receive_deletePressed_noIdError() async throws {
|
|
subject.state.cipher = .fixture(id: nil)
|
|
|
|
subject.receive(.deletePressed(.fixture(id: nil)))
|
|
|
|
// Confirm on the alert.
|
|
let confirmAction = try XCTUnwrap(coordinator.alertShown.last?.alertActions.first)
|
|
await confirmAction.handler?(confirmAction, [])
|
|
|
|
// Verify the results.
|
|
XCTAssertEqual(coordinator.alertShown.last, .networkResponseError(CipherAPIServiceError.updateMissingId))
|
|
XCTAssertEqual(errorReporter.errors.last as? CipherAPIServiceError, .updateMissingId)
|
|
}
|
|
|
|
/// `receive(_:)` with `.dismissPressed` dismisses the view.
|
|
@MainActor
|
|
func test_receive_dismissPressed() {
|
|
subject.receive(.dismissPressed)
|
|
|
|
XCTAssertEqual(coordinator.routes.last, .dismiss())
|
|
}
|
|
|
|
/// `receive(_:)` with `.toastShown` updates the state's toast value.
|
|
@MainActor
|
|
func test_receive_toastShown() {
|
|
let toast = Toast(title: "toast!")
|
|
subject.receive(.toastShown(toast))
|
|
XCTAssertEqual(subject.state.toast, toast)
|
|
|
|
subject.receive(.toastShown(nil))
|
|
XCTAssertNil(subject.state.toast)
|
|
}
|
|
}
|