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 is password123; 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.