Тестирование JavaScript от А до Я (Jest, React Testing Library, e2e, screenshot)

YOUTUBE · 18.11.2025 19:31

Ключевые темы и таймкоды

Введение

0:03
  • Автор приветствует зрителей и объявляет о начале курса по тестированию JavaScript-приложений.
  • Курс будет полным и всеобъемлющим, охватывающим теорию и практику тестирования.
  • Зрителей призывают поставить лайк и подписаться на телеграм-канал автора.

Пирамида тестирования

1:28
  • Обсуждается пирамида тестирования в JavaScript, включая скриншотные тесты.
  • Рассматриваются технологии: Jest, React Testing Library, WebDriverIO, Storybook, Loci.

Цель тестирования

3:16
  • Объясняется, что цель тестирования — проверить соответствие функциональности требованиям, а не просто проверить работу функции.
  • Приводится пример с форматированием даты, иллюстрирующий важность тестов.

Классификация тестов

5:40
  • Тесты делятся на функциональные и нефункциональные.
  • Функциональные тесты включают модульное, интеграционное и энту-тестирование.
  • Нефункциональные тесты проверяют нагрузку, безопасность и регрессионное тестирование.

Пирамида тестирования и её слои

6:18
  • Объясняется, почему пирамида тестирования имеет такую структуру: много юнит-тестов и мало энту-тестов.
  • Подробно описываются слои пирамиды: юнит-тесты, скриншотные тесты, интеграционные тесты, энту-тесты.

Юнит-тестирование

6:45
  • Юнит-тесты проверяют отдельные функции, методы и компоненты.
  • Примеры юнит-тестов: функция возведения числа в квадрат, валидация числа, преобразование массива чисел в массив строк.

Скриншотные тесты

7:34
  • Скриншотные тесты сравнивают старые и новые скриншоты UI-элементов.
  • Пример: изменение шрифтов на главной странице документации.
  • Система сравнивает скриншоты и выявляет различия, помогая обнаружить ошибки.

Интеграционные и энту-тесты

8:34
  • Интеграционные тесты проверяют связку модулей, например, React-компоненты с React Router.
  • Энту-тесты тестируют ключевую функциональность на реальных данных в реальном браузере, например, авторизацию, регистрацию, удаление пользователя.

Пропорции тестов в пирамиде

9:28
  • Энту-тестов должно быть меньше всего, около 10% от всех тестов.
  • Интеграционных тестов должно быть в 2–3 раза больше.
  • Скриншотных и юнит-тестов должно быть 70–80%.

Квадрат данных для тестирования

10:36
  • Значения в центре квадрата считаются валидными.
  • Один тест-кейс проверяется на положительный результат.
  • Второй тест-кейс тестирует пограничные значения.
  • Проверяются невалидные данные: значения больше и меньше валидных.

Пример тестирования функции валидации

11:32
  • Функция валидирует числовые значения.
  • Проверяются валидное значение 50, пограничные значения 0 и 100, а также невалидные значения -50 и 150.

Начало юнит-тестирования с Jest

12:01
  • Инициализация приложения с помощью npm init.
  • Установка Jest как dev-зависимости.
  • Создание папки src и файла для функции валидации.

Реализация функции валидации

12:58
  • Функция принимает числовое значение и возвращает true, если оно больше 0 и меньше 100, иначе — false.
  • Экспорт функции с помощью module.export.

Написание первого теста

13:54
  • Описание теста с помощью функции test и expect.
  • Проверка возврата true для валидного значения 50.

Запуск тестов

14:49
  • Запуск тестов через терминал или веб-шторм.
  • Проверка невалидных значений -1 и 101.

Проверка пограничных значений

15:48
  • Добавление тестов для пограничных значений 0 и 100.
  • Проверка корректности работы функции на пограничных значениях.

Тестирование функции преобразования массива

16:51
  • Функция фильтрует массив чисел и преобразует их в строки.
  • Тестирование функции с массивом чисел и ожиданием массива строк.

Сравнение объектов в JavaScript

18:09
  • Объяснение разницы между сравнением объектов по ссылке и по значению.
  • Использование метода equal для глубокого сравнения объектов.

Дополнительные тесты для функции преобразования

19:39
  • Добавление тестов с пустым массивом и отрицательными условиями.
  • Проверка работы функции с массивом, содержащим числа и строки.

