Skip to content

Instantly share code, notes, and snippets.

@Codooze
Last active July 25, 2023 12:39
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Codooze/7453045a43e88a07f69da07aad223f6e to your computer and use it in GitHub Desktop.
Save Codooze/7453045a43e88a07f69da07aad223f6e to your computer and use it in GitHub Desktop.
Guia de React setup con vite y 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

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

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,
};

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);
  });
});

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

module.exports = "";

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";
  },
};
//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 };
  },
};
//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(),
});

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
  }
}

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"
  },

Eso sería todo, nótese que tuve que cambiar module por commonjs aun así la app corre normalmente.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment