1.0.0 - preview 02 - final release before v1
[1.0.0-preview-02] - 2021-03-26
The following sections list all changes in 1.0.0 preview 02.
The plan is to make this the last preview release of bUnit. If no big blocking bugs show up the next two weeks, a non-preview release of bUnit will be pushed out to the world.
Added
List of new features.
-
Added the ability to pass a "fallback
IServiceProvider" to theTestServiceProvider, available through theServicesproperty on aTestContext. The fallback service provider enables a few interesting scenarios, such as using an alternative IoC container, or automatically generating mocks of services components under test depend on. See the Injecting Services into Components Under Test page for more details on this feature. By @thopdev in #310. -
Added
Task<Expection> ITestRenderer.UnhandledExceptionproperty that returns aTask<Exception>that completes when the renderer captures an unhandled exception from a component under test. If a component is missing exception handling of asynchronous operations, e.g. in theOnInitializedAsyncmethod, the exception will not break the test, because it happens on another thread. To have a test fail in this scenario, you can await theUnhandledExceptionproperty on theTestContext.Rendererproperty, e.g.:using var ctx = new TestContext(); var cut = ctx.RenderComponent<ComponentThatThrowsDuringAsyncOperation>(); Task<Exception?> waitTimeout = Task.Delay(500).ContinueWith(_ => Task.FromResult<Exception?>(null)).Unwrap(); Exception? unhandledException = await Task.WhenAny<Exception?>(Renderer.UnhandledException, waitTimeout).Unwrap(); Assert.Null(unhandledException);
In this example, we await any unhandled exceptions from the renderer, or our wait timeout. The
waitTimeoutensures that we will not wait forever, in case no unhandled exception is thrown.NOTE, a better approach is to use the
WaitForStateorWaitForAssertionmethods, which now also throws unhandled exceptions. Using them, you do not need to set up a wait timeout explicitly. -
Added a simple fake navigation manager, which is registered by default in bUnit's service provider. When the fake navigation manager's
NavigateTomethod is called, it does two things:- Set the
Uriproperty to the URI passed to theNavigateTomethod (with the URI normalized to an absolute URI). - Raise the
LocationChangedevent with the URI passed to theNavigateTomethod.
Lets look at an example: To verify that the
<GoesToFooOnInit>component below calls theNavigationManager.NavigateTomethod with the expected value, do the following:<GoesToFooOnInit>component:@inject NavigationManager NavMan @code { protected override void OnInitialized() { NavMan.NavigateTo("foo"); } }
Test code:
// Arrange using var ctx = new TestContext(); var navMan = ctx.Services.GetRequiredService<NavigationManager>(); // Act var cut = ctx.RenderComponent<GoesToFooOnInit>(); // Assert Assert.Equal($"{navMan.BaseUri}foo", navMan.Uri);
Since the
fooinput argument is normalized to an absolute URI, we have to do the same normalization in our assertion.The fake navigation manager's
BaseUriis set tohttp://localhost/, but it is not recommended to use that URL directly in your code. Instead create an assertion by getting that value from theBaseUriproperty, like shown in the example above. - Set the
-
Added additional bUnit JSInterop
Setupmethods, that makes it possible to get complete control of invocation matching for the created handler. By @egil.
Changed
List of changes in existing functionality.
-
WaitForAssertionandWaitForStatenow throws unhandled exception caught by the renderer from a component under test. This can happen if a component is awaiting an asynchronous operation that throws, e.g. a API call using a misconfiguredHttpClient. By @egil in #310. -
Improvements to error message from bUnit's JSInterop when it receives an invocation that it has not been set up to handle. By @egil in #346.