Пятая часть моей продолжающейся серии статей о том, как тестировать современные React-приложения. На этот раз я расскажу о том, как интегрировать MSW с Vitest, нашим фреймворком для юнит-тестирования. Большинство приложений должны получать данные с внутреннего сервера. Для полного охвата нам необходимо подражать этим запросам. Но что такое имитация?
Сделать копию или имитацию чего-либо
Оксфордские языки
Идея заключается в том, чтобы создать имитацию запроса, поступающего с бэкенда. Это имеет свои преимущества. Мы можем напрямую манипулировать тем, каким должен быть ответ, чтобы проверить несколько сценариев. В приложении, которое мы создали ранее, мы могли тестировать получение 0 сообщений, 100 сообщений, сообщений без текста и так далее и тому подобное.
Приложение, о котором идет речь:
Это очень мощно! Мы можем тестировать обычные случаи использования или граничные случаи, с которыми может столкнуться пользователь. И в конце концов, самое главное – это уверенность в наших тестах.
Что такое MSW?
MSW – это библиотека мокинга, которая очень проста в использовании.
Издевайтесь, перехватывая запросы на сетевом уровне. Беспрепятственное повторное использование одного и того же определения макета для тестирования, разработки и отладки.
Обычно это было бы ожидаемым взаимодействием:
Но, с добавлением MSW, мы добавим новый шаг.
Потрясающе! 😎 Давайте настроим это на нашем приложении. Для справки вот проект, который мы использовали до этого момента.
Конфигурационные файлы для MSW
Во-первых, давайте установим нашу новую библиотеку:
npm install msw --save-dev yarn add msw --dev
В директории src создадим каталог mocks older, где мы будем хранить обработчики запросов. Команда MSW называет это mock definitions. Внутри папки mocks создадим файл handlers.js.
Здесь мы можем экспортировать наши функции обработчиков. Поскольку мы делаем обычные REST-запросы, давайте импортируем rest из MSW.
import { rest } from 'msw';
Для того чтобы MSW распознал запрос, мы должны указать точный метод и путь и экспортировать их в массив.
export const handlers = [
rest.get('https://jsonplaceholder.typicode.com/posts', null),
];
Здесь мы можем заменить null на то, что мы хотим, чтобы MSW вернул нам. Это функция, известная как резольвер ответа. Возвращает следующее:
- req, информацию о соответствующем запросе;
- res, функциональная утилита для создания имитируемого ответа;
- ctx, группа функций, которые помогают установить код состояния, заголовки, тело и т.д. имитируемого ответа.
Давайте вернем наш собственный пользовательский ответ для этих постов.
import { rest } from 'msw';
export const handlers = [
rest.get('[https://jsonplaceholder.typicode.com/posts'](https://jsonplaceholder.typicode.com/posts'), (req, res, ctx) => {
return res(
ctx.status(200),
ctx.json([
{
body: 'This is a body',
id: 1,
title: 'Title',
userId: 1,
},
])
);
}),
];
Отлично, теперь мы настроили наш обработчик для MSW 🚀.
Конфигурационные файлы для Vitest
MSW устанавливает для нас сервер для перехвата запросов. Но мы должны создать экземпляр сервера. Создайте файл server.js в нашей папке mocks:
import { setupServer } from 'msw/node';
import { handlers } from './handlers';
// Here we import the handler created!
export const server = setupServer(...handlers);
В нашем vite.config.js добавим запись для наших файлов настроек в тестовом объекте:
setupFiles: ['./src/setup.js'],
Давайте создадим этот файл setup.js в нашей директории src. Это необходимо для корректной перезагрузки сервера при каждом выполнении теста:
import { server } from './mocks/server';
beforeAll(() => server.listen({ onUnhandledRequest: 'error' }));
afterAll(() => server.close());
afterEach(() => server.resetHandlers());
Теперь мы все настроили и готовы к тестированию! Давайте реализуем это в нашем тесте **Vitest**.
Подражание нашему API-запросу в Vitest
Давайте изменим наш тестовый файл:
import React from 'react';
import {
render,
screen,
waitForElementToBeRemoved,
} from '[@testing](http://twitter.com/testing)-library/react';
import userEvent from '[@testing](http://twitter.com/testing)-library/user-event';
import App from './App';
describe('Testing our React application', () => {
it('Fetch posts', async () => {
render(<App />);
expect(screen.getByText(/Modern React Testing/i)).toBeDefined();
userEvent.click(screen.getByRole('button', { name: 'Fetch Posts' }));
await waitForElementToBeRemoved(() =>
screen.queryByLabelText('loading')
);
expect(screen.getByRole('heading', { level: 3 })).toBeDefined();
});
});
Мы удалили библиотеку @testing-library/jest-dom, так как она больше не нужна. Но теперь наш тест должен пройти с зеленым цветом!
Также, поскольку наш тест работает в среде node, нам нужно заполнить нашу функцию fetch в оригинальном App.jsx
npm install cross-fetch
Просто импортируйте ее в самом верху:
import fetch from 'cross-fetch';
Побочная заметка
Если вы следили за другими моими статьями, вы могли заметить, что я изменил версию одной из зависимостей: @testing-library/user-event. У меня была проблема с отработкой нажатия кнопки.
Я понизил ее версию до 13.5.0 и вызывал событие нажатия непосредственно из userEvent.
Вы можете найти весь проект в этом репозитории с обновленным списком зависимостей.
Подведение итогов
Теперь в нашем распоряжении есть мощный инструмент для имитации запросов, пока мы продолжаем создавать модульные тесты! В следующей статье мы рассмотрим, как настроить Cypress.io.
Больше материалов на Relatable Code
Если вам понравилась эта статья, не стесняйтесь связаться со мной в LinkedIn или Twitter.
Получите мою бесплатную дорожную карту для разработчиков и еженедельные новости технологической индустрии в моей рассылке.