Add UI tests for AppLockFlowCoordinator. (#2055)

* Add UITests for the App Lock flow.

* Add Notification Signal

Fix unwanted imports in UITests.
This commit is contained in:
Doug 2023-11-10 15:38:54 +00:00 committed by GitHub
parent da831f6725
commit 37d88e622c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
71 changed files with 348 additions and 147 deletions

View File

@ -206,6 +206,7 @@
37906355E207DB5703754675 /* AppLockSetupBiometricsScreenViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = C9F893F4A111CB7BA5C96949 /* AppLockSetupBiometricsScreenViewModel.swift */; }; 37906355E207DB5703754675 /* AppLockSetupBiometricsScreenViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = C9F893F4A111CB7BA5C96949 /* AppLockSetupBiometricsScreenViewModel.swift */; };
37D789F24199B32E3FD1AA7B /* FileRoomTimelineItemContent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 216F0DDC98F2A2C162D09C28 /* FileRoomTimelineItemContent.swift */; }; 37D789F24199B32E3FD1AA7B /* FileRoomTimelineItemContent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 216F0DDC98F2A2C162D09C28 /* FileRoomTimelineItemContent.swift */; };
383055C6ABE5BE058CEE1DDB /* WelcomeScreenScreenCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 57FE5EF0AFFE360C66420AAE /* WelcomeScreenScreenCoordinator.swift */; }; 383055C6ABE5BE058CEE1DDB /* WelcomeScreenScreenCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 57FE5EF0AFFE360C66420AAE /* WelcomeScreenScreenCoordinator.swift */; };
384D6B9A7DFD7260139D6852 /* UITestsNotificationCenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = EBEB8D9F4940E161B18FE4BC /* UITestsNotificationCenter.swift */; };
38546A6010A2CF240EC9AF73 /* BindableState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6EA1D2CBAEA5D0BD00B90D1B /* BindableState.swift */; }; 38546A6010A2CF240EC9AF73 /* BindableState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6EA1D2CBAEA5D0BD00B90D1B /* BindableState.swift */; };
386720B603F87D156DB01FB2 /* VoiceMessageMediaManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 40076C770A5FB83325252973 /* VoiceMessageMediaManager.swift */; }; 386720B603F87D156DB01FB2 /* VoiceMessageMediaManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 40076C770A5FB83325252973 /* VoiceMessageMediaManager.swift */; };
38896D54D6D675534E606195 /* RoomTimelineControllerFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = E6FCC416A3BFE73DF7B3E6BF /* RoomTimelineControllerFactory.swift */; }; 38896D54D6D675534E606195 /* RoomTimelineControllerFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = E6FCC416A3BFE73DF7B3E6BF /* RoomTimelineControllerFactory.swift */; };
@ -724,6 +725,7 @@
BA31448FBD9697F8CB9A83CD /* ImageCache.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4E2245243369B99216C7D84E /* ImageCache.swift */; }; BA31448FBD9697F8CB9A83CD /* ImageCache.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4E2245243369B99216C7D84E /* ImageCache.swift */; };
BA43D782BE85C7F5F20C624A /* AttributedStringBuilderProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 72F37B5DA798C9AE436F2C2C /* AttributedStringBuilderProtocol.swift */; }; BA43D782BE85C7F5F20C624A /* AttributedStringBuilderProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 72F37B5DA798C9AE436F2C2C /* AttributedStringBuilderProtocol.swift */; };
BA4C9049BC96DED3A2F3B82E /* RoomNotificationSettingsScreenViewModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03DD998E523D4EC93C7ED703 /* RoomNotificationSettingsScreenViewModelProtocol.swift */; }; BA4C9049BC96DED3A2F3B82E /* RoomNotificationSettingsScreenViewModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03DD998E523D4EC93C7ED703 /* RoomNotificationSettingsScreenViewModelProtocol.swift */; };
BAC845780F17CCFBC5A9CA37 /* AppLockUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = F733F135E6D67BBBEB76CC30 /* AppLockUITests.swift */; };
BB6BF528BC7F5B87E08C4F18 /* CameraPicker.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8A3B7637DDBD6AA97AC2545 /* CameraPicker.swift */; }; BB6BF528BC7F5B87E08C4F18 /* CameraPicker.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8A3B7637DDBD6AA97AC2545 /* CameraPicker.swift */; };
BB784A02BADB03C820617A46 /* TextRoomTimelineItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 90A55430639712CFACA34F43 /* TextRoomTimelineItem.swift */; }; BB784A02BADB03C820617A46 /* TextRoomTimelineItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 90A55430639712CFACA34F43 /* TextRoomTimelineItem.swift */; };
BB9B800C6094E34860E89DC5 /* AppLockSetupBiometricsScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8CCF9A924521DECA44778C4 /* AppLockSetupBiometricsScreen.swift */; }; BB9B800C6094E34860E89DC5 /* AppLockSetupBiometricsScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8CCF9A924521DECA44778C4 /* AppLockSetupBiometricsScreen.swift */; };
@ -918,7 +920,6 @@
EF5009AC03212227131C8AF2 /* RoomNotificationSettingsProxyProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = E55B5EA766E89FF1F87C3ACB /* RoomNotificationSettingsProxyProtocol.swift */; }; EF5009AC03212227131C8AF2 /* RoomNotificationSettingsProxyProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = E55B5EA766E89FF1F87C3ACB /* RoomNotificationSettingsProxyProtocol.swift */; };
EF7924005216B8189898F370 /* BackgroundTaskProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CA028DCD4157F9A1F999827 /* BackgroundTaskProtocol.swift */; }; EF7924005216B8189898F370 /* BackgroundTaskProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CA028DCD4157F9A1F999827 /* BackgroundTaskProtocol.swift */; };
EF890DEF0479E66548F2BA23 /* AppLockTimer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 490BEADEFB2D6B7C9F618AE8 /* AppLockTimer.swift */; }; EF890DEF0479E66548F2BA23 /* AppLockTimer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 490BEADEFB2D6B7C9F618AE8 /* AppLockTimer.swift */; };
F05516474DB42369FD976CEF /* AppLockScreenUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 349C633291427A0F29C28C54 /* AppLockScreenUITests.swift */; };
F0570F1ECD70C4C851FB2052 /* SecureBackupRecoveryKeyScreenViewModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 93E7304F5ECB4CB11CB10E60 /* SecureBackupRecoveryKeyScreenViewModelProtocol.swift */; }; F0570F1ECD70C4C851FB2052 /* SecureBackupRecoveryKeyScreenViewModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 93E7304F5ECB4CB11CB10E60 /* SecureBackupRecoveryKeyScreenViewModelProtocol.swift */; };
F06CE9132855E81EBB6DDC32 /* Kingfisher in Frameworks */ = {isa = PBXBuildFile; productRef = 940C605265DD82DA0C655E23 /* Kingfisher */; }; F06CE9132855E81EBB6DDC32 /* Kingfisher in Frameworks */ = {isa = PBXBuildFile; productRef = 940C605265DD82DA0C655E23 /* Kingfisher */; };
F07D88421A9BC4D03D4A5055 /* VideoRoomTimelineItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = F348B5F2C12F9D4F4B4D3884 /* VideoRoomTimelineItem.swift */; }; F07D88421A9BC4D03D4A5055 /* VideoRoomTimelineItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = F348B5F2C12F9D4F4B4D3884 /* VideoRoomTimelineItem.swift */; };
@ -1215,7 +1216,6 @@
33E49C5C6F802B4D94CA78D1 /* ro */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ro; path = ro.lproj/Localizable.strings; sourceTree = "<group>"; }; 33E49C5C6F802B4D94CA78D1 /* ro */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ro; path = ro.lproj/Localizable.strings; sourceTree = "<group>"; };
340179A0FC1AD4AEDA7FC134 /* CreateRoomViewModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CreateRoomViewModelProtocol.swift; sourceTree = "<group>"; }; 340179A0FC1AD4AEDA7FC134 /* CreateRoomViewModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CreateRoomViewModelProtocol.swift; sourceTree = "<group>"; };
342BEBC3C5FC3F9943C41C4C /* TemplateScreenViewModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TemplateScreenViewModelProtocol.swift; sourceTree = "<group>"; }; 342BEBC3C5FC3F9943C41C4C /* TemplateScreenViewModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TemplateScreenViewModelProtocol.swift; sourceTree = "<group>"; };
349C633291427A0F29C28C54 /* AppLockScreenUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppLockScreenUITests.swift; sourceTree = "<group>"; };
351E89CE2ED9B73C5CC47955 /* TimelineReactionsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimelineReactionsView.swift; sourceTree = "<group>"; }; 351E89CE2ED9B73C5CC47955 /* TimelineReactionsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimelineReactionsView.swift; sourceTree = "<group>"; };
3558A15CFB934F9229301527 /* RestorationToken.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RestorationToken.swift; sourceTree = "<group>"; }; 3558A15CFB934F9229301527 /* RestorationToken.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RestorationToken.swift; sourceTree = "<group>"; };
35AFCF4C05DEED04E3DB1A16 /* de */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = de; path = de.lproj/Localizable.strings; sourceTree = "<group>"; }; 35AFCF4C05DEED04E3DB1A16 /* de */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = de; path = de.lproj/Localizable.strings; sourceTree = "<group>"; };
@ -1855,6 +1855,7 @@
E9D059BFE329BE09B6D96A9F /* ro */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = ro; path = ro.lproj/Localizable.stringsdict; sourceTree = "<group>"; }; E9D059BFE329BE09B6D96A9F /* ro */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = ro; path = ro.lproj/Localizable.stringsdict; sourceTree = "<group>"; };
EB3B237387B8288A5A938F1B /* UserAgentBuilderTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserAgentBuilderTests.swift; sourceTree = "<group>"; }; EB3B237387B8288A5A938F1B /* UserAgentBuilderTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserAgentBuilderTests.swift; sourceTree = "<group>"; };
EBBC5E7C0F8337D2A46EB2DD /* MigrationScreenViewModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MigrationScreenViewModelProtocol.swift; sourceTree = "<group>"; }; EBBC5E7C0F8337D2A46EB2DD /* MigrationScreenViewModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MigrationScreenViewModelProtocol.swift; sourceTree = "<group>"; };
EBEB8D9F4940E161B18FE4BC /* UITestsNotificationCenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UITestsNotificationCenter.swift; sourceTree = "<group>"; };
EC589E641AE46EFB2962534D /* RoomMemberDetailsViewModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomMemberDetailsViewModelTests.swift; sourceTree = "<group>"; }; EC589E641AE46EFB2962534D /* RoomMemberDetailsViewModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomMemberDetailsViewModelTests.swift; sourceTree = "<group>"; };
ECB08484CD5D77C9BF97AA78 /* WaitlistScreenUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WaitlistScreenUITests.swift; sourceTree = "<group>"; }; ECB08484CD5D77C9BF97AA78 /* WaitlistScreenUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WaitlistScreenUITests.swift; sourceTree = "<group>"; };
ECD5FCBA169B6A82F501CA1B /* AnalyticsSettingsScreenViewModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AnalyticsSettingsScreenViewModelProtocol.swift; sourceTree = "<group>"; }; ECD5FCBA169B6A82F501CA1B /* AnalyticsSettingsScreenViewModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AnalyticsSettingsScreenViewModelProtocol.swift; sourceTree = "<group>"; };
@ -1892,6 +1893,7 @@
F5E23D8EE6CBACF32F1EC874 /* MediaPlayerProviderProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MediaPlayerProviderProtocol.swift; sourceTree = "<group>"; }; F5E23D8EE6CBACF32F1EC874 /* MediaPlayerProviderProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MediaPlayerProviderProtocol.swift; sourceTree = "<group>"; };
F6D698BFD68B061350553930 /* WaitingDialog.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WaitingDialog.swift; sourceTree = "<group>"; }; F6D698BFD68B061350553930 /* WaitingDialog.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WaitingDialog.swift; sourceTree = "<group>"; };
F72EFC8C634469F9262659C7 /* NSItemProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NSItemProvider.swift; sourceTree = "<group>"; }; F72EFC8C634469F9262659C7 /* NSItemProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NSItemProvider.swift; sourceTree = "<group>"; };
F733F135E6D67BBBEB76CC30 /* AppLockUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppLockUITests.swift; sourceTree = "<group>"; };
F73FF1A33198F5FAE9D34B1F /* FormattedBodyText.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FormattedBodyText.swift; sourceTree = "<group>"; }; F73FF1A33198F5FAE9D34B1F /* FormattedBodyText.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FormattedBodyText.swift; sourceTree = "<group>"; };
F7478623CECC9438014244BA /* ServerConfirmationScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ServerConfirmationScreen.swift; sourceTree = "<group>"; }; F7478623CECC9438014244BA /* ServerConfirmationScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ServerConfirmationScreen.swift; sourceTree = "<group>"; };
F754E66A8970963B15B2A41E /* PermalinkBuilder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PermalinkBuilder.swift; sourceTree = "<group>"; }; F754E66A8970963B15B2A41E /* PermalinkBuilder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PermalinkBuilder.swift; sourceTree = "<group>"; };
@ -2400,6 +2402,7 @@
children = ( children = (
8F94F70480243CAA65A2008C /* BlanckFormCoordinator.swift */, 8F94F70480243CAA65A2008C /* BlanckFormCoordinator.swift */,
46C208DA43CE25D13E670F40 /* UITestsAppCoordinator.swift */, 46C208DA43CE25D13E670F40 /* UITestsAppCoordinator.swift */,
EBEB8D9F4940E161B18FE4BC /* UITestsNotificationCenter.swift */,
6CEBE5EA91E8691EDF364EC2 /* UITestsScreenIdentifier.swift */, 6CEBE5EA91E8691EDF364EC2 /* UITestsScreenIdentifier.swift */,
B7F0192CE2F891141A25B49F /* UITestsSignalling.swift */, B7F0192CE2F891141A25B49F /* UITestsSignalling.swift */,
); );
@ -3694,8 +3697,8 @@
AF11DD57D9FACF2A757AB024 /* AnalyticsPromptUITests.swift */, AF11DD57D9FACF2A757AB024 /* AnalyticsPromptUITests.swift */,
16037EE9E9A52AF37B7818E3 /* AnalyticsSettingsScreenUITests.swift */, 16037EE9E9A52AF37B7818E3 /* AnalyticsSettingsScreenUITests.swift */,
7D0CBC76C80E04345E11F2DB /* Application.swift */, 7D0CBC76C80E04345E11F2DB /* Application.swift */,
349C633291427A0F29C28C54 /* AppLockScreenUITests.swift */,
E8A1BBEF7318CA6B6ACCF4AE /* AppLockSetupUITests.swift */, E8A1BBEF7318CA6B6ACCF4AE /* AppLockSetupUITests.swift */,
F733F135E6D67BBBEB76CC30 /* AppLockUITests.swift */,
5D2D0A6F1ABC99D29462FB84 /* AuthenticationCoordinatorUITests.swift */, 5D2D0A6F1ABC99D29462FB84 /* AuthenticationCoordinatorUITests.swift */,
C6FEA87EA3752203065ECE27 /* BugReportUITests.swift */, C6FEA87EA3752203065ECE27 /* BugReportUITests.swift */,
1D8866FE1CCCF10305FCACBC /* CallScreenUITests.swift */, 1D8866FE1CCCF10305FCACBC /* CallScreenUITests.swift */,
@ -5854,6 +5857,7 @@
706F79A39BDB32F592B8C2C7 /* UIKitBackgroundTask.swift in Sources */, 706F79A39BDB32F592B8C2C7 /* UIKitBackgroundTask.swift in Sources */,
3097A0A867D2B19CE32DAE58 /* UIKitBackgroundTaskService.swift in Sources */, 3097A0A867D2B19CE32DAE58 /* UIKitBackgroundTaskService.swift in Sources */,
E96005321849DBD7C72A28F2 /* UITestsAppCoordinator.swift in Sources */, E96005321849DBD7C72A28F2 /* UITestsAppCoordinator.swift in Sources */,
384D6B9A7DFD7260139D6852 /* UITestsNotificationCenter.swift in Sources */,
22882C710BC99EC34A5024A0 /* UITestsScreenIdentifier.swift in Sources */, 22882C710BC99EC34A5024A0 /* UITestsScreenIdentifier.swift in Sources */,
706289B086B0A6B0C211763F /* UITestsSignalling.swift in Sources */, 706289B086B0A6B0C211763F /* UITestsSignalling.swift in Sources */,
245F7FE5961BD10C145A26E0 /* UITimelineView.swift in Sources */, 245F7FE5961BD10C145A26E0 /* UITimelineView.swift in Sources */,
@ -5936,8 +5940,8 @@
795A854F63301DC6B46217B9 /* AccessibilityIdentifiers.swift in Sources */, 795A854F63301DC6B46217B9 /* AccessibilityIdentifiers.swift in Sources */,
8024BE37156FF0A95A7A3465 /* AnalyticsPromptUITests.swift in Sources */, 8024BE37156FF0A95A7A3465 /* AnalyticsPromptUITests.swift in Sources */,
BF675964C9159F718589C36A /* AnalyticsSettingsScreenUITests.swift in Sources */, BF675964C9159F718589C36A /* AnalyticsSettingsScreenUITests.swift in Sources */,
F05516474DB42369FD976CEF /* AppLockScreenUITests.swift in Sources */,
44DA28B1E1F9C97C5795F7B3 /* AppLockSetupUITests.swift in Sources */, 44DA28B1E1F9C97C5795F7B3 /* AppLockSetupUITests.swift in Sources */,
BAC845780F17CCFBC5A9CA37 /* AppLockUITests.swift in Sources */,
7405B4824D45BA7C3D943E76 /* Application.swift in Sources */, 7405B4824D45BA7C3D943E76 /* Application.swift in Sources */,
ACF094CF3BF02DBFA6DFDE60 /* AuthenticationCoordinatorUITests.swift in Sources */, ACF094CF3BF02DBFA6DFDE60 /* AuthenticationCoordinatorUITests.swift in Sources */,
7756C4E90CABE6F14F7920A0 /* BugReportUITests.swift in Sources */, 7756C4E90CABE6F14F7920A0 /* BugReportUITests.swift in Sources */,

