fixture, bool shouldSuppress, bool skipNavigation = false)
+ where TServerFixture : ServerFixture
+ {
+ if (shouldSuppress)
+ {
+ var browser = fixture.Browser;
+
+ 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.
+ fixture.Navigate($"{fixture.ServerPathBase}/");
+ browser.Equal("Hello", () => browser.Exists(By.TagName("h1")).Text);
+ }
+
+ ((IJavaScriptExecutor)browser).ExecuteScript("sessionStorage.setItem('suppress-enhanced-navigation', 'true')");
+ }
+ }
+}
diff --git a/src/Components/test/E2ETest/ServerRenderingTests/FormHandlingTests/FormWithParentBindingContextTest.cs b/src/Components/test/E2ETest/ServerRenderingTests/FormHandlingTests/FormWithParentBindingContextTest.cs
index d7af436af828..e61914964bec 100644
--- a/src/Components/test/E2ETest/ServerRenderingTests/FormHandlingTests/FormWithParentBindingContextTest.cs
+++ b/src/Components/test/E2ETest/ServerRenderingTests/FormHandlingTests/FormWithParentBindingContextTest.cs
@@ -232,13 +232,7 @@ public void CanBindComplexTypeToDefaultForm(bool suppressEnhancedNavigation)
var url = "forms/default-form-bound-complextype-parameter";
var expectedTarget = GetExpectedTarget(this, null, url);
- if (suppressEnhancedNavigation)
- {
- GoTo("");
- Browser.Equal("Hello", () => Browser.Exists(By.TagName("h1")).Text);
- ((IJavaScriptExecutor)Browser).ExecuteScript("sessionStorage.setItem('suppress-enhanced-navigation', 'true')");
- }
-
+ SuppressEnhancedNavigation(suppressEnhancedNavigation);
GoTo(url);
Browser.Exists(By.Id("ready"));
@@ -275,13 +269,7 @@ public void CanBreakFormIntoMultipleComponents(bool suppressEnhancedNavigation)
var url = "forms/default-form-bound-complextype-multiple-components";
var expectedTarget = GetExpectedTarget(this, null, url);
- if (suppressEnhancedNavigation)
- {
- GoTo("");
- Browser.Equal("Hello", () => Browser.Exists(By.TagName("h1")).Text);
- ((IJavaScriptExecutor)Browser).ExecuteScript("sessionStorage.setItem('suppress-enhanced-navigation', 'true')");
- }
-
+ SuppressEnhancedNavigation(suppressEnhancedNavigation);
GoTo(url);
Browser.Exists(By.Id("ready"));
@@ -340,13 +328,7 @@ public void CanBreakFormIntoMultipleComponentsDisplaysErrorsCorrectly(bool suppr
var url = "forms/default-form-bound-complextype-multiple-components";
var expectedTarget = GetExpectedTarget(this, null, url);
- if (suppressEnhancedNavigation)
- {
- GoTo("");
- Browser.Equal("Hello", () => Browser.Exists(By.TagName("h1")).Text);
- ((IJavaScriptExecutor)Browser).ExecuteScript("sessionStorage.setItem('suppress-enhanced-navigation', 'true')");
- }
-
+ SuppressEnhancedNavigation(suppressEnhancedNavigation);
GoTo(url);
Browser.Exists(By.Id("ready"));
@@ -399,13 +381,7 @@ public void CanDisplayBindingErrorsComplexTypeToDefaultForm(bool suppressEnhance
var url = "forms/default-form-bound-complextype-parameter";
var expectedTarget = GetExpectedTarget(this, null, url);
- if (suppressEnhancedNavigation)
- {
- GoTo("");
- Browser.Equal("Hello", () => Browser.Exists(By.TagName("h1")).Text);
- ((IJavaScriptExecutor)Browser).ExecuteScript("sessionStorage.setItem('suppress-enhanced-navigation', 'true')");
- }
-
+ SuppressEnhancedNavigation(suppressEnhancedNavigation);
GoTo(url);
Browser.Exists(By.Id("ready"));
@@ -445,13 +421,7 @@ public void CanBindDictionaryToDefaultForm(bool suppressEnhancedNavigation)
var url = "forms/default-form-bound-dictionary-parameter";
var expectedTarget = GetExpectedTarget(this, null, url);
- if (suppressEnhancedNavigation)
- {
- GoTo("");
- Browser.Equal("Hello", () => Browser.Exists(By.TagName("h1")).Text);
- ((IJavaScriptExecutor)Browser).ExecuteScript("sessionStorage.setItem('suppress-enhanced-navigation', 'true')");
- }
-
+ SuppressEnhancedNavigation(suppressEnhancedNavigation);
GoTo(url);
Browser.Exists(By.Id("ready"));
@@ -488,13 +458,7 @@ public void CanDisplayBindingErrorsDictionaryToDefaultForm(bool suppressEnhanced
var url = "forms/default-form-bound-dictionary-parameter-errors";
var expectedTarget = GetExpectedTarget(this, null, url);
- if (suppressEnhancedNavigation)
- {
- GoTo("");
- Browser.Equal("Hello", () => Browser.Exists(By.TagName("h1")).Text);
- ((IJavaScriptExecutor)Browser).ExecuteScript("sessionStorage.setItem('suppress-enhanced-navigation', 'true')");
- }
-
+ SuppressEnhancedNavigation(suppressEnhancedNavigation);
GoTo(url);
Browser.Exists(By.Id("ready"));
@@ -535,13 +499,7 @@ public void CanBindCollectionsToDefaultForm(bool suppressEnhancedNavigation)
var url = "forms/default-form-bound-collection-parameter";
var expectedTarget = GetExpectedTarget(this, null, url);
- if (suppressEnhancedNavigation)
- {
- GoTo("");
- Browser.Equal("Hello", () => Browser.Exists(By.TagName("h1")).Text);
- ((IJavaScriptExecutor)Browser).ExecuteScript("sessionStorage.setItem('suppress-enhanced-navigation', 'true')");
- }
-
+ SuppressEnhancedNavigation(suppressEnhancedNavigation);
GoTo(url);
Browser.Exists(By.Id("ready"));
@@ -587,13 +545,7 @@ public void CanDisplayBindingErrorsCollectionsToDefaultForm(bool suppressEnhance
var url = "forms/default-form-bound-collection-parameter";
var expectedTarget = GetExpectedTarget(this, null, url);
- if (suppressEnhancedNavigation)
- {
- GoTo("");
- Browser.Equal("Hello", () => Browser.Exists(By.TagName("h1")).Text);
- ((IJavaScriptExecutor)Browser).ExecuteScript("sessionStorage.setItem('suppress-enhanced-navigation', 'true')");
- }
-
+ SuppressEnhancedNavigation(suppressEnhancedNavigation);
GoTo(url);
Browser.Exists(By.Id("ready"));
@@ -1117,16 +1069,6 @@ public void CanMutateDataSuppliedFromForm(bool suppressEnhancedNavigation)
Browser.Exists(By.Id("received-notification"));
}
- private void SuppressEnhancedNavigation(bool shouldSuppress)
- {
- if (shouldSuppress)
- {
- GoTo("");
- Browser.Equal("Hello", () => Browser.Exists(By.TagName("h1")).Text);
- ((IJavaScriptExecutor)Browser).ExecuteScript("sessionStorage.setItem('suppress-enhanced-navigation', 'true')");
- }
- }
-
private void AssertHasInternalServerError(bool suppressedEnhancedNavigation, bool streaming = false)
{
if (streaming)
@@ -1290,6 +1232,9 @@ private void DispatchToFormCore(DispatchToForm dispatch)
}
}
+ private void SuppressEnhancedNavigation(bool shouldSuppress)
+ => EnhancedNavigationTestUtil.SuppressEnhancedNavigation(this, shouldSuppress);
+
private record struct DispatchToForm()
{
public DispatchToForm(FormWithParentBindingContextTest test) : this()
diff --git a/src/Components/test/E2ETest/ServerRenderingTests/StreamingRenderingTest.cs b/src/Components/test/E2ETest/ServerRenderingTests/StreamingRenderingTest.cs
index 4b3c7c230d32..789eb51d4520 100644
--- a/src/Components/test/E2ETest/ServerRenderingTests/StreamingRenderingTest.cs
+++ b/src/Components/test/E2ETest/ServerRenderingTests/StreamingRenderingTest.cs
@@ -149,6 +149,21 @@ public async Task DisplaysErrorThatOccursWhileStreaming()
Assert.EndsWith("/subdir/nav", Browser.Url);
}
+ [Theory]
+ [InlineData(true)]
+ [InlineData(false)]
+ public void CanAddScriptElementsDynamically(bool suppressEnhancedNavigation)
+ {
+ EnhancedNavigationTestUtil.SuppressEnhancedNavigation(this, suppressEnhancedNavigation);
+ Navigate($"{ServerPathBase}/streaming-scripts");
+
+ Browser.Equal("This was set by JS via src", () => Browser.FindElement(By.Id("dynamic-script-output-src")).Text);
+ Browser.Equal("This was set by JS via inline script asynchronously (special chars: ' \" )", () => Browser.FindElement(By.Id("dynamic-script-output-inline")).Text);
+ Browser.Exists(By.Id("dynamic-p-before"));
+ Browser.Exists(By.Id("dynamic-p-between"));
+ Browser.Exists(By.Id("dynamic-p-after"));
+ }
+
[Fact]
public async Task HandlesOverlappingStreamingBatches()
{
diff --git a/src/Components/test/testassets/Components.TestServer/RazorComponents/Pages/StreamingRendering/StreamingWithDynamicScriptTags.razor b/src/Components/test/testassets/Components.TestServer/RazorComponents/Pages/StreamingRendering/StreamingWithDynamicScriptTags.razor
new file mode 100644
index 000000000000..d7b94ff9746e
--- /dev/null
+++ b/src/Components/test/testassets/Components.TestServer/RazorComponents/Pages/StreamingRendering/StreamingWithDynamicScriptTags.razor
@@ -0,0 +1,40 @@
+@page "/streaming-scripts"
+@attribute [StreamRendering]
+
+Adding script tags during streaming SSR
+
+
+ Script tags introduce additional considerations since they force "slotchange" events that interfere with how
+ we used to detect when streaming content was added. This test case is to show that it now works.
+
+
+
+
+
+@if (addScripts)
+{
+ This content is added before the scripts
+
+
+
+
+ This content is added between the scripts
+
+
+
+
+ This content is added after the scripts
+}
+
+@code {
+ bool addScripts;
+ string expressionWithSpecialChars = "' \" "; // To show the dynamic content is JS-encoded, not HTML-encoded
+
+ protected override async Task OnInitializedAsync()
+ {
+ await Task.Delay(250);
+ addScripts = true;
+ }
+}