Skip to content

Vous souhaitez recevoir de l'aide sur ce sujet ? rejoignez la communauté Angular.fr sur Discord.

Tester avec Jest dans Angular ​

Vous voulez des tests plus rapides et plus simples dans votre application Angular ? Jest est la solution ! Ce framework de test moderne remplace avantageusement Karma et Jasmine par défaut d'Angular.

Dans ce tutoriel, nous allons voir comment migrer de Karma/Jasmine vers Jest pour profiter de ses avantages : tests plus rapides, meilleure intégration avec les outils modernes et une syntaxe plus claire.

WARNING

Jest n'est pas le framework de test officiel d'Angular. Attention, cela peut plus fastidieux à configurer et à utiliser.

Configuration de Jest avec Angular ​

Étape 1 : Installation des dépendances ​

Commençons par installer Jest et ses dépendances spécifiques à Angular :

bash
npm install -D jest jest-preset-angular @types/jest jest-environment-jsdom jsdom ts-node

Puis désinstallons Karma et Jasmine si ils sont présents :

bash
npm remove karma karma-chrome-launcher karma-jasmine karma-coverage karma-jasmine-html-reporter jasmine-core @types/jasmine

Configuration recommandée

Ces paquets sont les versions recommandées par jest-preset-angular, le preset officiel pour Angular.

Étape 2 : Configuration Jest ​

Créons le fichier de configuration Jest à la racine du projet :

typescript
// jest.config.ts
const { createCjsPreset } = require('jest-preset-angular/presets');

/** @type {import('jest').Config} */
module.exports = {
  ...createCjsPreset(),
  testEnvironment: 'jsdom',
  setupFilesAfterEnv: ['<rootDir>/setup-jest.ts'],
  testPathIgnorePatterns: [
    '<rootDir>/node_modules/',
    '<rootDir>/dist/',
    '<rootDir>/src/test.ts', // fichier Karma par défaut
  ],
};

Cette configuration utilise le preset CommonJS d'Angular et configure l'environnement DOM pour les tests.

Mettez aussi "type": "module" dans le fichier package.json

Étape 3 : Fichier de setup ​

Créons le fichier setup-jest.ts à la racine pour initialiser l'environnement de test :

typescript
// setup-jest.ts
import { setupZoneTestEnv } from 'jest-preset-angular/setup-env/zone';

// Initialise l'environnement Zone.js pour les tests Angular
setupZoneTestEnv();

Ce fichier configure Zone.js, nécessaire pour que les tests Angular fonctionnent correctement.

Étape 4 : Configuration TypeScript ​

Mettons à jour tsconfig.spec.json pour Jest :

json
{
  "extends": "./tsconfig.json",
  "compilerOptions": {
    "module": "CommonJS",
    "types": ["jest"]
  },
  "include": ["src/**/*.spec.ts", "src/**/*.d.ts"]
}

Étape 5 : Scripts NPM ​

Modifions les scripts dans package.json :

json
{
  "scripts": {
    "test": "jest",
    "test:watch": "jest --watch",
    "test:coverage": "jest --coverage"
  }
}

Nettoyage Angular CLI

N'oubliez pas de supprimer ou vider la cible test basée sur Karma dans angular.json si vous ne l'utilisez plus.

Écrire des tests avec Jest et Angular ​

Maintenant que Jest est configuré, voyons les fonctionnalités spécifiques que Jest offre par rapport à Jasmine.

Fonctionnalités Jest vs Jasmine ​

Jest apporte de nombreuses améliorations par rapport à Jasmine. Voici les principales différences :

Jest.spyOn vs Jasmine.createSpy ​

Jest offre une syntaxe plus simple pour créer des espions :

typescript
// Avec Jasmine
const spy = jasmine.createSpy('methodName');
spy.and.returnValue(mockValue);

// Avec Jest - Plus simple et expressif
const spy = jest.spyOn(service, 'methodName');
spy.mockReturnValue(mockValue);

