En el desarrollo de aplicaciones web es fundamental poder probar y depurar el código que interactúa con APIs. Sin embargo, esto puede resultar complicado cuando no se dispone de acceso constante a los servidores de dichas APIs o cuando se desea simular diferentes escenarios de respuesta. Es aquí donde entra en juego Mock Service Worker (MSW), una biblioteca que nos permite simular servicios y APIs en el entorno de desarrollo y pruebas.

¿Qué es Mock Service Worker?

Mock Service Worker es una biblioteca de JavaScript que permite interceptar las solicitudes de red salientes y responder a ellas de manera controlada. Con MSW podemos simular respuestas de API personalizadas, establecer tiempos de espera, simular errores y mucho más. Es una herramienta poderosa para desarrolladores y equipos de pruebas, ya que nos permite trabajar de forma aislada y predecible, independientemente de la disponibilidad o el estado de los servicios reales.

Principales características

Instalación

Para testear la integración con Mock Service Worker, crearemos un proyecto de Vue, Vite y TypeScript, la configuración será similar si seleccionamos otro framework o librería como Angular o React.

npm create vite@latest orval-vue

Es importante seleccionar las opciones Vue y TypeScript para crear un proyecto base correctamente.

Ejecutaremos el siguiente comando para instalar la dependencia correspondiente:

npm install msw --save-dev

Recomendamos la instalación de @faker-js/faker, será el encargado de generar datos aleatorios para nuestras peticiones y nuestros mocks.

npm install @faker-js/faker

A continuación crearemos un fichero de configuración mock.config.ts, con la siguiente estructura:

// mock.config.ts
import { RequestHandler } from 'msw';
import { setupWorker } from 'msw/browser';

const mocks: Array<RequestHandler> = [];

const loadHandler = () => {
  // Añadir aquí los servicios mockeados
};

const initMocks = () => {
  loadHandler();
  const worker = setupWorker(...mocks);
  worker.start();
};

export default initMocks;

Como último paso en la configuración tendremos que ejecutar el siguiente comando, indicando el directorio público de nuestro proyecto que dependiendo de la tecnología principal de nuestro proyecto puede cambiar. Puedes verificar la configuración del directorio público por defecto en el siguiente enlace.

npx msw init ./public --save

Integración

Para integrar Mock Service Worker tendremos que invocar la función initMocks declarada anteriormente. Para ello modificaremos nuestro fichero main.ts añadiendo el siguiente bloque de código:

// main.tsx
import initMocks from './__mocks__/config/mock.config';

if (import.meta.env.VITE_APP_MOCKS === 'true') {
  initMocks();
}

Es recomendable añadir una variable de entorno, en nuestro caso VITE_APP_MOCKS, para determinar si estamos arrancando el servidor en modo mock, de esa manera solo ejecutaremos la instancia de mocks service worker cuando sea necesario.
Para determinar el modo de arranque solo tendremos que añadir un script a nuestro package.json con el parámetro “--mode mocks” y crear el fichero de variables de entorno .env.mocks con la variable de entorno ”VITE_APP_MOCKS=true”.

// Definición en package.json
"dev:mocks": "vite --mode mocks --open && tsc",

// Nueva variable de entorno, true solamente en .env.mocks
VITE_APP_MOCKS=true

//Arranque del servidor en modo mocks
npm run dev:mocks

Con todo configurado, ejecutaremos el script dev:mocks para arrancar nuestro servidor, tras arrancar el servidor y verificar que Mock Service Worker está configurado correctamente tendremos que revisar la consola de nuestro navegador, donde aparecerá el siguiente mensaje, que confirmará si el service worker está interceptando las peticiones.

Mock mensaje

Agregando mocks

Una vez configurado nuestro proyecto, el siguiente paso será añadir los servicios que queremos mockear, para ello tendremos que modificar en el fichero mocks.config.ts, la función loadHandler, añadiendo las definiciones necesarias para cada petición:

