From 77e6dad82e5f04e7c8ffb27d0912840e37400f41 Mon Sep 17 00:00:00 2001 From: Steve Sanderson Date: Mon, 4 Mar 2024 10:02:58 +0000 Subject: [PATCH 1/3] Fix test CanRenderLargeComponentsWithServerRenderMode --- .../test/E2ETest/ServerRenderingTests/RenderingTest.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Components/test/E2ETest/ServerRenderingTests/RenderingTest.cs b/src/Components/test/E2ETest/ServerRenderingTests/RenderingTest.cs index 1074c38ebebf..a24639700001 100644 --- a/src/Components/test/E2ETest/ServerRenderingTests/RenderingTest.cs +++ b/src/Components/test/E2ETest/ServerRenderingTests/RenderingTest.cs @@ -34,9 +34,9 @@ public void CanRenderLargeComponentsWithServerRenderMode() Navigate($"{ServerPathBase}/large-html-server"); var result = new string('*', 50000); - Assert.Equal(result, Browser.FindElement(By.Id("webassembly-prerender")).Text); - Assert.Equal(result, Browser.FindElement(By.Id("server-prerender")).Text); - Assert.Equal(result, Browser.FindElement(By.Id("server-prerender")).Text); + Browser.Equal(result, () => Browser.FindElement(By.Id("webassembly-prerender")).Text); + Browser.Equal(result, () => Browser.FindElement(By.Id("server-no-prerender")).Text); + Browser.Equal(result, () => Browser.FindElement(By.Id("server-prerender")).Text); } [Fact] From 5d58631e415cd298b01b5b494e348f71c3f40209 Mon Sep 17 00:00:00 2001 From: Steve Sanderson Date: Mon, 4 Mar 2024 16:32:24 +0000 Subject: [PATCH 2/3] Tolerate another way that stale elements can be reported --- .../WebDriverStaleElementAssertion.cs | 42 +++++++++++++++++++ .../EnhancedNavigationTest.cs | 8 ++-- .../FormWithParentBindingContextTest.cs | 3 +- .../ServerRenderingTests/RedirectionTest.cs | 2 +- .../test/E2ETest/Tests/RoutingTest.cs | 8 ++-- 5 files changed, 53 insertions(+), 10 deletions(-) create mode 100644 src/Components/test/E2ETest/Infrastructure/WebDriverExtensions/WebDriverStaleElementAssertion.cs diff --git a/src/Components/test/E2ETest/Infrastructure/WebDriverExtensions/WebDriverStaleElementAssertion.cs b/src/Components/test/E2ETest/Infrastructure/WebDriverExtensions/WebDriverStaleElementAssertion.cs new file mode 100644 index 000000000000..cfe6f0374f34 --- /dev/null +++ b/src/Components/test/E2ETest/Infrastructure/WebDriverExtensions/WebDriverStaleElementAssertion.cs @@ -0,0 +1,42 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using OpenQA.Selenium; + +namespace Microsoft.AspNetCore.Components.E2ETest.Infrastructure; + +internal static class WebDriverStaleElementAssertion +{ + public static void AssertThrowsDueToElementRemovedFromPage(Func callback) + => AssertThrowsDueToElementRemovedFromPage(() => callback()); + + public static void AssertThrowsDueToElementRemovedFromPage(Action callback) + { + var ex = Assert.Throws(callback); + if (!ExceptionMeansElementWasRemoved(ex)) + { + throw ex; + } + } + + public static bool ExceptionMeansElementWasRemoved(Exception ex) + { + if (ex is StaleElementReferenceException) + { + // This is the normal exception that occurs if you accessed something + // that was already removed from the page + return true; + } + else if (ex is WebDriverException) + { + // Sometimes we get this exception instead if the element is stale + // It may depend on timing + if (ex.Message.Contains("Node with given id does not belong to the document", StringComparison.Ordinal)) + { + return true; + } + } + + return false; + } +} diff --git a/src/Components/test/E2ETest/ServerRenderingTests/EnhancedNavigationTest.cs b/src/Components/test/E2ETest/ServerRenderingTests/EnhancedNavigationTest.cs index d8644cdde114..2193a71a8b01 100644 --- a/src/Components/test/E2ETest/ServerRenderingTests/EnhancedNavigationTest.cs +++ b/src/Components/test/E2ETest/ServerRenderingTests/EnhancedNavigationTest.cs @@ -97,7 +97,7 @@ public void EnhancedNavCanBeDisabledHierarchically() // Check we got there, but we did *not* retain the

element Browser.Equal("Other", () => Browser.Exists(By.TagName("h1")).Text); - Assert.Throws(() => originalH1Elem.Text); + WebDriverStaleElementAssertion.AssertThrowsDueToElementRemovedFromPage(() => originalH1Elem.Text); } [Fact] @@ -142,7 +142,7 @@ public void EnhancedNavCanBeDisabledInSVGElementContainingAnchor() // Check we got there, but we did *not* retain the

element Browser.Equal("Other", () => Browser.Exists(By.TagName("h1")).Text); - Assert.Throws(() => originalH1Elem.Text); + WebDriverStaleElementAssertion.AssertThrowsDueToElementRemovedFromPage(() => originalH1Elem.Text); } [Fact] @@ -157,7 +157,7 @@ public void EnhancedNavCanBeDisabledInSVGElementInsideAnchor() // Check we got there, but we did *not* retain the

element Browser.Equal("Other", () => Browser.Exists(By.TagName("h1")).Text); - Assert.Throws(() => originalH1Elem.Text); + WebDriverStaleElementAssertion.AssertThrowsDueToElementRemovedFromPage(() => originalH1Elem.Text); } [Fact] @@ -653,7 +653,7 @@ private static bool IsElementStale(IWebElement element) _ = element.Enabled; return false; } - catch (StaleElementReferenceException) + catch (Exception ex) when (WebDriverStaleElementAssertion.ExceptionMeansElementWasRemoved(ex)) { return true; } diff --git a/src/Components/test/E2ETest/ServerRenderingTests/FormHandlingTests/FormWithParentBindingContextTest.cs b/src/Components/test/E2ETest/ServerRenderingTests/FormHandlingTests/FormWithParentBindingContextTest.cs index 271d6bf686e5..d2002b9e99da 100644 --- a/src/Components/test/E2ETest/ServerRenderingTests/FormHandlingTests/FormWithParentBindingContextTest.cs +++ b/src/Components/test/E2ETest/ServerRenderingTests/FormHandlingTests/FormWithParentBindingContextTest.cs @@ -1592,7 +1592,8 @@ private void DispatchToFormCore(DispatchToForm dispatch) if (!dispatch.FormIsEnhanced) { // Verify the same form element is *not* still in the page - Assert.Throws(() => form.GetAttribute("method")); + WebDriverStaleElementAssertion.AssertThrowsDueToElementRemovedFromPage( + () => form.GetAttribute("method")); } else if (!dispatch.SuppressEnhancedNavigation) { diff --git a/src/Components/test/E2ETest/ServerRenderingTests/RedirectionTest.cs b/src/Components/test/E2ETest/ServerRenderingTests/RedirectionTest.cs index f3b70bc87509..4c9846dd7993 100644 --- a/src/Components/test/E2ETest/ServerRenderingTests/RedirectionTest.cs +++ b/src/Components/test/E2ETest/ServerRenderingTests/RedirectionTest.cs @@ -229,7 +229,7 @@ private void AssertElementRemoved(IWebElement element) { element.GetDomProperty("tagName"); } - catch (StaleElementReferenceException) + catch (Exception ex) when (WebDriverStaleElementAssertion.ExceptionMeansElementWasRemoved(ex)) { return true; } diff --git a/src/Components/test/E2ETest/Tests/RoutingTest.cs b/src/Components/test/E2ETest/Tests/RoutingTest.cs index 6faad58b1801..c409058c2206 100644 --- a/src/Components/test/E2ETest/Tests/RoutingTest.cs +++ b/src/Components/test/E2ETest/Tests/RoutingTest.cs @@ -433,7 +433,7 @@ public void CanNavigateProgrammaticallyWithForceLoad() Browser.True(() => Browser.Url.EndsWith("/Other", StringComparison.Ordinal)); // Because this was a full-page load, our element references should no longer be valid - Assert.Throws(() => + WebDriverStaleElementAssertion.AssertThrowsDueToElementRemovedFromPage(() => { testSelector.SelectedOption.GetAttribute("value"); }); @@ -470,7 +470,7 @@ public void CanNavigateProgrammaticallyWithStateValidateNoReplaceHistoryEntry() Browser.DoesNotExist(By.Id("test-state")); // We check if we had a force load - Assert.Throws(() => + WebDriverStaleElementAssertion.AssertThrowsDueToElementRemovedFromPage(() => testSelector.SelectedOption.GetAttribute("value")); // But still we should be able to navigate back, and end up at the "/ProgrammaticNavigationCases" page @@ -549,7 +549,7 @@ public void CanNavigateProgrammaticallyValidateNoReplaceHistoryEntry() Browser.True(() => Browser.Url.EndsWith("/Other", StringComparison.Ordinal)); // We check if we had a force load - Assert.Throws(() => + WebDriverStaleElementAssertion.AssertThrowsDueToElementRemovedFromPage(() => testSelector.SelectedOption.GetAttribute("value")); // But still we should be able to navigate back, and end up at the "/ProgrammaticNavigationCases" page @@ -602,7 +602,7 @@ public void CanNavigateProgrammaticallyWithForceLoadAndReplaceHistoryEntry() Browser.True(() => Browser.Url.EndsWith("/Other", StringComparison.Ordinal)); // We check if we had a force load - Assert.Throws(() => + WebDriverStaleElementAssertion.AssertThrowsDueToElementRemovedFromPage(() => testSelector.SelectedOption.GetAttribute("value")); // After we press back, we should end up at the "/" page so we know browser history has been replaced From 443f030c4917df7ca7d44699227b13758ff0034e Mon Sep 17 00:00:00 2001 From: Steve Sanderson Date: Tue, 5 Mar 2024 11:38:30 +0000 Subject: [PATCH 3/3] Revert "Tolerate another way that stale elements can be reported" This reverts commit 5d58631e415cd298b01b5b494e348f71c3f40209. --- .../WebDriverStaleElementAssertion.cs | 42 ------------------- .../EnhancedNavigationTest.cs | 8 ++-- .../FormWithParentBindingContextTest.cs | 3 +- .../ServerRenderingTests/RedirectionTest.cs | 2 +- .../test/E2ETest/Tests/RoutingTest.cs | 8 ++-- 5 files changed, 10 insertions(+), 53 deletions(-) delete mode 100644 src/Components/test/E2ETest/Infrastructure/WebDriverExtensions/WebDriverStaleElementAssertion.cs diff --git a/src/Components/test/E2ETest/Infrastructure/WebDriverExtensions/WebDriverStaleElementAssertion.cs b/src/Components/test/E2ETest/Infrastructure/WebDriverExtensions/WebDriverStaleElementAssertion.cs deleted file mode 100644 index cfe6f0374f34..000000000000 --- a/src/Components/test/E2ETest/Infrastructure/WebDriverExtensions/WebDriverStaleElementAssertion.cs +++ /dev/null @@ -1,42 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using OpenQA.Selenium; - -namespace Microsoft.AspNetCore.Components.E2ETest.Infrastructure; - -internal static class WebDriverStaleElementAssertion -{ - public static void AssertThrowsDueToElementRemovedFromPage(Func callback) - => AssertThrowsDueToElementRemovedFromPage(() => callback()); - - public static void AssertThrowsDueToElementRemovedFromPage(Action callback) - { - var ex = Assert.Throws(callback); - if (!ExceptionMeansElementWasRemoved(ex)) - { - throw ex; - } - } - - public static bool ExceptionMeansElementWasRemoved(Exception ex) - { - if (ex is StaleElementReferenceException) - { - // This is the normal exception that occurs if you accessed something - // that was already removed from the page - return true; - } - else if (ex is WebDriverException) - { - // Sometimes we get this exception instead if the element is stale - // It may depend on timing - if (ex.Message.Contains("Node with given id does not belong to the document", StringComparison.Ordinal)) - { - return true; - } - } - - return false; - } -} diff --git a/src/Components/test/E2ETest/ServerRenderingTests/EnhancedNavigationTest.cs b/src/Components/test/E2ETest/ServerRenderingTests/EnhancedNavigationTest.cs index 2193a71a8b01..d8644cdde114 100644 --- a/src/Components/test/E2ETest/ServerRenderingTests/EnhancedNavigationTest.cs +++ b/src/Components/test/E2ETest/ServerRenderingTests/EnhancedNavigationTest.cs @@ -97,7 +97,7 @@ public void EnhancedNavCanBeDisabledHierarchically() // Check we got there, but we did *not* retain the

element Browser.Equal("Other", () => Browser.Exists(By.TagName("h1")).Text); - WebDriverStaleElementAssertion.AssertThrowsDueToElementRemovedFromPage(() => originalH1Elem.Text); + Assert.Throws(() => originalH1Elem.Text); } [Fact] @@ -142,7 +142,7 @@ public void EnhancedNavCanBeDisabledInSVGElementContainingAnchor() // Check we got there, but we did *not* retain the

