Passer au contenu principal

Test unitaire React : Guide pratique d'amorçage à fin de cycle

Apprenez à tester unitairement React, de la mise en place à CI/CD. Ce guide couvre Jest, RTL, hooks, async code, mocking et les meilleures pratiques pour des applications cross-plateformes robustes.

Martin Donadieu

Martin Donadieu

[targetLanguage]

Unit Testing React : Guide Pratique Pas à Pas

Vous apportez une petite modification à l'interface avant le déjeuner. Elle semble sans danger. L'étiquette d'un bouton change, une condition de rendu se simplifie et un hook d'aide prend en compte une nouvelle branch. La demande de tirage est propre, la revue est rapide et le déploiement est effectué.

Une heure plus tard, le support signale que la connexion a cessé de fonctionner sur une plateforme. Web semble normal. Le shell de bureau a un chemin de rendu périmé. La construction mobile se comporte différemment après une modification d'état asynchrone. Personne n'a remarqué cela car les code avaient des tests, mais pas les bons tests, et certainement pas un système fiable autour de ces tests.

C'est le principal problème avec la mise en œuvre de tests unitaires pour React dans les équipes de production. Écrire quelques tests qui passent n'est pas difficile. Construire un ensemble de tests qui vous protège encore pendant les réorganisations, les trains de livraison, les correctifs d'urgence et la mise en boîte cross-plateforme est la partie difficile. Les applications React ne se cassent pas parce que l'équipe a oublié comment appeler render(). Elles se cassent parce que les tests se dirigent vers les détails d'implémentation, le comportement asynchrone est recouvert et la CI traite les tests comme une case à cocher au lieu d'une porte de livraison.

La mise en œuvre de tests unitaires modernes pour React fonctionne lorsque cela se comporte comme un système de sécurité. Feedback rapide localement. Contrôles déterministes dans la CI. Les limites claires autour de ce qui appartient à un test unitaire et ce qui ne l'appartient pas. Cela compte encore plus lorsque le même code React est exécuté à travers les navigateurs, les Capacitor conteneurs ou les shells Electron.

Table des matières

Pourquoi le test unitaire de React est votre meilleure protection

Les tests unitaires gagnent leur argent lorsque ils détectent l'erreur que vous étiez convaincu ne pouvait pas se produire. Dans React, cela signifie généralement que le composant continue de s'afficher, mais le comportement dont les utilisateurs dépendent a changé. Un bouton désactivé devient cliquable. Un état de chargement ne se déclenche jamais. Un message de remplacement disparaît après une refacteur. Ces échecs sont petits en code et coûteux en production.

Le testing React a changé de manière importante lorsqu' Le React Testing Library est devenu le modèle principal pour le testing du comportement au lieu des internes, poussant les équipes vers des tests qui reflètent le comportement des utilisateurs plutôt que les propriétés ou l'état des composants, comme le montre la guidance de testing de React Native à Résumé de la mise en œuvre de React Native. Cette évolution compte car React code se réorganise constamment. Les hooks se déplacent. Les composants se séparent. Le contexte est introduit. Un test lié à la structure interne se brise pendant des refacteurs sains. Un test lié au comportement visible survit généralement.

Ce que doit protéger un test unitaire

Un bon test unitaire React protège un petit contrat :

  • Sortie affichée : Voit l'utilisateur le bon texte, l'étiquette, l'état ou le fallback ?
  • Comportement d'interaction : La saisie, la saisie ou la modification du UI change-t-elle correctement ?
  • Gestion des limites : Le composant se comporte-t-il correctement lorsqu'il reçoit les entrées attendues, les données manquantes ou une voie d'erreur ?

Une faible test protège la mauvaise chose :

  • Internautes du composant : Forme de l'état, méthodes privées, propriétés d'implémentation uniquement
  • Mécanismes du cadre : Le React a-t-il mis à jour un crochet exactement comme vous l'attendiez internement ?
  • Détails de l'enfant : Marquage détenu par des composants imbriqués que vous n'avez pas l'intention de vérifier ici

Règle pratique : Si vous pouvez réfacturer le composant sans changer ce que voit ou fait l'utilisateur, le test n'a pas besoin de changer non plus.

