Allez directement au contenu principal

Unit Tests JavaScript : Guide Complet 2026

Maîtrisez les tests unitaires JavaScript avec notre guide 2026. Couvre Jest, Mocha, la mise en place, le mocking, la CI et des conseils pour les applications Capacitor & Electron.

Unit Tests JavaScript : Guide Complet 2026

Vous vous trouvez probablement dans l’une ou l’autre des situations actuellement. Soit votre projet JavaScript a presque pas de tests et chaque refactor se sent risqué, soit vous avez déjà des tests et la moitié d’entre eux sont lents, fragiles et difficilement fiables.

Cela empire en Capacitor et Capacitor Applications. Une fonctionnalité simple peut interagir avec la logique métier partagée, les API du navigateur, les plugins natifs, les fichiers locaux, les IPC et les services distants dans le même flux. Si vous testez ces pièces de la mauvaise manière, votre suite devient un labyrinthe de dépendances fictives. Si vous les testez de la bonne manière, vous obtenez un feedback rapide sur la logique qui ne fonctionne pas.

Les bonnes tests unitaires ne commencent pas par une syntaxe de matcheur astucieuse. Ils commencent par une frontière disciplinée : testez la logique pure directement, isolez les effets secondaires et évitez d'écrire des tests qui s'effondrent dès que vous renommez une fonction interne.

Table des matières

Choisir votre cadre de test de JavaScript

Un projet de JavaScript professionnel nécessite un vrai exécuteur de tests. Les scripts ad hoc et les vérifications manuelles de la console ne s'adaptent pas une fois que plusieurs ingénieurs touchent le même codebase. Vous avez besoin de la découverte des tests, des assertions, de la gestion des appels asynchrones, des mocks et une façon de lancer tout de manière cohérente en développement local et CI.

La guidance actuelle converge vers une petite gamme d'options de masse. Jest, Mocha et Jasmine sont régulièrement mis en avant comme les principaux cadres, avec Jest fréquemment mis en avant pour sa structure de test intégrée, ses assertions, sa simulation et son support async dans un seul package, comme le montre cet Labo de test JavaScript de Pluralsight.

Tableau de comparaison des frameworks de test JavaScript populaires, y compris Jest, Mocha, Cypress et Playwright.

Pourquoi un framework n'est pas optionnel

La première erreur que les équipes commettent est de considérer les tests unitaires comme une activité secondaire. Cela conduit généralement à des noms de fichiers incohérents, des assertions personnalisées que personne ne se rappelle et des aides que seul un seul personne comprend.

Un framework vous donne un langage partagé :

  • Structure de test et describe context : Page/zone : Site web de marketing Capgo. Rôle : Petit élément de navigation ou d'interface utilisateur. Vu dans : page trust.astro. Clé de message `et` (Et). test ou it
  • context : Fragment de texte HTML d'une chaîne de Capgo UI plus longue (clé parente `alternatives_cta_questions`). Page/zone : Page de comparaison des alternatives de mise à jour en direct de Capacitor. Rôle : Long paragraphe de marketing ou juridique. Vu dans : page alternatives.astro. Conservez les termes de produit et de marque de Capgo et les termes de développeur exactement. Clé de message `alternatives_cta_questions` (Questions de CTA pour les alternatives). | Fragment de texte HTML d'une chaîne de Capgo UI plus longue (clé parente `appflow_cta_questions`). Page/zone : Copie de marketing de comparaison/migration d'Appflow. Rôle : Long paragraphe de marketing ou juridique. Vu dans : page ionic-appflow.astro. Conservez les termes de produit et de marque de Capgo et les termes de développeur exactement. Clé de message `appflow_cta_questions` (Questions de CTA pour Appflow). | Fragment de texte HTML d'une chaîne de Capgo UI plus longue (clé parente `capwesome_cta_questions`). Page/zone : Page de comparaison de Capawesome. Rôle : Long paragraphe de marketing ou juridique. Vu dans : page capwesome.astro. Conservez les termes de produit et de marque de Capgo et les termes de développeur exactement. Clé de message `capwesome_cta_questions` (Questions de CTA pour Capawesome). | Page/zone : Page de services de consulting. Rôle : Sous-titre ou slogan de section. Vu dans : page consulting.astro. Conservez les termes de produit et de marque de Capgo et les termes de développeur exactement. Clé de message `consulting_faq_subtitle` (Sous-titre des questions fréquemment posées pour les services de consulting). | Page/zone : Copie de marketing de comparaison/migration d'Appflow. Rôle : Petit élément de navigation ou d'interface utilisateur. Vu dans : page ionic-appflow.astro, page ionic-enterprise-plugins.astro, page solutions/ionic-enterprise-plugins.astro. Clé de message `appflow_plugins_or` (Appflow Plugins ou). Assertions : avec des matcheurs lisibles
  • Hooks pour la configuration et la désconfiguration
  • Supporte les appels asynchrone pour les promesses et les temporisations
  • Outils de simulation pour les dépendances externes

