From 572b158d37157d802ab2c8993a5d46c20d3f723b Mon Sep 17 00:00:00 2001 From: Chris Yang Date: Tue, 25 Apr 2023 14:54:10 -0700 Subject: [PATCH 1/4] draft --- .../example/ios/RunnerUITests/RunnerUITests.swift | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/packages/quick_actions/quick_actions_ios/example/ios/RunnerUITests/RunnerUITests.swift b/packages/quick_actions/quick_actions_ios/example/ios/RunnerUITests/RunnerUITests.swift index a59692e7639d..3c183bac42d7 100644 --- a/packages/quick_actions/quick_actions_ios/example/ios/RunnerUITests/RunnerUITests.swift +++ b/packages/quick_actions/quick_actions_ios/example/ios/RunnerUITests/RunnerUITests.swift @@ -5,6 +5,9 @@ import XCTest private let elementWaitingTime: TimeInterval = 30 +private let quickActionPressDuration: TimeInterval = 1.5 +// Max number of tries to open the quick action menu if failed. +private let quickActionMaxRetries: Int = 3; class RunnerUITests: XCTestCase { @@ -31,7 +34,7 @@ class RunnerUITests: XCTestCase { ) } - quickActionsAppIcon.press(forDuration: 2) + quickActionsAppIcon.press(forDuration: quickActionPressDuration) let actionTwo = springboard.buttons["Action two"] if !actionTwo.waitForExistence(timeout: elementWaitingTime) { @@ -73,7 +76,7 @@ class RunnerUITests: XCTestCase { ) } - quickActionsAppIcon.press(forDuration: 2) + quickActionsAppIcon.press(forDuration: quickActionPressDuration) let actionOne = springboard.buttons["Action one"] if !actionOne.waitForExistence(timeout: elementWaitingTime) { From 3080c6fffa00a523536116ed890a2907499e27ce Mon Sep 17 00:00:00 2001 From: Chris Yang Date: Tue, 25 Apr 2023 15:44:56 -0700 Subject: [PATCH 2/4] retries --- .../ios/RunnerUITests/RunnerUITests.swift | 34 +++++++++++++------ 1 file changed, 24 insertions(+), 10 deletions(-) diff --git a/packages/quick_actions/quick_actions_ios/example/ios/RunnerUITests/RunnerUITests.swift b/packages/quick_actions/quick_actions_ios/example/ios/RunnerUITests/RunnerUITests.swift index 3c183bac42d7..9e60ee3d318d 100644 --- a/packages/quick_actions/quick_actions_ios/example/ios/RunnerUITests/RunnerUITests.swift +++ b/packages/quick_actions/quick_actions_ios/example/ios/RunnerUITests/RunnerUITests.swift @@ -34,16 +34,23 @@ class RunnerUITests: XCTestCase { ) } - quickActionsAppIcon.press(forDuration: quickActionPressDuration) - - let actionTwo = springboard.buttons["Action two"] - if !actionTwo.waitForExistence(timeout: elementWaitingTime) { + var actionTwo: XCUIElement? + for _ in 1...quickActionMaxRetries { + quickActionsAppIcon.press(forDuration: quickActionPressDuration) + actionTwo = springboard.buttons["Action two"] + if actionTwo!.waitForExistence(timeout: elementWaitingTime) { + break + } + // Reset to previous state. + XCUIDevice.shared.press(XCUIDevice.Button.home) + } + if (!actionTwo!.exists) { XCTFail( "Failed due to not able to find the actionTwo button from springboard with \(elementWaitingTime) seconds. Springboard debug description: \(springboard.debugDescription)" ) } - actionTwo.tap() + actionTwo!.tap() let actionTwoConfirmation = exampleApp.otherElements["action_two"] if !actionTwoConfirmation.waitForExistence(timeout: elementWaitingTime) { @@ -76,16 +83,23 @@ class RunnerUITests: XCTestCase { ) } - quickActionsAppIcon.press(forDuration: quickActionPressDuration) - - let actionOne = springboard.buttons["Action one"] - if !actionOne.waitForExistence(timeout: elementWaitingTime) { + var actionOne: XCUIElement? + for _ in 1...quickActionMaxRetries { + quickActionsAppIcon.press(forDuration: quickActionPressDuration) + actionOne = springboard.buttons["Action one"] + if actionOne!.waitForExistence(timeout: elementWaitingTime) { + break + } + // Reset to previous state. + XCUIDevice.shared.press(XCUIDevice.Button.home) + } + if (!actionOne!.exists) { XCTFail( "Failed due to not able to find the actionOne button from springboard with \(elementWaitingTime) seconds. Springboard debug description: \(springboard.debugDescription)" ) } - actionOne.tap() + actionOne!.tap() let actionOneConfirmation = exampleApp.otherElements["action_one"] if !actionOneConfirmation.waitForExistence(timeout: elementWaitingTime) { From a15dfdb0a1ef6575427a08dfa4898eaac252d26a Mon Sep 17 00:00:00 2001 From: Chris Yang Date: Wed, 26 Apr 2023 14:47:17 -0700 Subject: [PATCH 3/4] adjust wait time --- .../ios/RunnerUITests/RunnerUITests.swift | 79 +++++++++---------- 1 file changed, 39 insertions(+), 40 deletions(-) diff --git a/packages/quick_actions/quick_actions_ios/example/ios/RunnerUITests/RunnerUITests.swift b/packages/quick_actions/quick_actions_ios/example/ios/RunnerUITests/RunnerUITests.swift index 9e60ee3d318d..52ae64c71e48 100644 --- a/packages/quick_actions/quick_actions_ios/example/ios/RunnerUITests/RunnerUITests.swift +++ b/packages/quick_actions/quick_actions_ios/example/ios/RunnerUITests/RunnerUITests.swift @@ -4,10 +4,11 @@ import XCTest -private let elementWaitingTime: TimeInterval = 30 +private let elementWaitingTime: TimeInterval = 5 private let quickActionPressDuration: TimeInterval = 1.5 +private let pressDurationRetryAdjustment: TimeInterval = 0.2 // Max number of tries to open the quick action menu if failed. -private let quickActionMaxRetries: Int = 3; +private let quickActionMaxRetries: Int = 4; class RunnerUITests: XCTestCase { @@ -28,29 +29,8 @@ class RunnerUITests: XCTestCase { func testQuickActionWithFreshStart() { let springboard = XCUIApplication(bundleIdentifier: "com.apple.springboard") let quickActionsAppIcon = springboard.icons["quick_actions_example"] - if !quickActionsAppIcon.waitForExistence(timeout: elementWaitingTime) { - XCTFail( - "Failed due to not able to find the example app from springboard with \(elementWaitingTime) seconds. Springboard debug description: \(springboard.debugDescription)" - ) - } - var actionTwo: XCUIElement? - for _ in 1...quickActionMaxRetries { - quickActionsAppIcon.press(forDuration: quickActionPressDuration) - actionTwo = springboard.buttons["Action two"] - if actionTwo!.waitForExistence(timeout: elementWaitingTime) { - break - } - // Reset to previous state. - XCUIDevice.shared.press(XCUIDevice.Button.home) - } - if (!actionTwo!.exists) { - XCTFail( - "Failed due to not able to find the actionTwo button from springboard with \(elementWaitingTime) seconds. Springboard debug description: \(springboard.debugDescription)" - ) - } - - actionTwo!.tap() + findAndTapQuickActionButton(buttonName: "Action two", quickActionsAppIcon: quickActionsAppIcon, springboard: springboard); let actionTwoConfirmation = exampleApp.otherElements["action_two"] if !actionTwoConfirmation.waitForExistence(timeout: elementWaitingTime) { @@ -83,31 +63,50 @@ class RunnerUITests: XCTestCase { ) } - var actionOne: XCUIElement? + findAndTapQuickActionButton(buttonName: "Action one", quickActionsAppIcon: quickActionsAppIcon, springboard: springboard); + + let actionOneConfirmation = exampleApp.otherElements["action_one"] + if !actionOneConfirmation.waitForExistence(timeout: elementWaitingTime) { + XCTFail( + "Failed due to not able to find the actionOneConfirmation in the app with \(elementWaitingTime) seconds. Springboard debug description: \(springboard.debugDescription)" + ) + } + + XCTAssert(actionOneConfirmation.exists) + } + + private func findAndTapQuickActionButton(buttonName: String, quickActionsAppIcon: XCUIElement, springboard: XCUIElement) { + var actionButton: XCUIElement? + var pressDuration = quickActionPressDuration for _ in 1...quickActionMaxRetries { - quickActionsAppIcon.press(forDuration: quickActionPressDuration) - actionOne = springboard.buttons["Action one"] - if actionOne!.waitForExistence(timeout: elementWaitingTime) { + if !quickActionsAppIcon.waitForExistence(timeout: elementWaitingTime) { + XCTFail( + "Failed due to not able to find the example app from springboard with \(elementWaitingTime) seconds. Springboard debug description: \(springboard.debugDescription)" + ) + } + quickActionsAppIcon.press(forDuration: pressDuration) + actionButton = springboard.buttons[buttonName] + if actionButton!.waitForExistence(timeout: elementWaitingTime) { + // find the button, exit the retry loop. break } + let deleteButton = springboard.buttons["DeleteButton"] + if deleteButton.waitForExistence(timeout: elementWaitingTime) { + // Found delete button instead, we pressed too long, reduce the press time. + pressDuration -= pressDurationRetryAdjustment + } else { + // Neither action button nor delete button was found, we need a longer press. + pressDuration += pressDurationRetryAdjustment + } // Reset to previous state. XCUIDevice.shared.press(XCUIDevice.Button.home) } - if (!actionOne!.exists) { + if (!actionButton!.exists) { XCTFail( - "Failed due to not able to find the actionOne button from springboard with \(elementWaitingTime) seconds. Springboard debug description: \(springboard.debugDescription)" + "Failed due to not able to find the \(buttonName) button from springboard with \(elementWaitingTime) seconds. Springboard debug description: \(springboard.debugDescription)" ) } - actionOne!.tap() - - let actionOneConfirmation = exampleApp.otherElements["action_one"] - if !actionOneConfirmation.waitForExistence(timeout: elementWaitingTime) { - XCTFail( - "Failed due to not able to find the actionOneConfirmation in the app with \(elementWaitingTime) seconds. Springboard debug description: \(springboard.debugDescription)" - ) - } - - XCTAssert(actionOneConfirmation.exists) + actionButton!.tap(); } } From 33e6db4c6435093e4235754d3d720ee6e6e8ee14 Mon Sep 17 00:00:00 2001 From: Chris Yang Date: Wed, 26 Apr 2023 15:02:05 -0700 Subject: [PATCH 4/4] comments --- .../example/ios/RunnerUITests/RunnerUITests.swift | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/packages/quick_actions/quick_actions_ios/example/ios/RunnerUITests/RunnerUITests.swift b/packages/quick_actions/quick_actions_ios/example/ios/RunnerUITests/RunnerUITests.swift index 52ae64c71e48..2ac4fdbc46a9 100644 --- a/packages/quick_actions/quick_actions_ios/example/ios/RunnerUITests/RunnerUITests.swift +++ b/packages/quick_actions/quick_actions_ios/example/ios/RunnerUITests/RunnerUITests.swift @@ -4,10 +4,20 @@ import XCTest -private let elementWaitingTime: TimeInterval = 5 +private let elementWaitingTime: TimeInterval = 30 +// The duration in when pressing the app icon to open the +// quick action menu. This duration is undocumented by Apple. +// The duration will be adjusted with `pressDurationRetryAdjustment` if +// this duration does not result in the quick action menu opened. private let quickActionPressDuration: TimeInterval = 1.5 +// If the previous try to open quick action menu did not work, +// a new try with adjust the press time by this value. +// The adjusment could be + or - depends on the result of the previous try. private let pressDurationRetryAdjustment: TimeInterval = 0.2 // Max number of tries to open the quick action menu if failed. +// This is to deflake a situation where the quick action menu is not present after +// the long press. +// See: https://github.com/flutter/flutter/issues/125509 private let quickActionMaxRetries: Int = 4; class RunnerUITests: XCTestCase {