Les tests unitaires se situent également dans un système de test plus large. Ils ne cherchent pas à prouver que l'application fonctionne de bout en bout. Ils sont la couche rapide qui attrape les régressions avant que vous n'ayez besoin d'un test de niveau navigateur ou d'une validation de niveau appareil. C'est pourquoi ils constituent la première ligne de défense dans n'importe quel empilement sensé de tests d'automatisation pour les applications de production.

Pour les équipes React qui acheminent souvent, la confiance provient de cette division du travail. Les tests unitaires détectent rapidement les régressions locales. Les tests d'intégration vérifient les articulations. Les tests de bout-en-bout confirment les chemins critiques. Omettre la couche unitaire et que tout ce qui est plus lent en aval doit porter trop de poids.

Configuration de votre environnement de test moderne React

Un environnement de test fragile crée des tests flous avant même d'avoir écrit une seule assertion. Beaucoup de développeurs blâment Jest, jsdom ou React lorsque le problème sous-jacent est une configuration incohérente sur les machines locales et CI. La solution est de rendre l'environnement banal. Banal est bon ici.

Un espace de travail propre affichant un moniteur de l'ordinateur affichant les tests unitaires React code dans un éditeur code.

Commencez par un exécuteur prévisible et un environnement

Pour une application React moderne, surtout une créée avec Vite, la configuration de base devrait inclure :

  • Un exécuteur de tests : Jest reste commun, surtout dans les anciens codebases React et les stacks CI d'entreprise.
  • Un environnement simulant un navigateur : jsdom permet aux tests de composants de rendre la sortie DOM.
  • Utilitaires de bibliothèque de test : @testing-library/react And @testing-library/jest-dom
  • Une seule entrée de configuration : Un seul fichier pour enregistrer les matcheurs et les mocks globaux

Le workflow clé que la documentation de test de React renforce est simple : rendre le composant dans un environnement jsdom, interroger l'interface utilisateur avec des sélecteurs comme getByText ou getByRole, déclencher une interaction, et affirmer le changement de la zone de mise en page, comme décrit dans la documentation de test de React. Ce workflow reste fiable uniquement si chaque machine exécute le même environnement de test.

Une configuration de Jest pratique ressemble généralement à ceci :

// jest.config.js
module.exports = {
  testEnvironment: 'jsdom',
  setupFilesAfterEnv: ['<rootDir>/src/setupTests.js'],
  moduleNameMapper: {
    '\\.(css|less|scss)$': 'identity-obj-proxy',
    '^@/(.*)$': '<rootDir>/src/$1',
  },
  transform: {
    '^.+\\.(js|jsx|ts|tsx)$': 'babel-jest',
  },
};

Si votre équipe utilise SWC au lieu de Babel, cela ne pose pas de problème. Le point n'est pas le transformateur. Le point est la cohérence. Choisissez une voie et standardisez-la dans le dépôt. Si vous souhaitez une référence complémentaire utile pour les conventions de test JavaScript plus larges, le guide des tests unitaires de Capgo est un document de transmission d'équipe utile. is a useful team handoff doc.

Ajoutez le fichier de configuration que votre ensemble de tests dépendra

Un bon setupTests.js enregistre beaucoup de bruit répétitif : 

import '@testing-library/jest-dom';

Object.defineProperty(window, 'matchMedia', {
  writable: true,
  value: jest.fn().mockImplementation(query => ({
    matches: false,
    media: query,
    onchange: null,
    addListener: jest.fn(),
    removeListener: jest.fn(),
    addEventListener: jest.fn(),
    removeEventListener: jest.fn(),
    dispatchEvent: jest.fn(),
  })),
});

Ce fichier est où vous résolvez les écarts d'environnement une fois au lieu d'intérieur vingt fichiers de test. Ajoutez des mocks pour les API que votre interface utilisateur dépend, telles que matchMedia, ResizeObserver, ou IntersectionObserver, si votre bibliothèque de composants les attend.

Sans cela, les développeurs patcheront les variables globales ad hoc. Cela crée des tests incohérents et des erreurs difficiles à suivre. Une personne local passe parce qu'ils ont ajouté un mock manuel dans un fichier. Le CI échoue parce que la configuration n'a pas été partagée.

Maintenez le comportement local et CI aligné

La commande locale devrait correspondre à la commande CI aussi étroitement que possible. Si les développeurs exécutent la commande watch avec des paramètres permissifs mais que le CI exécute une configuration plus stricte, vous obtiendrez des échecs inattendus après la fusion. Gardez les scripts explicites : 

{
  "scripts": {
    "test": "jest",
    "test:watch": "jest --watch",
    "test:ci": "jest --runInBand --coverage"
  }
}

Un court parcours aide les nouveaux membres de l'équipe à obtenir la même base rapidement : 

La plus grande décision de configuration est la discipline autour des paramètres par défaut. Mettez des alias dans la configuration. Mettez les mocks d'environnement dans un fichier de configuration. Utilisez jsdom pour les tests de l'interface utilisateur et un environnement plus léger pour les utilitaires purs lorsque possible. Moins de comportement personnalisé que chaque test individuel nécessite, plus votre système devient fiable.

Écrire des Tests de Composants Signifiants

Les organisations n'ont pas de problème pour écrire des tests. Elles ont un problème pour écrire des tests qui ont encore de l'importance six mois plus tard.

Le modèle standard pour les tests unitaires des composants React est toujours le bon : rendre le composant, interroger l'interface utilisateur avec des sélecteurs centrés sur l'utilisateur, déclencher une interaction, et affirmer le changement de la zone DOM résultant, qui empêche les tests d'être proches des détails d'implémentation comme l'état ou les props, comme décrit dans le guide de test React. Le truc est d'appliquer ce modèle avec modération.

Tester l'accordéon comme un utilisateur l'utilise

Prenez un composant de base. Il affiche un bouton avec un titre. Le contenu du panneau commence caché. Cliquez sur le bouton pour révéler le contenu et mettre à jour l'état d'accessibilité. Accordion C'est suffisant pour plusieurs tests utiles :

La première mise en page montre le titre mais pas le contenu.

  1. Test the accordion like a user uses it
  2. En cliquant sur le déclencheur, le contenu est révélé.
  3. En cliquant à nouveau, il se replie.
  4. Les attributs d'accessibilité reflètent l'état visible.

Ce dernier point est trop souvent négligé. Si votre composant utilise des structures basées sur les rôles, vérifiez-les. Ce ne sont pas des détails d'implémentation. C'est une partie du contrat utilisateur-facing. aria-expanded, aria-controlsLes meilleures tests de composants ressemblent à un rapport d'erreur que vous n'aurez jamais.

Choisissez les requêtes en fonction de l'intention

La bibliothèque React Testing Library vous offre plusieurs styles de requêtes, mais ils ne sont pas interchangeables. Le choix du mauvais type rend les tests bruyants ou trompeurs.

Type de Requête

Lorsque l'élément est trouvéLorsque l'élément n'est pas trouvéExemple d'utilisation de l'application de cas d'utilisation __CAPGO_KEEP_0__
getByRenvoie l'élément immédiatementLance une erreur immédiatementAssurez-vous que le bouton ou l'en-tête doit déjà être affiché sur l'écran
queryByRenvoie l'élément immédiatementRenvoie nullAssurez-vous que le contenu caché n'existe pas avant l'interaction
findBySe résout lorsque l'élément apparaîtRejette après avoir attenduAssurez-vous que le contenu chargé en parallèle apparaît après une requête ou une mise à jour retardée

Un simple modèle mental aide :

  • Utilisez getBy pour les choses qui doivent déjà exister.
  • Utilisez-le pour les choses qui ne doivent pas encore exister. queryBy Utilisez-le lorsque les modifications ultérieures du UI sont nécessaires.
  • Si un test commence par findBy pour tout, cela signifie généralement que l'auteur n'est pas sûr de quand le composant se met à jour. Cette incertitude devient ensuite de la flousserie ultérieurement.

Exemple pratique d'accordéon findBy Voici un composant représentatif :

Et voici la forme de tests qui valent la peine d'être conservés :

Ce qui manque est tout aussi important. Il n'y a pas d'affirmation contre l'état interne. Aucune vérification que

function Accordion({ title, children }) {
  const [open, setOpen] = React.useState(false);

  return (
    <section>
      <button
        aria-expanded={open}
        aria-controls="accordion-panel"
        onClick={() => setOpen(prev => !prev)}
      >
        {title}
      </button>
      {open ? (
        <div id="accordion-panel">
          {children}
        </div>
      ) : null}
    </section>
  );
}

a été appelé. Aucun snapshot de l'arbre rendu entier. Ces tests ajouteraient de la maintenance, pas de confiance.

import { render, screen, fireEvent } from '@testing-library/react';

test('renders the accordion title and hides content initially', () => {
  render(<Accordion title="Shipping details">Delivery takes 3 days</Accordion>);

  expect(screen.getByRole('button', { name: /shipping details/i })).toBeInTheDocument();
  expect(screen.queryByText(/delivery takes 3 days/i)).not.toBeInTheDocument();
});

test('reveals content when the trigger is clicked', () => {
  render(<Accordion title="Shipping details">Delivery takes 3 days</Accordion>);

  fireEvent.click(screen.getByRole('button', { name: /shipping details/i }));

  expect(screen.getByText(/delivery takes 3 days/i)).toBeInTheDocument();
});

test('updates aria-expanded when opened', () => {
  render(<Accordion title="Shipping details">Delivery takes 3 days</Accordion>);

  const button = screen.getByRole('button', { name: /shipping details/i });
  expect(button).toHaveAttribute('aria-expanded', 'false');

  fireEvent.click(button);

  expect(button).toHaveAttribute('aria-expanded', 'true');
});

Quelques habitudes rendent les tests de composants plus solides : setOpen __CAPGO_KEEP_0__

__CAPGO_KEEP_1__

  • Préférez les requêtes basées sur les rôles : Les boutons, les titres, les dialogues, les alertes et les champs de saisie devraient généralement être trouvés par leur rôle.
  • Conservez chaque test étroit : Un comportement visible par l'utilisateur par test garde les erreurs lisibles.
  • Nommez les tests après les résultats : “met à jour aria-expanded lors de l'ouverture” est beaucoup plus utile que “fonctionne correctement.”

Si un composant est difficile à tester à travers le DOM, cela révèle souvent un problème de conception. Peut-être qu'il cache l'état dans le mauvais endroit. Peut-être qu'il manque de balises de sens. Les bonnes tests poussent souvent les équipes vers de meilleurs composants.

Testez les Hooks personnalisés et la logique d'application :

React apps hide a lot of important behavior outside components. State transitions live in hooks. Validation and formatting live in helper functions. Data shaping often happens before anything renders. If you only test visible components, you’ll miss a large part of the code that can still break production behavior.

Les Hooks nécessitent un harnais React-aware :

Un hook personnalisé a toujours besoin de React pour s'exécuter correctement, alors testez-le avec renderHook et enveloppez les appels modifiant l'état dans act().

A un petit useToggle est un bon exemple :

import { useState, useCallback } from 'react';

export function useToggle(initialValue = false) {
  const [value, setValue] = useState(initialValue);
  const toggle = useCallback(() => setValue(current => !current), []);
  return { value, toggle };
}

Sa test devrait rester concentrée sur le contrat public :

import { renderHook, act } from '@testing-library/react';
import { useToggle } from './useToggle';

test('returns the initial value', () => {
  const { result } = renderHook(() => useToggle(true));
  expect(result.current.value).toBe(true);
});

test('toggles the value', () => {
  const { result } = renderHook(() => useToggle(false));

  act(() => {
    result.current.toggle();
  });

  expect(result.current.value).toBe(true);
});

Cette test est utile car l'hameçon lui-même est l'unité. Vous ne testez pas les internes de React. Vous vérifiez le comportement externe de l'hameçon.

Pour les équipes de produits créant des UI ou des primitives de fonctionnalités réutilisables, ce modèle compte beaucoup. Les hameçons deviennent souvent l'interface partagée entre les applications, les systèmes de conception ou les outils internes. Si vous concevez un comportement réutilisable avec une intention commerciale, les ressources sur les hameçons pour les produits des créateurs peuvent aider à encadrer les hameçons comme des blocs de construction productisés plutôt que comme des détails d'implémentation.

