Testing Encore.ts Applications
Instructions
Encore.ts uses standard TypeScript testing tools. The recommended setup is Vitest.
Setup Vitest
npm install -D vitest
Add to package.json :
{ "scripts": { "test": "vitest" } }
Test an API Endpoint
// api.test.ts import { describe, it, expect } from "vitest"; import { hello } from "./api";
describe("hello endpoint", () => { it("returns a greeting", async () => { const response = await hello(); expect(response.message).toBe("Hello, World!"); }); });
Run Tests
Run with Encore (recommended - sets up infrastructure)
encore test
Or run directly with npm
npm test
Using encore test is recommended because it:
-
Sets up test databases automatically
-
Provides isolated infrastructure per test
-
Handles service dependencies
Test with Request Parameters
// api.test.ts import { describe, it, expect } from "vitest"; import { getUser } from "./api";
describe("getUser endpoint", () => { it("returns the user by ID", async () => { const user = await getUser({ id: "123" }); expect(user.id).toBe("123"); expect(user.name).toBeDefined(); }); });
Test Database Operations
Encore provides isolated test databases:
// user.test.ts import { describe, it, expect, beforeEach } from "vitest"; import { createUser, getUser, db } from "./user";
describe("user operations", () => {
beforeEach(async () => {
// Clean up before each test
await db.execDELETE FROM users;
});
it("creates and retrieves a user", async () => { const created = await createUser({ email: "test@example.com", name: "Test" }); const retrieved = await getUser({ id: created.id });
expect(retrieved.email).toBe("test@example.com");
}); });
Test Service-to-Service Calls
// order.test.ts import { describe, it, expect } from "vitest"; import { createOrder } from "./order";
describe("order service", () => { it("creates an order and notifies user service", async () => { // Service calls work normally in tests const order = await createOrder({ userId: "user-123", items: [{ productId: "prod-1", quantity: 2 }], });
expect(order.id).toBeDefined();
expect(order.status).toBe("pending");
}); });
Test Error Cases
import { describe, it, expect } from "vitest"; import { getUser } from "./api"; import { APIError } from "encore.dev/api";
describe("error handling", () => { it("throws NotFound for missing user", async () => { await expect(getUser({ id: "nonexistent" })) .rejects .toThrow("user not found"); });
it("throws with correct error code", async () => { try { await getUser({ id: "nonexistent" }); } catch (error) { expect(error).toBeInstanceOf(APIError); expect((error as APIError).code).toBe("not_found"); } }); });
Test Pub/Sub
// notifications.test.ts import { describe, it, expect, vi } from "vitest"; import { orderCreated } from "./events";
describe("pub/sub", () => { it("publishes order created event", async () => { const messageId = await orderCreated.publish({ orderId: "order-123", userId: "user-456", total: 9999, });
expect(messageId).toBeDefined();
}); });
Test Cron Jobs
Test the underlying function, not the cron schedule:
// cleanup.test.ts import { describe, it, expect } from "vitest"; import { cleanupExpiredSessions } from "./cleanup";
describe("cleanup job", () => { it("removes expired sessions", async () => { // Create some expired sessions first await createExpiredSession();
// Call the endpoint directly
await cleanupExpiredSessions();
// Verify cleanup happened
const remaining = await countSessions();
expect(remaining).toBe(0);
}); });
Mocking External Services
import { describe, it, expect, vi, beforeEach } from "vitest"; import { sendWelcomeEmail } from "./email";
// Mock external API vi.mock("./external-email-client", () => ({ send: vi.fn().mockResolvedValue({ success: true }), }));
describe("email service", () => { it("sends welcome email", async () => { const result = await sendWelcomeEmail({ userId: "123" }); expect(result.sent).toBe(true); }); });
Test Configuration
Create vitest.config.ts :
import { defineConfig } from "vitest/config";
export default defineConfig({ test: { globals: true, environment: "node", include: ["**/*.test.ts"], coverage: { reporter: ["text", "json", "html"], }, }, });
Guidelines
-
Use encore test to run tests with infrastructure setup
-
Each test file gets an isolated database transaction (rolled back after)
-
Test API endpoints by calling them directly as functions
-
Service-to-service calls work normally in tests
-
Mock external dependencies (third-party APIs, email services, etc.)
-
Don't mock Encore infrastructure (databases, Pub/Sub) - use the real thing