DEV Community

ᒍᗩᑕE
ᒍᗩᑕE

Posted on • Edited on

React with vite + jest

¡Hola! En este tutorial te mostraré cómo usar React con Vite y Jest. Usaremos pnpm como gestor de paquetes. Para empezar, asumiré que ya has creado un proyecto básico de React con Vite y que has instalado todas las dependencias necesarias.

pnpm create vite
Enter fullscreen mode Exit fullscreen mode

Para este ejemplo usaremos React + typescript

Para este tutorial me "guie" 🤣 por este otro está en inglés, la razón por la que quise contribuir con una nueva versión es que ya ha habido algunos cambios en Jest por lo que todo lo que encuentren allí no funcionará 100%. Aunque allí está mejor explicado todo por alguien si sabe lo que hace ❤️.

Paso 1: Instalar Jest

Primero, debes instalar Jest como una dependencia de desarrollo en tu proyecto. Para hacer esto, abre una terminal en la raíz de tu proyecto y ejecuta el siguiente comando:

pnpm install --save-dev jest @types/jest jest-environment-jsdom jest-watch-typeahead @testing-library/dom @testing-library/jest-dom @testing-library/react @testing-library/user-event @swc/jest @types/testing-library__jest-dom
Enter fullscreen mode Exit fullscreen mode

Paso 2: Configurar Jest

Ahora, necesitas configurar Jest en tu proyecto. Crea un archivo llamado jest.config.cjs en la raíz de tu proyecto y pega el siguiente código:

module.exports = {
  roots: ["<rootDir>/src"],
  collectCoverageFrom: [
    "src/**/*.{js,jsx,ts,tsx}",
    "!src/**/*.d.ts",
    "!src/mocks/**",
  ],
  coveragePathIgnorePatterns: [],
  setupFilesAfterEnv: ["./config/jest/setupTests.js"],
  testEnvironment: "jsdom",
  modulePaths: ["<rootDir>/src"],
  transform: {
    "^.+\\.(ts|js|tsx|jsx)$": "@swc/jest",
    "^.+\\.css$": "<rootDir>/config/jest/cssTransform.js",
    "^(?!.*\\.(js|jsx|mjs|cjs|ts|tsx|css|json)$)":
      "<rootDir>/config/jest/fileTransform.js",
  },
  transformIgnorePatterns: [
    "[/\\\\]node_modules[/\\\\].+\\.(js|jsx|mjs|cjs|ts|tsx)$",
    "^.+\\.module\\.(css|sass|scss)$",
  ],
  moduleNameMapper: {
    "^react-native$": "react-native-web",
    "^.+\\.module\\.(css|sass|scss)$": "identity-obj-proxy",
    "^.+\\.(svg)$": "<rootDir>/src/__mocks__/fileMock.js",
  },
  moduleFileExtensions: [
    // Place tsx and ts to beginning as suggestion from Jest team
    // https://jestjs.io/docs/configuration#modulefileextensions-arraystring
    "tsx",
    "ts",
    "web.js",
    "js",
    "web.ts",
    "web.tsx",
    "json",
    "web.jsx",
    "jsx",
    "node",
  ],
  watchPlugins: [
    "jest-watch-typeahead/filename",
    "jest-watch-typeahead/testname",
  ],
  resetMocks: true,
};

Enter fullscreen mode Exit fullscreen mode

Paso 3: Archivos adicionales

Crea un archivo en /src/__tests__/App.test.tsx con el siguiente contenido:

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

describe("App", () => {
  it("should work as expected", () => {
    render(<App />);
    expect(1 + 1).toBe(2);
  });
});
Enter fullscreen mode Exit fullscreen mode

Crea un archivo en /src/__mocks__/fileMock.js con el siguiente contenido:

module.exports = "";
Enter fullscreen mode Exit fullscreen mode

Esto es necesario porque Jest no puede entender cómo manejar las importaciones de archivos que no son de JS (en este caso, archivos SVG), por lo que el módulo fileTransform.js intercepta estas importaciones y devuelve el nombre de archivo del recurso. Sin esta transformación, Jest no sería capaz de ejecutar el conjunto de pruebas, ya que fallaría al resolver las importaciones de archivos que no son de JS.

Crea en la raíz del proyecto las siguientes carpetas /config/jest con los siguientes archivos: cssTransform.js, fileTransform.js, setupTests.js

//cssTransform.js
"use strict";

