Тестирование фронтенд компонентов с jest-dom на видимость пользователю

от автора

Решаем проблему с тестированием элемента, что он виден пользователю или не виден.

Предпосылки

Разработчики react-testing-library рекомендуют нам писать тесты так, как если бы код работал как у пользователя. А это значит что нужно вызывать пользовательские события, проверять что пользователь видит тот компонент, который должен.

Для тестирования компонентов мы используем библиотеку react-testing-library с testing-library/jest-dom, в рамках которого мы проверяем показывается тот или иной компонент на странице или нет.

Варианты решения

  1. Проверять с помощью метод toHaveClass то, что у элемента есть тот или иной класс. Не является хорошей практикой, т.к. на скрытие элемента также влияют его родители. Если родительский элемент не виден пользователь, соответственно и его дочерние тоже не будут.

  2. Использовать метод toBeVisible, который под капотом использует getComputedStyle, на расчет которого как раз влияют родительские компоненты и примененные классы к ним и к самому элементу. Но мы чаще всего css файлы стабаем (заменяем пустым объектом), чтобы тесты быстрее проходили, т.к. нам в принципе не важно, как выглядят компоненты у пользователя. Но есть проблема, как нам дать знать тестовому окружению, что у нас есть классы которые влияют на скрытие элемента.

Решение

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

Самый простое и легкое решение, это загрузить только те классы, которые у нас вызывает сокрытие у пользователя компонента. Если мы говорим про tailwindcss, то это классы hidden и invisible.

Добавим в файл jest.setup.js небольшой код, который решает нашу проблему:

import '@testing-library/jest-dom';  beforeEach(() => {     const style = document.createElement('style');     style.innerHTML = `     .hidden {         display: none;     }     .invisible {         visibility: hidden;     }     `;     document.head.appendChild(style); });

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

... test('Check element is show and hidden', async () => {   render(<Dropdown {...someProps} />);   const searchInput = screen.getByPlaceholderText(/Найти/i);    await userEvent.click(searchInput);    const listbox = screen.getByRole('listbox');    expect(listbox).toBeVisible();    await userEvent.click(document.body);    // если вы вдруг будете запрашивать элемент когда он скрыт используется getByRole с hidden: true, иначе элемент не найдет, т.к. для пользователя он скрыт, но присутствует в DOM-дереве   // const listbox = screen.getByRole('listbox', { hidden: true });    expect(listbox).not.toBeVisible(); }); ...

В данном тесте мы находим элемент у которого placeholder со значением «Найти», после мы имитируем нажатие на этот элемент. Компонент реализован у нас таким образом, что при нажатии на него, у нас показывается список элементов.

Затем с помощью getByRole ищем семантический тег список, проверяем его что он показывает на экране. Затем мы имитируем нажатие на тело документа, в приложении у нас компонент список скрывается на это действие и мы проверяем это с помощью expect(listbox).not.toBeVisible();

Но если бы мы в файле jest.setup.js не добавили описание для этих css стилей, которые скрывают элемент, то у нас тест бы не прошел, т.к. jest-dom думал бы, что элемент показывается, т.к. он не знает «реализацию» класса.

P.S. Также есть метод toBeInTheDocument, он проверяет если ли элемент в DOM-дереве элементов, но он не проверяет что видит пользователь или нет его на экране.


ссылка на оригинал статьи https://habr.com/ru/articles/856522/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *