Skip to main content

Testing

DaoFlow uses a multi-layer testing strategy.

Test Types

TypeToolDirectoryRuns
Unit testsBun test runnerpackages/*/src/*.test.tsbun run test
E2E testsPlaywrighte2e/bunx playwright test
Docs testsPlaywrighte2e/docs.spec.tsbunx playwright test --config playwright-docs.config.ts
Type checkingTypeScriptbun run typecheck

Running Tests

# All unit tests
bun run test

# Specific package
cd packages/server && bun test

# E2E tests (requires running infrastructure)
bunx playwright test

# Docs E2E tests
bunx playwright test --config playwright-docs.config.ts

# Type checking
bun run typecheck

Writing Unit Tests

Place test files next to the source:

server/src/authz.ts
server/src/authz.test.ts ← test file

Example:

import { test, expect, describe } from "bun:test";
import { hasScope, roleCapabilities } from "./authz";

describe("hasScope", () => {
test("owner has all scopes", () => {
const caps = roleCapabilities.owner;
expect(hasScope(caps, "deploy:start")).toBe(true);
expect(hasScope(caps, "terminal:open")).toBe(true);
});

test("viewer cannot deploy", () => {
const caps = roleCapabilities.viewer;
expect(hasScope(caps, "deploy:start")).toBe(false);
});
});

Writing E2E Tests

E2E tests use Playwright. See e2e/ for examples:

import { test, expect } from "@playwright/test";

test("can sign up and see dashboard", async ({ page }) => {
await page.goto("/auth/sign-up");
await page.fill('[name="email"]', "test@example.com");
await page.fill('[name="password"]', "secure-password");
await page.click('[type="submit"]');
await expect(page).toHaveURL(/dashboard/);
});

CI Integration

Tests run automatically in GitHub Actions on every push and pull request. The CI pipeline:

  1. Installs dependencies
  2. Runs type checking
  3. Runs unit tests
  4. Starts infrastructure (Postgres + Redis)
  5. Runs E2E tests
  6. Builds the docs site
  7. Runs docs E2E tests