// pokemon.service.mocks.ts

import {delay, http, HttpResponse} from "msw";

// Mocks que devolverá siempre nuestro servicio
const findAllJson = { ... };
const findByIdJson = { ... };
const findByNameJson = { ... };

export const getPokemonServicesMock = () => [
    http.get('*/api/v2/pokemon/:name/', async () => {
        return new HttpResponse(JSON.stringify(findByNameJson), {
            status: 200,
            headers: {
                'Content-Type': 'application/json',
            },
        });
    }),
    http.get('*/api/v2/pokemon/', async () => {
        await delay(1000); // Configuración de delay para retrasar la petición
        return new HttpResponse(JSON.stringify(findAllJson), {
            status: 200,
            headers: {
                'Content-Type': 'application/json',
            },
        });
    }),

     http.get('*/api/v2/pokemon/:id', async () => {
        return new HttpResponse(JSON.stringify(findByIdJson), {
            status: 500, // Configuración de status, útil para probar integración con errores
            headers: {
                'Content-Type': 'application/json',
            },
        });
    }),

];

Una vez definidas las respuestas de las peticiones será el momento de añadir a nuestro fichero mocks.config.ts la respuesta que acabamos de generar, ya que Mock Service Worker necesita las respuestas a la hora de inicializar la instancia.

import { getPokemonServicesMock } from "../pokemon/pokemon.service.mocks";

const mocks: Array<RequestHandler> = [];

const loadHandler = () => {
    mocks.push(...getPokemonServicesMock());
};

De esta manera, dividiendo la definición de servicios de cada ámbito por fichero, si queremos mockear solamente una parte de nuestra aplicación (por ejemplo, el login) solo tendríamos que añadir el fichero correspondiente a nuestra definición dentro de loadlHandler.

Datos de prueba aleatorios

Anteriormente, en el apartado de instalación, hemos añadido la dependencia @faker-js/faker, que nos proporcionará una forma sencilla de generar datos aleatorios realistas en diferentes formatos, como nombres, direcciones, números de teléfono, direcciones de correo electrónico, texto lorem ipsum, fechas y muchos más. Por ejemplo, para generar datos aleatorios en nuestro detalle del ejemplo anterior, la definición de nuestro JSON sería así:

import { faker } from "@faker-js/faker";

const pikachuJson = {
    "base_experience":  faker.number.int(),
    "forms": [
        {
            "name": faker.internet.userName,
            "url": faker.internet.url
        }
    ],
    "height":  faker.number.int(),
    "id":  faker.number.int(),
    "is_default": faker.datatype.boolean(),
    "location_area_encounters": faker.internet.url,
    "name": faker.internet.userName,
    "order":  faker.number.int(),
    "species": {
        "name": faker.internet.userName,
        "url": faker.internet.url
    },
    "sprites": {},
    "types": [
        {
            "slot":  faker.number.int(),
            "type": {
                "name": faker.person.firstName(),
                "url": faker.internet.url
            }
        }
    ],
    "weight":  faker.number.int()
};

De esta manera, solo tenemos que especificar el tipo de dato que queremos crear en cada caso. Será de utilidad la documentación oficial de faker para usar el dato más adecuado en cada caso.

Conclusión

Mock Service Worker es una herramienta valiosa para simplificar y agilizar el desarrollo y las pruebas unitarias. Al simular solicitudes de red y tener control total sobre las respuestas, MSW te permite realizar desarrollos más rápidos, estables y específicos. Aprovecha esta potente biblioteca para mejorar la calidad de tu código y facilitar el proceso de desarrollo y pruebas en tu proyecto.

Cuéntanos qué te parece.

Los comentarios serán moderados. Serán visibles si aportan un argumento constructivo. Si no estás de acuerdo con algún punto, por favor, muestra tus opiniones de manera educada.

Suscríbete

Estamos comprometidos.

Tecnología, personas e impacto positivo.