Skip to main content
MDCMS uses Bun’s built-in test runner for both unit and integration tests. This page covers how to run tests, write new ones, and manage database migrations.

Unit Tests

Unit tests live alongside source files with the *.test.ts suffix.
Pattern*.test.ts next to the source file
RunnerBun test (bun test)
Commandbun run unit
Per-packagebun nx test <package>
Unit tests cover config parsing, validation logic, contracts, SDK methods, and utility functions. They do not require any external services.
# Run all unit tests
bun run unit

# Run tests for a specific package
bun nx test shared
bun nx test sdk

Integration Tests

Integration tests exercise the full stack — API endpoints, authentication flows, database operations, and the content lifecycle.
RequiresDocker Compose services (PostgreSQL, Redis, MinIO)
Commandbun run integration
Integration tests require Docker services to be running. Start them before running:
docker compose -f docker-compose.dev.yml up -d
# Run all integration tests
bun run integration

CI Gates

The CI pipeline runs three sequential stages. All must pass before a PR can be merged.
1

Quality

Format check + TypeScript typecheck across all packages.
bun run quality
2

Unit tests

All unit tests across every package.
bun run unit
3

Integration tests

Full integration test suite. Requires Docker services.
bun run integration
The combined command that runs all three stages:
bun run ci:required
The pre-push git hook runs ci:required automatically before every push.

Writing Tests

Follow these principles when adding tests:
  1. Write the failing test first. Verify it actually fails before writing any implementation.
  2. Implement until the test passes. Do not modify the test to make it pass — fix the implementation.
  3. Test behavior, not implementation details. Assert on observable outcomes (return values, side effects, API responses), not internal state.
  4. Keep tests focused. Each test should verify one behavior. Use descriptive test names that explain the expected behavior.
import { describe, expect, test } from "bun:test";
import { parseConfig } from "./parse-config";

describe("parseConfig", () => {
  test("returns parsed config when input is valid", () => {
    const result = parseConfig({
      project: "my-site",
      serverUrl: "http://localhost:4000",
    });
    expect(result.project).toBe("my-site");
  });

  test("throws on missing project field", () => {
    expect(() => parseConfig({ serverUrl: "http://localhost:4000" })).toThrow();
  });
});
Run bun run unit during development for fast feedback. Save bun run integration for before pushing.

Database Migrations

MDCMS uses Drizzle ORM for database schema management. Migrations are generated from the schema definition and applied via Drizzle Kit.
1

Modify the schema

Edit the Drizzle schema file:
apps/server/src/lib/db/schema.ts
2

Generate migration

bunx drizzle-kit generate
This creates a new SQL migration file in the drizzle/ directory.
3

Review the generated SQL

Open the generated file in drizzle/ and verify the SQL matches your intent. Pay attention to destructive operations like column drops or type changes.
4

Apply locally

bunx drizzle-kit push
5

Test with existing data

Verify the migration works correctly against a database that already has data. Check that existing records are preserved and new constraints do not cause failures.
6

Commit together

Commit the schema change and the generated migration file in the same commit:
git add apps/server/src/lib/db/schema.ts drizzle/
git commit -m "feat(server): add webhook retry columns"
Always test migrations against a database with realistic data before deploying to production. A migration that works on an empty database may fail or corrupt data on a populated one.