Appearance
Tester une directive seule avec TestBed.createDirective()
Une directive d'attribut est souvent testée au travers d'un petit composant créé uniquement pour le test. C'est nécessaire quand la directive dépend réellement d'un template complet. Mais, pour un comportement local et simple, ce composant hôte ajoute du bruit : template, import, puis recherche de l'élément dans le DOM.
Depuis Angular 22.2, TestBed.createDirective() crée directement un élément hôte et retourne un DirectiveFixture. Le test reste un vrai test Angular : injection, cycle de détection des changements et DOM sont présents. Il est simplement plus ciblé.
La directive à tester
Prenons une directive qui applique une couleur de fond à son élément hôte. input() permet de configurer la couleur depuis le template, et Renderer2 évite de manipuler le DOM directement dans la directive.
ts
import { Directive, ElementRef, inject, input, Renderer2 } from '@angular/core';
@Directive({ selector: '[appHighlight]' })
export class HighlightDirective {
readonly color = input('gold');
private readonly renderer = inject(Renderer2);
private readonly element = inject(ElementRef<HTMLElement>);
ngOnChanges() {
this.renderer.setStyle(
this.element.nativeElement,
'backgroundColor',
this.color(),
);
}
}Le comportement que nous voulons vérifier est précis : quand color vaut plum, l'élément hôte reçoit cette couleur.
Créer le DirectiveFixture
TestBed.createDirective() reçoit la classe de la directive et, facultativement, des options :
tagNamechoisit l'élément hôte créé pour le test ;bindingsapplique des liaisons Angular, comme le ferait un template.
ts
import { inputBinding } from '@angular/core';
import { TestBed } from '@angular/core/testing';
import { describe, expect, it } from 'vitest';
import { HighlightDirective } from './highlight.directive';
describe('HighlightDirective', () => {
it('applique son input à l’élément hôte', () => {
const fixture = TestBed.createDirective(HighlightDirective, {
tagName: 'p',
bindings: [inputBinding('color', () => 'plum')],
});
fixture.detectChanges();
expect(fixture.directiveInstance.color()).toBe('plum');
expect((fixture.nativeElement as HTMLElement).style.backgroundColor).toBe(
'plum',
);
});
});fixture.directiveInstance donne accès à l'instance de la directive. fixture.nativeElement est l'élément hôte réellement créé, ce qui permet de vérifier son effet visible. Comme son type générique est Element, le cast vers HTMLElement est utile ici pour accéder à style.
inputBinding() est important : il reproduit une liaison d'entrée Angular. Modifier une propriété de l'objet après coup ne testerait pas le même chemin que [appHighlight]="color" dans un template.
Déclencher les changements
La directive est créée avant le premier passage de détection des changements. fixture.detectChanges() applique les bindings puis exécute les hooks de cycle de vie nécessaires, dont ngOnChanges() dans cet exemple.
Pour tester une nouvelle valeur, utilisez une source réactive dans inputBinding(), modifiez-la, puis appelez à nouveau detectChanges() :
ts
import { signal } from '@angular/core';
const color = signal('plum');
const fixture = TestBed.createDirective(HighlightDirective, {
bindings: [inputBinding('color', color)],
});
fixture.detectChanges();
color.set('teal');
fixture.detectChanges();
expect((fixture.nativeElement as HTMLElement).style.backgroundColor).toBe('teal');Quand conserver un composant hôte ?
createDirective() est très pratique pour tester un effet local : une classe CSS, un attribut ARIA, un style, un listener ou une petite interaction avec l'élément hôte.
Conservez plutôt un composant de test quand le comportement dépend de plusieurs nœuds du template, de contenu projeté, d'une directive structurelle, ou de l'interaction avec d'autres composants. Dans ce cas, le template fait partie du comportement à vérifier : le retirer rendrait le test moins représentatif.
Ce n'est donc pas un remplacement systématique de TestBed.createComponent(). C'est une option plus directe pour les directives dont le contrat tient principalement sur leur élément hôte.
À retenir
Avec Angular 22.2 ou une version plus récente, TestBed.createDirective() permet de tester une directive isolée avec un vrai contexte Angular, sans écrire de composant hôte jetable. Utilisez DirectiveFixture pour lire l'instance et le DOM, et gardez les tests avec composant hôte lorsque le template est une partie essentielle du scénario.