La logique pure devrait rester pure dans les tests

Ce n'est pas nécessairement tout jsdom, React, ou Testing Library. Si une fonction est pure, testez-la avec Jest simple dans un environnement Node.

Exemple :

export function formatDisplayName(firstName: string, lastName: string) {
  return `${firstName.trim()} ${lastName.trim()}`.trim();
}

Cette test devrait être mortellement simple :

import { formatDisplayName } from './formatDisplayName';

test('joins and trims both names', () => {
  expect(formatDisplayName(' Ada ', ' Lovelace ')).toBe('Ada Lovelace');
});

test('handles a missing last name', () => {
  expect(formatDisplayName('Ada', '')).toBe('Ada');
});

La victoire ici est la vitesse et la clarté. Lorsqu'une fonction n'a pas besoin d'un arbre rendu, ne lui en donne pas. Les outils spécifiques à React ajoutent un surcoût. Gardez les tests de logique métier petits, rapides et proches de la fonction qu'ils vérifient.

Une séparation pratique fonctionne bien :

  • Hooks : Utilisez renderHook, act()et les fournisseurs de wrapper lorsque nécessaire.
  • Utilités : Utilisez Jest simple et sans DOM.
  • Logique de l'état transversale : Extrayez-la dans des aides testables lorsque le test de composant commence à faire trop de choses.

Les équipes ont souvent surchargé les tests de composant de logique d'affirmation qui appartiennent à une couche inférieure. L'extraction de cette logique donne deux avantages. Le test de composant devient plus propre, et le test de logique devient plus rapide.

Maîtriser les Techniques Avancées de Mise en Scène et d'Async

La plupart des suites React les plus instables se cassent en deux endroits. Elles se cassent aux limites de dépendance, et elles se cassent autour du temps.

That’s why async testing and mocking are the dividing line between a test suite de jouet and one you pouvez vous fier avant la mise en production. Une analyse attribue 46,5% des flakages de test à des problèmes liés à l'environnement ou à des ressources, comme les temps d'exécution asynchrone en cette analyse de test unitaire React. Dans les applications React, cela se traduit directement par les transitions d'état, le rendu différé, les interfaces utilisateur dérivées du réseau, et les tests qui supposent au lieu d'attendre de manière déterministe.

Un tableau de comparaison montrant les techniques de test avancées de React, en mettant l'accent spécifiquement sur le recours aux dépendances de test versus les tests asynchrones.

Simulez la frontière, pas chaque couche

La façon la plus rapide d'écrire un test trompeur est de simuler la moitié de votre arbre de composant et d'affirmer ensuite que vos propres simulations ont fonctionné.

Pour un composant qui récupère les données de compte, simulez le client de réseau ou le API module. N'ayez pas peur de simuler la fonction de hook, la composante de ligne enfant, le chargeur de chargement et trois fonctions d'utilité, à moins que le test nécessite vraiment l'isolement à ces joints.

Utilisez ce jeu de règles :

  • Simulez les services externes : Les clients HTTP, les analyses, les API du navigateur uniquement, les ponts natifs
  • Simulez les API de plateforme instables : matchMedia, les temporisateurs, les interfaces de préchargement Electron, les Capacitor plugins lorsqu'ils sont indisponibles dans jsdom
  • Évitez de simuler vos propres internes par défaut : les crochets personnalisés, les enfants simples, les utilitaires locaux

Si un test passe parce que toutes les parties difficiles ont été remplacées par des faux, cela n'a pas beaucoup acheté de confiance dans la version de sortie.

Pour les équipes qui veulent des exemples et des modèles autour des API de l'exécuteur, le Capgo Catégorie Jest est une bibliothèque de référence pratique, surtout lors de l'incorporation de développeurs qui connaissent React mais pas les mécaniques de test encore.

Les tests asynchrones échouent lorsqu'il y a des temps flous

Les échecs asynchrones proviennent généralement d'une des trois erreurs :

  1. Le test affirme trop tôt.
  2. Le test attend avec des temporisateurs arbitraires.
  3. Le composant se met à jour plus d'une fois, mais le test ne modélise qu'une seule transition.

Un test asynchrone stable a généralement cette forme :