element Browser.Equal("Other", () => Browser.Exists(By.TagName("h1")).Text); - WebDriverStaleElementAssertion.AssertThrowsDueToElementRemovedFromPage(() => originalH1Elem.Text); + Assert.Throws(() => originalH1Elem.Text); } [Fact] @@ -157,7 +157,7 @@ public void EnhancedNavCanBeDisabledInSVGElementInsideAnchor() // Check we got there, but we did *not* retain the

element Browser.Equal("Other", () => Browser.Exists(By.TagName("h1")).Text); - WebDriverStaleElementAssertion.AssertThrowsDueToElementRemovedFromPage(() => originalH1Elem.Text); + Assert.Throws(() => originalH1Elem.Text); } [Fact] @@ -653,7 +653,7 @@ private static bool IsElementStale(IWebElement element) _ = element.Enabled; return false; } - catch (Exception ex) when (WebDriverStaleElementAssertion.ExceptionMeansElementWasRemoved(ex)) + catch (StaleElementReferenceException) { return true; } diff --git a/src/Components/test/E2ETest/ServerRenderingTests/FormHandlingTests/FormWithParentBindingContextTest.cs b/src/Components/test/E2ETest/ServerRenderingTests/FormHandlingTests/FormWithParentBindingContextTest.cs index d2002b9e99da..271d6bf686e5 100644 --- a/src/Components/test/E2ETest/ServerRenderingTests/FormHandlingTests/FormWithParentBindingContextTest.cs +++ b/src/Components/test/E2ETest/ServerRenderingTests/FormHandlingTests/FormWithParentBindingContextTest.cs @@ -1592,8 +1592,7 @@ private void DispatchToFormCore(DispatchToForm dispatch) if (!dispatch.FormIsEnhanced) { // Verify the same form element is *not* still in the page - WebDriverStaleElementAssertion.AssertThrowsDueToElementRemovedFromPage( - () => form.GetAttribute("method")); + Assert.Throws(() => form.GetAttribute("method")); } else if (!dispatch.SuppressEnhancedNavigation) { diff --git a/src/Components/test/E2ETest/ServerRenderingTests/RedirectionTest.cs b/src/Components/test/E2ETest/ServerRenderingTests/RedirectionTest.cs index 4c9846dd7993..f3b70bc87509 100644 --- a/src/Components/test/E2ETest/ServerRenderingTests/RedirectionTest.cs +++ b/src/Components/test/E2ETest/ServerRenderingTests/RedirectionTest.cs @@ -229,7 +229,7 @@ private void AssertElementRemoved(IWebElement element) { element.GetDomProperty("tagName"); } - catch (Exception ex) when (WebDriverStaleElementAssertion.ExceptionMeansElementWasRemoved(ex)) + catch (StaleElementReferenceException) { return true; } diff --git a/src/Components/test/E2ETest/Tests/RoutingTest.cs b/src/Components/test/E2ETest/Tests/RoutingTest.cs index c409058c2206..6faad58b1801 100644 --- a/src/Components/test/E2ETest/Tests/RoutingTest.cs +++ b/src/Components/test/E2ETest/Tests/RoutingTest.cs @@ -433,7 +433,7 @@ public void CanNavigateProgrammaticallyWithForceLoad() Browser.True(() => Browser.Url.EndsWith("/Other", StringComparison.Ordinal)); // Because this was a full-page load, our element references should no longer be valid - WebDriverStaleElementAssertion.AssertThrowsDueToElementRemovedFromPage(() => + Assert.Throws(() => { testSelector.SelectedOption.GetAttribute("value"); }); @@ -470,7 +470,7 @@ public void CanNavigateProgrammaticallyWithStateValidateNoReplaceHistoryEntry() Browser.DoesNotExist(By.Id("test-state")); // We check if we had a force load - WebDriverStaleElementAssertion.AssertThrowsDueToElementRemovedFromPage(() => + Assert.Throws(() => testSelector.SelectedOption.GetAttribute("value")); // But still we should be able to navigate back, and end up at the "/ProgrammaticNavigationCases" page @@ -549,7 +549,7 @@ public void CanNavigateProgrammaticallyValidateNoReplaceHistoryEntry() Browser.True(() => Browser.Url.EndsWith("/Other", StringComparison.Ordinal)); // We check if we had a force load - WebDriverStaleElementAssertion.AssertThrowsDueToElementRemovedFromPage(() => + Assert.Throws(() => testSelector.SelectedOption.GetAttribute("value")); // But still we should be able to navigate back, and end up at the "/ProgrammaticNavigationCases" page @@ -602,7 +602,7 @@ public void CanNavigateProgrammaticallyWithForceLoadAndReplaceHistoryEntry() Browser.True(() => Browser.Url.EndsWith("/Other", StringComparison.Ordinal)); // We check if we had a force load - WebDriverStaleElementAssertion.AssertThrowsDueToElementRemovedFromPage(() => + Assert.Throws(() => testSelector.SelectedOption.GetAttribute("value")); // After we press back, we should end up at the "/" page so we know browser history has been replaced