|
1 | 1 | --- |
2 | 2 | uid: async-assertion |
3 | | -title: Asynchronous Assertion of Change in a Component Under Test |
| 3 | +title: Assertion of Asynchronous Changes |
4 | 4 | --- |
5 | 5 |
|
6 | | -# Asynchronous Assertion of Change in a Component Under Test |
| 6 | +# Assertion of Asynchronous Changes |
| 7 | + |
| 8 | +A test can fail if a component performs asynchronous renders, e.g. because it was awaiting a task to complete before continuing its render life-cycle. For example, if a component is waiting for an async web service to return data to it in the `OnInitializedAsync()` life-cycle method, before rendering it to the render tree. |
| 9 | + |
| 10 | +This happens because tests execute in the test framework's synchronization context and the test renderer executes renders in its own synchronization context. |
| 11 | + |
| 12 | +bUnit comes with two methods that helps deal with this issue, the [`WaitForAssertion(Action, TimeSpan?)`](xref:Bunit.RenderedFragmentWaitForHelperExtensions.WaitForAssertion(Bunit.IRenderedFragmentBase,System.Action,System.Nullable{System.TimeSpan})) method covered on this page, and the [`WaitForState(Func<Boolean>, TimeSpan?)`](xref:Bunit.RenderedFragmentWaitForHelperExtensions.WaitForState(Bunit.IRenderedFragmentBase,System.Func{System.Boolean},System.Nullable{System.TimeSpan})) method covered on the <xref:awaiting-async-state> page. |
| 13 | + |
| 14 | +## Waiting for Assertion to Pass Using `WaitForAssertion` |
| 15 | + |
| 16 | +The [`WaitForAssertion(Action, TimeSpan?)`](xref:Bunit.RenderedFragmentWaitForHelperExtensions.WaitForAssertion(Bunit.IRenderedFragmentBase,System.Action,System.Nullable{System.TimeSpan})) method can be used to block and wait in a test method, until the provided assert action does not throw an exception, or the timeout is reached (the default timeout is one second). |
| 17 | + |
| 18 | +> [!NOTE] |
| 19 | +> The `WaitForAssertion()` method will try the assert action pass to it when the `WaitForAssertion()` method is called, and every time the component under test renders. |
| 20 | +
|
| 21 | +Let us look at an example. Consider the following `<AsyncData>` component, who awaits an async `TextService` in its `OnInitializedAsync()` life-cycle method. When the service returns the data, the component will automatically re-render, to update its rendered markup. |
| 22 | + |
| 23 | +[!code-html[AsyncData.razor](../../../samples/components/AsyncData.razor)] |
| 24 | + |
| 25 | +To test the `<AsyncData>` component, do the following: |
| 26 | + |
| 27 | +[!code-csharp[AsyncDataTest.cs](../../../samples/tests/xunit/AsyncDataTest.cs?start=54&end=65&highlight=3,9,12)] |
| 28 | + |
| 29 | +This is what happens in the test: |
| 30 | + |
| 31 | +1. The test uses a `TaskCompletionSource<string>` to simulate an async web service. |
| 32 | +2. In the second highlighted line, the result is provided to the component through the `textService`. This causes the component to re-render. |
| 33 | +3. Finally, in the third highlighted line, the `WaitForAssertion()` method is used to block the test until the predicate assertion action runs without throwing an exception. |
| 34 | + |
| 35 | +### Controlling Wait Timeout |
| 36 | + |
| 37 | +The timeout, which defaults to one second, can be controlled by passing a `TimeSpan` as the second argument to the `WaitForAssertion()` method, e.g.: |
| 38 | + |
| 39 | +[!code-csharp[](../../../samples/tests/xunit/AsyncDataTest.cs?start=66&end=66)] |
| 40 | + |
| 41 | +If the timeout is reached, a <xref:Bunit.Extensions.WaitForHelpers.WaitForFailedException> exception is thrown with the following error message: |
| 42 | + |
| 43 | +> The assertion did not pass within the timeout period. |
0 commit comments