Maison interface Web js tutoriel Faisons fonctionner Jest beaucoup plus rapidement

Faisons fonctionner Jest beaucoup plus rapidement

Oct 31, 2024 pm 12:23 PM

Let’s Make Jest Run Much Faster

Mais d'abord, nous devons comprendre pourquoi c'est si lent.

Exemple pratique

Considérons un simple composant React.

import React from "react";
import { deepClone } from "./utils";

export function App() {
  const obj = { foo: 'bar' };

  return (
    <div>
      <p>Object looks like this: {JSON.stringify(deepClone(obj))}</p>
    </div>
  );
}
Copier après la connexion
Copier après la connexion
Copier après la connexion

Le composant de l'application ne dépend que d'une seule fonction utilitaire - deepClone. Le fichier utils ressemble à ceci.

import _ from 'lodash';
import moment from 'moment';
import * as mui from '@mui/material';

export const deepClone = (obj) => _.cloneDeep(obj);
export const getFormattedDate = (date) => moment(date).format('YYYY-MM-DD');

export const isButton = (instance) => instance === mui.Button;
Copier après la connexion
Copier après la connexion

Il exporte trois fonctions d'assistance sur une ligne. C'est tout.
Maintenant, voici une grande question : combien de temps pensez-vous qu'il faudra pour exécuter ce test ?

import React from "react";
import { render, screen } from "@testing-library/react";
import { App } from "./app";
import "@testing-library/jest-dom";

test("renders the app", () => {
  render(<App />);
});
Copier après la connexion
Copier après la connexion

La réponse ? Une éternité !

 PASS  src/tests/react-app/react-app.test.js
  √ renders the date and sum correctly (25 ms)

Test Suites: 1 passed, 1 total
Tests:       1 passed, 1 total
Snapshots:   0 total
Time:        5.045 s
Copier après la connexion

Il a fallu 5 secondes sur ma machine pour exécuter un scénario de test à une seule ligne pour un composant React à une seule ligne.

Analyse des performances

Pour analyser ce qui se passe dans les coulisses, nous pouvons utiliser le profileur de Chrome - Je vous recommande de regarder cette vidéo perspicace de Kent C. Dodds.
Alternativement, vous pouvez utiliser une bibliothèque jest-neat-runner, qui simplifie le processus de profilage. Définissez l'option NEAT_REPORT_MODULE_LOAD_ABOVE_MS sur 150 et activez NEAT_REPORT_TRANSFORM. Cette configuration imprimera les modules qui prennent plus de 150 ms à charger et fournira des informations sur le temps qu'il a fallu pour traiter (ouvrir et transpiler) les fichiers.

Utilisons ce dernier. C'est le résultat.

> jest src/tests/react-app/

From src\tests\react-app\utils.js -> @mui/material in 1759ms
From node_modules\@mui\material\node\styles\adaptV4Theme.js -> @mui/system in 509ms
From src\tests\react-app\react-app.test.js -> @testing-library/react in 317ms
From node_modules\@testing-library\react\dist\pure.js -> @testing-library/dom in 266ms
From node_modules\@mui\system\ThemeProvider\ThemeProvider.js -> @mui/private-theming in 166ms
From node_modules\@testing-library\dom\dist\role-helpers.js -> aria-query in 161ms
Copier après la connexion

On charge la bibliothèque "@mui/material" pendant presque 2 secondes sans même l'utiliser !

Cause fondamentale de nombreux projets ?

Dépendances désordonnées

D'après mon expérience, les problèmes de performances avec jest proviennent principalement du grand nombre de dépendances transitives qui ne sont même pas utilisées au moment de l'exécution. Comme le montre notre exemple ci-dessus, si vous ne prêtez pas suffisamment attention aux fichiers que vous importez dans votre application, vous pourriez vous retrouver dans la même situation que moi.

Dans mon cas, le composant App dépend uniquement de la fonction utilitaire deepClone. Cependant, puisque deepClone est exporté à partir du fichier utils, toutes les dépendances du fichier utils ont également été chargées avec celui-ci.

Les fichiers contenant de nombreuses fonctions vaguement liées et de lourdes dépendances peuvent ralentir considérablement votre application et vos tests.

