Écrire des tests unitaires isolés pour vos pipes Angular

Les pipes Angular nous permettent de transformer des données avant de les afficher. Angular nous fournit une large gamme de pipes de base, mais nous devons parfois implémenter nos propres pipes. Dans ce cas, il faut aussi écrire des tests unitaires pour nos pipes.

Le pipe fait partie des concepts Angular les plus simples. Il s’agit d’une classe TypeScript munie du décorateur @Pipe et qui implémente l’interface PipeTransform. Cette interface comporte uniquement une méthode, la méthode transform comme le montre le bout de code suivant :

interface PipeTransform {
transform(value: any, ...args: any[]): any;
}

La méthode transform prend une donnée en entrée, la transforme, et la retourne pour qu’on puisse l’afficher dans nos templates avec un bon formatage.

Les pipes Angular sont faciles à tester, car ils n’interagissent que très rarement avec le DOM. Techniquement, nous pouvons donc les tester sans nous servir des utilitaires de test fournis par Angular ou TestBed.

On peut écrire deux types de tests unitaires pour nos pipes Angular :

  • des tests unitaires en isolation (sans TestBed),
  • des tests unitaires en intégration (avec TestBed).

Dans cet article, nous allons apprendre à écrire des tests unitaires isolés pour nos pipes Angular. Dans un prochain article, nous verrons comment écrire des tests unitaires en intégration avec TestBed.

On parle de test unitaire isolé lorsqu’on teste le pipe comme si c’était une banale classe TypeScript. On fait fi du fait qu’un pipe est utilisé dans des templates Angular. En un mot, on ne teste que la méthode transform du pipe.

Le code utilisé pour l’exemple (mean.pipe.ts)

Pour le reste de l’article, on va utiliser un pipe dont le but est de prendre en entrée un tableau d’entier et de retourner en sortie la moyenne des éléments qui le constituent. En voici le code :

import { Pipe, PipeTransform } from '@angular/core';
@Pipe({
name: 'mean',
})
export class MeanPipe implements PipeTransform {
transform(value: number[]): number {
if (!Array.isArray(value)) {
return value;
}
if (value.length === 0) {
return undefined;
}
const sum = value.reduce((n: number, m: number) => n + m, 0);
return sum / value.length;
}
}

On voit dans ce bout de code que:

  1. La classe MeanPipe implémente l’interface PipeTransform.
  2. La méthode transform retourne la moyenne des éléments du tableau value qui lui est passé en entrée.

Testons cet pipe en isolation (mean.pipe.spec.ts)

Lorsque nous utilisons le Angular CLI pour générer un notre pipe, le CLI génère aussi un squelette de test se présentant comme suit :

describe('MeanPipe', () => {
it('create an instance', () => {
const pipe = new MeanPipe();
expect(pipe).toBeTruthy();
});
});

Cette exemple de code :

  1. crée une nouvelle instance de MeanPipe,
  2. vérifie que le pipe est correctement instancié.

Ce test unitaire ne sert pas vraiment à grand-chose, mais c’est un bon point de départ. À partir de là, nous pouvons écrire des tests unitaires qui font plus sens.

Testons le comportement de notre pipe avec de mauvais inputs

La suite de tests Bad inputs teste le pipe lorsque nous lui passons des valeurs incorrectes comme un object {a: 'a'}, null ou un tableau vide.

describe('MeanPipe', () => {
const pipe = new MeanPipe();
// ...
describe('Bad inputs', () => {
it('should return the object without modification', () => {
expect(pipe.transform({ a: 'a' } as any)).toEqual({ a: 'a' } as any);
});
it('should return null ', () => {
expect(pipe.transform(null)).toEqual(null);
});
it('should return undefined', () => {
expect(pipe.transform([])).toEqual(undefined);
});
});
});

Testons le comportement de notre pipe avec de bons inputs

La suite de tests Good inputs teste le pipe lorsque nous lui passons des valeurs correctes.

describe('MeanPipe', () => {
const pipe = new MeanPipe();
// ...
describe('Good inputs', () => {
it('should return 1', () => {
expect(pipe.transform([1])).toEqual(1);
});
it('should return 0', () => {
expect(pipe.transform([1, -1])).toEqual(0);
});
it('should return 1', () => {
expect(pipe.transform([1, 1])).toEqual(1);
});
it('should return -1', () => {
expect(pipe.transform([-1, -1])).toEqual(-1);
});
});
});

Nous n’avons pas eu besoin d’utiliser un bloc BeforeEach parce que cet pipe est pure; sa méthode transform est sans état.

Conclusion

Dans cet article, nous avons appris qu’il y avait deux types de tests unitaires pour les pipes Angular : les tests unitaires isolés et les tests unitaires intégrés. Nous avons mis l’accent sur les tests unitaires isolés et vu à quel point c’était facile d’en écrire. Dans un prochain article, nous allons apprendre à écrire des tests unitaires intégrés pour nos pipes Angular.


Vous aimez ce blog ?
Suivez-moi sur Twitter pour plus de contenu !

Rejoignez la newsletter pour du contenu de grande qualité dans votre boite mail

Pas de spam. Que du contenu de qualité.