Comprehensive Playwright-based UI testing suite for verifying AdminUI functionality, DOM structure, CSS styling, and form interactions.
This testing suite is designed for:
- AI-Driven UI Verification: Quick validation of UI changes and styling
- Regression Testing: Ensure UI components work correctly after updates
- DOM Inspection: Understand component structure for debugging
- Form Behavior Testing: Verify form interactions without data modification
tools/ui-tests/
├── tests/
│ ├── auth.setup.ts # Authentication setup (run once)
│ ├── auth.verify.spec.ts # Verify authentication is working
│ ├── dom-inspection.spec.ts # DOM structure and CSS verification
│ ├── form-interactions.spec.ts # Non-destructive form testing
│ └── tmp/ # Disposable tests (gitignored)
│ ├── README.md # Guide for disposable tests
│ └── example-disposable.spec.ts # Example temporary test
├── screenshots/ # Test screenshots (gitignored)
├── .auth/ # Authentication state (gitignored)
├── .env # Environment variables (gitignored)
├── .env.example # Example environment variables
├── playwright.config.ts # Playwright configuration
├── package.json # Dependencies
└── README.md # This file
cd tools/ui-tests
npm installCopy .env.example to .env and fill in your credentials:
cp .env.example .envEdit .env:
TEST_USERNAME=your.email@example.com
TEST_PASSWORD=your_passwordEnsure the AdminUI is running (Docker or local):
# From project root
docker compose --profile all up -d
# OR run locally
cd src/AdminUI
dotnet runFirst time only (or when auth expires):
npx playwright test auth.setup.ts --headedThis saves your authenticated session to .auth/user.json.
# Run all tests (uses list reporter by default)
npx playwright test
# Run specific test file
npx playwright test auth.verify.spec.ts
# Run with UI (headed mode)
npx playwright test --headed
# Run with debug mode
npx playwright test --debug
# Create disposable test for quick debugging
npx playwright test tests/tmp/my-debug.spec.ts --headedNote: The project is configured to use --reporter=list by default for non-blocking output.
All production tests use the shared takeResponsiveScreenshots() utility for consistent naming and behavior:
Format: {device}-{resolution}-{name}.png
Example: mobile-375x667-page-load.png, tablet-768x1024-overflow.png
import { takeResponsiveScreenshots } from "../../utils/screenshot-helper";
// Takes screenshots across mobile, tablet, and desktop
await takeResponsiveScreenshots(
page,
"screenshots/notifications",
"page-load", // Automatically strips device prefixes (e.g., 'desktop-page-load' → 'page-load')
{
collapseSidebar: true, // Auto-collapse sidebar on mobile/tablet
waitForNetwork: false, // Optional: wait for networkidle
fullPage: true, // Full page screenshot
}
);Generated files:
mobile-375x667-page-load.png(iPhone SE)tablet-768x1024-page-load.png(iPad)desktop-1920x1080-page-load.png(Full HD)
Benefits:
- ✅ Consistent naming across all tests
- ✅ Automatically strips device prefixes from names (avoids redundancy)
- ✅ Automatic sidebar collapse on mobile/tablet
- ✅ Network settling and animation waits
- ✅ Single function call instead of 30+ lines of code
Purpose: Verify authentication is working correctly.
# Setup authentication (save session)
npx playwright test auth.setup.ts
# Verify authentication works
npx playwright test auth.verify.spec.tsWhat it tests:
- ✅ Login flow to SSW Identity
- ✅ Session persistence
- ✅ Access to protected pages
- ✅ Cookie validity
Purpose: Inspect and verify DOM structure and CSS styling.
npx playwright test dom-inspection.spec.tsWhat it tests:
- 🔍 Page structure and sections
- 🔍 Component hierarchy (MudBlazor)
- 🎨 CSS variable definitions
- 🎨 Focused input styling (smokey white background)
- 📦 Input field class structure
Use cases:
- Debugging CSS selector issues
- Verifying styling changes
- Understanding MudBlazor component structure
Purpose: Test form behavior without creating data.
npx playwright test form-interactions.spec.tsWhat it tests:
- 📝 Form field population
- ✅ Validation behavior
- 🔘 Radio button interactions
- 👁️ Conditional field visibility
- 🎯 Autocomplete dropdowns
Non-destructive: These tests fill forms but never submit them.
Purpose: Temporary tests for experimentation and debugging.
The tests/tmp/ folder is gitignored for disposable/temporary tests:
# Create a quick debugging test
npx playwright test tests/tmp/my-debug.spec.ts --headed
# Run example disposable test
npx playwright test tests/tmp/example-disposable.spec.tsUse cases:
- 🔬 Experimenting with new test approaches
- 🐛 Debugging specific UI issues
- 📸 Capturing screenshots for bug reports
- 📚 Learning Playwright syntax
- ⚡ Quick one-off verifications
See: tests/tmp/README.md for detailed guide on disposable tests
After making CSS changes:
# 1. Rebuild Docker container (if using Docker)
docker compose --profile all restart rewards-adminui
# 2. Run DOM inspection test
npx playwright test dom-inspection.spec.ts --headed
# 3. Check console output for CSS values
# Expected: background: rgb(247, 247, 247), color: rgb(0, 0, 0)# Create a temporary test file with screenshot helper
cat > tests/tmp/debug-issue.spec.ts << 'EOF'
import { test } from '@playwright/test';
import { takeResponsiveScreenshots } from '../../utils/screenshot-helper';
test.use({ storageState: '.auth/user.json' });
test('debug specific issue', async ({ page }) => {
await page.goto('https://localhost:7137/send-notification');
await page.waitForLoadState('networkidle');
// Take responsive screenshots with consistent naming
await takeResponsiveScreenshots(
page,
'screenshots/tmp',
'debug-issue',
{ collapseSidebar: true }
);
console.log('✅ Debug screenshots captured');
});
EOF
# Run it (list reporter by default, non-blocking)
npx playwright test tests/tmp/debug-issue.spec.ts --headed
# Delete when done (it's gitignored anyway!)
rm tests/tmp/debug-issue.spec.tsAfter UI changes:
npx playwright test form-interactions.spec.ts --headedWatch the test interact with the form automatically.
- Create a disposable test in
tests/tmp/or open an existing test file - Add inspection code for your element:
const myElement = page.locator("your-selector");
const classes = await myElement.getAttribute("class");
const styles = await myElement.evaluate((el) => ({
background: window.getComputedStyle(el).backgroundColor,
color: window.getComputedStyle(el).color,
}));
console.log("Classes:", classes);
console.log("Styles:", styles);- Run with
--headedto see it live:
npx playwright test dom-inspection.spec.ts --headedScreenshots are automatically saved to screenshots/ during test runs:
form-filled.png- Fully populated notification form- Test failure screenshots - Automatically captured on errors
Key settings:
- Base URL:
https://localhost:7137 - Timeout: 30 seconds
- Retries: 2 (for flaky tests)
- Screenshot on failure: Enabled
- Video on failure: Enabled
TEST_USERNAME=your.email@example.com # Required for auth
TEST_PASSWORD=your_password # Required for authtest.use({ storageState: ".auth/user.json" });This avoids re-authenticating for every test.
await page.goto("https://localhost:7137/your-page");
await page.waitForLoadState("networkidle");// ✅ Good: Use data-testid
await page.getByTestId("target-achievement").click();
// ✅ Good: Use aria-label
const input = page.locator('input[aria-label*="notification title"]');
// ❌ Avoid: Generic selectors
const input = page.locator("input").first();await page.click("button");
await page.waitForTimeout(300); // Wait for MudBlazor animationsconsole.log("✅ Verification passed");
console.log(`📊 Found ${count} elements`);
console.log(`🎨 Background color: ${bgColor}`);# Re-run auth setup
npx playwright test auth.setup.ts --headed# Run with debug mode to step through
npx playwright test --debug
# Run specific test with UI visible
npx playwright test form-interactions.spec.ts --headed# Force rebuild Docker container
cd ../..
docker compose --profile all down
docker compose --profile all build --no-cache rewards-adminui
docker compose --profile all up -d
# Wait for container to start
sleep 10
# Re-run tests
cd tools/ui-tests
npx playwright test dom-inspection.spec.ts- Run test with
--headedto see the page - Use browser DevTools to inspect element
- Check the actual selector:
// Debug selector
const element = page.locator("your-selector");
const count = await element.count();
console.log(`Found ${count} elements matching selector`);npx playwright test dom-inspection.spec.ts --grep "verify CSS styling"npx playwright test form-interactions.spec.ts --grep "conditional fields"# Run all non-destructive tests
npx playwright test --grep-invert "setup"- Non-Destructive: These tests never create or modify data
- Fast Feedback: Get immediate verification of UI changes
- AI-Friendly: Clear console output for automated analysis
- Maintainable: Tests focus on behavior, not implementation details
Last Updated: November 2025
Playwright Version: Latest
Target: AdminUI on https://localhost:7137