mirror of
https://github.com/bitwarden/ios.git
synced 2025-12-11 04:34:55 -06:00
221 lines
7.8 KiB
Swift
221 lines
7.8 KiB
Swift
import Foundation
|
|
import XCTest
|
|
|
|
@testable import BitwardenShared
|
|
|
|
class AppProcessorTests: BitwardenTestCase {
|
|
// MARK: Properties
|
|
|
|
var appModule: MockAppModule!
|
|
var authRepository: MockAuthRepository!
|
|
var clientService: MockClientService!
|
|
var coordinator: MockCoordinator<AppRoute, AppEvent>!
|
|
var errorReporter: MockErrorReporter!
|
|
var migrationService: MockMigrationService!
|
|
var notificationCenterService: MockNotificationCenterService!
|
|
var notificationService: MockNotificationService!
|
|
var router: MockRouter<AuthEvent, AuthRoute>!
|
|
var stateService: MockStateService!
|
|
var subject: AppProcessor!
|
|
var syncService: MockSyncService!
|
|
var timeProvider: MockTimeProvider!
|
|
var vaultTimeoutService: MockVaultTimeoutService!
|
|
|
|
// MARK: Setup & Teardown
|
|
|
|
override func setUp() {
|
|
super.setUp()
|
|
|
|
router = MockRouter(routeForEvent: { _ in .landing })
|
|
appModule = MockAppModule()
|
|
authRepository = MockAuthRepository()
|
|
clientService = MockClientService()
|
|
coordinator = MockCoordinator()
|
|
appModule.authRouter = router
|
|
appModule.appCoordinator = coordinator
|
|
errorReporter = MockErrorReporter()
|
|
migrationService = MockMigrationService()
|
|
notificationCenterService = MockNotificationCenterService()
|
|
notificationService = MockNotificationService()
|
|
stateService = MockStateService()
|
|
syncService = MockSyncService()
|
|
timeProvider = MockTimeProvider(.currentTime)
|
|
vaultTimeoutService = MockVaultTimeoutService()
|
|
|
|
subject = AppProcessor(
|
|
appModule: appModule,
|
|
services: ServiceContainer.withMocks(
|
|
authRepository: authRepository,
|
|
clientService: clientService,
|
|
errorReporter: errorReporter,
|
|
migrationService: migrationService,
|
|
notificationService: notificationService,
|
|
notificationCenterService: notificationCenterService,
|
|
stateService: stateService,
|
|
syncService: syncService,
|
|
vaultTimeoutService: vaultTimeoutService
|
|
)
|
|
)
|
|
subject.coordinator = coordinator.asAnyCoordinator()
|
|
}
|
|
|
|
override func tearDown() {
|
|
super.tearDown()
|
|
|
|
appModule = nil
|
|
authRepository = nil
|
|
clientService = nil
|
|
coordinator = nil
|
|
errorReporter = nil
|
|
migrationService = nil
|
|
notificationCenterService = nil
|
|
notificationService = nil
|
|
stateService = nil
|
|
subject = nil
|
|
syncService = nil
|
|
timeProvider = nil
|
|
vaultTimeoutService = nil
|
|
}
|
|
|
|
// MARK: Tests
|
|
|
|
/// The user's last active time is updated when the app is backgrounded.
|
|
func test_appBackgrounded_setLastActiveTime() {
|
|
let account: Account = .fixture()
|
|
stateService.activeAccount = account
|
|
|
|
vaultTimeoutService.lastActiveTime[account.profile.userId] = .distantPast
|
|
|
|
notificationCenterService.didEnterBackgroundSubject.send()
|
|
waitFor(vaultTimeoutService.lastActiveTime[account.profile.userId] != .distantPast)
|
|
|
|
let updated = vaultTimeoutService.lastActiveTime[account.profile.userId]
|
|
|
|
XCTAssertEqual(timeProvider.presentTime.timeIntervalSince1970, updated!.timeIntervalSince1970, accuracy: 1.0)
|
|
}
|
|
|
|
/// `didRegister(withToken:)` passes the token to the notification service.
|
|
func test_didRegister() throws {
|
|
let tokenData = try XCTUnwrap("tokensForFree".data(using: .utf8))
|
|
|
|
let task = Task {
|
|
subject.didRegister(withToken: tokenData)
|
|
}
|
|
|
|
waitFor(notificationService.registrationTokenData == tokenData)
|
|
task.cancel()
|
|
}
|
|
|
|
/// `failedToRegister(_:)` records the error.
|
|
func test_failedToRegister() {
|
|
subject.failedToRegister(BitwardenTestError.example)
|
|
XCTAssertEqual(errorReporter.errors.last as? BitwardenTestError, .example)
|
|
}
|
|
|
|
/// `init()` sets the `AppProcessor` as the delegate of any necessary services.
|
|
func test_init_setDelegates() {
|
|
XCTAssertIdentical(notificationService.delegate, subject)
|
|
XCTAssertIdentical(syncService.delegate, subject)
|
|
}
|
|
|
|
/// `messageReceived(_:notificationDismissed:notificationTapped)` passes the data to the notification service.
|
|
func test_messageReceived() async {
|
|
let message: [AnyHashable: Any] = ["knock knock": "who's there?"]
|
|
|
|
await subject.messageReceived(message)
|
|
|
|
XCTAssertEqual(notificationService.messageReceivedMessage?.keys.first, "knock knock")
|
|
}
|
|
|
|
/// `routeToLanding(_:)` navigates to show the landing view.
|
|
func test_routeToLanding() async {
|
|
await subject.routeToLanding()
|
|
XCTAssertEqual(coordinator.routes.last, .auth(.landing))
|
|
}
|
|
|
|
/// `securityStampChanged(userId:)` logs the user out and notifies the coordinator.
|
|
func test_securityStampChanged() async {
|
|
coordinator.isLoadingOverlayShowing = true
|
|
|
|
await subject.securityStampChanged(userId: "1")
|
|
|
|
XCTAssertTrue(authRepository.logoutCalled)
|
|
XCTAssertEqual(authRepository.logoutUserId, "1")
|
|
XCTAssertFalse(coordinator.isLoadingOverlayShowing)
|
|
XCTAssertEqual(coordinator.events, [.didLogout(userId: "1", userInitiated: false)])
|
|
}
|
|
|
|
/// Upon a session timeout on app foreground, send the user to the `.didTimeout` route.
|
|
func test_shouldSessionTimeout_navigateTo_didTimeout() throws {
|
|
let rootNavigator = MockRootNavigator()
|
|
let user = Account.fixture()
|
|
let userId = user.profile.userId
|
|
let user2 = Account.fixture()
|
|
let user2Id = user2.profile.userId
|
|
|
|
stateService.activeAccount = user
|
|
stateService.accounts = [user, user2]
|
|
|
|
let task = Task {
|
|
await subject.start(appContext: .mainApp, navigator: rootNavigator, window: nil)
|
|
}
|
|
waitFor(coordinator.events == [.didStart])
|
|
task.cancel()
|
|
|
|
vaultTimeoutService.shouldSessionTimeout[userId] = true
|
|
notificationCenterService.willEnterForegroundSubject.send()
|
|
|
|
waitFor(vaultTimeoutService.shouldSessionTimeout[userId] == true)
|
|
waitFor(coordinator.events.count > 1)
|
|
waitFor(vaultTimeoutService.isLocked(userId: user2Id))
|
|
|
|
XCTAssertEqual(
|
|
coordinator.events,
|
|
[
|
|
.didStart,
|
|
.didTimeout(userId: userId),
|
|
]
|
|
)
|
|
}
|
|
|
|
/// `showLoginRequest(_:)` navigates to show the login request view.
|
|
func test_showLoginRequest() {
|
|
subject.showLoginRequest(.fixture())
|
|
XCTAssertEqual(coordinator.routes.last, .loginRequest(.fixture()))
|
|
}
|
|
|
|
/// `start(navigator:)` builds the AppCoordinator and navigates to the initial route if provided.
|
|
func test_start_initialRoute() async {
|
|
let rootNavigator = MockRootNavigator()
|
|
|
|
await subject.start(
|
|
appContext: .mainApp,
|
|
initialRoute: .extensionSetup(.extensionActivation(type: .appExtension)),
|
|
navigator: rootNavigator,
|
|
window: nil
|
|
)
|
|
|
|
waitFor(!coordinator.routes.isEmpty)
|
|
|
|
XCTAssertTrue(appModule.appCoordinator.isStarted)
|
|
XCTAssertEqual(
|
|
appModule.appCoordinator.routes,
|
|
[.extensionSetup(.extensionActivation(type: .appExtension))]
|
|
)
|
|
XCTAssertEqual(migrationService.didPerformMigrations, true)
|
|
}
|
|
|
|
/// `start(navigator:)` builds the AppCoordinator and navigates to the `.didStart` route.
|
|
func test_start_authRoute() async {
|
|
let rootNavigator = MockRootNavigator()
|
|
|
|
await subject.start(appContext: .mainApp, navigator: rootNavigator, window: nil)
|
|
|
|
waitFor(!coordinator.events.isEmpty)
|
|
|
|
XCTAssertTrue(appModule.appCoordinator.isStarted)
|
|
XCTAssertEqual(appModule.appCoordinator.events, [.didStart])
|
|
XCTAssertEqual(migrationService.didPerformMigrations, true)
|
|
}
|
|
}
|