Skip to content

Improve enhanced navigation suppression in tests #63132

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 11 commits into
base: main
Choose a base branch
from
Draft
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ public EnhancedNavigationTest(
// One of the tests here makes use of the streaming rendering page, which uses global state
// so we can't run at the same time as other such tests
public override Task InitializeAsync()
=> InitializeAsync(BrowserFixture.StreamingContext);
=> InitializeAsync(BrowserFixture.StreamingContext, supportEnhancedNavigationSuppression: true);

[Fact]
public void CanNavigateToAnotherPageWhilePreservingCommonDOMElements()
Expand Down Expand Up @@ -677,11 +677,10 @@ public void CanUpdateHrefOnLinkTagWithIntegrity()
}

[Theory]
[QuarantinedTest("https://github.com/dotnet/aspnetcore/issues/60875")]
// [InlineData(false, false, false)] // https://github.com/dotnet/aspnetcore/issues/60875
[InlineData(false, false, false)]
[InlineData(false, true, false)]
[InlineData(true, true, false)]
// [InlineData(true, false, false)] // https://github.com/dotnet/aspnetcore/issues/60875
[InlineData(true, false, false)]
// [InlineData(false, false, true)] programmatic navigation doesn't work without enhanced navigation
[InlineData(false, true, true)]
[InlineData(true, true, true)]
Expand All @@ -692,8 +691,8 @@ public void EnhancedNavigationScrollBehavesSameAsBrowserOnNavigation(bool enable
// 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/scroll-test{landingPageSuffix}");
EnhancedNavigationTestUtil.SuppressEnhancedNavigation(this, shouldSuppress: !useEnhancedNavigation, skipNavigation: true);
Navigate($"{ServerPathBase}/nav/scroll-test{landingPageSuffix}");

// "landing" page: scroll maximally down and go to "next" page - we should land at the top of that page
AssertWeAreOnLandingPage();
Expand Down Expand Up @@ -732,10 +731,10 @@ public void EnhancedNavigationScrollBehavesSameAsBrowserOnNavigation(bool enable
}

[Theory]
// [InlineData(false, false, false)] // https://github.com/dotnet/aspnetcore/issues/60875
[InlineData(false, false, false)]
[InlineData(false, true, false)]
[InlineData(true, true, false)]
// [InlineData(true, false, false)] // https://github.com/dotnet/aspnetcore/issues/60875
[InlineData(true, false, false)]
// [InlineData(false, false, true)] programmatic navigation doesn't work without enhanced navigation
[InlineData(false, true, true)]
[InlineData(true, true, true)]
Expand All @@ -745,8 +744,8 @@ public void EnhancedNavigationScrollBehavesSameAsBrowserOnBackwardsForwardsActio
// 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/scroll-test{landingPageSuffix}");
EnhancedNavigationTestUtil.SuppressEnhancedNavigation(this, shouldSuppress: !useEnhancedNavigation, skipNavigation: true);
Navigate($"{ServerPathBase}/nav/scroll-test{landingPageSuffix}");

// "landing" page: scroll to pos1, navigate away
AssertWeAreOnLandingPage();
Expand Down Expand Up @@ -831,6 +830,7 @@ private void AssertScrollPositionCorrect(bool useEnhancedNavigation, long previo
private void AssertEnhancedNavigation(bool useEnhancedNavigation, IWebElement elementForStalenessCheck, int retryCount = 3, int delayBetweenRetriesMs = 1000)
{
bool enhancedNavigationDetected = false;
string logging = "";
for (int i = 0; i < retryCount; i++)
{
try
Expand All @@ -841,15 +841,31 @@ private void AssertEnhancedNavigation(bool useEnhancedNavigation, IWebElement el
}
catch (XunitException)
{
var logs = Browser.GetBrowserLogs(LogLevel.Warning);
logging += $"{string.Join(", ", logs.Select(l => l.Message))}\n";

var testId = ((IJavaScriptExecutor)Browser).ExecuteScript("return sessionStorage.getItem('test-id');");
logging += $" testId: {testId}\n";
if (testId is null)
{
continue;
}
var suppressKey = $"suppress-enhanced-navigation-{testId}";

var enhancedNavAttached = ((IJavaScriptExecutor)Browser).ExecuteScript("return sessionStorage.getItem('blazor-enhanced-nav-attached');");
var suppressEnhancedNavigation = ((IJavaScriptExecutor)Browser).ExecuteScript($"return sessionStorage.getItem('{suppressKey}');");

logging += $" suppressKey: {suppressKey}\n";
logging += $" {suppressKey}: {suppressEnhancedNavigation}\n";
// Maybe the check was done too early to change the DOM ref, retry
}

Thread.Sleep(delayBetweenRetriesMs);
}
string expectedNavigation = useEnhancedNavigation ? "enhanced navigation" : "browser navigation";
string expectedNavigation = useEnhancedNavigation ? "enhanced navigation" : "full page load";
string isStale = enhancedNavigationDetected ? "is not stale" : "is stale";
var isNavigationSupressed = (string)((IJavaScriptExecutor)Browser).ExecuteScript("return sessionStorage.getItem('suppress-enhanced-navigation');");
throw new Exception($"Expected to use {expectedNavigation} because 'suppress-enhanced-navigation' is set to {isNavigationSupressed} but the element from previous path {isStale}");
var isNavigationSuppressed = (string)((IJavaScriptExecutor)Browser).ExecuteScript("return sessionStorage.getItem('suppress-enhanced-navigation');");
throw new Exception($"Expected to use {expectedNavigation} because 'suppress-enhanced-navigation' is set to {isNavigationSuppressed} but the element from previous path {isStale}. logging={logging}");
}

private void AssertWeAreOnLandingPage()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,27 @@ public static void SuppressEnhancedNavigation<TServerFixture>(ServerTestBase<TSe
{
var browser = fixture.Browser;

// Set the suppression flag - this will prevent enhanced navigation from being attached on the next navigation
// and trigger detachment of currently attached enhanced navigation via the periodic check
var testId = ((IJavaScriptExecutor)browser).ExecuteScript($"return sessionStorage.getItem('test-id')");
if (testId == null)
{
throw new InvalidOperationException("Test ID not found in sessionStorage. Ensure that suppression is enabled for test class by passing `supportEnhancedNavigationSuppression: true` to InitializeAsync or for a given test by calling `GrantTestId()` in the beginning of the test.");
}

if (!skipNavigation)
{
// Normally we need to navigate here first otherwise the browser isn't on the correct origin to access
// localStorage. But some tests are already in the right place and need to avoid extra navigation.
// sessionStorage. But some tests are already in the right place and need to avoid extra navigation.
fixture.Navigate($"{fixture.ServerPathBase}/");
browser.Equal("Hello", () => browser.Exists(By.TagName("h1")).Text);
}

((IJavaScriptExecutor)browser).ExecuteScript("sessionStorage.setItem('suppress-enhanced-navigation', 'true')");
((IJavaScriptExecutor)browser).ExecuteScript($"sessionStorage.setItem('suppress-enhanced-navigation-{testId}', 'true')");

var suppressEnhancedNavigation = ((IJavaScriptExecutor)browser).ExecuteScript($"return sessionStorage.getItem('suppress-enhanced-navigation-{testId}');");
Assert.True(suppressEnhancedNavigation is not null && (string)suppressEnhancedNavigation == "true",
"Expected 'suppress-enhanced-navigation' to be set in sessionStorage.");
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ public override Task InitializeAsync()
_tempDirectory = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString("N"));
Directory.CreateDirectory(_tempDirectory);

return InitializeAsync(BrowserFixture.StreamingContext);
return InitializeAsync(BrowserFixture.StreamingContext, supportEnhancedNavigationSuppression: true);
}

[Theory]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -285,6 +285,7 @@ public void NotFoundSetOnInitialization_ResponseStarted_SSR(bool hasReExecutionM
[InlineData(false, true)]
public void NotFoundSetOnInitialization_ResponseStarted_EnhancedNavigationDisabled_SSR(bool hasReExecutionMiddleware, bool hasCustomNotFoundPageSet)
{
GrantTestId();
EnhancedNavigationTestUtil.SuppressEnhancedNavigation(this, true, skipNavigation: true);
string reexecution = hasReExecutionMiddleware ? "/reexecution" : "";
string testUrl = $"{ServerPathBase}{reexecution}/set-not-found-ssr-streaming?useCustomNotFoundPage={hasCustomNotFoundPageSet}";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ public StreamingRenderingTest(
}

public override Task InitializeAsync()
=> InitializeAsync(BrowserFixture.StreamingContext);
=> InitializeAsync(BrowserFixture.StreamingContext, supportEnhancedNavigationSuppression: true);

[Fact]
public async Task CanRenderNonstreamingPageWithoutInjectingStreamingMarkersOrHeaders()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ public StatePersistenceTest(

// Separate contexts to ensure that caches and other state don't interfere across tests.
public override Task InitializeAsync()
=> InitializeAsync(BrowserFixture.StreamingContext + _nextStreamingIdContext++);
=> InitializeAsync(BrowserFixture.StreamingContext + _nextStreamingIdContext++, supportEnhancedNavigationSuppression: true);

// Validates that we can use persisted state across server, webassembly, and auto modes, with and without
// streaming rendering.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -137,10 +137,10 @@
}

const enableClassicInitializers = sessionStorage.getItem('enable-classic-initializers') === 'true';
const suppressEnhancedNavigation = sessionStorage.getItem('suppress-enhanced-navigation') === 'true';
const testId = sessionStorage.getItem('test-id');
const suppressEnhancedNavigation = testId ? sessionStorage.getItem(`suppress-enhanced-navigation-${testId}`) === 'true' : false;
const blockLoadBootResource = sessionStorage.getItem('block-load-boot-resource') === 'true';
const blockWebassemblySettings = sessionStorage.getItem('block-webassembly-settings') === 'true';
sessionStorage.removeItem('suppress-enhanced-navigation');
sessionStorage.removeItem('block-load-boot-resource');
sessionStorage.removeItem('enable-classic-initializers');
sessionStorage.removeItem('block-webassembly-settings');
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@

<script src="@Assets["_framework/blazor.web.js"]" autostart="false"></script>
<script>
const suppressEnhancedNavigation = sessionStorage.getItem('suppress-enhanced-navigation') === 'true';
const testId = sessionStorage.getItem('test-id');
const suppressEnhancedNavigation = testId ? sessionStorage.getItem(`suppress-enhanced-navigation-${testId}`) === 'true' : false;

let pwr = Promise.withResolvers();
let reconnectPromise = pwr.promise;
Expand All @@ -40,7 +41,6 @@
};
}

sessionStorage.removeItem('suppress-enhanced-navigation');
function callBlazorStart() {
Blazor.start({
ssr: {
Expand Down
13 changes: 11 additions & 2 deletions src/Shared/E2ETesting/BrowserTestBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -53,19 +53,28 @@ public Task DisposeAsync()
{
return Task.CompletedTask;
}

public virtual Task InitializeAsync()
{
return InitializeAsync("");
}

public virtual Task InitializeAsync(string isolationContext)
public virtual Task InitializeAsync(string isolationContext, bool supportEnhancedNavigationSuppression = false)
{
InitializeBrowser(isolationContext);
InitializeAsyncCore();
if (supportEnhancedNavigationSuppression)
{
GrantTestId();
}
return Task.CompletedTask;
}

protected void GrantTestId()
{
var testId = Guid.NewGuid().ToString("N")[..8];
((IJavaScriptExecutor)Browser).ExecuteScript($"sessionStorage.setItem('test-id', '{testId}')");
}

protected virtual void InitializeAsyncCore()
{
}
Expand Down
Loading