Testing Guide¶
Run and write tests across the full stack.
Test Layers¶
The project has three testing layers:
| Layer | Backend | Frontend |
|---|---|---|
| Unit tests | xUnit + Moq + AwesomeAssertions | Vitest (jsdom) |
| Integration tests | xUnit + WebApplicationFactory | — |
| E2E tests | — | Playwright |
Backend Unit Tests¶
Framework: xUnit with Moq for mocking and AwesomeAssertions for assertions.
Project: UnicornTrails.API.Tests.Unit
Tests cover commands, queries, validators, and domain logic. Use Arrange/Act/Assert pattern. Shared test infrastructure (builders, factories, fakes) lives in the UnicornTrails.API.Tests.Infrastructure project.
Patterns¶
// Arrange
var handler = new CreateMarkerCommandHandler(context, dateTimeProvider);
var command = new CreateMarkerCommand(request);
// Act
var result = await handler.Handle(command, CancellationToken.None);
// Assert
result.Title.Should().Be(request.Title);
See Dev Environment Setup for commands.
Backend Integration Tests¶
Framework: xUnit with WebApplicationFactory for in-memory hosting.
Project: UnicornTrails.API.Tests.Integration
Tests exercise the full API stack including middleware, auth, rate limiting, and database. The test configuration uses:
- A dedicated
appsettings.Testing.jsonwith rate limiting disabled and test JWT keys - MinIO (via docker-compose) for object storage
- Test Cloudflare Turnstile secret key
- In-memory or test PostgreSQL database
Integration tests cover endpoint responses, authorization, validation, and error handling.
Frontend Unit Tests¶
Framework: Vitest with jsdom environment.
Directory: tests/unit/
Structure mirrors the source:
tests/unit/
├── api/ # API utility tests
├── hooks/ # Custom hook tests
├── setup.ts # Global test setup
├── stores/ # Zustand store tests
└── utils/ # Utility function tests
Patterns¶
// Utility functions
import { dateFormat } from "src/utils/dateFormat";
// -> tests/unit/utils/dateFormat.test.ts
// Hooks: renderHook + act
const { result } = renderHook(() => useSomeHook());
// Components: render + screen + userEvent
render(<MyComponent />);
await user.click(screen.getByRole("button"));
The setup file mocks global dependencies: localStorage, i18next, matchMedia, and animation frame functions.
Commands¶
npm run test:unit # Run all unit tests
npm run test:unit:watch # Watch mode
npm run test:unit:coverage # With coverage report
Frontend E2E Tests¶
Framework: Playwright with three projects:
| Project | Runs | Auth State |
|---|---|---|
auth-setup | Login flow first | Saves storage state |
unauthenticated | Auth-only specs | None |
chromium | All other specs | Uses saved user.json |
Structure¶
tests/e2e/
├── features/{feature}/
│ ├── {feature}.spec.ts
│ └── {feature}.page.ts
├── shared/
│ ├── fixtures/ # Auth setup
│ ├── data.helper.ts # Test data generators
│ ├── paths.helper.ts # Asset paths
│ ├── selectors.ts # Common selectors
│ └── timeouts.ts # Timeout constants
├── assets/ # Test images
└── .reports/ # Output (gitignored)
Key Patterns¶
- Self-cleaning tests: Every test creates, uses, then deletes entities via the UI
- Test data naming: Must use
E2E_{timestamp}_prefix viacreateTestName() - Page Object pattern: Page objects return values, assertions live in specs
- Selector priority:
getByRole>getByLabel>getByText>getByTestId
Commands¶
npm run test:e2e # Run all E2E tests
npm run test:e2e:ui # UI mode (debugging)
npm run test:e2e:headed # See browser window
npm run test:e2e -- --grep "delete" # Run matching tests
Prerequisites¶
- Backend running:
dotnet run --project UnicornTrails.API - Frontend running:
npm run dev .env.testwithE2E_BASE_URL,E2E_API_URL,E2E_USERNAME,E2E_PASSWORD
CI Test Execution¶
Tests run automatically in GitHub Actions:
| Check | Backend CI | Frontend CI |
|---|---|---|
| Build | dotnet build --warnaserror | npm run build |
| Lint | — | npm run lint |
| Type Check | — | npm run type-check |
| Unit Tests | dotnet test (+ coverage) | npm run test:unit |
| Integration Tests | dotnet test (+ coverage) | — |
| Vulnerability Scan | dotnet list package --vulnerable | npm audit --audit-level=high |
| Secret Scan | Gitleaks (shared workflow) | Gitleaks |
See CI/CD for pipeline configuration.
Related¶
- Dev Environment Setup — Local test commands
- CI/CD — Automated test execution in pipelines
- Validation Pattern — Test patterns for validators
- Hooks Pattern — Test patterns for hooks