mcpField
E
encore-testing

encore-testing

github.com/encoredevテスト・品質30801 回インストール2 日前に更新
リポジトリ

encore-testing について

encore-testingは、VitestでEncore.tsアプリをテストする開発者向けのスキルです。Encoreが用意するテスト基盤の利用方法と、エンドポイント、データベース、サービス呼び出し、認証、Pub/Sub、cronジョブ、外部依存関係のテストを扱います。

主な機能

  1. 01Vitestの設定とテスト実行
  2. 02Encore管理のテスト基盤
  3. 03エンドポイントとデータベースのテスト
  4. 04サービス呼び出しと認証のテスト
  5. 05Pub/Subとcron関数のテスト
  6. 06外部依存関係のモック

活用シーン

  1. 01関数を直接呼び出してエンドポイントをテスト
  2. 02分離されたテストでデータベース操作を検証
  3. 03認証が必要なエンドポイントの動作確認
  4. 04Pub/Subイベントとcron関数のテスト

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/encoredev/skills --skill encore-testing

インストール後、Claude Code で/encore-testingを入力して読み込まれたか確認します。

詳細

Encore.ts アプリケーションのテスト

手順

Encore.ts は標準的な TypeScript テストツールを使用します。推奨されるセットアップは Vitest です。

Vitest のセットアップ
npm install -D vitest

package.json に追加します:

{
  "scripts": {
    "test": "vitest"
  }
}
API エンドポイントのテスト
// 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 with Encore (recommended - sets up infrastructure)
encore test

# Or run directly with npm
npm test

encore test の使用が推奨されます。その理由は次のとおりです:

  • テストデータベースを自動的にセットアップします
  • テストごとに分離されたインフラストラクチャを提供します
  • サービスの依存関係を処理します
リクエストパラメータを使ったテスト
// 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();
  });
});
データベース操作のテスト

Encore は分離されたテストデータベースを提供します:

// 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]");
  });
});
サービス間呼び出しのテスト
// 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");
  });
});
エラーケースのテスト
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");
    }
  });
});
認証されたエンドポイントのテスト

getAuthData をモックして、指定したユーザーとして auth: true エンドポイントを直接呼び出します:

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");
});

このモックは、テストプロセス内で getAuthData() を直接読み取るコードにのみ影響します。~encore/clients を経由した呼び出しは Encore ランタイムを通り、このモックを認識しないため、その方法で呼び出された auth: true エンドポイントは「endpoint requires auth but none provided」で失敗します。代わりに認証データを明示的に渡してください:

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

await user.follow({ username: "jake" }, { authData: { userID: "123" } });
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();
  });
});
Cron ジョブのテスト

Cron スケジュールではなく、その基盤となる関数をテストします:

// 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);
  });
});
外部サービスのモック
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);
  });
});
テストの設定

vite.config.ts を作成します(~encore インポートに必要です):

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 統合

Vitest 拡張機能をインストールし、.vscode/settings.json に追加します:

{
  "vitest.commandLine": "encore test"
}

Note: VS Code のテストエクスプローラーでは、ポートの競合を避けるためにファイルレベルの並列処理を無効にしてください:

// vite.config.ts
export default defineConfig({
  // ...
  test: {
    fileParallelism: false,  // Disable for VS Code
    // ...
  },
});

CI では再度有効にします: encore test --fileParallelism=true

ガイドライン
  • インフラストラクチャのセットアップを伴うテストを実行するには encore test を使用します
  • 各テストファイルは分離されたデータベーストランザクションを取得します(テスト後にロールバックされます)
  • API エンドポイントは関数として直接呼び出してテストします
  • サービス間呼び出しはテスト内で通常どおり動作します
  • 外部依存関係(サードパーティ API、メールサービスなど)はモックします
  • Encore のインフラストラクチャ(データベース、Pub/Sub)はモックしないでください。本物を使用してください

コメント