Si votre équipe a également besoin d'une vue plus large de l'automatisation des tests au-delà du niveau unitaire, Capgo présente une vue d'ensemble utile de la mise en œuvre de tests automatisés dans les flux de livraison d'applications.

Jest vs Mocha en un coup d'œil

Jest et Mocha représentent deux philosophies différentes.

Jest est l'option tout-en-un. Il embarque la plupart des éléments dont les équipes ont besoin dès le premier jour.
Mocha est plus modulaire. Il vous donne un exécuteur et vous attend que vous assembliez le reste de la pile.

Caractéristique Jest Mocha
Complexité de mise en place Plus basse pour la plupart des équipes Plus élevée car vous ajoutez généralement des bibliothèques d'assertion et de simulation
Assertions Intégré Généralement associé à une autre bibliothèque
Simulation Intégré par défaut Généralement associé à une autre bibliothèque
Test asynchrone Intégré par défaut et direct Supporté, mais dépend plus de la configuration entourante
Flux de couverture Intégré couramment dans le même flux de travail Plus souvent assemblé pièce après pièce
Meilleure correspondance Nouveaux projets, équipes qui veulent de la cohérence Pile de legacy, équipes qui veulent un contrôle modulaire

Règle pratique : Si votre équipe doit demander quel bibliothèque d'assertion et quelle bibliothèque de simulation doivent être associées au lanceur, vous voulez probablement Jest.

Ce que je recommande pour la plupart des équipes

Pour la plupart des projets modernes, je choisirais Jest sauf si le codebase a déjà des raisons solides pour rester sur Mocha. Cette recommandation devient plus forte lorsque l'application inclut Capacitor ou Electroncar ces projets ont déjà suffisamment de parties en mouvement. La réduction de la dispersion des outils de test rapporte rapidement.

Mocha est toujours pertinent dans les services Node.js plus anciens ou les codebases à long terme où l'écosystème autour de lui est déjà stabilisé. Mais pour un ingénieur de niveau moyen qui configure un ensemble robuste depuis zéro, Jest élimine généralement plus de friction qu'il ne crée.

Un important rappel de portée. Cypress et Playwright sont de très bons outils, mais ils résolvent un problème différent. Ils sont mieux adaptés aux vérifications de niveau navigateur et fin de ligne, et non à la boucle rapide interne où les tests unitaires JavaScript devraient vivre.

Configuration du Projet et Premier Test

A un testage propre, il devrait être ennuyeux. Si l'ajout du premier test semble compliqué, le lot probablement ne restera pas en bonne santé.

Un homme portant des lunettes travaillant sur un projet de programmation sur un ordinateur portable sur un bureau en bois.

Un setup Jest simple

Démarrez avec un projet JavaScript qui a déjà un package.jsonEnsuite, ajoutez Jest en tant que dépendance de développement et reliez un script de test.

{
  "scripts": {
    "test": "jest"
  }
}

Cela suffit pour beaucoup de projets. Vous pouvez ajouter plus de configuration plus tard si votre système de modules, votre transpilation ou votre structure de monorepo le nécessitent.

Si vous construisez une application locale Capacitor et que vous voulez que votre environnement de développement soit en ordre avant d'ajouter des tests autour de la logique partagée, le guide de Capgo sur la mise en place d'un environnement local Capacitor est un compagnon pratique. Écrivez le test avant le Capacitor Le modèle test-first n'est pas juste une préférence personnelle. La recommandation de la protection financière du consommateur des États-Unis sur la programmation JavaScript recommande explicitement d'écrire le test en premier.

