Files
element-x-ios/IntegrationTests/Sources/Common.swift
Stefan Ceriu 8ead25eaa3 Stop the integration tests from backgrounding the web authentication session
Tapping the SafariViewService app object makes XCUITest activate it as a
standalone app. That backgrounds Element X, which hosts the web view, so the
hosted scene goes to the background too and WebKit suspends it mid load. The
sign in page is fetched successfully but never rendered, and the test times
out waiting for the username field.

The tap dates from when the element was a web view inside the app, where it
was a plain in app tap, so it no longer does what its comment describes.
2026-08-24 15:18:48 +03:00

138 lines
6.2 KiB
Swift

//
// Copyright 2025 Element Creations Ltd.
// Copyright 2023-2025 New Vector Ltd.
//
// SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
// Please see LICENSE files in the repository root for full details.
//
import XCTest
enum IntegrationTestsError: Error {
case webAuthenticationSessionFailure
}
extension XCUIApplication {
private var doesNotExistPredicate: NSPredicate {
NSPredicate(format: "exists == 0")
}
func login(currentTestCase: XCTestCase) throws {
let getStartedButton = buttons[A11yIdentifiers.authenticationStartScreen.signIn]
XCTAssertTrue(getStartedButton.waitForExistence(timeout: 10.0))
getStartedButton.tap(.center)
if let homeserver {
// Server selection screen appears directly after sign in
let homeserverTextField = textFields[A11yIdentifiers.changeServerScreen.server]
XCTAssertTrue(homeserverTextField.waitForExistence(timeout: 10.0))
homeserverTextField.clearAndTypeText(homeserver, app: self)
}
let springboard = XCUIApplication(bundleIdentifier: "com.apple.springboard")
let webAuthenticationSessionAlertContinueButton = springboard.buttons["Continue"].firstMatch
// On a fresh simulator the webcredentials association is sometimes slow to be resolved.
// This results in an error alert being shown instead of the Web Authentication Session alert.
// Keep looping on the Continue button for ~5 minutes until the Authentication Session is happy.
var remainingAttempts = 10
while !webAuthenticationSessionAlertContinueButton.exists {
let continueButton = buttons[A11yIdentifiers.changeServerScreen.continue]
XCTAssertTrue(continueButton.waitForExistence(timeout: 30.0))
continueButton.tap(.center)
if webAuthenticationSessionAlertContinueButton.waitForExistence(timeout: 30.0) {
break
}
remainingAttempts -= 1
if remainingAttempts <= 0 {
XCTFail("Failed to present the web authentication session.")
throw IntegrationTestsError.webAuthenticationSessionFailure
}
if alerts.firstMatch.exists {
alerts.firstMatch.buttons["OK"].firstMatch.tap()
}
}
webAuthenticationSessionAlertContinueButton.tap(.center)
let webAuthenticationView = XCUIApplication(bundleIdentifier: "com.apple.SafariViewService")
XCTAssertTrue(webAuthenticationView.waitForExistence(timeout: 10.0))
// The user may already be authenticated on MAS. Sign them out.
// The button label varies by MAS version: "Sign out" or "Use another account".
let webLogoutPredicate = NSPredicate(format: "label == 'Sign out' OR label == 'Use another account'")
let webLogoutButton = webAuthenticationView.buttons.matching(webLogoutPredicate).firstMatch
if webLogoutButton.waitForExistence(timeout: 2.0) {
webLogoutButton.tap(.center)
}
let webUsernameTextField = textFields["Username or Email"]
XCTAssertTrue(webUsernameTextField.waitForExistence(timeout: 10.0))
webUsernameTextField.clearAndTypeText(username, app: self)
webAuthenticationView.buttons["Done"].firstMatch.tap() // Dismiss the keyboard so that the password text field is fully hittable.
let webPasswordTextField = secureTextFields["Password"]
XCTAssertTrue(webPasswordTextField.waitForExistence(timeout: 10.0))
webPasswordTextField.clearAndTypeText(password, app: self)
webAuthenticationView.buttons["Done"].firstMatch.tap() // Dismiss the keyboard so that the continue button is fully hittable.
let webLoginButton = webAuthenticationView.buttons["Continue"]
XCTAssertTrue(webLoginButton.waitForExistence(timeout: 10.0))
webLoginButton.tap(.center)
// Handle the password saving dialog
let savePasswordButton = buttons["Save Password"]
if savePasswordButton.waitForExistence(timeout: 10.0) {
// Tapping the sheet button while animating upwards fails. Wait for it to settle
sleep(1)
buttons["Not Now"].tap(.center)
}
let webConsentButton = webAuthenticationView.buttons["Continue"]
XCTAssertTrue(webConsentButton.waitForExistence(timeout: 10.0))
webConsentButton.tap(.center)
// Wait for login to finish
currentTestCase.expectation(for: doesNotExistPredicate, evaluatedWith: webUsernameTextField)
currentTestCase.waitForExpectations(timeout: 300.0)
// Wait for the home screen to become visible.
let profileButton = buttons[A11yIdentifiers.homeScreen.userAvatar]
// Timeouts are huge because we're waiting for the server.
XCTAssertTrue(profileButton.waitForExistence(timeout: 300.0))
}
func logout() {
// On first login when multiple sheets get presented the profile button is not hittable
// Moving the scroll fixed it for some obscure reason
swipeDown()
let profileButton = buttons[A11yIdentifiers.homeScreen.userAvatar]
// `Failed to scroll to visible (by AX action) Button` https://stackoverflow.com/a/33534187/730924
profileButton.tap(.center)
// Make the logout button visible
swipeUp()
// Logout
let logoutButton = buttons[A11yIdentifiers.settingsScreen.logout]
XCTAssertTrue(logoutButton.waitForExistence(timeout: 10.0))
logoutButton.tap(.center)
// Confirm logout (Remove this device)
let alertLogoutButton = alerts.firstMatch.buttons[A11yIdentifiers.alertInfo.primaryButton].firstMatch
XCTAssertTrue(alertLogoutButton.waitForExistence(timeout: 10.0))
alertLogoutButton.tap(.center)
// Check that we're back on the login screen
let getStartedButton = buttons[A11yIdentifiers.authenticationStartScreen.signIn]
XCTAssertTrue(getStartedButton.waitForExistence(timeout: 10.0))
}
}