akka-aspire-configurat…
Configure Akka.NET with .NET Aspire for local development and production deployments. Covers actor system setup, clustering, persistence, Akka.Management…
Write UI tests for Blazor applications (Server or WebAssembly) using Playwright. Covers navigation, interaction, authentication, selectors, and common Blazor-specific patterns.
$ npx -y skills add aaronontheweb/dotnet-skills --skill playwright-blazor --agent claude-codeHow it fires
How this skill gets triggered: by you, by Claude, or both.
/playwright-blazorContext preview
The summary Claude sees to decide when to auto-load this skill.
Write UI tests for Blazor applications (Server or WebAssembly) using Playwright. Covers navigation, interaction, authentication, selectors, and common Blazor-specific patterns.
name: playwright-blazor-testing description: Write UI tests for Blazor applications (Server or WebAssembly) using Playwright. Covers navigation, interaction, authentication, selectors, and common Blazor-specific patterns. invocable: false
Use this skill when:
1. **Wait for Rendering** - Blazor renders asynchronously; use proper wait strategies 2. **Test Attributes** - Use `data-test` or `data-testid` attributes for stable selectors 3. **Headless by Default** - Run tests headless in CI, headed for local debugging 4. **Handle Error UI** - Always check for `#blazor-error-ui` to catch unhandled exceptions 5. **Avoid Network Wait States** - Blazor navigation doesn't trigger network loads; wait for DOM changes 6. **Pin Browser Channels** - Use specific browser channels (msedge, chrome) for reproducibility
<ItemGroup> <PackageReference Include="Microsoft.Playwright" Version="*" /> <PackageReference Include="Microsoft.Playwright.MSTest" Version="*" /> <!-- OR for xUnit --> <PackageReference Include="xunit" Version="*" /> <PackageReference Include="xunit.runner.visualstudio" Version="*" /> </ItemGroup>
Before running tests, install Playwright browsers:
pwsh -Command "playwright install --with-deps"
using Microsoft.Playwright;
public class PlaywrightFixture : IAsyncLifetime
{
private IPlaywright? _playwright;
private IBrowser? _browser;
public IBrowser Browser => _browser
?? throw new InvalidOperationException("Browser not initialized");
public async Task InitializeAsync()
{
_playwright = await Playwright.CreateAsync();
_browser = await _playwright.Chromium.LaunchAsync(new()
{
Headless = true,
// For CI/debugging, you might want:
// Headless = Environment.GetEnvironmentVariable("CI") != null,
// SlowMo = 100 // Slow down actions for debugging
});
}
public async Task DisposeAsync()
{
if (_browser is not null)
await _browser.DisposeAsync();
_playwright?.Dispose();
}
}[Fact]
public async Task InitialPageLoad()
{
var page = await _fixture.Browser.NewPageAsync();
// First load is classic HTTP navigation
await page.GotoAsync("https://localhost:5001");
// Wait for Blazor to initialize
await page.WaitForSelectorAsync("h1:has-text('Welcome')");
Assert.True(await page.IsVisibleAsync("h1:has-text('Welcome')"));
}Blazor uses client-side routing, so subsequent navigations don't trigger page reloads:
[Fact]
public async Task InternalNavigation()
{
var page = await _fixture.Browser.NewPageAsync();
await page.GotoAsync("https://localhost:5001");
// Method 1: Click a navigation link
await page.GetByRole(AriaRole.Link, new() { Name = "Counter" })
.ClickAsync();
// Wait for the new page content (NOT network idle!)
await page.WaitForSelectorAsync("h1:has-text('Counter')");
// Method 2: Programmatic navigation (Blazor 8+)
await page.EvaluateAsync("window.Blazor.navigateTo('/fetchdata')");
await page.WaitForSelectorAsync("h1:has-text('Weather')");
// Method 3: Direct URL navigation (causes full reload)
await page.GotoAsync("https://localhost:5001/counter");
await page.WaitForSelectorAsync("h1:has-text('Counter')");
}// ❌ DON'T: Wait for network idle (Blazor doesn't reload pages)
await page.WaitForLoadStateAsync(LoadState.NetworkIdle);
// ✅ DO: Wait for specific DOM elements
await page.WaitForSelectorAsync("h1:has-text('My Page')");
// ✅ DO: Wait for element visibility
await page.Locator("[data-test='content']").WaitForAsync();
// ✅ DO: Wait for URL change
await page.WaitForURLAsync("**/counter");<!-- Add data-test attributes for stable selectors -->
<button data-test="submit-button" @onclick="HandleSubmit">
Submit
</button>
<input data-test="username-input" @bind="Username" />
<div data-test="result-container">
@Result
</div>[Fact]
public async Task FormSubmission()
{
var page = await _fixture.Browser.NewPageAsync();
await page.GotoAsync(baseUrl);
// Use GetByTestId for elements with data-test attributes
await page.GetByTestId("username-input").FillAsync("testuser");
await page.GetByTestId("password-input").FillAsync("password123");
await page.GetByTestId("submit-button").ClickAsync();
// Verify result
var result = await page.GetByTestId("result-container").TextContentAsync();
Assert.Contains("Success", result);
}[Fact]
public async Task LoginFlow()
{
var page = await _fixture.Browser.NewPageAsync();
await page.GotoAsync($"{baseUrl}/login");
// Fill login form
await page.FillAsync("input[name='username']", "alice");
await page.FillAsync("input[name='password']", "P@ssw0rd");
await page.ClickAsync("button[type='submit']");
// Wait for redirect to dashboard
await page.WaitForURLAsync("**/dashboard");
// Verify logged in
var username = await page.TextContenA comprehensive AI coding plugin with 30 skills and 5 specialized agents for professional .NET development. Battle-tested patterns from production systems covering C#, Akka.NET, Aspire, EF Core, testing, and performance optimization.
Configure Akka.NET with .NET Aspire for local development and production deployments. Covers actor system setup, clustering, persistence, Akka.Management…
Critical Akka.NET best practices including EventStream vs DistributedPubSub, supervision strategies, error handling, Props vs DependencyResolver, work…
Patterns for building entity actors with Akka.Hosting - GenericChildPerEntityParent, message extractors, cluster sharding abstraction, akka-reminders, and…
Akka.Management for cluster bootstrapping, service discovery (Kubernetes, Azure, Config), health checks, and dynamic cluster formation without static seed…
Write unit and integration tests for Akka.NET actors using modern Akka.Hosting.TestKit patterns. Covers dependency injection, TestProbes, persistence testing,…
Guidelines for making .NET libraries and applications trimming-safe and Native AOT compatible. Covers the trimming/AOT model, the MSBuild properties that…