Write the test before the code

Jest en tant que dépendance de développement et reliez un script de test. Si votre système de modules, votre transpilation ou votre structure de monorepo le nécessitent, vous pouvez ajouter plus de configuration plus tard., organiser les tests avec describe et it, et encadrer les vérifications autour de expect(...) affirmations dans ses guides de test unitaire JavaScript.

Cela compte car les changements test-first modifient la façon dont vous concevez code. Les fonctions tendent à devenir plus petites, les dépendances deviennent plus visibles, et les effets secondaires cessent de se faufiler dans la logique qui devrait rester pure.

Voici un exemple minimal :

// math.js
function addTax(amount, rate) {
  return amount + amount * rate;
}

module.exports = { addTax };
// math.test.js
const { addTax } = require('./math');

describe('addTax', () => {
  it('returns the amount with the tax applied', () => {
    expect(addTax(100, 0.2)).toBe(120);
  });
});

Utilisez Arrange Act Assert chaque fois

Le pattern Arrange, Act, Assert garde les tests lisibles, même lorsqu'ils deviennent plus complexes.

  1. Arrange l'entrée et tout l'installation nécessaire.
  2. Agir en appelant la fonction.
  3. Affirmer sur le résultat.

Appliqué à un assistant de validation :

function isSupportedPlatform(platform) {
  return ['ios', 'android', 'web', 'desktop'].includes(platform);
}

describe('isSupportedPlatform', () => {
  it('returns true for ios', () => {
    // Arrange
    const platform = 'ios';

    // Act
    const result = isSupportedPlatform(platform);

    // Assert
    expect(result).toBe(true);
  });
});

Les petites tests vieillissent bien. Une test devrait répondre généralement à une question, et non raconter un flux de travail entier.

Pour les projets Capacitor et Electron, cette discipline compte plus car votre logique pure se trouve souvent à côté d'une intégration native ou de bureau code. Gardez la règle commerciale testable sans le runtime de la plateforme, et votre première test ne sera pas votre dernière utile.

Maîtriser les Mocks et les Code Asynchrones

La plupart des bugs dans l'application code ne proviennent pas de l'addition de deux nombres. Ils proviennent de code qui se dépassent : les requêtes réseau, les fichiers, les API des plugins, les temporisateurs, les canaux de communication inter-processus, les couches de stockage.

C'est là où les mocks sont utiles. Ils vous donnent le contrôle sur la frontière afin que la test puisse se concentrer sur la prise de décision de votre code.

Un diagramme de tableau blanc illustrant une architecture de microservices avec des APIs, des magasins de données, des services externes et un flux de données basé sur les événements.

Fixez les limites, pas tout

La guidance de test maintenable met l'accent sur la couverture de la couche unique et une seule affirmation forte par test, et elle avertit également que l'utilisation excessive de mocks rend les tests fragiles et étroitement couplés aux détails d'implémentation, comme résumé dans cet article de TestRail sur les tests unitaires maintenables.

Cette avertissement compte beaucoup en JavaScript. Les équipes commencent souvent en mockant chaque module importé et finissent par tester si les fonctions appellent d'autres fonctions dans l'ordre « correct », au lieu de tester le comportement réel.

Objectif à éviter pour un test lourd en mocks :

  • si l'aide A a appelé l'aide B
  • si le service C a appelé le sérialiseur D
  • si une fonction privée interne a été exécutée deux fois

Un objectif cible mieux conçu :

  • ce que la fonction a retourné
  • si elle a correctement géré une dépendance échouée
  • si elle a transformé les données dans la forme attendue

Un modèle plus approprié pour Capacitor et Electron code

Dans les applications mobiles et de bureau, j'ai préféré une couche de wrapper autour des API natives ou de plateforme. Les tests unitaires simulent ensuite la couche de wrapper, et non la plateforme elle-même.

Structure d'exemple :

// cameraGateway.js
async function getPhoto(cameraPlugin) {
  return cameraPlugin.getPhoto();
}