Fichiers de baril

Jest n'est pas un ami des modules ESM, ce qui l'amène à se replier sur CommonJS. Par conséquent, le tremblement d’arbre ne fonctionne pas correctement. Ceci est particulièrement problématique lorsqu'on s'appuie sur des modules importés à partir de fichiers Barrel (fichiers d'index).
Par exemple, lorsque vous importez un petit composant ou une fonction à partir d'un fichier Barrel, Jest chargera également tout le reste - , ce qui entraîne évidemment une surcharge inutile.

Et maintenant ?

Ajuster manuellement la stratégie d'importation

En plus de supprimer les fichiers Barrel et de refactoriser l'intégralité de la base de code en divisant les fichiers avec de nombreuses dépendances en modules plus petits et plus ciblés. Nous pouvons identifier les modules qui prennent beaucoup de temps à charger et rechercher des modules alternatifs plus petits ou vérifier si le module importé exporte des pièces individuelles séparément (c'est-à-dire des importations nommées) au lieu d'utiliser le fichier baril.
C'est-à-dire, au lieu de

import React from "react";
import { deepClone } from "./utils";

export function App() {
  const obj = { foo: 'bar' };

  return (
    <div>
      <p>Object looks like this: {JSON.stringify(deepClone(obj))}</p>
    </div>
  );
}
Copier après la connexion
Copier après la connexion
Copier après la connexion

faire

import _ from 'lodash';
import moment from 'moment';
import * as mui from '@mui/material';

export const deepClone = (obj) => _.cloneDeep(obj);
export const getFormattedDate = (date) => moment(date).format('YYYY-MM-DD');

export const isButton = (instance) => instance === mui.Button;
Copier après la connexion
Copier après la connexion

Si nous n'utilisons pas du tout le module, nous pouvons le simuler via jest.mock pour éviter de le charger complètement.
Cependant, ces ajustements peuvent prendre beaucoup de temps.

Approche du cache d'exécution

Une méthode plus efficace consiste à utiliser la bibliothèque jest-neat-runner avec l'option NEAT_RUNTIME_CACHE. Lorsque cette option est activée, la bibliothèque suit l'utilisation réelle de tous les modules (par fichier de test) et stocke les dépendances dont nous n'avons pas besoin pour les tests ultérieurs dans un cache. Laissez-moi vous montrer ce qu'il fait sur l'exemple ci-dessus

import React from "react";
import { render, screen } from "@testing-library/react";
import { App } from "./app";
import "@testing-library/jest-dom";

test("renders the app", () => {
  render(<App />);
});
Copier après la connexion
Copier après la connexion

Nous avons réduit le temps d'exécution de cinq secondes à deux en sautant le chargement de 26 bibliothèques inutiles, dont la bibliothèque MUI.
Soyez prudent - il y a plusieurs mises en garde lors de l'utilisation de NEAT_RUNTIME_CACHE, alors assurez-vous de lire le README avant de l'utiliser.

Autres techniques d'optimisation

Optimisations de la transpilation : examinez le nombre de fichiers qui doivent être transpilés et utilisez le transpileur le plus efficace (comme SWC ou esbuild). Si vous souhaitez gagner du temps, l'option NEAT_REPORT_TRANSFORM de jest-neat-runner fournira des informations détaillées sur le temps et le nombre de modules nécessaires pour transpiler.

Mise en cache des modules en mémoire : Par défaut, Jest ne met pas en cache les modules en mémoire, ce qui signifie que chaque exécution de test doit ouvrir, analyser et charger le module en mémoire. Si vous disposez d'une vaste suite de tests et de suffisamment de mémoire, envisagez d'utiliser l'option NEAT_TRANSFORM_CACHE pour accélérer les choses.

Qu’en est-il du pipeline CI ?

