Привет, дзен! Недавно на работе споткнулся о тестирование компонента, в котором используется подписка на событие onTransitionEnd. Долго не мог придумать, решение. Потом вспомнил, что это javascript и придумал костыль. Из этого родилась маленькая статья, приятного чтения!
Компонент для тестирования
Есть обработчик события onTransitionEnd. Так как под transition попадает несколько свойств, а нам нужно только свойство высоты - простая проверка (вот о нее я и споткнулся) и вызов колбека - все очень просто.
Тест 1. Наивный
Тест тоже довольно простой, рендерим компонент, проверяем, что колбек не был вызван, файрим ивент, проверяем, что колбек был вызван один раз. Как думаете, пройдет тест?
Первый запуск
Тест не прошел с сообщением
Но интереснее посмотреть на консоль лог
Как я и думал, мы не задаем свойство propertyName, как результат оно не определено. Но почему конструктор Event? Должен же быть TransitionEvent? 🤨
Тест испорчен, вечер в шоке.
Тест 2. Переопределяем свойства.
Судя по тайпингам и документации функция вторым параметром можно передать либо ивент, либо настройки ивента, давайте попробуем.
Тест снова не проходит, смотрим лог
cancelable изменился, а propertyName нет? Чего? 🤨
Тест 3. Кастомный ивент
Ну, думаю, ладно, можно же создать кастомный ивент и стриггерить его, попробуем.
Делаем ставки, господа, что пойдет не так на этот раз?
Вот это поворот :)
Лезем в исходники и подглядываем.
В файлике `@testing-library/dom/dist/events.js` находим волшебные строки
Ну теперь хотя бы становится понятно, почему при вызове fireEvent.transitionEnd название конструктора Event а не TransitionEvent.
Дело в том, что testing library работает поверх jsdom. Не знаю как в свежих версиях, но в моей версии jsdom не существует TransitionEvent. Существует только Event.
Я, конечно, попробовал создать Event c параметрами {cancelable: false, bubbles: true, propertyName: 'height'}, но конструктор Event игнорирует propertyName. Я пробовал создать CustomEvent, но мои попытки не увенчались успехом
Проблема
Мне нужно создать ивент, который бы содержал propertyName = "height".
Все, доступные в jsdom, конструкторы событий игнорируют propertyName.
Что же делать? Есть идеи?
Костыль. Отличная идея
По хорошему, я бы поискал полифил TransitionEvent для jsdom, однако я нашел отличный (по моему мнению) костыль. Это же javascript :)
Мы можем создать Event, однако у него нет свойства propertyName.
Как бы нам так положить туда propertyName, да еще так, чтобы typescript не орал на меня?
Что мы делаем, когда property is undefined? Правильно, используем defineProperty :)
Ну сейчас-то тест пройдет?
Посмотрим на логи
Ура! Долгожданный тест пройден 🥳
Заключение
Это я сейчас в статье поставил консоль логи, обратил внимание на имя конструктора и тому подобное, но еще вчера на два часа моей жизни стало меньше из-за этой прекрасной особенности :)
Пишите тесты, определяйте свойства (это лютый костыль, не стоит так делать), подписывайтесь на события, на меня на ютубе, на меня в телеграмм канале.