Domina Vitest Mock Fetch con TypeScript y React JS: Una Guía Completa 2024

Domina Vitest Mock Fetch con TypeScript y React JS: Una Guía Completa 2024

¿Quieres hacer un unit test en vitest haciendo peticiones con fetch y no sabes cómo? Entonces haz llegado al tutorial de paso a paso para todo lo relacionado con vitest mock fetch usando TypeScript y React JS.

Si te gusta aprender visualmente, puedes ver el video tutorial que hice en mi canal de YouTube, y si no, puedes seguir leyendo este tutorial.

Mira la tabla de contenidos a continuación y da click al tema en cuestión que necesitas resolver.

Table of Contents

    Qué es Vitest y los Mocks

    En caso de que aún no estés familiarizado del todo, ¿qué es vitest? Vitest es un framework de testing de nueva generación diseñado para complementar Vite, destacando principalmente por su velocidad para el testing unitario.

    En el desarrollo FrontEnd, es común que nuestros componentes o aplicaciones necesiten interactuar con APIs externas. En este contexto, el mocking de las solicitudes fetch se convierte en una opción cuando se trata de testear dichos componentes o aplicaciones.

    El mocking es una técnica de testing que nos permite simular comportamientos de objetos o funciones en nuestros tests.

    Si suena confuso, no te preocupes, al inicio siempre es así. Pero a medida que vayas leyendo este tutorial, todo irá tomando sentido. ¡Sigamos!

    Entendiendo el Mocking de Solicitudes Fetch

    Como te decía, el mocking lo usamos para simular comportamientos de objetos o funciones en tiempo de ejecución de los tests y es muy útil para hacer pruebas de código que tiene dependencias externas.

    Como en este caso, un componente de React que depende de Fetch (que es una dependencia necesaria para que funcione el componente).

    La API Fetch es una de las maneras más populares de hacer estas solicitudes debido a que es nativa en el navegador (no tienes que instalar dependencias), y es una buena alternativa colocar estas llamadas a la API en métodos dentro de archivos de servicio como veremos a continuación.

    Lo que haremos en el test es reemplazar la implementación de la función fetch por una implementación falsa que nosotros mismos definiremos.

    De esta manera, podemos simular el comportamiento de la función fetch y probar nuestro código sin tener que hacer una llamada real a la API.

    Es más fácil de lo que parece, ¡veamos cómo se traduce esto en código!

    Configurando Vitest en un Proyecto React JS

    Para comenzar a trabajar con Vitest en un proyecto React JS, es importante tener una configuración adecuada, lo cuál es bastante sencillo y es una de las tantas ventajas de Vitest.

    En esta guía te voy a explicar todo el proceso desde cero y paso a paso.

    Para comenzar, necesitamos crear un proyecto React JS con TypeScript usando Vite. Para ello, ejecuta el siguiente comando en tu terminal:

    npm init vite@latest my-vitest-project -- --template react-ts
    

    Luego, instala las dependencias necesarias para Vitest:

    npm install -D vitest
    

    Ahora, agrega el siguiente script en el archivo package.json:

    {
      "scripts": {
        "test": "vitest"
      }
    }
    

    Para finalizar, hay diferentes formas de configurar Vitest con Vite. La más sencilla y práctica es actualizar el archivo vite.config.ts que viene en la raíz del proyecto con el siguiente contenido:

    import { defineConfig } from 'vitest/config'
    import react from '@vitejs/plugin-react'
    
    // https://vitejs.dev/config/
    export default defineConfig({
      plugins: [react()],
      test: {
        globals: true,
        environment: 'jsdom',
        setupFiles: ['./src/setup-tests.ts'],
      },
    })
    

    Nota que el import de vitest/config es necesario para que Vite pueda reconocer la configuración de Vitest.

    La propiedad test es la que nos permite configurar Vitest. En este caso, estamos definiendo que queremos usar React JS y que queremos usar el entorno de pruebas de JSDOM y usar un archivo de configuración de pruebas personalizado.

    En el archivo setup-tests.ts que definimos en la propiedad setupFiles, vamos a importar jest-dom para extender las funcionalidades de los métodos expect de Vitest.

    import '@testing-library/jest-dom'
    

    Nota: A pesar del nombre del archivo, no estamos usando Jest, sino Vitest. Pero Vitest usa Jest para algunas funcionalidades. Es por eso que podemos importar jest-dom.

    Mock de requests de Fetch con Vitest

    Vitest proporciona una forma súper fácil de mockear las solicitudes fetch.

    A continuación te presento una guía paso a paso sobre cómo mockear solicitudes GET y POST en Vitest usando un ejemplo de un Servicio Todo.

    Digamos que tienes el siguiente código en un archivo todo.tsx:

    import { useState, useEffect } from 'react'
    
    export const Todo = () => {
      const [todo, setTodo] = useState({})
    
      useEffect(() => {
        fetch('https://jsonplaceholder.typicode.com/todos/2')
          .then((response) => response.json())
          .then((json) => setTodo(json))
      }, [])
    
      return (
        <div>
          <h1>Todo</h1>
          <p>{JSON.stringify(todo)}</p>
        </div>
      )
    }
    

    Nota: Este código es sólo un ejemplo para mostrar cómo mockear las solicitudes fetch en Vitest. No es una buena práctica hacer llamadas a la API desde un componente de React.

    Lo ideal es que las llamadas a la API se hagan desde un archivo de servicio como veremos a continuación.

    Pero sirve de ejemplo para poder enseñarte también cómo hacer el test correctamente, y luego poder refactorizar el código mientras que mi test sigue funcionando.

    Hacer refactors de código y que mis tests me indiquen si sigue funcionando o no, es una de las cosas que más me gusta de hacer tests.

    Primer test

    Por regla general, me gusta crear los archivos de test con el mismo nombre que el archivo que estoy testeando, pero con la extensión .test.tsx, y ubicarlos en la misma carpeta donde está el archivo que estoy testeando.

    De este modo, puedo tener una estructura de carpetas como la siguiente:

    src/
    ├── components/
    │   ├── todo/
    │   │   ├── todo.tsx
    │   │   └── todo.test.tsx
    

    La ventaja de esta estructura es que puedo tener todos los archivos relacionados con un componente en una misma carpeta.

    Ahora, dentro de mi archivo todo.test.tsx, empiezo con la primera prueba:

    import { render, screen } from '@testing-library/react'
    
    import { Todo } from './todo'
    
    beforeEach(() => {
      vi.resetAllMocks()
    })
    
    test('renders Todo component', () => {
      render(<Todo />)
      const titleElement = screen.getByText(/todo/i)
      expect(titleElement).toBeInTheDocument()
    })
    

    En este test, estoy renderizando el componente Todo y luego estoy buscando el título Todo en el documento.

    Si el título se encuentra en el documento, significa que el componente se renderizó correctamente.

    Segundo test (Mocking de Solicitudes GET)

    Existen diferentes maneras para mockear las solicitudes fetch en Vitest. En este tutorial, vamos a usar la función vi.spyOn para mockear las solicitudes GET.

    En el archivo todo.test.tsx, vamos a agregar el siguiente test debajo del test anterior:

    import { vi } from "vitest";
    
    // previous test...
    
    test("renders the todo content", async () => {
      const mockResponse = {
        userId: 1,
        id: 2,
        title: "test pass",
        completed: false,
      };
    
      vi.spyOn(window, "fetch").mockImplementationOnce(() => {
        return Promise.resolve({
          json: () => Promise.resolve(mockResponse),
        } as Response);
      });
    
      render(<Todo />);
      const todoElement = await screen.findByText(/test pass/i);
      expect(todoElement).toBeInTheDocument();
    });
    
    

    En este test, estamos mockeando la función fetch usando vi.spyOn y mockImplementationOnce.

    La función mockImplementationOnce nos permite definir una implementación falsa de la función fetch que se ejecutará una sola vez.

    En este caso, estamos definiendo que la función fetch va a retornar una promesa que se resuelve con un objeto que tiene la misma estructura que la respuesta de la API.

    Luego, estamos renderizando el componente Todo y buscando el texto test pass en el documento.

    ¿Por qué estamos retornando una promesa? Porque la función fetch retorna una promesa al ser ejecutada (es asíncrona).

    ¿Por qué estamos retornando un objeto con la propiedad json? Porque la función fetch retorna un objeto de tipo Response que tiene un método json que retorna una promesa.

    Veamos de nuevo el código de fetch:

    fetch('https://jsonplaceholder.typicode.com/todos/2')
      .then((response) => response.json())
      .then((json) => setTodo(json))
    

    Conclusión y Recursos

    En este tutorial, aprendimos cómo usar vitest mock fetch con TypeScript y React JS.

    Vimos cómo configurar Vitest en un proyecto React JS, y cómo mockear solicitudes GET y POST usando la función vi.spyOn.

    Si quieres aprender más sobre testing, accede al mega curso y los tutoriales que tengo en mi canal de YouTube dando click aquí.

    También puedes ver más tutoriales sobre testing en mi blog dando click aquí.

    juan correa
    ¿Quieres pasar a nivel Senior en React?
    Soy Juan Correa y he ayudado a cientos de desarrolladores a avanzar en sus carreras ¿Quieres saber cómo?