encore-testing — скилл для Claude Code: тесты Encore.ts
Помогает писать и запускать автотесты для Encore.ts через encore test и vitest или jest. Пригодится, когда нужно покрыть эндпоинт или сервис и не возиться с изолированными базами вручную.
npx skills add encoredev/skills --skill encore-testing -a claude-code
npx skills add encoredev/skills --skill testing -a claude-codeЧто делает encore-testing
Скилл описывает, как тестировать приложения на Encore.ts обычными инструментами TypeScript. Рекомендованная связка — Vitest: npm install -D vitest, скрипт test в package.json, запуск через encore test. Именно encore test поднимает тестовые базы и разводит инфраструктуру по тестам, поэтому он и стоит первым в примерах.
Внутри разобраны типовые сценарии: вызов хендлера напрямую с параметрами, проверка ошибок через APIError и код not_found, работа с базой в beforeEach и очистка таблиц, сервис-сервис вызовы, публикация событий и тесты cron-задач (там тестируется сама функция, а не расписание). Для ~encore импортов нужен vite.config.ts с алиасом на ./encore.gen.
Отдельный момент про авторизацию. Мок getAuthData работает только в том коде, который читает его напрямую в процессе теста. Вызовы через ~encore/clients идут через рантайм Encore, мок он не видит, и эндпоинт с auth: true упадёт с ошибкой про отсутствующую авторизацию. В этом случае данные авторизации передают явно вторым аргументом. Если гоняете тесты в VS Code, файловый параллелизм советуют отключить — иначе конфликтуют порты.
Какие задачи решает
- написать первый тест для эндпоинта Encore.ts
- настроить
encore testи vitest в проекте - поднять изолированную базу под каждый тест
- проверить ответ и код ошибки
APIError - протестировать эндпоинт с
auth: trueбез реального логина
Примеры запросов агенту
- напиши vitest-тест для эндпоинта getUser с параметром id
- настрой encore test и очистку таблицы users в beforeEach
- протестируй эндпоинт с auth: true, передав authData явно
Как установить encore-testing
1Через Skills CLI (Vercel)
npx skills add encoredev/skills --skill encore-testing -a claude-codenpx skills add encoredev/skills --skill testing -a claude-code2Вручную: положить файлы
~/.claude/skills/testing/SKILL.mdПапка скилла целиком; для одного проекта — .claude/skills/testing/
1Через Skills CLI (Vercel)
npx skills add encoredev/skills --skill testing -a codex2Вручную: положить файлы
.agents/skills/testing/SKILL.mdДля всех проектов — ~/.agents/skills/
1Через Skills CLI (Vercel)
npx skills add encoredev/skills --skill testing -a cursor2Вручную: положить файлы
.cursor/skills/testing/SKILL.mdCursor читает и .agents/skills/, и .claude/skills/
1GitHub CLI
gh skill install encoredev/skills testing2Вручную: положить файлы
.github/skills/testing/SKILL.md1Через Skills CLI (Vercel)
npx skills add encoredev/skills --skill testing -a gemini-cli2Командой платформы
gemini skills install https://github.com/encoredev/skills --path encore/testingВручную: положить файлы
.devin/skills/testing/SKILL.mdСтарый путь .windsurf/skills/ тоже читается
Через Skills CLI (Vercel)
npx skills add encoredev/skills --skill testing -a opencodeClaude.ai
Упакуйте папку в zip и загрузите в Settings → Capabilities → Skills
По шагам, с командами для каждой платформы: Как установить скилл в Claude Code: пять способов
Вопросы о encore-testing
Как установить encore-testing в Claude?
Через skills CLI: npx skills add encoredev/skills --skill encore-testing -a claude-code. После установки файл скилла лежит в ~/.claude/skills/testing/SKILL.md.
Что делает encore-testing?
Подсказывает агенту, как писать и запускать тесты для Encore.ts: вызов хендлеров напрямую, изолированные базы, моки внешних сервисов, проверка ошибок и авторизации.
Почему мок getAuthData не работает через ~encore/clients?
Такие вызовы идут через рантайм Encore, который мок не видит, и эндпоинт с auth: true падает. Данные авторизации передавайте явно: await user.follow({ username: "jake" }, { authData: { userID: "123" } }).
Исходный текст
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