Доказательство концепции

Недавно мне стало любопытно: Можно ли писать модульные тесты для внешнего кода, не использующего никаких 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, он ... заработал! Доказательство концепции имело большой успех, и было много радости.

Заключение

Итак, вернемся к первоначальному вопросу: можно ли писать модульные тесты для внешнего кода, которые не используют какой-либо фреймворк пользовательского интерфейса или инструменты разработчика?

Ответ: Да!

Хотя мое демонстрационное приложение, безусловно, не отражает того, как будет выглядеть готовое к производству приложение, тестирование пользовательских интерфейсов таким образом, если это необходимо, действительно кажется жизнеспособным вариантом.

Спасибо за прочтение!