module.exports = { getPhoto };
// profilePhotoService.js
async function loadProfilePhoto(cameraGateway) {
  const photo = await cameraGateway.getPhoto();
  return { path: photo.path, ready: true };
}

module.exports = { loadProfilePhoto };
// profilePhotoService.test.js
const { loadProfilePhoto } = require('./profilePhotoService');

test('returns mapped photo data', async () => {
  const fakeCameraGateway = {
    getPhoto: jest.fn().mockResolvedValue({ path: '/tmp/pic.jpg' })
  };

  const result = await loadProfilePhoto(fakeCameraGateway);

  expect(result).toEqual({ path: '/tmp/pic.jpg', ready: true });
});

Ce modèle fonctionne également pour Electron. Wrap ipcRendererles accès au fichier, les intégrations de shell ou les intéractions derrière un adaptateur mince. Les tests unitaires frappent la couche de service, et non la runtime directement.

Pour les équipes testant la logique de mise à jour et les chemins d'actualisation dans les applications Capacitor, Capgo a une guide pertinent sur la mise à l'essai des mises à jour OTA Capacitor avec des scénarios de simulation.

Un aperçu rapide est utile si votre équipe normalise encore le style de test asynchrone :

Flux asynchrones sans flottabilité

Utilisez async/await dans les tests lorsque le code testé renvoie une promesse. C'est plus clair que les modèles lourds en appels de fonctions et plus facile à déboguer.

async function fetchProfile(api) {
  const response = await api.getUser();
  return response.name;
}

test('returns the user name from the API response', async () => {
  const api = {
    getUser: jest.fn().mockResolvedValue({ name: 'Ava' })
  };

  const result = await fetchProfile(api);

  expect(result).toBe('Ava');
});

Testez également la voie de l'échec :

test('throws when the API request fails', async () => {
  const api = {
    getUser: jest.fn().mockRejectedValue(new Error('network failed'))
  };

  await expect(fetchProfile(api)).rejects.toThrow('network failed');
});

Testez à la fois la voie heureuse et la voie laide. En production, la voie laide est généralement celle que les utilisateurs se rappellent.

Stratégies avancées pour des tests robustes

Un ensemble de tests devient utile lorsque cela reste utile après que le code a changé. C'est plus difficile que d'écrire un tas de tests qui passent.

Un diagramme illustrant des stratégies pour construire des logiciels robustes grâce à une couverture de tests exhaustive et à des ensembles de tests maintenables.

Utilisez le test en deux parties comme un budget

Un guide pratique recommande un 70/20/10 split entre tests unitaires, tests d'intégration et tests finauxavec les tests unitaires fournissant le feedback le plus rapide et les échecs les plus stables. La même guidance indique que tout un ensemble de tests unitaires devrait idéalement se terminer en moins de 10 secondeset les vérifications pré-commit devraient rester moins de 5 secondesselon ce guide de test de OpenReplay Je considère cela comme un outil de budget, pas une religion. Si la plupart de vos efforts sont consacrés aux tests end-to-end, votre équipe attendra trop longtemps pour obtenir des feedback. Si tout est uniquement unitaire, vous manquerez de vraies limites du système..

Pour une application __CAPGO_KEEP_0__ ou Electron, un équilibre sain ressemble généralement à ceci :

For a Capacitor or Electron app, a healthy balance usually looks like this:

  • pour la logique de tarification, les règles de permissions, la sérialisation, l'éligibilité à la mise à jour, les drapeaux de fonctionnalité et les transformations d'état Tests d'intégration
  • pour les adaptateurs de stockage, les enveloppes de plugin et les contrats de communication inter-processus Tests d'intégration pour les contrats de communication inter-processus
  • E2E tests pour quelques voyages critiques comme la connexion, le flux d'achat, la synchronisation ou les invitations de mise à jour

La couverture est une lampe-torche, pas un objectif

Les rapports de couverture sont utiles lorsqu'ils vous aident à repérer des branches non testées dans une logique importante. Ils deviennent nuisibles lorsque les équipes poursuivent des pourcentages de couverture pour leur propre compte.

