Pourquoi tester automatiquement
Les tests automatisés détectent les régressions avant vos utilisateurs. Ils documentent le comportement attendu du code et permettent de refactorer en confiance.
Ce site satellite dispose de plus de 400 tests automatisés (unitaires et property-based). C’est le standard de qualité que Lueur Externe applique sur tous ses projets.
La pyramide des tests
╱╲
╱ E2E ╲ Peu, lents, coûteux
╱────────╲
╱ Intégration ╲ Modéré
╱──────────────╲
╱ Unitaires ╲ Beaucoup, rapides, peu coûteux
╱────────────────────╲
Tests unitaires (base)
Testent une fonction ou un module isolément :
import { describe, it, expect } from "vitest";
import { calculateReadingTime } from "../src/lib/reading-time";
describe("calculateReadingTime", () => {
it("returns 1 min for short content", () => {
const content = "Hello world ".repeat(50); // 100 mots
expect(calculateReadingTime(content)).toBe(1);
});
it("returns correct time for long content", () => {
const content = "word ".repeat(1000); // 1000 mots
expect(calculateReadingTime(content)).toBe(5);
});
});
Tests d’intégration (milieu)
Testent l’interaction entre plusieurs modules :
describe("Content pipeline", () => {
it("validates and transforms blog content", async () => {
const rawContent = loadFixture("blog/sample-article.md");
const validated = await validateContent(rawContent);
const transformed = await transformContent(validated);
expect(transformed.slug).toBeDefined();
expect(transformed.readingTime).toBeGreaterThan(0);
});
});
Tests E2E (sommet)
Testent le parcours utilisateur complet dans un navigateur :
import { test, expect } from "@playwright/test";
test("user can navigate to blog and read article", async ({ page }) => {
await page.goto("/fr/");
await page.click('a[href="/fr/blog/"]');
await expect(page.locator("h1")).toContainText("Blog");
await page.click(".post-card a");
await expect(page.locator("article")).toBeVisible();
});
Property-based testing
Au lieu de tester des cas spécifiques, testez des propriétés qui doivent toujours être vraies :
import { test, fc } from "@fast-check/vitest";
test.prop([fc.string()])("slug never contains uppercase", (input) => {
const slug = generateSlug(input);
expect(slug).toBe(slug.toLowerCase());
});
test.prop([fc.string().filter(s => s.length > 0)])("slug is never empty for non-empty input", (input) => {
const slug = generateSlug(input);
expect(slug.length).toBeGreaterThan(0);
});
C’est une technique que nous utilisons intensivement sur ce projet pour valider les fonctions de génération de slugs, de SEO et de validation de contenu.
Vitest : le test runner moderne
Vitest est notre choix chez Lueur Externe pour les projets TypeScript :
// vitest.config.ts
import { defineConfig } from "vitest/config";
export default defineConfig({
test: {
include: ["tests/**/*.test.ts", "tests/**/*.prop.ts"],
coverage: {
provider: "v8",
reporter: ["text", "html"],
},
},
});
Avantages de Vitest
- Compatible avec l’API Jest (migration facile)
- Support TypeScript natif
- Hot Module Replacement pour les tests
- Intégration Vite (même config que le projet)
Bonnes pratiques
Nommage
// ✅ Descriptif
it("returns 404 when article does not exist")
// ❌ Vague
it("works correctly")
Arrange-Act-Assert
it("calculates reading time correctly", () => {
// Arrange
const content = "word ".repeat(400);
// Act
const result = calculateReadingTime(content);
// Assert
expect(result).toBe(2);
});
Isolation
Chaque test doit être indépendant. Utilisez beforeEach pour réinitialiser l’état.
Intégration CI/CD
Exécutez les tests automatiquement à chaque commit :
test:
stage: test
script:
- npm ci
- npx vitest run --coverage
artifacts:
reports:
coverage_report:
coverage_format: cobertura
path: coverage/cobertura-coverage.xml
Conclusion
Les tests automatisés ne sont pas un luxe, c’est une nécessité pour tout projet professionnel. Ils réduisent les bugs, accélèrent le développement et documentent le code. Contactez Lueur Externe pour des projets testés et fiables.