Component callbacks allow developers to build Blazor components that fire events to their parent components/pages to notify them of state changes. The parent components can then respond to those changes as well. bUnit supports EventCallbacks
as parameters on those components, so that we can validate their behavior.
First, we must have a Blazor project and corresponding test project. Either open an existing solution or please follow the steps in the How-To: Add bUnit Test Project to Blazor Solution article to get both projects and all of the required packages. For this article, we called the projects: Blazor.HowTo and Blazor.HowTo.Tests.
Then, we need a Blazor component in our project. If we don’t already have one, we can create one using the steps in the How-To: Define EventCallback on Blazor Component article.
Component With EventCallback
Let’s review the markup and code from the component with EventCallback
article:
<div class="col-12 pt-1 rounded border"
style="background-color: lightgray; cursor: pointer"
@onclick="AdClicked">
<img class="float-left mr-2 mt-2 align-items-center" src="@ImageLink" />
<h5><strong>@Title</strong></h5>
<p style="font-size: small">
@ChildContent
</p>
</div>
@code {
[Parameter]
public string Title { get; set; }
[Parameter]
public string ImageLink { get; set; }
[Parameter]
public RenderFragment ChildContent { get; set; }
[Parameter]
public EventCallback AdClicked { get; set; }
}
As we can see, we defined an EventCallback
parameter that is invoked whenever the user clicks on the BannerAd
component.
Create Test Class
Now, let’s create the BannerAdTests
class in the Blazor.HowTo.Tests project and Components folder.
using Blazor.HowTo.Components;
using Bunit;
using Xunit;
namespace Blazor.HowTo.Tests.Components
{
public class BannerAdTests
{
[Fact]
public void InitialRender_WithEventCallback()
{
// arrange
var ctx = new TestContext();
var eventCalled = false;
// act
var comp = ctx.RenderComponent<BannerAd>(parameters => parameters
.Add(p => p.Title, "Test Ad")
.Add(p => p.ImageLink, "/foo/test.png")
.AddChildContent("Test <strong>ad</strong> description.")
.Add(p => p.AdClicked, () => { eventCalled = true; })
);
// assert
var expectedHtml =
@" <div class=""col-12 pt-1 rounded border""
style=""background-color: lightgray; cursor: pointer"">
<img class=""float-left mr-2 mt-2 align-items-center""
src=""/foo/test.png"">
<h5>
<strong>Test Ad</strong>
</h5>
<p style=""font-size: small"">Test <strong>ad</strong> description.</p>
</div>
";
comp.MarkupMatches(expectedHtml);
Assert.False(eventCalled);
}
[Fact]
public void AdClicked()
{
// arrange
var ctx = new TestContext();
var eventCalled = false;
var comp = ctx.RenderComponent<BannerAd>(parameters => parameters
.Add(p => p.Title, "Test Ad")
.Add(p => p.ImageLink, "/foo/test.png")
.AddChildContent("Test <strong>ad</strong> description.")
.Add(p => p.AdClicked, () => { eventCalled = true; }));
// act
comp.Find("div").Click();
// assert
Assert.True(eventCalled);
}
}
}
In the InitialRender_WithEventCallback
test method (lines #9-38), we set the component parameters on the RenderComponent
method (see the How-To: Write bUnit Tests for Components with Parameters article for details on that).
- In addition to normal parameters, we set the
AdClicked EventCallback
parameter as well (line #21). - In the event handler, we set the test’s
eventCalled
variable to true, so we know when theEventCallback
was invoked. - The
EventCallback
does not add any HTML to the expected markup. - The first test validates that the
EventCallback
was not invoked by checking thateventCalled
is still false.
In the AdClicked
test method (lines #40-58), we simulate the onclick
event within the BannerAd
component to validate that our event handler gets called.
- First, in the test setup, we render the component just like our first test… with
eventCalled
variable initialized to false, and theAdClicked EventCallback
parameter set. - Then, we use the
Find
method to retrieve the containerdiv
within ourBannerAd
markup (line #54).Find
uses the CSS naming convention to look up elements. - Next, we call the
Click
method to simulate theonclick
event on this element (line #54). - Finally, we validate that the
eventCalled
variable was changed in the event handler (line #75)… verifying that theEventCallback
was invoked. - Since this operations does not cause any change to the component’s HTML markup, we didn’t verify the markup.
These two tests verify that our EventCallback
was set up correctly and that it was invoked in response to an event within the BannerAd
component.
Finally, let’s launch the new tests in the Visual Studio TestExplorer and verify that they pass as we expect.
In conclusion, we can pass component EventCallbacks
as parameters in the bUnit TestContext.RenderComponent
method (just like any other component parameters). EventCallbacks
are invoked by either our code or in response to another component event. Our tests showed how to validate that those EventCallbacks
are called as expected.