Skip to content

Improve renderer unit test #62016

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

Merged
merged 4 commits into from
May 21, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,8 @@ protected override void AddPendingTask(ComponentState? componentState, Task task
base.AddPendingTask(componentState, task);
}

private void SignalRendererToFinishRendering()
// 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
_rendererIsStopped = true;
Expand Down
42 changes: 25 additions & 17 deletions src/Components/Endpoints/test/EndpointHtmlRendererTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -47,18 +48,23 @@ 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);
var initialRenderOperation = renderer.Dispatcher.InvokeAsync(
() => renderer.RenderRootComponentAsync(id, ParameterView.Empty));

Assert.DoesNotContain("Hello from SimpleComponent", content);
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);
}

[Fact]
Expand Down Expand Up @@ -1772,18 +1778,10 @@ private TestEndpointHtmlRenderer GetEndpointHtmlRenderer(IServiceProvider servic
private class TestEndpointHtmlRenderer : EndpointHtmlRenderer
{
private bool _rendererIsStopped = false;
public TestEndpointHtmlRenderer(IServiceProvider serviceProvider, ILoggerFactory loggerFactory) : base(serviceProvider, loggerFactory)
{
}
private int _renderCount;

internal int TestAssignRootComponentId(IComponent component)
public TestEndpointHtmlRenderer(IServiceProvider serviceProvider, ILoggerFactory loggerFactory) : base(serviceProvider, loggerFactory)
{
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;
}

protected override void ProcessPendingRender()
Expand All @@ -1793,6 +1791,16 @@ protected override void ProcessPendingRender()
return;
}
base.ProcessPendingRender();

_renderCount++;
}

public int RenderCount => _renderCount;

public new void SignalRendererToFinishRendering()
{
_rendererIsStopped = true;
base.SignalRendererToFinishRendering();
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<h1>Hello from StoppingRendererComponent</h1>
<p>State is @_state</p>

@code {
private bool _state = true;

// expose a TCS so the test can control when OnInitializedAsync completes
public TaskCompletionSource<bool> TaskCompletionSource = new TaskCompletionSource<bool>();

protected override async Task OnInitializedAsync()
{
// wait until the test signals
var result = await TaskCompletionSource.Task;
_state = result;
StateHasChanged();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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<string, Task>? _onNavigateTo;
Expand Down
Loading