200 millisecondes environ : c’est la durée observée pour exécuter un test de composant isolé sur une machine de développement courante, contre plusieurs secondes pour l’équivalent monté dans l’éditeur de blocs complet. Cet écart, mesuré sur une bibliothèque de composants internes, justifie à lui seul de reconsidérer la façon dont un composant fonctionnel est testé.
Un composant fonctionnel construit avec @wordpress/element — la couche que WordPress fournit au-dessus de React pour les blocs — peut, dans la majorité des cas, être testé isolément. Ce sujet se limite volontairement au composant lui-même, sans entrer dans @wordpress/data ni dans le magasin Redux d’un bloc, qui relèvent d’un autre exercice de test.
Ce que @wordpress/element expose réellement
Le paquet @wordpress/element réexporte l’essentiel de l’API de React (createElement, useState, useEffect, Fragment) sous un espace de noms propre à WordPress. Un composant fonctionnel écrit avec ce paquet reste, du point de vue d’un outil de test, un composant React ordinaire : les bibliothèques de test habituelles de l’écosystème React s’appliquent sans adaptation particulière.
Un composant simple à isoler
Prenons un composant qui affiche un badge de statut pour un article, à partir d’une propriété statut :
// badge-statut.js
import { createElement } from '@wordpress/element';
export function BadgeStatut({ statut }) {
const libelle = {
brouillon: 'Brouillon',
en_attente: 'En attente de relecture',
publie: 'Publié',
}[statut] ?? 'Statut inconnu';
return createElement('span', { className: `badge badge--${statut}` }, libelle);
}
Ce composant ne dépend d’aucun magasin de données ni d’aucun contexte fourni par l’éditeur : il reçoit une propriété, il rend une sortie. C’est exactement le type de composant qui se prête à un test isolé.
Le test avec @testing-library/react
// badge-statut.test.js
import { render, screen } from '@testing-library/react';
import { BadgeStatut } from './badge-statut';
describe('BadgeStatut', () => {
it('affiche le libellé correspondant au statut publié', () => {
render(<BadgeStatut statut="publie" />);
expect(screen.getByText('Publié')).toBeInTheDocument();
});
it('affiche un libellé de repli pour un statut inconnu', () => {
render(<BadgeStatut statut="archive" />);
expect(screen.getByText('Statut inconnu')).toBeInTheDocument();
});
});

Ce test se lance avec Jest, déjà configuré par défaut dans un projet créé via @wordpress/scripts, sans nécessiter ni base de données, ni serveur PHP, ni éditeur monté. Sa durée d’exécution se compte en dizaines ou centaines de millisecondes, contre plusieurs secondes pour un test end-to-end équivalent.
Où placer la limite de l’isolation
Un composant qui appelle useState localement (par exemple pour gérer l’ouverture d’un menu déroulant) reste testable de la même façon, en simulant une interaction utilisateur avec fireEvent ou userEvent de la bibliothèque de test :
- Un composant sans état ni dépendance externe : test unitaire isolé, rapide, à privilégier en priorité.
- Un composant avec état local géré par
useState: toujours isolable, en simulant les interactions qui déclenchent les changements d’état. - Un composant connecté à un magasin de données via
useSelectouuseDispatch: sort du périmètre de ce test isolé, car il nécessite un environnement simulé du magasin, sujet distinct.
Un gain qui se voit surtout à l’échelle
Sur une bibliothèque de composants qui compte plusieurs dizaines de blocs, multiplier les tests d’intégration lourds pour chaque variante visuelle (statut, taille, thème de couleur) devient vite coûteux en temps d’exécution. Isoler les composants de présentation permet de couvrir un grand nombre de combinaisons de propriétés sans faire grimper la durée totale de la suite, réservant les tests plus lourds aux points d’intégration réels entre le composant et l’éditeur.
En résumé
Un composant fonctionnel écrit avec @wordpress/element se teste comme n’importe quel composant React, à condition qu’il ne dépende pas directement d’un magasin de données. Cette isolation réduit le temps d’exécution d’un test de composant à quelques centaines de millisecondes, tout en gardant une couverture précise sur chaque variante de rendu.