Add UI Tests Skill
Add Selenium WebDriver + xUnit UI tests for NovaTune's Vue SPAs, running against an Aspire-hosted backend with Vite dev servers.
Steps
Read the execution plan at tasks/add_ui_tests/main_exec.md for the full implementation specification including phases, code, and acceptance criteria.
Read the planning doc at tasks/add_ui_tests/main.md for architecture context and design rationale.
Check current state of the ui_tests directory and solution:
ls src/ui_tests/ — check if project already exists
- Check
src/NovaTuneApp/NovaTuneApp.sln for existing ui_tests entries
- Check Vue components for existing
data-testid attributes
Execute phases sequentially as defined in main_exec.md:
- Phase 0: Add
data-testid attributes to Vue components
- Phase 1: Bootstrap the xUnit + Selenium project
- Phase 2: Create fixtures (UiTestFixture, WebDriverFactory, UiTestBase)
- Phase 3: Player UI tests (auth, library, playlists)
- Phase 4: Admin UI tests (auth, dashboard)
- Phase 5: Gitignore + cleanup
- Phase 6: Verify full suite
Verify each phase passes its acceptance criteria before proceeding.
Key Patterns
Project Structure
src/ui_tests/NovaTuneApp.UiTests/
Fixtures/
UiTestFixture.cs # Aspire host + Vite processes + data seeding
WebDriverFactory.cs # ChromeDriver creation (headless by default)
TestCollections.cs # xUnit collection definition
Infrastructure/
WaitHelpers.cs # Explicit waits (never Thread.Sleep)
ScreenshotHelper.cs # Screenshot on failure
UiTestBase.cs # Base class with driver lifecycle + login helpers
Player/
PlayerAuthTests.cs # Login, register, redirect, error states
PlayerLibraryTests.cs # Track listing, empty state
PlayerPlaylistsTests.cs # Create playlist, empty state
Admin/
AdminAuthTests.cs # Admin login, non-admin rejection, register
AdminDashboardTests.cs # Stat cards, sidebar navigation
Test Convention
- Collection:
[Collection("UI Tests")] — shared fixture, no parallel execution
- Traits:
[Trait("Category", "UI")], [Trait("App", "Player")] or [Trait("App", "Admin")]
- Base class:
UiTestBase handles ChromeDriver lifecycle, ClearDataAsync(), screenshot-on-failure
- Login helpers:
PlayerLogin(email, password) and AdminLogin(email, password) in base class
- Selectors: Prefer
data-testid via WaitHelpers.WaitForTestId(), fall back to text via WaitHelpers.WaitForText()
- No
Thread.Sleep — only explicit WebDriverWait via WaitHelpers
Fixture Lifecycle
UiTestFixture (collection-level): Starts Aspire + 2 Vite servers once per test run
UiTestBase (per-class): Creates fresh ChromeDriver, clears DB, captures screenshot on failure
- Vite ports: 26173 (player), 26174 (admin) — offset from dev ports to avoid conflicts
VITE_API_BASE_URL injected into Vite processes pointing to test API
Data Seeding
SeedUserAsync(email, displayName, password) — register via API
SeedAdminUserAsync(email, displayName, password) — register + grant Admin role via RavenDB
SeedTracksForUserAsync(userId, count) — batch insert Track documents
ClearDataAsync() — wipe all users, tracks, playlists, audit logs
data-testid Conventions
- Auth forms:
email, password, login-button, register-button, displayName, confirmPassword
- Error states:
error-message, success-message
- Page headings:
library-heading, playlists-heading, dashboard-heading
- Empty states:
empty-state
- Interactive:
create-playlist-button, playlist-name-input, playlist-submit-button
- Lists:
track-list
Commands
# Build
dotnet build src/ui_tests/NovaTuneApp.UiTests/NovaTuneApp.UiTests.csproj
# Run all UI tests
dotnet test src/ui_tests/NovaTuneApp.UiTests/NovaTuneApp.UiTests.csproj -c Debug
# Player only
dotnet test src/ui_tests/NovaTuneApp.UiTests/NovaTuneApp.UiTests.csproj -c Debug \
--filter "Trait=App&Value=Player"
# Admin only
dotnet test src/ui_tests/NovaTuneApp.UiTests/NovaTuneApp.UiTests.csproj -c Debug \
--filter "Trait=App&Value=Admin"
# Headed mode (see browser)
UI_TESTS_HEADED=1 dotnet test src/ui_tests/NovaTuneApp.UiTests/NovaTuneApp.UiTests.csproj -c Debug
# Frontend lint/typecheck after adding data-testid
cd src/NovaTuneClient && pnpm lint && pnpm typecheck
Prerequisites
- Docker/Podman running (for Aspire infrastructure containers)
- Chrome/Chromium installed (Selenium Manager handles chromedriver)
pnpm install completed in src/NovaTuneClient/
- .NET 9 SDK installed
1---2name: add-ui-tests3description: Add Selenium-based UI tests for NovaTune player and admin Vue SPAs against Aspire backend4---5
6
7# Add UI Tests Skill
8
9Add Selenium WebDriver + xUnit UI tests for NovaTune's Vue SPAs, running against an Aspire-hosted backend with Vite dev servers.
10
11## Steps
12
131. **Read the execution plan** at `tasks/add_ui_tests/main_exec.md` for the full implementation specification including phases, code, and acceptance criteria.
14
152. **Read the planning doc** at `tasks/add_ui_tests/main.md` for architecture context and design rationale.
16
173. **Check current state** of the ui_tests directory and solution:
18 - `ls src/ui_tests/` — check if project already exists
19 - Check `src/NovaTuneApp/NovaTuneApp.sln` for existing ui_tests entries
20 - Check Vue components for existing `data-testid` attributes
21
224. **Execute phases sequentially** as defined in `main_exec.md`:
23 - Phase 0: Add `data-testid` attributes to Vue components
24 - Phase 1: Bootstrap the xUnit + Selenium project
25 - Phase 2: Create fixtures (UiTestFixture, WebDriverFactory, UiTestBase)
26 - Phase 3: Player UI tests (auth, library, playlists)
27 - Phase 4: Admin UI tests (auth, dashboard)
28 - Phase 5: Gitignore + cleanup
29 - Phase 6: Verify full suite
30
315. **Verify each phase** passes its acceptance criteria before proceeding.
32
33## Key Patterns
34
35### Project Structure
36```
37src/ui_tests/NovaTuneApp.UiTests/
38 Fixtures/
39 UiTestFixture.cs # Aspire host + Vite processes + data seeding
40 WebDriverFactory.cs # ChromeDriver creation (headless by default)
41 TestCollections.cs # xUnit collection definition
42 Infrastructure/
43 WaitHelpers.cs # Explicit waits (never Thread.Sleep)
44 ScreenshotHelper.cs # Screenshot on failure
45 UiTestBase.cs # Base class with driver lifecycle + login helpers
46 Player/
47 PlayerAuthTests.cs # Login, register, redirect, error states
48 PlayerLibraryTests.cs # Track listing, empty state
49 PlayerPlaylistsTests.cs # Create playlist, empty state
50 Admin/
51 AdminAuthTests.cs # Admin login, non-admin rejection, register
52 AdminDashboardTests.cs # Stat cards, sidebar navigation
53```
54
55### Test Convention
56- Collection: `[Collection("UI Tests")]` — shared fixture, no parallel execution
57- Traits: `[Trait("Category", "UI")]`, `[Trait("App", "Player")]` or `[Trait("App", "Admin")]`
58- Base class: `UiTestBase` handles ChromeDriver lifecycle, `ClearDataAsync()`, screenshot-on-failure
59- Login helpers: `PlayerLogin(email, password)` and `AdminLogin(email, password)` in base class
60- Selectors: Prefer `data-testid` via `WaitHelpers.WaitForTestId()`, fall back to text via `WaitHelpers.WaitForText()`
61- No `Thread.Sleep` — only explicit WebDriverWait via `WaitHelpers`
62
63### Fixture Lifecycle
64- `UiTestFixture` (collection-level): Starts Aspire + 2 Vite servers once per test run
65- `UiTestBase` (per-class): Creates fresh ChromeDriver, clears DB, captures screenshot on failure
66- Vite ports: 26173 (player), 26174 (admin) — offset from dev ports to avoid conflicts
67- `VITE_API_BASE_URL` injected into Vite processes pointing to test API
68
69### Data Seeding
70- `SeedUserAsync(email, displayName, password)` — register via API
71- `SeedAdminUserAsync(email, displayName, password)` — register + grant Admin role via RavenDB
72- `SeedTracksForUserAsync(userId, count)` — batch insert Track documents
73- `ClearDataAsync()` — wipe all users, tracks, playlists, audit logs
74
75### data-testid Conventions
76- Auth forms: `email`, `password`, `login-button`, `register-button`, `displayName`, `confirmPassword`
77- Error states: `error-message`, `success-message`
78- Page headings: `library-heading`, `playlists-heading`, `dashboard-heading`
79- Empty states: `empty-state`
80- Interactive: `create-playlist-button`, `playlist-name-input`, `playlist-submit-button`
81- Lists: `track-list`
82
83## Commands
84
85```bash
86# Build
87dotnet build src/ui_tests/NovaTuneApp.UiTests/NovaTuneApp.UiTests.csproj
88
89# Run all UI tests
90dotnet test src/ui_tests/NovaTuneApp.UiTests/NovaTuneApp.UiTests.csproj -c Debug
91
92# Player only
93dotnet test src/ui_tests/NovaTuneApp.UiTests/NovaTuneApp.UiTests.csproj -c Debug \
94 --filter "Trait=App&Value=Player"
95
96# Admin only
97dotnet test src/ui_tests/NovaTuneApp.UiTests/NovaTuneApp.UiTests.csproj -c Debug \
98 --filter "Trait=App&Value=Admin"
99
100# Headed mode (see browser)
101UI_TESTS_HEADED=1 dotnet test src/ui_tests/NovaTuneApp.UiTests/NovaTuneApp.UiTests.csproj -c Debug
102
103# Frontend lint/typecheck after adding data-testid
104cd src/NovaTuneClient && pnpm lint && pnpm typecheck
105```
106
107## Prerequisites
108
109- Docker/Podman running (for Aspire infrastructure containers)
110- Chrome/Chromium installed (Selenium Manager handles chromedriver)
111- `pnpm install` completed in `src/NovaTuneClient/`
112- .NET 9 SDK installed