Skip to content

Releases: bUnit-dev/bUnit

1.2.49

09 Aug 14:40
54b46a0

Choose a tag to compare

Added

List of added functionality in this release.

  • Added more extensions methods to MarkupMatchesAssertExtensions to allow asserting with MarkupMatches on IEnumerable and IElement. By @jgoday.

  • Added BunitErrorBoundaryLogger implementation of IErrorBoundaryLogger (needed for Blazor's ErrorBoundary component in .NET 6.0). By @jgoday.

  • Added ComponentFactories property to the TestContextBase type. The ComponentFactories property is a ComponentFactoryCollection type that contains IComponentFactory types. These are used by bUnits component activator, whenever a component is created during testing. If no component factories is added to the collection, the standard component activator mechanism from Blazor is used. This feature makes it possible to control what components are created normally during a test, and which should be e.g. replaced by a test dummy. More info is available in issue #388.

    Learn more about this feature on the Controlling component instantiation page.

  • Added HasComponent<TComponent>() to IRenderedFragement. Use it to check if the rendered fragment contains a component of type TComponent. Added by @egil.

  • Added AddStub and Add extension methods to ComponentFactories that makes it easy to configure bUnit to replace components in the render tree with stubs. Both methods have overloads that allow for fine grained selection of component types to "double" during testing. Added by @egil in #400.

Changed

List of changes in this release.

  • Updated AngleSharp and related libraries to 0.16.0. NOTE, the new version of AngleSharp includes nullable annotations, which might affect how your code compiles, if you have nullable checking enabled in your test project. By @egil.

  • Updated .NET 6 dependencies to preview 5. By @egil.

Fixed

List of fixes in this release.

  • Fixed JSInterop error message when trying to import an unconfigured module. By @jgoday in #425.

  • Fixed issue where a registered fall-back service provider was not made available to resolve service dependencies of components under test. Thanks to @dady8889 for the reporting the issue.

  • Fixed handling of escaped uri's in FakeNavigationManager. By @linkdotnet in #460.

  • Captured error message from event dispatcher in renderer that would previously be hidden from the user. Related to issue #399.

Release 1.1.5

30 Apr 11:20
c54db88

Choose a tag to compare

Added

  • All bUnit assemblies is now strong named signed.
  • Added .NET 6 (preview 3) as a target framework for bUnit, bUnit.core and bUnit.web.

Changed

  • Changed bunit.template such that created projects only reference the bunit package. Bumped other referenced packages to latest version.

1.0.16

11 Apr 09:15

Choose a tag to compare

[1.0.16] - 2021-04-11

It took a while, but its finally here: a release of bUnit without the preview/beta tag. bUnit has been stable for a long time, so this long overdue, but now at least the wait is over!

The following section list all changes since preview 02.

Changed

List of changes in existing functionality.

  • BREAKING CHANGE: Writing tests using the test components <Fixture> and <SnapshotTest> components inside .razor files has been moved to its own library, bunit.web.testcomponents. This was done for several reasons:

    • The feature has been experimental since it was introduced, and it was introduced get a more natural way of specifying the component under test and any related markup used by test.
    • The feature is only supported with xUnit.
    • There are some issues related to the SourceFileFinder library, which is used to discover the test components.
    • A better way of writing tests in .razor files has been added to bUnit, using "inline render fragments". This method works with all general purpose test frameworks, e.g. MSTest, NUnit, and xUnit, is more flexible, and offer less boilerplate code than the test components. The bUnit documentation has been updated with a guide to this style.

    The new package bunit.web.testcomponents is provided as is, without expectation of further development or enhancements. If you are using the test components currently for writing tests, it will continue to work for you. If you are starting a new project, or have few of these tests, consider switching to the "inline render fragments" style.

    Here is a quick comparison of the styles, using a very simple component.

    First, the test component style:

    @inherits TestComponentBase
    
    <Fixture Test="HelloWorldComponentRendersCorrectly">
      <ComponentUnderTest>
        <HelloWorld />
      </ComponentUnderTest>
    
      @code
      {
        void HelloWorldComponentRendersCorrectly(Fixture fixture)
        {
          // Act
          var cut = fixture.GetComponentUnderTest<HelloWorld>();
    
          // Assert
          cut.MarkupMatches("<h1>Hello world from Blazor</h1>");
        }
      }
    </Fixture>
    
    <SnapshotTest Description="HelloWorld component renders correctly">
      <TestInput>
        <HelloWorld />
      </TestInput>
      <ExpectedOutput>
        <h1>Hello world from Blazor</h1>
      </ExpectedOutput>
    </SnapshotTest>

    The a single test in "inline render fragments" style covers both cases:

    @inherits TestContext
    @code {
      [Fact]
      public void HelloWorldComponentRendersCorrectly()
      {
        // Act
        var cut = Render(@<HelloWorld />);
    
        // Assert
        cut.MarkupMatches(@<h1>Hello world from Blazor</h1>);
      }  
    }
    

    To make the snapshot test scenario even more compact, consider putting all code in one line, e.g. Render(@<HelloWorld />).MarkupMatches(@<h1>Hello world from Blazor</h1>);.

    For a more complete snapshot testing experience, I recommend looking at Simon Cropp's Verify library, in particular the Verify.Blazor extension to bUnit. Verify comes with all the features you expect from a snapshot testing library.

Removed

List of now removed features.

  • The AddXunitLogger method, which provided support for capturing ILogger messages and passing them to xUnit's ITestOutputHelper, has been removed. There were no need to keep xUnit specific code around in bUnit going forward, and there are many implementations on-line that supports this feature, so having it in bUnit made little sense. One such alternative, which bUnit has adopted internally, is to use Serilog. This looks as follows:

    1. Add the following packages to your test project: Serilog, Serilog.Extensions.Logging, and Serilog.Sinks.XUnit.
    2. Add the following class/extension method to your test project (which replicates the signature of the removed AddXunitLogger method):
     using Microsoft.Extensions.DependencyInjection;
     using Microsoft.Extensions.Logging;
     using Serilog;
     using Serilog.Events;
     using Xunit.Abstractions;
    
     namespace Bunit
     {
     	public static class ServiceCollectionLoggingExtensions
     	{
     		public static IServiceCollection AddXunitLogger(this IServiceCollection services, ITestOutputHelper outputHelper)
     		{
     			var serilogLogger = new LoggerConfiguration()
     				.MinimumLevel.Verbose()
     				.WriteTo.TestOutput(outputHelper, LogEventLevel.Verbose)
     				.CreateLogger();
    
     			services.AddSingleton<ILoggerFactory>(new LoggerFactory().AddSerilog(serilogLogger, dispose: true));
     			services.AddSingleton(typeof(ILogger<>), typeof(Logger<>));
    
     			return services;
     		}
     	}
     }
  • The bunit.xunit package has been removed, since it is no longer needed (there is no code left in it).

1.0.0 - preview 02 - final release before v1

26 Mar 16:18

Choose a tag to compare

[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 the TestServiceProvider, available through the Services property on a TestContext. 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.UnhandledException property that returns a Task<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 the OnInitializedAsync method, the exception will not break the test, because it happens on another thread. To have a test fail in this scenario, you can await the UnhandledException property on the TestContext.Renderer property, 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 waitTimeout ensures that we will not wait forever, in case no unhandled exception is thrown.

    NOTE, a better approach is to use the WaitForState or WaitForAssertion methods, which now also throws unhandled exceptions. Using them, you do not need to set up a wait timeout explicitly.

    By @egil in #344.

  • Added a simple fake navigation manager, which is registered by default in bUnit's service provider. When the fake navigation manager's NavigateTo method is called, it does two things:

    1. Set the Uri property to the URI passed to the NavigateTo method (with the URI normalized to an absolute URI).
    2. Raise the LocationChanged event with the URI passed to the NavigateTo method.

    Lets look at an example: To verify that the <GoesToFooOnInit> component below calls the NavigationManager.NavigateTo method 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 foo input argument is normalized to an absolute URI, we have to do the same normalization in our assertion.

    The fake navigation manager's BaseUri is set to http://localhost/, but it is not recommended to use that URL directly in your code. Instead create an assertion by getting that value from the BaseUri property, like shown in the example above.

    By @egil in #345.

  • Added additional bUnit JSInterop Setup methods, that makes it possible to get complete control of invocation matching for the created handler. By @egil.

Changed

List of changes in existing functionality.

  • WaitForAssertion and WaitForState now 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 misconfigured HttpClient. 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.

1.0.0 - preview 01

24 Dec 11:03
fe6f6e0

Choose a tag to compare

[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 BUnitJSRuntime to IJSInProcessRuntime and IJSUnmarshalledRuntime. By @KristofferStrube in #279

  • Added support for triggering @ontoggle event handlers through a dedicated Toggle() 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 that FocusAsync has 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 using FocusAsync:

    var cut = RenderComponent<FocusingComponent>();
    
    var input = cut.Find("input");
    
    JSInterop.VerifyFocusAsyncInvoke()
      .Arguments[0] // the first argument is the ElemenetReference
      .ShouldBeElementReferenceTo(input);

    By @egil in #260.

  • Added Render(RenderFragment) and Render<TComponent>(RenderFragment) methods to TestContext, as well as various overloads to the MarkupMatches methods, that also takes a RenderFragment as the expected value.

    The difference between the generic Render method and the non-generic one is that the generic returns an IRenderedComponent<TComponent>, whereas the non-generic one returns a IRenderedFragment.

    Calling Render<TComponent>(RenderFragent) is equivalent to calling Render(RenderFragment).FindComponent<TComponent>(), e.g. it returns the first component in the render tree of type TComponent. This is different from the RenderComponent<TComponent>() method, where TComponent is 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 a CounterTest.razor file):

    @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 Render methods, a empty BuildRenderTree method has been added to the TestContext type. This makes it possible to inherit from the TestContext type in test components, removing the need for newing up the TestContext in 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.razor file inside it and add the @inherits TestContext statement in that, removing the need to add it to every test component.

    By @egil in #262.

  • 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 various SetupModule methods available on the BunitJSInterop type available through the TestContext.JSInterop property. For example, to set up a module for handling calls to foo.js, do the following:

    using var ctx = new TestContext();
    var moduleJsInterop = ctx.JSInterop.SetupModule("foo.js");

    The returned moduleJsInterop is a BunitJSInterop type, which means all the normal Setup<TResult> and SetupVoid methods can be used to configure it to handle calls to the module from a component. For example, to configure a handler for a call to hello in the foo.js module, do the following:

    moduleJsInterop.SetupVoid("hello");

    By @egil in #288.

  • Added support for registering services in bUnits Services collection that implements IAsyncDisposable. 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's JSInterop property. 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 the TryGetInvokeHandler() method, that will return handler that can handle the parameters passed to it. E.g. to get a handler for a IJSRuntime.InvokaAsync<string>("getValue"), call ctx.JSInterop.TryGetInvokeHandler<string>("getValue").

    Learn more issue #237. By @egil in #247.

  • The Setup<TResult>(string identifier, Func<IReadOnlyList<object?>, bool> argumentsMatcher) and SetupVoid(string identifier, Func<IReadOnlyList<object?>, bool> argumentsMatcher) methods in bUnits JSInterop/MockJSRuntime has a new second parameter, an InvocationMatcher.

    The InvocationMatcher type is a delegate that receives a JSRuntimeInvoation and returns true. The JSRuntimeInvoation type contains the arguments of the invocation and the identifier for the invocation. This means old code using the Setup and SetupVoid methods should be updated to use the arguments list in JSRuntimeInvoation, 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 added in relation to #240 in #257 by @egil.

  • Changed AddTestAuthorization such that it works in Razor-based test contexts, i.e. on the Fixture and SnapshotTest types.

Removed

List of now removed features.

  • A few bUnit internal xUnit assert helper methods, the custom ShouldAllBe methods, has mistakingly been part of the bunit.xunit package. These have been removed.

Fixed

List of any bug fixes.

  • When an Add call 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. an cut.Find("button").Click() event trigger method, an ElementNotFoundException was 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.

Beta 11

26 Oct 13:41

Choose a tag to compare

[1.0.0-beta 11] - 2020-10-26

The following section list all changes in beta-11.

Big thanks to the contributors who helped with this release!

Added

List of new features.

  • Two new overloads to the RenderFragment() and ChildContent() component parameter factory methods have been added that takes a RenderFragment as input. By @egil in #203.

  • Added a ComponentParameterCollection type. The ComponentParameterCollection is a collection of component parameters, that knows how to turn those components parameters into a RenderFragment, which will render a component and pass any parameters inside the collection to that component. That logic was spread out over multiple places in bUnit, and is now owned by the ComponentParameterCollection type. By @egil in #203.

  • Added additional placeholder services for NavigationManager, HttpClient, and IStringLocalizer, to make it easier for users to figure out why a test is failing due to missing service registration before rendering a component. By @joro550 in #223.

  • Added Key class that represents a keyboard key and helps to avoid constructing KeyboardEventArgs object manually. The key can be passed to KeyPress, KeyDown, or KeyUp helper methods to raise keyboard events. The Key class provides static special keys or can be obtained from character or string. Keys can be combined with key modifiers: Key.Enter + Key.Alt.

    For example, this makes it easier to trigger keyboard events on an element:

    var cut = ctx.RenderComponent<ComponentWithKeyboardEvents>();
    var element = cut.Find("input");
    
    element.KeyDown(Key.Enter + Key.Control); // Triggers onkeydown event with Ctrl + Enter
    element.KeyUp(Key.Control + Key.Shift + 'B'); // Triggers onkeyup event with Ctrl + Shift  + B
    element.KeyPress('1'); // Triggers onkeypress event with key 1
    element.KeyDown(Key.Alt + "<"); // Triggers onkeydown event with Alt + <

    By @duracellko in #101.

  • Added support for registering/adding components to a test context root render tree, which components under test is rendered inside. This allows you to simplify the "arrange" step of a test when a component under test requires a certain render tree as its parent, e.g. a cascading value.

    For example, to pass a cascading string value foo to all components rendered with the test context, do the following:

    ctx.RenderTree.Add<CascadingValue<string>>(parameters => parameters.Add(p => p.Value, "foo"));
    var cut = ctx.RenderComponent<ComponentReceivingFoo>();

    By @egil in #236.

  • Added "catch-all" Setup method to bUnit's mock JS runtime, that allows you to specify only the type when setting up a planned invocation. By @nemesv in #234.

Changed

List of changes in existing functionality.

  • The ComponentParameterBuilder has been renamed to ComponentParameterCollectionBuilder, since it now builds the ComponentParameterCollection type, introduced in this release of bUnit. By @egil in #203.

  • ComponentParameterCollectionBuilder now allows adding cascading values that is not directly used by the component type it targets. This makes it possible to add cascading values to children of the target component. By @egil in #203.

  • The Add(object) has been replaced by AddCascadingValue(object) in ComponentParameterCollectionBuilder, to make it more clear that an unnamed cascading value is being passed to the target component or one of its child components. It is also possible to pass unnamed cascading values using the Add(parameterSelector, value) method, which now correctly detect if the selected cascading value parameter is named or unnamed. By @egil in #203.

  • It is now possible to call the Add(), AddChildContent() methods on ComponentParameterCollectionBuilder, and the factory methods RenderFragment(), ChildContent(), and Template(), multiple times for the same parameter, if it is of type RenderFragment or RenderFragment<TValue>. Doing so previously would either result in an exception or just the last passed RenderFragment to be used. Now all the provided RenderFragment or RenderFragment<TValue> will be combined at runtime into a single RenderFragment or RenderFragment<TValue>.

    For example, this makes it easier to pass e.g. both a markup string and a component to a ChildContent parameter:

    var cut = ctx.RenderComponent<Component>(parameters => parameters
      .AddChildContent("<h1>Below you will find a most interesting alert!</h1>")
      .AddChildContent<Alert>(childParams => childParams
        .Add(p => p.Heading, "Alert heading")
        .Add(p => p.Type, AlertType.Warning)
        .AddChildContent("<p>Hello World</p>")
      )
    );

    By @egil in #203.

  • All test doubles are now in the same namespace, Bunit.TestDoubles. So all import statements for Bunit.TestDoubles.JSInterop and Bunit.TestDoubles.Authorization must be changed to Bunit.TestDoubles. By @egil in #223.

  • Marked MarkupMatches methods as assertion methods to stop SonarSource analyzers complaining about missing assertions in tests. By @egil in #229.

  • AddTestAuthorization now extends TestContext instead of TestServiceProvider, and also automatically adds the CascadingAuthenticationState component to the root render tree. @egil in #237.

Removed

List of now removed features.

  • The async event dispatcher helper methods have been removed (e.g. ClickAsync()), as they do not provide any benefit. If you have an event that triggers async operations in the component under test, instead use cut.WaitForState() or cut.WaitForAssertion() to await the expected state in the component.

Fixed

List of any bug fixes.

  • Using the ComponentParameterCollectionBuilder's Add(p => p.Param, value) method to add a unnamed cascading value didn't create an unnnamed cascading value parameter. By @egil in #203. Credits to Ben Sampica (@benjaminsampica) for reporting and helping investigate this issue.
  • Triggered events now bubble correctly up the DOM tree and triggers other events of the same type. This is a potentially breaking change, since this changes the behaviour of event triggering and thus you might see tests start breaking as a result hereof. By @egil in #119.

Beta 10

15 Sep 21:08

Choose a tag to compare

[1.0.0-beta 10] - 2020-09-15

This release fixes a few bugs and more importantly, adds support for .net 5 release candidate 1.

Added

List of new features.

  • Added support for .NET 5 RC-1.

Changed

List of changes in existing functionality.

  • Related to #189, a bunch of the core ITestRenderer and related types have changed. The internals of ITestRenderer is now less exposed and the test renderer is now in control of when rendered components and rendered fragments are created, and when they are updated. This enables the test renderer to protect against race conditions when the FindComponent, FindComponents, RenderFragment, and RenderComponent methods are called.

Fixed

List of any bug fixes.

  • Fixes #189: The test renderer did not correctly protect against a race condition during initial rendering of a component, and that could in some rare circumstances cause a test to fail when it should not. This has been addressed in this release with a major rewrite of the test renderer, which now controls and owns the rendered component and rendered fragment instances which is created when a component is rendered. By @egil in #201. Credits to @Smurf-IV for reporting and helping investigate this issue.

Beta 9 - adds support for .net 5.0 preview 8 and later

26 Aug 21:18

Choose a tag to compare

[1.0.0-beta-9] - 2020-08-26

This release contains a couple of fixes, and adds support for .NET Preview 8 and later. There are no breaking changes in this release.

A huge thank you goes out to all who contributed to this release, including pharry22, for submitting fixes and improvements to the documentation.

See all changes below:

Added

List of new features.

  • Added InvokeAsync(Func<Task>) to RenderedComponentInvokeAsyncExtensions. By @JeroenBos in #151.
  • Added ITestRenderer Renderer { get ; } to IRenderedFragment to make it possible to simplify the IRenderedComponentBase<TComponent> interface. By @JeroenBos in #151.
  • Added support for scoped CSS to MarkupMatches and related comparer methods. By @egil in #195.

Changed

List of changes in existing functionality.

  • Moved InvokeAsync(), Render() and SetParametersAndRender() methods out of IRenderedComponentBase<TComponent> into extension methods. By @JeroenBos in #151.
  • Accessing Markup, Nodes and related methods on a rendered fragment whose underlying component has been removed from the render tree (disposed) now throws a ComponentDisposedException. By @egil in #184.
  • Changed bUnit's build to target both .net 5.0 and .net standard 2.1. By @egil in #187.

Fixed

List of any bug fixes.

  • Fixes #175: When a component referenced in a test, e.g. through the FindComponent() method was removed from the render tree, accessing the reference could caused bUnit to look for updates to it in the renderer, causing a exception to be thrown. By @egil in #184.

Beta 8

15 Jul 09:57
8306d82

Choose a tag to compare

Here is beta-8, a small summer vacation release. A few needed additions, especially around testing components that use Blazor's authentication and authorization. Big thanks to all contributors for helping out with this release. I especially want to highlight @DarthPedro for all his work on the fake authorization helpers.

In addition to this, a lot of documentation has been added to https://bunit.egilhansen.com/, which I hope will help newcomers to bUnit get a good and easy start.

The details are in the changelog below:

Added

List of new features.

  • Authorization fakes added to make it much easier to test components that use authentication and authorization. Learn more in the Faking Blazor's Authentication and Authorization page. By @DarthPedro in #151.

  • Added MarkupMatches(this string actual ...) extension methods. Make it easier to compare just the text content from a DON text node with a string, while still getting the benefit of the semantic HTML comparer.

Changed

List of changes in existing functionality.

  • TestContextBase.Dispose made virtual to allow inheritor's to override it. By @SimonCropp in #137.

  • [Breaking change] Changed naming convention for JSMock feature and moved to new namespace, Bunit.TestDoubles.JSInterop. All classes and methods containing Js (meaning JavaScript) renamed to JS for consistency with Blazor's IJSRuntime. By @yourilima in #150

Beta 7

19 May 19:30

Choose a tag to compare

NuGet downloads

The latest version of the library is available on NuGet in various incarnations:

Name Type NuGet Download Link
bUnit Library, includes core, web, and xUnit Nuget
bUnit.core Library, only core Nuget
bUnit.web Library, web and core Nuget
bUnit.xUnit Library, xUnit and core Nuget
bUnit.template Template, which currently creates an xUnit based bUnit test projects only Nuget

Contributions

Thanks to Martin Stühmer (@samtrion) and Stef Heyenrath (@StefH) for their code contributions in this release, and to Brad Wilson (@bradwilson) for his help with enabling xUnit to discover and run Razor based tests.

Also a big thank to all you who have contributed by raising issues, participated in issues by helping answer questions and providing input on design and technical issues.

New in beta 7

There are three big changes in bUnit in this release, as well as a whole host of small new features, improvements to the API, and bug fixes. The three big changes are:

  1. A splitting of the library
  2. Discovery of razor base tests, and
  3. A strongly typed way to pass parameters to a component under test.

There are also some breaking changes, which we will cover first.

NOTE: The documentation is next on the TODO list, so please bear with me while I update it to reflect all the recent changes.

Breaking changes

Due to the big restructuring of the library, there are some breaking changes, hopefully for the better.

Razor test changes

Previously, the Test and Setup methods on <Fixture> and <SnapshotTest> did not have any arguments, and the test context they represented when running, was implicitly available in the scope. This has changed with this release, such that all Test and Setup methods now receive the text context as an argument, and that should be used to call e.g. GetComponentUnderTest() on.

For example, if you have a razor based test that looks like this currently:

<Fixture Test="Test001" Setup="TestSetup">
    <ComponentUnderTest><Counter /></ComponentUnderTest>
    <Fragment>...</Fragment>
</Fixture>
@code {
    void TestSetup() => Services.AddMockJsRuntime();

    void Test001()
    {
        var cut = GetComponentUnderTest<Counter>();
        var fragment = GetFragment();
    }
}

You have to change it to this:

<Fixture Test="Test001" Setup="TestSetup">
    <ComponentUnderTest><Counter /></ComponentUnderTest>
</Fixture>
@code {
    // Add a Fixture fixture argument to the setup method and use
    // the services collection inside the fixture to register dependencies
    void TestSetup(Fixture fixture) => fixture.Services.AddMockJsRuntime();

    // Add a Fixture fixture argument to the test method
    void Test001(Fixture fixture) 
    {
        // Use the fixture instance to get the component under test
        var cut = fixture.GetComponentUnderTest<Counter>();
        var fragment = fixture.GetFragment();
    }
}

It is a little more typing, but it is also a lot more obvious what is going on, e.g. where the component under test or fragment is coming from.

In addition to this, the Tests and TestsAsync methods on <Fixture> have been deprecated in this release and throws a runtime exception if used. They were not very used and caused confusion about the state of the components under test between the method calls. Now you can only specify either a Test or TestAsync method per <Fixture>.

WaitForRender removed

The WaitForRender method has been removed entirely from the library. Since it would only wait for one render, it had a very specific use case, where as the more general WaitForAssertion or WaitForState will wait for any number of renders, until the assertion passes, or the state predicate returns true. These make them much better suited to create stable tests.

With WaitForRender, you would pass in an action that would cause a render before attempting your assertion, e.g.:

cut.WaitForRender(() => mockForecastService.Task.SetResult(forecasts));

Assert.Equal("...", cut.Markup);

This can now be changed to first call the action that will trigger the render, and then wait for an assertion to pass, using WaitForAssertion:

mockForecastService.Task.SetResult(forecasts);

cut.WaitForAssertion(() => Assert.Equal("...", cut.Markup));

The two "wait for" methods are also only available through a rendered fragment or rendered component now.

ComponentTestFixture deprecated

Previously, the recommended method for creating xUnit component test classes was to inherit from ComponentTestFixture. Due to the restructuring of the library, this type is now just a TestContext with static component parameters factory methods, so it does not add much value anymore.

The component parameter factory methods are now also available in the more general purpose ComponentParameterFactory type, which can be imported into all test classes, not just xUnit ones, using the import static Bunit.ComponentParameterFactory method, and then you can change your existing xUnit test classes to inherit from TestContext instead of ComponentTestFixture to keep the current functionality for xUnit test classes.

That covers the most important breaking changes. Now lets look at the other big changes.

Splitting up the library

In this release sees bUnit refactored and split up into three different sub libraries. The reasons for doing this are:

  • To make it possible to extract the direct dependency on xUnit and easily add support for NUnit or MSTest
  • To make it easier to maintain distinct parts of the library going forward
  • To enable future support for other non-web variants of Blazor, e.g. the Blazor Mobile Bindings.

The three parts of the library is now:

  • bUnit.core: The core library only contains code related to the general Blazor component model, i.e. it is not specific to the web version of Blazor.
  • bUnit.web: The web library, which has a dependency on core, provides all the specific types for rendering and testing Blazor web components.
  • bUnit.xUnit: The xUnit library, which has a dependency on core, has xUnit specific extensions to bUnit, that enable logging to the test output through the ILogger interface in .net core, and an extension to xUnit's test runners, that enable it to discover and run razor based tests defined in .razor files.

To keep things compatible with previous releases, an additional package is available, bUnit, which includes all of three libraries. That means existing users should be able to keep their single <PackageReference Include="bunit"> in their projects.

Discovery of Razor based tests

One of the pain points of writing Razor based tests in .razor files was that the individual tests was not correctly discovered. That meant that if had multiple tests in a file, you would not see them in Visual Studios Test Explorer individually, you could not run them individually, and error was not reported individually.

This has changed with the bUnit.xUnit library, that now includes a way for it to discover individual razor tests, currently either a <Fixture> or <SnapshotTest> inside test components defined in .razor files. It also enables you to navigate to the test by double clicking on it in the Test Explorer, and you can run each test individually, and see error reports individually.

WARNING: You still have to wait for the Blazor compiler to translate the .razor files into .cs files, before the tests show up in the Test Explorer, and the this can trip up the Test Explorer. So while this feature is a big improvement to razor based testing, it is still not perfect, and more works need to be done to refine it.

Strongly typed component parameters

If you prefer writing your tests in C# only, you will be happy to know that there is now a new strongly typed way to pass parameters to components, using a builder. E.g., to render a ContactInfo component:

var cut = RenderComponent<ContactInfo>(parameters => parameters
    .Add(p => p.Name, "Egil Hansen")
    .Add(p => p.Country, "Iceland")
);

There are a bunch of different Add methods available on the builder, that allows you to easily pass in a EventCallback, ChildContent, or RenderFragment.

The old way using the component parameter factory methods are still available if you prefer that syntax.

NOTE: The parameter builder API is experimental at this point, and will likely change.

Added

  • A new event, OnAfterRender, has been added to IRenderedFragmentBase, which IRenderedFragment inherits from. Subscribers will be invoked each time the rendered fragment is re-rendered. Related issue #118.
  • A new property, RenderCount, has been added to IRenderedFragmentBase, which IRenderedFragment inherits from. Its represents the number of times a rendered fragment has been rendered. Related issue #118.
  • A new event, OnMarkupUpdated, has been added to `IRenderedFra...
Read more