test('shows user details after data loads', async () => {
  render(<UserProfile userId="42" />);
  expect(screen.getByText(/loading/i)).toBeInTheDocument();

  expect(await screen.findByText(/account owner/i)).toBeInTheDocument();
});

Ou, lorsque vous avez besoin de attendre une condition spécifique :

await waitFor(() => {
  expect(screen.getByRole('alert')).toBeInTheDocument();
});

Utilisez findBy lorsque l'apparition d'un élément est l'événement dont vous vous souciez. Utilisez waitFor lorsque la condition est plus large ou que l'état ne peut pas être exprimé avec une seule requête. Évitez setTimeout dans les tests à moins que vous ne testiez explicitement le comportement des temporisations et que vous utilisiez des temporisations artificielles.

L'écosystème de test de React attend également que vous respectiez act() la sémiotique autour des mises à jour. La bibliothèque de test gère beaucoup de cela pour vous, mais si vous avancez manuellement l'état ou les temporisations, vous devez encore réfléchir à quand les mises à jour se mettent à jour.

Sachez quelle outil de simulation à utiliser

Les outils de simulation différents résolvent des problèmes différents :

OutilMeilleure utilisationErreur commune
jest.fn()Fonctions de rappel isolées ou fonctions injectéesUtiliser cela pour remplacer un module complet lorsque simplement un rappel est suffisant
jest.spyOn()Observer ou surcharger une méthode sur un objet ou un module réelOublier de restaurer l'implémentation originale
jest.mock()Remplacer une dépendance de module à la frontière d'importationSimuler des modules importants par défaut et perdre le comportement significatif

Exemples d'aide :

  • Recherchez jest.fn() lorsqu'un composant prend un onSubmit propriété.
  • Utilisez-le jest.spyOn() lorsque vous avez besoin de vérifier console.errorune méthode de stockage, ou une fonction API exportée.
  • Utilisez-le jest.mock() lorsque l'importation d'un module entraînerait sinon des accès I/O, des code natifs, ou du comportement en dehors de la limite de l'unité.

Un domaine avancé que de nombreux guides négligent est la testabilité des chemins d'erreur dans React moderne. Les limites d'erreur, les changements de l'état retardés, et les UI de rechange asynchrones méritent des tests de premier ordre, et non seulement l'exemple de clic « heureux ». Si un enfant lance une erreur, affirmez l'UI de rechange. Si une requête échoue, affirmez l'état de récupération visible. Si un bouton est désactivé pendant le chargement, affirmez aussi cela. Ce sont les bugs que les utilisateurs se rappellent.

Améliorer la qualité et la stratégie des tests

Beaucoup d'équipes poursuivent toujours la couverture comme si c'était la même chose que la confiance. Ce n'est pas le cas.

Vous pouvez atteindre un objectif de couverture et manquer encore les régressions qui comptent. Un ensemble de déclarations d'assertion peu profondes, de captures d'écran larges, et d'internes mockés créent l'apparence de la sécurité tout en augmentant le coût de maintenance.

Un infographic comparant les avantages de la testabilité de qualité par rapport à l'overhead de maintenance des suites de tests de grande quantité.

La couverture est une carte, pas le but

Les rapports de couverture sont utiles lorsqu'ils répondent à une seule question : quels chemins critiques n'ont pas encore de protection ?

Ils ne sont pas utiles lorsqu'ils poussent les développeurs à tester des enveloppes triviales, des marques de mise en page statiques ou des fichiers de passage d'une ligne juste pour déplacer un pourcentage. Traitez la couverture comme un outil de découverte. Si l'état d'authentification, les actions de facturation, les drapeaux de fonctionnalité ou les invitations à la mise à jour n'ont pas de tests, c'est un signal. Si un composant d'icône présentatif n'a pas de tests, ce n'est généralement pas le cas.

Une question de revue saine est simple : cette test réduit-t-il le risque de mise à jour ?

  • Oui : Il vérifie le comportement visible de l'utilisateur sur un chemin critique.
  • Peut-être : Il protège la logique commerciale qui est facile à briser pendant la refacturation.
  • Non : Il affirme des détails d'implémentation ou duplique la valeur d'un autre test.