View File

@ -18,5 +18,6 @@ import Foundation
protocol AppCoordinatorProtocol: CoordinatorProtocol { protocol AppCoordinatorProtocol: CoordinatorProtocol {
var notificationManager: NotificationManagerProtocol { get } var notificationManager: NotificationManagerProtocol { get }
var windowManager: WindowManager { get }
@discardableResult func handleDeepLink(_ url: URL) -> Bool @discardableResult func handleDeepLink(_ url: URL) -> Bool
} }

View File

@ -15,8 +15,7 @@
// //
import Combine import Combine
import Foundation import SwiftUI
import UIKit
enum AppDelegateCallback { enum AppDelegateCallback {
case registeredNotifications(deviceToken: Data) case registeredNotifications(deviceToken: Data)

View File

@ -29,10 +29,9 @@ struct Application: App {
} else if ProcessInfo.isRunningUnitTests { } else if ProcessInfo.isRunningUnitTests {
appCoordinator = UnitTestsAppCoordinator() appCoordinator = UnitTestsAppCoordinator()
} else { } else {
let coordinator = AppCoordinator(appDelegate: appDelegate) appCoordinator = AppCoordinator(appDelegate: appDelegate)
SceneDelegate.windowManager = coordinator.windowManager
appCoordinator = coordinator
} }
SceneDelegate.windowManager = appCoordinator.windowManager
} }
var body: some Scene { var body: some Scene {

View File

@ -23,7 +23,7 @@ class SceneDelegate: NSObject, UIWindowSceneDelegate {
weak static var windowManager: WindowManager! weak static var windowManager: WindowManager!
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) { func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
guard let windowScene = scene as? UIWindowScene, !ProcessInfo.isRunningTests else { return } guard let windowScene = scene as? UIWindowScene else { return }
Self.windowManager.configure(with: windowScene) Self.windowManager.configure(with: windowScene)
} }
} }

