Blazor components and pages can have normal HTML hyperlinks and navigation driven in code. Both forms allow users to move between pages. Blazor has the NavigationManager
which allows our code to perform URL navigations. And, bUnit provides a mock NavigationManager
to allow test code to request a navigation without actually performing it. Under our test context, our code can call NavigateTo
and ensure the appropriate action was performed.
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 page in our project. If we don’t already have one, we can create one using the steps in the How-To: Create New Page in Blazor article. For this article, we called the page: PageWithNavLinks.
Page with Navigation
First, let’s create a page with some navigations (the PageWithNavLinks.razor file):
@page "/page-with-nav"
@inject NavigationManager nav;
<h3>Page With NavLinks</h3>
<a id="normal-link" href="page-1">Normal Link</a>
<button id="button-link" @onclick="@NavButtonClicked">Button link</button>
@code {
private void NavButtonClicked()
{
nav.NavigateTo("page-2");
}
}
- We start with defining the route for this page:
@page "/page-with-nav"
(line #1). - Then, we inject the
NavigationManager
class into our page (line #2). The@inject
directive finds the specified type in the ASP.NET Core dependency injection system, then retrieves an instance of that type, and places it in a property callednav
.NavigationManager
is placed into the DI container by default by ASP.NET Core. - First, we define a normal HTML hyperlink (line #6). When that link is clicked, the application navigates to page-1.
- Then, we define a button with an
onclick
event (line #7), which calls an event handler. - Finally, the
NavButtonClicked
event handler(lines #10-13) uses theNavigationManager
injected earlier to call itsNavigateTo
method. That operation navigates the application to page-2.
With this code in place, we now have a simple page with two methods of navigating to other pages.
Test Class
Now, let’s create the PageWithNavLinksTests
class in the Blazor.HowTo.Tests project and Pages folder. In that test class we will implement a couple of tests:
using Blazor.HowTo.Pages;
using Bunit;
using Microsoft.AspNetCore.Components;
using Microsoft.Extensions.DependencyInjection;
using Xunit;
namespace Blazor.HowTo.Tests.Pages
{
public class PageWithNavLinksTests
{
[Fact]
public void RenderHyperlinks()
{
// arrange
var ctx = new TestContext();
// act
var cut = ctx.RenderComponent<PageWithNavLinks>();
// assert
var expectedMarkup =
@" <h3>Page With NavLinks</h3>
<a id=""normal-link"" href=""page-1"">Normal Link</a>
<button id=""button-link"">Button link</button>
";
cut.MarkupMatches(expectedMarkup);
}
[Fact]
public void ButtonLinkClicked()
{
// arrange
var ctx = new TestContext();
var nav = ctx.Services.GetRequiredService<NavigationManager>();
var cut = ctx.RenderComponent<PageWithNavLinks>();
// act
cut.Find("#button-link").Click();
// assert
Assert.Equal("http://localhost/page-2", nav.Uri);
}
}
}
- The
RenderHyperlinks
test (lines #12-27) performs the usual component rendering test (that we’ve done in many articles). And, we verify that thehref
for our page link is formatted as expected. Blazor is responsible for taking the hyperlink and navigating appropriately, so we don’t need any further validation of the navigation. - The
ButtonLinkClicked
test (lines #30-43) performs the navigation check on the button click.- After defining the
TestContext
, we get access to theNavigationManager
from the context services. Notice that we didn’t have to place a testNavigationManager
into the services. bUnit actually places itsFakeNavigationManager
into the services list. - This subclass of
NavigationManager
overrides theNavigateToCore
method and only sets the newUri
property but doesn’t perform the actual navigation. - Then, we render the page.
- Next, we find the button on the page (using its id) and perform the
Click
action (this fires the button’sonclick
event). - Finally, we assert that the
NavigationManager.Uri
property matches our expected destination URL.
- After defining the
With both tests complete, we have covered both styles of navigation in our Blazor application. We have ensured that our click handling code is performing the navigation we expect.
Finally, let’s run the new tests in the Visual Studio TestExplorer and verify that they both pass as expected.
In conclusion, Blazor allows us to navigate between pages either using hyperlinks or the NavigationManager
. We can verify hyperlinks are correct with bUnit rendering tests. We can test code that navigates via the NavigationManager
by using the FakeNavigationManager
defined in the bUnit library. With both mechanisms, we can verify that our pages/components will navigate as expected.
This test covers all that is needed for navigation to work properly, except for one thing: It does not test that page-2 has the proper @page directive.
This is somewhat unfortunate, because if we want to verify a multi-page use case, we cannot guarantee that, if the use case’s test passes, the application will work correctly. We’d still need something like Cypress.
LikeLike