Testing
Vitest covers server loads, form actions, and authorization. Playwright exercises the application in Chromium. The current release has 40 unit tests and 39 browser tests; there is no numeric coverage threshold.
Commands
pnpm test
pnpm test:watch
pnpm exec vitest run "src/routes/(app)/users/users.test.ts"
pnpm test:e2e
pnpm check
pnpm lint
pnpm format:check Isolated unit tests
Name tests *.test.ts beside the route they cover. createTestDb() creates an
in-memory SQLite database. Mock the database module before dynamically importing a route; close the
test database after each test.
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
import { createTestDb, createTestUser, createMockLocals } from "#lib/server/db/test-utils.js";
let testDb: ReturnType<typeof createTestDb>;
vi.mock("#lib/server/db/index.js", () => ({
get db() { return testDb; },
}));
const { load } = await import("./+page.server.js");
describe("Users load", () => {
beforeEach(() => { testDb = createTestDb(); });
afterEach(() => { testDb.$client.close(); });
it("returns users without password hashes", async () => {
const adminId = await createTestUser(testDb, { role: "admin" });
const result = await load({
locals: createMockLocals(adminId, "admin"),
} as Parameters<typeof load>[0]);
expect(result.users).toHaveLength(1);
expect(result.users[0]).not.toHaveProperty("passwordHash");
});
}); Fixture helpers
await createTestUser(db, overrides)inserts a user and returns their ID. Its password ispassword123; its default role is viewer.createMockLocals(userId, role)builds locals; role defaults to admin, so pass the intended role explicitly in permission tests.createFormData(entries)accepts a record of string values.createMockRequest(formData)creates a POST request.
When changing schema.ts, also update SCHEMA_SQL in test-utils.ts. Test successful operations, invalid input, unauthenticated requests,
and every relevant role.
Browser tests
Name browser tests e2e/*.spec.ts. Install Chromium once:
pnpm exec playwright install chromium
pnpm test:e2e Playwright automatically creates and seeds .svelte-kit/e2e.db, builds the
application, and starts a fresh preview server on port 4173. It ignores your normal database path
and does not reuse another running server. Local runs use four workers; CI uses one worker and
retries failed tests twice.
Reuse login and heading helpers from e2e/helpers.ts. Failed-run reports appear in playwright-report/; traces are recorded on the first retry. Both report and result
directories are ignored by Git.
CI and deployment
The reusable .github/workflows/ci.yml workflow runs frozen installation, type
checking, lint, formatting, unit tests, and browser tests. Deployment waits for those checks,
builds for the production origin, and verifies the served commit at /api/health.