Unit-тестирование кода с Vex

Vex — это мощная библиотека для работы с UI-элементами, которая предоставляет удобные инструменты для создания различных интерфейсных компонентов, таких как модальные окна, уведомления и диалоги. Одной из важнейших частей разработки на JavaScript является тестирование, и Vex не исключение. В этой статье рассматриваются основы написания unit-тестов для кода, использующего библиотеку Vex.

Важность unit-тестирования

Unit-тестирование представляет собой процесс проверки отдельных частей программы (модулей, функций) на корректность их работы. В контексте использования Vex это может включать тестирование логики отображения диалогов, правильности взаимодействия с пользователем, а также проверки всех возможных сценариев использования компонентов.

Unit-тесты позволяют:

  • Убедиться в правильности работы функционала на ранних стадиях разработки.
  • Упростить поддержку и рефакторинг кода.
  • Обеспечить стабильность системы при добавлении новых функций.

Подготовка окружения

Для того чтобы начать писать тесты для кода, использующего Vex, необходимо настроить окружение. В качестве тестового фреймворка можно использовать Jest, так как он предоставляет удобный API для написания тестов и интеграции с библиотеками, такими как Vex.

Для начала установим необходимые зависимости:

npm install jest @testing-library/react vex-js

Jest является популярным инструментом для тестирования кода на JavaScript, а @testing-library/react упрощает тестирование UI-компонентов, таких как модальные окна, с использованием подхода, ориентированного на пользователя.

Мокирование зависимостей Vex

Одной из задач при тестировании с использованием Vex является мокирование самой библиотеки, чтобы убедиться, что компоненты отображаются и работают корректно, не создавая при этом реальных модальных окон. Для этого используется jest.mock.

Пример мокирования вызова Vex:

jest.mock('vex-js', () => ({
  vex: {
    open: jest.fn(),
    close: jest.fn(),
  },
}));

В этом примере создается мок для функций open и close, которые позволяют управлять отображением модальных окон. Такие моки позволят проверять, были ли вызваны эти методы, и работать с их результатами в тестах.

Тестирование создания модальных окон

Одним из основных компонентов, с которым работает Vex, является создание и управление модальными окнами. Рассмотрим пример простого компонента, который открывает модальное окно при нажатии на кнопку.

import React, { useState } from 'react';
import { vex } from 'vex-js';

const ModalButton = () => {
  const [isModalOpen, setIsModalOpen] = useState(false);

  const openModal = () => {
    vex.open({ content: 'Это модальное окно!' });
    setIsModalOpen(true);
  };

  return <button onCl ick={openModal}>Открыть модальное окно</button>;
};

export default ModalButton;

Для тестирования этого компонента можно использовать @testing-library/react, чтобы имитировать нажатие кнопки и проверить, что вызов метода open был сделан корректно.

Пример теста:

import { render, screen, fireEvent } from '@testing-library/react';
import ModalButton from './ModalButton';
import { vex } from 'vex-js';

jest.mock('vex-js', () => ({
  vex: {
    open: jest.fn(),
    close: jest.fn(),
  },
}));

test('открывает модальное окно при нажатии на кнопку', () => {
  render(<ModalButton />);

  const button = screen.getByText('Открыть модальное окно');
  fireEvent.click(button);

  expect(vex.open).toHaveBeenCalledTimes(1);
  expect(vex.open).toHaveBeenCalledWith({
    content: 'Это модальное окно!',
  });
});

Этот тест:

  1. Рендерит компонент ModalButton.
  2. Имитирует клик по кнопке.
  3. Проверяет, что метод vex.open был вызван с правильными аргументами.

Тестирование закрытия модальных окон

Не менее важной задачей является проверка закрытия модальных окон. Рассмотрим следующий пример компонента, который закрывает модальное окно при нажатии на кнопку.

import React, { useState } from 'react';
import { vex } from 'vex-js';

const CloseModalButton = () => {
  const closeModal = () => {
    vex.close();
  };

  return <button onCl ick={closeModal}>Закрыть модальное окно</button>;
};