Un validateur de connexion avec des tests d'extrémités réfléchis apporte plus de valeur qu'un fichier couvert rempli d'assertions triviales. C'est tout particulièrement vrai pour les code chargés en entrées comme les formulaires, les parseurs, la logique des dates et les vérifications de permissions. Si votre équipe resserre la qualité autour de la validation lourde de l'interface utilisateur, ce guide sur la maîtrise de la validation de formulaire frontend est un bon complément à la stratégie de test au niveau unitaire. Les tests comportementaux résistent aux réorganisations

Un ensemble fiable devrait vous permettre de réorganiser les internes sans réécrire la moitié des tests. La meilleure façon d'y parvenir est d'assurer

le comportement observable au lieu des détails d'implémentation. Les cas d'utilisation qui résistent bien :

Les cas d'utilisation qui résistent bien :

  • Conditions de limites comme des entrées vides, des valeurs similaires à null, des types invalides et des chaînes de caractères surdimensionnées
  • Résultats du domaine comme « les retours sont refusés en raison d'une permission manquante »
  • Transitions d'état comme « marque l'actualisation comme en attente après la validation des métadonnées de téléchargement »

Cas d'utilisation qui se détériorent souvent :

  • l'inspection d'appels d'aide interne
  • l'affirmation de la séquence de méthodes privées
  • le mocking de chaque niveau de la chaîne d'appel

Pour les équipes de développement d'applications qui construisent des processus de mise en production disciplinés, l'article de Capgo sur la garantie de la qualité des applications est utile car il relie le travail de test à la plus large chaîne de livraison.

Test pour CI, Capacitor, et Electron Apps

Un test qui ne s'exécute que sur une machine d'un développeur n'est pas un filet de sécurité. C'est une habitude locale.

CI transforme le travail de test JavaScript en infrastructure d'équipe. Chaque push, demande de tirage ou branch de version peut exécuter les mêmes commandes avec les mêmes attentes. Cette cohérence compte encore plus pour Capacitor et Electron, où le dérive de l'environnement entraîne des échecs subtils.

Fixez l'exécution par défaut sur CI

Au minimum, votre CI doit installer les dépendances et exécuter le jeu de tests unitaires à chaque ensemble de modifications. Gardez la commande identique à celle de développement local lorsque possible.

Un workflow d'Actions GitHub de base peut être aussi petit que cela :

name: test

on: [push, pull_request]

jobs:
  unit:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: '20'
      - run: npm ci
      - run: npm test

Cela suffit pour capturer les imports brisés, les assertions échouées et les hypothèses d'assomption de plateforme accidentelles avant qu'elles ne soient intégrées dans la version principale.

Pour les équipes mobiles qui acheminent à travers des pipelines automatisés, Capgo a une guide pratique pour la mise en place de CI/CD pour les applications Capacitor.

Testez les interactions du plugin Capacitor

L'approche incorrecte pour tester les Capacitor code est de tirer les plugins natifs directement dans chaque service. Cela couple votre jeu de tests à la passerelle de plateforme.

Le modèle plus performant est une abstraction fine :

// deviceStorage.js
async function saveFile(filesystem, path, data) {
  return filesystem.writeFile({ path, data });
}

module.exports = { saveFile };
// draftService.js
async function persistDraft(storage, draft) {
  await storage.save('draft.json', JSON.stringify(draft));
  return { saved: true };
}

module.exports = { persistDraft };
// draftService.test.js
const { persistDraft } = require('./draftService');

test('persists a serialized draft', async () => {
  const storage = {
    save: jest.fn().mockResolvedValue(undefined)
  };

  const result = await persistDraft(storage, { title: 'Hello' });

  expect(result).toEqual({ saved: true });
});

L'idée est applicable à l'accès à la caméra, aux invitations biométriques, à l'enregistrement de jetons de poussée et à l'état de réseau. Conservez les appels de plugins dans les adaptateurs. Testez la logique de l'application contre des interfaces que vous contrôlez.

Testez Electron main renderer et IPC code

Les applications Electron ont deux joints importants : processus principal code et renderer process codeprocessus de rendu __CAPGO_KEEP_0__