Exécutions parallèles : CircleCI et GitHub Actions prennent en charge les exécutions parallèles. Cela signifie que vous pouvez faire tourner plus de machines et diviser la charge à l'aide du paramètre shard dans Jest.
Stockage du cache Jest et Neat : ceci est crucial pour tirer parti de Jest et de Jest-neat-runner dans le CI. Assurez-vous de définir l'option cacheDirectory dans Jest. Ensuite, stockez le répertoire après l’exécution du test et restaurez le cache avant d’exécuter les tests. Attention : si vous utilisez le parallélisme, assurez-vous de stocker des caches uniques pour chaque nœud. Par exemple, CircleCI expose la variable d'environnement CIRCLE_NODE_INDEX, que vous pouvez exploiter lors du stockage du cache. Voici à quoi cela ressemble dans le CircleCI.

import React from "react";
import { deepClone } from "./utils";

export function App() {
  const obj = { foo: 'bar' };

  return (
    <div>
      <p>Object looks like this: {JSON.stringify(deepClone(obj))}</p>
    </div>
  );
}
Copier après la connexion
Copier après la connexion
Copier après la connexion

En suivant ces directives, vous pouvez améliorer considérablement les performances de Jest dans vos projets.

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn

Article chaud

Combien de temps faut-il pour battre Split Fiction?
3 Il y a quelques semaines By DDD
Repo: Comment relancer ses coéquipiers
3 Il y a quelques semaines By 尊渡假赌尊渡假赌尊渡假赌
Hello Kitty Island Adventure: Comment obtenir des graines géantes
3 Il y a quelques semaines By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. Crystals d'énergie expliqués et ce qu'ils font (cristal jaune)
1 Il y a quelques semaines By 尊渡假赌尊渡假赌尊渡假赌

Article chaud

Combien de temps faut-il pour battre Split Fiction?
3 Il y a quelques semaines By DDD
Repo: Comment relancer ses coéquipiers
3 Il y a quelques semaines By 尊渡假赌尊渡假赌尊渡假赌
Hello Kitty Island Adventure: Comment obtenir des graines géantes
3 Il y a quelques semaines By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. Crystals d'énergie expliqués et ce qu'ils font (cristal jaune)
1 Il y a quelques semaines By 尊渡假赌尊渡假赌尊渡假赌

Tags d'article chaud

Bloc-notes++7.3.1

Bloc-notes++7.3.1

Éditeur de code facile à utiliser et gratuit

SublimeText3 version chinoise

SublimeText3 version chinoise

Version chinoise, très simple à utiliser

Envoyer Studio 13.0.1

Envoyer Studio 13.0.1

Puissant environnement de développement intégré PHP

Dreamweaver CS6

Dreamweaver CS6

Outils de développement Web visuel

SublimeText3 version Mac

SublimeText3 version Mac

Logiciel d'édition de code au niveau de Dieu (SublimeText3)

Remplacer les caractères de chaîne en javascript Remplacer les caractères de chaîne en javascript Mar 11, 2025 am 12:07 AM

Remplacer les caractères de chaîne en javascript

jQuery obtient un rembourrage / marge d'élément jQuery obtient un rembourrage / marge d'élément Mar 01, 2025 am 08:53 AM

jQuery obtient un rembourrage / marge d'élément

jQuery Vérifiez si la date est valide jQuery Vérifiez si la date est valide Mar 01, 2025 am 08:51 AM

jQuery Vérifiez si la date est valide

10 onglets jQuery Accordion 10 onglets jQuery Accordion Mar 01, 2025 am 01:34 AM

10 onglets jQuery Accordion

10 vaut la peine de vérifier les plugins jQuery 10 vaut la peine de vérifier les plugins jQuery Mar 01, 2025 am 01:29 AM

10 vaut la peine de vérifier les plugins jQuery

Http débogage avec le nœud et le http-console Http débogage avec le nœud et le http-console Mar 01, 2025 am 01:37 AM

Http débogage avec le nœud et le http-console

Tutoriel de configuration de l'API de recherche Google personnalisé Tutoriel de configuration de l'API de recherche Google personnalisé Mar 04, 2025 am 01:06 AM

Tutoriel de configuration de l'API de recherche Google personnalisé

jQuery Ajouter une barre de défilement à div jQuery Ajouter une barre de défilement à div Mar 01, 2025 am 01:30 AM

jQuery Ajouter une barre de défilement à div

See all articles