Доказательство концепции
Недавно мне стало любопытно: Можно ли писать модульные тесты для внешнего кода, не использующего никаких UI-фреймворков или инструментов разработчика?
Другими словами, никаких React, Angular или Vue. Нет веб-пакетов или накопительных пакетов. Никаких инструментов для сборки. Просто старый добрый index.html
файл и немного ванильного JavaScript.
Можно ли протестировать такую установку?
Эта статья и ее репозиторий на GitHub - результат ответа на этот вопрос.
Предыдущий опыт
В своей профессиональной жизни я провел немало тестов. Я в первую очередь разработчик программного обеспечения, поэтому в мои области знаний входит написание модульных тестов с использованием Jest в качестве тестовой среды и Enzyme или React Testing Library в качестве моей тестовой библиотеки при работе с React. Я также проводил сквозное тестирование с использованием Cypress или Selenium.
Обычно я предпочитаю создавать пользовательские интерфейсы с помощью React. При тестировании этих интерфейсов я начал использовать Enzyme несколько лет назад, но с тех пор я предпочел React Testing Library и философию, согласно которой вы должны тестировать свое приложение так же, как пользователи используют ваше приложение, а не тестировать детали реализации.
Библиотека тестирования реакции Кента С. Доддса построена на основе его Библиотеки тестирования DOM, которая, как следует из названия, представляет собой библиотеку, которая помогает вам тестировать DOM. Я подумал, что это может быть хорошей отправной точкой.
Первоначальное исследование
В мире разработки программного обеспечения очень редко бывает, что вы первым пытаетесь что-то сделать. Практически все было сделано раньше в той или иной форме. По этой причине Google, Stack Overflow и форумы разработчиков - ваши друзья.
Я подумал, что наверняка кто-то еще пробовал это раньше и писал об этом. Однако после некоторых исследований выяснилось, что некоторые люди пробовали это в прошлом, но зашли в тупик. Один разработчик еще в августе 2019 года просил о помощи, но не получил ответа. Другой разработчик написал полезную статью о том, что они придумали, но, к сожалению, они закончили тестирование деталей реализации, чего я хотел избежать.
Итак, с информацией, которую я смог получить из их попыток, я начал делать свой собственный демонстрационный проект.
Демо-приложение
Как отмечалось выше, вы можете найти код моего демонстрационного приложения здесь. Вы также можете просмотреть приложение в действии, размещенное здесь. Он небольшой и простой, поскольку это, в конце концов, всего лишь проверка концепции.
Демо-приложения не должны быть скучными, поэтому я создал генератор слов для вашего развлечения. Вот как это выглядит:
При просмотре исходного кода следует помнить о двух важных файлах:
src/index.html
: Это все приложение. Никаких других файлов, только один HTML-файл с тегом сценария в нем.src/index.test.js
: Это тестовый файл. Я использую Jest и DOM Testing Library.
Оба файла маленькие, поэтому я включил их ниже:
Исходный файл: index.html
Тестовый файл: index.test.js
Обзор исходного файла
Как видно из файла index.html
, в нем нет ничего особенного. Если бы вы впервые изучали, как создать простую веб-страницу, ваш результат, скорее всего, выглядел бы очень похожим на этот с некоторыми базовыми HTML, CSS и JavaScript. Для простоты я включил в файл встроенные CSS и JavaScript, а не ссылки на дополнительные исходные файлы.
JavaScript создает массив каламбуров, добавляет к кнопке прослушиватель событий щелчка, а затем вставляет новый каламбур на экран каждый раз при нажатии кнопки. Достаточно просто, правда?
Погружение в тестовый файл
Поскольку это статья о тестировании, ключевой здесь является тестовый файл. Давайте вместе рассмотрим некоторые из наиболее интересных фрагментов.
Получение файла HTML
Первый вопрос, который у меня возник, заключался в том, как импортировать HTML-файл в тестовый файл. Если вы тестировали файл JavaScript, обычно вы импортируете экспортированные методы из файла, который хотите протестировать, следующим образом:
import { methodA, methodB } from './my-source-file'
Однако в моем случае этот подход не работает с файлом HTML. Вместо этого я использовал встроенный модуль fs
Node, чтобы прочитать HTML-файл и сохранить его в переменной:
const html = fs.readFileSync(path.resolve(__dirname, './index.html'), 'utf8');
Создание DOM
Теперь, когда у меня была строка, содержащая HTML-содержимое файла, мне нужно было как-то ее отрендерить. По умолчанию Jest использует jsdom для имитации браузера при запуске тестов. Если вам нужно настроить jsdom, вы также можете явно импортировать его в свой тестовый файл, что я и сделал:
import { JSDOM } from 'jsdom'
Затем в моем beforeEach
методе я использовал jsdom для рендеринга своего HTML-кода, чтобы проверить его:
let dom let container beforeEach(() => { dom = new JSDOM(html, { runScripts: 'dangerously' }) container = dom.window.document.body })
Запуск скриптов в среде jsdom
Самая важная часть для правильной работы содержится в параметрах конфигурации, переданных в jsdom:
{ runScripts: 'dangerously' }
Поскольку я сказал jsdom опасно запускать сценарии, он фактически интерпретирует и выполнит код, содержащийся в теге script
моего index.html
файла. Если этот параметр не включен, JavaScript никогда не выполняется, поэтому тестирование событий нажатия кнопки не сработает.
Заявление об ограничении ответственности: важно отметить, что здесь нельзя запускать ненадежные скрипты. Поскольку я контролирую HTML-файл и код JavaScript внутри него, я могу считать это безопасным, но если бы этот скрипт был сторонним или если бы он включал пользовательский ввод, было бы неразумно применять такой подход к настройке jsdom.
Момент истины
Теперь, после завершения описанной выше настройки, когда я запустил yarn test
, он ... заработал! Доказательство концепции имело большой успех, и было много радости.
Заключение
Итак, вернемся к первоначальному вопросу: можно ли писать модульные тесты для внешнего кода, которые не используют какой-либо фреймворк пользовательского интерфейса или инструменты разработчика?
Ответ: Да!
Хотя мое демонстрационное приложение, безусловно, не отражает того, как будет выглядеть готовое к производству приложение, тестирование пользовательских интерфейсов таким образом, если это необходимо, действительно кажется жизнеспособным вариантом.
Спасибо за прочтение!