Тестирование функции возведения числа в квадрат

20:58
  • Создание функции, которая возводит число в квадрат.
  • Тестирование функции с аргументом 2 и ожиданием результата 4.
  • Использование методов equal, lessThan, greaterThan и отрицания для проверок.

Функции бифор и бифор ол

22:03
  • Функция бифор ич вызывается перед каждым тестом и позволяет выполнять операции перед их запуском, например, создавать моки.
  • Функция бифор ол вызывается один раз перед запуском всех тестов.
  • Аналогично существуют функции автор ич и автор ол для выполнения операций после тестов.

Пример использования моков

23:33
  • Демонстрация использования моков для проверки вызова метода оф.
  • Использование методов кол-таймс и колт для проверки количества вызовов метода.
  • Пример с условием: если значение больше единицы, вызывается метод оф.

Метод спай он

24:45
  • Объяснение работы метода спай он для замокания метода внутри объекта.
  • Пример замокания метода по внутри объекта масс.
  • Проверка вызова замоченного метода с помощью экспекта.

Очистка моков

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

Тестирование асинхронных функций

27:39
  • Создание функции дилей для вызова колбека с задержкой.
  • Реализация функции с использованием промеса и сет-тайм-аут.
  • Тестирование функции с задержкой и проверка результата.

Функция гет дата

29:43
  • Создание функции гет дата для отправки запроса на сервер и получения данных.
  • Использование аксиуса для отправки запроса и получения данных с jsonplaceholder.
  • Преобразование данных и экспорт функции.

Мокинг аксиуса

31:32
  • Импорт аксиуса и замокание данных, возвращаемых методом гет.
  • Использование бифор ич для замокания данных перед каждым тестом.
  • Согласование схемы возвращаемых данных с методом гет аксиуса с помощью мок терн велью.

Мокинг и использование мок терн велью

33:27
  • Объяснение работы мок терн велью и его применения.
  • Пример использования мок терн велью для замокания данных.
  • Завершение примера с вызовом функции гет дата.

Синхронное тестирование функции

33:52
  • Функция синхронная, используется приставка `async`.
  • Ожидание вызова `axios.get` хотя бы один раз с помощью `toBeCalledOnce`.
  • Проверка возврата массива идентификаторов пользователей с помощью `expect`.
  • Запуск теста и проверка результатов: зелёные галочки означают успех.

Провальные тесты

34:47
  • При изменении значения тест проваливается.
  • Сравнение ожидаемых и полученных данных.
  • Простота использования инструментов для тестирования сложных функций.

Использование снэпшотов

35:49
  • Функция `takeSnapshot` сохраняет результат вычислений в файл.
  • Сравнение снэпшотов помогает выявить изменения в коде.
  • Удобство для тестирования компонентов и вложенности элементов.

Начало тестирования React

37:18
  • Настройка React Testing Library с помощью `create-react-app`.
  • Добавление логики в компонент: заголовок, кнопка, инпут.
  • Создание теста для компонента с использованием `render`.

Поиск элементов с помощью селекторов

38:14
  • Использование селекторов для поиска элементов: `get-by-text`, `find-by-role`, `find-by-placeholder`.
  • Проверка содержимого элемента с помощью регулярного выражения.
  • Запуск теста и исправление ошибки при несовпадении содержимого.

Проверка наличия элементов

40:13
  • Поиск кнопки и инпута по роли и плейсхолдеру.
  • Ожидание нахождения элементов в DOM-дереве.
  • Успешное выполнение теста.

Отладка с помощью `debug`

41:08
  • Метод `debug` возвращает разметку после рендеринга компонента.
  • Использование `takeSnapshot` для создания снэпшота инпута.
  • Подтверждение изменений с помощью кнопки `click to update snapshot`.

Различие селекторов

42:25
  • Объяснение различий между селекторами `find`, `get` и `query`.
  • `Find` возвращает массив элементов, `get` — один элемент.
  • `Query` используется для проверки отсутствия элемента на странице.

Отличия между getByText и findByText

43:40
  • GetByText возвращает объект, а findByText — объект, завернутый в промес.
  • FindByText используется для работы с асинхронным кодом.
  • GetByText гарантирует наличие элемента, иначе будет ошибка.
  • QueryByText проверяет отсутствие элемента, но не гарантирует его наличие.

