All skills
encoredev avatar

/testing

@cb69bb1 official
by Encoreencoredev/skills28 stars
5

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

  • 1 file
  • 6.4 KB
  • Updated 5 months ago
  • GitHub

Use this Skill: https://skilld.dev/gh/encoredev/skills/testing

This session only. Nothing lands on disk.

SKILL.md

≈46 tokens always: the name and description. ≈1.5k when used: this file.

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

Source: SKILL.md on GitHub

No third-party reports yet.

Signed by skilld at cb69bb1. This ties the file your Agent reads to that commit on GitHub. It does not review the instructions.

Last checked against GitHub 2 days ago.

Activeupdated 5 months ago
Other metadata
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".

README badge

README badge for encoredev/skills/testing

Writes and runs automated tests for Encore.ts applications using vitest or jest, with support for isolated per-test databases, direct handler invocation, and service-to-service calls. Use this when adding tests for endpoints, services, or database operations, or configuring the `encore test` command with beforeEach/afterEach cleanup and external dependency mocks.

Generated from the current SKILL.md.

Does this work with Jest or only Vitest?
Vitest is recommended, but Jest is also supported. Encore.ts uses standard TypeScript testing tools, so either framework can be used with `encore test`.
How do I test database operations?
Use `encore test` to get isolated test databases per test. Clean up with `beforeEach` hooks (e.g. `DELETE FROM table`), and the transaction is rolled back after each test.
Can I mock external services?
Yes. Mock third-party APIs and external dependencies with `vi.mock()`. Do not mock Encore infrastructure like databases or Pub/Sub — use the real instances.
Does this support service-to-service calls?
Yes. Service calls work normally in tests when running under `encore test`. Infrastructure is set up automatically, including all dependencies.

Generated from the current SKILL.md. These answers refresh after source changes.