Топовые современные браузеры уже поддерживают модули 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

Шаблон после очистки:

Добавьте простой тест, чтобы убедиться, что он работает

В качестве демонстрации я создал два файла:

  1. Исходный файл 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. Эти операторы позволяют устанавливать зависимости между модулями.

  1. Исходный файл 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 выглядит очень четко! Но это не работает.

Есть две проблемы:

  1. Первая проблема связана с самой 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 или применив другой тест-раннер. Но это тема другого дня. 🙂

Спасибо за чтение и удачного тестирования!