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

2.7 KiB

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.