Aller au contenu principal

Stratégies de Test

Guide complet pour tester votre intégration avec l'API MONCRENEAU.

1. Tests Unitaires

Tester les fonctions critiques en isolation.

Exemple: Vérification de Signature Webhook

const crypto = require('crypto');
const { verifyWebhookSignature } = require('../lib/webhooks');

describe('verifyWebhookSignature', () => {
const secret = 'your_secret_key';
const payload = JSON.stringify({
id: 'evt_123',
type: 'appointment.created'
});

it('should return true for valid signature', () => {
const signature = 'sha256=' + crypto
.createHmac('sha256', secret)
.update(payload)
.digest('hex');

const result = verifyWebhookSignature(payload, signature, secret);
expect(result).toBe(true);
});

it('should return false for invalid signature', () => {
const result = verifyWebhookSignature(payload, 'sha256=invalid', secret);
expect(result).toBe(false);
});

it('should return false for missing signature', () => {
const result = verifyWebhookSignature(payload, null, secret);
expect(result).toBe(false);
});
});

Exemple: Gestion des Crédits

const { canCreateAppointment } = require('../lib/credits');

describe('canCreateAppointment', () => {
it('should allow creation with sufficient credits', async () => {
const org = { id: 1, availableCredits: 10 };
const result = await canCreateAppointment(org);
expect(result).toBe(true);
});

it('should block creation with insufficient credits', async () => {
const org = { id: 1, availableCredits: 0 };
const result = await canCreateAppointment(org);
expect(result).toBe(false);
});
});

2. Tests d'Intégration

Tester avec la vraie API.

Configuration

[object Object]

Exemple: Création de Rendez-vous

[object Object]

3. Tests de Webhooks

Option A: Serveur Local avec ngrok

# 1. Installer ngrok
npm install -g ngrok

# 2. Démarrer votre serveur local
npm start # Port 3000

# 3. Exposer avec ngrok
ngrok http 3000

# 4. Configurer l'URL webhook
# https://abc123.ngrok.io/webhooks/moncreneau

Option B: Tests Unitaires avec Mocks

const request = require('supertest');
const app = require('../app');
const crypto = require('crypto');

describe('Webhook Endpoint', () => {
const secret = process.env.WEBHOOK_SECRET;

function signPayload(payload) {
const signature = crypto
.createHmac('sha256', secret)
.update(payload)
.digest('hex');
return `sha256=${signature}`;
}

it('should process appointment.created event', async () => {
const payload = JSON.stringify({
id: 'evt_test_123',
type: 'appointment.created',
created: new Date().toISOString(),
data: {
object: {
id: 123,
status: 'pending',
userPhone: '+224622000000'
}
}
});

const signature = signPayload(payload);

const response = await request(app)
.post('/webhooks/moncreneau')
.set('Content-Type', 'application/json')
.set('X-Moncreneau-Signature', signature)
.set('X-Moncreneau-Event', 'appointment.created')
.send(payload);

expect(response.status).toBe(200);

// Vérifier que l'événement a été traité
const processed = await db.processedEvents.findOne({
eventId: 'evt_test_123'
});
expect(processed).toBeTruthy();
});

it('should reject invalid signature', async () => {
const payload = JSON.stringify({ id: 'evt_test' });

const response = await request(app)
.post('/webhooks/moncreneau')
.set('X-Moncreneau-Signature', 'sha256=invalid_signature')
.send(payload);

expect(response.status).toBe(401);
});

it('should be idempotent', async () => {
const payload = JSON.stringify({
id: 'evt_test_456',
type: 'appointment.created'
});
const signature = signPayload(payload);

// Premier appel
await request(app)
.post('/webhooks/moncreneau')
.set('X-Moncreneau-Signature', signature)
.send(payload);

// Deuxième appel (doublon)
const response = await request(app)
.post('/webhooks/moncreneau')
.set('X-Moncreneau-Signature', signature)
.send(payload);

expect(response.status).toBe(200);

// Vérifier qu'il n'y a qu'un seul enregistrement
const count = await db.processedEvents.countDocuments({
eventId: 'evt_test_456'
});
expect(count).toBe(1);
});
});

4. Tests de Charge

Vérifier que votre intégration peut gérer le volume de production.

Avec Artillery

[object Object]
# Exécuter le test
artillery run load-test.yml

Avec k6

[object Object]
# Exécuter
k6 run load-test.js

5. Tests de Contrat (Contract Testing)

Vérifier que votre code respecte le contrat API.

Avec Pact

[object Object]

6. Tests End-to-End

Scénario complet utilisateur.

describe('E2E: Complete Appointment Flow', () => {
it('should complete full appointment cycle', async () => {
// 1. Récupérer les créneaux disponibles
const slotsResponse = await api.get('/departments/5/availability', {
params: {
startDate: '2026-02-01',
endDate: '2026-02-28'
}
});
expect(slotsResponse.status).toBe(200);
const slot = slotsResponse.data.availability[0].slots[0];

// 2. Créer le rendez-vous
const createResponse = await api.post('/appointments', {
departmentId: 5,
dateTime: slot.dateTime,
name: 'Jean Test'
});
expect(createResponse.status).toBe(201);
const appointmentId = createResponse.data.id;

// 3. Vérifier le statut
const statusResponse = await api.get(`/appointments/${appointmentId}`);
expect(statusResponse.data.status).toBe('pending');

// 4. Annuler le rendez-vous
const cancelResponse = await api.delete(`/appointments/${appointmentId}`);
expect(cancelResponse.status).toBe(200);

// 5. Vérifier l'annulation
const finalStatus = await api.get(`/appointments/${appointmentId}`);
expect(finalStatus.data.status).toBe('cancelled');
});
});

Bonnes Pratiques

✅ À Faire

  • Nettoyer les données de test après chaque test
  • Tester les cas d'erreur (pas seulement le happy path)
  • Automatiser les tests dans la CI/CD
  • Tester l'idempotence des webhooks
  • Mesurer la couverture de code (> 80%)
  • Utiliser des données de test cohérentes

❌ À Éviter

  • Hardcoder les IDs de test
  • Ignorer les tests qui échouent
  • Tester uniquement le succès
  • Oublier de tester les timeouts
  • Dépendre de données externes instables

Checklist Tests

Avant le déploiement:

  • Tests unitaires passent (> 80% coverage)
  • Tests d'intégration avec API OK
  • Tests de webhooks avec ngrok OK
  • Tests de charge validés (100 req/min)
  • Tests E2E complets OK
  • Tous les cas d'erreur testés
  • Documentation des tests à jour
  • CI/CD exécute les tests automatiquement

Ressources