Files
portal/docs/ai/testing-patterns.md
T
NeilClack 9e9cabfb2b
Build and Push to Digital Ocean Container Registry / build-and-push (push) Successful in 1m42s
Build and Push to Digital Ocean Container Registry / migrate (push) Failing after 22s
Update docs and formatting; remove obsolete v2 schema doc
- Refresh AI guide docs (api, svelte-patterns, testing-patterns)
- Add API updates notes, drop the outdated portal_api_v2_schema.md
- Format package.json
2026-08-27 12:07:34 -05:00

242 lines
2.7 KiB
Markdown

# Testing Patterns
Only read this file when creating or modifying tests.
This project uses:
- Vitest
- Playwright browser testing
- Svelte Testing Library patterns through vitest/browser
---
# Test Philosophy
Tests should prove behavior.
Do not write tests that only confirm implementation details.
Every test must contain meaningful assertions.
A test without assertions fails because:
expect.requireAssertions is enabled.
---
# Test Locations
Tests are colocated with source files.
Client tests:
_.svelte.test.ts
_.svelte.spec.ts
Server tests:
_.test.ts
_.spec.ts
---
# Vitest Projects
There are two test environments.
## Client
Used for Svelte components.
Environment:
Playwright Chromium browser.
Used for:
- rendering
- user interaction
- form behavior
---
## Server
Used for:
- load functions
- actions
- server utilities
Environment:
Node.
---
# Before Each Test
Always reset mocks:
beforeEach(() => {
vi.clearAllMocks();
});
---
# Server Tests
Server route tests should cover:
- authenticated behavior
- unauthenticated behavior
- authorization rules
- successful operations
- failed operations
Mock:
- $lib/db
- authentication helpers
- external services
---
# Prisma Mocking
Mock only the methods used.
Example:
vi.mock('$lib/db', () => ({
prisma: {
proclamation: {
findMany: vi.fn(),
findUnique: vi.fn(),
create: vi.fn(),
update: vi.fn(),
delete: vi.fn()
}
}
}));
Do not create massive unused mocks.
---
# Authentication Testing
Use:
createLocals()
Examples:
Unauthenticated:
createLocals()
Authenticated:
createLocals(mockUser() as any)
Specific roles:
createLocals(
mockUser({ roleId: 4 }) as any
)
---
# Client Test Locators
Available:
getByRole
getByText
getByPlaceholder
getByAltText
getByTestId
Unavailable:
getByLabel
getByDisplayValue
---
# Role Queries
Always use exact regex names.
Preferred:
page.getByRole(
'textbox',
{ name: /^Name$/ }
)
Avoid:
page.getByRole(
'textbox',
{ name: 'Name' }
)
because substring matching can create strict-mode failures.
---
# Select Testing
Because selects use selected options instead of bind:value:
const element =
await page
.getByRole(
'combobox',
{ name: /^Frequency$/ }
)
.element();
expect(
(element as HTMLSelectElement).value
).toBe('2');
---
# Svelte Component Mocking
When mocking Svelte 5 components:
Use:
vi.mock('$lib/components/example.svelte', () => ({
default: ($anchor: Element) => {
const div = document.createElement('div');
$anchor.replaceWith(div);
}
}));
Imports using mocked modules must come after vi.mock().
If variables are needed inside mocks:
Use vi.hoisted().
---
# Test Completion Rule
After writing tests:
Run:
npm run test
If failures occur:
Fix them.
Do not report "tests added" without verifying they pass.