Mock automatique avec jest.mock() ​

Jest peut automatiquement mocker des modules entiers :

typescript
// Mock automatique d'un service
jest.mock('./user.service', () => ({
  UserService: jest.fn().mockImplementation(() => ({
    getUsers: jest.fn().mockReturnValue([]),
    addUser: jest.fn()
  }))
}));

Snapshot testing ​

Jest permet de tester la structure des objets avec les snapshots :

typescript
it('should match user object snapshot', () => {
  const user = {
    id: 1,
    name: 'John Doe',
    email: '[email protected]'
  };
  
  expect(user).toMatchSnapshot();
});

Tests avec mockReturnValue et mockImplementation ​

Jest offre des méthodes de mock plus flexibles :

typescript
// Mock avec valeur de retour
const mockService = {
  getData: jest.fn().mockReturnValue('mocked data')
};

// Mock avec implémentation personnalisée
const mockService = {
  getData: jest.fn().mockImplementation((id: number) => {
    return id > 0 ? 'valid data' : 'invalid data';
  })
};

Mock des timers ​

Jest permet de contrôler les timers pour tester les opérations asynchrones :

typescript
it('should handle timeout', () => {
  jest.useFakeTimers();
  
  let callback = jest.fn();
  setTimeout(callback, 1000);
  
  // Avancer le temps
  jest.advanceTimersByTime(1000);
  
  expect(callback).toHaveBeenCalled();
  
  jest.useRealTimers();
});

Bonnes pratiques Jest spécifiques ​

Utilisation des mocks avec Jest ​

Jest offre un système de mocking très puissant et plus simple que Jasmine :

typescript
// Mock d'un service HTTP avec Jest
const mockHttpService = {
  get: jest.fn().mockReturnValue(of(mockData)),
  post: jest.fn().mockResolvedValue(mockResponse),
  put: jest.fn().mockRejectedValue(new Error('Network error')),
  delete: jest.fn().mockImplementation((url) => {
    return url.includes('admin') ? of(successResponse) : throwError('Unauthorized');
  })
};

// Dans le test
beforeEach(() => {
  // Jest permet de réinitialiser tous les mocks facilement
  jest.clearAllMocks();
});

Tests avec fakeAsync et Jest timers ​

Jest améliore aussi la gestion des timers :

typescript
import { fakeAsync, tick } from '@angular/core/testing';

it('should handle async operations with Jest timers', fakeAsync(() => {
  // Arrange
  jest.useFakeTimers();
  let result: any;
  
  // Act
  service.asyncOperation().subscribe(data => {
    result = data;
  });
  
  // Jest permet un contrôle plus fin des timers
  jest.advanceTimersByTime(1000);
  tick();
  
  // Assert
  expect(result).toBeDefined();
  
  // Nettoyage
  jest.useRealTimers();
}));

Matchers Jest supplémentaires ​

Jest offre des matchers plus expressifs :

typescript
it('should use Jest-specific matchers', () => {
  const mockFunction = jest.fn();
  
  mockFunction('test');
  
  // Matchers Jest plus expressifs
  expect(mockFunction).toHaveBeenCalledWith('test');
  expect(mockFunction).toHaveBeenCalledTimes(1);
  expect(mockFunction).toHaveBeenLastCalledWith('test');
  expect(mockFunction).toHaveReturnedWith(undefined);
  
  // Matchers pour les tableaux et objets
  expect(['a', 'b', 'c']).toContain('b');
  expect({ name: 'John', age: 30 }).toHaveProperty('name', 'John');
  expect(mockFunction.mock.calls[0]).toEqual(['test']);
});

Avantages Jest vs Jasmine

  • Performance : Jest est 3-5x plus rapide
  • Mocking : API plus simple et puissante
  • Snapshots : Tests de régression automatiques
  • Configuration : Moins de configuration nécessaire
  • Intégration : Meilleure intégration avec les outils modernes