encore-testing

Test APIs and services with Vitest in Encore.ts.

INSTALLATION
npx skills add https://github.com/encoredev/skills --skill encore-testing
Run in your project or agent environment. Adjust flags if your CLI version differs.

SKILL.md

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.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

// 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 vite.config.ts (required for ~encore imports):

/// <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 and add to .vscode/settings.json:

{

  "vitest.commandLine": "encore test"

}

Note: For VS Code test explorer, disable file-level parallelism to avoid port conflicts:

// 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
BrowserAct

Let your agent run on any real-world website

Bypass CAPTCHA & anti-bot for free. Start local, scale to cloud.

Explore BrowserAct Skills →

Stop writing automation&scrapers

Install the CLI. Run your first Skill in 30 seconds. Scale when you're ready.

Start free
free · no credit card