encore-testing

Par encoredev · skills

Testez les APIs et services avec Vitest dans Encore.ts.

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

Tester les applications Encore.ts

Instructions

Encore.ts utilise les outils TypeScript standard pour les tests. La configuration recommandée est Vitest.

Configurer Vitest

npm install -D vitest

Ajoutez à package.json :

{
  "scripts": {
    "test": "vitest"
  }
}

Tester un endpoint 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!");
  });
});

Exécuter les tests

# Exécuter avec Encore (recommandé - configure l'infrastructure)
encore test

# Ou exécuter directement avec npm
npm test

L'utilisation de encore test est recommandée car elle :

  • Configure automatiquement les bases de données de test
  • Fournit une infrastructure isolée par test
  • Gère les dépendances de services

Tester avec des paramètres de requête

// 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();
  });
});

Tester les opérations de base de données

Encore fournit des bases de données de test isolées :

// user.test.ts
import { describe, it, expect, beforeEach } from "vitest";
import { createUser, getUser, db } from "./user";

describe("user operations", () => {
  beforeEach(async () => {
    // Nettoyer avant chaque 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");
  });
});

Tester les appels entre services

// 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 () => {
    // Les appels de service fonctionnent normalement dans les tests
    const order = await createOrder({
      userId: "user-123",
      items: [{ productId: "prod-1", quantity: 2 }],
    });

    expect(order.id).toBeDefined();
    expect(order.status).toBe("pending");
  });
});

Tester les cas d'erreur

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

Tester le 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();
  });
});

Tester les tâches Cron

Testez la fonction sous-jacente, pas l'horaire cron :

// cleanup.test.ts
import { describe, it, expect } from "vitest";
import { cleanupExpiredSessions } from "./cleanup";

describe("cleanup job", () => {
  it("removes expired sessions", async () => {
    // Créer d'abord quelques sessions expirées
    await createExpiredSession();

    // Appeler l'endpoint directement
    await cleanupExpiredSessions();

    // Vérifier que le nettoyage s'est produit
    const remaining = await countSessions();
    expect(remaining).toBe(0);
  });
});

Mocker les services externes

import { describe, it, expect, vi, beforeEach } from "vitest";
import { sendWelcomeEmail } from "./email";

// Mocker l'API externe
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);
  });
});

Configuration des tests

Créez vite.config.ts (requis pour les imports ~encore) :

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

Intégration VS Code

Installez l'extension Vitest et ajoutez à .vscode/settings.json :

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

Remarque : Pour l'explorateur de tests VS Code, désactivez le parallélisme au niveau des fichiers pour éviter les conflits de ports :

// vite.config.ts
export default defineConfig({
  // ...
  test: {
    fileParallelism: false,  // Désactiver pour VS Code
    // ...
  },
});

Réactivez pour CI : encore test --fileParallelism=true

Directives

  • Utilisez encore test pour exécuter les tests avec la configuration de l'infrastructure
  • Chaque fichier de test reçoit une transaction de base de données isolée (annulée après)
  • Testez les endpoints API en les appelant directement comme des fonctions
  • Les appels entre services fonctionnent normalement dans les tests
  • Mockez les dépendances externes (APIs tiers, services d'email, etc.)
  • Ne mockez pas l'infrastructure Encore (bases de données, Pub/Sub) - utilisez la vraie chose

Skills similaires