Skip to main content
skill CX Codex

encore-testing — Claude Code skill: test Encore.ts apps

Guides your agent through writing and running automated tests for Encore.ts with encore test and vitest or jest. Useful when an endpoint or service needs coverage without hand-rolling test databases.

Install into Claude Code · Skills CLI (Vercel) All methods and platforms ↓
npx skills add encoredev/skills --skill encore-testing -a claude-code
npx skills add encoredev/skills --skill testing -a claude-code
Open on GitHub

What encore-testing does

The skill covers testing Encore.ts code with standard TypeScript tooling. Vitest is the recommended setup: npm install -D vitest, a test script in package.json, then encore test. Running through encore test is the preferred path because it provisions test databases and keeps infrastructure isolated per test.

Examples walk through the common cases: calling a handler directly with request parameters, asserting on APIError and its not_found code, cleaning tables in beforeEach, service-to-service calls, publishing events, and cron jobs (test the function, not the schedule). Imports from ~encore need a vite.config.ts with an alias pointing at ./encore.gen.

Auth is where it gets fiddly. Mocking getAuthData only affects code in the test process that reads it directly. Calls through ~encore/clients go via the Encore runtime, which never sees the mock, so an auth: true endpoint fails with an error about missing auth. Pass the auth data explicitly instead. In VS Code, file-level parallelism is worth turning off to avoid port conflicts.

What it helps with

  • write a first test for an Encore.ts endpoint
  • set up encore test with vitest
  • spin up an isolated database per test
  • assert on APIError codes and messages
  • test an auth: true endpoint without a real login

Example prompts for the agent

  • write a vitest test for the getUser endpoint with an id parameter
  • set up encore test and clean the users table in beforeEach
  • test the auth: true endpoint by passing authData explicitly

How to install encore-testing

1Skills CLI (Vercel)

npx skills add encoredev/skills --skill encore-testing -a claude-code
npx skills add encoredev/skills --skill testing -a claude-code

2Manually: put the files in place

~/.claude/skills/testing/SKILL.md

Copy the whole skill folder; for one project use .claude/skills/testing/

Step by step, with commands for each platform: How to install skills in Claude Code: five ways

Questions about encore-testing

How do I install encore-testing in Claude?

Use the skills CLI: npx skills add encoredev/skills --skill encore-testing -a claude-code. The skill file lands at ~/.claude/skills/testing/SKILL.md.

What does encore-testing do?

It tells the agent how to write and run Encore.ts tests: calling handlers directly, isolated test databases, mocking external services, and checking errors and auth.

Why does mocking getAuthData fail through ~encore/clients?

Those calls go through the Encore runtime, which does not see the mock, so an auth: true endpoint fails. Pass auth data explicitly: await user.follow({ username: "jake" }, { authData: { userID: "123" } }).

Source text

SKILL.md · Apache-2.0
---
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`.
when_to_use: >-
  User wants to add/write/fix a test, write a vitest or jest spec, test an endpoint or service, set up `encore test`, configure isolated test databases, write `beforeEach`/`afterEach` for db cleanup, mock external dependencies, or assert on API request/response behaviour. Trigger phrases: "write a test", "write a vitest test", "add tests for", "vitest", "jest", "encore test", "test the endpoint", "test the service", "integration test", "isolated database".
---

# 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: "[email protected]", name: "Test" });
    const retrieved = await getUser({ id: created.id });
    
    expect(retrieved.email).toBe("[email protected]");
  });
});
```

### 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 Authenticated Endpoints

Mock `getAuthData` to call `auth: true` endpoints directly as a given user:

```typescript
import { describe, it, expect, vi } from "vitest";
import * as auth from "~encore/auth";
import { getProfile } from "./api";

it("returns the caller's profile", async () => {
  vi.spyOn(auth, "getAuthData").mockImplementation(() => ({ userID: "123" }));
  const profile = await getProfile();
  expect(profile.id).toBe("123");
});
```

The mock only affects code in the test process that reads `getAuthData()` directly. Calls made through `~encore/clients` go through the Encore runtime, which does not see the mock, so an `auth: true` endpoint called that way fails with "endpoint requires auth but none provided". Pass the auth data explicitly instead:

```typescript
import { user } from "~encore/clients";

await user.follow({ username: "jake" }, { authData: { userID: "123" } });
```

### 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
import { defineConfig } from "vitest/config";
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 thing

© encoredev · Apache-2.0 · encoredev/skills

Similar skills

Everything for Testing and QA →

From the same set10

Project sponsors

Companies that keep this analytics open
Gold sponsor

Impressions, clicks and code copies — open statistics. We keep the numbers public for the same reason NeBlask itself is public. Become a sponsor