FragmentContainer was not found in async test
See original GitHub issueDescribe the bug
I have a relatively simple component that just renders different content depending on the state of a Task
. The code of both component and test is very similar to the async example except that instead of awaiting the task on init I’m using task.ContinueWith(...) => InvokeAsync(StateHasChanged)
and using the razor test syntax.
When using bUnit 1.16.2 and not using WaitForAssertion
, the tests almost always pass. (I did very very rarely observe the same waiting
failure as below.)
When using later versions of bUnit, the tests will more frequently intermittently fail (showing the waiting
content rather than the done
content).
When I tried adding WaitForAssertion
(in 1.16.2) it started instead failing with:
Bunit.Extensions.WaitForHelpers.WaitForFailedException : The assertion did not pass within the timeout period. Check count: 2. Component render count: 2. Total render count: 5.
----> Bunit.Rendering.ComponentNotFoundException : A component of type FragmentContainer was not found in the render tree.
at Bunit.RenderedFragmentWaitForHelperExtensions.WaitForAssertion(IRenderedFragmentBase renderedFragment, Action assertion, Nullable`1 timeout) in /_/src/bunit.core/Extensions/WaitForHelpers/RenderedFragmentWaitForHelperExtensions.cs:line 72
I haven’t been able to replicate precisely this behaviour in a MCVE test, but what I did manage to reproduce is described below.
(Oddly, the MCVE code always fails (with waiting
content, not the exception) when not using WaitForAssertion
. While not exactly surprising due to async, it’s odd that it’s different; though it’s likely that this is due to the real component being a bit more complex.)
Example: Testing this component:
@if (Task != null)
{
@if (Task.IsCompleted)
{
<span>done</span>
}
else
{
<span>waiting</span>
}
}
@code {
[Parameter] public Task? Task { get; set; }
private Task? _RegisteredTask;
protected override void OnParametersSet()
{
var task = Task;
if (task != _RegisteredTask)
{
_RegisteredTask = task;
_ = task?.ContinueWith((t, o) =>
{
if (t == Task)
{
_ = InvokeAsync(StateHasChanged);
}
}, null);
}
base.OnParametersSet();
}
}
With this test:
@using NUnit.Framework
@using Bunit
@*@inherits Bunit.TestContext*@
@inherits BunitTestContext /* this uses TestContextWrapper */
@code {
[Test]
public void Cancel1()
{
var tcs = new TaskCompletionSource();
using var cut = Render(@<MyComponent Task="@tcs.Task"/>);
cut.MarkupMatches(@<span>waiting</span>);
tcs.SetCanceled();
cut.WaitForAssertion(() => cut.MarkupMatches(@<span>done</span>));
}
[Test]
public void Cancel2()
{
var tcs = new TaskCompletionSource();
using var cut = Render(@<MyComponent Task="@tcs.Task"/>);
cut.MarkupMatches(@<span>waiting</span>);
tcs.SetCanceled();
cut.WaitForAssertion(() => cut.MarkupMatches(@<span>done</span>));
}
[Test]
public void Cancel3()
{
var tcs = new TaskCompletionSource();
using var cut = Render(@<MyComponent Task="@tcs.Task"/>);
cut.MarkupMatches(@<span>waiting</span>);
tcs.SetCanceled();
cut.WaitForAssertion(() => cut.MarkupMatches(@<span>done</span>));
}
}
(Note that this is three identical copies of the same test.)
Expected behavior:
All tests should pass.
Actual behavior:
The first test always passes. The other two tests intermittently fail with the exception above.
If I run the tests in the debugger (without stopping on any breakpoints or exceptions), all tests pass.
Version info:
- bUnit version: 1.21.9
- Blazor version: 6.0.18
- .NET Runtime version: 6.0.405 (SDK 7.0.102)
- OS type and version: Windows 10, VS2022
Issue Analytics
- State:
- Created 3 months ago
- Comments:40 (17 by maintainers)
Yes, it’s the same FragmentContainer exception.
I try to find some time to provide a fix