1.0.0 - preview 01
[1.0.0-preview-01] - 2020-12-24
Happy holidays everyone. This release marks the first preview release of bUnit, which means that only small features additions and bugfixes will follow before version 1.0.0 is release soon.
Yet again many folks in the community have contributes by raising issues, answering questions, sending in pull requests and taking part in design discussions. A huge thanks to all of you. Also, a huge thanks to the sponsors of the project.
The following section list all changes in 1.0.0 preview 01.
Added
List of new features.
-
Added support for casting
BUnitJSRuntimetoIJSInProcessRuntimeandIJSUnmarshalledRuntime. By @KristofferStrube in #279 -
Added support for triggering
@ontoggleevent handlers through a dedicatedToggle()method. By @egil in #256. -
Added out of the box support for
<Virtualize>component. When a<Virtualize>component is used in a component under test, it's JavaScript interop-calls are faked by bUnits JSInterop, and it should result in all items being rendered immediately. By @egil in #240. -
Added support for components that call
ElementReference.FocusAsync. These calls are handled by the bUnits JSInterop, that also allows you to verify thatFocusAsynchas been called for a specific element. For example, if a component has rendered an<input>element, then the following code will verify that it has been focused usingFocusAsync:var cut = RenderComponent<FocusingComponent>(); var input = cut.Find("input"); JSInterop.VerifyFocusAsyncInvoke() .Arguments[0] // the first argument is the ElemenetReference .ShouldBeElementReferenceTo(input);
-
Added
Render(RenderFragment)andRender<TComponent>(RenderFragment)methods toTestContext, as well as various overloads to theMarkupMatchesmethods, that also takes aRenderFragmentas the expected value.The difference between the generic
Rendermethod and the non-generic one is that the generic returns anIRenderedComponent<TComponent>, whereas the non-generic one returns aIRenderedFragment.Calling
Render<TComponent>(RenderFragent)is equivalent to callingRender(RenderFragment).FindComponent<TComponent>(), e.g. it returns the first component in the render tree of typeTComponent. This is different from theRenderComponent<TComponent>()method, whereTComponentis the root component of the render tree.The main usecase for these are when writing tests inside .razor files. Here the inline syntax for declaring render fragments make these methods very useful.
For example, to tests the
<Counter>page/component that is part of new Blazor apps, do the following (inside aCounterTest.razorfile):@code { [Fact] public void Counter_Increments_When_Button_Is_Clicked() { using var ctx = new TestContext(); var cut = ctx.Render(@<Counter />); cut.Find("button").Click(); cut.Find("p").MarkupMatches(@<p>Current count: 1</p>); } }
Note: This example uses xUnit, but NUnit or MSTest works equally well.
In addition to the new
Rendermethods, a emptyBuildRenderTreemethod has been added to theTestContexttype. This makes it possible to inherit from theTestContexttype in test components, removing the need for newing up theTestContextin each test.This means the test component above ends up looking like this:
@inherts TestContext @code { [Fact] public void Counter_Increments_When_Button_Is_Clicked() { var cut = Render(@<Counter />); cut.Find("button").Click(); cut.Find("p").MarkupMatches(@<p>Current count: 1</p>); } }
Tip: If you have multiple test components in the same folder, you can add a
_Imports.razorfile inside it and add the@inherits TestContextstatement in that, removing the need to add it to every test component. -
Added support for
IJSRuntime.InvokeAsync<IJSObjectReference>(...)calls from components. There is now a new setup helper methods for configuring how invocations towards JS modules should be handled. This is done with the variousSetupModulemethods available on theBunitJSInteroptype available through theTestContext.JSInteropproperty. For example, to set up a module for handling calls tofoo.js, do the following:using var ctx = new TestContext(); var moduleJsInterop = ctx.JSInterop.SetupModule("foo.js");
The returned
moduleJsInteropis aBunitJSInteroptype, which means all the normalSetup<TResult>andSetupVoidmethods can be used to configure it to handle calls to the module from a component. For example, to configure a handler for a call tohelloin thefoo.jsmodule, do the following:moduleJsInterop.SetupVoid("hello");
-
Added support for registering services in bUnits
Servicescollection that implementsIAsyncDisposable. Suggested by @jmaillet in #249.
Changed
List of changes in existing functionality.
-
bUnit's mock IJSRuntime has been moved to an "always on" state by default, in strict mode, and is now available through
TestContext'sJSInteropproperty. This makes it possible for first party Blazor components like the<Virtualize>component, which depend on JSInterop, to "just work" in tests.Compatible with previous releases: To get the same effect as calling
Services.AddMockJSRuntime()in beta-11, which used to add the mock IJSRuntime in "loose" mode, you now just need to change the mode of the already on JSInterop, i.e.ctx.JSInterop.Mode = JSRuntimeMode.Loose.Inspect registered handlers: Since the new design allows registering invoke handlers in the context of the
TestContext, you might need to get already registered handlers in your individual tests. This can be done with theTryGetInvokeHandler()method, that will return handler that can handle the parameters passed to it. E.g. to get a handler for aIJSRuntime.InvokaAsync<string>("getValue"), callctx.JSInterop.TryGetInvokeHandler<string>("getValue").Learn more issue #237. By @egil in #247.
-
The
Setup<TResult>(string identifier, Func<IReadOnlyList<object?>, bool> argumentsMatcher)andSetupVoid(string identifier, Func<IReadOnlyList<object?>, bool> argumentsMatcher)methods in bUnits JSInterop/MockJSRuntime has a new second parameter, anInvocationMatcher.The
InvocationMatchertype is a delegate that receives aJSRuntimeInvoationand returns true. TheJSRuntimeInvoationtype contains the arguments of the invocation and the identifier for the invocation. This means old code using theSetupandSetupVoidmethods should be updated to use the arguments list inJSRuntimeInvoation, e.g., change the following call:ctx.JSInterop.Setup<string>("foo", args => args.Count == 2)to this:
ctx.JSInterop.Setup<string>("foo", invocation => invocation.Arguments.Count == 2). -
Changed
AddTestAuthorizationsuch that it works in Razor-based test contexts, i.e. on theFixtureandSnapshotTesttypes.
Removed
List of now removed features.
- A few bUnit internal xUnit assert helper methods, the custom
ShouldAllBemethods, has mistakingly been part of the bunit.xunit package. These have been removed.
Fixed
List of any bug fixes.
-
When an
Addcall to the component parameter collection builder was used to select a parameter that was inherited from a base component, the builder incorrectly reported the selected property/parameter as missing on the type. Reported by @nickmuller in #250. -
When an element, found in the DOM tree using the
Find(), method was removed because of an event handler trigger on it, e.g. ancut.Find("button").Click()event trigger method, anElementNotFoundExceptionwas thrown. Reported by @nickmuller in #251. -
In the built-in fake authentication system in bUnit, roles and claims were not available in components through the a cascading parameter of type
Task<AuthenticationState>. Reported by @AFAde in #253 and fixed in #291 by @egil.