. N'effacez pas ces joints dans les tests.

  • Une configuration fiable sépare généralement : Tests unitaires de rendu
  • pour les modèles de vue, l'état, la mise en forme et la logique commerciale côté UI pour les menus, les opérations de fichiers et les décisions de cycle d'application
  • tests du contrat de communication inter-processus pour la forme des messages et les réponses attendues

Exemple de wrapper de communication inter-processus :

// ipcGateway.js
function sendSettings(ipcRenderer, payload) {
  ipcRenderer.send('settings:update', payload);
}

module.exports = { sendSettings };
// ipcGateway.test.js
const { sendSettings } = require('./ipcGateway');

test('sends settings update over ipc', () => {
  const ipcRenderer = { send: jest.fn() };

  sendSettings(ipcRenderer, { theme: 'dark' });

  expect(ipcRenderer.send).toHaveBeenCalledWith('settings:update', { theme: 'dark' });
});

Si vous modifiez plus tard l'implémentation interne d'un helper en un autre, ce test reste valable car il vérifie le comportement qui compte. C'est le standard que vous souhaitez pour les desktop et les mobiles code.

Questions Fréquentes sur les Tests Unitaires de JavaScript

Quelle est la différence entre les tests unitaires et d'intégration et les tests E2E

A test unitaire vérifie une petite pièce de logique en isolation. Un test d'intégration vérifie si quelques composants ou services fonctionnent ensemble correctement. Un tests de bout en bout exerce une trajectoire utilisateur à travers l'application en cours d'exécution.

Utilisez les tests unitaires pour une confiance rapide dans les règles commerciales. Utilisez les tests d'intégration pour les joints tels que le stockage, les enveloppes de plugins et l'IPC. Utilisez les tests E2E avec parcimonie pour les workflows qui seraient gravement affectés si ils se rompaient.

Devrions-nous viser une couverture complète

Non. Une couverture complète peut pousser les équipes vers des tests de faible valeur.

La couverture est utile lorsqu'elle révèle des risques code inconnus qui n'ont jamais été exercés. C'est pas utile lorsqu'ingénieurs ajoutent des assertions superficielles juste pour satisfaire un tableau de bord. Si votre ensemble est fragile, plus de couverture ne le sauvera pas.

Comment ajouter des tests à un codebase existant

Commencez là où les changements ont déjà lieu. N'immobilisez pas l'équipe et n'annoncez pas une grande réécriture de la stratégie de test.

Une séquence pratique ressemble à ceci :

  • Protégez les code actifs en premier en ajoutant des tests aux modules que vous touchez pendant le travail de fonctionnalité ou les corrections de bogues
  • Extraire la logique pure des fichiers difficiles à tester afin que les règles commerciales puissent être testées sans bruitage de framework ou de runtime
  • Ajoutez des enveloppes de jointure autour de plugins natifs, de clients de réseau, d'appels au système de fichiers et d'IPC Electron
  • Refusez les modèles fragiles lorsque vous introduisez des simulations. Les conseils de la meilleure pratique de test de JavaScript sont particulièrement utiles ici car ils mettent en évidence le problème souvent manqué de sur-simulation et les tests fragiles qui suivent L'objectif n'est pas la complétude immédiate. C'est une amélioration progressive dans les endroits où les régressions coûtent le plus à l'équipe

Si votre équipe expédie


Capgo Capacitor Le but n'est pas la complétude immédiate. C'est une amélioration progressive dans les endroits où les régressions coûtent le plus à l'équipe ou applications et nécessite un processus de mise à jour plus propre autour des modifications JavaScript, Capgo est une option à considérer. Elle fournit des mises à jour en temps réel pour les applications CapacitorJS et Electron, avec des contrôles de déploiement et des capacités d'observation, afin que les équipes puissent associer des tests unitaires solides à un chemin de navigation plus sûr vers la mise à jour des changements de bundle web sans attendre la revue de chaque correctif par les magasins.

Mises à jour instantanées pour les applications Capacitor

Lorsqu'un bug de la couche web est en direct, expédiez la correction par le biais de 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.

Un support humain de Martin

Commencez dès maintenant

Dernières actualités de notre Blog

Capgo vous offre les meilleures informations nécessaires pour créer une application mobile véritablement professionnelle.