module.exports = {
  process(src, filename, config, options) {
    return {
      code: "module.exports = {};",
    };
  },
  getCacheKey() {
    return "cssTransform";
  },
};
Enter fullscreen mode Exit fullscreen mode
//fileTransform.js
"use strict";

const path = require("path");
const camelcase = require("camelcase");
module.exports = {
  process(src, filename) {
    const assetFilename = JSON.stringify(path.basename(filename));

    if (filename.match(/\.svg$/)) {
      // Based on how SVGR generates a component name:
      // https://github.com/smooth-code/svgr/blob/01b194cf967347d43d4cbe6b434404731b87cf27/packages/core/src/state.js#L6
      const pascalCaseFilename = camelcase(path.parse(filename).name, {
        pascalCase: true,
      });
      const componentName = `Svg${pascalCaseFilename}`;
      const svgComponentCode = `const React = require('react');
      module.exports = {
        __esModule: true,
        default: ${assetFilename},
        ReactComponent: React.forwardRef(function ${componentName}(props, ref) {
          return {
            $$typeof: Symbol.for('react.element'),
            type: 'svg',
            ref: ref,
            key: null,
            props: Object.assign({}, props, {
              children: ${assetFilename}
            })
          };
        }),
      };`;
      return { code: svgComponentCode };
    }

    const fileModuleCode = `module.exports = ${assetFilename};`;
    return { code: fileModuleCode };
  },
};
Enter fullscreen mode Exit fullscreen mode
//setupTests.js
import "@testing-library/jest-dom/extend-expect";

window.matchMedia = (query) => ({
  matches: false,
  media: query,
  onchange: null,
  addEventListener: jest.fn(),
  removeEventListener: jest.fn(),
  dispatchEvent: jest.fn(),
  addListener: jest.fn(),
  removeListener: jest.fn(),
});

Object.defineProperty(URL, "createObjectURL", {
  writable: true,
  value: jest.fn(),
});
Enter fullscreen mode Exit fullscreen mode

Crea en la raíz del proyecto un archivo llamado .swcrc con lo siguiente:

{
  "jsc": {
    "target": "es2017",
    "parser": {
      "syntax": "typescript",
      "tsx": true,
      "decorators": false,
      "dynamicImport": false
    },
    "transform": {
      "react": {
        "pragma": "React.createElement",
        "pragmaFrag": "React.Fragment",
        "throwIfNamespace": true,
        "development": false,
        "useBuiltins": false,
        "runtime": "automatic"
      },
      "hidden": {
        "jest": true
      }
    }
  },
  "module": {
    "type": "commonjs",
    "strict": false,
    "strictMode": true,
    "lazy": false,
    "noInterop": false
  }
}
Enter fullscreen mode Exit fullscreen mode

swcrc es un archivo de configuración para el compilador de JavaScript swc. swc es un compilador de JavaScript/TypeScript extremadamente rápido que se utiliza para transpilar y optimizar el código fuente de una aplicación.

Paso 4: Edita package.json

"type": "commonjs",
  "scripts": {
    //...
    "test": "jest"
  },
Enter fullscreen mode Exit fullscreen mode

Eso sería todo, nótese que tuve que cambiar module por commonjs aun así la app corre normalmente.
Por último, si desean contribuir para mejorar o mantener esta guia actualizada, pueden hacerlo desde aquí.

Top comments (5)

Collapse
 
sitonimbus profile image
Carlos Andrés Mora González

hey tienes repetido modulePaths en el fichero jest.config.cjs

Collapse
 
codooze profile image
ᒍᗩᑕE

Ya esta corregido, gracias por avisar 👍️

Collapse
 
sitonimbus profile image
Carlos Andrés Mora González

gracias a ti por compatir 🤗

Collapse
 
k_h_ra profile image
anon

excelente guia, para agregar tambien el dato que si tienen alias no le funcionará a la primera, deberan hacer modificaciones en el config de jest
quedando por ejemplo asi

moduleNameMapper: {
..,
'^@/(.*)': '/src/$1',
},

mi alias en tsconfig

"paths": {
"@/": ["./src/"]
}

Collapse
 
jerrygpstrat profile image
vertidev.com

hola amigo ami me sale el error de

Cannot find module '@testing-library/jest-dom/extend-expect' from 'config/jest/setupTests.js'

ya le busque instalando de diferentes manetras pero no funciona