WordPress 6.5, sorti en avril, a introduit deux nouveautés qui changent la façon d’écrire des blocs interactifs : l’Interactivity API, un système standardisé pour ajouter de l’interactivité côté front sans dépendre de React complet, et les block bindings, qui permettent de connecter dynamiquement un attribut de bloc à une source de données (une métadonnée d’article, un champ personnalisé) sans écrire de PHP de rendu spécifique. Ces deux fonctionnalités, encore jeunes, demandent d’adapter la stratégie de test habituelle des blocs Gutenberg.
Cet article détaille comment tester un bloc qui utilise l’Interactivity API, avec ses directives data-wp-* et son store JavaScript, ainsi que la vérification des block bindings à la fois côté PHP et côté rendu final.
Comprendre ce qu’il y a à tester dans l’Interactivity API
Un bloc interactif construit avec cette API repose sur trois éléments distincts, qui appellent chacun une stratégie de test différente : le balisage HTML enrichi de directives (data-wp-interactive, data-wp-on--click, data-wp-bind--*), un store JavaScript qui contient l’état et la logique, et le rendu final observable dans le navigateur une fois le script d’hydratation exécuté.
<div
data-wp-interactive="mon-plugin"
data-wp-context='{ "compteur": 0 }'
>
<button data-wp-on--click="actions.incrementer">
Cliquer
</button>
<span data-wp-text="state.texteAffiche"></span>
</div>
Tester le store en isolation avec Jest
Le store JavaScript, déclaré via store() depuis @wordpress/interactivity, contient généralement de la logique pure (calculs, dérivations d’état) qui se teste très bien avec Jest, sans avoir besoin de monter le DOM complet :
import { store } from '@wordpress/interactivity';
const { state, actions } = store( 'mon-plugin', {
state: {
compteur: 0,
get texteAffiche() {
return `Compteur : ${ state.compteur }`;
},
},
actions: {
incrementer() {
state.compteur++;
},
},
} );
export { state, actions };
import { state, actions } from '../view';
describe( 'Store du compteur', () => {
beforeEach( () => {
state.compteur = 0;
} );
it( 'incrémente le compteur', () => {
actions.incrementer();
expect( state.compteur ).toBe( 1 );
} );
it( 'met à jour le texte affiché', () => {
actions.incrementer();
expect( state.texteAffiche ).toBe( 'Compteur : 1' );
} );
} );

Vérifier le rendu réel avec un test E2E ciblé
La logique testée en Jest ne garantit pas que les directives data-wp-* sont correctement câblées dans le HTML, ni que le script d’hydratation s’exécute sans erreur dans un vrai navigateur. Un test E2E ciblé, avec Playwright et @wordpress/e2e-test-utils-playwright, reste nécessaire pour ce niveau de vérification :
test( 'le clic incrémente le compteur affiché', async ( { page, editor, admin } ) => {
await admin.createNewPost();
await editor.insertBlock( { name: 'mon-plugin/compteur' } );
await editor.publishPost();
const url = page.url();
await page.goto( url );
await page.click( 'button' );
await expect( page.locator( 'span' ) ).toHaveText( 'Compteur : 1' );
} );
Ce test valide l’ensemble de la chaîne : sérialisation correcte des directives dans le HTML publié, chargement du module d’interactivité côté front, et exécution effective de l’action au clic.
Tester les block bindings côté PHP
Les block bindings permettent de connecter un attribut de bloc, comme le contenu d’un paragraphe ou la source d’une image, à une valeur dynamique via un callback enregistré avec register_block_bindings_source(). Ce callback PHP se teste comme n’importe quelle fonction, avec WP_UnitTestCase :
register_block_bindings_source( 'mon-plugin/prix-produit', array(
'label' => __( 'Prix du produit', 'mon-plugin' ),
'get_value_callback' => 'mon_plugin_get_prix_binding',
) );
function mon_plugin_get_prix_binding( $source_args, $block_instance ) {
$prix = get_post_meta( $block_instance->context['postId'], '_prix', true );
return $prix ? number_format_i18n( (float) $prix, 2 ) . ' €' : '';
}
class Test_Binding_Prix extends WP_UnitTestCase {
public function test_formate_le_prix_en_euros() {
$post_id = $this->factory()->post->create();
update_post_meta( $post_id, '_prix', '19.9' );
$bloc_instance = new stdClass();
$bloc_instance->context = array( 'postId' => $post_id );
$resultat = mon_plugin_get_prix_binding( array(), $bloc_instance );
$this->assertStringContainsString( '19,90', $resultat );
}
}
Ce test vérifie la logique de formatage isolément, sans avoir besoin de publier réellement le bloc dans l’éditeur.
Une répartition claire des responsabilités de test
- Jest pour la logique pure du store d’interactivité : dérivations d’état, actions qui ne touchent pas le DOM.
- PHPUnit pour les callbacks de block bindings et toute logique serveur associée.
- E2E ciblé pour vérifier que les directives sont bien câblées et que l’hydratation fonctionne réellement dans un navigateur, sur un nombre restreint de scénarios critiques.
Sur nos premiers projets utilisant l’Interactivity API, nous avons appris à ne pas sur-tester le store en E2E : ce que Jest peut vérifier en quelques millisecondes n’a pas besoin d’un navigateur complet. Le E2E doit se concentrer sur ce que lui seul peut prouver, le câblage réel entre le balisage et le comportement observé.
En résumé
Tester un bloc qui exploite l’Interactivity API et les block bindings de WordPress 6.5 demande de répartir l’effort sur trois couches distinctes plutôt que de tout pousser en E2E : Jest pour la logique du store, PHPUnit pour les callbacks de binding côté serveur, et un E2E ciblé pour valider l’hydratation réelle dans le navigateur. Cette répartition, encore en train de se stabiliser dans les pratiques de la communauté, garde les suites de tests rapides tout en couvrant ce qui compte vraiment sur ces fonctionnalités encore jeunes.