Тестирование фронтенда
2026-02-26 20:00 Diff

theme: gaia class:

  • lead
  • invert paginate: true

Dom Testing Library

Hexlet

Экосистема Testing Library

  • dom testing library — основная библиотека
  • user-event — имитация браузерных событий
  • jest-dom — кастомные матчеры Jest
  • eslint-plugin-testing-library — плагин ESLint для Testing Library
  • eslint-plugin-jest-dom — плагин ESLint для Jest DOM
  • Версии для фреймворков
    • react testing library
    • angular testing library
    • svelte testing library

Ключевой руководящий принцип

Чем лучше ваши тесты имитируют реальное использование вашего приложения, тем больше уверенности они могут вам дать

  • тестируйте UI компоненты с точки зрения пользователя
  • избегайте проверки деталей реализации
  • не полагайтесь на конкретный фреймворк для тестирования
  • не используйте test runner
  • DOM Testing Library работает с любым окружением, где есть DOM API
    • Jest, Mocha
    • JSDOM
    • реальный браузер

Запросы

  • get, getAll
  • query, queryAll
  • find, findAll

ByRole

  • Селектор элементов по роли
  • getByRole, getAllByRole
  • queryByRole queryAllByRole
  • findByRole, findAllByRole
  • Доступные роли: link, button, form, heading, document, img, checkbox, radio, listitem, main, navigation, table, textbox
  • getByRole(expectedRole, { name: /submit/i })
  • getByRole('checkbox', { checked: true })
  • getAllByRole('button', { hidden: true })

ByText

TextMatch

  • как строка
    • screen.getByText("Hello World") - поиск по полной строке
    • screen.getByText('llo worl', { exact: false }) — поиск по подстроке, игнорируется регистр
  • как регулярное выражение
    • screen.getByText(/world/i) — поиск по подстроке, игнорируется регистр
    • screen.getByText(/^hello world$/i) — поиск по полной строке, игнорируется регистр
  • как функция
    • screen.getByText((content, element) => content.startsWith("Hello"))
  • screen.getByLabelText('Username') ищет элемент с соответствющим label
  • getByLabelText хорошо подходит для полей формы
  • getByPlaceholderText ищет по атрибуту placeholder
  • getByTitle ищет по атрибуту title

ByTestId

  • configure({testIdAttribute: 'data-my-test-attribute'})

Расширение для браузеров Chrome и Firefox Testing Playground

Вызов событий

fireEvent(node: HTMLElement, event: Event)

fireEvent[eventName](node: HTMLElement, eventProperties: Object)


Асинхронность

findBy = getBy + waitFor

waitFor

  • await waitFor(() => screen.getByRole('alert'))

  • await waitFor(() => expect(mockAPI).toHaveBeenCalledTimes(1))

  • WaitForElementToBeRemoved

  • wrapper on waitFor

  • fireEvent подходит для большинства сценариев, НО
  • fireEvent.click не порождает другие события:
    • fireEvent.mouseOver(element)
    • fireEvent.mouseMove(element)
    • fireEvent.mouseDown(element)
    • element.focus() (если элемент допускает это)
    • fireEvent.mouseUp(element)
    • fireEvent.click(element)

Рефакторинг

user-event

Это вспомогательная библиотека для Testing Library, которая обеспечивает более совершенное моделирование взаимодействия с браузером, чем встроенный метод fireEvent

user-event API

  • click / dbclick
  • hover / unhover
  • type
  • upload
  • selectOptions / deselectOptions
  • tab
  • paste

Click

click(element, eventInit, options)

Клики по элементу, могут иметь различные побочные эффекты в зависимости от элемента

  • Клик вызовет сначала событие hover Его можно отключить установивtrue для параметра skipHover
  • Можно также вызывать клик с зажатыми клавишаи, ctrlClick / shiftClick / пр.
    • userEvent.click(elem, { ctrlKey: true, shiftKey: true })