+
+ Navigation to another page (testing-scroll)
+
+
+
This is the content.
+}
+
+
bottom spacer
+
+@code {
+
+ bool showContent;
+ string uriOnPageLoad;
+
+ protected override async Task OnInitializedAsync()
+ {
+ uriOnPageLoad = NavigationManager.Uri;
+ await Task.Delay(1000);
+ showContent = true;
+ }
+}
diff --git a/src/Components/test/testassets/Components.TestServer/RazorComponents/Shared/EnhancedNavLayout.razor b/src/Components/test/testassets/Components.TestServer/RazorComponents/Shared/EnhancedNavLayout.razor
index 00f71a068f58..7e9166fabb1e 100644
--- a/src/Components/test/testassets/Components.TestServer/RazorComponents/Shared/EnhancedNavLayout.razor
+++ b/src/Components/test/testassets/Components.TestServer/RazorComponents/Shared/EnhancedNavLayout.razor
@@ -9,8 +9,6 @@
Non-HTML page |
Non-Blazor HTML page |
Scroll to hash |
- Scroll testing-scroll without streaming |
- Scroll testing-scroll with streaming |
Error while streaming |
Interactive component navigation (server) |
Interactive component navigation (webassembly) |
From fc2e05e8e673d192b3b9f01016fc48becdfc6515 Mon Sep 17 00:00:00 2001
From: Ilona Tomkowicz
Date: Mon, 17 Feb 2025 22:14:47 +0100
Subject: [PATCH 07/25] Missing change to the backwards/forwards fix commit.
---
.../Web.JS/src/Services/NavigationEnhancement.ts | 11 +++++------
1 file changed, 5 insertions(+), 6 deletions(-)
diff --git a/src/Components/Web.JS/src/Services/NavigationEnhancement.ts b/src/Components/Web.JS/src/Services/NavigationEnhancement.ts
index d6faf0c457d0..0065ee895931 100644
--- a/src/Components/Web.JS/src/Services/NavigationEnhancement.ts
+++ b/src/Components/Web.JS/src/Services/NavigationEnhancement.ts
@@ -88,8 +88,7 @@ function performProgrammaticEnhancedNavigation(absoluteInternalHref: string, rep
}
}
-function getCurrentScrollPosition()
-{
+function getCurrentScrollPosition() {
const scrollPositionX = window.scrollX;
const scrollPositionY = window.scrollY;
return { X: scrollPositionX, Y: scrollPositionY };
@@ -98,9 +97,9 @@ function getCurrentScrollPosition()
function saveScrollPosition() {
const currentState = history.state || {};
const scrollPosition = getCurrentScrollPosition();
- // save the current scroll position
- const updatedState = { ...currentState, scrollPosition: scrollPosition };
- history.replaceState(updatedState, /* ignored title */ '', location.href);
+ // save the current scroll position
+ const updatedState = { ...currentState, scrollPosition: scrollPosition };
+ history.replaceState(updatedState, /* ignored title */ '', location.href);
}
function onDocumentClick(event: MouseEvent) {
@@ -139,9 +138,9 @@ function onPopState(state: PopStateEvent) {
}
// load the new page
+ const scrollPosition = history.state?.scrollPosition;
saveScrollPosition();
performEnhancedPageLoad(location.href, /* interceptedLink */ false).then(() => {
- const scrollPosition = history.state?.scrollPosition;
if (scrollPosition !== undefined &&
(scrollPosition.X !== window.scrollX || scrollPosition.Y !== window.scrollY)) {
window.scrollTo(scrollPosition.X, scrollPosition.Y);
From 0a6085148fe6941c36a110f51fea0633236a0209 Mon Sep 17 00:00:00 2001
From: Ilona Tomkowicz
Date: Mon, 17 Feb 2025 22:21:15 +0100
Subject: [PATCH 08/25] Fix the test to pass in all cases.
---
.../EnhancedNavigationTest.cs | 22 ++++++++++++++-----
1 file changed, 17 insertions(+), 5 deletions(-)
diff --git a/src/Components/test/E2ETest/ServerRenderingTests/EnhancedNavigationTest.cs b/src/Components/test/E2ETest/ServerRenderingTests/EnhancedNavigationTest.cs
index d2ebcf49d376..9fe9b13c5828 100644
--- a/src/Components/test/E2ETest/ServerRenderingTests/EnhancedNavigationTest.cs
+++ b/src/Components/test/E2ETest/ServerRenderingTests/EnhancedNavigationTest.cs
@@ -664,10 +664,10 @@ public void CanUpdateHrefOnLinkTagWithIntegrity()
}
[Theory]
- [InlineData(false, false)] // PASSES
- [InlineData(false, true)] // PASSES
- [InlineData(true, true)] // line 709 Expected: 1732 Actual: 0
- [InlineData(true, false)] // line 709 Expected: 1732 Actual: 0
+ [InlineData(false, false)]
+ [InlineData(false, true)]
+ [InlineData(true, true)]
+ [InlineData(true, false)]
public async Task EnhancedNavigationScrollBehavesSameAsFullNavigation(bool enableStreaming, bool useEnhancedNavigation)
{
// This test checks if the navigation to other path moves the scroll to the top of the page,
@@ -695,7 +695,7 @@ public async Task EnhancedNavigationScrollBehavesSameAsFullNavigation(bool enabl
if (enableStreaming)
{
- // wait for the fragment to be visible
+ // wait for the fragment to be visible - let the streaming finish
await Task.Delay(TimeSpan.FromSeconds(1));
}
var fragmentScrollPosition = (long)jsExecutor.ExecuteScript("return Math.round(document.getElementById('some-content').getBoundingClientRect().top + window.scrollY);");
@@ -708,6 +708,13 @@ public async Task EnhancedNavigationScrollBehavesSameAsFullNavigation(bool enabl
// parts of page conditioned with showContent are showing with a delay - it affect the scroll position
// from some reason, scroll position differs by 1 pixel between enhanced and browser's navigation
var expectedMaxScrollPositionAfterBackwardsAction = useEnhancedNavigation ? maxScrollPosition: maxScrollPosition - 1;
+ if (enableStreaming)
+ {
+ // let the streaming finish
+ await Task.Delay(TimeSpan.FromSeconds(1));
+ expectedMaxScrollPositionAfterBackwardsAction = maxScrollPosition + 127; // why 127 ???
+ expectedMaxScrollPositionAfterBackwardsAction = useEnhancedNavigation ? expectedMaxScrollPositionAfterBackwardsAction : expectedMaxScrollPositionAfterBackwardsAction - 1;
+ }
Assert.Equal(expectedMaxScrollPositionAfterBackwardsAction, Browser.GetScrollY());
// navigate to a fragment on another page - we should land at the beginning of the fragment
@@ -715,6 +722,11 @@ public async Task EnhancedNavigationScrollBehavesSameAsFullNavigation(bool enabl
AssertWeAreOnHashPage();
AssertEnhancedNavigationOnHashPage();
var expectedFragmentScrollPosition = fragmentScrollPosition - 1;
+ if (enableStreaming)
+ {
+ // let the streaming finish
+ await Task.Delay(TimeSpan.FromSeconds(1));
+ }
Assert.Equal(expectedFragmentScrollPosition, Browser.GetScrollY());
// go back to be able to go forward and check if the scroll position is preserved
From d94b1af1001c06d080a79544de474c12c62a0dda Mon Sep 17 00:00:00 2001
From: Ilona Tomkowicz
Date: Tue, 18 Feb 2025 12:08:34 +0100
Subject: [PATCH 09/25] Make the tests deterministic.
---
.../WebDriverExtensions.cs | 17 ++++++++++
.../EnhancedNavigationTest.cs | 33 +++++++++----------
2 files changed, 32 insertions(+), 18 deletions(-)
diff --git a/src/Components/test/E2ETest/Infrastructure/WebDriverExtensions/WebDriverExtensions.cs b/src/Components/test/E2ETest/Infrastructure/WebDriverExtensions/WebDriverExtensions.cs
index e7b2771f6514..afb206fc95c4 100644
--- a/src/Components/test/E2ETest/Infrastructure/WebDriverExtensions/WebDriverExtensions.cs
+++ b/src/Components/test/E2ETest/Infrastructure/WebDriverExtensions/WebDriverExtensions.cs
@@ -2,6 +2,8 @@
// The .NET Foundation licenses this file to you under the MIT license.
using OpenQA.Selenium;
+using OpenQA.Selenium.Support.UI;
+using System;
namespace Microsoft.AspNetCore.Components.E2ETest;
@@ -14,4 +16,19 @@ public static void Navigate(this IWebDriver browser, Uri baseUri, string relativ
browser.Navigate().GoToUrl("about:blank");
browser.Navigate().GoToUrl(absoluteUrl);
}
+
+ public static void WaitForElementToBeVisible(this IWebDriver browser, By by, int timeoutInSeconds = 5)
+ {
+ var wait = new DefaultWait(browser)
+ {
+ Timeout = TimeSpan.FromSeconds(timeoutInSeconds),
+ PollingInterval = TimeSpan.FromMilliseconds(100)
+ };
+ wait.IgnoreExceptionTypes(typeof(NoSuchElementException));
+ wait.Until(driver =>
+ {
+ var element = driver.FindElement(by);
+ return element.Displayed;
+ });
+ }
}
diff --git a/src/Components/test/E2ETest/ServerRenderingTests/EnhancedNavigationTest.cs b/src/Components/test/E2ETest/ServerRenderingTests/EnhancedNavigationTest.cs
index 9fe9b13c5828..9116ee654f90 100644
--- a/src/Components/test/E2ETest/ServerRenderingTests/EnhancedNavigationTest.cs
+++ b/src/Components/test/E2ETest/ServerRenderingTests/EnhancedNavigationTest.cs
@@ -1,6 +1,7 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
+using Microsoft.AspNetCore.Components.E2ETest;
using Microsoft.AspNetCore.Components.E2ETest.Infrastructure.ServerFixtures;
using Microsoft.AspNetCore.Components.E2ETest.Infrastructure;
using Microsoft.AspNetCore.E2ETesting;
@@ -668,7 +669,7 @@ public void CanUpdateHrefOnLinkTagWithIntegrity()
[InlineData(false, true)]
[InlineData(true, true)]
[InlineData(true, false)]
- public async Task EnhancedNavigationScrollBehavesSameAsFullNavigation(bool enableStreaming, bool useEnhancedNavigation)
+ public void EnhancedNavigationScrollBehavesSameAsFullNavigation(bool enableStreaming, bool useEnhancedNavigation)
{
// This test checks if the navigation to other path moves the scroll to the top of the page,
// or to the beginning of a fragment, regardless of the previous scroll position,
@@ -683,6 +684,7 @@ public async Task EnhancedNavigationScrollBehavesSameAsFullNavigation(bool enabl
var elementForStalenessCheckOnScrollPage = Browser.Exists(By.TagName("html"));
var jsExecutor = (IJavaScriptExecutor)Browser;
+ WaitFullPageLoaded();
var maxScrollPosition = (long)jsExecutor.ExecuteScript("return document.documentElement.scrollHeight - window.innerHeight;");
// scroll maximally down and go to another page - we should land at the top of that page
@@ -693,11 +695,7 @@ public async Task EnhancedNavigationScrollBehavesSameAsFullNavigation(bool enabl
Assert.Equal(0, Browser.GetScrollY());
var elementForStalenessCheckOnHashPage = Browser.Exists(By.TagName("html"));
- if (enableStreaming)
- {
- // wait for the fragment to be visible - let the streaming finish
- await Task.Delay(TimeSpan.FromSeconds(1));
- }
+ WaitFullPageLoaded();
var fragmentScrollPosition = (long)jsExecutor.ExecuteScript("return Math.round(document.getElementById('some-content').getBoundingClientRect().top + window.scrollY);");
// go back and check if the scroll position is preserved
@@ -708,13 +706,7 @@ public async Task EnhancedNavigationScrollBehavesSameAsFullNavigation(bool enabl
// parts of page conditioned with showContent are showing with a delay - it affect the scroll position
// from some reason, scroll position differs by 1 pixel between enhanced and browser's navigation
var expectedMaxScrollPositionAfterBackwardsAction = useEnhancedNavigation ? maxScrollPosition: maxScrollPosition - 1;
- if (enableStreaming)
- {
- // let the streaming finish
- await Task.Delay(TimeSpan.FromSeconds(1));
- expectedMaxScrollPositionAfterBackwardsAction = maxScrollPosition + 127; // why 127 ???
- expectedMaxScrollPositionAfterBackwardsAction = useEnhancedNavigation ? expectedMaxScrollPositionAfterBackwardsAction : expectedMaxScrollPositionAfterBackwardsAction - 1;
- }
+ WaitFullPageLoaded();
Assert.Equal(expectedMaxScrollPositionAfterBackwardsAction, Browser.GetScrollY());
// navigate to a fragment on another page - we should land at the beginning of the fragment
@@ -722,11 +714,7 @@ public async Task EnhancedNavigationScrollBehavesSameAsFullNavigation(bool enabl
AssertWeAreOnHashPage();
AssertEnhancedNavigationOnHashPage();
var expectedFragmentScrollPosition = fragmentScrollPosition - 1;
- if (enableStreaming)
- {
- // let the streaming finish
- await Task.Delay(TimeSpan.FromSeconds(1));
- }
+ WaitFullPageLoaded();
Assert.Equal(expectedFragmentScrollPosition, Browser.GetScrollY());
// go back to be able to go forward and check if the scroll position is preserved
@@ -737,6 +725,7 @@ public async Task EnhancedNavigationScrollBehavesSameAsFullNavigation(bool enabl
Browser.Navigate().Forward();
AssertWeAreOnHashPage();
AssertEnhancedNavigationOnHashPage();
+ WaitFullPageLoaded();
Assert.Equal(expectedFragmentScrollPosition, Browser.GetScrollY());
void AssertEnhancedNavigationOnHashPage() =>
@@ -765,6 +754,14 @@ void AssertWeAreOnHashPage()
{
Browser.Equal("Scroll to hash", () => Browser.Exists(By.Id("test-info")).Text);
}
+
+ void WaitFullPageLoaded()
+ {
+ if (enableStreaming)
+ {
+ Browser.WaitForElementToBeVisible(By.Id("some-content"));
+ }
+ }
}
private void AssertEnhancedUpdateCountEquals(long count)
From bd7858d9b02059cedd308298a5694504dc4f0c27 Mon Sep 17 00:00:00 2001
From: Ilona Tomkowicz
Date: Tue, 18 Feb 2025 12:18:22 +0100
Subject: [PATCH 10/25] Restore enhanced nav asserts after the condition that
full page is loaded.
---
.../ServerRenderingTests/EnhancedNavigationTest.cs | 14 +++++---------
1 file changed, 5 insertions(+), 9 deletions(-)
diff --git a/src/Components/test/E2ETest/ServerRenderingTests/EnhancedNavigationTest.cs b/src/Components/test/E2ETest/ServerRenderingTests/EnhancedNavigationTest.cs
index 9116ee654f90..737f1fd3abe2 100644
--- a/src/Components/test/E2ETest/ServerRenderingTests/EnhancedNavigationTest.cs
+++ b/src/Components/test/E2ETest/ServerRenderingTests/EnhancedNavigationTest.cs
@@ -690,42 +690,43 @@ public void EnhancedNavigationScrollBehavesSameAsFullNavigation(bool enableStrea
// scroll maximally down and go to another page - we should land at the top of that page
Browser.SetScrollY(maxScrollPosition);
Browser.Exists(By.Id("do-navigation")).Click();
+ WaitFullPageLoaded();
AssertEnhancedNavigationOnHashPage();
AssertWeAreOnHashPage();
Assert.Equal(0, Browser.GetScrollY());
var elementForStalenessCheckOnHashPage = Browser.Exists(By.TagName("html"));
- WaitFullPageLoaded();
var fragmentScrollPosition = (long)jsExecutor.ExecuteScript("return Math.round(document.getElementById('some-content').getBoundingClientRect().top + window.scrollY);");
// go back and check if the scroll position is preserved
Browser.Navigate().Back();
AssertWeAreOnScrollTestPage();
+ WaitFullPageLoaded();
AssertEnhancedNavigationOnScrollPage();
// parts of page conditioned with showContent are showing with a delay - it affect the scroll position
// from some reason, scroll position differs by 1 pixel between enhanced and browser's navigation
var expectedMaxScrollPositionAfterBackwardsAction = useEnhancedNavigation ? maxScrollPosition: maxScrollPosition - 1;
- WaitFullPageLoaded();
Assert.Equal(expectedMaxScrollPositionAfterBackwardsAction, Browser.GetScrollY());
// navigate to a fragment on another page - we should land at the beginning of the fragment
Browser.Exists(By.Id("do-navigation-with-fragment")).Click();
AssertWeAreOnHashPage();
+ WaitFullPageLoaded();
AssertEnhancedNavigationOnHashPage();
var expectedFragmentScrollPosition = fragmentScrollPosition - 1;
- WaitFullPageLoaded();
Assert.Equal(expectedFragmentScrollPosition, Browser.GetScrollY());
// go back to be able to go forward and check if the scroll position is preserved
Browser.Navigate().Back();
AssertWeAreOnScrollTestPage();
+ WaitFullPageLoaded();
AssertEnhancedNavigationOnScrollPage();
Browser.Navigate().Forward();
AssertWeAreOnHashPage();
- AssertEnhancedNavigationOnHashPage();
WaitFullPageLoaded();
+ AssertEnhancedNavigationOnHashPage();
Assert.Equal(expectedFragmentScrollPosition, Browser.GetScrollY());
void AssertEnhancedNavigationOnHashPage() =>
@@ -736,11 +737,6 @@ void AssertEnhancedNavigationOnScrollPage()
void AssertEnhancedNavigation(IWebElement elementForStalenessCheck)
{
- // enhanced navigation asserts are not deterministic with streaming
- if (enableStreaming)
- {
- return;
- }
bool enhancedNavigationDetected = !IsElementStale(elementForStalenessCheck);
Assert.Equal(useEnhancedNavigation, enhancedNavigationDetected);
}
From 9a1d687be61c0ab74fadae8bd26b39bd051dbb76 Mon Sep 17 00:00:00 2001
From: Ilona Tomkowicz
Date: Tue, 18 Feb 2025 17:22:13 +0100
Subject: [PATCH 11/25] More tests revealing a problem with forwards/backwards
action.
---
.../EnhancedNavigationTest.cs | 144 +++++++++++-------
.../PageForScrollPositionTests.razor | 2 +-
...ageForScrollPositionTestsNoStreaming.razor | 2 +-
.../PageForScrollingToHashNoStreaming.razor | 2 +-
4 files changed, 94 insertions(+), 56 deletions(-)
diff --git a/src/Components/test/E2ETest/ServerRenderingTests/EnhancedNavigationTest.cs b/src/Components/test/E2ETest/ServerRenderingTests/EnhancedNavigationTest.cs
index 737f1fd3abe2..84ff50e4202b 100644
--- a/src/Components/test/E2ETest/ServerRenderingTests/EnhancedNavigationTest.cs
+++ b/src/Components/test/E2ETest/ServerRenderingTests/EnhancedNavigationTest.cs
@@ -669,94 +669,132 @@ public void CanUpdateHrefOnLinkTagWithIntegrity()
[InlineData(false, true)]
[InlineData(true, true)]
[InlineData(true, false)]
- public void EnhancedNavigationScrollBehavesSameAsFullNavigation(bool enableStreaming, bool useEnhancedNavigation)
+ public void EnhancedNavigationScrollBehavesSameAsBrowserOnNavLinkNavigation(bool enableStreaming, bool useEnhancedNavigation)
{
- // This test checks if the navigation to other path moves the scroll to the top of the page,
- // or to the beginning of a fragment, regardless of the previous scroll position,
- // checks if going backwards and forwards preserves the scroll position
+ // This test checks if the navigation to another path moves the scroll to the top of the page,
+ // or to the beginning of a fragment, regardless of the previous scroll position
string landingPageSuffix = enableStreaming ? "" : "-no-streaming";
Navigate($"{ServerPathBase}/nav/testing-scroll{landingPageSuffix}");
EnhancedNavigationTestUtil.SuppressEnhancedNavigation(this, shouldSuppress: !useEnhancedNavigation, skipNavigation: true);
+ // "scroll" page: scroll maximally down and go to "hash" page - we should land at the top of that page
AssertWeAreOnScrollTestPage();
+ WaitStreamingRendersFullPage(enableStreaming);
- // assert enhanced navigation is enabled/disabled, as requested
- var elementForStalenessCheckOnScrollPage = Browser.Exists(By.TagName("html"));
+ // staleness check is used to assert enhanced navigation is enabled/disabled, as requested
+ var elementForStalenessCheckOnHashPage = Browser.Exists(By.TagName("html"));
var jsExecutor = (IJavaScriptExecutor)Browser;
- WaitFullPageLoaded();
var maxScrollPosition = (long)jsExecutor.ExecuteScript("return document.documentElement.scrollHeight - window.innerHeight;");
-
- // scroll maximally down and go to another page - we should land at the top of that page
Browser.SetScrollY(maxScrollPosition);
Browser.Exists(By.Id("do-navigation")).Click();
- WaitFullPageLoaded();
- AssertEnhancedNavigationOnHashPage();
+
+ // "hash" page: check if we landed at 0, then navigate to "scroll"
+ WaitStreamingRendersFullPage(enableStreaming);
+ AssertEnhancedNavigation(useEnhancedNavigation, elementForStalenessCheckOnHashPage);
AssertWeAreOnHashPage();
Assert.Equal(0, Browser.GetScrollY());
- var elementForStalenessCheckOnHashPage = Browser.Exists(By.TagName("html"));
-
+ var elementForStalenessCheckOnScrollPage = Browser.Exists(By.TagName("html"));
var fragmentScrollPosition = (long)jsExecutor.ExecuteScript("return Math.round(document.getElementById('some-content').getBoundingClientRect().top + window.scrollY);");
+ Browser.Exists(By.Id("do-navigation")).Click();
- // go back and check if the scroll position is preserved
- Browser.Navigate().Back();
+ // "scroll" page: navigate to a fragment on another page - we should land at the beginning of the fragment
AssertWeAreOnScrollTestPage();
- WaitFullPageLoaded();
- AssertEnhancedNavigationOnScrollPage();
+ WaitStreamingRendersFullPage(enableStreaming);
+ AssertEnhancedNavigation(useEnhancedNavigation, elementForStalenessCheckOnScrollPage);
- // parts of page conditioned with showContent are showing with a delay - it affect the scroll position
- // from some reason, scroll position differs by 1 pixel between enhanced and browser's navigation
- var expectedMaxScrollPositionAfterBackwardsAction = useEnhancedNavigation ? maxScrollPosition: maxScrollPosition - 1;
- Assert.Equal(expectedMaxScrollPositionAfterBackwardsAction, Browser.GetScrollY());
-
- // navigate to a fragment on another page - we should land at the beginning of the fragment
Browser.Exists(By.Id("do-navigation-with-fragment")).Click();
AssertWeAreOnHashPage();
- WaitFullPageLoaded();
- AssertEnhancedNavigationOnHashPage();
+ WaitStreamingRendersFullPage(enableStreaming);
+ AssertEnhancedNavigation(useEnhancedNavigation, elementForStalenessCheckOnHashPage);
var expectedFragmentScrollPosition = fragmentScrollPosition - 1;
Assert.Equal(expectedFragmentScrollPosition, Browser.GetScrollY());
+ }
+
+ [Theory]
+ [InlineData(false, false)]
+ [InlineData(false, true)] // ToDo: Forwards -> line 772, Expected: 3270 Actual: 1400
+ [InlineData(true, true)] // ToDo: Forwards -> line 772, Expected: 2400 Actual: 412
+ [InlineData(true, false)] // ToDo: why it requires a special condition?
+ public void EnhancedNavigationScrollBehavesSameAsBrowserOnBackwardsForwardsAction(bool enableStreaming, bool useEnhancedNavigation)
+ {
+ // This test checks if the scroll position is preserved after backwards/forwards action
+ string landingPageSuffix = enableStreaming ? "" : "-no-streaming";
+ Navigate($"{ServerPathBase}/nav/testing-scroll{landingPageSuffix}");
+ EnhancedNavigationTestUtil.SuppressEnhancedNavigation(this, shouldSuppress: !useEnhancedNavigation, skipNavigation: true);
+
+ // "scroll" page: max scroll position on exiting it
+ AssertWeAreOnScrollTestPage();
+ WaitStreamingRendersFullPage(enableStreaming);
+
+ // staleness check is used to assert enhanced navigation is enabled/disabled, as requested
+ var elementForStalenessCheckOnHashPage = Browser.Exists(By.TagName("html"));
- // go back to be able to go forward and check if the scroll position is preserved
+ var jsExecutor = (IJavaScriptExecutor)Browser;
+ var maxScrollPosition = (long)jsExecutor.ExecuteScript("return document.documentElement.scrollHeight - window.innerHeight;");
+ Browser.SetScrollY(maxScrollPosition);
+ Browser.Exists(By.Id("do-navigation")).Click();
+
+ // "hash" page: scroll position at fragment on exiting it
+ WaitStreamingRendersFullPage(enableStreaming);
+ AssertEnhancedNavigation(useEnhancedNavigation, elementForStalenessCheckOnHashPage);
+ AssertWeAreOnHashPage();
+ var elementForStalenessCheckOnScrollPage = Browser.Exists(By.TagName("html"));
+ var fragmentScrollPosition = (long)jsExecutor.ExecuteScript("return Math.round(document.getElementById('some-content').getBoundingClientRect().top + window.scrollY);");
+ Browser.SetScrollY(fragmentScrollPosition);
Browser.Navigate().Back();
+
+ // "scroll" page: check if the scroll position is preserved at the bottom
AssertWeAreOnScrollTestPage();
- WaitFullPageLoaded();
- AssertEnhancedNavigationOnScrollPage();
+ WaitStreamingRendersFullPage(enableStreaming);
+ AssertEnhancedNavigation(useEnhancedNavigation, elementForStalenessCheckOnScrollPage);
+
+ // from some reason, scroll position differs by 1 pixel between enhanced and browser's navigation
+ // browser's navigation is not precisely going backwards/forwards to the previous state
+ var expectedMaxScrollPositionAfterBackwardsAction = useEnhancedNavigation ? maxScrollPosition : maxScrollPosition - 1;
+ Assert.Equal(expectedMaxScrollPositionAfterBackwardsAction, Browser.GetScrollY());
+ // "scroll" page: go forwards to "hash" page, max scroll position on exiting
Browser.Navigate().Forward();
AssertWeAreOnHashPage();
- WaitFullPageLoaded();
- AssertEnhancedNavigationOnHashPage();
+ WaitStreamingRendersFullPage(enableStreaming);
+ AssertEnhancedNavigation(useEnhancedNavigation, elementForStalenessCheckOnHashPage);
+ // WHY is streaming with browser same as non-streaming with enhanced nav but different than non-streaming with browser?
+ var expectedFragmentScrollPosition = (useEnhancedNavigation || enableStreaming) ? fragmentScrollPosition : fragmentScrollPosition - 1;
Assert.Equal(expectedFragmentScrollPosition, Browser.GetScrollY());
- void AssertEnhancedNavigationOnHashPage() =>
- AssertEnhancedNavigation(elementForStalenessCheckOnScrollPage);
-
- void AssertEnhancedNavigationOnScrollPage()
- => AssertEnhancedNavigation(elementForStalenessCheckOnHashPage);
+ // "hash" page: go back to "scroll" page
+ Browser.Navigate().Back();
+ AssertWeAreOnScrollTestPage();
+ WaitStreamingRendersFullPage(enableStreaming);
+ AssertEnhancedNavigation(useEnhancedNavigation, elementForStalenessCheckOnScrollPage);
+ var expectedMaxScrollPositionAfterSecondBackwardsAction = useEnhancedNavigation
+ ? expectedMaxScrollPositionAfterBackwardsAction
+ : expectedMaxScrollPositionAfterBackwardsAction - 1;
+ Assert.Equal(expectedMaxScrollPositionAfterSecondBackwardsAction, Browser.GetScrollY());
+ }
- void AssertEnhancedNavigation(IWebElement elementForStalenessCheck)
- {
- bool enhancedNavigationDetected = !IsElementStale(elementForStalenessCheck);
- Assert.Equal(useEnhancedNavigation, enhancedNavigationDetected);
- }
+ private void AssertEnhancedNavigation(bool useEnhancedNavigation, IWebElement elementForStalenessCheck)
+ {
+ bool enhancedNavigationDetected = !IsElementStale(elementForStalenessCheck);
+ Assert.Equal(useEnhancedNavigation, enhancedNavigationDetected);
+ }
- void AssertWeAreOnScrollTestPage()
- {
- Browser.Equal("Go back to me", () => Browser.Exists(By.Id("test-info")).Text);
- }
+ private void AssertWeAreOnScrollTestPage()
+ {
+ Browser.Equal("Scroll tests landing page", () => Browser.Exists(By.Id("test-info")).Text);
+ }
- void AssertWeAreOnHashPage()
- {
- Browser.Equal("Scroll to hash", () => Browser.Exists(By.Id("test-info")).Text);
- }
+ private void AssertWeAreOnHashPage()
+ {
+ Browser.Equal("Scroll to hash", () => Browser.Exists(By.Id("test-info")).Text);
+ }
- void WaitFullPageLoaded()
+ private void WaitStreamingRendersFullPage(bool enableStreaming)
+ {
+ if (enableStreaming)
{
- if (enableStreaming)
- {
- Browser.WaitForElementToBeVisible(By.Id("some-content"));
- }
+ Browser.WaitForElementToBeVisible(By.Id("some-content"));
}
}
diff --git a/src/Components/test/testassets/Components.TestServer/RazorComponents/Pages/EnhancedNav/PageForScrollPositionTests.razor b/src/Components/test/testassets/Components.TestServer/RazorComponents/Pages/EnhancedNav/PageForScrollPositionTests.razor
index b5a9dc063807..7c263deec9b0 100644
--- a/src/Components/test/testassets/Components.TestServer/RazorComponents/Pages/EnhancedNav/PageForScrollPositionTests.razor
+++ b/src/Components/test/testassets/Components.TestServer/RazorComponents/Pages/EnhancedNav/PageForScrollPositionTests.razor
@@ -4,7 +4,7 @@
Page for testing scroll position
-
Go back to me
+
Scroll tests landing page
If you scroll down a long way, you'll find more content. We add it asynchronously via streaming rendering.
diff --git a/src/Components/test/testassets/Components.TestServer/RazorComponents/Pages/EnhancedNav/PageForScrollPositionTestsNoStreaming.razor b/src/Components/test/testassets/Components.TestServer/RazorComponents/Pages/EnhancedNav/PageForScrollPositionTestsNoStreaming.razor
index 893ba56ca57b..f7b3ca6a5f47 100644
--- a/src/Components/test/testassets/Components.TestServer/RazorComponents/Pages/EnhancedNav/PageForScrollPositionTestsNoStreaming.razor
+++ b/src/Components/test/testassets/Components.TestServer/RazorComponents/Pages/EnhancedNav/PageForScrollPositionTestsNoStreaming.razor
@@ -4,7 +4,7 @@
Page for testing scroll position
-
Go back to me
+
Scroll tests landing page
If you scroll down a long way, you'll find more content.
@if (showContent)
{
From 65cbf50d439000aaf99607621771f64954aac698 Mon Sep 17 00:00:00 2001
From: Ilona Tomkowicz
Date: Wed, 19 Feb 2025 18:18:03 +0100
Subject: [PATCH 12/25] Let the browser handle history produced by
forwards/backwards actions and enhanced nav handle the history produced by
onDocumentClick.
---
.../Web.JS/src/Services/NavigationEnhancement.ts | 13 ++++++++++---
.../EnhancedNav/PageForScrollPositionTests.razor | 7 +++----
.../PageForScrollPositionTestsNoStreaming.razor | 7 +++----
3 files changed, 16 insertions(+), 11 deletions(-)
diff --git a/src/Components/Web.JS/src/Services/NavigationEnhancement.ts b/src/Components/Web.JS/src/Services/NavigationEnhancement.ts
index 0065ee895931..41174ec0324a 100644
--- a/src/Components/Web.JS/src/Services/NavigationEnhancement.ts
+++ b/src/Components/Web.JS/src/Services/NavigationEnhancement.ts
@@ -132,18 +132,25 @@ function onDocumentClick(event: MouseEvent) {
});
}
-function onPopState(state: PopStateEvent) {
+function removeScrollPositionFromState() {
+ const currentState = history.state || {};
+ const { scrollPosition, ...rest } = currentState;
+ history.replaceState(Object.keys(rest).length ? rest : null, /* ignored title */ '', location.href);
+}
+
+function onPopState(event: PopStateEvent) {
if (hasInteractiveRouter()) {
return;
}
// load the new page
- const scrollPosition = history.state?.scrollPosition;
- saveScrollPosition();
performEnhancedPageLoad(location.href, /* interceptedLink */ false).then(() => {
+ const scrollPosition = event.state?.scrollPosition;
if (scrollPosition !== undefined &&
(scrollPosition.X !== window.scrollX || scrollPosition.Y !== window.scrollY)) {
window.scrollTo(scrollPosition.X, scrollPosition.Y);
+ // let the browser handle scroll restoration for the history produced by forwards/backwards actions
+ removeScrollPositionFromState();
}
})
}
diff --git a/src/Components/test/testassets/Components.TestServer/RazorComponents/Pages/EnhancedNav/PageForScrollPositionTests.razor b/src/Components/test/testassets/Components.TestServer/RazorComponents/Pages/EnhancedNav/PageForScrollPositionTests.razor
index 7c263deec9b0..78bd11ab41cf 100644
--- a/src/Components/test/testassets/Components.TestServer/RazorComponents/Pages/EnhancedNav/PageForScrollPositionTests.razor
+++ b/src/Components/test/testassets/Components.TestServer/RazorComponents/Pages/EnhancedNav/PageForScrollPositionTests.razor
@@ -15,6 +15,9 @@
Navigation to another page with fragment (scroll-to-hash#some-content)
+
+ Navigation to another page (scroll-to-hash)
+
}
spacer bottom
@@ -23,10 +26,6 @@
{
Some content
This is the content.
-
-
- Navigation to another page (scroll-to-hash)
-
}
@code {
diff --git a/src/Components/test/testassets/Components.TestServer/RazorComponents/Pages/EnhancedNav/PageForScrollPositionTestsNoStreaming.razor b/src/Components/test/testassets/Components.TestServer/RazorComponents/Pages/EnhancedNav/PageForScrollPositionTestsNoStreaming.razor
index f7b3ca6a5f47..0af84f4de70f 100644
--- a/src/Components/test/testassets/Components.TestServer/RazorComponents/Pages/EnhancedNav/PageForScrollPositionTestsNoStreaming.razor
+++ b/src/Components/test/testassets/Components.TestServer/RazorComponents/Pages/EnhancedNav/PageForScrollPositionTestsNoStreaming.razor
@@ -15,6 +15,9 @@
Navigation to another page with fragment (scroll-to-hash#some-content)
+
+ Navigation to another page (scroll-to-hash)
+
}
spacer bottom
@@ -23,10 +26,6 @@
{
Some content
This is the content.
-
-
- Navigation to another page (scroll-to-hash)
-
}
@code {
From a8eb776fd21559e573fdf91aacde5d933b7897d0 Mon Sep 17 00:00:00 2001
From: Ilona Tomkowicz
Date: Thu, 20 Feb 2025 09:57:42 +0100
Subject: [PATCH 13/25] Missing change to the last commit.
---
.../EnhancedNavigationTest.cs | 71 ++++++++++++-------
1 file changed, 45 insertions(+), 26 deletions(-)
diff --git a/src/Components/test/E2ETest/ServerRenderingTests/EnhancedNavigationTest.cs b/src/Components/test/E2ETest/ServerRenderingTests/EnhancedNavigationTest.cs
index 84ff50e4202b..6b0f2540afb6 100644
--- a/src/Components/test/E2ETest/ServerRenderingTests/EnhancedNavigationTest.cs
+++ b/src/Components/test/E2ETest/ServerRenderingTests/EnhancedNavigationTest.cs
@@ -685,11 +685,11 @@ public void EnhancedNavigationScrollBehavesSameAsBrowserOnNavLinkNavigation(bool
var elementForStalenessCheckOnHashPage = Browser.Exists(By.TagName("html"));
var jsExecutor = (IJavaScriptExecutor)Browser;
- var maxScrollPosition = (long)jsExecutor.ExecuteScript("return document.documentElement.scrollHeight - window.innerHeight;");
- Browser.SetScrollY(maxScrollPosition);
+ var button1Pos = (long)jsExecutor.ExecuteScript("return Math.round(document.getElementById('do-navigation').getBoundingClientRect().top + window.scrollY);");
+ Browser.SetScrollY(button1Pos);
Browser.Exists(By.Id("do-navigation")).Click();
- // "hash" page: check if we landed at 0, then navigate to "scroll"
+ // "hash" page: check if we landed at 0, then navigate to "scroll"
WaitStreamingRendersFullPage(enableStreaming);
AssertEnhancedNavigation(useEnhancedNavigation, elementForStalenessCheckOnHashPage);
AssertWeAreOnHashPage();
@@ -713,9 +713,9 @@ public void EnhancedNavigationScrollBehavesSameAsBrowserOnNavLinkNavigation(bool
[Theory]
[InlineData(false, false)]
- [InlineData(false, true)] // ToDo: Forwards -> line 772, Expected: 3270 Actual: 1400
- [InlineData(true, true)] // ToDo: Forwards -> line 772, Expected: 2400 Actual: 412
- [InlineData(true, false)] // ToDo: why it requires a special condition?
+ [InlineData(false, true)]
+ [InlineData(true, true)]
+ [InlineData(true, false)]
public void EnhancedNavigationScrollBehavesSameAsBrowserOnBackwardsForwardsAction(bool enableStreaming, bool useEnhancedNavigation)
{
// This test checks if the scroll position is preserved after backwards/forwards action
@@ -723,7 +723,7 @@ public void EnhancedNavigationScrollBehavesSameAsBrowserOnBackwardsForwardsActio
Navigate($"{ServerPathBase}/nav/testing-scroll{landingPageSuffix}");
EnhancedNavigationTestUtil.SuppressEnhancedNavigation(this, shouldSuppress: !useEnhancedNavigation, skipNavigation: true);
- // "scroll" page: max scroll position on exiting it
+ // "scroll" page: scroll to pos1, navigate away
AssertWeAreOnScrollTestPage();
WaitStreamingRendersFullPage(enableStreaming);
@@ -731,47 +731,66 @@ public void EnhancedNavigationScrollBehavesSameAsBrowserOnBackwardsForwardsActio
var elementForStalenessCheckOnHashPage = Browser.Exists(By.TagName("html"));
var jsExecutor = (IJavaScriptExecutor)Browser;
- var maxScrollPosition = (long)jsExecutor.ExecuteScript("return document.documentElement.scrollHeight - window.innerHeight;");
- Browser.SetScrollY(maxScrollPosition);
+ var scrollPagePos1 = (long)jsExecutor.ExecuteScript("return Math.round(document.getElementById('do-navigation').getBoundingClientRect().top + window.scrollY);") - 100;
+ Browser.SetScrollY(scrollPagePos1);
Browser.Exists(By.Id("do-navigation")).Click();
- // "hash" page: scroll position at fragment on exiting it
+ // "hash" page: scroll to pos1, navigate away
WaitStreamingRendersFullPage(enableStreaming);
AssertEnhancedNavigation(useEnhancedNavigation, elementForStalenessCheckOnHashPage);
AssertWeAreOnHashPage();
var elementForStalenessCheckOnScrollPage = Browser.Exists(By.TagName("html"));
- var fragmentScrollPosition = (long)jsExecutor.ExecuteScript("return Math.round(document.getElementById('some-content').getBoundingClientRect().top + window.scrollY);");
- Browser.SetScrollY(fragmentScrollPosition);
- Browser.Navigate().Back();
+ var hashPagePos1 = (long)jsExecutor.ExecuteScript("return Math.round(document.getElementById('do-navigation').getBoundingClientRect().top + window.scrollY);") - 100;
+ // make sure we are expecting different scroll positions on thr 1st and the 2nd page
+ Assert.NotEqual(scrollPagePos1, hashPagePos1);
+ Browser.SetScrollY(hashPagePos1);
+ Browser.Exists(By.Id("do-navigation")).Click();
- // "scroll" page: check if the scroll position is preserved at the bottom
+ // "scroll" page: scroll to pos2, go backwards
AssertWeAreOnScrollTestPage();
WaitStreamingRendersFullPage(enableStreaming);
AssertEnhancedNavigation(useEnhancedNavigation, elementForStalenessCheckOnScrollPage);
+ var scrollPagePos2 = 500;
+ Browser.SetScrollY(scrollPagePos2);
+ Browser.Navigate().Back();
+ // "hash" page: check if we landed on pos1, move the scroll to pos2, go backwards
+ AssertWeAreOnHashPage();
+ WaitStreamingRendersFullPage(enableStreaming);
+ AssertEnhancedNavigation(useEnhancedNavigation, elementForStalenessCheckOnHashPage);
// from some reason, scroll position differs by 1 pixel between enhanced and browser's navigation
// browser's navigation is not precisely going backwards/forwards to the previous state
- var expectedMaxScrollPositionAfterBackwardsAction = useEnhancedNavigation ? maxScrollPosition : maxScrollPosition - 1;
- Assert.Equal(expectedMaxScrollPositionAfterBackwardsAction, Browser.GetScrollY());
+ var expectedHashPagePos1 = useEnhancedNavigation ? hashPagePos1 : hashPagePos1 - 1;
+ Assert.Equal(expectedHashPagePos1, Browser.GetScrollY());
+ var hashPagePos2 = 600;
+ Browser.SetScrollY(hashPagePos2);
+ Browser.Navigate().Back();
- // "scroll" page: go forwards to "hash" page, max scroll position on exiting
+ // "scroll" page: check if we landed on pos1, move the scroll to pos3, go forwards
+ AssertWeAreOnScrollTestPage();
+ WaitStreamingRendersFullPage(enableStreaming);
+ AssertEnhancedNavigation(useEnhancedNavigation, elementForStalenessCheckOnScrollPage);
+ var expectedScrollPagePos1 = useEnhancedNavigation ? scrollPagePos1 : scrollPagePos1 - 1;
+ Assert.Equal(expectedScrollPagePos1, Browser.GetScrollY());
+ var scrollPagePos3 = 700;
+ Browser.SetScrollY(scrollPagePos3);
Browser.Navigate().Forward();
+
+ // "hash" page: check if we landed on pos1, go forwards
AssertWeAreOnHashPage();
WaitStreamingRendersFullPage(enableStreaming);
AssertEnhancedNavigation(useEnhancedNavigation, elementForStalenessCheckOnHashPage);
- // WHY is streaming with browser same as non-streaming with enhanced nav but different than non-streaming with browser?
- var expectedFragmentScrollPosition = (useEnhancedNavigation || enableStreaming) ? fragmentScrollPosition : fragmentScrollPosition - 1;
- Assert.Equal(expectedFragmentScrollPosition, Browser.GetScrollY());
+ var expectedHashPagePos2 = useEnhancedNavigation ? hashPagePos2 : hashPagePos2 - 1;
+ Assert.Equal(expectedHashPagePos2, Browser.GetScrollY());
+ Browser.Navigate().Forward();
- // "hash" page: go back to "scroll" page
- Browser.Navigate().Back();
+ // "scroll" page: check if we landed on pos2
AssertWeAreOnScrollTestPage();
WaitStreamingRendersFullPage(enableStreaming);
AssertEnhancedNavigation(useEnhancedNavigation, elementForStalenessCheckOnScrollPage);
- var expectedMaxScrollPositionAfterSecondBackwardsAction = useEnhancedNavigation
- ? expectedMaxScrollPositionAfterBackwardsAction
- : expectedMaxScrollPositionAfterBackwardsAction - 1;
- Assert.Equal(expectedMaxScrollPositionAfterSecondBackwardsAction, Browser.GetScrollY());
+ var expectedScrollPagePos2 = useEnhancedNavigation ? scrollPagePos2 : scrollPagePos2 - 1;
+ Assert.Equal(expectedScrollPagePos2, Browser.GetScrollY());
+
}
private void AssertEnhancedNavigation(bool useEnhancedNavigation, IWebElement elementForStalenessCheck)
From 47f06f5d8c06cc236994aef14302f7078ca7351f Mon Sep 17 00:00:00 2001
From: Ilona Tomkowicz
Date: Thu, 20 Feb 2025 15:51:00 +0100
Subject: [PATCH 14/25] Add programmatic navigation test cases.
---
.../WebDriverExtensions.cs | 14 ++-
.../EnhancedNavigationTest.cs | 92 ++++++++++++-------
.../PageForScrollPositionTests.razor | 15 ++-
...ageForScrollPositionTestsNoStreaming.razor | 42 ++++-----
.../EnhancedNav/PageForScrollingToHash.razor | 9 +-
.../PageForScrollingToHashNoStreaming.razor | 27 +++---
6 files changed, 120 insertions(+), 79 deletions(-)
diff --git a/src/Components/test/E2ETest/Infrastructure/WebDriverExtensions/WebDriverExtensions.cs b/src/Components/test/E2ETest/Infrastructure/WebDriverExtensions/WebDriverExtensions.cs
index afb206fc95c4..a4582034e902 100644
--- a/src/Components/test/E2ETest/Infrastructure/WebDriverExtensions/WebDriverExtensions.cs
+++ b/src/Components/test/E2ETest/Infrastructure/WebDriverExtensions/WebDriverExtensions.cs
@@ -24,11 +24,19 @@ public static void WaitForElementToBeVisible(this IWebDriver browser, By by, int
Timeout = TimeSpan.FromSeconds(timeoutInSeconds),
PollingInterval = TimeSpan.FromMilliseconds(100)
};
- wait.IgnoreExceptionTypes(typeof(NoSuchElementException));
+ wait.IgnoreExceptionTypes(typeof(NoSuchElementException), typeof(StaleElementReferenceException));
wait.Until(driver =>
{
- var element = driver.FindElement(by);
- return element.Displayed;
+ try
+ {
+ var element = driver.FindElement(by);
+ return element.Displayed;
+ }
+ catch (StaleElementReferenceException)
+ {
+ // Retry finding the element
+ return false;
+ }
});
}
}
diff --git a/src/Components/test/E2ETest/ServerRenderingTests/EnhancedNavigationTest.cs b/src/Components/test/E2ETest/ServerRenderingTests/EnhancedNavigationTest.cs
index 6b0f2540afb6..253ca3df497d 100644
--- a/src/Components/test/E2ETest/ServerRenderingTests/EnhancedNavigationTest.cs
+++ b/src/Components/test/E2ETest/ServerRenderingTests/EnhancedNavigationTest.cs
@@ -665,45 +665,53 @@ public void CanUpdateHrefOnLinkTagWithIntegrity()
}
[Theory]
- [InlineData(false, false)]
- [InlineData(false, true)]
- [InlineData(true, true)]
- [InlineData(true, false)]
- public void EnhancedNavigationScrollBehavesSameAsBrowserOnNavLinkNavigation(bool enableStreaming, bool useEnhancedNavigation)
+ [InlineData(false, false, false)]
+ [InlineData(false, true, false)]
+ [InlineData(true, true, false)]
+ [InlineData(true, false, false)]
+ [InlineData(false, false, true)]
+ [InlineData(false, true, true)]
+ [InlineData(true, true, true)]
+ [InlineData(true, false, true)]
+ public void EnhancedNavigationScrollBehavesSameAsBrowserOnNavigation(bool enableStreaming, bool useEnhancedNavigation, bool programmaticNavigation)
{
// This test checks if the navigation to another path moves the scroll to the top of the page,
// or to the beginning of a fragment, regardless of the previous scroll position
string landingPageSuffix = enableStreaming ? "" : "-no-streaming";
+ string buttonKeyword = programmaticNavigation ? "-programmatic" : "";
Navigate($"{ServerPathBase}/nav/testing-scroll{landingPageSuffix}");
EnhancedNavigationTestUtil.SuppressEnhancedNavigation(this, shouldSuppress: !useEnhancedNavigation, skipNavigation: true);
// "scroll" page: scroll maximally down and go to "hash" page - we should land at the top of that page
AssertWeAreOnScrollTestPage();
- WaitStreamingRendersFullPage(enableStreaming);
// staleness check is used to assert enhanced navigation is enabled/disabled, as requested
var elementForStalenessCheckOnHashPage = Browser.Exists(By.TagName("html"));
var jsExecutor = (IJavaScriptExecutor)Browser;
- var button1Pos = (long)jsExecutor.ExecuteScript("return Math.round(document.getElementById('do-navigation').getBoundingClientRect().top + window.scrollY);");
+ var button1Id = $"do{buttonKeyword}-navigation";
+ Browser.WaitForElementToBeVisible(By.Id(button1Id));
+ var button1Pos = (long)jsExecutor.ExecuteScript($"return Math.round(document.getElementById('{button1Id}').getBoundingClientRect().top + window.scrollY);");
Browser.SetScrollY(button1Pos);
- Browser.Exists(By.Id("do-navigation")).Click();
+ Browser.Exists(By.Id(button1Id)).Click();
// "hash" page: check if we landed at 0, then navigate to "scroll"
+ AssertWeAreOnHashPage();
WaitStreamingRendersFullPage(enableStreaming);
AssertEnhancedNavigation(useEnhancedNavigation, elementForStalenessCheckOnHashPage);
- AssertWeAreOnHashPage();
Assert.Equal(0, Browser.GetScrollY());
var elementForStalenessCheckOnScrollPage = Browser.Exists(By.TagName("html"));
+ Browser.WaitForElementToBeVisible(By.Id("some-content"));
var fragmentScrollPosition = (long)jsExecutor.ExecuteScript("return Math.round(document.getElementById('some-content').getBoundingClientRect().top + window.scrollY);");
- Browser.Exists(By.Id("do-navigation")).Click();
+ Browser.Exists(By.Id(button1Id)).Click();
// "scroll" page: navigate to a fragment on another page - we should land at the beginning of the fragment
AssertWeAreOnScrollTestPage();
WaitStreamingRendersFullPage(enableStreaming);
AssertEnhancedNavigation(useEnhancedNavigation, elementForStalenessCheckOnScrollPage);
- Browser.Exists(By.Id("do-navigation-with-fragment")).Click();
+ var button2Id = $"do{buttonKeyword}-navigation-with-fragment";
+ Browser.Exists(By.Id(button2Id)).Click();
AssertWeAreOnHashPage();
WaitStreamingRendersFullPage(enableStreaming);
AssertEnhancedNavigation(useEnhancedNavigation, elementForStalenessCheckOnHashPage);
@@ -712,14 +720,19 @@ public void EnhancedNavigationScrollBehavesSameAsBrowserOnNavLinkNavigation(bool
}
[Theory]
- [InlineData(false, false)]
- [InlineData(false, true)]
- [InlineData(true, true)]
- [InlineData(true, false)]
- public void EnhancedNavigationScrollBehavesSameAsBrowserOnBackwardsForwardsAction(bool enableStreaming, bool useEnhancedNavigation)
+ [InlineData(false, false, false)]
+ [InlineData(false, true, false)]
+ [InlineData(true, true, false)]
+ [InlineData(true, false, false)]
+ [InlineData(false, false, true)]
+ [InlineData(false, true, true)]
+ [InlineData(true, true, true)]
+ [InlineData(true, false, true)]
+ public void EnhancedNavigationScrollBehavesSameAsBrowserOnBackwardsForwardsAction(bool enableStreaming, bool useEnhancedNavigation, bool programmaticNavigation)
{
// This test checks if the scroll position is preserved after backwards/forwards action
string landingPageSuffix = enableStreaming ? "" : "-no-streaming";
+ string buttonKeyword = programmaticNavigation ? "-programmatic" : "";
Navigate($"{ServerPathBase}/nav/testing-scroll{landingPageSuffix}");
EnhancedNavigationTestUtil.SuppressEnhancedNavigation(this, shouldSuppress: !useEnhancedNavigation, skipNavigation: true);
@@ -731,20 +744,21 @@ public void EnhancedNavigationScrollBehavesSameAsBrowserOnBackwardsForwardsActio
var elementForStalenessCheckOnHashPage = Browser.Exists(By.TagName("html"));
var jsExecutor = (IJavaScriptExecutor)Browser;
- var scrollPagePos1 = (long)jsExecutor.ExecuteScript("return Math.round(document.getElementById('do-navigation').getBoundingClientRect().top + window.scrollY);") - 100;
+ var buttonId = $"do{buttonKeyword}-navigation";
+ var scrollPagePos1 = (long)jsExecutor.ExecuteScript($"return Math.round(document.getElementById('{buttonId}').getBoundingClientRect().top + window.scrollY);") - 100;
Browser.SetScrollY(scrollPagePos1);
- Browser.Exists(By.Id("do-navigation")).Click();
+ Browser.Exists(By.Id(buttonId)).Click();
// "hash" page: scroll to pos1, navigate away
+ AssertWeAreOnHashPage();
WaitStreamingRendersFullPage(enableStreaming);
AssertEnhancedNavigation(useEnhancedNavigation, elementForStalenessCheckOnHashPage);
- AssertWeAreOnHashPage();
var elementForStalenessCheckOnScrollPage = Browser.Exists(By.TagName("html"));
- var hashPagePos1 = (long)jsExecutor.ExecuteScript("return Math.round(document.getElementById('do-navigation').getBoundingClientRect().top + window.scrollY);") - 100;
+ var hashPagePos1 = (long)jsExecutor.ExecuteScript($"return Math.round(document.getElementById('{buttonId}').getBoundingClientRect().top + window.scrollY);") - 100;
// make sure we are expecting different scroll positions on thr 1st and the 2nd page
Assert.NotEqual(scrollPagePos1, hashPagePos1);
Browser.SetScrollY(hashPagePos1);
- Browser.Exists(By.Id("do-navigation")).Click();
+ Browser.Exists(By.Id(buttonId)).Click();
// "scroll" page: scroll to pos2, go backwards
AssertWeAreOnScrollTestPage();
@@ -758,10 +772,8 @@ public void EnhancedNavigationScrollBehavesSameAsBrowserOnBackwardsForwardsActio
AssertWeAreOnHashPage();
WaitStreamingRendersFullPage(enableStreaming);
AssertEnhancedNavigation(useEnhancedNavigation, elementForStalenessCheckOnHashPage);
- // from some reason, scroll position differs by 1 pixel between enhanced and browser's navigation
- // browser's navigation is not precisely going backwards/forwards to the previous state
- var expectedHashPagePos1 = useEnhancedNavigation ? hashPagePos1 : hashPagePos1 - 1;
- Assert.Equal(expectedHashPagePos1, Browser.GetScrollY());
+ AssertScrollPositionCorrect(useEnhancedNavigation, hashPagePos1);
+
var hashPagePos2 = 600;
Browser.SetScrollY(hashPagePos2);
Browser.Navigate().Back();
@@ -770,8 +782,7 @@ public void EnhancedNavigationScrollBehavesSameAsBrowserOnBackwardsForwardsActio
AssertWeAreOnScrollTestPage();
WaitStreamingRendersFullPage(enableStreaming);
AssertEnhancedNavigation(useEnhancedNavigation, elementForStalenessCheckOnScrollPage);
- var expectedScrollPagePos1 = useEnhancedNavigation ? scrollPagePos1 : scrollPagePos1 - 1;
- Assert.Equal(expectedScrollPagePos1, Browser.GetScrollY());
+ AssertScrollPositionCorrect(useEnhancedNavigation, scrollPagePos1);
var scrollPagePos3 = 700;
Browser.SetScrollY(scrollPagePos3);
Browser.Navigate().Forward();
@@ -780,17 +791,28 @@ public void EnhancedNavigationScrollBehavesSameAsBrowserOnBackwardsForwardsActio
AssertWeAreOnHashPage();
WaitStreamingRendersFullPage(enableStreaming);
AssertEnhancedNavigation(useEnhancedNavigation, elementForStalenessCheckOnHashPage);
- var expectedHashPagePos2 = useEnhancedNavigation ? hashPagePos2 : hashPagePos2 - 1;
- Assert.Equal(expectedHashPagePos2, Browser.GetScrollY());
+ AssertScrollPositionCorrect(useEnhancedNavigation, hashPagePos2);
Browser.Navigate().Forward();
// "scroll" page: check if we landed on pos2
AssertWeAreOnScrollTestPage();
WaitStreamingRendersFullPage(enableStreaming);
AssertEnhancedNavigation(useEnhancedNavigation, elementForStalenessCheckOnScrollPage);
- var expectedScrollPagePos2 = useEnhancedNavigation ? scrollPagePos2 : scrollPagePos2 - 1;
- Assert.Equal(expectedScrollPagePos2, Browser.GetScrollY());
+ AssertScrollPositionCorrect(useEnhancedNavigation, scrollPagePos2);
+ }
+ private void AssertScrollPositionCorrect(bool useEnhancedNavigation, long previousScrollPosition)
+ {
+ // from some reason, scroll position sometimes differs by 1 pixel between enhanced and browser's navigation
+ // browser's navigation is not precisely going backwards/forwards to the previous state
+ var currentScrollPosition = Browser.GetScrollY();
+ string messagePart = useEnhancedNavigation ? $"{previousScrollPosition}" : $"{previousScrollPosition} or {previousScrollPosition - 1}";
+ bool isPreciselyWhereItWasLeft = currentScrollPosition == previousScrollPosition;
+ bool isPixelLowerThanItWasLeft = currentScrollPosition == (previousScrollPosition - 1);
+ bool success = useEnhancedNavigation
+ ? isPreciselyWhereItWasLeft
+ : (isPreciselyWhereItWasLeft || isPixelLowerThanItWasLeft);
+ Assert.True(success, $"The expected scroll position was {messagePart}, but it was found at {currentScrollPosition}.");
}
private void AssertEnhancedNavigation(bool useEnhancedNavigation, IWebElement elementForStalenessCheck)
@@ -801,12 +823,16 @@ private void AssertEnhancedNavigation(bool useEnhancedNavigation, IWebElement el
private void AssertWeAreOnScrollTestPage()
{
- Browser.Equal("Scroll tests landing page", () => Browser.Exists(By.Id("test-info")).Text);
+ string infoName = "test-info-scroll";
+ Browser.WaitForElementToBeVisible(By.Id(infoName), timeoutInSeconds: 20);
+ Browser.Equal("Scroll tests landing page", () => Browser.Exists(By.Id(infoName)).Text);
}
private void AssertWeAreOnHashPage()
{
- Browser.Equal("Scroll to hash", () => Browser.Exists(By.Id("test-info")).Text);
+ string infoName = "test-info-hash";
+ Browser.WaitForElementToBeVisible(By.Id(infoName), timeoutInSeconds: 20);
+ Browser.Equal("Scroll to hash", () => Browser.Exists(By.Id(infoName)).Text);
}
private void WaitStreamingRendersFullPage(bool enableStreaming)
diff --git a/src/Components/test/testassets/Components.TestServer/RazorComponents/Pages/EnhancedNav/PageForScrollPositionTests.razor b/src/Components/test/testassets/Components.TestServer/RazorComponents/Pages/EnhancedNav/PageForScrollPositionTests.razor
index 78bd11ab41cf..e6cac6e8cb19 100644
--- a/src/Components/test/testassets/Components.TestServer/RazorComponents/Pages/EnhancedNav/PageForScrollPositionTests.razor
+++ b/src/Components/test/testassets/Components.TestServer/RazorComponents/Pages/EnhancedNav/PageForScrollPositionTests.razor
@@ -1,10 +1,11 @@
@page "/nav/testing-scroll"
@inject NavigationManager NavigationManager
@attribute [StreamRendering]
+@rendermode RenderMode.InteractiveServer
Page for testing scroll position
-
Scroll tests landing page
+
Scroll tests landing page
If you scroll down a long way, you'll find more content. We add it asynchronously via streaming rendering.
@@ -12,12 +13,18 @@
@if (showContent)
{
-
+
Navigation to another page with fragment (scroll-to-hash#some-content)
-
+
Navigation to another page (scroll-to-hash)
+
+
}
spacer bottom
@@ -31,6 +38,8 @@
@code {
bool showContent;
string uriOnPageLoad;
+ string hashPagePath = "nav/scroll-to-hash";
+ string hashPageFragmentPath = "nav/scroll-to-hash#some-content";
protected override async Task OnInitializedAsync()
{
diff --git a/src/Components/test/testassets/Components.TestServer/RazorComponents/Pages/EnhancedNav/PageForScrollPositionTestsNoStreaming.razor b/src/Components/test/testassets/Components.TestServer/RazorComponents/Pages/EnhancedNav/PageForScrollPositionTestsNoStreaming.razor
index 0af84f4de70f..ba8eedf020f6 100644
--- a/src/Components/test/testassets/Components.TestServer/RazorComponents/Pages/EnhancedNav/PageForScrollPositionTestsNoStreaming.razor
+++ b/src/Components/test/testassets/Components.TestServer/RazorComponents/Pages/EnhancedNav/PageForScrollPositionTestsNoStreaming.razor
@@ -1,41 +1,35 @@
@page "/nav/testing-scroll-no-streaming"
@inject NavigationManager NavigationManager
+@rendermode RenderMode.InteractiveServer
@* This is a copy of PageForScrollPositionTests, without StreamRendering *@
Page for testing scroll position
-
Scroll tests landing page
+
Scroll tests landing page
If you scroll down a long way, you'll find more content.
spacer top
-@if (showContent)
-{
-
- Navigation to another page with fragment (scroll-to-hash#some-content)
-
-
- Navigation to another page (scroll-to-hash)
-
-}
+
+ Navigation to another page with fragment (scroll-to-hash#some-content)
+
+
+ Navigation to another page (scroll-to-hash)
+
+
+
If you scroll down a long way, you'll find more content. We add it asynchronously via streaming rendering.
@@ -14,16 +14,16 @@
@if (showContent)
{
- Navigation to another page with fragment (scroll-to-hash#some-content)
+ Navigation to another page with fragment
- Navigation to another page (scroll-to-hash)
+ Navigation to another page
}
@@ -38,8 +38,8 @@
@code {
bool showContent;
string uriOnPageLoad;
- string hashPagePath = "nav/scroll-to-hash";
- string hashPageFragmentPath = "nav/scroll-to-hash#some-content";
+ string hashPagePath = "nav/scroll-test-next";
+ string hashPageFragmentPath = "nav/scroll-test-next#some-content";
protected override async Task OnInitializedAsync()
{
diff --git a/src/Components/test/testassets/Components.TestServer/RazorComponents/Pages/EnhancedNav/PageForScrollPositionTestsNoStreaming.razor b/src/Components/test/testassets/Components.TestServer/RazorComponents/Pages/EnhancedNav/ScrollTestLandingPageNoStreaming.razor
similarity index 51%
rename from src/Components/test/testassets/Components.TestServer/RazorComponents/Pages/EnhancedNav/PageForScrollPositionTestsNoStreaming.razor
rename to src/Components/test/testassets/Components.TestServer/RazorComponents/Pages/EnhancedNav/ScrollTestLandingPageNoStreaming.razor
index ba8eedf020f6..160dd0db39a7 100644
--- a/src/Components/test/testassets/Components.TestServer/RazorComponents/Pages/EnhancedNav/PageForScrollPositionTestsNoStreaming.razor
+++ b/src/Components/test/testassets/Components.TestServer/RazorComponents/Pages/EnhancedNav/ScrollTestLandingPageNoStreaming.razor
@@ -1,35 +1,32 @@
-@page "/nav/testing-scroll-no-streaming"
+@page "/nav/scroll-test-no-streaming"
@inject NavigationManager NavigationManager
@rendermode RenderMode.InteractiveServer
-@* This is a copy of PageForScrollPositionTests, without StreamRendering *@
+@* This is a copy of ScrollTestLandingPage, without StreamRendering *@
Page for testing scroll position
-
Scroll tests landing page
-
-
If you scroll down a long way, you'll find more content.
+
Scroll tests landing page
spacer top
- Navigation to another page with fragment (scroll-to-hash#some-content)
+ Navigation to another page with fragment
- Navigation to another page (scroll-to-hash)
+ Navigation to another page