diff --git a/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue33034.cs b/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue33034.cs index e2b9d4836436..d6b8ba4e9099 100644 --- a/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue33034.cs +++ b/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue33034.cs @@ -20,12 +20,12 @@ public void SafeAreaShouldWorkOnAllShellTabs() App.SetOrientationLandscape(); //Adding delay to allow for orientation change to complete Thread.Sleep(2000); - var initialRect = App.WaitForElement("EdgeLabel").GetRect(); + var initialRect = App.WaitForElementAndGetRect("EdgeLabel"); App.TapTab("Second Tab"); App.WaitForElement("EdgeLabel"); App.TapTab("First Tab"); - var afterSwitchRect = App.WaitForElement("EdgeLabel").GetRect(); + var afterSwitchRect = App.WaitForElementAndGetRect("EdgeLabel"); Assert.That(afterSwitchRect.X, Is.EqualTo(initialRect.X).Within(5)); Assert.That(afterSwitchRect.Width, Is.EqualTo(initialRect.Width).Within(5)); diff --git a/src/TestUtils/src/UITest.Appium/HelperExtensions.cs b/src/TestUtils/src/UITest.Appium/HelperExtensions.cs index 9bd0aefa2bc6..1343d574af89 100644 --- a/src/TestUtils/src/UITest.Appium/HelperExtensions.cs +++ b/src/TestUtils/src/UITest.Appium/HelperExtensions.cs @@ -179,6 +179,39 @@ public static Rectangle GetRect(this IUIElement element) })!; } + /// + /// Waits for an element and reads its on-screen rectangle, re-querying and retrying if the + /// element reference becomes stale. A navigation or tab-switch animation can recycle the + /// underlying view between the element query and the geometry read, which surfaces as a + /// from . Re-finding + /// the element and reading again once it has settled keeps the geometry read deterministic + /// without changing what the caller asserts on. This mirrors the existing stale-element handling + /// used elsewhere in the framework (see AppiumMouseActions). + /// + /// Represents the main gateway to interact with an app. + /// The id of the element to locate and measure. + /// Optional timeout for each wait operation. Default is null, which uses the default timeout. + public static Rectangle WaitForElementAndGetRect(this IApp app, string elementId, TimeSpan? timeout = null) + { + StaleElementReferenceException? lastStale = null; + + for (int attempt = 0; attempt < 3; attempt++) + { + try + { + return app.WaitForElement(elementId, timeout: timeout).GetRect(); + } + catch (StaleElementReferenceException ex) + { + // The view was recycled between the query and the geometry read (typically + // mid-animation); re-find the element and read again now that it should have settled. + lastStale = ex; + } + } + + throw lastStale!; + } + /// /// Determine if a form or form-like element (checkbox, select, etc...) is selected. ///