View File

@ -40,7 +40,9 @@ class AppLockFlowCoordinator: CoordinatorProtocol {
actionsSubject.eraseToAnyPublisher() actionsSubject.eraseToAnyPublisher()
} }
init(appLockService: AppLockServiceProtocol, navigationCoordinator: NavigationRootCoordinator) { init(appLockService: AppLockServiceProtocol,
navigationCoordinator: NavigationRootCoordinator,
notificationCenter: NotificationCenter = .default) {
self.appLockService = appLockService self.appLockService = appLockService
self.navigationCoordinator = navigationCoordinator self.navigationCoordinator = navigationCoordinator
@ -54,13 +56,13 @@ class AppLockFlowCoordinator: CoordinatorProtocol {
} }
.store(in: &cancellables) .store(in: &cancellables)
NotificationCenter.default.publisher(for: UIApplication.didEnterBackgroundNotification) notificationCenter.publisher(for: UIApplication.didEnterBackgroundNotification)
.sink { [weak self] _ in .sink { [weak self] _ in
self?.applicationDidEnterBackground() self?.applicationDidEnterBackground()
} }
.store(in: &cancellables) .store(in: &cancellables)
NotificationCenter.default.publisher(for: UIApplication.willEnterForegroundNotification) notificationCenter.publisher(for: UIApplication.willEnterForegroundNotification)
.sink { [weak self] _ in .sink { [weak self] _ in
self?.applicationWillEnterForeground() self?.applicationWillEnterForeground()
} }

View File

@ -19,6 +19,7 @@ import Foundation
enum A11yIdentifiers { enum A11yIdentifiers {
static let alertInfo = AlertInfo() static let alertInfo = AlertInfo()
static let analyticsPromptScreen = AnalyticsPromptScreen() static let analyticsPromptScreen = AnalyticsPromptScreen()
static let appLockScreen = AppLockScreen()
static let appLockSetupBiometricsScreen = AppLockSetupBiometricsScreen() static let appLockSetupBiometricsScreen = AppLockSetupBiometricsScreen()
static let appLockSetupPINScreen = AppLockSetupPINScreen() static let appLockSetupPINScreen = AppLockSetupPINScreen()
static let appLockSetupSettingsScreen = AppLockSetupSettingsScreen() static let appLockSetupSettingsScreen = AppLockSetupSettingsScreen()
@ -51,6 +52,10 @@ enum A11yIdentifiers {
let secondaryButton = "alert_info-secondary_button" let secondaryButton = "alert_info-secondary_button"
} }
struct AppLockScreen {
func numpad(_ digit: Int) -> String { "app_lock-numpad_\(digit)" }
}
struct AppLockSetupBiometricsScreen { struct AppLockSetupBiometricsScreen {
let allow = "app_lock_setup_biometrics-allow" let allow = "app_lock_setup_biometrics-allow"
} }

View File

@ -27,12 +27,14 @@ struct AppLockScreenPINKeypad: View {
ForEach(1..<4) { column in ForEach(1..<4) { column in
let digit = (3 * row) + column let digit = (3 * row) + column
Button("\(digit)") { press(digit) } Button("\(digit)") { press(digit) }
.accessibilityIdentifier(A11yIdentifiers.appLockScreen.numpad(digit))
} }
} }
} }
GridRow { GridRow {
Button("") { }.hidden() Button("") { }.hidden()
Button("0") { press(0) } Button("0") { press(0) }
.accessibilityIdentifier(A11yIdentifiers.appLockScreen.numpad(0))
Button(action: pressDelete) { Button(action: pressDelete) {
Image(systemSymbol: .deleteBackward) Image(systemSymbol: .deleteBackward)
.symbolVariant(.fill) .symbolVariant(.fill)

View File

@ -125,9 +125,9 @@ class MockRoomTimelineController: RoomTimelineControllerProtocol {
/// Handles a UI test signal as necessary. /// Handles a UI test signal as necessary.
private func handleSignal(_ signal: UITestsSignal) async throws { private func handleSignal(_ signal: UITestsSignal) async throws {
switch signal { switch signal {
case .paginate: case .timeline(.paginate):
try await simulateBackPagination() try await simulateBackPagination()
case .incomingMessage: case .timeline(.incomingMessage):
try await simulateIncomingItem() try await simulateIncomingItem()
default: default:
break break

View File

@ -19,10 +19,13 @@ import MatrixRustSDK
import SwiftUI import SwiftUI
import UIKit import UIKit
class UITestsAppCoordinator: AppCoordinatorProtocol { class UITestsAppCoordinator: AppCoordinatorProtocol, WindowManagerDelegate {
private let navigationRootCoordinator: NavigationRootCoordinator private let navigationRootCoordinator: NavigationRootCoordinator
private var mockScreen: MockScreen? private var mockScreen: MockScreen?
private var alternateWindowMockScreen: MockScreen?
let notificationManager: NotificationManagerProtocol = NotificationManagerMock() let notificationManager: NotificationManagerProtocol = NotificationManagerMock()
let windowManager = WindowManager()
init() { init() {
// disabling View animations // disabling View animations
@ -30,6 +33,8 @@ class UITestsAppCoordinator: AppCoordinatorProtocol {
navigationRootCoordinator = NavigationRootCoordinator() navigationRootCoordinator = NavigationRootCoordinator()
windowManager.delegate = self
ServiceLocator.shared.register(userIndicatorController: UserIndicatorControllerMock.default) ServiceLocator.shared.register(userIndicatorController: UserIndicatorControllerMock.default)
AppSettings.configureWithSuiteName("io.element.elementx.uitests") AppSettings.configureWithSuiteName("io.element.elementx.uitests")
@ -42,14 +47,6 @@ class UITestsAppCoordinator: AppCoordinatorProtocol {
} }
func start() { func start() {
// Fix the app tint colour.
UIApplication.shared.connectedScenes.forEach { scene in
guard let delegate = scene.delegate as? UIWindowSceneDelegate else {
return
}
delegate.window??.tintColor = .compound.textActionPrimary
}
guard let screenID = ProcessInfo.testScreenID else { fatalError("Unable to launch with unknown screen.") } guard let screenID = ProcessInfo.testScreenID else { fatalError("Unable to launch with unknown screen.") }
let mockScreen = MockScreen(id: screenID) let mockScreen = MockScreen(id: screenID)
@ -64,17 +61,27 @@ class UITestsAppCoordinator: AppCoordinatorProtocol {
func handleDeepLink(_ url: URL) -> Bool { func handleDeepLink(_ url: URL) -> Bool {
fatalError("Not implemented.") fatalError("Not implemented.")
} }
func windowManagerDidConfigureWindows(_ windowManager: WindowManager) {
guard let screenID = ProcessInfo.testScreenID, screenID == .appLockFlow || screenID == .appLockFlowDisabled else { return }
let screen = MockScreen(id: screenID == .appLockFlow ? .appLockFlowAlternateWindow : .appLockFlowDisabledAlternateWindow, windowManager: windowManager)
windowManager.alternateWindow.rootViewController = UIHostingController(rootView: screen.coordinator.toPresentable().statusBarHidden())
alternateWindowMockScreen = screen
}
} }
@MainActor @MainActor
class MockScreen: Identifiable { class MockScreen: Identifiable {
let id: UITestsScreenIdentifier let id: UITestsScreenIdentifier
let windowManager: WindowManager?
private var retainedState = [Any]() private var retainedState = [Any]()
private var cancellables = Set<AnyCancellable>() private var cancellables = Set<AnyCancellable>()
init(id: UITestsScreenIdentifier) { init(id: UITestsScreenIdentifier, windowManager: WindowManager? = nil) {
self.id = id self.id = id
self.windowManager = windowManager
} }
lazy var coordinator: CoordinatorProtocol = { lazy var coordinator: CoordinatorProtocol = {
@ -158,24 +165,15 @@ class MockScreen: Identifiable {
let coordinator = TemplateScreenCoordinator(parameters: .init()) let coordinator = TemplateScreenCoordinator(parameters: .init())
navigationStackCoordinator.setRootCoordinator(coordinator) navigationStackCoordinator.setRootCoordinator(coordinator)
return navigationStackCoordinator return navigationStackCoordinator
case .appLockScreen: case .appLockFlow, .appLockFlowDisabled:
let appLockService = AppLockService(keychainController: KeychainControllerMock(), appSettings: ServiceLocator.shared.settings) // The tested coordinator is setup below in the alternate window.
let coordinator = AppLockScreenCoordinator(parameters: .init(appLockService: appLockService)) // Here we just return a blank screen to snapshot as the unlocked app.
return coordinator return BlankFormCoordinator()
case .appLockSetupFlow, .appLockSetupFlowUnlock, .appLockSetupFlowMandatory: case .appLockFlowAlternateWindow, .appLockFlowDisabledAlternateWindow:
let navigationStackCoordinator = NavigationStackCoordinator() let navigationCoordinator = NavigationRootCoordinator()
// The flow expects an existing root coordinator, use the placeholder as a placeholder 😅
navigationStackCoordinator.setRootCoordinator(BlankFormCoordinator())
let keychainController = KeychainController(service: .tests, accessGroup: InfoPlistReader.main.keychainAccessGroupIdentifier) let keychainController = KeychainController(service: .tests, accessGroup: InfoPlistReader.main.keychainAccessGroupIdentifier)
keychainController.resetSecrets() keychainController.resetSecrets()
if id == .appLockSetupFlowUnlock {
do {
try keychainController.setPINCode("2023")
} catch {
fatalError("Failed to pre-set the PIN code")
}
}
let context = LAContextMock() let context = LAContextMock()
context.biometryTypeValue = UIDevice.current.isPhone ? .faceID : .touchID // (iPhone 14 & iPad 9th gen) context.biometryTypeValue = UIDevice.current.isPhone ? .faceID : .touchID // (iPhone 14 & iPad 9th gen)
@ -186,6 +184,59 @@ class MockScreen: Identifiable {
appSettings: ServiceLocator.shared.settings, appSettings: ServiceLocator.shared.settings,
context: context) context: context)
if id == .appLockFlowAlternateWindow {
guard case .success = appLockService.setupPINCode("2023") else {
fatalError("Failed to preset the PIN code.")
}
}
let notificationCenter = UITestsNotificationCenter()
do {
try notificationCenter.startListening()
} catch {
fatalError("Failed to start listening for notifications.")
}
let coordinator = AppLockFlowCoordinator(appLockService: appLockService,
navigationCoordinator: navigationCoordinator,
notificationCenter: notificationCenter)
guard let windowManager else { fatalError("The window manager must be supplied.") }
coordinator.actions
.sink { action in
switch action {
case .lockApp:
windowManager.switchToAlternate()
case .unlockApp:
windowManager.switchToMain()
case .forceLogout:
break
}
}
.store(in: &cancellables)
return coordinator
case .appLockSetupFlow, .appLockSetupFlowUnlock, .appLockSetupFlowMandatory:
let navigationStackCoordinator = NavigationStackCoordinator()
// The flow expects an existing root coordinator, use a blank form as a placeholder.
navigationStackCoordinator.setRootCoordinator(BlankFormCoordinator())
let keychainController = KeychainController(service: .tests, accessGroup: InfoPlistReader.main.keychainAccessGroupIdentifier)
keychainController.resetSecrets()
let context = LAContextMock()
context.biometryTypeValue = UIDevice.current.isPhone ? .faceID : .touchID // (iPhone 14 & iPad 9th gen)
context.evaluatePolicyReturnValue = true
context.evaluatedPolicyDomainStateValue = "😎".data(using: .utf8)
let appLockService = AppLockService(keychainController: keychainController,
appSettings: ServiceLocator.shared.settings,
context: context)
if id == .appLockSetupFlowUnlock, case .failure = appLockService.setupPINCode("2023") {
fatalError("Failed to pre-set the PIN code")
}
let flow: AppLockSetupFlowCoordinator.PresentationFlow = id == .appLockSetupFlowMandatory ? .onboarding : .settings let flow: AppLockSetupFlowCoordinator.PresentationFlow = id == .appLockSetupFlowMandatory ? .onboarding : .settings
let coordinator = AppLockSetupFlowCoordinator(presentingFlow: flow, let coordinator = AppLockSetupFlowCoordinator(presentingFlow: flow,
appLockService: appLockService, appLockService: appLockService,

View File

@ -0,0 +1,57 @@
//
// Copyright 2023 New Vector Ltd
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
import Combine
import SwiftUI
@MainActor
/// A notification center that can be injected in the app to post notifications
/// that are sent from the UI tests runner. Usage:
/// - Create an instance of the center in the screen you want to test and call `startListening`.
/// - Create a `UITestSignalling.Client` in the `.tests` mode in your tests.
/// - Start the app from the tests and call `client.waitForApp()` to establish communication.
/// - Send the notification from the tests you would like posted in the app.
class UITestsNotificationCenter: NotificationCenter {
private var client: UITestsSignalling.Client?
private var signalCancellable: AnyCancellable?
/// Starts listening for signals to post notifications.
func startListening() throws {
let client = try UITestsSignalling.Client(mode: .app)
signalCancellable = client.signals.sink { [weak self] signal in
Task {
do {
try await self?.handleSignal(signal)
} catch {
MXLog.error(error.localizedDescription)
}
}
}
self.client = client
}
/// Handles any notification signals, and drops anything else received.
private func handleSignal(_ signal: UITestsSignal) async throws {
switch signal {
case .notification(let name):
post(name: name, object: nil)
default:
break
}
}
}

View File

@ -29,7 +29,10 @@ enum UITestsScreenIdentifier: String {
case analyticsSettingsScreen case analyticsSettingsScreen
case migration case migration
case templateScreen case templateScreen
case appLockScreen case appLockFlow
case appLockFlowAlternateWindow
case appLockFlowDisabled
case appLockFlowDisabledAlternateWindow
case appLockSetupFlow case appLockSetupFlow
case appLockSetupFlowUnlock case appLockSetupFlowUnlock
case appLockSetupFlowMandatory case appLockSetupFlowMandatory

View File

@ -18,15 +18,24 @@ import Combine
import KZFileWatchers import KZFileWatchers
import SwiftUI import SwiftUI
enum UITestsSignal: String { extension Notification.Name: Codable { }
enum UITestsSignal: Codable, Equatable {
/// An internal signal used to indicate that one side of the connection is ready. /// An internal signal used to indicate that one side of the connection is ready.
case ready case ready
/// The operation has completed successfully.
case success
case timeline(Timeline)
enum Timeline: Codable {
/// Ask the app to back paginate. /// Ask the app to back paginate.
case paginate case paginate
/// Ask the app to simulate an incoming message. /// Ask the app to simulate an incoming message.
case incomingMessage case incomingMessage
/// The operation has completed successfully. }
case success
/// Posts a notification.
case notification(name: Notification.Name)
} }
enum UITestsSignalError: String, LocalizedError { enum UITestsSignalError: String, LocalizedError {
@ -60,7 +69,7 @@ enum UITestsSignalling {
}() }()
/// A mode that defines the behaviour of the client. /// A mode that defines the behaviour of the client.
enum Mode: String { case app, tests } enum Mode: Codable { case app, tests }
/// The mode that the client is using. /// The mode that the client is using.
let mode: Mode let mode: Mode
@ -78,10 +87,10 @@ enum UITestsSignalling {
switch mode { switch mode {
case .tests: case .tests:
// The tests client is started first and writes to the file saying it is ready. // The tests client is started first and writes to the file saying it is ready.
try rawSignal(.ready).write(to: fileURL, atomically: false, encoding: .utf8) try rawMessage(.ready).write(to: fileURL, atomically: false, encoding: .utf8)
case .app: case .app:
// The app client is started second and checks that there is a ready signal from the tests. // The app client is started second and checks that there is a ready signal from the tests.
guard try String(contentsOf: fileURL) == "\(Mode.tests):\(UITestsSignal.ready)" else { throw UITestsSignalError.testsClientNotReady } guard try String(contentsOf: fileURL) == Message(mode: .tests, signal: .ready).rawValue else { throw UITestsSignalError.testsClientNotReady }
isConnected = true isConnected = true
// The app client then echoes back to the tests that it is now ready. // The app client then echoes back to the tests that it is now ready.
try send(.ready) try send(.ready)
@ -110,15 +119,42 @@ enum UITestsSignalling {
func send(_ signal: UITestsSignal) throws { func send(_ signal: UITestsSignal) throws {
guard isConnected else { throw UITestsSignalError.notConnected } guard isConnected else { throw UITestsSignalError.notConnected }
let rawSignal = rawSignal(signal) let rawMessage = rawMessage(signal)
try rawSignal.write(to: fileURL, atomically: false, encoding: .utf8) try rawMessage.write(to: fileURL, atomically: false, encoding: .utf8)
NSLog("UITestsSignalling: Sent \(rawSignal)") NSLog("UITestsSignalling: Sent \(rawMessage)")
} }
/// The signal formatted as a string, prefixed with an identifier for the sender. /// The signal formatted as a complete message string, including the identifier for this sender.
/// E.g. The tests client would produce `tests:ready` for the ready signal. private func rawMessage(_ signal: UITestsSignal) -> String {
private func rawSignal(_ signal: UITestsSignal) -> String { Message(mode: mode, signal: signal).rawValue
"\(mode.rawValue):\(signal.rawValue)" }
/// The complete data that is serialised to disk for signalling.
/// This consists of the signal along with an identifier for the sender.
private struct Message: Codable {
let mode: Mode
let signal: UITestsSignal
init(mode: Mode, signal: UITestsSignal) {
self.mode = mode
self.signal = signal
}
var rawValue: String {
guard let data = try? JSONEncoder().encode(self),
let string = String(data: data, encoding: .utf8) else {
return "unknown"
}
return string
}
init?(rawValue: String) {
guard let data = rawValue.data(using: .utf8),
let value = try? JSONDecoder().decode(Self.self, from: data) else {
return nil
}
self = value
}
} }
/// Handles a file refresh to receive a new signal. /// Handles a file refresh to receive a new signal.
@ -134,22 +170,19 @@ enum UITestsSignalling {
/// Processes string data from the file and publishes its signal. /// Processes string data from the file and publishes its signal.
private func processFileData(_ data: Data) { private func processFileData(_ data: Data) {
guard let message = String(data: data, encoding: .utf8) else { return } guard let rawMessage = String(data: data, encoding: .utf8) else { return }
let components = message.components(separatedBy: ":") guard let message = Message(rawValue: rawMessage),
message.mode != mode // Filter out messages sent by this client.
guard components.count == 2,
components[0] != mode.rawValue, // Filter out messages sent by this client.
let signal = UITestsSignal(rawValue: components[1])
else { return } else { return }
if signal == .ready { if message.signal == .ready {
isConnected = true isConnected = true
} }
signals.send(signal) signals.send(message.signal)
NSLog("UITestsSignalling: Received \(message)") NSLog("UITestsSignalling: Received \(rawMessage)")
} }
} }
} }

View File

@ -18,6 +18,7 @@ import SwiftUI
class UnitTestsAppCoordinator: AppCoordinatorProtocol { class UnitTestsAppCoordinator: AppCoordinatorProtocol {
let notificationManager: NotificationManagerProtocol = NotificationManagerMock() let notificationManager: NotificationManagerProtocol = NotificationManagerMock()
let windowManager = WindowManager()
init() { init() {
ServiceLocator.shared.register(userIndicatorController: UserIndicatorControllerMock.default) ServiceLocator.shared.register(userIndicatorController: UserIndicatorControllerMock.default)

View File

@ -14,7 +14,6 @@
// limitations under the License. // limitations under the License.
// //
import ElementX
import XCTest import XCTest
@MainActor @MainActor

View File

@ -14,7 +14,6 @@
// limitations under the License. // limitations under the License.
// //
import ElementX
import XCTest import XCTest
@MainActor @MainActor

View File

@ -14,7 +14,6 @@
// limitations under the License. // limitations under the License.
// //
import ElementX
import XCTest import XCTest
@MainActor @MainActor

View File

@ -1,26 +0,0 @@
//
// Copyright 2022 New Vector Ltd
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
import ElementX
import XCTest
@MainActor
class AppLockScreenUITests: XCTestCase {
func testScreen() async throws {
let app = Application.launch(.appLockScreen)
try await app.assertScreenshot(.appLockScreen)
}
}

View File

@ -16,8 +16,6 @@
import XCTest import XCTest
@testable import ElementX
@MainActor @MainActor
class AppLockSetupUITests: XCTestCase { class AppLockSetupUITests: XCTestCase {
var app: XCUIApplication! var app: XCUIApplication!

View File

@ -0,0 +1,87 @@
//
// Copyright 2022 New Vector Ltd
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
import XCTest
@MainActor
class AppLockUITests: XCTestCase {
var app: XCUIApplication!
enum Step {
static let placeholder = 0
static let lockScreen = 1
static let unlocked = 99
}
func testFlowEnabled() async throws {
// Given an app with screen lock enabled.
let client = try UITestsSignalling.Client(mode: .tests)
app = Application.launch(.appLockFlow)
await client.waitForApp()
// Blank form representing an unlocked app.
try await app.assertScreenshot(.appLockFlow, step: Step.unlocked)
// When backgrounding the app.
try client.send(.notification(name: UIApplication.didEnterBackgroundNotification))
// Then the placeholder screen should obscure the content.
try await app.assertScreenshot(.appLockFlow, step: Step.placeholder)
// When foregrounding the app.
try client.send(.notification(name: UIApplication.willEnterForegroundNotification))
// Then the Lock Screen should be shown to enter a PIN.
try await app.assertScreenshot(.appLockFlow, step: Step.lockScreen)
// When entering a PIN
enterPIN()
// Then the app should be unlocked again.
try await app.assertScreenshot(.appLockFlow, step: Step.unlocked)
}
func testFlowDisabled() async throws {
// Given an app with screen lock enabled.
let client = try UITestsSignalling.Client(mode: .tests)
app = Application.launch(.appLockFlowDisabled)
await client.waitForApp()
// Blank form representing an unlocked app.
try await app.assertScreenshot(.appLockFlow, step: Step.unlocked)
// When backgrounding the app.
try client.send(.notification(name: UIApplication.didEnterBackgroundNotification))
// Then the app should remain unlocked.
try await app.assertScreenshot(.appLockFlow, step: Step.unlocked)
// When foregrounding the app.
try client.send(.notification(name: UIApplication.willEnterForegroundNotification))
// Then the app should still remain unlocked.
try await app.assertScreenshot(.appLockFlow, step: Step.unlocked)
}
// MARK: - Helpers
func enterPIN() {
app.buttons[A11yIdentifiers.appLockScreen.numpad(2)].tap()
app.buttons[A11yIdentifiers.appLockScreen.numpad(0)].tap()
app.buttons[A11yIdentifiers.appLockScreen.numpad(2)].tap()
app.buttons[A11yIdentifiers.appLockScreen.numpad(3)].tap()
}
}

View File

@ -16,8 +16,6 @@
import XCTest import XCTest
@testable import ElementX
@MainActor @MainActor
class AuthenticationCoordinatorUITests: XCTestCase { class AuthenticationCoordinatorUITests: XCTestCase {
func testLoginWithPassword() async throws { func testLoginWithPassword() async throws {

View File

@ -14,7 +14,6 @@
// limitations under the License. // limitations under the License.
// //
import ElementX
import XCTest import XCTest
@MainActor @MainActor

View File

@ -14,7 +14,6 @@
// limitations under the License. // limitations under the License.
// //
import ElementX
import XCTest import XCTest
@MainActor @MainActor

View File

@ -14,7 +14,6 @@
// limitations under the License. // limitations under the License.
// //
import ElementX
import XCTest import XCTest
@MainActor @MainActor

View File

@ -14,7 +14,6 @@
// limitations under the License. // limitations under the License.
// //
import ElementX
import XCTest import XCTest
@MainActor @MainActor

View File

@ -14,7 +14,6 @@
// limitations under the License. // limitations under the License.
// //
import ElementX
import XCTest import XCTest
@MainActor @MainActor

View File

@ -14,7 +14,6 @@
// limitations under the License. // limitations under the License.
// //
import ElementX
import XCTest import XCTest
@MainActor @MainActor

View File

@ -14,7 +14,6 @@
// limitations under the License. // limitations under the License.
// //
import ElementX
import XCTest import XCTest
@MainActor @MainActor

View File

@ -14,7 +14,6 @@
// limitations under the License. // limitations under the License.
// //
import ElementX
import XCTest import XCTest
@MainActor @MainActor

View File

@ -14,7 +14,6 @@
// limitations under the License. // limitations under the License.
// //
import ElementX
import XCTest import XCTest
@MainActor @MainActor

View File

@ -14,7 +14,6 @@
// limitations under the License. // limitations under the License.
// //
import ElementX
import XCTest import XCTest
@MainActor @MainActor

View File

@ -14,7 +14,6 @@
// limitations under the License. // limitations under the License.
// //
import ElementX
import XCTest import XCTest
@MainActor @MainActor

View File

@ -14,7 +14,6 @@
// limitations under the License. // limitations under the License.
// //
import ElementX
import XCTest import XCTest
@MainActor @MainActor

View File

@ -14,7 +14,6 @@
// limitations under the License. // limitations under the License.
// //
import ElementX
import XCTest import XCTest
@MainActor @MainActor

View File

@ -14,7 +14,6 @@
// limitations under the License. // limitations under the License.
// //
import ElementX
import XCTest import XCTest
@MainActor @MainActor

View File

@ -14,7 +14,6 @@
// limitations under the License. // limitations under the License.
// //
import ElementX
import XCTest import XCTest
@MainActor @MainActor

View File

@ -14,7 +14,6 @@
// limitations under the License. // limitations under the License.
// //
import ElementX
import XCTest import XCTest
@MainActor @MainActor

View File

@ -14,7 +14,6 @@
// limitations under the License. // limitations under the License.
// //
import ElementX
import XCTest import XCTest
@MainActor @MainActor

View File

@ -14,7 +14,6 @@
// limitations under the License. // limitations under the License.
// //
import ElementX
import XCTest import XCTest
@MainActor @MainActor

View File

@ -14,7 +14,6 @@
// limitations under the License. // limitations under the License.
// //
import ElementX
import XCTest import XCTest
@MainActor @MainActor

View File

@ -14,7 +14,6 @@
// limitations under the License. // limitations under the License.
// //
import ElementX
import XCTest import XCTest
@MainActor @MainActor

View File

@ -14,7 +14,6 @@
// limitations under the License. // limitations under the License.
// //
import ElementX
import XCTest import XCTest
@MainActor @MainActor
@ -181,8 +180,8 @@ class RoomScreenUITests: XCTestCase {
// MARK: - Helper Methods // MARK: - Helper Methods
private func performOperation(_ operation: UITestsSignal, using client: UITestsSignalling.Client) async throws { private func performOperation(_ operation: UITestsSignal.Timeline, using client: UITestsSignalling.Client) async throws {
try client.send(operation) try client.send(.timeline(operation))
await _ = client.signals.values.first { $0 == .success } await _ = client.signals.values.first { $0 == .success }
try await Task.sleep(for: .seconds(2)) // Allow the timeline to update try await Task.sleep(for: .seconds(2)) // Allow the timeline to update
} }

View File

@ -14,7 +14,6 @@
// limitations under the License. // limitations under the License.
// //
import ElementX
import XCTest import XCTest
@MainActor @MainActor

View File

@ -14,7 +14,6 @@
// limitations under the License. // limitations under the License.
// //
import ElementX
import XCTest import XCTest
@MainActor @MainActor

View File

@ -14,7 +14,6 @@
// limitations under the License. // limitations under the License.
// //
import ElementX
import XCTest import XCTest
@MainActor @MainActor

View File

@ -14,7 +14,6 @@
// limitations under the License. // limitations under the License.
// //
import ElementX
import XCTest import XCTest
@MainActor @MainActor

View File

@ -14,7 +14,6 @@
// limitations under the License. // limitations under the License.
// //
import ElementX
import XCTest import XCTest
@MainActor @MainActor

View File

@ -14,7 +14,6 @@
// limitations under the License. // limitations under the License.
// //
import ElementX
import XCTest import XCTest
@MainActor @MainActor

View File

@ -14,7 +14,6 @@
// limitations under the License. // limitations under the License.
// //
import ElementX
import XCTest import XCTest
@MainActor @MainActor

View File

@ -14,7 +14,6 @@
// limitations under the License. // limitations under the License.
// //
import ElementX
import XCTest import XCTest
@MainActor @MainActor

View File

@ -14,7 +14,6 @@
// limitations under the License. // limitations under the License.
// //
import ElementX
import XCTest import XCTest
@MainActor @MainActor

View File

@ -14,7 +14,6 @@
// limitations under the License. // limitations under the License.
// //
import ElementX
import XCTest import XCTest
@MainActor @MainActor

View File

@ -14,7 +14,6 @@
// limitations under the License. // limitations under the License.
// //
import ElementX
import XCTest import XCTest
@MainActor @MainActor

View File

@ -14,7 +14,6 @@
// limitations under the License. // limitations under the License.
// //
import ElementX
import XCTest import XCTest
@MainActor @MainActor

View File

@ -14,7 +14,6 @@
// limitations under the License. // limitations under the License.
// //
import ElementX
import XCTest import XCTest
@MainActor @MainActor

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.