From 86560b961bd82aeaa2dcdd7c64e2ff07a83bf2e4 Mon Sep 17 00:00:00 2001 From: Ilona Tomkowicz Date: Tue, 20 May 2025 13:57:41 +0200 Subject: [PATCH 1/3] Improve tests, use constant string in feature attribute. --- .../src/Rendering/EndpointHtmlRenderer.cs | 2 +- .../test/EndpointHtmlRendererTest.cs | 44 +++++++++++++------ .../StoppingRendererComponent.razor | 17 +++++++ .../src/Circuits/RemoteNavigationManager.cs | 2 +- 4 files changed, 50 insertions(+), 15 deletions(-) create mode 100644 src/Components/Endpoints/test/TestComponents/StoppingRendererComponent.razor diff --git a/src/Components/Endpoints/src/Rendering/EndpointHtmlRenderer.cs b/src/Components/Endpoints/src/Rendering/EndpointHtmlRenderer.cs index 5ad06a390cdf..f33238983ec9 100644 --- a/src/Components/Endpoints/src/Rendering/EndpointHtmlRenderer.cs +++ b/src/Components/Endpoints/src/Rendering/EndpointHtmlRenderer.cs @@ -183,7 +183,7 @@ protected override void AddPendingTask(ComponentState? componentState, Task task base.AddPendingTask(componentState, task); } - private void SignalRendererToFinishRendering() + internal void SignalRendererToFinishRendering() { // sets a deferred stop on the renderer, which will have an effect after the current batch is completed _rendererIsStopped = true; diff --git a/src/Components/Endpoints/test/EndpointHtmlRendererTest.cs b/src/Components/Endpoints/test/EndpointHtmlRendererTest.cs index bfb82e50d284..fea523269e3e 100644 --- a/src/Components/Endpoints/test/EndpointHtmlRendererTest.cs +++ b/src/Components/Endpoints/test/EndpointHtmlRendererTest.cs @@ -11,6 +11,7 @@ using Microsoft.AspNetCore.Components.Infrastructure; using Microsoft.AspNetCore.Components.Reflection; using Microsoft.AspNetCore.Components.Rendering; +using Microsoft.AspNetCore.Components.RenderTree; using Microsoft.AspNetCore.Components.Test.Helpers; using Microsoft.AspNetCore.Components.Web; using Microsoft.AspNetCore.DataProtection; @@ -47,18 +48,21 @@ public EndpointHtmlRendererTest() } [Fact] - public async Task DoesNotRenderChildAfterRendererStopped() + public async Task DoesNotRenderAfterRendererStopped() { - renderer.SignalRendererToFinishRendering(); - var httpContext = GetHttpContext(); var writer = new StringWriter(); - var result = await renderer.PrerenderComponentAsync(httpContext, typeof(SimpleComponent), null, ParameterView.Empty); - await renderer.Dispatcher.InvokeAsync(() => result.WriteTo(writer, HtmlEncoder.Default)); - var content = writer.ToString(); + var component = new StoppingRendererComponent(); + var id = renderer.AssignRootComponentId(component); + await renderer.Dispatcher.InvokeAsync(() => renderer.RenderRootComponentAsync(id, ParameterView.Empty)); + int initialRenderCount = renderer.RenderCount; + + renderer.SignalRendererToFinishRendering(); - Assert.DoesNotContain("Hello from SimpleComponent", content); + component.TaskCompletionSource.SetResult(false); + await renderer.Dispatcher.InvokeAsync(() => renderer.RenderRootComponentAsync(id, ParameterView.Empty)); + Assert.Equal(initialRenderCount, renderer.RenderCount); } [Fact] @@ -1772,18 +1776,19 @@ private TestEndpointHtmlRenderer GetEndpointHtmlRenderer(IServiceProvider servic private class TestEndpointHtmlRenderer : EndpointHtmlRenderer { private bool _rendererIsStopped = false; + private int _lastComponentId; + private int _renderCount; + private RenderBatch _lastBatch; + public TestEndpointHtmlRenderer(IServiceProvider serviceProvider, ILoggerFactory loggerFactory) : base(serviceProvider, loggerFactory) { } internal int TestAssignRootComponentId(IComponent component) { - return base.AssignRootComponentId(component); - } - public void SignalRendererToFinishRendering() - { - // sets a deferred stop on the renderer, which will have an effect after the current batch is completed - _rendererIsStopped = true; + var id = base.AssignRootComponentId(component); + _lastComponentId = id; + return id; } protected override void ProcessPendingRender() @@ -1793,6 +1798,19 @@ protected override void ProcessPendingRender() return; } base.ProcessPendingRender(); + + _renderCount++; + _lastBatch = GetCurrentRenderBatch(); + } + + public int RenderCount => _renderCount; + + public RenderBatch GetCurrentRenderBatch() => _lastBatch; + + public new void SignalRendererToFinishRendering() + { + _rendererIsStopped = true; + base.SignalRendererToFinishRendering(); } } diff --git a/src/Components/Endpoints/test/TestComponents/StoppingRendererComponent.razor b/src/Components/Endpoints/test/TestComponents/StoppingRendererComponent.razor new file mode 100644 index 000000000000..521257c5d11b --- /dev/null +++ b/src/Components/Endpoints/test/TestComponents/StoppingRendererComponent.razor @@ -0,0 +1,17 @@ +

Hello from StoppingRendererComponent

+

State is @_state

+ +@code { + private bool _state = true; + + // expose a TCS so the test can control when OnInitializedAsync completes + public TaskCompletionSource TaskCompletionSource = new TaskCompletionSource(); + + protected override async Task OnInitializedAsync() + { + // wait until the test signals + var result = await TaskCompletionSource.Task; + _state = result; + StateHasChanged(); + } +} \ No newline at end of file diff --git a/src/Components/Server/src/Circuits/RemoteNavigationManager.cs b/src/Components/Server/src/Circuits/RemoteNavigationManager.cs index b2d166f960a7..ddb5df5b03db 100644 --- a/src/Components/Server/src/Circuits/RemoteNavigationManager.cs +++ b/src/Components/Server/src/Circuits/RemoteNavigationManager.cs @@ -19,7 +19,7 @@ internal sealed partial class RemoteNavigationManager : NavigationManager, IHost private bool? _navigationLockStateBeforeJsRuntimeAttached; private const string _enableThrowNavigationException = "Microsoft.AspNetCore.Components.Endpoints.NavigationManager.EnableThrowNavigationException"; - [FeatureSwitchDefinition("Microsoft.AspNetCore.Components.Endpoints.NavigationManager.EnableThrowNavigationException")] + [FeatureSwitchDefinition(_enableThrowNavigationException)] private static bool _throwNavigationException => AppContext.TryGetSwitch(_enableThrowNavigationException, out var switchValue) && switchValue; private Func? _onNavigateTo; From c80f15d4156fcedacacc82865b9a7c245e87caac Mon Sep 17 00:00:00 2001 From: Ilona Tomkowicz <32700855+ilonatommy@users.noreply.github.com> Date: Tue, 20 May 2025 14:32:39 +0200 Subject: [PATCH 2/3] Update src/Components/Endpoints/src/Rendering/EndpointHtmlRenderer.cs Co-authored-by: Javier Calvarro Nelson --- src/Components/Endpoints/src/Rendering/EndpointHtmlRenderer.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Components/Endpoints/src/Rendering/EndpointHtmlRenderer.cs b/src/Components/Endpoints/src/Rendering/EndpointHtmlRenderer.cs index f33238983ec9..33e52fa0ed57 100644 --- a/src/Components/Endpoints/src/Rendering/EndpointHtmlRenderer.cs +++ b/src/Components/Endpoints/src/Rendering/EndpointHtmlRenderer.cs @@ -183,6 +183,7 @@ protected override void AddPendingTask(ComponentState? componentState, Task task base.AddPendingTask(componentState, task); } + // For testing purposes only internal void SignalRendererToFinishRendering() { // sets a deferred stop on the renderer, which will have an effect after the current batch is completed From ac76fab7df6efe057c5e67e4034b4a0c4295de3d Mon Sep 17 00:00:00 2001 From: Ilona Tomkowicz Date: Wed, 21 May 2025 09:33:34 +0200 Subject: [PATCH 3/3] Cleanup, avoid timeouts. --- .../test/EndpointHtmlRendererTest.cs | 20 +++++-------------- 1 file changed, 5 insertions(+), 15 deletions(-) diff --git a/src/Components/Endpoints/test/EndpointHtmlRendererTest.cs b/src/Components/Endpoints/test/EndpointHtmlRendererTest.cs index fea523269e3e..ac787b76bfe5 100644 --- a/src/Components/Endpoints/test/EndpointHtmlRendererTest.cs +++ b/src/Components/Endpoints/test/EndpointHtmlRendererTest.cs @@ -55,12 +55,14 @@ public async Task DoesNotRenderAfterRendererStopped() var component = new StoppingRendererComponent(); var id = renderer.AssignRootComponentId(component); - await renderer.Dispatcher.InvokeAsync(() => renderer.RenderRootComponentAsync(id, ParameterView.Empty)); - int initialRenderCount = renderer.RenderCount; + var initialRenderOperation = renderer.Dispatcher.InvokeAsync( + () => renderer.RenderRootComponentAsync(id, ParameterView.Empty)); renderer.SignalRendererToFinishRendering(); - component.TaskCompletionSource.SetResult(false); + await initialRenderOperation; + int initialRenderCount = renderer.RenderCount; + await renderer.Dispatcher.InvokeAsync(() => renderer.RenderRootComponentAsync(id, ParameterView.Empty)); Assert.Equal(initialRenderCount, renderer.RenderCount); } @@ -1776,21 +1778,12 @@ private TestEndpointHtmlRenderer GetEndpointHtmlRenderer(IServiceProvider servic private class TestEndpointHtmlRenderer : EndpointHtmlRenderer { private bool _rendererIsStopped = false; - private int _lastComponentId; private int _renderCount; - private RenderBatch _lastBatch; public TestEndpointHtmlRenderer(IServiceProvider serviceProvider, ILoggerFactory loggerFactory) : base(serviceProvider, loggerFactory) { } - internal int TestAssignRootComponentId(IComponent component) - { - var id = base.AssignRootComponentId(component); - _lastComponentId = id; - return id; - } - protected override void ProcessPendingRender() { if (_rendererIsStopped) @@ -1800,13 +1793,10 @@ protected override void ProcessPendingRender() base.ProcessPendingRender(); _renderCount++; - _lastBatch = GetCurrentRenderBatch(); } public int RenderCount => _renderCount; - public RenderBatch GetCurrentRenderBatch() => _lastBatch; - public new void SignalRendererToFinishRendering() { _rendererIsStopped = true;