Table of Contents

Faking persistent component state

bUnit comes with fake version of the PersistentComponentState type in Blazor that makes it possible to test components that use the type.

Using the fake PersistentComponentState

To use the fake PersistentComponentState in bUnit, call the AddFakePersistentComponentState extension method on TestContext:

var fakeState = this.AddFakePersistentComponentState();

Calling AddFakePersistentComponentState returns a FakePersistentComponentState type, which has three methods; one to persist data, one to get persisted data, and one that triggers any "OnPersisting" callbacks added to the PersistentComponentState.

To add data to the PersistentComponentState before running a test, i.e. to verify that a component uses the persisted state, use the Persist method:

var fakeState = this.AddFakePersistentComponentState();
var key = "STATE KEY";
var data = ...; // data to persist

fakeState.Persist(key, data);

// render component

To trigger a callback registered with the PersistentComponentState.RegisterOnPersisting method, use the TriggerOnPersisting method on FakePersistentComponentState:

var fakeState = this.AddFakePersistentComponentState();

// render component

fakeState.TriggerOnPersisting();

To check if data has been persisted, use the TryTake method:

var fakeState = this.AddFakePersistentComponentState();
var key = "STATE KEY";

// render component, call TriggerOnPersisting

bool foundState = fakeState.TryTake<string>(key, out var data);

The following section has a complete example.

Example - testing the <FetchData> component

In this example, lets test the following <FetchData> component that use PersistentComponentState:

@page "/fetchdata"
@inject PersistentComponentState State

@foreach (var f in Forecasts)
{
  <p>@f.Temperature</p>
}

@code {
  private WeatherForecast[] Forecasts { get; set; }

  protected override async Task OnInitializedAsync()
  {
    State.RegisterOnPersisting(PersistForecasts);
    
    if (!State.TryTakeFromJson<WeatherForecast[]>("weather-data", out var forecasts))
    {
        forecasts = await CreateForecastsAsync();
    }
    
    Forecasts = forecasts;
  }

  private Task PersistForecasts()
  {
    State.PersistAsJson("weather-data", Forecasts);
    return Task.CompletedTask;
  }

  // Emulates calling an API or database to get forecasts
  private Task<WeatherForecast[]> CreateForecastsAsync() =>
    new WeatherForecast[] { ... };
}

To test that the <FetchData> component uses persisted weather data instead of downloading (generating) it again with the CreateForecastsAsync method, use the Persist method on the FakePersistentComponentState type:

// Arrange
var fakeState = this.AddFakePersistentComponentState();

// Persist a single weather forecast with a temperature of 42
fakeState.Persist("weather-data", new [] { new WeatherForecast { Temperature = 42 } });

// Act
var cut = RenderComponent<FetchData>();

// Assert - verify that the persisted forecast was rendered out
cut.MarkupMatches("<p>42</p>");

To test that the <FetchData> component correctly persists weather data when its OnPersisting callback is triggered, do the following:

// Arrange
var fakeState = this.AddFakePersistentComponentState();
var cut = RenderComponent<FetchData>();

// Act - trigger the FetchData components PersistForecasts method
fakeState.TriggerOnPersisting();

// Assert that state was saved and there is a non-empty forecast array returned
var didSaveState = fakeState.TryTake<WeatherForecast[]>("weather-data", out var savedState);
Assert.IsTrue(didSaveState);
Assert.NotEmpty(savedState);
Progress Telerik

Premium sponsor: Progress Telerik.

Packt

Editorial support provided by Packt.

.NET Foundation

Supported by the .NET Foundation.