Ce qu'il ne faut pas tester unitairement

Beaucoup de guides React ne passent pas encore suffisamment de temps sur l'omission. Cette lacune compte car la sur-mockage et la testabilité des détails d'implémentation créent des ensembles fragiles qui passent tandis que l'expérience utilisateur continue de se briser, comme le note le guide de BrowserStack sur Ce qu'il ne faut pas tester unitairement dans React.

Omittez ou limitez fortement ces modèles :

  • Affirmations d'état internes : N'évaluez pas isOpen directement lorsque vous pouvez tester si le panneau s'est ouvert.
  • Comportement du cadre : N'évaluez pas que React a appelé un effet. Testez le résultat de ce que les effets changent.
  • Intégrales de bibliothèques tierces : Testez votre intégration avec un sélecteur de date ou un navigateur, et non la logique de rendu de la bibliothèque elle-même.
  • Unités surchargées : Si vous avez mocké tous les enfants et les assistants, vous ne testez peut-être plus un comportement significatif.

Les mauvaises tests sont pires que les tests manquants lorsqu'ils bloquent les réfacteurs et ne parviennent pas à détecter les bogues de production.

Un bon heuristique est la propriété des limites. Testez ce que votre code possède. N'évaluez pas ce que React, le navigateur ou une bibliothèque mature possèdent déjà, à moins que votre couche d'intégration change le contrat.

Où les captures d'écran sont utiles et où elles nuisent

Les captures d'écran ne sont pas inutiles. Elles sont simplement faciles à mal utiliser.

Utilisez-les avec parcimonie pour les composants avec une sortie stable et simple où une différence structurale large est significative. Évitez-les pour les composants interactifs ou dynamiques car ils deviennent du bruit. Les développeurs cessent de les lire et commencent à les mettre à jour de manière réflexe.

Des alternatives meilleures existent généralement :

  • Pour la mise en conditionnel, affirmez la présence ou l'absence de texte clé.
  • Pour les changements d'état visuels, affirmez le rôle, l'étiquette ou l'attribut qui compte.
  • Pour les erreurs et les redondances, affirmez le message ou la région d'alerte réelle.

Si votre équipe a besoin d'un processus de qualité plus large au-delà des tests unitaires, un compagnon solide est un flux de garantie de qualité d'application qui traite les tests, les contrôles de mise en production et la planification de retrait comme un système. C'est le changement de mentalité qui améliore la qualité des tests le plus rapidement. Arrêtez de demander combien de tests vous avez. Commencez à demander quels échecs pourraient encore atteindre les utilisateurs.

Intégration des Tests dans une Pipeline de CI/CD Cross-Plateforme

Un ensemble de tests qui ne s'exécute que sur un ordinateur de développement est une suggestion, pas un contrôle.

L'ensemble devient opérationnel lorsque chaque demande de tirage exécute les mêmes vérifications dans un environnement propre et bloque les mises à jour lorsque ces vérifications échouent. Cela semble évident, mais de nombreuses équipes laissent encore des lacunes critiques. Les tests sont exécutés manuellement. Les rapports de couverture sont optionnels. Les tâches de packaging et de mise en production commencent avant que les tâches de test n'aient fini. C'est ainsi que les petites regressions d'interface glissent dans les plus grandes échecs de mise en production.

Avec un diagramme à cinq étapes illustrant le processus d'intégration des tests automatiques React dans un pipeline de développement CI/CD.

Une demande de tirage devrait déclencher la même porte d'entrée chaque fois.

Pour le test unitaire React, agir comme un filet de sécurité, le CI a besoin de quelques éléments essentiels :

  • Exécuter sur chaque demande de tirage
  • Installer les dépendances à partir du fichier de verrouillage
  • Utiliser la même commande de test chaque fois
  • Échouer rapidement en cas de failures de test
  • Publier les artefacts uniquement après les tests réussissent

C'est le cœur des pratiques de déploiement continu pour les équipes d'applications. Construire la confiance avant la mise en production, et non après.

Un workflow d'Actions GitHub simple est suffisant pour de nombreuses équipes :

name: test

on:
  pull_request:
  push:
    branches:
      - main

