Testing Library. Расширение и песочница
Есть прикольное расширение, которое помогает выбрать подходящий метод для поиска элемента на странице: https://chromewebstore.google.com/detail/testing-playground/hejbmebodbijjdhflfknehhcgaklhano
Устанавливаем его, в DevTools появляется новая вкладка Testing Playground.
Открываем ее, наводим курсор на нужный элемент, и расширение пытается подобрать самый подходящий метод с учетом всех best practices.
А еще есть песочница, где можно ввести любой кусок HTML и поиграться с запросами - https://testing-playground.com/
#тестирование #testinglibrary #документация
Есть прикольное расширение, которое помогает выбрать подходящий метод для поиска элемента на странице: https://chromewebstore.google.com/detail/testing-playground/hejbmebodbijjdhflfknehhcgaklhano
Устанавливаем его, в DevTools появляется новая вкладка Testing Playground.
Открываем ее, наводим курсор на нужный элемент, и расширение пытается подобрать самый подходящий метод с учетом всех best practices.
А еще есть песочница, где можно ввести любой кусок HTML и поиграться с запросами - https://testing-playground.com/
#тестирование #testinglibrary #документация
Google
Testing Playground - Chrome Web Store
Simple and complete DOM testing playground that encourage good testing practices.
👍3
byRole
Итак, начнем с подробного разбора самого главного запроса в Testing Library:
Документация: https://testing-library.com/docs/queries/byrole
Собственно роль
Первым параметром метод принимает собственно роль нужного элемента в виде строки. Это может быть
Речь идет не об атрибуте
Опции
Вторым параметром можно передать объект с кучей дополнительных опций, которые помогут найти нужный элемент. Например, если у вас на странице куча кнопок, а нужно найти конкретную.
Тут будет много опций для поиска по
🔸hidden: boolean
По умолчанию значение равно false - из-за этого в поиск не включаются "недоступные" элементы (display: none, aria-hidden, role=none).
🔸name: TextMatch
Для элемента формы - это текст лейбла, для кнопки - собственно текст кнопки. Также может использоваться значение атрибута
Что за тип такой
Функция принимает два аргумента: content: string (собственно текстовый контент, по которому производится поиск) и element (DOMElement) и должна вернуть true или false.
🔸description: TextMatch
Это для атрибута aria-describedby.
🔸selected: boolean
Отбор по значению атрибута aria-selected.
🔸busy: boolean
Отбор по значению атрибута aria-busy.
🔸checked: boolean
Отбор по значению атрибута aria-checked.
🔸pressed: boolean
Отбор по значению атрибута aria-pressed.
🔸suggest: boolean
Эта настройка для того, чтобы Testing Library предлагала вам запросы получше, чем тот, что написали вы.
🔸current: boolean | string
Отбор по значению атрибута aria-current.
🔸expanded: boolean
Отбор по значению атрибута aria-expanded.
🔸queryFallbacks: boolean
По умолчанию учитывается только первая роль каждого элемента, но есть поставить тут true, то будут приняты во внимание и запасные роли, если они есть.
🔸level: number
Уровень заголовка для роли
🔸value
Это для группы атрибутов
#тестирование #testinglibrary #документация
Итак, начнем с подробного разбора самого главного запроса в Testing Library:
byRole
. Это методы getByRole
, getAllByRole
, queryByRole
, queryAllByRole
, findByRole
, findAllByRole
.Документация: https://testing-library.com/docs/queries/byrole
Собственно роль
Первым параметром метод принимает собственно роль нужного элемента в виде строки. Это может быть
button
, heading
, switch
и так далее. Речь идет не об атрибуте
role
, а прежде всего о дефолтной (встроенной) роли элементов. Например, элемент button
имеет роль button
, даже без явного указания на это. Вот тут можно почитать про роли элементов.Опции
Вторым параметром можно передать объект с кучей дополнительных опций, которые помогут найти нужный элемент. Например, если у вас на странице куча кнопок, а нужно найти конкретную.
Тут будет много опций для поиска по
aria-
атрибутам.🔸hidden: boolean
По умолчанию значение равно false - из-за этого в поиск не включаются "недоступные" элементы (display: none, aria-hidden, role=none).
🔸name: TextMatch
Для элемента формы - это текст лейбла, для кнопки - собственно текст кнопки. Также может использоваться значение атрибута
aria-label
.Что за тип такой
TextMatch
? Это составной тип, который может быть обычной строкой, регулярным выражением или даже функцией.Функция принимает два аргумента: content: string (собственно текстовый контент, по которому производится поиск) и element (DOMElement) и должна вернуть true или false.
screen.getByText((content, element) => content.startsWith('Hello'))
🔸description: TextMatch
Это для атрибута aria-describedby.
🔸selected: boolean
Отбор по значению атрибута aria-selected.
🔸busy: boolean
Отбор по значению атрибута aria-busy.
🔸checked: boolean
Отбор по значению атрибута aria-checked.
🔸pressed: boolean
Отбор по значению атрибута aria-pressed.
🔸suggest: boolean
Эта настройка для того, чтобы Testing Library предлагала вам запросы получше, чем тот, что написали вы.
🔸current: boolean | string
Отбор по значению атрибута aria-current.
🔸expanded: boolean
Отбор по значению атрибута aria-expanded.
🔸queryFallbacks: boolean
По умолчанию учитывается только первая роль каждого элемента, но есть поставить тут true, то будут приняты во внимание и запасные роли, если они есть.
🔸level: number
Уровень заголовка для роли
heading
. Учитывает как семантику тега, так и атрибут aria-level
.🔸value
Это для группы атрибутов
aria-value
, например, aria-valuemin
, aria-valuetext
. Указывается в виде объекта:
screen.getByRole('spinbutton', { value: { min: 5, max: 10 }})
#тестирование #testinglibrary #документация
Testing-Library
ByRole | Testing Library
getByRole, queryByRole, getAllByRole, queryAllByRole, findByRole,
👍2
ByLabelText, ByPlaceholderText
Два запроса, предназначенных в основном для интерактивных элементов форм: поиск по тексту лейбла и по плейсхолдеру.
ByLabelText
Поле ввода может быть связано с лейблом разными способами:
- через атрибуты for и id
- через атрибут aria-labelledby
- если поле находится внутри label
- лейбл можно указать в атрибуте aria-label
Сигнатура:
Текст лейбла можно задать первым параметром в виде строки, регулярки или функции (TextMatch).
Вторым параметром идет объект настроект:
- selector - можно дополнительно указать селектор нужного элемента
- exact - если текст задан в виде строки, то этот параметр определяет должен ли поиск быть точным (по полной строке, с учетом регистра символов) или нет
- normalizer - по умолчанию Testing Library нормализует текст (убирает лишние пробелы). Можно передать собственный нормализатор
ByPlaceholderText
Очень похожий метод, только ищет элемент по тексту плейсхолдера. Менее предпочтительный, следует использовать только если элемент нельзя найти по лейблу или роли.
Сигнатура:
#тестирование #testinglibrary #документация #примерыкода
Два запроса, предназначенных в основном для интерактивных элементов форм: поиск по тексту лейбла и по плейсхолдеру.
ByLabelText
Поле ввода может быть связано с лейблом разными способами:
- через атрибуты for и id
- через атрибут aria-labelledby
- если поле находится внутри label
- лейбл можно указать в атрибуте aria-label
Сигнатура:
screen.getByLabelText(
text: TextMatch,
options: {
selector?: string = '*',
exact?: boolean = true,
normalizer?: NormalizeFn
}
)
Текст лейбла можно задать первым параметром в виде строки, регулярки или функции (TextMatch).
Вторым параметром идет объект настроект:
- selector - можно дополнительно указать селектор нужного элемента
- exact - если текст задан в виде строки, то этот параметр определяет должен ли поиск быть точным (по полной строке, с учетом регистра символов) или нет
- normalizer - по умолчанию Testing Library нормализует текст (убирает лишние пробелы). Можно передать собственный нормализатор
ByPlaceholderText
Очень похожий метод, только ищет элемент по тексту плейсхолдера. Менее предпочтительный, следует использовать только если элемент нельзя найти по лейблу или роли.
Сигнатура:
screen.getByPlaceholderText(
text: TextMatch,
options: {
exact?: boolean = true,
normalizer?: NormalizerFn
}
)
#тестирование #testinglibrary #документация #примерыкода
👍2
ByDisplayValue
Еще один запрос для интерактивных элементов, у которых может быть value (input, textarea, select). Соответственно поиск происходит по текущему значению value - это текст, который отображается в инпуте. Настроек у запроса немного:
#тестирование #testinglibrary #документация #примерыкода
Еще один запрос для интерактивных элементов, у которых может быть value (input, textarea, select). Соответственно поиск происходит по текущему значению value - это текст, который отображается в инпуте. Настроек у запроса немного:
screen.getByDisplayValue(
value: TextMatch,
options?: {
exact?: boolean = true,
normalizer?: NormalizerFn,
}
)
#тестирование #testinglibrary #документация #примерыкода
👍1
ByText
Есть возможность искать элементы по текстовому контенту. Это сработает для всех элементов, у которых есть
Настройки у запроса стандартные:
Новая для нас настройка -
#тестирование #testinglibrary #документация #примерыкода
Есть возможность искать элементы по текстовому контенту. Это сработает для всех элементов, у которых есть
textContent
, а также для инпутов с типом submit
или button
.Настройки у запроса стандартные:
getByText(
text: TextMatch,
options?: {
selector?: string = '*',
exact?: boolean = true,
ignore?: string|boolean = 'script, style',
normalizer?: NormalizerFn,
})
Новая для нас настройка -
ignore
, она указывает, какие селекторы игнорировать при поиске.#тестирование #testinglibrary #документация #примерыкода
👍1
ByAltText, ByTitle
Еще два запроса для поиска по значению атрибутов:
-
-
#тестирование #testinglibrary #документация #примерыкода
Еще два запроса для поиска по значению атрибутов:
-
alt
- в основном для изображений-
title
screen.getByAltText(
text: TextMatch,
options?: {
exact?: boolean = true,
normalizer?: NormalizerFn,
})
screen.getByTitle(
title: TextMatch,
options?: {
exact?: boolean = true,
normalizer?: NormalizerFn,
})
#тестирование #testinglibrary #документация #примерыкода
👍1
ByTestId
И наконец последний, запасной запрос, который рекомендуется использовать только в самом крайнем случае, если ничего другое вам не подошло - поиск по атрибуту data-testid (название атрибута можно изменить в настройках).
#тестирование #testinglibrary #документация #примерыкода
И наконец последний, запасной запрос, который рекомендуется использовать только в самом крайнем случае, если ничего другое вам не подошло - поиск по атрибуту data-testid (название атрибута можно изменить в настройках).
screen.getByTestId(
text: TextMatch,
options?: {
exact?: boolean = true,
normalizer?: NormalizerFn,
})
#тестирование #testinglibrary #документация #примерыкода
👍1
Testing Library. Вызов событий. fireEvent
В тестах часто требуется проверить как элементы реагируют на действия пользователя, например, что при клике на кнопку отправились данные формы.
Testing Library предоставляет несколько способов эмулировать такие события. Самый простой - метод
Документация нам говорит, что в большинстве случаев мы будем использовать другой пакет - @testing-library/user-event, но пока посмотрим на этот.
Метод
Также есть несколько готовых методов для конкретных событий, которым можно передать объект с настройками:
Дока тут: https://testing-library.com/docs/dom-testing-library/api-events
Это особенно полезно для сложных событий ввода, например, для инпута с файлами, которому мы не можем вручную установить значение свойства
Пример: https://codesandbox.io/p/devbox/testing-library-global-jsdom-screen-react-junior-forked-7t9cmt
#тестирование #testinglibrary #документация #примерыкода
В тестах часто требуется проверить как элементы реагируют на действия пользователя, например, что при клике на кнопку отправились данные формы.
Testing Library предоставляет несколько способов эмулировать такие события. Самый простой - метод
fireEvent
из пакета @testing-library/dom
. Документация нам говорит, что в большинстве случаев мы будем использовать другой пакет - @testing-library/user-event, но пока посмотрим на этот.
Метод
fireEvent
принимает первым аргументом элемент, на котором необходимо вызвать событие. Вторым - объект события.
fireEvent(input, new MouseEvent('click'))
Также есть несколько готовых методов для конкретных событий, которым можно передать объект с настройками:
fireEvent.change(input, { target: { value: 'hello' } })
fireEvent.keyDown(domNode, {key: 'Enter', code: 'Enter', charCode: 13})
Дока тут: https://testing-library.com/docs/dom-testing-library/api-events
Это особенно полезно для сложных событий ввода, например, для инпута с файлами, которому мы не можем вручную установить значение свойства
files
.Пример: https://codesandbox.io/p/devbox/testing-library-global-jsdom-screen-react-junior-forked-7t9cmt
#тестирование #testinglibrary #документация #примерыкода
Testing-Library
Firing Events | Testing Library
Note
👍2
Testing Library. Асинхронщина. waitFor
В ряде случаев для тестирования нам нужно подождать, когда на странице что-то произойдет: появится/пропадет конкретный элемент, закончится какой-то таймер, юзер что-то кликнет и так далее. Библиотека предоставляет несколько способов для такого ожидания.
waitFor
Основная механика ожидания - это метод waitFor. Первым аргументом он принимает коллбэк, который собственно и должен проверить, произошло ли то, что нужно. Если произошло, нужно вернуть true, если нет - выбросить исключение. В этом случае коллбэк будет вызван для проверки снова спустя некоторое время, и так до тех пор, пока он не будет удовлетворен.
Мы можем даже использовать expect для проверки условий, так как при несоответствии он как раз выбрасывает ошибку:
Вместо коллбэка-функции можно передать промис, он не будет вызываться повторно.
Вторым аргументом можно передать объект с настройками:
- container: HTMLElement - по умолчанию document
Если мы ждем появления элемента внутри конкретного контейра, то можно передать его
- timeout - время ожидания
- interval - как часто вызывать коллбэк
- onTimeout: (error: Error) => Error - по умолчанию добавляет к ошибке текущее состояние элемента container
- mutationObsereverOptions - для настройки вызова коллбэка при изменениях контейнера
#тестирование #testinglibrary #документация #примерыкода
В ряде случаев для тестирования нам нужно подождать, когда на странице что-то произойдет: появится/пропадет конкретный элемент, закончится какой-то таймер, юзер что-то кликнет и так далее. Библиотека предоставляет несколько способов для такого ожидания.
waitFor
Основная механика ожидания - это метод waitFor. Первым аргументом он принимает коллбэк, который собственно и должен проверить, произошло ли то, что нужно. Если произошло, нужно вернуть true, если нет - выбросить исключение. В этом случае коллбэк будет вызван для проверки снова спустя некоторое время, и так до тех пор, пока он не будет удовлетворен.
Мы можем даже использовать expect для проверки условий, так как при несоответствии он как раз выбрасывает ошибку:
await waitFor(() => expect(mockAPI).toHaveBeenCalledTimes(1))
Вместо коллбэка-функции можно передать промис, он не будет вызываться повторно.
Вторым аргументом можно передать объект с настройками:
- container: HTMLElement - по умолчанию document
Если мы ждем появления элемента внутри конкретного контейра, то можно передать его
- timeout - время ожидания
- interval - как часто вызывать коллбэк
- onTimeout: (error: Error) => Error - по умолчанию добавляет к ошибке текущее состояние элемента container
- mutationObsereverOptions - для настройки вызова коллбэка при изменениях контейнера
#тестирование #testinglibrary #документация #примерыкода
👍2👏1
Testing Library. Асинхронщина. findBy
Мы помним, что у нас есть три вида запросов - getBy, queryBy и findBy. Так вот findBy - это комбинация getBy и уже рассмотренного выше метода waitFor. Таким образом, запрос
Можно использовать в комбинации с await:
#тестирование #testinglibrary #документация #примерыкода
Мы помним, что у нас есть три вида запросов - getBy, queryBy и findBy. Так вот findBy - это комбинация getBy и уже рассмотренного выше метода waitFor. Таким образом, запрос
findBy
по умолчанию ожидает, когда искомый элемент появится на странице.Можно использовать в комбинации с await:
await screen.findByText('Clicked once')
#тестирование #testinglibrary #документация #примерыкода
👍1
Testing Library. Асинхронщина. waitForElementToBeRemoved
Есть еще одна утилита, позволяющая дождаться, когда конкретный элемент исчезнет со страницы: waitForElementToBeRemoved.
Первым параметром она принимает элемент или массив элементов. Кроме того, можно передать функцию-коллбэк, которая вернет элемент или массив элементов. Если элемент null или массив пустой, будет ошибка.
Вторым параметром можно передать объект с настройками, такой же как у функции waitFor.
#тестирование #testinglibrary #документация #примерыкода
Есть еще одна утилита, позволяющая дождаться, когда конкретный элемент исчезнет со страницы: waitForElementToBeRemoved.
Первым параметром она принимает элемент или массив элементов. Кроме того, можно передать функцию-коллбэк, которая вернет элемент или массив элементов. Если элемент null или массив пустой, будет ошибка.
const el = document.querySelector('div.getOuttaHere')
await waitForElementToBeRemoved(el)
Вторым параметром можно передать объект с настройками, такой же как у функции waitFor.
#тестирование #testinglibrary #документация #примерыкода
👍1
Testing Library. Размышления о fireEvent
Хорошая статья в документации про особенности эмуляции событий: https://testing-library.com/docs/guide-events
Помня о главном принципе библиотеки, что "тестировать нужно максимально похоже на то, как действует реальный пользователь", мы тем не менее должны помнить о некоторых условностях, особенно в работе с событиями.
Например, если мы вызываем метод
Про это важно помнить, чтобы не столкнуться однажды с неожиданным и непонятным поведением.
Статья предлагает пару паттернов для эмуляции событий с помощью fireEvent. Например, вместо прямого вызова события keyDown на элементе, лучше сначала сфокусироваться на нем, а затем вызвать событие на document.activeElement:
#тестирование #testinglibrary #документация #примерыкода
Хорошая статья в документации про особенности эмуляции событий: https://testing-library.com/docs/guide-events
Помня о главном принципе библиотеки, что "тестировать нужно максимально похоже на то, как действует реальный пользователь", мы тем не менее должны помнить о некоторых условностях, особенно в работе с событиями.
Например, если мы вызываем метод
fireEvent.click(element)
, он задиспатчит событие клика и сработает обработчик клика, если он есть. В большинстве случаев нам этого более чем достаточно. Однако когда настоящий юзер кликает на настоящий элемент, мы получаем гораздо больше событий: mouseOver, mouseMove, mouseDown, focus (если элемент focusable), mouseUp и только теперь, наконец, click.Про это важно помнить, чтобы не столкнуться однажды с неожиданным и непонятным поведением.
Статья предлагает пару паттернов для эмуляции событий с помощью fireEvent. Например, вместо прямого вызова события keyDown на элементе, лучше сначала сфокусироваться на нем, а затем вызвать событие на document.activeElement:
getByText('click me')
fireEvent.keyDown(document.activeElement || document.body)
#тестирование #testinglibrary #документация #примерыкода
Testing-Library
Considerations for fireEvent | Testing Library
Interactions vs. events
👍2
Testing Library. Тестирование доступности
Если возникла необходимость затестить доступность вашего приложения, Testing Library предлагает пару полезных утилит:
getRoles
Находит на странице все элементы, имеющие роли, и возвращает их в виде объекта
logRoles
То же самое, только выводит данные в консоль.
isInaccessible
Проверяет, исключен ли элемент из дерева доступности браузера.
Подробнее в документации: https://testing-library.com/docs/dom-testing-library/api-accessibility
#тестирование #testinglibrary #документация
Если возникла необходимость затестить доступность вашего приложения, Testing Library предлагает пару полезных утилит:
getRoles
Находит на странице все элементы, имеющие роли, и возвращает их в виде объекта
logRoles
То же самое, только выводит данные в консоль.
isInaccessible
Проверяет, исключен ли элемент из дерева доступности браузера.
Подробнее в документации: https://testing-library.com/docs/dom-testing-library/api-accessibility
#тестирование #testinglibrary #документация
Testing-Library
Accessibility | Testing Library
Testing for Accessibility
👍1
Testing Library. Debugging
Библиотека предоставляет ряд возможностей для отладки
- Если запросы
- Утилита
- Метод
- Метод
- Утилита
Подробнее в документации: https://testing-library.com/docs/dom-testing-library/api-debugging
#тестирование #testinglibrary #документация
Библиотека предоставляет ряд возможностей для отладки
- Если запросы
get
или find
не находят элементов, то они выбрасывают ошибку, а в консоль выводится DOM корневого элемента (screen или container)- Утилита
prettyDOM
принимает элемент и возвращает его структуру- Метод
screen.debug()
или screen.debug(element)
также получает DOM элемента и выводит его в консоль- Метод
screen.logTestingPlaygroundURL()
выводит урл песочницы, в которой уже будет сохранен ваш документ- Утилита
logRoles
выводит все элементы, имеющие ролиПодробнее в документации: https://testing-library.com/docs/dom-testing-library/api-debugging
#тестирование #testinglibrary #документация
Testing-Library
Debugging | Testing Library
Automatic Logging
👍1
Testing Library. within и кастомные запросы
Библиотека также предоставляет ряд низкоуровневых функций для построения более точных/сложных запросов: https://testing-library.com/docs/dom-testing-library/api-custom-queries
И еще есть полезная функция
#тестирование #testinglibrary #документация
Библиотека также предоставляет ряд низкоуровневых функций для построения более точных/сложных запросов: https://testing-library.com/docs/dom-testing-library/api-custom-queries
И еще есть полезная функция
within(element)
. Она оборачивает полученный элемент и возвращает объект со всеми уже известными нам методами (как у объекта screen). И все эти методы работают "в контексте" полученного элемента: https://testing-library.com/docs/dom-testing-library/api-within#тестирование #testinglibrary #документация
Testing-Library
Custom Queries | Testing Library
DOM Testing Library exposes many of the helper functions that are used to
👍3