From 00bc8d0581aeed5d57919ffe037dacff860a2e41 Mon Sep 17 00:00:00 2001 From: "Eric C. Johnson" Date: Fri, 12 Jun 2026 15:17:37 -0600 Subject: [PATCH] @W-22954922: [iOS] Stabilize flaky test testCAOpaque_DefaultScopes_WebServerFlow (increase timeouts and assert wait results) --- .github/workflows/pr.yaml | 4 +-- .github/workflows/ui-test-nightly.yaml | 4 +-- .../AuthFlowTesterMainPageObject.swift | 13 +++++----- .../PageObjects/AuthFlowTypesPageObject.swift | 5 ++-- .../PageObjects/LoginOptionsPageObject.swift | 5 ++-- .../PageObjects/LoginPageObject.swift | 25 ++++++++++--------- .../Util/UITestTimeouts.swift | 17 ++++++++++--- 7 files changed, 43 insertions(+), 30 deletions(-) diff --git a/.github/workflows/pr.yaml b/.github/workflows/pr.yaml index 44b2adf2bf..e9590e7f7e 100644 --- a/.github/workflows/pr.yaml +++ b/.github/workflows/pr.yaml @@ -183,8 +183,8 @@ jobs: ios: ${{ matrix.ios }} xcode: ${{ matrix.xcode }} pr_test: "AuthFlowTesterUITests/LegacyLoginTests/testCAOpaque_DefaultScopes_WebServerFlow" - short_timeout: "2" - long_timeout: "7" + short_timeout: "3" + long_timeout: "15" secrets: UI_TEST_CONFIG: ${{ secrets.UI_TEST_CONFIG }} CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} \ No newline at end of file diff --git a/.github/workflows/ui-test-nightly.yaml b/.github/workflows/ui-test-nightly.yaml index d126682d47..684b90fc47 100644 --- a/.github/workflows/ui-test-nightly.yaml +++ b/.github/workflows/ui-test-nightly.yaml @@ -26,8 +26,8 @@ jobs: with: ios: ${{ matrix.ios }} xcode: ${{ matrix.xcode }} - short_timeout: "2" - long_timeout: "7" + short_timeout: "3" + long_timeout: "15" secrets: UI_TEST_CONFIG: ${{ secrets.UI_TEST_CONFIG }} CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} diff --git a/native/SampleApps/AuthFlowTester/AuthFlowTesterUITests/PageObjects/AuthFlowTesterMainPageObject.swift b/native/SampleApps/AuthFlowTester/AuthFlowTesterUITests/PageObjects/AuthFlowTesterMainPageObject.swift index 8ccc32fa25..86b8bd61cd 100644 --- a/native/SampleApps/AuthFlowTester/AuthFlowTesterUITests/PageObjects/AuthFlowTesterMainPageObject.swift +++ b/native/SampleApps/AuthFlowTester/AuthFlowTesterUITests/PageObjects/AuthFlowTesterMainPageObject.swift @@ -221,7 +221,7 @@ class AuthFlowTesterMainPageObject { } func isShowing() -> Bool { - return navigationTitle().waitForExistence(timeout: UITestTimeouts.long) + return navigationTitle().waitForExistence(timeout: UITestTimeouts.network) } func performLogout() { @@ -461,13 +461,14 @@ class AuthFlowTesterMainPageObject { // MARK: - Actions - private func tap(_ element: XCUIElement) { - _ = element.waitForExistence(timeout: UITestTimeouts.long) + private func tap(_ element: XCUIElement, timeout: TimeInterval = UITestTimeouts.long, file: StaticString = #file, line: UInt = #line) { + let exists = element.waitForExistence(timeout: timeout) + XCTAssertTrue(exists, "Element \(element.debugDescription) did not appear within \(timeout)s", file: file, line: line) element.tap() } - - private func tapIfPresent(_ element: XCUIElement) { - if (element.waitForExistence(timeout: UITestTimeouts.long)) { + + private func tapIfPresent(_ element: XCUIElement, timeout: TimeInterval = UITestTimeouts.long) { + if element.waitForExistence(timeout: timeout) { element.tap() } } diff --git a/native/SampleApps/AuthFlowTester/AuthFlowTesterUITests/PageObjects/AuthFlowTypesPageObject.swift b/native/SampleApps/AuthFlowTester/AuthFlowTesterUITests/PageObjects/AuthFlowTypesPageObject.swift index 54e3593aa9..fa2ede27d0 100644 --- a/native/SampleApps/AuthFlowTester/AuthFlowTesterUITests/PageObjects/AuthFlowTypesPageObject.swift +++ b/native/SampleApps/AuthFlowTester/AuthFlowTesterUITests/PageObjects/AuthFlowTypesPageObject.swift @@ -88,8 +88,9 @@ class AuthFlowTypesPageObject { // MARK: - Actions - private func tap(_ element: XCUIElement) { - _ = element.waitForExistence(timeout: UITestTimeouts.long) + private func tap(_ element: XCUIElement, timeout: TimeInterval = UITestTimeouts.long, file: StaticString = #file, line: UInt = #line) { + let exists = element.waitForExistence(timeout: timeout) + XCTAssertTrue(exists, "Element \(element.debugDescription) did not appear within \(timeout)s", file: file, line: line) element.tap() } } diff --git a/native/SampleApps/AuthFlowTester/AuthFlowTesterUITests/PageObjects/LoginOptionsPageObject.swift b/native/SampleApps/AuthFlowTester/AuthFlowTesterUITests/PageObjects/LoginOptionsPageObject.swift index 7753b711ba..9bc10fbdbe 100644 --- a/native/SampleApps/AuthFlowTester/AuthFlowTesterUITests/PageObjects/LoginOptionsPageObject.swift +++ b/native/SampleApps/AuthFlowTester/AuthFlowTesterUITests/PageObjects/LoginOptionsPageObject.swift @@ -148,8 +148,9 @@ class LoginOptionsPageObject { // MARK: - Actions - private func tap(_ element: XCUIElement) { - _ = element.waitForExistence(timeout: UITestTimeouts.long) + private func tap(_ element: XCUIElement, timeout: TimeInterval = UITestTimeouts.long, file: StaticString = #file, line: UInt = #line) { + let exists = element.waitForExistence(timeout: timeout) + XCTAssertTrue(exists, "Element \(element.debugDescription) did not appear within \(timeout)s", file: file, line: line) element.tap() } } diff --git a/native/SampleApps/AuthFlowTester/AuthFlowTesterUITests/PageObjects/LoginPageObject.swift b/native/SampleApps/AuthFlowTester/AuthFlowTesterUITests/PageObjects/LoginPageObject.swift index fded35d832..cea132da46 100644 --- a/native/SampleApps/AuthFlowTester/AuthFlowTesterUITests/PageObjects/LoginPageObject.swift +++ b/native/SampleApps/AuthFlowTester/AuthFlowTesterUITests/PageObjects/LoginPageObject.swift @@ -39,7 +39,7 @@ class LoginPageObject { } func isShowing() -> Bool { - return loginNavigationBar().waitForExistence(timeout: UITestTimeouts.long) + return loginNavigationBar().waitForExistence(timeout: UITestTimeouts.network) } func hasFilledUsernameField(username: String) -> Bool { @@ -84,16 +84,16 @@ class LoginPageObject { usernameField().typeText(XCUIKeyboardKey.return.rawValue) } else { dismissKeyboardAfterTyping() - tap(loginButton()) + tap(loginButton(), timeout: UITestTimeouts.network) } setTextField(passwordField(), value: password) if advancedAuth { passwordField().typeText(XCUIKeyboardKey.return.rawValue) } else { dismissKeyboardAfterTyping() - tap(loginButton()) + tap(loginButton(), timeout: UITestTimeouts.network) } - tapIfPresent(allowButton()) + tapIfPresent(allowButton(), timeout: UITestTimeouts.network) } /// Performs login via the "Login for Admin" flow. @@ -111,15 +111,15 @@ class LoginPageObject { } func performWelcomeLogin(password: String, advancedAuth: Bool = false) { - tap(loginButton()) + tap(loginButton(), timeout: UITestTimeouts.network) setTextField(passwordField(), value: password) if advancedAuth { passwordField().typeText(XCUIKeyboardKey.return.rawValue) } else { dismissKeyboardAfterTyping() - tap(loginButton()) + tap(loginButton(), timeout: UITestTimeouts.network) } - tapIfPresent(allowButton()) + tapIfPresent(allowButton(), timeout: UITestTimeouts.network) } func configureLoginOptions( @@ -257,14 +257,15 @@ class LoginPageObject { // MARK: - Actions - private func tap(_ element: XCUIElement) { - _ = element.waitForExistence(timeout: UITestTimeouts.long) + private func tap(_ element: XCUIElement, timeout: TimeInterval = UITestTimeouts.long, file: StaticString = #file, line: UInt = #line) { + let exists = element.waitForExistence(timeout: timeout) + XCTAssertTrue(exists, "Element \(element.debugDescription) did not appear within \(timeout)s", file: file, line: line) element.tap() } - + @discardableResult - private func tapIfPresent(_ element: XCUIElement) -> Bool { - if element.waitForExistence(timeout: UITestTimeouts.long) { + private func tapIfPresent(_ element: XCUIElement, timeout: TimeInterval = UITestTimeouts.long) -> Bool { + if element.waitForExistence(timeout: timeout) { element.tap() return true } diff --git a/native/SampleApps/AuthFlowTester/AuthFlowTesterUITests/Util/UITestTimeouts.swift b/native/SampleApps/AuthFlowTester/AuthFlowTesterUITests/Util/UITestTimeouts.swift index 9afe2d5866..db4ec8b29c 100644 --- a/native/SampleApps/AuthFlowTester/AuthFlowTesterUITests/Util/UITestTimeouts.swift +++ b/native/SampleApps/AuthFlowTester/AuthFlowTesterUITests/Util/UITestTimeouts.swift @@ -28,13 +28,16 @@ import Foundation /// Provides timeout values for UI test element waits. -/// Values come from the environment (`UI_TEST_SHORT_TIMEOUT`, `UI_TEST_LONG_TIMEOUT`) when set, -/// otherwise from defaults. CI workflows can pass larger timeouts via these env vars. +/// Values come from the environment (`UI_TEST_SHORT_TIMEOUT`, `UI_TEST_LONG_TIMEOUT`, +/// `UI_TEST_NETWORK_TIMEOUT`) when set, otherwise from defaults. +/// CI workflows can pass larger timeouts via these env vars. enum UITestTimeouts { /// Default short timeout in seconds (e.g. for quick UI state checks). - private static let defaultShort: TimeInterval = 1 + private static let defaultShort: TimeInterval = 2 /// Default long timeout in seconds (e.g. for page load or alert appearance). - private static let defaultLong: TimeInterval = 3 + private static let defaultLong: TimeInterval = 10 + /// Default network timeout in seconds (e.g. for operations that hit real OAuth servers). + private static let defaultNetwork: TimeInterval = 30 private static func parseEnv(_ key: String) -> TimeInterval? { guard let raw = ProcessInfo.processInfo.environment[key], @@ -53,4 +56,10 @@ enum UITestTimeouts { static var long: TimeInterval { parseEnv("UI_TEST_LONG_TIMEOUT") ?? defaultLong } + + /// Network timeout (seconds). Use for operations involving real server round-trips + /// (e.g. OAuth login, WKWebView page loads hitting Salesforce endpoints). + static var network: TimeInterval { + parseEnv("UI_TEST_NETWORK_TIMEOUT") ?? defaultNetwork + } }