Топовые современные браузеры уже поддерживают модули ES6. Это отличная новость с точки зрения модульного тестирования. Браузер может изначально загружать и тестировать исходные коды проекта без транспилятора.
Как разработчик я хотел бы использовать эту функцию! Удаление лишних шагов из процесса разработки повысит скорость и производительность.
Ниже я расскажу о том, как у меня получилось работать с тест-раннером Mocha.
Начните с официального шаблона
Официальная документация Mocha содержит HTML-шаблон для запуска тестов в браузере.
Давайте посмотрим на это:
В шаблоне используются традиционные теги <script>
без атрибута type="module"
. Это означает, что сейчас он не использует модули ES6.
Чтобы сделать HTML-код более понятным и актуальным, необходимо внести некоторые изменения:
- Удалить jQuery
- Обновить версию Mocha до актуальной
4.0.1
- Заменить заброшенный expect.js на chaijs
- Поменяйте URL-адреса CDN на unpkg.com (поскольку cdn.rawgit.com не имеет необходимых версий Mocha)
- Удалите поддельные тестовые файлы:
test.array.js
,test.object.js
,test.xhr.js
Шаблон после очистки:
Добавьте простой тест, чтобы убедиться, что он работает
В качестве демонстрации я создал два файла:
- Исходный файл
sum.js
с простойsum()
функцией:
2. Тестовый файл sum.test.js
, проверяющий, sum()
работает нормально:
Я добавил эти файлы в HTML с помощью обычных тегов <script>
:
... <script>mocha.setup('bdd')</script> <script src="sum.js"></script> <script src="sum.test.js"></script> <script> mocha.checkLeaks(); mocha.run(); </script> ...
И открыла страницу в браузере:
Все работает. 🎉
Теперь давайте добьемся того же результата с собственными модулями ES6!
Перейти на модули ES
Двумя основными синтаксическими частями модулей ES являются import
и export
. Эти операторы позволяют устанавливать зависимости между модулями.
- Исходный файл
sum.js
превращается в модуль, который выполняет функцию экспорта:
2. Тестовый файл sum.test.js
превращается в модуль, который импортирует функцию и выполняет тест:
Поскольку тестовый файл теперь импортирует исходный файл, HTML-страница может включать только тестовый файл, а не оба файла, как раньше. Для импорта модуля ES в HTML-код тег <script>
должен иметь атрибут type="module"
:
... <script>mocha.setup('bdd')</script> <script type="module" src="sum.test.js"></script> <script> mocha.checkLeaks(); mocha.run(); </script> ...
Попробуем открыть страницу в браузере. Результат - пустой экран :( Это потому, что модули ES по умолчанию отложены. Вызов mocha.run()
в приведенном выше фрагменте кода происходит до загрузки sum.test.js
!
Обходной путь - сохранить порядок выполнения скриптов таким же, как теги <script>
в документе. С не встроенными скриптами атрибут defer
может выполнить эту работу. Но вот встроенный скрипт и атрибут defer
не применим.
Решение состоит в том, чтобы установить type="module"
как встроенный скрипт. Хотя он ничего не импортирует / не экспортирует, браузер сохраняет порядок выполнения и вызывает mocha.run()
после загрузки теста:
... <script type="module" src="sum.test.js"></script> <script type="module"> mocha.checkLeaks(); mocha.run(); </script> ...
Теперь это работает! Оба файла загружаются как модули ES, и тест проходит:
Это отличный результат для опыта разработки! Я могу редактировать файлы модуля ES и повторно запускать тесты в браузере без транспиляции!
Для проверки сделаем ошибку. 🐜
Тест показывает ошибку после перезагрузки страницы:
Улучшить результат
Решение работает, но его можно улучшить. В настоящее время логика запуска теста смешана с разметкой HTML в виде встроенных скриптов. Я предпочитаю убрать всю логику из HTML. Разметка должна быть ясной и простой.
Довольно простой способ - поместить все в один модуль JS:
..и включить на страницу только этот файл:
... <body> <div id="mocha"></div> <script type="module" src="run.js"></script> </body> ...
Теперь HTML выглядит очень четко! Но это не работает.
Есть две проблемы:
- Первая проблема связана с самой Mocha. Невозможно импортировать текущую версию Mocha (4.0.1) как модуль ES. Я пробовал разные подходы, но безуспешно:
import 'https://unpkg.com/[email protected]/mocha.js'; // Uncaught ReferenceError: require is not defined import 'https://unpkg.com/[email protected]/index.js'; // Uncaught ReferenceError: module is not defined import mocha from 'https://unpkg.com/[email protected]/mocha.js'; // Uncaught SyntaxError: The requested module does not provide an export named 'default'
Наконец, я вернул загрузку Mocha в обычный тег <script>
и открыл issue в репозитории Mocha.
2. Вторая проблема связана со статичностью модулей ES6. Все import
операторы в модуле разрешаются перед запуском кода. Но тесты Mocha полагаются на глобальные describe() / it()
функции, которые должны существовать во время выполнения теста. Импорт тестового файла как модуля вызывает ошибку, поскольку Mocha еще не экспортирует глобальные функции:
mocha.setup('bdd'); // <-- exports global describe() / it() import './sum.test.js'; // <-- executed before mocha.setup('bdd')
Единственное решение здесь - загрузить два отдельных модуля ES один за другим. Первый - настроить глобальные переменные для тестирования и утверждения: describe() / it()
и chai
. Второй - загрузить тесты и запустить раннер.
Настраивать:
Запустить:
HTML:
Теперь цель достигнута! HTML довольно прост, и логика живет в файлах JS. Я могу масштабировать это решение, добавляя больше тестовых файлов в run.js
.
Резервный вариант для старых браузеров
Последняя интересная задача - заставить эту страницу работать в старых браузерах.
Они не понимают <script type="module">
и не выполняют модули ES. Для этих браузеров весь импорт должен быть разрешен статически, объединен в один файл и включен на страницу как <script nomodule>
. Атрибут nomodule
предотвращает загрузку резервного скрипта в современных браузерах, которые знают о модулях ES.
Чтобы упаковать существующие модули setup.js
и run.js
в один файл, я воспользуюсь webpack. Он может разрешать import / export
операторов из коробки.
Начнем с простой конфигурации веб-пакета:
Но сборка не удалась:
> webpack ERROR in ./setup.js Module not found: Can't resolve 'https://unpkg.com/[email protected]/chai.js'
Это потому, что setup.js
пытается импортировать удаленный url:
import 'https://unpkg.com/[email protected]/chai.js';
Webpack предназначен для работы с локальной файловой системой. Но у него есть механизм псевдонимов, который позволяет отображать удаленные и локальные ресурсы. Я установил chai.js локально из npm и сопоставил удаленный chai.js
url с node_modules
:
Теперь проходы сборки и выведенные bundle.js
могут быть включены в HTML:
Для проверки результата воспользуюсь Firefox 57. Поддержка модулей ES там помечена флажком и по умолчанию отключена. Первая попытка отображает ошибку:
Объект утверждения chai
, загруженный из node_modules/chai
, не был добавлен в window
. Почему? Внутренне chai
построен как библиотека UMD. Это означает, что он использует window
, только если нет специальных переменных, таких как define
, module
и exports
. Webpack импортировал chai
как модуль CommonJS и предоставил переменную exports
. Вот в чем причина!
Как указать веб-пакету обрабатывать файл как готовый к использованию скрипт и не предоставлять специальные переменные? В документации есть ответ:
script-loader
оценивает код в глобальном контексте, аналогично включению через тегscript
. В этом режиме должна работать каждая нормальная библиотека.require
,module
и т. Д. Не определены.
Это именно то, что нужно. Добавление script-loader
в конфигурацию webpack устранило ошибку. chai.js
загружен и доступен по всему миру. Окончательная конфигурация веб-пакета:
В Firefox тест проходит!
Теперь тестовая страница работает во всех браузерах:
- Если браузер поддерживает модули ES - скрипты загружаются как модули ES.
- Если браузер не поддерживает модули ES - страница откатывается к встроенному скрипту.
Вы можете проверить онлайн в своем браузере. Исходный код доступен на GitHub.
Заключение
Модули ES - это способ организации всех будущих приложений JavaScript. Простое тестирование таких приложений является важным моментом для тестировщиков наряду с производительностью, тестированием снимков и другими функциями.
Пример выше - это начальная установка для Mocha. Его можно расширить, запустив в Headless Chrome, интегрировав с Karma или применив другой тест-раннер. Но это тема другого дня. 🙂
Спасибо за чтение и удачного тестирования!