-
-
Notifications
You must be signed in to change notification settings - Fork 110
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
How to wait for SetParametersAsync in test? #157
Comments
Hey @JeroenBos, thanks for a very well formed question, makes it very easy to help you. The Until then, you can write your test like this: @inherits TestComponentBase
<Fixture Test="OutputMatchesFragment">
<ComponentUnderTest>
<ComponentWithWorkInSetParameterAsync />
</ComponentUnderTest>
<Fragment>Done</Fragment>
@code
{
public void OutputMatchesFragment(Fixture fixture)
{
var cut = fixture.GetComponentUnderTest();
var expected = fixture.GetFragment();
cut.WaitForAssertion(() => cut.MarkupMatches(expected), TimeSpan.FromSeconds(2));
}
}
</Fixture> The The MarkupMatches method is what The background to this is described here, if you want to know the details of what is going on in the test: https://bunit.egilhansen.com/docs/interaction/awaiting-async-state.html |
Thank you. Very useful link. Your proposed solution works. Pragmatically speaking, I will use it. Principally, though it doesn't sit too right with me. The link mentions mentions the two synchronization contexts, framework and renderer. Wouldn't the "proper" way of waiting on the async work involve one synchronization context waiting for the other, rather than checking some delegate at times it could have changed? Let me suggest what I would like to usage to look like: <Fixture Test="OutputMatchesFragment">
<ComponentUnderTest>
<ComponentWithWorkInSetParameterAsync />
</ComponentUnderTest>
<Fragment>Done</Fragment>
@code
{
public async Task OutputMatchesFragment(Fixture fixture)
{
var cut = fixture.GetComponentUnderTest();
var expected = fixture.GetFragment();
await cut.WaitForSetParametersAsync(); // and cut.WaitForOnInitializedAsync(), etc
cut.MarkupMatches(expected);
}
}
</Fixture> where I'm unsure of how That's would be very lovely functionality by bUnit, and also something I expected to be there. I guess this has turned this question into a feature request 😀 |
@JeroenBos there is actually an issue #124 trying to address this. The ideal solution would in my view be to have just one sync context, such that there is no need to wait at all. My concern is deadlocks, but I will have to investigate when I get to that issue, or somebody does it for me (hint hint). As for your proposal, I do not think it is possible, or at least not without reimplementing the entire rendering pipeline in Blazor. I'll take the liberty to close this issue. Let me know if you have any more questions. |
Description of testing scenario:
What I'm trying to achieve is to compare the rendered html of a component whose
SetParameterAsync
performs long-running work. The comparison test is supposed to take place after that work has taken place, and consistently after. Preferably not by insertingTask.Delay
with an arbitrary number of seconds.I have something like the following in mind (as written, the test fails):
ComponentWithWorkInSetParameterAsync.razor
:The test fails with the obvious error:
Attempted solution
Now, the tests runs to success if you placed
Task.Delay(2000);
inBunit.SnapshotTest.Run
between these two lines, like so:This is sort of the approach that I was taking (by constructing a
MySnapshotTest
, if you will).Now I have a very specific question:
What would you write instead of
Task.Delay(2000);
that waits on theSetParameterAsync
?I was hoping to find members like
Renderer.WaitAll()
orRenderer.Dispatcher.WaitAll()
or something but I can't seem to find it. Using reflection, I tried waiting for the private listMicrosoft.AspNetCore.Components.RenderTree.Renderer._pendingTasks
as well, doesn't work either.Where does the task returned by
SetParametersAsync
go, anyway?I followed it by debugging the blazor source code and I think it gets discarded? In particular here:
https://source.dot.net/#Microsoft.AspNetCore.Components/RenderTree/Renderer.cs,300
because
_pendingTasks
is null. The call is coming fromhttps://source.dot.net/#Microsoft.AspNetCore.Components/Rendering/ComponentState.cs,157
To be precise, I followed it when
var testRenderId = Renderer.RenderFragment(TestInput);
was replaced byvar (testRenderId, cut) = this.Renderer.RenderComponent<ComponentWithWorkInSetParameterAsync>(Array.Empty<ComponentParameter>());
but I don't think it matters.Additional context:
dotnet=3.1.300. bUnit version master today.
Conclusion
It seems the Task that I would like to wait for is unobtainable. Although I hope that I can be shown wrong?
The text was updated successfully, but these errors were encountered: