mirror of
https://github.com/element-hq/element-x-ios.git
synced 2025-03-10 13:37:11 +00:00
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:
parent
da831f6725
commit
37d88e622c
@ -206,6 +206,7 @@
|
||||
37906355E207DB5703754675 /* AppLockSetupBiometricsScreenViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = C9F893F4A111CB7BA5C96949 /* AppLockSetupBiometricsScreenViewModel.swift */; };
|
||||
37D789F24199B32E3FD1AA7B /* FileRoomTimelineItemContent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 216F0DDC98F2A2C162D09C28 /* FileRoomTimelineItemContent.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 */; };
|
||||
386720B603F87D156DB01FB2 /* VoiceMessageMediaManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 40076C770A5FB83325252973 /* VoiceMessageMediaManager.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 */; };
|
||||
BA43D782BE85C7F5F20C624A /* AttributedStringBuilderProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 72F37B5DA798C9AE436F2C2C /* AttributedStringBuilderProtocol.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 */; };
|
||||
BB784A02BADB03C820617A46 /* TextRoomTimelineItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 90A55430639712CFACA34F43 /* TextRoomTimelineItem.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 */; };
|
||||
EF7924005216B8189898F370 /* BackgroundTaskProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CA028DCD4157F9A1F999827 /* BackgroundTaskProtocol.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 */; };
|
||||
F06CE9132855E81EBB6DDC32 /* Kingfisher in Frameworks */ = {isa = PBXBuildFile; productRef = 940C605265DD82DA0C655E23 /* Kingfisher */; };
|
||||
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>"; };
|
||||
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>"; };
|
||||
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>"; };
|
||||
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>"; };
|
||||
@ -1855,6 +1855,7 @@
|
||||
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>"; };
|
||||
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>"; };
|
||||
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>"; };
|
||||
@ -1892,6 +1893,7 @@
|
||||
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>"; };
|
||||
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>"; };
|
||||
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>"; };
|
||||
@ -2400,6 +2402,7 @@
|
||||
children = (
|
||||
8F94F70480243CAA65A2008C /* BlanckFormCoordinator.swift */,
|
||||
46C208DA43CE25D13E670F40 /* UITestsAppCoordinator.swift */,
|
||||
EBEB8D9F4940E161B18FE4BC /* UITestsNotificationCenter.swift */,
|
||||
6CEBE5EA91E8691EDF364EC2 /* UITestsScreenIdentifier.swift */,
|
||||
B7F0192CE2F891141A25B49F /* UITestsSignalling.swift */,
|
||||
);
|
||||
@ -3694,8 +3697,8 @@
|
||||
AF11DD57D9FACF2A757AB024 /* AnalyticsPromptUITests.swift */,
|
||||
16037EE9E9A52AF37B7818E3 /* AnalyticsSettingsScreenUITests.swift */,
|
||||
7D0CBC76C80E04345E11F2DB /* Application.swift */,
|
||||
349C633291427A0F29C28C54 /* AppLockScreenUITests.swift */,
|
||||
E8A1BBEF7318CA6B6ACCF4AE /* AppLockSetupUITests.swift */,
|
||||
F733F135E6D67BBBEB76CC30 /* AppLockUITests.swift */,
|
||||
5D2D0A6F1ABC99D29462FB84 /* AuthenticationCoordinatorUITests.swift */,
|
||||
C6FEA87EA3752203065ECE27 /* BugReportUITests.swift */,
|
||||
1D8866FE1CCCF10305FCACBC /* CallScreenUITests.swift */,
|
||||
@ -5854,6 +5857,7 @@
|
||||
706F79A39BDB32F592B8C2C7 /* UIKitBackgroundTask.swift in Sources */,
|
||||
3097A0A867D2B19CE32DAE58 /* UIKitBackgroundTaskService.swift in Sources */,
|
||||
E96005321849DBD7C72A28F2 /* UITestsAppCoordinator.swift in Sources */,
|
||||
384D6B9A7DFD7260139D6852 /* UITestsNotificationCenter.swift in Sources */,
|
||||
22882C710BC99EC34A5024A0 /* UITestsScreenIdentifier.swift in Sources */,
|
||||
706289B086B0A6B0C211763F /* UITestsSignalling.swift in Sources */,
|
||||
245F7FE5961BD10C145A26E0 /* UITimelineView.swift in Sources */,
|
||||
@ -5936,8 +5940,8 @@
|
||||
795A854F63301DC6B46217B9 /* AccessibilityIdentifiers.swift in Sources */,
|
||||
8024BE37156FF0A95A7A3465 /* AnalyticsPromptUITests.swift in Sources */,
|
||||
BF675964C9159F718589C36A /* AnalyticsSettingsScreenUITests.swift in Sources */,
|
||||
F05516474DB42369FD976CEF /* AppLockScreenUITests.swift in Sources */,
|
||||
44DA28B1E1F9C97C5795F7B3 /* AppLockSetupUITests.swift in Sources */,
|
||||
BAC845780F17CCFBC5A9CA37 /* AppLockUITests.swift in Sources */,
|
||||
7405B4824D45BA7C3D943E76 /* Application.swift in Sources */,
|
||||
ACF094CF3BF02DBFA6DFDE60 /* AuthenticationCoordinatorUITests.swift in Sources */,
|
||||
7756C4E90CABE6F14F7920A0 /* BugReportUITests.swift in Sources */,
|
||||
|
@ -18,5 +18,6 @@ import Foundation
|
||||
|
||||
protocol AppCoordinatorProtocol: CoordinatorProtocol {
|
||||
var notificationManager: NotificationManagerProtocol { get }
|
||||
var windowManager: WindowManager { get }
|
||||
@discardableResult func handleDeepLink(_ url: URL) -> Bool
|
||||
}
|
||||
|
@ -15,8 +15,7 @@
|
||||
//
|
||||
|
||||
import Combine
|
||||
import Foundation
|
||||
import UIKit
|
||||
import SwiftUI
|
||||
|
||||
enum AppDelegateCallback {
|
||||
case registeredNotifications(deviceToken: Data)
|
||||
|
@ -29,10 +29,9 @@ struct Application: App {
|
||||
} else if ProcessInfo.isRunningUnitTests {
|
||||
appCoordinator = UnitTestsAppCoordinator()
|
||||
} else {
|
||||
let coordinator = AppCoordinator(appDelegate: appDelegate)
|
||||
SceneDelegate.windowManager = coordinator.windowManager
|
||||
appCoordinator = coordinator
|
||||
appCoordinator = AppCoordinator(appDelegate: appDelegate)
|
||||
}
|
||||
SceneDelegate.windowManager = appCoordinator.windowManager
|
||||
}
|
||||
|
||||
var body: some Scene {
|
||||
|
@ -23,7 +23,7 @@ class SceneDelegate: NSObject, UIWindowSceneDelegate {
|
||||
weak static var windowManager: WindowManager!
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
@ -40,7 +40,9 @@ class AppLockFlowCoordinator: CoordinatorProtocol {
|
||||
actionsSubject.eraseToAnyPublisher()
|
||||
}
|
||||
|
||||
init(appLockService: AppLockServiceProtocol, navigationCoordinator: NavigationRootCoordinator) {
|
||||
init(appLockService: AppLockServiceProtocol,
|
||||
navigationCoordinator: NavigationRootCoordinator,
|
||||
notificationCenter: NotificationCenter = .default) {
|
||||
self.appLockService = appLockService
|
||||
self.navigationCoordinator = navigationCoordinator
|
||||
|
||||
@ -54,13 +56,13 @@ class AppLockFlowCoordinator: CoordinatorProtocol {
|
||||
}
|
||||
.store(in: &cancellables)
|
||||
|
||||
NotificationCenter.default.publisher(for: UIApplication.didEnterBackgroundNotification)
|
||||
notificationCenter.publisher(for: UIApplication.didEnterBackgroundNotification)
|
||||
.sink { [weak self] _ in
|
||||
self?.applicationDidEnterBackground()
|
||||
}
|
||||
.store(in: &cancellables)
|
||||
|
||||
NotificationCenter.default.publisher(for: UIApplication.willEnterForegroundNotification)
|
||||
notificationCenter.publisher(for: UIApplication.willEnterForegroundNotification)
|
||||
.sink { [weak self] _ in
|
||||
self?.applicationWillEnterForeground()
|
||||
}
|
||||
|
@ -19,6 +19,7 @@ import Foundation
|
||||
enum A11yIdentifiers {
|
||||
static let alertInfo = AlertInfo()
|
||||
static let analyticsPromptScreen = AnalyticsPromptScreen()
|
||||
static let appLockScreen = AppLockScreen()
|
||||
static let appLockSetupBiometricsScreen = AppLockSetupBiometricsScreen()
|
||||
static let appLockSetupPINScreen = AppLockSetupPINScreen()
|
||||
static let appLockSetupSettingsScreen = AppLockSetupSettingsScreen()
|
||||
@ -51,6 +52,10 @@ enum A11yIdentifiers {
|
||||
let secondaryButton = "alert_info-secondary_button"
|
||||
}
|
||||
|
||||
struct AppLockScreen {
|
||||
func numpad(_ digit: Int) -> String { "app_lock-numpad_\(digit)" }
|
||||
}
|
||||
|
||||
struct AppLockSetupBiometricsScreen {
|
||||
let allow = "app_lock_setup_biometrics-allow"
|
||||
}
|
||||
|
@ -27,12 +27,14 @@ struct AppLockScreenPINKeypad: View {
|
||||
ForEach(1..<4) { column in
|
||||
let digit = (3 * row) + column
|
||||
Button("\(digit)") { press(digit) }
|
||||
.accessibilityIdentifier(A11yIdentifiers.appLockScreen.numpad(digit))
|
||||
}
|
||||
}
|
||||
}
|
||||
GridRow {
|
||||
Button("") { }.hidden()
|
||||
Button("0") { press(0) }
|
||||
.accessibilityIdentifier(A11yIdentifiers.appLockScreen.numpad(0))
|
||||
Button(action: pressDelete) {
|
||||
Image(systemSymbol: .deleteBackward)
|
||||
.symbolVariant(.fill)
|
||||
|
@ -125,9 +125,9 @@ class MockRoomTimelineController: RoomTimelineControllerProtocol {
|
||||
/// Handles a UI test signal as necessary.
|
||||
private func handleSignal(_ signal: UITestsSignal) async throws {
|
||||
switch signal {
|
||||
case .paginate:
|
||||
case .timeline(.paginate):
|
||||
try await simulateBackPagination()
|
||||
case .incomingMessage:
|
||||
case .timeline(.incomingMessage):
|
||||
try await simulateIncomingItem()
|
||||
default:
|
||||
break
|
||||
|
@ -19,17 +19,22 @@ import MatrixRustSDK
|
||||
import SwiftUI
|
||||
import UIKit
|
||||
|
||||
class UITestsAppCoordinator: AppCoordinatorProtocol {
|
||||
class UITestsAppCoordinator: AppCoordinatorProtocol, WindowManagerDelegate {
|
||||
private let navigationRootCoordinator: NavigationRootCoordinator
|
||||
private var mockScreen: MockScreen?
|
||||
private var alternateWindowMockScreen: MockScreen?
|
||||
|
||||
let notificationManager: NotificationManagerProtocol = NotificationManagerMock()
|
||||
let windowManager = WindowManager()
|
||||
|
||||
init() {
|
||||
// disabling View animations
|
||||
UIView.setAnimationsEnabled(false)
|
||||
|
||||
|
||||
navigationRootCoordinator = NavigationRootCoordinator()
|
||||
|
||||
windowManager.delegate = self
|
||||
|
||||
ServiceLocator.shared.register(userIndicatorController: UserIndicatorControllerMock.default)
|
||||
|
||||
AppSettings.configureWithSuiteName("io.element.elementx.uitests")
|
||||
@ -42,14 +47,6 @@ class UITestsAppCoordinator: AppCoordinatorProtocol {
|
||||
}
|
||||
|
||||
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.") }
|
||||
|
||||
let mockScreen = MockScreen(id: screenID)
|
||||
@ -64,17 +61,27 @@ class UITestsAppCoordinator: AppCoordinatorProtocol {
|
||||
func handleDeepLink(_ url: URL) -> Bool {
|
||||
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
|
||||
class MockScreen: Identifiable {
|
||||
let id: UITestsScreenIdentifier
|
||||
let windowManager: WindowManager?
|
||||
|
||||
private var retainedState = [Any]()
|
||||
private var cancellables = Set<AnyCancellable>()
|
||||
|
||||
init(id: UITestsScreenIdentifier) {
|
||||
init(id: UITestsScreenIdentifier, windowManager: WindowManager? = nil) {
|
||||
self.id = id
|
||||
self.windowManager = windowManager
|
||||
}
|
||||
|
||||
lazy var coordinator: CoordinatorProtocol = {
|
||||
@ -158,24 +165,15 @@ class MockScreen: Identifiable {
|
||||
let coordinator = TemplateScreenCoordinator(parameters: .init())
|
||||
navigationStackCoordinator.setRootCoordinator(coordinator)
|
||||
return navigationStackCoordinator
|
||||
case .appLockScreen:
|
||||
let appLockService = AppLockService(keychainController: KeychainControllerMock(), appSettings: ServiceLocator.shared.settings)
|
||||
let coordinator = AppLockScreenCoordinator(parameters: .init(appLockService: appLockService))
|
||||
return coordinator
|
||||
case .appLockSetupFlow, .appLockSetupFlowUnlock, .appLockSetupFlowMandatory:
|
||||
let navigationStackCoordinator = NavigationStackCoordinator()
|
||||
// The flow expects an existing root coordinator, use the placeholder as a placeholder 😅
|
||||
navigationStackCoordinator.setRootCoordinator(BlankFormCoordinator())
|
||||
case .appLockFlow, .appLockFlowDisabled:
|
||||
// The tested coordinator is setup below in the alternate window.
|
||||
// Here we just return a blank screen to snapshot as the unlocked app.
|
||||
return BlankFormCoordinator()
|
||||
case .appLockFlowAlternateWindow, .appLockFlowDisabledAlternateWindow:
|
||||
let navigationCoordinator = NavigationRootCoordinator()
|
||||
|
||||
let keychainController = KeychainController(service: .tests, accessGroup: InfoPlistReader.main.keychainAccessGroupIdentifier)
|
||||
keychainController.resetSecrets()
|
||||
if id == .appLockSetupFlowUnlock {
|
||||
do {
|
||||
try keychainController.setPINCode("2023")
|
||||
} catch {
|
||||
fatalError("Failed to pre-set the PIN code")
|
||||
}
|
||||
}
|
||||
|
||||
let context = LAContextMock()
|
||||
context.biometryTypeValue = UIDevice.current.isPhone ? .faceID : .touchID // (iPhone 14 & iPad 9th gen)
|
||||
@ -186,6 +184,59 @@ class MockScreen: Identifiable {
|
||||
appSettings: ServiceLocator.shared.settings,
|
||||
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 coordinator = AppLockSetupFlowCoordinator(presentingFlow: flow,
|
||||
appLockService: appLockService,
|
||||
|
57
ElementX/Sources/UITests/UITestsNotificationCenter.swift
Normal file
57
ElementX/Sources/UITests/UITestsNotificationCenter.swift
Normal 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
|
||||
}
|
||||
}
|
||||
}
|
@ -29,7 +29,10 @@ enum UITestsScreenIdentifier: String {
|
||||
case analyticsSettingsScreen
|
||||
case migration
|
||||
case templateScreen
|
||||
case appLockScreen
|
||||
case appLockFlow
|
||||
case appLockFlowAlternateWindow
|
||||
case appLockFlowDisabled
|
||||
case appLockFlowDisabledAlternateWindow
|
||||
case appLockSetupFlow
|
||||
case appLockSetupFlowUnlock
|
||||
case appLockSetupFlowMandatory
|
||||
|
@ -18,15 +18,24 @@ import Combine
|
||||
import KZFileWatchers
|
||||
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.
|
||||
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.
|
||||
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 {
|
||||
@ -60,7 +69,7 @@ enum UITestsSignalling {
|
||||
}()
|
||||
|
||||
/// 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.
|
||||
let mode: Mode
|
||||
|
||||
@ -78,10 +87,10 @@ enum UITestsSignalling {
|
||||
switch mode {
|
||||
case .tests:
|
||||
// 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:
|
||||
// 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
|
||||
// The app client then echoes back to the tests that it is now ready.
|
||||
try send(.ready)
|
||||
@ -110,15 +119,42 @@ enum UITestsSignalling {
|
||||
func send(_ signal: UITestsSignal) throws {
|
||||
guard isConnected else { throw UITestsSignalError.notConnected }
|
||||
|
||||
let rawSignal = rawSignal(signal)
|
||||
try rawSignal.write(to: fileURL, atomically: false, encoding: .utf8)
|
||||
NSLog("UITestsSignalling: Sent \(rawSignal)")
|
||||
let rawMessage = rawMessage(signal)
|
||||
try rawMessage.write(to: fileURL, atomically: false, encoding: .utf8)
|
||||
NSLog("UITestsSignalling: Sent \(rawMessage)")
|
||||
}
|
||||
|
||||
/// The signal formatted as a string, prefixed with an identifier for the sender.
|
||||
/// E.g. The tests client would produce `tests:ready` for the ready signal.
|
||||
private func rawSignal(_ signal: UITestsSignal) -> String {
|
||||
"\(mode.rawValue):\(signal.rawValue)"
|
||||
/// The signal formatted as a complete message string, including the identifier for this sender.
|
||||
private func rawMessage(_ signal: UITestsSignal) -> String {
|
||||
Message(mode: mode, signal: 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.
|
||||
@ -134,22 +170,19 @@ enum UITestsSignalling {
|
||||
|
||||
/// Processes string data from the file and publishes its signal.
|
||||
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 components.count == 2,
|
||||
components[0] != mode.rawValue, // Filter out messages sent by this client.
|
||||
let signal = UITestsSignal(rawValue: components[1])
|
||||
guard let message = Message(rawValue: rawMessage),
|
||||
message.mode != mode // Filter out messages sent by this client.
|
||||
else { return }
|
||||
|
||||
if signal == .ready {
|
||||
if message.signal == .ready {
|
||||
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 {
|
||||
let notificationManager: NotificationManagerProtocol = NotificationManagerMock()
|
||||
let windowManager = WindowManager()
|
||||
|
||||
init() {
|
||||
ServiceLocator.shared.register(userIndicatorController: UserIndicatorControllerMock.default)
|
||||
|
@ -14,7 +14,6 @@
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import ElementX
|
||||
import XCTest
|
||||
|
||||
@MainActor
|
||||
|
@ -14,7 +14,6 @@
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import ElementX
|
||||
import XCTest
|
||||
|
||||
@MainActor
|
||||
|
@ -14,7 +14,6 @@
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import ElementX
|
||||
import XCTest
|
||||
|
||||
@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
|
||||
|
||||
@testable import ElementX
|
||||
|
||||
@MainActor
|
||||
class AppLockSetupUITests: XCTestCase {
|
||||
var app: XCUIApplication!
|
||||
|
87
UITests/Sources/AppLockUITests.swift
Normal file
87
UITests/Sources/AppLockUITests.swift
Normal 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
|
||||
|
||||
@testable import ElementX
|
||||
|
||||
@MainActor
|
||||
class AuthenticationCoordinatorUITests: XCTestCase {
|
||||
func testLoginWithPassword() async throws {
|
||||
|
@ -14,7 +14,6 @@
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import ElementX
|
||||
import XCTest
|
||||
|
||||
@MainActor
|
||||
|
@ -14,7 +14,6 @@
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import ElementX
|
||||
import XCTest
|
||||
|
||||
@MainActor
|
||||
|
@ -14,7 +14,6 @@
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import ElementX
|
||||
import XCTest
|
||||
|
||||
@MainActor
|
||||
|
@ -14,7 +14,6 @@
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import ElementX
|
||||
import XCTest
|
||||
|
||||
@MainActor
|
||||
|
@ -14,7 +14,6 @@
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import ElementX
|
||||
import XCTest
|
||||
|
||||
@MainActor
|
||||
|
@ -14,7 +14,6 @@
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import ElementX
|
||||
import XCTest
|
||||
|
||||
@MainActor
|
||||
|
@ -14,7 +14,6 @@
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import ElementX
|
||||
import XCTest
|
||||
|
||||
@MainActor
|
||||
|
@ -14,7 +14,6 @@
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import ElementX
|
||||
import XCTest
|
||||
|
||||
@MainActor
|
||||
|
@ -14,7 +14,6 @@
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import ElementX
|
||||
import XCTest
|
||||
|
||||
@MainActor
|
||||
|
@ -14,7 +14,6 @@
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import ElementX
|
||||
import XCTest
|
||||
|
||||
@MainActor
|
||||
|
@ -14,7 +14,6 @@
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import ElementX
|
||||
import XCTest
|
||||
|
||||
@MainActor
|
||||
|
@ -14,7 +14,6 @@
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import ElementX
|
||||
import XCTest
|
||||
|
||||
@MainActor
|
||||
|
@ -14,7 +14,6 @@
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import ElementX
|
||||
import XCTest
|
||||
|
||||
@MainActor
|
||||
|
@ -14,7 +14,6 @@
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import ElementX
|
||||
import XCTest
|
||||
|
||||
@MainActor
|
||||
|
@ -14,7 +14,6 @@
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import ElementX
|
||||
import XCTest
|
||||
|
||||
@MainActor
|
||||
|
@ -14,7 +14,6 @@
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import ElementX
|
||||
import XCTest
|
||||
|
||||
@MainActor
|
||||
|
@ -14,7 +14,6 @@
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import ElementX
|
||||
import XCTest
|
||||
|
||||
@MainActor
|
||||
|
@ -14,7 +14,6 @@
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import ElementX
|
||||
import XCTest
|
||||
|
||||
@MainActor
|
||||
|
@ -14,7 +14,6 @@
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import ElementX
|
||||
import XCTest
|
||||
|
||||
@MainActor
|
||||
|
@ -14,7 +14,6 @@
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import ElementX
|
||||
import XCTest
|
||||
|
||||
@MainActor
|
||||
|
@ -14,7 +14,6 @@
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import ElementX
|
||||
import XCTest
|
||||
|
||||
@MainActor
|
||||
@ -181,8 +180,8 @@ class RoomScreenUITests: XCTestCase {
|
||||
|
||||
// MARK: - Helper Methods
|
||||
|
||||
private func performOperation(_ operation: UITestsSignal, using client: UITestsSignalling.Client) async throws {
|
||||
try client.send(operation)
|
||||
private func performOperation(_ operation: UITestsSignal.Timeline, using client: UITestsSignalling.Client) async throws {
|
||||
try client.send(.timeline(operation))
|
||||
await _ = client.signals.values.first { $0 == .success }
|
||||
try await Task.sleep(for: .seconds(2)) // Allow the timeline to update
|
||||
}
|
||||
|
@ -14,7 +14,6 @@
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import ElementX
|
||||
import XCTest
|
||||
|
||||
@MainActor
|
||||
|
@ -14,7 +14,6 @@
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import ElementX
|
||||
import XCTest
|
||||
|
||||
@MainActor
|
||||
|
@ -14,7 +14,6 @@
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import ElementX
|
||||
import XCTest
|
||||
|
||||
@MainActor
|
||||
|
@ -14,7 +14,6 @@
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import ElementX
|
||||
import XCTest
|
||||
|
||||
@MainActor
|
||||
|
@ -14,7 +14,6 @@
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import ElementX
|
||||
import XCTest
|
||||
|
||||
@MainActor
|
||||
|
@ -14,7 +14,6 @@
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import ElementX
|
||||
import XCTest
|
||||
|
||||
@MainActor
|
||||
|
@ -14,7 +14,6 @@
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import ElementX
|
||||
import XCTest
|
||||
|
||||
@MainActor
|
||||
|
@ -14,7 +14,6 @@
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import ElementX
|
||||
import XCTest
|
||||
|
||||
@MainActor
|
||||
|
@ -14,7 +14,6 @@
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import ElementX
|
||||
import XCTest
|
||||
|
||||
@MainActor
|
||||
|
@ -14,7 +14,6 @@
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import ElementX
|
||||
import XCTest
|
||||
|
||||
@MainActor
|
||||
|
@ -14,7 +14,6 @@
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import ElementX
|
||||
import XCTest
|
||||
|
||||
@MainActor
|
||||
|
@ -14,7 +14,6 @@
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import ElementX
|
||||
import XCTest
|
||||
|
||||
@MainActor
|
||||
|
@ -14,7 +14,6 @@
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import ElementX
|
||||
import XCTest
|
||||
|
||||
@MainActor
|
||||
|
BIN
UITests/Sources/__Snapshots__/Application/en-GB-iPad-9th-generation.appLockFlow-0.png
(Stored with Git LFS)
Normal file
BIN
UITests/Sources/__Snapshots__/Application/en-GB-iPad-9th-generation.appLockFlow-0.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
UITests/Sources/__Snapshots__/Application/en-GB-iPad-9th-generation.appLockFlow-1.png
(Stored with Git LFS)
Normal file
BIN
UITests/Sources/__Snapshots__/Application/en-GB-iPad-9th-generation.appLockFlow-1.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
UITests/Sources/__Snapshots__/Application/en-GB-iPad-9th-generation.appLockFlow-99.png
(Stored with Git LFS)
Normal file
BIN
UITests/Sources/__Snapshots__/Application/en-GB-iPad-9th-generation.appLockFlow-99.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
UITests/Sources/__Snapshots__/Application/en-GB-iPad-9th-generation.appLockScreen.png
(Stored with Git LFS)
BIN
UITests/Sources/__Snapshots__/Application/en-GB-iPad-9th-generation.appLockScreen.png
(Stored with Git LFS)
Binary file not shown.
BIN
UITests/Sources/__Snapshots__/Application/en-GB-iPhone-14.appLockFlow-0.png
(Stored with Git LFS)
Normal file
BIN
UITests/Sources/__Snapshots__/Application/en-GB-iPhone-14.appLockFlow-0.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
UITests/Sources/__Snapshots__/Application/en-GB-iPhone-14.appLockFlow-1.png
(Stored with Git LFS)
Normal file
BIN
UITests/Sources/__Snapshots__/Application/en-GB-iPhone-14.appLockFlow-1.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
UITests/Sources/__Snapshots__/Application/en-GB-iPhone-14.appLockFlow-99.png
(Stored with Git LFS)
Normal file
BIN
UITests/Sources/__Snapshots__/Application/en-GB-iPhone-14.appLockFlow-99.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
UITests/Sources/__Snapshots__/Application/en-GB-iPhone-14.appLockScreen.png
(Stored with Git LFS)
BIN
UITests/Sources/__Snapshots__/Application/en-GB-iPhone-14.appLockScreen.png
(Stored with Git LFS)
Binary file not shown.
BIN
UITests/Sources/__Snapshots__/Application/pseudo-iPad-9th-generation.appLockFlow-0.png
(Stored with Git LFS)
Normal file
BIN
UITests/Sources/__Snapshots__/Application/pseudo-iPad-9th-generation.appLockFlow-0.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
UITests/Sources/__Snapshots__/Application/pseudo-iPad-9th-generation.appLockFlow-1.png
(Stored with Git LFS)
Normal file
BIN
UITests/Sources/__Snapshots__/Application/pseudo-iPad-9th-generation.appLockFlow-1.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
UITests/Sources/__Snapshots__/Application/pseudo-iPad-9th-generation.appLockFlow-99.png
(Stored with Git LFS)
Normal file
BIN
UITests/Sources/__Snapshots__/Application/pseudo-iPad-9th-generation.appLockFlow-99.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
UITests/Sources/__Snapshots__/Application/pseudo-iPad-9th-generation.appLockScreen.png
(Stored with Git LFS)
BIN
UITests/Sources/__Snapshots__/Application/pseudo-iPad-9th-generation.appLockScreen.png
(Stored with Git LFS)
Binary file not shown.
BIN
UITests/Sources/__Snapshots__/Application/pseudo-iPhone-14.appLockFlow-0.png
(Stored with Git LFS)
Normal file
BIN
UITests/Sources/__Snapshots__/Application/pseudo-iPhone-14.appLockFlow-0.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
UITests/Sources/__Snapshots__/Application/pseudo-iPhone-14.appLockFlow-1.png
(Stored with Git LFS)
Normal file
BIN
UITests/Sources/__Snapshots__/Application/pseudo-iPhone-14.appLockFlow-1.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
UITests/Sources/__Snapshots__/Application/pseudo-iPhone-14.appLockFlow-99.png
(Stored with Git LFS)
Normal file
BIN
UITests/Sources/__Snapshots__/Application/pseudo-iPhone-14.appLockFlow-99.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
UITests/Sources/__Snapshots__/Application/pseudo-iPhone-14.appLockScreen.png
(Stored with Git LFS)
BIN
UITests/Sources/__Snapshots__/Application/pseudo-iPhone-14.appLockScreen.png
(Stored with Git LFS)
Binary file not shown.
Loading…
x
Reference in New Issue
Block a user