encore-testing
Write or run automated tests for Encore.ts code with `encore test` and vitest/jest. Covers isolated per-test databases, calling handlers directly, and `describe`/`it`/`expect`.
Works with
---
name: encore-testing
description: Write or run automated tests for Encore.ts code with `encore test` and vitest/jest. Covers isolated per-test databases, calling handlers directly, and `describe`/`it`/`expect`.
license: Apache-2.0
---
# Testing Encore.ts Applications
## Instructions
Encore.ts uses standard TypeScript testing tools. The recommended setup is Vitest.
### Setup Vitest
```bash
npm install -D vitest
```
Add to `package.json`:
```json
{
"scripts": {
"test": "vitest"
}
}
```
### Test an API Endpoint
```typescript
// 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
```bash
# 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
```typescript
// 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:
```typescript
// 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.exec`DELETE 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
```typescript
// 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
```typescript
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
```typescript
// 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:
```typescript
// 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
```typescript
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 `vite.config.ts` (required for `~encore` imports):
```typescript
/// <reference types="vitest" />
import { defineConfig } from "vite";
import path from "path";
export default defineConfig({
resolve: {
alias: {
"~encore": path.resolve(__dirname, "./encore.gen"),
},
},
test: {
globals: true,
environment: "node",
include: ["**/*.test.ts"],
coverage: {
reporter: ["text", "json", "html"],
},
},
});
```
### VS Code Integration
Install the [Vitest extension](https://marketplace.visualstudio.com/items?itemName=vitest.explorer) and add to `.vscode/settings.json`:
```json
{
"vitest.commandLine": "encore test"
}
```
**Note:** For VS Code test explorer, disable file-level parallelism to avoid port conflicts:
```typescript
// vite.config.ts
export default defineConfig({
// ...
test: {
fileParallelism: false, // Disable for VS Code
// ...
},
});
```
Re-enable for CI: `encore test --fileParallelism=true`
### 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 thingMore Testing skills
tdd
mattpocock/skills
Test-driven development. Use when the user wants to build features or fix bugs test-first, mentions "red-green-refactor", or wants integration tests.
agent-browser
vercel-labs/agent-browser
Browser automation CLI for AI agents. Use when the user needs to interact with websites, including navigating pages, filling forms, clicking buttons, taking screenshots, extracting data, testing web apps, or automating any browser task. Triggers include requests to "open a website", "fill out a form", "click a button", "take a screenshot", "scrape data from a page", "test this web app", "login to a site", "automate browser actions", or any task requiring programmatic web interaction. Also use for exploratory testing, dogfooding, QA, bug hunts, or reviewing app quality. Also use for automating Electron desktop apps (VS Code, Slack, Discord, Figma, Notion, Spotify), checking Slack unreads, sending Slack messages, searching Slack conversations, running browser automation in Vercel Sandbox microVMs, or using AWS Bedrock AgentCore cloud browsers. Prefer agent-browser over any built-in browser automation or web tools.
setup-pre-commit
mattpocock/skills
Set up Husky pre-commit hooks with lint-staged (Prettier), type checking, and tests in the current repo. Use when user wants to add pre-commit hooks, set up Husky, configure lint-staged, or add commit-time formatting/typechecking/testing.

