sorcha-ui
npx skills add https://github.com/stuartf303/sorcha --skill sorcha-ui
Agent 安装分布
Skill 文档
Sorcha UI Development Skill
Test-driven UI development for Sorcha.UI. Every page change is paired with Playwright E2E tests that run against the Docker environment (docker-compose up -d). Tests automatically validate console errors, network failures, MudBlazor CSS health, and take screenshots on failure.
Prerequisites
Docker must be running with all services:
docker-compose up -d
# UI at http://localhost:5400 | API Gateway at http://localhost:80
# Login: admin@sorcha.local / Dev_Pass_2025!
Workflow: Building a Page
For every page you build or modify, follow these steps in order:
Step 1: Create the Page Object
Create tests/Sorcha.UI.E2E.Tests/PageObjects/{PageName}Page.cs:
using Microsoft.Playwright;
using Sorcha.UI.E2E.Tests.Infrastructure;
using Sorcha.UI.E2E.Tests.PageObjects.Shared;
namespace Sorcha.UI.E2E.Tests.PageObjects;
public class WalletListPage
{
private readonly IPage _page;
public WalletListPage(IPage page) => _page = page;
// Use data-testid as primary selector strategy
public ILocator WalletCards => MudBlazorHelpers.TestIdPrefix(_page, "wallet-card-");
public ILocator CreateButton => MudBlazorHelpers.TestId(_page, "create-wallet-btn");
public ILocator EmptyState => MudBlazorHelpers.TestId(_page, "wallet-empty-state");
public ILocator SearchInput => _page.Locator("input[placeholder*='Search']");
// Fallback to MudBlazor class selectors
public ILocator Table => MudBlazorHelpers.Table(_page);
public ILocator LoadingSpinner => MudBlazorHelpers.CircularProgress(_page);
public async Task NavigateAsync()
{
await _page.GotoAsync($"{TestConstants.UiWebUrl}{TestConstants.AuthenticatedRoutes.Wallets}");
await _page.WaitForLoadStateAsync(LoadState.NetworkIdle);
await MudBlazorHelpers.WaitForBlazorAsync(_page);
}
public async Task<int> GetWalletCountAsync() => await WalletCards.CountAsync();
public async Task<bool> IsEmptyStateVisibleAsync() =>
await EmptyState.CountAsync() > 0 && await EmptyState.IsVisibleAsync();
}
Step 2: Write the Playwright Tests (Test-First)
Create tests/Sorcha.UI.E2E.Tests/Docker/{Feature}Tests.cs:
using Sorcha.UI.E2E.Tests.Infrastructure;
using Sorcha.UI.E2E.Tests.PageObjects;
namespace Sorcha.UI.E2E.Tests.Docker;
[Parallelizable(ParallelScope.Self)]
[TestFixture]
[Category("Docker")]
[Category("Wallets")]
[Category("Authenticated")]
public class WalletListTests : AuthenticatedDockerTestBase
{
private WalletListPage _walletList = null!;
[SetUp]
public override async Task BaseSetUp()
{
await base.BaseSetUp();
_walletList = new WalletListPage(Page);
}
[Test]
[Retry(2)]
public async Task WalletList_LoadsWithoutErrors()
{
await NavigateAuthenticatedAsync(TestConstants.AuthenticatedRoutes.Wallets);
// Base class automatically checks console errors, network 5xx, CSS health
}
[Test]
public async Task WalletList_ShowsEmptyStateOrWallets()
{
await _walletList.NavigateAsync();
var count = await _walletList.GetWalletCountAsync();
if (count == 0)
{
Assert.That(await _walletList.IsEmptyStateVisibleAsync(), Is.True,
"Empty system should show empty state message");
}
else
{
Assert.That(count, Is.GreaterThan(0));
}
}
}
Step 3: Build the Blazor Page
Edit src/Apps/Sorcha.UI/Sorcha.UI.Web.Client/Pages/{Page}.razor:
@page "/wallets"
@layout MainLayout
@rendermode @(new InteractiveWebAssemblyRenderMode(prerender: false))
@attribute [Authorize]
@inject HttpClient Http
<PageTitle>Wallets - Sorcha</PageTitle>
@if (_isLoading)
{
<MudProgressCircular Indeterminate="true" data-testid="wallet-loading" />
}
else if (_wallets.Count == 0)
{
<MudAlert Severity="Severity.Info" data-testid="wallet-empty-state">
No wallets found. Create your first wallet to get started.
</MudAlert>
}
else
{
@foreach (var wallet in _wallets)
{
<MudCard data-testid="wallet-card-@wallet.Id" Class="mb-3">
<MudCardContent>
<MudText Typo="Typo.h6">@wallet.Name</MudText>
</MudCardContent>
</MudCard>
}
}
<MudButton data-testid="create-wallet-btn" Variant="Variant.Filled"
Color="Color.Primary" Href="wallets/create">
Create Wallet
</MudButton>
Step 4: Run Tests
# Run tests for the feature you just built
dotnet test tests/Sorcha.UI.E2E.Tests --filter "Category=Wallets"
# Run all smoke tests (fast CI gate)
dotnet test tests/Sorcha.UI.E2E.Tests --filter "Category=Smoke"
# Run all Docker tests
dotnet test tests/Sorcha.UI.E2E.Tests --filter "Category=Docker"
Step 5: Check Artifacts on Failure
Screenshots are saved to tests/Sorcha.UI.E2E.Tests/bin/Debug/net10.0/screenshots/ on any test failure. Console errors and network failures are reported in the test output.
Key Concepts
| Concept | Usage | Location |
|---|---|---|
DockerTestBase |
Unauthenticated tests with auto error capture | Infrastructure/DockerTestBase.cs |
AuthenticatedDockerTestBase |
Login once, reuse auth state across tests | Infrastructure/AuthenticatedDockerTestBase.cs |
TestConstants |
URLs, credentials, routes, timeouts | Infrastructure/TestConstants.cs |
| Page Objects | Encapsulate selectors and actions per page | PageObjects/*.cs |
MudBlazorHelpers |
Shared MudBlazor locators and layout validation | PageObjects/Shared/MudBlazorHelpers.cs |
data-testid |
Primary selector strategy for resilient tests | Added to Razor components |
| Categories | Filter tests by feature or concern | [Category("Wallets")] on test classes |
Test Inheritance
PageTest (Playwright NUnit)
âââ DockerTestBase (console errors, network failures, screenshots)
âââ ComponentHealthTests, LoginTests (unauthenticated)
âââ AuthenticatedDockerTestBase (login once, reuse state, layout health)
âââ DashboardTests
âââ NavigationTests
âââ WalletTests
âââ ... (one per feature area)
Test Categories
| Category | Scope | Use |
|---|---|---|
Smoke |
All pages load, no JS errors | CI gate |
Docker |
All tests targeting Docker | Full Docker suite |
Auth |
Login, logout, redirects | Authentication features |
Authenticated |
All tests needing login | Post-login features |
Dashboard |
Dashboard page | Dashboard development |
Navigation |
Drawer, app bar, routing | Layout changes |
Components |
CSS, MudBlazor, responsive | Style/component changes |
Wallets |
Wallet pages | Wallet features |
Blueprints |
Blueprint pages | Blueprint features |
Registers |
Register pages | Register features |
Schemas |
Schema library | Schema features |
Admin |
Administration pages | Admin features |
File Locations
| What | Where |
|---|---|
| Blazor pages | src/Apps/Sorcha.UI/Sorcha.UI.Web.Client/Pages/ |
| Shared components | src/Apps/Sorcha.UI/Sorcha.UI.Core/ |
| Layout | src/Apps/Sorcha.UI/Sorcha.UI.Web.Client/Components/Layout/ |
| Test infrastructure | tests/Sorcha.UI.E2E.Tests/Infrastructure/ |
| Page objects | tests/Sorcha.UI.E2E.Tests/PageObjects/ |
| Docker tests | tests/Sorcha.UI.E2E.Tests/Docker/ |
| MudBlazor helpers | tests/Sorcha.UI.E2E.Tests/PageObjects/Shared/MudBlazorHelpers.cs |
See Also
Related Skills
- See the blazor skill for Blazor WASM component architecture
- See the playwright skill for Playwright API reference
- See the frontend-design skill for MudBlazor styling
- See the minimal-apis skill for backend API endpoints the pages call
- See the jwt skill for authentication token handling
Documentation Resources
Fetch latest Playwright .NET and MudBlazor documentation with Context7.
Library IDs:
/websites/playwright_dev_dotnet(Playwright .NET)/websites/mudblazor(MudBlazor component library)
Recommended Queries:
- “Locators selectors data-testid”
- “NUnit test fixtures parallel”
- “MudBlazor card table dialog”
- “MudBlazor form validation”
- “Browser storage state authentication”