Пример использования findByText

44:40
  • Добавление асинхронности с помощью useEffect и тайм-аута.
  • Проверка наличия элемента после тайм-аута.
  • Использование await для синхронной работы с промесом.

Тестирование стилей и поведения

46:42
  • Проверка наличия стилей у блока.
  • Пример с красным цветом текста.
  • Описание ожидаемого поведения страницы.

Работа с событиями и кнопками

47:38
  • Добавление булевого состояния и функции для слушателя события нажатия.
  • Получение кнопки по идентификатору.
  • Использование FireEvent для работы с событиями.

Тестирование ввода данных

51:09
  • Оживление ввода данных с помощью двустороннего связывания.
  • Проверка значения в заголовке после ввода.
  • Тестирование валидации ввода.

Эмуляция пользовательских действий

53:04
  • Модуль UserEvent для эмуляции полноценного взаимодействия пользователя.
  • Функция tap для ввода текста в ввод.
  • Сравнение FireEvent и UserEvent.

Тестирование сложных компонентов

54:48
  • Создание компонента Users и его тестирование.
  • Инициализация состояния списка пользователей.
  • Итерация по массиву пользователей и вывод их имён.

Тестирование Axios

55:26
  • Возвращение к первой части урока для тестирования функции getData.
  • Использование mockAxios для имитации ответа сервера.
  • Подготовка функции для получения пользователей с помощью axios.

Установка Axios и настройка теста

56:23
  • Установка Axios через npm.
  • Перенос кода из первой части урока в новый тест.
  • Удаление лишних данных для упрощения теста.

Рендеринг компонента и проверка данных

57:17
  • Рендеринг компонента и ожидание работы useEffect.
  • Импорт Axios для запроса данных.
  • Проверка количества пользователей с помощью селектора.

Запуск теста и проверка результата

58:13
  • Запуск теста и проверка отображения списка пользователей.
  • Подтверждение успешного прохождения теста.

Настройка роутера в React

58:38
  • Установка React Router и Home.
  • Импорт browserRouter и компонента Routes.
  • Создание папок для страниц и компонентов.

Настройка роутов и ссылок

59:20
  • Описание роутов в корневом компоненте.
  • Добавление ссылок на страницы с тестовыми идентификаторами.
  • Запуск приложения для проверки работы ссылок.

Тестирование переходов между страницами

1:00:16
  • Создание файла для тестирования роутера.
  • Проверка появления заголовков страниц при нажатии на ссылки.
  • Успешное прохождение теста.

Тестирование с MemoryRouter

1:01:28
  • Ошибка при отсутствии компонента Router.
  • Решение проблемы с помощью MemoryRouter.
  • Успешное прохождение теста после исправления.

Тестирование несуществующих путей

1:02:25
  • Добавление роута для перехвата несуществующих путей.
  • Создание компонента ErrorPage.
  • Тестирование редиректа на страницу с ошибкой при открытии несуществующего пути.

Проверка редиректа

1:03:24
  • Проверка редиректа на страницу NotFound при открытии несуществующей страницы.
  • Ошибка при попытке открыть существующую страницу.

Тестирование компонента «Юзерс»

1:03:39
  • Создание компонента «Юзерс», который отображает список пользователей.
  • Добавление ссылки на страницу с детальной информацией о пользователе.
  • Настройка роутов для отображения списка пользователей и детальной информации.

Проверка работы ссылок

1:04:39
  • Открытие приложения и проверка работы ссылок.
  • Тестирование перехода на страницу с детальной информацией о пользователе.

Проблемы с тестированием

1:05:31
  • Обнаружение проблемы с рендерингом компонентов без роутеров.
  • Решение проблемы путём оборачивания компонента «Юзерс» в мемори роутер.

Оптимизация роутов

1:07:25
  • Создание компонента «Эпроутер» для управления роутерами.
  • Импорт компонента «Эпроутер» в корневой компонент.

Создание хелпера для тестирования

1:08:18
  • Разработка функции «рендер виз роутер» для тестирования переходов между страницами.
  • Использование хелпера в тестах для упрощения конструкции.

Тестирование компонента «Нав бар»

1:10:05
  • Вынесение ссылок в компонент «Нав бар».
  • Тестирование переходов по ссылкам с помощью хелпера.
  • Разделение тестов на отдельные тесты для каждой ссылки.