export default CloseModalButton;

Для тестирования этого компонента создадим тест, который проверит, что метод close был вызван при нажатии на кнопку.

import { render, screen, fireEvent } from '@testing-library/react';
import CloseModalButton from './CloseModalButton';
import { vex } from 'vex-js';

jest.mock('vex-js', () => ({
  vex: {
    open: jest.fn(),
    close: jest.fn(),
  },
}));

test('закрывает модальное окно при нажатии на кнопку', () => {
  render(<CloseModalButton />);

  const button = screen.getByText('Закрыть модальное окно');
  fireEvent.click(button);

  expect(vex.close).toHaveBeenCalledTimes(1);
});

Здесь:

  1. Рендерится компонент CloseModalButton.
  2. Имитируется клик по кнопке.
  3. Проверяется, что метод vex.close был вызван один раз.

Проверка работы модальных окон с асинхронными операциями

В реальных приложениях часто встречаются случаи, когда отображение и скрытие модальных окон зависит от асинхронных операций, например, запросов к серверу. Рассмотрим пример, где окно открывается только после успешного ответа от сервера.

import React, { useState } from 'react';
import { vex } from 'vex-js';

const AsyncModalButton = () => {
  const [loading, setLoading] = useState(false);

  const openModalAsync = async () => {
    setLoading(true);
    const response = await fetch('/api/data');
    if (response.ok) {
      vex.open({ content: 'Данные загружены!' });
    }
    setLoading(false);
  };

  return <button onCl ick={openModalAsync} disabled={loading}>Открыть модальное окно</button>;
};

export default AsyncModalButton;

Для тестирования этого компонента можно использовать mocking для асинхронного запроса:

import { render, screen, fireEvent, waitFor } from '@testing-library/react';
import AsyncModalButton from './AsyncModalButton';
import { vex } from 'vex-js';

jest.mock('vex-js', () => ({
  vex: {
    open: jest.fn(),
    close: jest.fn(),
  },
}));

test('открывает модальное окно после успешного запроса', async () => {
  global.fetch = jest.fn().mockResolvedValue({ ok: true });

  render(<AsyncModalButton />);

  const button = screen.getByText('Открыть модальное окно');
  fireEvent.click(button);

  await waitFor(() => expect(vex.open).toHaveBeenCalledTimes(1));
  expect(vex.open).toHaveBeenCalledWith({ content: 'Данные загружены!' });
});

В этом тесте:

  1. Мокируется глобальная функция fetch, чтобы имитировать успешный запрос.
  2. Имитируется клик по кнопке.
  3. Ожидается, что метод vex.open будет вызван только после того, как запрос завершится успешно.

Обработка ошибок и неудачных сценариев

Важно также тестировать сценарии, когда операция не удается. В случае с асинхронными запросами это может быть ошибка сети или ошибка сервера. Рассмотрим пример, где модальное окно не открывается, если запрос не удался.

import React, { useState } from 'react';
import { vex } from 'vex-js';

const ErrorModalButton = () => {
  const [loading, setLoading] = useState(false);

  const openModalError = async () => {
    setLoading(true);
    try {
      const response = await fetch('/api/data');
      if (!response.ok) {
        throw new Error('Ошибка загрузки данных');
      }
      vex.open({ content: 'Данные загружены!' });
    } catch (error) {
      vex.open({ content: `Ошибка: ${error.message}` });
    }
    setLoading(false);
  };

  return <button onCl ick={openModalError} disabled={loading}>Открыть модальное окно</button>;
};

export default ErrorModalButton;

Тестируем обработку ошибки:

import { render, screen, fireEvent, waitFor } from '@testing-library/react';
import ErrorModalButton from './ErrorModalButton';
import { vex } from 'vex-js';

jest.mock('vex-js', () => ({
  vex: {
    open: jest.fn(),
    close: jest.fn(),
  },
}));

test('открывает модальное окно с ошибкой при неудачном запросе', async () => {
  global.fetch