Gabriel Jiménez | Hace alrededor de 1 mes
En este artículo, aprenderemos a simular peticiones al backend dentro de nuestras pruebas, usando Mock Service Worker. Además, listaremos las diferencias entre Jest, React Testing Library y Mock Service Worker. Una vez que entendamos para que sirve cada herramienta, desarrollaremos un ejemplo práctico utilizándolas en conjunto.
Mock Service Worker es una librería para simular peticiones a nuestra API.
En empresas medianas o grandes, configurar el API puede ser una tarea bastante pesada, puede que nuestra API involucre que varios microservicios se comuniquen entre si. Además, cada uno puede tener su propia configuración. Como desarrolladores frontend configurar estos servicios, puedo atrasarnos y distraernos de nuestro objetivo principal — comunicar el frontend con nuestros servicios (backend).
Un punto importante a destacar sobre Mock Service Worker es sobre la respuesta que devuelve al interceptar una petición HTTP. Si la petición que hacemos “api/productos” existe en Mock Service Worker, devuelve la data simulada, en caso contrario, nuestra API real la procesa.
Para configurar Mock Service Worker es bastante sencillo, consta de cuatro sencillos pasos:
1. Instalar Mock Service Worker usando “npm”
npm install [email protected] --save-de
2. Crear nuestros interceptores (handlers) para simular la data
import { rest } from "msw";
export const handlers = [
rest.get(“/api/usuarios”, (req, res, ctx) => {
return res(
ctx.status(200),
ctx.json([{ id: 1, name: "John Doe" }])
);
}),
];
3. Configuramos un server para habilitar los interceptores de nuestra aplicación
import { setupServer } from "msw/node";
import { handlers } from "./handlers";
export const server = setupServer(...handlers);
4. Encendemos el server para interceptar cualquier petición HTTP
import { server } from ‘./mocks/node.js'
server.listen()
De esta forma, cada que se haga una petición a la url “/api/usuarios”, Mock Service Worker entra en acción.
Si quieres aprender a configurar Jest en tu entorno, revisa mi publicación: Qué es Jest y cómo funciona con React
Nuestro ejemplo práctico, consiste en crear una aplicación bastante sencilla para ilustrar el funcionamiento de Jest, React Testing Library y Mock Service Worker.
Nuestra aplicación hace lo siguiente:
Nuestra prueba debe de validar lo siguiente:
Configurando nuestro entorno
Para agilizar y enfocarnos en la funcionalidad principal, utilizaremos Create React App porque facilita la configuración de Jest y React Testing Library.
Creación de nuestro proyecto
Creamos nuestra aplicación usando el comando:
npx create-react-app mock-service-worker cd mock-service-worker npm start
Instalación y configuración de Mock Service Worker
Ya dentro del proyecto “my-app”, instalamos Mock Service Worker con el siguiente comando:
npm install [email protected] --save-de
Creación de nuestro interceptor de productos
File: src/mocks/handlers.js
1: import { rest } from "msw";
2:
3: export const handlers = [
4: rest.get("/api/productos", (req, res, ctx) => {
5: return res(
6: ctx.status(200),
7: ctx.json([{ id: 1, name: "Producto A" }])
8: )})
9: ]
Habilitamos nuestros interceptores
File: src/mocks/server.js
1: import { setupServer } from 'msw/node'
2: import { handlers } from './handlers'
3: export const server = setupServer(...handlers)
Ya que hemos configurado todo nuestro entorno, estamos listo para atacar la funcionalidad principal de nuestra aplicación “Crear una compra”.
Lo primero es crear nuestro archivo de pruebas “CrearCompra.test.jsx”, y dentro, nuestra primera prueba.
File: src/CrearCompra.test.jsx
1: describe('CrearCompra', () => {
2: it('crear compra correctamente', () => {
3: })
4: });
Si quieres aprender más sobre testing en React, revisa alguno de mis casos prácticos como: Cómo probar el flujo de registro en Slack con React Testing Library y Jest
Continuemos con la implementación de nuestra prueba:
File: src/CrearCompra.test.jsx
1: import * as React from 'react';
2: import CrearCompra from "./CrearCompra";
3: import {act, fireEvent, render, screen} from "@testing-library/react";
4: import {server} from "./mocks/server.js";
5:
6: describe('CrearCompra', () => {
7: it('crear compra correctamente', async () => {
8: server.listen()
9:
10: const props = { onSubmit: jest.fn() }
11:
12: await act(() => {
13: render(<CrearCompra { ...props } />);
14: })
15:
16: fireEvent.change(screen.getByTestId('producto'), { target: { value: 1 } });
17: fireEvent.change(screen.getByPlaceholderText('Precio'), { target: { value: '1000' } });
18: fireEvent.change(screen.getByPlaceholderText('Descripción'), { target: { value: 'Para mi mascota' } });
19:
20: fireEvent.submit(screen.getByText('Guardar'));
21:
22: expect(props.onSubmit).toHaveBeenCalledWith({
23: producto: '1',
24: precio: '1000',
25: descripcion: 'Para mi mascota',
26: });
27: })
28: });
Línea 8
Activamos nuestro servidor para interceptar las peticiones a nuestra API.
Línea 10
Definimos los props del componente
Linea 12-14
Montamos nuestro componente mientras esperamos a que los productos se devuelvan del API y se los listamos al usuario.
Línea 16
Seleccionamos el producto con “id” 1.
Línea 17-18
Escribimos el precio y una descripción.
Línea 20
Hacemos clic en el botón Guardar. En este momento se lanza la petición al backend.
Line 22-27
Validamos que la función onSubmit reciba la data correctamente.
Ahora, debemos de agregar la implementación del componente productivo para pasar esta prueba.
File: src/CrearCompra.jsx
1: import React from 'react'
2: import axios from 'axios'
3: import {useEffect, useState} from "react";
4:
5: const CrearCompra = ({ onSubmit }) => {
6: const [values, setValues] = useState({
7: producto: "",
8: precio: "",
9: descripcion: "",
10: });
11: const [productos, setProductos] = useState([]);
12:
13: useEffect(() => {
14: axios.get("/api/productos")
15: .then(({ data }) => {
16: setProductos(data)
17: })
18: }, [])
19:
20: function handleChange({ target }) {
21: const { name, value } = target;
22:
23: setValues({ ...values, [name]: value });
24: }
25:
26: async function handleSubmit() {
27: await onSubmit(values)
28: }
29:
30: return (
31: <form onSubmit={handleSubmit}>
32: <select name="producto" data-testid="producto" onChange={handleChange}>
33: <option value="">Seleccione</option>
34: {productos.map(producto => (
35: <option key={producto.id} value={producto.id}>{producto.name}</option>
36: ))}
37: </select>
38: <input type="text" name='precio' placeholder="Precio" onChange={handleChange} />
39: <input type="text" name='descripcion' placeholder="Descripción" onChange={handleChange} />
40: <button type="submit">Guardar</button>
41: </form>
42: )
43: }
44:
45: export default CrearCompra
Bastante sencillo, define un estado con tres campos: producto, precio y descripción. Cada campo se sincroniza usando handleChange. Al montar el componente realizamos una petición al API para solicitar los productos y poderlos listar. Al hacer clic en el botón se envía la data al backend mediante la función onSubmit.
Si ejecutamos esta prueba, obtendremos un resultado exitoso como el siguiente:
PASS src/CrearCompra.test.jsx
CrearCompra
✓ crear compra correctamente (34 ms)
Test Suites: 1 passed, 1 total
Tests: 1 passed, 1 total
Snapshots: 0 total
Time: 0.717 s, estimated 1 s
Conclusión
Mock Server Worker es una herramienta útil para simular la comunicación con nuestras API. Evita tener que preocuparnos por configurar y mantener nuestras APIs funcionando en nuestro entorno local.