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
71 changed files with 348 additions and 147 deletions
+8 -4
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 */,
@@ -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
} }
@@ -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)
@@ -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 {
@@ -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)
} }
} }
@@ -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()
} }
@@ -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"
} }
@@ -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)
@@ -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
@@ -19,17 +19,22 @@ 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
UIView.setAnimationsEnabled(false) UIView.setAnimationsEnabled(false)
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,
@@ -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
}
}
}
@@ -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
@@ -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
/// Ask the app to back paginate.
case paginate
/// Ask the app to simulate an incoming message.
case incomingMessage
/// The operation has completed successfully. /// The operation has completed successfully.
case success case success
case timeline(Timeline)
enum Timeline: Codable {
/// Ask the app to back paginate.
case paginate
/// Ask the app to simulate an incoming message.
case incomingMessage
}
/// 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)")
} }
} }
} }
@@ -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)
@@ -14,7 +14,6 @@
// limitations under the License. // limitations under the License.
// //
import ElementX
import XCTest import XCTest
@MainActor @MainActor
@@ -14,7 +14,6 @@
// limitations under the License. // limitations under the License.
// //
import ElementX
import XCTest import XCTest
@MainActor @MainActor
@@ -14,7 +14,6 @@
// limitations under the License. // limitations under the License.
// //
import ElementX
import XCTest import XCTest
@MainActor @MainActor
@@ -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)
}
}
@@ -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!
+87
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()
}
}
@@ -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 {
-1
View File
@@ -14,7 +14,6 @@
// limitations under the License. // limitations under the License.
// //
import ElementX
import XCTest import XCTest
@MainActor @MainActor
-1
View File
@@ -14,7 +14,6 @@
// limitations under the License. // limitations under the License.
// //
import ElementX
import XCTest import XCTest
@MainActor @MainActor
@@ -14,7 +14,6 @@
// limitations under the License. // limitations under the License.
// //
import ElementX
import XCTest import XCTest
@MainActor @MainActor
@@ -14,7 +14,6 @@
// limitations under the License. // limitations under the License.
// //
import ElementX
import XCTest import XCTest
@MainActor @MainActor
@@ -14,7 +14,6 @@
// limitations under the License. // limitations under the License.
// //
import ElementX
import XCTest import XCTest
@MainActor @MainActor
@@ -14,7 +14,6 @@
// limitations under the License. // limitations under the License.
// //
import ElementX
import XCTest import XCTest
@MainActor @MainActor
@@ -14,7 +14,6 @@
// limitations under the License. // limitations under the License.
// //
import ElementX
import XCTest import XCTest
@MainActor @MainActor
@@ -14,7 +14,6 @@
// limitations under the License. // limitations under the License.
// //
import ElementX
import XCTest import XCTest
@MainActor @MainActor
-1
View File
@@ -14,7 +14,6 @@
// limitations under the License. // limitations under the License.
// //
import ElementX
import XCTest import XCTest
@MainActor @MainActor
@@ -14,7 +14,6 @@
// limitations under the License. // limitations under the License.
// //
import ElementX
import XCTest import XCTest
@MainActor @MainActor
@@ -14,7 +14,6 @@
// limitations under the License. // limitations under the License.
// //
import ElementX
import XCTest import XCTest
@MainActor @MainActor
@@ -14,7 +14,6 @@
// limitations under the License. // limitations under the License.
// //
import ElementX
import XCTest import XCTest
@MainActor @MainActor
@@ -14,7 +14,6 @@
// limitations under the License. // limitations under the License.
// //
import ElementX
import XCTest import XCTest
@MainActor @MainActor
@@ -14,7 +14,6 @@
// limitations under the License. // limitations under the License.
// //
import ElementX
import XCTest import XCTest
@MainActor @MainActor
@@ -14,7 +14,6 @@
// limitations under the License. // limitations under the License.
// //
import ElementX
import XCTest import XCTest
@MainActor @MainActor
@@ -14,7 +14,6 @@
// limitations under the License. // limitations under the License.
// //
import ElementX
import XCTest import XCTest
@MainActor @MainActor
@@ -14,7 +14,6 @@
// limitations under the License. // limitations under the License.
// //
import ElementX
import XCTest import XCTest
@MainActor @MainActor
@@ -14,7 +14,6 @@
// limitations under the License. // limitations under the License.
// //
import ElementX
import XCTest import XCTest
@MainActor @MainActor
@@ -14,7 +14,6 @@
// limitations under the License. // limitations under the License.
// //
import ElementX
import XCTest import XCTest
@MainActor @MainActor
@@ -14,7 +14,6 @@
// limitations under the License. // limitations under the License.
// //
import ElementX
import XCTest import XCTest
@MainActor @MainActor
+2 -3
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
} }
@@ -14,7 +14,6 @@
// limitations under the License. // limitations under the License.
// //
import ElementX
import XCTest import XCTest
@MainActor @MainActor
@@ -14,7 +14,6 @@
// limitations under the License. // limitations under the License.
// //
import ElementX
import XCTest import XCTest
@MainActor @MainActor
@@ -14,7 +14,6 @@
// limitations under the License. // limitations under the License.
// //
import ElementX
import XCTest import XCTest
@MainActor @MainActor
@@ -14,7 +14,6 @@
// limitations under the License. // limitations under the License.
// //
import ElementX
import XCTest import XCTest
@MainActor @MainActor
@@ -14,7 +14,6 @@
// limitations under the License. // limitations under the License.
// //
import ElementX
import XCTest import XCTest
@MainActor @MainActor
@@ -14,7 +14,6 @@
// limitations under the License. // limitations under the License.
// //
import ElementX
import XCTest import XCTest
@MainActor @MainActor
@@ -14,7 +14,6 @@
// limitations under the License. // limitations under the License.
// //
import ElementX
import XCTest import XCTest
@MainActor @MainActor
@@ -14,7 +14,6 @@
// limitations under the License. // limitations under the License.
// //
import ElementX
import XCTest import XCTest
@MainActor @MainActor
-1
View File
@@ -14,7 +14,6 @@
// limitations under the License. // limitations under the License.
// //
import ElementX
import XCTest import XCTest
@MainActor @MainActor
@@ -14,7 +14,6 @@
// limitations under the License. // limitations under the License.
// //
import ElementX
import XCTest import XCTest
@MainActor @MainActor
@@ -14,7 +14,6 @@
// limitations under the License. // limitations under the License.
// //
import ElementX
import XCTest import XCTest
@MainActor @MainActor
@@ -14,7 +14,6 @@
// limitations under the License. // limitations under the License.
// //
import ElementX
import XCTest import XCTest
@MainActor @MainActor
@@ -14,7 +14,6 @@
// limitations under the License. // limitations under the License.
// //
import ElementX
import XCTest import XCTest
@MainActor @MainActor
@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:19be252acb1287d614ee24423930c02e9470aa0c1a39a58a56573098d3de5e4c
size 1296179
@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:5ea38cf925c1ecb6f681f70f9e69261e04458f315037c826608c62827b4d4a43
size 100758
@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:7d09d2089cd5d540e12aaa823da60e20806c25202f0f3b60bfd4cebc8978e8a9
size 58054
@@ -1,3 +0,0 @@
version https://git-lfs.github.com/spec/v1
oid sha256:02d0e19e329769fd507b7e02cbb95c55f36db403ba221b1362fea51e8e37a026
size 100756
@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:5d2509f4aede5aab31616f52227ae55547e62060f59fe57498cefaaa65a7fe00
size 937763
@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:218cd540d96ff548dfcd300e3d6819cec8675756b1581d3bff9ad65a5dec8222
size 119101
@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:af5d5eeb0ec353137c190a149bdb394da32faa730f17f3667768992cb9db0ee9
size 57774
@@ -1,3 +0,0 @@
version https://git-lfs.github.com/spec/v1
oid sha256:326cb365efab4ca083b39104402e1056ae915e4a230dacd07f494343e427cef7
size 117772
@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:19be252acb1287d614ee24423930c02e9470aa0c1a39a58a56573098d3de5e4c
size 1296179
@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:ade0d3ff831c271820d475203689b69ca1b935bc32d8c6ad1c3e31a1ba3d339b
size 108963
@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:e4f8dfd9c3e7bf9c5b7fe6ccd94c7a710b331ee9920a658c664287fa4d6403f7
size 58873
@@ -1,3 +0,0 @@
version https://git-lfs.github.com/spec/v1
oid sha256:c5b462d8c9213706f06d4dab74a2b51bd29a5b961748ad3fd8156e48d407d832
size 108960
@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:fddcd92de45f0d1c41bb3c4a1555a48b91a0f9c23582ef780aa38fdec0f08186
size 936389
@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:f287ea8b97c94e38ddddb0cf3ef81d25eecc2b0136a4b68d0ac48779e13ab1ed
size 127569
@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:b6f97fa428f0cccd0b72f2033c3b7c54c5f15f80a7293fb1b58da88704cf91b7
size 60147
@@ -1,3 +0,0 @@
version https://git-lfs.github.com/spec/v1
oid sha256:2d439b5c3e450115d6e46ae632ab3486a54763478db5e2111a763b9ab71da0cb
size 127567