Установка Redux

1:12:14
  • Установка Redux через документацию.
  • Создание папки «стор» и файла «стор.js».
  • Создание редюсера для управления счётчиком.

Настройка Redux в приложении

1:13:19
  • Создание функции для создания Redux Store.
  • Добавление корневого редюсера и провайдера для работы с Redux.

Тестирование компонента «Каутер»

1:14:03
  • Использование хука useDispatch для работы с экшенами.
  • Получение значения счётчика с помощью селектора.
  • Добавление кнопок для инкремента и декремента счётчика.

Создание селектора для счётчика

1:14:27
  • Создаём папку «селекторы», внутри неё — папку «гет каунтер велью» и файл «гет катер джес».
  • Селектор принимает состояние и возвращает часть состояния, в данном случае — значение счётчика.
  • Используем селектор в компоненте, передавая его как аргумент в `useSelector`.

Тестирование счётчика в браузере

1:15:22
  • Обновляем страницу в браузере, проверяем работу счётчика.
  • Нажимаем на кнопки, чтобы изменить значение счётчика.
  • Инициализируем состояние счётчика по умолчанию, передавая его в функцию `createReducerStore`.

Тестирование селектора

1:16:04
  • Тестируем селектор, передавая пустой объект, ожидаем возврат нуля.
  • Проверяем работу селектора с инициализированным состоянием.
  • Подчёркиваем важность тестирования селекторов для предотвращения ошибок.

Тестирование редуктора

1:18:02
  • Тестируем инкремент и декремент редуктора.
  • Сравниваем объекты с помощью `toEqual`.
  • Проверяем работу редуктора с пустым состоянием.

Тестирование компонента счётчика

1:19:33
  • Добавляем тесты на кнопки и заголовок счётчика.
  • Используем функцию `render` из `React Testing Library`.
  • Проверяем изменение значения счётчика после нажатия кнопки.

Использование провайдера для тестирования

1:21:20
  • Создаём провайдер для компонента, оборачивая его в `Provider`.
  • Запускаем тесты, проверяем их успешность.

Подготовка состояния для тестирования

1:21:36
  • Задаём значение счётчика по умолчанию, например, 10.
  • Создаём хелпер для подготовки состояния.
  • Применяем хелпер для тестирования компонента.

Комбинированный хелпер для тестирования

1:23:26
  • Создаём хелпер, сочетающий функции роутера и редуктора.
  • Проверяем работу хелпера, передавая компонент и опции.
  • Исправляем ошибки, если тест падает из-за дублирования компонентов.

Введение в E2E-тесты

1:25:20
  • Объясняем разницу между интеграционными и E2E-тестами.
  • Упоминаем фреймворк WebDriver для E2E-тестов.
  • Устанавливаем WebDriver через npm.

Инициализация и настройки

1:26:27
  • Настройка параметров для запуска тестов на локальной машине.
  • Выбор фреймворкаmocha вместо Jasmine или Cucumber.
  • Указание пути для тестов и регулярного выражения для названий файлов.
  • Согласие на генерацию файлов веб-драйвером и использование паттерна Page Object.

Инициализация и конфигурация

1:27:21
  • Настройка пути для хранения классов Page Object.
  • Инициализация с базовым URL localhost.
  • Создание конфигурации с настройками и указанием порта 3000.

Пример теста и его запуск

1:28:30
  • Демонстрация примера теста: открытие страницы, вызов функции login, проверка появления алерта.
  • Запуск теста с помощью команды npm run.
  • Добавление скрипта для запуска тестов в package.json.

Паттерн Page Object

1:29:29
  • Описание взаимодействия с реальной страницей через класс Page Object.
  • Разбиение большой страницы на блоки для более удобного тестирования.
  • Примеры методов: open, login, uploadImage, uploadFile.

Создание новой страницы

1:30:27
  • Добавление новой страницы с input, button и заголовком.
  • Настройка состояния видимости заголовка.
  • Добавление логики для переключения видимости заголовка при нажатии на кнопку.

Реализация паттерна Page Object

1:32:06
  • Создание файла Page.js и базового класса Page.
  • Изменение метода open для открытия страницы на localhost:3000.
  • Импорт класса HelloPage и настройка селекторов для элементов.

Написание теста

