From 8f906c7be7a90b836398169ec46c0b51c4e6dc0d Mon Sep 17 00:00:00 2001 From: Doug <6060466+pixlwave@users.noreply.github.com> Date: Wed, 18 Jan 2023 13:28:59 +0000 Subject: [PATCH] Fix unit and UI tests. (#460) * Fix race condition on session verification tests. * Fix clear button on text field. * Add a timeout to UI test signalling. * Use snapshot testing for login screen. --- DesignKit/Package.swift | 2 +- .../TextFields/BorderedInputFieldStyle.swift | 118 ------------------ .../TextFields/ElementTextFieldStyle.swift | 113 ++++++++++++++--- ...ckSessionVerificationControllerProxy.swift | 2 +- .../UITests/UITestsAppCoordinator.swift | 4 +- .../Sources/UITests/UITestsSignalling.swift | 25 ++++ UITests/Sources/LoginScreenUITests.swift | 106 ++-------------- .../de-DE-iPad-9th-generation.login-0.png | 3 + .../de-DE-iPad-9th-generation.login-1.png | 3 + .../de-DE-iPad-9th-generation.login-2.png | 3 + .../Application/de-DE-iPhone-14.login-0.png | 3 + .../Application/de-DE-iPhone-14.login-1.png | 3 + .../Application/de-DE-iPhone-14.login-2.png | 3 + .../en-GB-iPad-9th-generation.login-0.png | 3 + .../en-GB-iPad-9th-generation.login-1.png | 3 + .../en-GB-iPad-9th-generation.login-2.png | 3 + .../Application/en-GB-iPhone-14.login-0.png | 3 + .../Application/en-GB-iPhone-14.login-1.png | 3 + .../Application/en-GB-iPhone-14.login-2.png | 3 + .../SessionVerificationViewModelTests.swift | 6 +- 20 files changed, 175 insertions(+), 237 deletions(-) delete mode 100644 DesignKit/Sources/TextFields/BorderedInputFieldStyle.swift create mode 100644 UITests/Sources/__Snapshots__/Application/de-DE-iPad-9th-generation.login-0.png create mode 100644 UITests/Sources/__Snapshots__/Application/de-DE-iPad-9th-generation.login-1.png create mode 100644 UITests/Sources/__Snapshots__/Application/de-DE-iPad-9th-generation.login-2.png create mode 100644 UITests/Sources/__Snapshots__/Application/de-DE-iPhone-14.login-0.png create mode 100644 UITests/Sources/__Snapshots__/Application/de-DE-iPhone-14.login-1.png create mode 100644 UITests/Sources/__Snapshots__/Application/de-DE-iPhone-14.login-2.png create mode 100644 UITests/Sources/__Snapshots__/Application/en-GB-iPad-9th-generation.login-0.png create mode 100644 UITests/Sources/__Snapshots__/Application/en-GB-iPad-9th-generation.login-1.png create mode 100644 UITests/Sources/__Snapshots__/Application/en-GB-iPad-9th-generation.login-2.png create mode 100644 UITests/Sources/__Snapshots__/Application/en-GB-iPhone-14.login-0.png create mode 100644 UITests/Sources/__Snapshots__/Application/en-GB-iPhone-14.login-1.png create mode 100644 UITests/Sources/__Snapshots__/Application/en-GB-iPhone-14.login-2.png diff --git a/DesignKit/Package.swift b/DesignKit/Package.swift index 4c244d742..b1f6cf8c0 100644 --- a/DesignKit/Package.swift +++ b/DesignKit/Package.swift @@ -6,7 +6,7 @@ import PackageDescription let package = Package( name: "DesignKit", platforms: [ - .iOS(.v14) + .iOS(.v16) ], products: [ .library(name: "DesignKit", targets: ["DesignKit"]) diff --git a/DesignKit/Sources/TextFields/BorderedInputFieldStyle.swift b/DesignKit/Sources/TextFields/BorderedInputFieldStyle.swift deleted file mode 100644 index 57b6f4528..000000000 --- a/DesignKit/Sources/TextFields/BorderedInputFieldStyle.swift +++ /dev/null @@ -1,118 +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 DesignTokens -import Introspect -import SwiftUI - -/// A bordered style of text input -/// -/// As defined in: -/// https://www.figma.com/file/X4XTH9iS2KGJ2wFKDqkyed/Compound?node-id=2039%3A26415 -public struct BorderedInputFieldStyle: TextFieldStyle { - @Environment(\.isEnabled) var isEnabled - @Environment(\.colorScheme) var colorScheme - - public var isEditing: Bool - public var isError: Bool - public var returnKey: UIReturnKeyType? - - private var borderColor: Color { - guard !isError else { return .element.alert } - return isEditing ? .element.accent : .element.quinaryContent - } - - private var accentColor: Color { - isError ? .element.alert : .element.accent - } - - private var textColor: Color { - if colorScheme == .dark { - return isEnabled ? .element.primaryContent : .element.tertiaryContent - } else { - return isEnabled ? .element.primaryContent : .element.quaternaryContent - } - } - - private var backgroundColor: Color { - if !isEnabled, colorScheme == .dark { - return .element.quinaryContent - } - return .element.background - } - - private var placeholderColor: Color { - .element.tertiaryContent - } - - private var borderWidth: CGFloat { - isEditing || isError ? 2.0 : 1.5 - } - - /// Creates the text field style configured as required. - /// - Parameters: - /// - isEditing: Whether or not the text field is currently being edited. - /// - isError: Whether or not the text field is currently in the error state. - /// - returnKey: The return key to be used. Pass `nil` for iOS 15+ and use `.submitLabel` instead. - public init(isEditing: Bool = false, isError: Bool = false, returnKey: UIReturnKeyType? = .done) { - self.isEditing = isEditing - self.isError = isError - self.returnKey = returnKey - } - - public func _body(configuration: TextField<_Label>) -> some View { - let rect = RoundedRectangle(cornerRadius: 8.0) - return configuration - .font(.element.callout) - .foregroundColor(textColor) - .accentColor(accentColor) - .padding(.vertical, 12.0) - .padding(.horizontal, 8.0) - .background(backgroundColor) - .clipShape(rect) - .overlay(rect.stroke(borderColor, lineWidth: borderWidth)) - .introspectTextField { textField in - if let returnKey { - textField.returnKeyType = returnKey - } - - textField.clearButtonMode = .whileEditing - textField.attributedPlaceholder = NSAttributedString(string: textField.placeholder ?? "", - attributes: [NSAttributedString.Key.foregroundColor: UIColor(placeholderColor)]) - } - } -} - -public struct BorderedInputFieldStyle_Previews: PreviewProvider { - public static var previews: some View { - VStack { - TextField("Placeholder", text: .constant("")) - .textFieldStyle(BorderedInputFieldStyle()) - TextField("Placeholder", text: .constant("")) - .textFieldStyle(BorderedInputFieldStyle(isEditing: true)) - TextField("Placeholder", text: .constant("Web")) - .textFieldStyle(BorderedInputFieldStyle()) - TextField("Placeholder", text: .constant("Web")) - .textFieldStyle(BorderedInputFieldStyle(isEditing: true)) - TextField("Placeholder", text: .constant("Web")) - .textFieldStyle(BorderedInputFieldStyle()) - .disabled(true) - TextField("Placeholder", text: .constant("Web")) - .textFieldStyle(BorderedInputFieldStyle(isEditing: true, isError: true)) - } - .padding() - } -} diff --git a/DesignKit/Sources/TextFields/ElementTextFieldStyle.swift b/DesignKit/Sources/TextFields/ElementTextFieldStyle.swift index fa6e7f672..ca2844045 100644 --- a/DesignKit/Sources/TextFields/ElementTextFieldStyle.swift +++ b/DesignKit/Sources/TextFields/ElementTextFieldStyle.swift @@ -15,9 +15,9 @@ // import DesignTokens +import Introspect import SwiftUI -@available(iOS 15.0, *) public extension TextFieldStyle where Self == ElementTextFieldStyle { static func elementInput(labelText: String? = nil, footerText: String? = nil, @@ -26,7 +26,10 @@ public extension TextFieldStyle where Self == ElementTextFieldStyle { } } -@available(iOS 15.0, *) +/// A bordered style of text input with a label and a footer +/// +/// As defined in: +/// https://www.figma.com/file/X4XTH9iS2KGJ2wFKDqkyed/Compound?node-id=2039%3A26415 public struct ElementTextFieldStyle: TextFieldStyle { @Environment(\.isEnabled) private var isEnabled @Environment(\.colorScheme) private var colorScheme @@ -36,15 +39,59 @@ public struct ElementTextFieldStyle: TextFieldStyle { public let footerText: String? public let isError: Bool + /// The color of the text field's border. + private var borderColor: Color { + guard !isError else { return .element.alert } + return isFocused ? .element.accent : .element.quinaryContent + } + + /// The width of the text field's border. + private var borderWidth: CGFloat { + isFocused || isError ? 2.0 : 1.5 + } + + private var accentColor: Color { + isError ? .element.alert : .element.accent + } + + /// The color of the text inside the text field. + private var textColor: Color { + if colorScheme == .dark { + return isEnabled ? .element.primaryContent : .element.tertiaryContent + } else { + return isEnabled ? .element.primaryContent : .element.quaternaryContent + } + } + + /// The color of the text field's background. + private var backgroundColor: Color { + if !isEnabled, colorScheme == .dark { + return .element.quinaryContent + } + return .element.background + } + + /// The color of the placeholder text inside the text field. + private var placeholderColor: Color { + .element.tertiaryContent + } + + /// The color of the label above the text field. private var labelColor: Color { guard colorScheme == .light else { return .element.tertiaryContent } return isEnabled ? .element.primaryContent : .element.quaternaryContent } + /// The color of the footer label below the text field. private var footerColor: Color { isError ? .element.alert : .element.tertiaryContent } + /// Creates the text field style configured as required. + /// - Parameters: + /// - labelText: The text shown in the label above the field. + /// - footerText: The text shown in the footer label below the field. + /// - isError: Whether or not the text field is currently in the error state. public init(labelText: String? = nil, footerText: String? = nil, isError: Bool = false) { self.labelText = labelText self.footerText = footerText @@ -52,7 +99,9 @@ public struct ElementTextFieldStyle: TextFieldStyle { } public func _body(configuration: TextField<_Label>) -> some View { - VStack(alignment: .leading, spacing: 8) { + let rectangle = RoundedRectangle(cornerRadius: 8.0) + + return VStack(alignment: .leading, spacing: 8) { if let labelText { Text(labelText) .font(.element.subheadline) @@ -60,9 +109,26 @@ public struct ElementTextFieldStyle: TextFieldStyle { } configuration - .textFieldStyle(BorderedInputFieldStyle(isEditing: isFocused, isError: isError, returnKey: nil)) .focused($isFocused) - .onTapGesture { isFocused = true } // Set focus with taps in the space between the border and text field. + .font(.element.callout) + .foregroundColor(textColor) + .accentColor(accentColor) + .padding(.vertical, 12.0) + .padding(.horizontal, 8.0) + .background { + ZStack { + backgroundColor + .clipShape(rectangle) + rectangle + .stroke(borderColor, lineWidth: borderWidth) + } + .onTapGesture { isFocused = true } // Set focus with taps outside of the text field + } + .introspectTextField { textField in + textField.clearButtonMode = .whileEditing + textField.attributedPlaceholder = NSAttributedString(string: textField.placeholder ?? "", + attributes: [NSAttributedString.Key.foregroundColor: UIColor(placeholderColor)]) + } if let footerText { Text(footerText) @@ -73,20 +139,33 @@ public struct ElementTextFieldStyle: TextFieldStyle { } } -@available(iOS 15.0, *) struct ElementTextFieldStyle_Previews: PreviewProvider { public static var previews: some View { - VStack(spacing: 12) { - TextField("Placeholder", text: .constant("")) - .textFieldStyle(.elementInput(labelText: "Label", footerText: "Footer")) - TextField("Placeholder", text: .constant("Input text")) - .textFieldStyle(.elementInput(labelText: "Title", footerText: "Footer")) - TextField("Placeholder", text: .constant("Bad text")) - .textFieldStyle(.elementInput(labelText: "Title", footerText: "Footer", isError: true)) - TextField("Placeholder", text: .constant("")) - .textFieldStyle(.elementInput(labelText: "Title", footerText: "Footer")) - .disabled(true) + ScrollView { + VStack(spacing: 20) { + // Plain text field. + TextField("Placeholder", text: .constant("")) + .textFieldStyle(.elementInput()) + TextField("Placeholder", text: .constant("Web")) + .textFieldStyle(.elementInput()) + TextField("Placeholder", text: .constant("Web")) + .textFieldStyle(.elementInput()) + .disabled(true) + TextField("Placeholder", text: .constant("Web")) + .textFieldStyle(.elementInput(isError: true)) + + // Text field with labels + TextField("Placeholder", text: .constant("")) + .textFieldStyle(.elementInput(labelText: "Label", footerText: "Footer")) + TextField("Placeholder", text: .constant("Input text")) + .textFieldStyle(.elementInput(labelText: "Title", footerText: "Footer")) + TextField("Placeholder", text: .constant("Bad text")) + .textFieldStyle(.elementInput(labelText: "Title", footerText: "Footer", isError: true)) + TextField("Placeholder", text: .constant("")) + .textFieldStyle(.elementInput(labelText: "Title", footerText: "Footer")) + .disabled(true) + } + .padding() } - .padding() } } diff --git a/ElementX/Sources/Services/SessionVerification/MockSessionVerificationControllerProxy.swift b/ElementX/Sources/Services/SessionVerification/MockSessionVerificationControllerProxy.swift index 5487c31ea..90d37a11c 100644 --- a/ElementX/Sources/Services/SessionVerification/MockSessionVerificationControllerProxy.swift +++ b/ElementX/Sources/Services/SessionVerification/MockSessionVerificationControllerProxy.swift @@ -22,7 +22,7 @@ struct MockSessionVerificationControllerProxy: SessionVerificationControllerProx var callbacks = PassthroughSubject() var isVerified = false - var requestDelay: Duration = .seconds(2) + var requestDelay: Duration = .seconds(1) func requestVerification() async -> Result { Task.detached { diff --git a/ElementX/Sources/UITests/UITestsAppCoordinator.swift b/ElementX/Sources/UITests/UITestsAppCoordinator.swift index 953e476f1..9f59ad4f4 100644 --- a/ElementX/Sources/UITests/UITestsAppCoordinator.swift +++ b/ElementX/Sources/UITests/UITestsAppCoordinator.swift @@ -253,7 +253,9 @@ class MockScreen: Identifiable { navigationStackCoordinator.setRootCoordinator(coordinator) return navigationStackCoordinator case .sessionVerification: - let parameters = SessionVerificationCoordinatorParameters(sessionVerificationControllerProxy: MockSessionVerificationControllerProxy()) + var sessionVerificationControllerProxy = MockSessionVerificationControllerProxy() + sessionVerificationControllerProxy.requestDelay = .seconds(2) + let parameters = SessionVerificationCoordinatorParameters(sessionVerificationControllerProxy: sessionVerificationControllerProxy) return SessionVerificationCoordinator(parameters: parameters) case .userSessionScreen: let navigationSplitCoordinator = NavigationSplitCoordinator(placeholderCoordinator: SplashScreenCoordinator()) diff --git a/ElementX/Sources/UITests/UITestsSignalling.swift b/ElementX/Sources/UITests/UITestsSignalling.swift index 3e7ec2240..709616b2e 100644 --- a/ElementX/Sources/UITests/UITestsSignalling.swift +++ b/ElementX/Sources/UITests/UITestsSignalling.swift @@ -39,6 +39,8 @@ enum UITestsSignalError: Error { case notConnected /// Attempted to receive multiple signals at once. case awaitingAnotherSignal + /// Receiving the next signal timed out. + case timeout /// A network error occurred. case nwError(NWError) /// An unexpected signal was received. This error isn't used internally. @@ -123,6 +125,12 @@ enum UITestsSignalling { private let connection: NWConnection /// A continuation to call each time a signal is received. private var nextMessageContinuation: CheckedContinuation? + /// A task to handle the timeout when receiving a signal. + private var nextMessageTimeoutTask: Task? { + didSet { + oldValue?.cancel() + } + } /// Creates a new signalling `Connection`. init() { @@ -165,6 +173,7 @@ enum UITestsSignalling { if let nextMessageContinuation { nextMessageContinuation.resume(throwing: UITestsSignalError.cancelled) self.nextMessageContinuation = nil + nextMessageTimeoutTask = nil } } @@ -182,6 +191,20 @@ enum UITestsSignalling { return try await withCheckedThrowingContinuation { continuation in self.nextMessageContinuation = continuation + + // Add a 30 second timeout to stop tests from hanging + self.nextMessageTimeoutTask = Task { [weak self] in + guard let self else { return } + try? await Task.sleep(for: .seconds(30)) + + guard !Task.isCancelled, + let nextMessageContinuation = self.nextMessageContinuation + else { return } + + nextMessageContinuation.resume(throwing: UITestsSignalError.timeout) + self.nextMessageContinuation = nil + self.nextMessageTimeoutTask = nil + } } } @@ -198,12 +221,14 @@ enum UITestsSignalling { let error: UITestsSignalError = error.map { .nwError($0) } ?? .unknown self.nextMessageContinuation?.resume(with: .failure(error)) self.nextMessageContinuation = nil + self.nextMessageTimeoutTask = nil return } if signal != .connect { self.nextMessageContinuation?.resume(returning: signal) self.nextMessageContinuation = nil + self.nextMessageTimeoutTask = nil } self.receiveNextMessage() diff --git a/UITests/Sources/LoginScreenUITests.swift b/UITests/Sources/LoginScreenUITests.swift index 040bfc7b9..a711da12b 100644 --- a/UITests/Sources/LoginScreenUITests.swift +++ b/UITests/Sources/LoginScreenUITests.swift @@ -19,127 +19,41 @@ import XCTest @MainActor class LoginScreenUITests: XCTestCase { - var app: XCUIApplication! - - @MainActor - override func setUp() async throws { - app = nil - } - func testMatrixDotOrg() { // Given the initial login screen which defaults to matrix.org. - app = Application.launch() + let app = Application.launch() app.goToScreenWithIdentifier(.login) - - let state = "matrix.org" - validateLoginFormIsVisible(for: state) - validateOIDCButtonIsHidden(for: state) - validateNextButtonIsDisabled(for: state) - validateUnsupportedServerTextIsHidden(for: state) - app.assertScreenshot(.login) // When typing in a username and password. - app.textFields.element.clearAndTypeText("@test:matrix.org") - - app.secureTextFields.element.clearAndTypeText("12345678") + app.textFields["usernameTextField"].clearAndTypeText("@test:matrix.org") + app.secureTextFields["passwordTextField"].clearAndTypeText("12345678") // Then the form should be ready to submit. - validateNextButtonIsEnabled(for: "matrix.org with credentials entered") + app.assertScreenshot(.login, step: 0) } func testOIDC() { // Given the initial login screen. - app = Application.launch() + let app = Application.launch() app.goToScreenWithIdentifier(.login) // When entering a username on a homeserver that only supports OIDC. - app.textFields.element.clearAndTypeText("@test:company.com\n") + app.textFields["usernameTextField"].clearAndTypeText("@test:company.com\n") // Then the screen should be configured for OIDC. - let state = "an OIDC only server" - validateOIDCButtonIsShown(for: state) - validateLoginFormIsHidden(for: state) - validateUnsupportedServerTextIsHidden(for: state) + app.assertScreenshot(.login, step: 1) } func testUnsupported() { // Given the initial login screen. - app = Application.launch() + let app = Application.launch() app.goToScreenWithIdentifier(.login) // When entering a username on a homeserver with an unsupported flow. - app.textFields.element.clearAndTypeText("@test:server.net\n") + app.textFields["usernameTextField"].clearAndTypeText("@test:server.net\n") // Then the screen should not allow login to continue. - let state = "an unsupported server" - validateUnsupportedServerTextIsShown(for: state) - validateLoginFormIsHidden(for: state) - validateOIDCButtonIsHidden(for: state) - } - - /// Checks that the username and password text fields are shown along with the next button. - func validateLoginFormIsVisible(for state: String) { - let usernameTextField = app.textFields.element - let passwordTextField = app.secureTextFields.element - let nextButton = app.buttons["nextButton"] - - XCTAssertTrue(usernameTextField.exists, "Username input should be shown for \(state).") - XCTAssertTrue(passwordTextField.exists, "Password input should be shown for \(state).") - XCTAssertTrue(nextButton.exists, "The next button should be shown for \(state).") - XCTAssertEqual(nextButton.label, ElementL10n.loginSignupSubmit) - } - - /// Checks that the username and password text fields are hidden along with the next button. - func validateLoginFormIsHidden(for state: String) { - let usernameTextField = app.textFields.element - let passwordTextField = app.secureTextFields.element - let nextButton = app.buttons["nextButton"] - - XCTAssertFalse(usernameTextField.exists, "Username input should not be shown for \(state).") - XCTAssertFalse(passwordTextField.exists, "Password input should not be shown for \(state).") - XCTAssertFalse(nextButton.exists, "The next button should not be shown for \(state).") - } - - /// Checks that the next button is shown but is disabled. - func validateNextButtonIsDisabled(for state: String) { - let nextButton = app.buttons["nextButton"] - XCTAssertTrue(nextButton.exists, "The next button should be shown.") - XCTAssertFalse(nextButton.isEnabled, "The next button should be disabled for \(state).") - XCTAssertEqual(nextButton.label, ElementL10n.loginSignupSubmit) - } - - /// Checks that the next button is shown and is enabled. - func validateNextButtonIsEnabled(for state: String) { - let nextButton = app.buttons["nextButton"] - XCTAssertTrue(nextButton.exists, "The next button should be shown.") - XCTAssertTrue(nextButton.isEnabled, "The next button should be enabled for \(state).") - XCTAssertEqual(nextButton.label, ElementL10n.loginSignupSubmit) - } - - /// Checks that the OIDC button is shown on the screen. - func validateOIDCButtonIsShown(for state: String) { - let oidcButton = app.buttons["oidcButton"] - XCTAssertTrue(oidcButton.waitForExistence(timeout: 1), "The OIDC button should be shown for \(state).") - XCTAssertEqual(oidcButton.label, ElementL10n.loginContinue) - } - - /// Checks that the OIDC button is not shown on the screen. - func validateOIDCButtonIsHidden(for state: String) { - let oidcButton = app.buttons["oidcButton"] - XCTAssertFalse(oidcButton.exists, "The OIDC button should be hidden for \(state).") - } - - /// Checks that the unsupported homeserver text is shown on the screen. - func validateUnsupportedServerTextIsShown(for state: String) { - let unsupportedText = app.staticTexts["unsupportedServerText"] - XCTAssertTrue(unsupportedText.waitForExistence(timeout: 1), "The unsupported homeserver text should be shown for \(state).") - XCTAssertEqual(unsupportedText.label, ElementL10n.autodiscoverWellKnownError) - } - - /// Checks that the unsupported homeserver text is not shown on the screen. - func validateUnsupportedServerTextIsHidden(for state: String) { - let unsupportedText = app.staticTexts["unsupportedServerText"] - XCTAssertFalse(unsupportedText.exists, "The unsupported homeserver text should be hidden for \(state).") + app.assertScreenshot(.login, step: 2) } } diff --git a/UITests/Sources/__Snapshots__/Application/de-DE-iPad-9th-generation.login-0.png b/UITests/Sources/__Snapshots__/Application/de-DE-iPad-9th-generation.login-0.png new file mode 100644 index 000000000..d0acadac0 --- /dev/null +++ b/UITests/Sources/__Snapshots__/Application/de-DE-iPad-9th-generation.login-0.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:4b94b634587f6f2326763babe911f68f089f0c82b5d5ecb48a8da9a48d4ed048 +size 91500 diff --git a/UITests/Sources/__Snapshots__/Application/de-DE-iPad-9th-generation.login-1.png b/UITests/Sources/__Snapshots__/Application/de-DE-iPad-9th-generation.login-1.png new file mode 100644 index 000000000..3467b2ddb --- /dev/null +++ b/UITests/Sources/__Snapshots__/Application/de-DE-iPad-9th-generation.login-1.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:2047a424580d38d7780fef8a1287d70fc1663565cc1cbfce30882b7fc2df8993 +size 76516 diff --git a/UITests/Sources/__Snapshots__/Application/de-DE-iPad-9th-generation.login-2.png b/UITests/Sources/__Snapshots__/Application/de-DE-iPad-9th-generation.login-2.png new file mode 100644 index 000000000..841ccca56 --- /dev/null +++ b/UITests/Sources/__Snapshots__/Application/de-DE-iPad-9th-generation.login-2.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:572337d216e1705d6c23c47bfaf064f0518f9048e4d9ff06b48079e986702d14 +size 83871 diff --git a/UITests/Sources/__Snapshots__/Application/de-DE-iPhone-14.login-0.png b/UITests/Sources/__Snapshots__/Application/de-DE-iPhone-14.login-0.png new file mode 100644 index 000000000..1da16d8eb --- /dev/null +++ b/UITests/Sources/__Snapshots__/Application/de-DE-iPhone-14.login-0.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f56d59dee20430b613c93ed9d05547fbc887a5f5f4f66fa9cbc6da14d9d1d86f +size 102841 diff --git a/UITests/Sources/__Snapshots__/Application/de-DE-iPhone-14.login-1.png b/UITests/Sources/__Snapshots__/Application/de-DE-iPhone-14.login-1.png new file mode 100644 index 000000000..ce3899fd6 --- /dev/null +++ b/UITests/Sources/__Snapshots__/Application/de-DE-iPhone-14.login-1.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:bd8314e6b5eaa80eea9bba1d3a93d1c224707fb81b6280625454d6136c8ca66f +size 80882 diff --git a/UITests/Sources/__Snapshots__/Application/de-DE-iPhone-14.login-2.png b/UITests/Sources/__Snapshots__/Application/de-DE-iPhone-14.login-2.png new file mode 100644 index 000000000..2777e146f --- /dev/null +++ b/UITests/Sources/__Snapshots__/Application/de-DE-iPhone-14.login-2.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:ce3f468a20ae0d814dfc91dd138c5f861505e4b0283c1d3e09f81adad2b6d37e +size 91436 diff --git a/UITests/Sources/__Snapshots__/Application/en-GB-iPad-9th-generation.login-0.png b/UITests/Sources/__Snapshots__/Application/en-GB-iPad-9th-generation.login-0.png new file mode 100644 index 000000000..257e423ab --- /dev/null +++ b/UITests/Sources/__Snapshots__/Application/en-GB-iPad-9th-generation.login-0.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:d6dd66777ae8f3e28df56483cdc1a7ec69c89215e1cff3a4eb89babcca05f68b +size 89322 diff --git a/UITests/Sources/__Snapshots__/Application/en-GB-iPad-9th-generation.login-1.png b/UITests/Sources/__Snapshots__/Application/en-GB-iPad-9th-generation.login-1.png new file mode 100644 index 000000000..73185d3d5 --- /dev/null +++ b/UITests/Sources/__Snapshots__/Application/en-GB-iPad-9th-generation.login-1.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:376013470882195ec51279f0ddf31e1704c6751ef10b0154e937df2bd93daf9d +size 74868 diff --git a/UITests/Sources/__Snapshots__/Application/en-GB-iPad-9th-generation.login-2.png b/UITests/Sources/__Snapshots__/Application/en-GB-iPad-9th-generation.login-2.png new file mode 100644 index 000000000..463596d44 --- /dev/null +++ b/UITests/Sources/__Snapshots__/Application/en-GB-iPad-9th-generation.login-2.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:eb947f6d7daf93f194f513cd0d2c30cf549382c39d7997dab32ace6be08faf1b +size 79052 diff --git a/UITests/Sources/__Snapshots__/Application/en-GB-iPhone-14.login-0.png b/UITests/Sources/__Snapshots__/Application/en-GB-iPhone-14.login-0.png new file mode 100644 index 000000000..567187e6f --- /dev/null +++ b/UITests/Sources/__Snapshots__/Application/en-GB-iPhone-14.login-0.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f4d64453f35dca2757748779076ceb8ece88d1725f8b276ced97026416eac5d3 +size 98345 diff --git a/UITests/Sources/__Snapshots__/Application/en-GB-iPhone-14.login-1.png b/UITests/Sources/__Snapshots__/Application/en-GB-iPhone-14.login-1.png new file mode 100644 index 000000000..cc8221e3d --- /dev/null +++ b/UITests/Sources/__Snapshots__/Application/en-GB-iPhone-14.login-1.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:c8cbed1a62e312a569b30822a3551a19552f1b363590522ed58a2b7059598f84 +size 77367 diff --git a/UITests/Sources/__Snapshots__/Application/en-GB-iPhone-14.login-2.png b/UITests/Sources/__Snapshots__/Application/en-GB-iPhone-14.login-2.png new file mode 100644 index 000000000..db7fcefc8 --- /dev/null +++ b/UITests/Sources/__Snapshots__/Application/en-GB-iPhone-14.login-2.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:73e27d2985ac00b401c794248e9a582abdef6c4bc024180e0a138781a3d8d087 +size 86637 diff --git a/UnitTests/Sources/SessionVerificationViewModelTests.swift b/UnitTests/Sources/SessionVerificationViewModelTests.swift index 7b28e6e67..bf3e5913d 100644 --- a/UnitTests/Sources/SessionVerificationViewModelTests.swift +++ b/UnitTests/Sources/SessionVerificationViewModelTests.swift @@ -74,7 +74,7 @@ class SessionVerificationViewModelTests: XCTestCase { let waitForAcceptance = XCTestExpectation(description: "Wait for acceptance") let cancellable = sessionVerificationController.callbacks - .debounce(for: .seconds(2.0), scheduler: DispatchQueue.main) + .delay(for: .seconds(0.1), scheduler: DispatchQueue.main) // Allow the view model to process the callback first. .sink { callback in switch callback { case .finished: @@ -101,7 +101,7 @@ class SessionVerificationViewModelTests: XCTestCase { let expectation = XCTestExpectation(description: "Wait for cancellation") let cancellable = sessionVerificationController.callbacks - .debounce(for: .seconds(2.0), scheduler: DispatchQueue.main) + .delay(for: .seconds(0.1), scheduler: DispatchQueue.main) // Allow the view model to process the callback first. .sink { callback in switch callback { case .cancelled: @@ -130,7 +130,7 @@ class SessionVerificationViewModelTests: XCTestCase { let verificationDataReceivalExpectation = XCTestExpectation(description: "Wait for Emoji data") let cancellable = sessionVerificationController.callbacks - .debounce(for: .seconds(2.0), scheduler: DispatchQueue.main) + .delay(for: .seconds(0.1), scheduler: DispatchQueue.main) // Allow the view model to process the callback first. .sink { callback in switch callback { case .acceptedVerificationRequest: