Testing
Procella has two levels of testing: unit tests (320 tests across all packages) and E2E acceptance tests (89 tests exercising the full Pulumi CLI lifecycle).
Unit Tests
Section titled “Unit Tests”bun run check# or: bun testUnit tests use Bun’s built-in test runner (bun:test) with describe, test, expect, beforeAll, and afterAll. They run without any external dependencies (no database, no Docker).
Key test suites across packages:
| Package | Coverage |
|---|---|
packages/auth | Auth service (dev + Descope mock) |
packages/crypto | AES-256-GCM encryption, HKDF key derivation |
packages/storage | Local + S3 blob storage |
packages/stacks | Stack CRUD operations |
packages/updates | Update lifecycle, GC worker |
apps/server | HTTP handlers, middleware, route matching |
apps/api | tRPC procedures (stacks, updates, events) |
Running Specific Tests
Section titled “Running Specific Tests”# Run tests in a specific packagebun test --cwd packages/crypto
# Run tests matching a patternbun test --filter "encrypt"E2E Acceptance Tests
Section titled “E2E Acceptance Tests”bun run e2eE2E tests exercise the full Pulumi CLI lifecycle against a real Procella server. They require:
- PostgreSQL (started via
docker compose up -d) - Pulumi CLI installed
PROCELLA_DATABASE_URLenvironment variable
Test Files
Section titled “Test Files”| File | Coverage |
|---|---|
e2e/setup.ts | Test infrastructure, server setup/teardown |
e2e/login.test.ts | pulumi login validation |
e2e/healthz.test.ts | Health endpoint |
e2e/stacks.test.ts | Create, list, get, delete stacks |
e2e/rename.test.ts | Stack rename operations |
e2e/updates.test.ts | Full update flow: create → start → checkpoint → events → complete |
e2e/state.test.ts | Export, import, versioned export |
e2e/encryption.test.ts | Secret encryption/decryption |
e2e/cancel.test.ts | Update cancellation + GC |
e2e/examples.test.ts | Real Pulumi YAML programs (pulumi-random, pulumi-command) |
Test Count
Section titled “Test Count”89 tests covering the full Pulumi CLI lifecycle, multi-tenant isolation, and edge cases.
Example Programs
Section titled “Example Programs”The e2e/examples.test.ts file deploys real Pulumi YAML programs from the examples/ directory using:
- pulumi-random — generates random resources (no cloud provider needed)
- pulumi-command — runs local shell commands
This validates the complete update lifecycle end-to-end without requiring cloud provider credentials.
Quality Gates
Section titled “Quality Gates”bun run check # Biome lint + typecheck + 320 unit testsbun run e2e # 89 E2E acceptance testsbun run check:all # check + e2eWriting New Tests
Section titled “Writing New Tests”Unit Test Pattern
Section titled “Unit Test Pattern”import { describe, expect, test } from "bun:test";
describe("MyFeature", () => { test("handles valid input", () => { const result = myFeature("foo"); expect(result).toBe("bar"); });
test("rejects empty input", () => { expect(() => myFeature("")).toThrow(); });});E2E Test Pattern
Section titled “E2E Test Pattern”E2E tests use bun:test and interact with the server via HTTP or the Pulumi CLI:
import { describe, expect, test } from "bun:test";import { pulumiCli, serverUrl } from "./helpers";
describe("MyE2EFeature", () => { test("works end-to-end", async () => { const result = await pulumiCli(["stack", "ls", "--json"]); expect(result.exitCode).toBe(0); });});Running a Subset
Section titled “Running a Subset”# Run a specific test filebun test e2e/stacks.test.ts
# Run tests matching a patternbun test --filter "stack lifecycle"