Saltar a contenido

Front

Librerias necesarias

Para realizar los test de integración es necesario instalar la librería msw. Esta librería lo que hace es mockear las peticiones HTTP que es especialmente Útil para evitar pegarles a las API´s reales.

npm install -D msw

Configuración Necesaria

Tener las configuraciones necesarias colocadas en la sección de testing unitario y configuración de providers

Pasos

1. Handlers

Vienen siendo funciones que representan las peticiones HTTP, hace el front a una ruta específica y nos permite setear respuesta, estatus, delay, entre otras opciones.

  • El primer argumento del handler es la ruta que intercepta, en este caso es la ruta completa guardada en environments que por ejemplo podría ser REACT_APP_BASE_URL, siendo este el valor real de la API cuando la web le hace las peticiones.

  • El segundo argumento es el callback, que recibe el request, el response y el contexto.

Con este ejemplo podemos ver un caso simple de respuesta satisfactoria.

import { rest } from "msw";

interface IOrderResponse {
    pedidoId: string;
    message: string;
}

const dataSuccess: IOrderResponse = {
  pedidoId: "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  message: "success",
};
// Estos van a interceptar las peticiones a nivel http
const handlers = [
  rest.post(process.env.REACT_APP_BASE_URL as string, (req, res, ctx) => {
    return res(ctx.json(dataSuccess), ctx.delay());
  }),
];

2. Configurar el server

Le enviamos los handlers al server

import { setupServer } from "msw/node";

// handlers omitidos

const server = setupServer(...handlers);

Configuramos el server para que: - Escuche las peticiones antes del set de tests. - Reinicie los handlers luego de cada test. - Apague el server luego de la ejecución del set de test.

describe("<Form />", () => {
    beforeAll(() => server.listen());
    afterEach(() => server.resetHandlers());
    afterAll(() => server.close());
});

Tomar en cuenta que utilizamos screen en vez de destructurar desde el render. Por otro lado, el test es async para que pueda esperar el resultado de la API.

Por recomendación de este modo no mockeamos ni necesitamos saber la implementación por debajo, por ejemplo de axios o de redux, lo que nos hace desacoplarnos de las tecnologías que se usen por debajo.

import { fireEvent, screen, waitFor } from "@testing-library/react";
import renderWithProviders from "test-utils/";

describe("<Form />", () => {
    // Omitido por brevedad
  it("shouldn't show errors in validation if the input values are correct", async () => {
    renderWithProviders(<OrderCreationForm />);
    const button = screen.getByTestId("button");
    const cuentaCorrienteInput = screen.getByTestId("inputCuentaCorriente") as HTMLInputElement;
    const codigoDeContratoInterno = screen.getByTestId(
      "inputCodigoContratoInterno"
    ) as HTMLInputElement;
    fireEvent.change(cuentaCorrienteInput, { target: { value: order.cuentaCorriente } });
    fireEvent.change(codigoDeContratoInterno, { target: { value: order.codigoDeContratoInterno } });
    fireEvent.click(button);
    await waitFor(() => {
      expect(cuentaCorrienteInput.value).toBe(order.cuentaCorriente);
      expect(codigoDeContratoInterno.value).toBe(order.codigoDeContratoInterno);
    });
  });

});

Casos para comprobar múltiples respuestas

En ciertas ocasiones necesitamos comprobar casos de error, por ejemplo, que la UI responda con un mensaje de alerta si la petición a ese mismo endpoint no ocurre de la manera felíz.

Una forma de comprobar esto puede ser mandar un status code no válido y un json como error.

it("should find an error message if request failed", async () => {
    // De este modo pisamos los handlers para este test especifico
    server.use(
      rest.post(process.env.REACT_APP_BASE_URL as string, (req, res, ctx) => {
        // Ver que lemendamos un objedo de error, y un status code no valido
        return res(ctx.status(400), ctx.json(dataError), ctx.delay());
      })
    );
    renderWithProviders(<OrderCreationForm />);
    const button = screen.getByTestId("button");
    const cuentaCorrienteInput = screen.getByTestId("inputCuentaCorriente") as HTMLInputElement;
    const codigoDeContratoInterno = screen.getByTestId(
      "inputCodigoContratoInterno"
    ) as HTMLInputElement;
    fireEvent.change(cuentaCorrienteInput, { target: { value: order.cuentaCorriente } });
    fireEvent.change(codigoDeContratoInterno, { target: { value: order.codigoDeContratoInterno } });
    fireEvent.click(button);
    expect(await screen.findByText("El pedido no pudo ser procesado.")).toBeInTheDocument();
  });

Ejemplo de test de integración

Un test de integración podría ser similar a este: test de integracíon