Тестирование фронтенда
Теория: Testing Library Dom
theme: gaia class:
- lead
- invert paginate: true
Dom Testing Library
Hexlet
Экосистема Testing Library
dom testing library— основная библиотекаuser-event— имитация браузерных событийjest-dom— кастомные матчеры Jesteslint-plugin-testing-library— плагин ESLint для Testing Libraryeslint-plugin-jest-dom— плагин ESLint для Jest DOM- Версии для фреймворков
react testing libraryangular testing librarysvelte testing library
Ключевой руководящий принцип
Чем лучше ваши тесты имитируют реальное использование вашего приложения, тем больше уверенности они могут вам дать
- тестируйте UI компоненты с точки зрения пользователя
- избегайте проверки деталей реализации
- не полагайтесь на конкретный фреймворк для тестирования
- не используйте test runner
DOM Testing Libraryработает с любым окружением, где есть DOM API- Jest, Mocha
- JSDOM
- реальный браузер
Запросы
- get, getAll
- query, queryAll
- find, findAll
ByRole
- Селектор элементов по роли
getByRole,getAllByRolequeryByRolequeryAllByRolefindByRole,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')ищет элемент с соответствющим labelgetByLabelTextхорошо подходит для полей формыgetByPlaceholderTextищет по атрибуту placeholdergetByTitleищет по атрибуту 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 })