jobs:
  react-tests:
    runs-on: ubuntu-latest

    steps:
      - name: Check out code
        uses: actions/checkout@v4

      - name: Set up Node
        uses: actions/setup-node@v4
        with:
          node-version: 20
          cache: npm

      - name: Install dependencies
        run: npm ci

      - name: Run unit tests
        run: npm run test:ci

This n'est pas élégant, et c'est là que réside le point. Les pipelines les plus solides sont généralement les moins surprenants.

Pourquoi cela compte plus pour Capacitor et Electron

Les applications React multiplateformes comportent plus de risques lors de la mise en production que les applications uniquement en navigateur car la même interface utilisateur code est souvent déployée dans différents conteneurs avec différentes hypothèses de runtime.

Quelques exemples montrent où les pipelines sont utiles :

  • Capacitor applications : Les applications Web code peuvent passer localement mais échouer lorsqu'une passerelle de plugin, un état hors ligne ou un cas d'échec de cycle d'application change le comportement après le packaging.
  • Applications Electron : Un composant de rendu peut dépendre d'APIs de préchargement, de messages de fenêtre ou d'état de bureau uniquement qui n'existeront pas dans les tests de navigateur en plain que si on les a intentionnellement mockés.
  • Trains de publication partagés : Un bundle mauvais peut avoir un impact sur plusieurs cibles si votre processus de déploiement ne bloque pas étroitement la publication.

C'est pourquoi les tests unitaires doivent s'exécuter avant les tâches de packaging, et les tâches de packaging doivent s'exécuter avant les tâches de distribution. Chaque étape réduit le risque. Les tests unitaires détectent rapidement les régressions locales. La vérification de packaging de plateforme vérifie les hypothèses d'environnement. L'approbation manuelle ou le lancement étalé gère la confiance finale de la mise en production.

Un workflow d'actions pratique GitHub

A un pipeline plus mature, les responsabilités sont généralement réparties :

  1. Job de test : Tests unitaires et de crochet rapides
  2. Job de build : Seul build de production après passage des tests
  3. Job de package : Capacitor synchronisation, packaging Electron ou bundling d'artefacts
  4. Job de release : Seul publication à partir de branches ou de tags approuvés

Pour les équipes qui délivrent des mises à jour en direct vers Capacitor ou Electron, c'est là que les outils de release comptent. Une option dans ce workflow est Capacitor , qui publie des bundles web signés pour les applications CapacitorJS et Electron avec prise en charge de rollback et de contrôle de lancement basé sur les canaux. En pratique, cela signifie que votre job de test React peut agir comme la première barrière dure avant que tout bundle web ne soit promu vers la livraison de staging ou de production. Capgo__CAPGO_KEEP_0__

The règle d'opération est simple. N'allez pas laisser l'infrastructure de mise en production compenser les tests faibles. Utilisez l'infrastructure de mise en production après que les tests fiables ont déjà éliminé les mauvaises modifications.

Un système de test fiable change le comportement de l'équipe. Les ingénieurs fusionnent avec moins de hésitation. Les réviseurs se concentrent sur les cas d'extrémité au lieu de re-réexécuter les bases manuellement. Les gestionnaires de mise en production cessent de traiter chaque déploiement comme un jeu d'hasard. C'est le résultat de faire des tests unitaires React bien.


Si votre équipe expédie React par Capacitor ou Electron, la sécurité de la mise en production dépend de plus que des tests locaux verts. Capgo offre aux équipes un moyen contrôlé de publier des mises à jour web signées, de cibler les canaux de déploiement et de revenir sur les mauvaises ensembles sans attendre la revue du magasin, ce qui s'intègre naturellement derrière une chaîne d'intégration qui exige déjà que les tests unitaires passent avant le déploiement.

Mises à jour en temps réel pour les applications Capacitor

Lorsqu'un bug de la couche web est en ligne, expédiez la correction par Capgo au lieu d'attendre des jours pour l'approbation de la boutique d'applications. Les utilisateurs reçoivent la mise à jour en arrière-plan tandis que les modifications natives restent dans le chemin de revue normal.

Commencez dès maintenant

Dernières actualités de notre Blog

Capgo vous donne les meilleures informations dont vous avez besoin pour créer une application mobile vraiment professionnelle.