1:34:48
  • Импорт класса Page в тест-кейс.
  • Вызов метода toggleTitle для переключения видимости заголовка.
  • Проверка появления и исчезновения заголовка на странице.

Запуск теста и исправление ошибок

1:35:45
  • Запуск теста и обнаружение ошибки с открытием главной страницы.
  • Исправление ошибки в роутере и повторный запуск теста.
  • Успешное прохождение теста после исправления.

Проверка валидности

1:37:14
  • Проверка валидности ввода текста в input.
  • Запуск теста с невалидным текстом и проверка отсутствия появления заголовка.
  • Подтверждение успешного прохождения двух тестов.

Создание компонента для тестирования

1:38:14
  • Создаём компонент «UsersForTest» в папке «users».
  • Компонент содержит массив пользователей и состояние загрузки.
  • Используем JSONPlaceholder для загрузки пользователей с тайм-аутом.
  • Реализуем функцию удаления пользователя по ID.

Настройка селекторов

1:39:11
  • Добавляем новый путь в роутер.
  • Создаём селекторы для индикатора загрузки данных, обертки списка пользователей и массива пользователей.
  • Применяем селекторы с решёткой для получения элементов по ID.

Асинхронная функция для проверки загрузки данных

1:40:18
  • Открываем страницу с помощью метода open.
  • Ждём появления индикатора загрузки данных с помощью waitForDisplay.
  • Проверяем появление элемента «users-list» в течение двух секунд.
  • Оборачиваем логику в try-catch для обработки ошибок.

Тестирование загрузки данных

1:41:18
  • Создаём файл для тестирования «users.test.ejs».
  • Вызываем функцию loadData и ждём её выполнения.
  • Проверяем появление индикатора и списка пользователей.

Тестирование удаления пользователя

1:41:52
  • Реализуем функцию удаления пользователя по ID.
  • Описываем логику внутри try-catch для обработки ошибок.
  • Получаем количество пользователей и проверяем его изменение после нажатия кнопки.

Запуск тестов

1:44:03
  • Подгружаем пользователей и вызываем функцию deleteUser.
  • Запускаем тесты и проверяем их успешность.

Введение в Storybook

1:44:55
  • Устанавливаем Storybook в проект.
  • Запускаем Storybook и просматриваем компоненты в разных состояниях.
  • Storybook помогает отслеживать темы и комплектации компонентов.

Написание Storybook-тестов

1:46:43
  • Создаём компоненты с разными состояниями, передавая props.
  • Стимулируем изменения стилей компонентов и проверяем их влияние на верстку.
  • Storybook-тесты помогают проверить, что состояния компонентов не сломались.

Использование библиотеки Loci для скриншотов

1:47:42
  • Для снятия скриншотов используем библиотеку Loci.
  • Loci бесплатна и доступна для установки.
  • Примеры будут демонстрироваться на новом проекте, развёрнутом на Mac.

Начало работы с Storybook

1:48:25
  • Развёртывание проекта с помощью Create-React-App.
  • Инициализация Storybook и установка зависимостей.
  • Запуск Storybook и инициализация Loci с помощью скрипта `pix-loci init`.

Снятие скриншотов

1:49:20
  • Снятие скриншотов с компьютера и телефона с помощью команды `npx pix-loci test`.
  • Создание папки `loci/reference` с референсными скриншотами.
  • Проверка адаптивности интерфейса на разных устройствах.

Изменение стиля и анализ изменений

1:50:16
  • Изменение цвета шрифта и размера шрифта в CSS.
  • Повторное выполнение команды `npx pix-loci test` и анализ результатов.
  • Создание папок `loci/current` и `loci/diff` для текущих и изменённых скриншотов.
  • Проверка изменений с помощью файла `diff`.

Завершение работы с Loci

1:51:16
  • Замена старых скриншотов на новые с помощью команды `npx pix-loci replace`.
  • Подчёркивание полезности скриншотных тестов для тестирования UI.

Виды тестов

1:51:50
  • Объяснение различий между юнит-тестами, скриншотными тестами, интеграционными тестами и энту-тестами.
  • Указание на важность покрытия ключевого функционала энту-тестами.

Заключение

1:53:02
  • Подведение итогов и благодарность зрителям.
  • Призыв к оставлению комментариев, лайкам и подписке.
  • Анонс следующего ролика.