npx skills add ...
npx skills add microsoft/aspire --skill dashboard-testing
Guide for writing tests for the Aspire Dashboard. Use this when asked to create, modify, or debug dashboard unit tests or Blazor component tests.
npx skills add microsoft/aspire --skill dashboard-testing
This skill provides patterns and practices for writing tests for the Aspire Dashboard. There are two test projects depending on whether the code under test uses Blazor types.
| Project | Location | Use When |
|---|---|---|
| Aspire.Dashboard.Tests | tests/Aspire.Dashboard.Tests/ | Testing code that does not use Blazor types (models, helpers, utils, OTLP services, middleware) |
| Aspire.Dashboard.Components.Tests | tests/Aspire.Dashboard.Components.Tests/ | Testing code that does use Blazor types (pages, components, controls). Uses bUnit for in-memory rendering |
The dashboard source code is in src/Aspire.Dashboard/. Key subdirectories:
Components/ — Blazor components (pages, controls, layout) → test in Components.TestsModel/ — View models, data models, helpers → test in Dashboard.TestsOtlp/ — OpenTelemetry protocol handling → test in Dashboard.TestsUtils/ — Utility and helper classes → test in Dashboard.TestsStandard xUnit tests for models, helpers, utilities, middleware, and services that don't depend on Blazor rendering.
Key points:
[Fact] for single test cases, [Theory] with [InlineData] for parameterized testsModelTestHelpers.CreateResource(...) from shared test utilities to build ResourceViewModel instancesMockKnownPropertyLookup) instead of mocking frameworksUses bUnit to render and test Blazor components in-memory without a browser.
All bUnit component tests must extend DashboardTestContext:
Dashboard services require extensive DI setup (telemetry, storage, localization, FluentUI JS interop mocks, etc.). Reuse existing shared setup methods to avoid duplicate registration logic. When adding tests for a new area, add a new setup helper rather than duplicating setup across test classes.
| Helper | Location | Purpose |
|---|---|---|
FluentUISetupHelpers.AddCommonDashboardServices() | Shared/FluentUISetupHelpers.cs | Registers core DI services shared by all dashboard pages (localization, storage, telemetry, theme, dialog, shortcuts, etc.) |
FluentUISetupHelpers.SetupFluentUIComponents() | Shared/FluentUISetupHelpers.cs | Calls AddFluentUIComponents() and configures the menu provider for tests |
FluentUISetupHelpers.SetupDialogInfrastructure() | Shared/FluentUISetupHelpers.cs | Combines common services + FluentUI components + dialog provider JS mocks |
FluentUISetupHelpers.SetupFluentDataGrid() | Shared/FluentUISetupHelpers.cs | Mocks FluentDataGrid JS interop |
FluentUISetupHelpers.SetupFluentSearch() | Shared/FluentUISetupHelpers.cs | Mocks FluentSearch JS interop |
FluentUISetupHelpers.SetupFluentMenu() | Shared/FluentUISetupHelpers.cs | Mocks FluentMenu JS interop |
ResourceSetupHelpers.SetupResourcesPage() | Shared/ResourceSetupHelpers.cs | Full setup for the Resources page |
ResourceSetupHelpers.SetupResourceDetails() | Shared/ResourceSetupHelpers.cs | Setup for ResourceDetails control |
MetricsSetupHelpers.SetupMetricsPage() | Shared/MetricsSetupHelpers.cs | Full setup for the Metrics page |
MetricsSetupHelpers.SetupChartContainer() | Shared/MetricsSetupHelpers.cs | Setup for chart container and Plotly |
StructuredLogsSetupHelpers.SetupStructuredLogsDetails() | Shared/StructuredLogsSetupHelpers.cs | Setup for structured log details |
IntegrationTestHelpers.CreateLoggerFactory() | Shared/IntegrationTestHelpers.cs | Creates ILoggerFactory wired to xUnit test output |
FluentUI Blazor components require JavaScript interop. bUnit runs without a browser, so all JS calls must be mocked. Use the helpers from FluentUISetupHelpers:
When testing a new component area, create a dedicated setup helper in Shared/:
Both test projects use hand-rolled fakes — no mocking framework is used. Cross-project fakes live in tests/Shared/ (e.g., TestDashboardClient, ModelTestHelpers), while bUnit-specific fakes live in tests/Aspire.Dashboard.Components.Tests/Shared/ (e.g., TestLocalStorage, TestTimeProvider).
| Fake | Purpose |
|---|---|
TestDashboardClient | Configurable IDashboardClient with channel providers for resources, console logs, interactions, and commands |
TestDialogService | Fake dialog service |
TestSessionStorage | In-memory session storage |
TestStringLocalizer | Pass-through string localizer |
TestDashboardTelemetrySender | No-op telemetry sender |
ModelTestHelpers.CreateResource() | Factory for building ResourceViewModel instances with sensible defaults |
TestDashboardClient is constructor-configurable with channel providers:
Create test resource view models with keyword arguments:
Use this when verifying the installed/released dashboard instead of the repo-local one.
Projects.Aspire_Dashboard for local dashboard development. Running an installed aspire CLI is not enough when the AppHost model already contains that local project.SkipDashboardProjectReference=true to opt out of the shared playground dashboard project reference, and point AspireDashboardPath at the installed bundle.Run aspire doctor --format json --non-interactive and use the first installation row, which represents the running CLI. Use canonicalPath together with route to locate its bundle root. If canonicalPath is absent, stop rather than guessing from path, which can be an unresolved package-manager symlink.
| Installation route | Bundle root |
|---|---|
script, pr, localhive | Parent of the directory containing canonicalPath |
winget, brew, dotnet-tool | Directory containing canonicalPath |
nix, other, or no sidecar | ASPIRE_HOME when set; otherwise ~/.aspire |
$dashboard, and its source must be aspire-managed (aspire-managed.exe on Windows), not Aspire.Dashboard.csproj.[UseCulture("en-US")] for Culture-Sensitive Component TestsApply [UseCulture("en-US")] to bUnit test classes that assert culture-sensitive formatting (for example, numbers or dates) so those tests run deterministically across environments:
Call existing helpers instead of duplicating DI registrations:
If testing a new page or component area, add a setup helper in Shared/ to consolidate the setup:
WaitForAssertion for Async State ChangesWhen component state updates happen asynchronously, use bUnit's WaitForAssertion:
Push changes through channels to simulate dashboard data updates:
Many dashboard pages require viewport information:
The project uses hand-rolled fakes: