Mocha: Поддержка тестов в стиле ES6 без использования транспилятора

Созданный на 18 сент. 2017  ·  75Комментарии  ·  Источник: mochajs/mocha

Предпосылки

  • [x] Проверено, что ваша проблема еще не зарегистрирована путем перекрестных ссылок на проблемы с меткой common mistake
  • [x] Проверены проблемы следующего поколения ES и проблемы синтаксиса с использованием той же среды и/или конфигурации транспилятора без Mocha, чтобы убедиться, что это не просто функция, которая на самом деле не поддерживается в рассматриваемой среде, или ошибка в вашем коде. .
  • [x] «Смоук протестировал» код, который необходимо протестировать, запустив его вне реального набора тестов, чтобы лучше понять, связана ли проблема с тестируемым кодом, использованием Mocha или самим Mocha.
  • [x] Устранено несоответствие между локальной и глобальной версиями Mocha. Вы можете найти их с помощью:
    node node_modules/.bin/mocha --version (локальный) и mocha --version (глобальный). Мы рекомендуем избегать использования глобально установленного Mocha.

Описание

Прежде чем я начну, у меня уже есть несколько закрытых вопросов, касающихся этой темы, но, поскольку предпосылки изменились, я хотел бы начать новую попытку.

Теперь, когда узел поддерживает запуск модулей EMCAScript (да, я знаю, что это экспериментально), было бы здорово увидеть, как mocha работает в сочетании с тестовыми определениями mjs .

Действия по воспроизведению

у меня очень простой тест

describe('Test', function () {
});

Которые я сохранил как test.js и test.mjs

Ожидаемое поведение: я хотел бы, чтобы оба теста показывали

- test/test.js 
  0 passing (1ms)
(node:70422) ExperimentalWarning: The ESM module loader is experimental.

Фактическое поведение: в то время как тест js работает, тест mjs дает мне

- test/test.mjs 
module.js:658
    throw new errors.Error('ERR_REQUIRE_ESM', filename);
    ^

Error [ERR_REQUIRE_ESM]: Must use import to load ES Module: /Users/dgehl/Repositories/LOreal/code/ecom-lora/test/frontend/components/global/test.mjs

Как часто воспроизводится: 100%

Версии

node --version - v8.5.0
mocha --version - 3.5.3

Дополнительная информация

Я _думаю_, что это может быть из-за того, что бегун мокко использует commonjs, а текущая реализация nodejs не позволяет использовать модули ECMAScript из контекста commonjs.

Пожалуйста, не отвечайте «используйте транспилятор», я хочу явно не использовать его.

Редактировать: в более ранней версии я случайно использовал jsx вместо mjs.

feature usability

Самый полезный комментарий

Мы реализовали встроенную поддержку Node ESM в Mocha v7.1.0.

Все 75 Комментарий

Первоначальные мысли в голове, прежде чем проводить какие-либо дальнейшие исследования:

  • Кажется, я припоминаю, что разработчики Node специально изменили стандарт, чтобы обеспечить обратную совместимость с модулями CommonJS. Если это (все еще?) верно, то я ожидаю , что в конечном итоге это будет поддерживаться без необходимости что-либо делать с Mocha. (И под «в конечном итоге» я подразумеваю «возможно, даже быстрее, чем изменения Mocha», учитывая скорость цикла выпуска Node; более подробное объяснение этого см. В выделенном предпоследнем месте ниже.)
  • Могу ли я предположить, что это было запущено как node --experimental-modules node_modules/mocha/bin/_mocha ?
  • Как именно участвует .jsx ? Я вижу, что показанный пример ошибки относится к .mjs ; из того, что было опубликовано, неясно, где находится jsx .
  • Я также смутно припоминаю, что слышал о первоначальной реализации Node, требующей расширения файла .mjs ; если это (все еще?) верно, и если вы пытаетесь использовать import / export с файлом .jsx (либо import с .jsx Файл .mjs или загрузка файла .jsx , содержащего import / export ), может ли проблема быть в этом, а не в Mocha?
  • Нам нужно было бы придумать способ гарантировать, что изменения в экспериментальной функции не потребуют изменений в Mocha, которые должны были бы ждать semver major — в противном случае вы могли бы вернуться туда, где мы сейчас, за исключением ожидания еще дольше .
  • Говоря чисто по моему мнению, а не от имени команды, если новый формат модуля не может взаимодействовать со старым форматом модуля без модификации существующих библиотек, написанных в старом формате, то новый формат модуля еще не готов .

Кажется, я припоминаю, что разработчики Node специально изменили стандарт, чтобы обеспечить обратную совместимость с модулями CommonJS. Если это (все еще?) верно, то я ожидаю, что в конечном итоге это будет поддерживаться без необходимости что-либо делать с Mocha. (И под «в конечном итоге» я подразумеваю «возможно, даже быстрее, чем изменения Mocha», учитывая скорость цикла выпуска Node; более подробное объяснение этого см. В выделенном предпоследнем месте ниже.)

Из моего (небольшого) исследования кажется, что, по крайней мере, на данный момент разрешено использовать require из модуля ECMAScript, но не import из модуля commonjs.

Могу ли я предположить, что это было запущено как node --experimental-modules node_modules/mocha/bin/_mocha?
Как именно задействован .jsx? Я вижу, что показанный пример ошибки относится к .mjs; из того, что было опубликовано, неясно, где находится jsx.

Да, он был запущен с --experimental-modules . jsx — это опечатка, я имел в виду mjs , обновлю исходный пост.

Я также смутно припоминаю, что слышал о первоначальной реализации Node, требующей расширения файла .mjs; если это (все еще?) верно, и если вы пытаетесь использовать импорт/экспорт с файлом .jsx (либо импортируя файл .jsx в файл .mjs, либо загружая файл .jsx, который содержит импорт/экспорт), может ли это быть проблема, а не мокко?

Кажется, проблема в том, и я мог что-то упустить, что мокко использует require для загрузки теста (по крайней мере, это мое текущее предположение, поскольку я не эксперт по мокко, а скорее пользователь), который затем включает другие модули через import . Это в сочетании с первым пунктом объясняет ошибку.

Нам нужно было бы придумать способ гарантировать, что изменения в экспериментальной функции не потребуют изменений в Mocha, которые должны были бы ждать semver major — в противном случае вы могли бы вернуться туда, где мы сейчас, за исключением ожидания еще дольше. (поскольку основной цикл выпуска Mocha не привязан к два раза в год, как Node).
Говоря чисто по моему мнению, а не от имени команды, если новый формат модуля не может взаимодействовать со старым форматом модуля без модификации существующих библиотек, написанных в старом формате, то новый формат модуля еще не готов.

Я боялся, что это будет ответ и понимаю, что это не первоочередная задача. Если мое предположение о причине приведенной выше ошибки верно, что-то вроде # 956 может помочь, поскольку точкой входа в тест может быть модуль mjs , а не commonjs, чего, вероятно, трудно достичь в противном случае. Похоже, что в дорожной карте команды nodejs есть поддержка import из текущих модулей, однако сроки неясны.

Из моего (небольшого) исследования кажется, что, по крайней мере, на данный момент разрешено использовать требование из модуля ECMAScript, но не импортировать из модуля commonjs.

Похоже, что в дорожной карте команды nodejs есть поддержка импорта из текущих модулей, однако неясны сроки.

Чтобы уточнить: учитывая, что в «старых» (в некоторых случаях текущих неэкспериментальных) средах import является синтаксической ошибкой, которой нельзя избежать с помощью логики ветвления или чего-то подобного, то, что нужно Mocha, не чтобы иметь возможность использовать сам import , а скорее иметь возможность использовать require для загрузки модулей, которые используют (или которые используют модули, которые используют) новый формат.

jsx — это опечатка, я имел в виду mjs, обновлю исходный пост.

Спасибо, это исключает один возможный угол!

Если мое предположение о причине приведенной выше ошибки верно, что-то вроде # 956 может помочь, поскольку точкой входа в тест может быть модуль mjs, а не commonjs, чего, вероятно, трудно достичь в противном случае.

Заставить Mocha не создавать глобальные переменные, к сожалению, невозможно без обширного переписывания некоторых наиболее загадочных внутренних элементов (я пробовал, но сам не смог понять это 😿 ); однако использование вашей собственной точки входа JS теперь возможно через «программный» API (который может быть не задокументирован за пределами старой вики-страницы и комментариев JSDoc в исходных файлах, но официально поддерживается):

// test.mjs
var Mocha = require('mocha'),
var mocha = new Mocha();

// your mission: create a file `example.mjs`
// in the `test` folder and have it `import` stuff
// as well as using `describe` and `it` to make tests
mocha.addFile("./test/example.mjs");

mocha.run(function(failures){
  process.on('exit', function () {
    process.exit(failures ? 1 : 0);
  });
});
node --experimental-modules test.mjs

На самом деле я не пробовал это, чтобы увидеть, имеет ли это значение (сначала нужно получить последнюю версию Node), но дайте мне знать, если это сработает для вас...

Прежде всего, спасибо за вашу поддержку в этом!

я пробовал это

// runner.mjs
import Mocha from 'mocha';
var mocha = new Mocha();

// your mission: create a file `example.mjs`
// in the `test` folder and have it `import` stuff
// as well as using `describe` and `it` to make tests
mocha.addFile('./test/frontend/components/global/test.mjs');

mocha.run(function (failures) {
    process.on('exit', function () {
        process.exit(failures ? 1 : 0);
    });
});

Таким образом, в основном точка входа узла была представлена ​​модулем ECMAScript.

Я запускаю его через node --experimental-modules --harmony ./runner.mjs

я получил

(node:88620) ExperimentalWarning: The ESM module loader is experimental.
{ Error [ERR_REQUIRE_ESM]: Must use import to load ES Module: /.../test/frontend/components/global/test.mjs
    at Object.Module._extensions..mjs (module.js:658:11)
    at Module.load (module.js:545:32)
    at tryModuleLoad (module.js:508:12)
    at Function.Module._load (module.js:500:3)

то, что нужно Mocha, - это не возможность использовать сам import , а возможность использовать require для загрузки модулей, которые используют (или используют модули, которые используют) новый формат.

Боюсь, в настоящее время это невозможно в узле, вы можете использовать require только в модулях, которые вы импортировали через import . Есть ли способ избежать mocha.addFile('./test/frontend/components/global/test.mjs'); и вместо этого импортировать тест и добавить импортированный скрипт, подобный этому

import test from './test';
mocha.addTest(test);

?

На данный момент в Mocha нет такой функции, но вы можете сделать что-то в этом роде. addFile просто добавляет файл в список, который позже require d с помощью функции run . Функция run вызывает loadFiles для require :

https://github.com/mochajs/mocha/blob/1cc0fc0e6153bbd746b0c2da565363570432cdf7/lib/mocha.js#L220 -L235

Что вы хотели бы сделать, так это для любых файлов, которые должны быть изменены на import вместо require d, не вызывайте addFile (поэтому Mocha не будет пытаться require #$8$#$). run ) и вместо этого перед вызовом run вызовите некоторый код, похожий на то, что находится в loadFiles , но используя import вместо require . Я не припоминаю сразу, есть ли какие-либо ограничения на использование import , которые могли бы предотвратить это, но если это вообще возможно, то я думаю, что это будет выглядеть довольно близко к:

modules.forEach(function (file) {
  file = path.resolve(file);
  mocha.suite.emit('pre-require', global, file, mocha);
  import fileExport from file; // fileExport is used by the exports interface, not sure if anything else; most interfaces act as a side effect of running the file
  mocha.suite.emit('require', fileExport, file, mocha);
  mocha.suite.emit('post-require', global, file, mocha);
});

Вы также можете посмотреть, как https://github.com/mochajs/mocha/blob/master/bin/_mocha использует программный API Mocha, чтобы понять, как предоставлять другие параметры и как использовать такие вещи, как функция поиска файлов Mocha. Он не очень хорошо организован, но все, что делает интерфейс командной строки, находится там (либо напрямую, либо потому, что есть вызов функций в программном API Mocha).

Я могу сделать еще один шаг, но импортированный тест теперь жалуется, что не знает об описании ( ReferenceError: describe is not defined ). Как правильно его вводить? Если я сделаю

import Mocha from 'mocha';
const describe = Mocha.describe;

он жалуется TypeError: describe is not a function

Итак, мой дистрибутив наконец-то получил NodeJS 8.5, и у меня была возможность поиграть с ним и подтвердить пару догадок, которые у меня были, но я не хотел заявлять, пока не смог проверить:

  1. Я не могу найти способ загрузить модуль ES без жесткого кодирования его имени в файле скрипта/модуля. Это означает, что Mocha не может загружать их через интерфейс командной строки независимо от того, что мы делаем, и независимо от любой другой семантики ES и CommonJS. Если и когда это изменится, я думаю, мы захотим узнать. (Если он изменится так, что ES-модуль можно будет загрузить через переменную require , нам, вероятно, не нужно будет ничего менять, но я не думаю, что мы можем что-то сказать о том, как работают модули, пока это не произойдет. .)
  2. В то время как Mocha настраивает интерфейс в эмиссии события pre-require (не при первой загрузке модуля; выбранный интерфейс специфичен для экземпляра new Mocha ), новая модульная система фактически анализирует дерево зависимостей. и загружает зависимости перед модулями, которые зависят от них, поэтому причина, по которой describe не определена, заключается в том, что Mocha не устанавливает его до тех пор, пока не будут загружены тестовые модули. Это означает, что это будет запутанно, чтобы это произошло вообще (опять же, до тех пор, пока require(file) не будет разрешено и не загрузит зависимость в этой конкретной строке, желательно синхронно, поэтому нам не нужно ничего менять ).

Тем не менее, я обнаружил, что могу заставить его работать, используя тот факт, что загруженные модули import загружаются в порядке вызовов import . (Это было бы намного более избыточно, если бы вы использовали интерфейс экспорта или генератор отчетов, которому нужно имя каждого отдельного файла, как описано в коде, который я собираюсь связать, но в принципе это работает.) Если бы этот факт был измениться без изменения каких-либо других вышеперечисленных фактов, то даже это было бы вообще невозможно. Но пока я думаю, что это то, что вам нужно сделать.

https://gist.github.com/anonymous/caba0883254a2349c5615df8e9286665

node --experimental-modules ./run.mjs

К сожалению, я почти уверен, что это лучшее, что мы можем сделать, учитывая то, как работают модули ES и что Node позволяет в настоящее время.

Подумайте об этом иначе:

  • import — это синтаксис.
  • require — это функция.

Вы не можете динамически import ничего, так же как вы не можете динамически запускать код без использования, например, eval() .

Существует это предложение этапа 3 , которое позволило бы такое поведение, но я не уверен, что какие-либо среды выполнения его еще отгружают.

Таким образом, у Mocha нет возможности импортировать файл .mjs при запуске через mocha без добавления, возможно, @std/esm и использования его реализации require для файлов с .mjs Расширение может быть жизнеспособным решением, и мы могли бы подумать о его поддержке, но обсуждение (и такой PR), скорее всего, должно исходить от сообщества, по крайней мере, до тех пор, пока такое поведение не будет скрыто под флагом.

К сожалению, import describe from 'mocha' находится довольно низко в списке приоритетов из-за присущей этому роду сложности (#956). Лучше всего работать с node и придерживаться глобальных переменных.

На самом деле мне приходит в голову, что мы могли бы загрузить тесты и использовать vm.runInContext , предполагая, что такая штука поддерживает модули. Поскольку загрузочное поведение Node привязано к расширению .mjs , а vm.runInContext ожидает string , не понимаю, как это могло быть — и в документации об этом ничего не упоминается. Может где- то проблема?

(опять же, это может быть именно то, что @std/esm делает под капотом!)

У меня есть тесты мокко, работающие без транспилятора в браузере . Может быть, это поможет в этом вопросе.

это не имеет отношения, поскольку вы используете мокко не как модуль, а скорее как скрипт...

извините сам запутался. в браузере по другому.

Я хочу проголосовать за то, чтобы сделать что-то, чтобы позволить Mocha запускать тесты, расположенные в модуле ES. Я попал сюда после попытки написать такой тест и получил странную ошибку от загрузчика модуля Node.js. Я использую Node.js 9.5, который изначально поддерживает модули ES6.

В настоящее время Node.js 9.5 не позволяет модулю CommonJS требовать() модуля ES6. Может быть, они работают над тем, чтобы разрешить это, я не знаю.

Я написал тест как модуль ES6 с расширением .mjs и попытался его запустить. Получил ошибку от загрузчика - я предполагаю, что команда mocha приводит к использованию require() , и поэтому она не удалась.

Переделал тест с расширением .js и попытался использовать require() для загрузки тестируемого модуля. Вот и вылезла ошибка загрузчика.

Я считаю, что мир Node.js должен подумать о том, как они будут переходить на модули ES6 и поддерживать их. Поскольку Mocha — очень популярный инструмент в этом мире, команде Mocha было бы лучше подумать о том, как поддерживать модули ES6.

Чтобы продолжить ... После некоторых размышлений и поисков я смог заставить эту последовательность работать в качестве обходного пути.

Назовите тестовый скрипт с расширением .js (что сделает его скриптом CommonJS).

Затем добавьте это в тестовый скрипт:

require = require("@std/esm")(module,{"esm":"js"});

Затем я могу require() модуль ES так:

const model = require('../models/notes');

@robogeek Или, может быть, даже лучше использовать предварительный загрузчик @std/esm из командной строки, чтобы вам не приходилось загромождать файлы спецификаций обходными путями, и вы могли иметь расширения .mjs .

mocha -r @std/esm spec.mjs

Динамический импорт поставляется с узлом версии 9.6, скрытым флагом --harmony-dynamic-import . Динамический импорт позволяет mocha загружать тесты, содержащиеся в модулях es6, без транспилятора.

@harrysarson Это не сработает из коробки. Mocha использует модули cjs и require , вам нужно будет написать тестовые файлы, используя cjs, с некоторым дополнительным связующим кодом для обработки асинхронного характера import . Или я что-то упускаю?

Я бот, который следит за проблемами на предмет бездействия.
В последнее время по этой проблеме не было никаких действий, и я помечаю ее как stale . Через 14 дней, если не будет дальнейших комментариев или активности, я закрою эту тему.
Спасибо за вклад в Mocha!

Проблема по-прежнему актуальна, но зависит от встроенной поддержки ESM. В браузерах это есть, в Node еще нет.

Я просто баловался, знакомился с ESM/.mjs и решил, что нужны тесты для моей игрушки. Понимая, что мокко еще официально не поддерживает файлы .mjs , я быстро собрал промежуточный модуль (пока кто-нибудь не успеет добавить полную поддержку мокко):

https://www.npmjs.com/package/mocha-esm
PR/вопросы приветствуются: https://github.com/stefanpenner/mocha-esm

Там может быть что-то лучше, но вместе было весело. так \о/

Я решил разветвить сам mocha для поддержки динамического импорта (основываясь на некоторых идеях выше, но я не мог заставить его работать каким-либо другим способом).

Это означает, что вы можете запустить, используя, например, node --experimental-modules --harmony-dynamic-import test.mjs

Затем в test.mjs :

import 'should';
import Mocha from 'mocha';

const mocha = new Mocha();

mocha.addFile(() => import("./some-module.spec.mjs"));

mocha.run(failures => {
  process.on('exit', function () {
    process.exit(failures ? 1 : 0);
  });
});

Я сохранил изменения в мокко для поддержки этого минимального , и у меня не было времени правильно интегрировать это для потенциального PR, и я не добавлял специализированный модуль npm, но вы можете установить этот форк напрямую с github "mocha": "git+https://[email protected]/odolha/mocha" .

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

РЕДАКТИРОВАТЬ

Я забыл упомянуть, что ваши тесты не могут быть чистыми скриптами с таким подходом, потому что мы не можем внедрить контекст, поэтому вместо этого вам нужно:

// some-module.psec.mjs
export const test = ({ describe, it }) => {
  describe('Something', () => {
    it('works', () => {
      ...
}

@одолха
Спасибо за ссылку на вашу вилку.
Уже был PR для поддержки собственного ESM , но он был закрыт, потому что поддержка модулей все еще находится в экспериментальном состоянии.

Ваша реализация утешает меня тем, что добавить поддержку этого должно быть легко. Мы многие с нетерпением ждем этой функции :)

@demurgos :no_mouth: да... Я только что увидел этот пиар после того, как сделал свое дело, черт возьми 😃.

@harrysarson @костяной череп
Пакет esm (ранее называвшийся @std/esm ) отказался от поддержки файлов .mjs в этом коммите .
Это означает, что его больше нельзя использовать с Mocha для тестирования файлов .mjs . Это обсуждается в этом выпуске .

Я все еще хочу иметь возможность тестировать модули ES, чтобы я мог безопасно запускать их в Node или браузерах.

Что касается текущих обсуждений модулей, существует консенсус, что .mjs должен быть доступен в конечном результате (возможно, не как единственное решение, но, по крайней мере, доступно) и что import("./foo.mjs") вернет обещание для соответствующее пространство имен ES. Тот факт, что модули CJS преобразуются в модуль с экспортом default , соответствующим module.exports , вызывает больше споров, но это кажется безопасным предположением.

Можно ли пересмотреть добавление встроенной поддержки ES с помощью динамического import в Mocha? Флаг функции можно переименовать в --experimental-es-modules (из #3253), чтобы лучше показать, что это зависит от текущего улучшения поддержки Node.
В соответствии с установленными сроками окончательная спецификация не появится до Node 12, поэтому текущая реализация останется там на некоторое время (и является относительно безопасным подмножеством окончательного предложения).

@demurgos Лично я предпочитаю подождать с этим еще немного, прежде чем приступать к какой-либо реализации кода на мокко. Но, может быть , @boneskull или @ScottFreeCode не согласны?

@демургос

Пакет esm (ранее называвшийся @std/esm) удалил файлы поддержки .mjs в этом коммите.

Загрузчик esm не отказался от поддержки .mjs . Мы просто следуем текущей реализации --experimental-modules и выдаем ошибку при попытке загрузить .mjs с помощью require . Пользователи по-прежнему могут использовать файл .js для своего файла тестовой записи, который использует синтаксис ESM или динамический import() для загрузки последующих тестовых файлов размером .mjs или .js как esm делает для своих собственных тестов .

Согласно срокам, окончательная спецификация не появится до Node 12, поэтому текущая реализация останется там на некоторое время.

Нет установленного времени для --experimental-modules , чтобы приземлиться без флажка. Есть надежда, что он может приземлиться где-то в цикле поддержки Node 10 _(то есть где-то в ближайшие 2 года)_, но ничего не высечено на камне.

(и является относительно безопасным подмножеством окончательного предложения).

Текущая реализация --experimental-modules может быть несовместима с окончательным предложением. Существует несколько дискуссий о том, как будет выглядеть поддержка ESM в Node. Некоторые предложенные направления несовместимы с текущей экспериментальной реализацией. В зависимости от того, как обстоят дела, код, который вы пишете сегодня за --experimental-modules , может не работать с какой бы ни была окончательная форма.

Загрузчик esm не отказался от поддержки .mjs.

Я хочу сказать, что esm больше не позволяет требовать .mjs , поэтому вы больше не можете использовать тестовое обнаружение Mocha для .mjs . Но вы правы, это не было задокументировано, поэтому на самом деле это не критическое изменение, даже если на него полагались другие люди.

Что касается сроков, я имел в виду этот вопрос . Кажется, есть попытка для Node 11 и окончательная реализация для Node 12, чтобы ее можно было портировать на Node 10 LTS. Одни хотят, чтобы это произошло раньше, другие предупреждают, чтобы не торопились.

Мое предложение состоит в том, чтобы объединить #3253. Это предлагает только механизм отказа для использования import(...) вместо require для загрузки тестовых случаев. Поскольку я ожидаю, что он будет в основном применяться для .mjs в контексте --experimental-modules , я все еще думаю, что это безопасно. (динамический импорт .mjs , возвращающий обещание пространства имен, вероятно, останется). Но я оставлю вам решать, можете ли вы объединить это и не слишком настаивать на этом.

Опять же, основная причина этого PR заключается в том, что без него вы больше не можете использовать тестовое обнаружение Mocha, но должны использовать обходной путь, описанный выше @jdalton. (точка входа .js и ручной импорт)

Мое предложение состоит в том, чтобы объединить #3253.

3253 имел довольно много недостатков, определенно не стоит объединять его как есть.

Следуя примеру @jdalton , я настроил небольшой рабочий процесс для тестирования собственного ESM без пакета esm (чистый Node + Mocha).
Я использую определения асинхронных тестов (используя --delay ) и --experimental-modules .

В настоящее время _mocha_ может импортировать только CJS, а CJS может импортировать только ESM, используя динамическую псевдофункцию import() . Поэтому я создаю следующую точку входа CJS (ее имя заканчивается на .js ), которая импортирует файлы спецификации и запускает выполнение теста:

test.esm.js :

(async () => {
  await import("./test/a.spec.mjs");
  await import("./test/b.spec.mjs");
  run();
})();

(Я генерирую точку входа со списком импорта во время сборки, но вы можете написать его вручную или использовать там glob .)

Затем я выполняю его с помощью следующей команды:

NODE_OPTIONS="--experimental-modules" mocha --delay build/test/test.esm.js

Мне нужно пройти через NODE_OPTIONS , потому что флаг не распознается мокко.


Я все еще надеюсь, что mocha обеспечит лучшую поддержку экспериментального ESM, но, по крайней мере, приятно знать, что сегодня есть способ использовать его без других инструментов.

@demurgos , это хороший небольшой обходной путь, который вы нашли :+1:.

Приятно видеть, что действительно возможно (хотя и не просто) использовать модули es с mocha : smile:.

@demurgos Эта проблема касается поддержки тестов в стиле ES6 без использования транспилятора . Что такое "время сборки"? Тот код, который вы используете для создания тестовых точек входа, является транспайлером, только специализированным.

@rulatir
Я упомянул, что использую инструменты сборки, но они не относятся к тому уровню, который обсуждается в этом выпуске: Mocha работает с собственным ESM, а не с ESM, пониженным до CJS с помощью транспилятора.

Смотрите мое сообщение:

Я генерирую точку входа со списком импорта во время сборки, но вы можете написать его вручную или использовать там glob .

Я использовал шаг сборки, потому что хочу, чтобы мои импорты были (1) статически определены и (2) не поддерживали список самостоятельно.

Если у вас есть только несколько файлов спецификаций, удаление (2) — это нормально: просто создайте точку входа, импортирующую ваши 1-2 файла спецификаций.
(1) уже является особым требованием для тестовых файлов, поэтому в основном это просто «приятно иметь», и вы можете использовать glob во время выполнения (вместо времени сборки, как я). Это всего лишь деталь, которая, в конце концов, не имеет значения, когда вы понимаете основную идею.

Если вам просто нужно что-то вроде простого решения для копирования и вставки, которое находит файлы спецификаций mjs во время выполнения, вот пример:

const {sync: globSync} = require("glob");

(async () => {
  const matches = globSync("**/*.spec.mjs");
  for (const match of matches) {
    await import(match);
  }
  run();
})();

Запустите его с NODE_OPTIONS="--experimental-modules" mocha --delay test.esm.js .
Как видите, сборки нет вообще, а шума в коде немного больше.

Я бот, который следит за проблемами на предмет бездействия.
В последнее время по этой проблеме не было никаких действий, и я помечаю ее как stale . Через 14 дней, если не будет дальнейших комментариев или активности, я закрою эту тему.
Спасибо за вклад в Mocha!

Этот вопрос все еще актуален и не должен быть закрыт.

Предстоящий релиз mocha@6 будет иметь флаг --experimental-modules из белого списка, позволяющий легче экспериментировать с модулями ES6. Возможно ли выпустить второстепенный выпуск или патч до v6? В настоящее время я дорабатываю новый инструмент покрытия, который использует отладчик V8 вместо Istanbul, и хотел бы протестировать его с модулями Mocha и ES6 (без использования зависимости git в моем package.json).

@демургос

Когда я пытаюсь вот так...

const {sync: globSync} = require("glob");
(async () => {
    const matches = globSync("**/*.spec.mjs");
    for (const match of matches) {
        await import(match);
    }
    run();
})();

я получил

(node:4632) UnhandledPromiseRejectionWarning: Error: Cannot find module test/Sanity.spec.mjs

Но когда я так бегу...

const {sync: globSync} = require("glob");
(async () => {
    await import("./Sanity.spec.mjs");
    run();
})();

Работает идеально, что мне не хватает?

@demurgos вы должны согласовать с @bcoe; см. https://github.com/bcoe/c8

@demurgos , чтобы вырезать второстепенный выпуск, нам нужно было бы собрать все некритические изменения, начиная с версии 5.2.0, в ветку и скомпилировать их в CHANGELOG. если вы или кто-то еще желает сделать эту работу, мы можем сократить релиз.

Между прочим, я рекомендую esm вместо --experimental-modules , пока Node.js не прояснит свою историю. это будет значительное ожидание.

@костяной череп
Хаха спасибо. Я уже работаю над c8 с июля (я открыл кучу PR и выпусков в этом репо). Есть также некоторые проектные решения, с которыми мы не согласны, поэтому мы пытаемся разделить большинство зависимостей (например, я написал алгоритм слияния) и решили опубликовать другой инструмент: c88 . Я заставил его работать на этих выходных, и сейчас я тестирую его на своих библиотеках. Я могу использовать его с собственным ESM и мокко в CI. Мне все еще нужно время, чтобы задокументировать и исправить это, но оно должно быть готово в январе).

@jrgleason
Я написал код выше головы. Похоже, проблема здесь в том, что globSync возвращает относительные пути, которые не начинаются с ./ или ../ . Вы можете добавить к нему ./ : он должен работать с простыми относительными путями.
Также следует учитывать, что при динамическом импорте используются относительные URL-адреса: # , ? и другие специальные символы могут обрабатываться по-разному. Если вам нужно надежное решение, вы должны разрешить абсолютный путь к модулю, а затем преобразовать его в URL-адрес файла. В рамках моей работы над покрытием я написал библиотеку для преобразования между абсолютными путями и URL-адресами: вы можете использовать fromSysPath из furi . Преобразования должны обрабатывать любой путь (даже пространства имен Windows и пути UNC...).

Вот как может выглядеть полный пример:

const {fromSysPath} = require("furi");
const {sync: globSync} = require("glob");
const {resolve} = require("path");

(async () => {
    const matches = globSync("**/*.spec.mjs");
    for (const match of matches) {
        await import(fromSysPath(resolve(match)).href);
    }
    run();
})();

Я имею в виду, разве mocha --require esm просто не работает ? Нам действительно нужно автоматическое обнаружение? Это звучит сложно и добавляет накладные расходы...

@demurgos , чтобы вырезать второстепенный выпуск, нам нужно было бы собрать все некритические изменения, начиная с версии 5.2.0, в ветку и скомпилировать их в CHANGELOG. если вы или кто-то еще желает сделать эту работу, мы можем сократить релиз.

Спасибо за предложение. По-прежнему можно получить --experimental-modules с помощью NODE_OPTIONS , поэтому это не имеет высокого приоритета (и это может усложнить дерево git для фиксации вишневого выбора). Если мне удастся закрыть проблемы, которые у меня есть с другими зависимостями, я посмотрю, смогу ли я потратить на это некоторое время. А пока я просто слежу за вехой v6.

Между прочим, я рекомендую esm вместо --experimental-modules , пока Node.js не прояснит свою историю. это будет значительное ожидание.
Я имею в виду, разве mocha --require esm просто не работает?

Я определенно согласен с тем, что это лучшее решение на данный момент: это самое простое решение для настройки, и оно существует уже некоторое время: оно работает. В моем случае я поддерживаю свои собственные инструменты сборки и работаю с собственным ESM в качестве альтернативы классическим сборкам CJS. Несмотря на то, что я действительно стремлюсь к нативному ESM, я все же рекомендую не использовать его как единственный способ запуска вашего кода: в конце концов, это экспериментально :stuck_out_ language :.

Большинство моих последних сообщений посвящены тому, что можно сделать с помощью нативного ESM. Это в основном экспериментальная работа, и я ожидаю, что мне придется изменить ее, когда ESM Node станет стабильной. В долгосрочной перспективе преимущества решения, не требующего пакета esm . Вот мои причины:

  • Это уменьшает количество необходимых инструментов (меньшая сложность, меньше конфигурации для понимания)
  • Может быть несколько различий между реальным ESM и esm в пограничных случаях (ошибки оценки, циклы, ошибки загрузки, асинхронные/динамические модули, wasm и т. д.). При написании изоморфного кода может быть безопаснее уменьшить любой возможный источник расхождений в поведении. Это также связано с собственным покрытием: с esm V8 видит транспилированный вывод, поэтому вам приходится иметь дело с исходными картами (еще не поддерживается c8 , но я готовлю PR, они работают на c88 ). При отладке могут проявиться и другие отличия.
  • Это позволяет избежать динамической транспиляции кода и помогает повысить производительность.

Нам действительно нужно автоматическое обнаружение? Это звучит сложно и добавляет накладные расходы...

Я не уверен, о каком автоматическом обнаружении вы говорите. Связано ли это с PR, отправленным ранее в этом году?


Редактировать : я также нахожусь в Slack инструментов Node (в основном активен на канале #c8 ), если вы хотите обсудить.

@demurgos Думаю, я немного запутался в том, что люди хотели здесь. В любом случае...

Если NODE_OPTIONS=--experimental-modules работает до тех пор, пока --experimental-modules не будет поддерживаться в Mocha v6.0.0, нужно ли что-то еще делать для решения этой проблемы? Вот чего мне не хватает.

Я ожидаю, что этот вопрос должен оставаться открытым до тех пор, пока собственный ESM («тесты в стиле ES6 без использования транспилятора») не заработает «из коробки» / так же легко, как CJS работает в настоящее время.

Решение, которое я разместил с помощью --delay и NODE_OPTIONS=--experimental-modules , является скорее обходным путем, чем надлежащей поддержкой. Я считаю, что эта проблема исправлена, как только вы сможете запустить mocha **/*.spec.mjs и получить отчет.

К сожалению, на данный момент я чувствую, что нам все еще нужно подождать, пока Node разберется с поддержкой ESM. Я бы проверил, но я думаю, что PR не использовал автоматическое определение, а просто импортировал каждый модуль (CJS или ESM) с помощью динамического импорта. Реализация будет зависеть от истории взаимодействия модулей.


Изменить : я имею в виду https://github.com/mochajs/mocha/pull/3253. Это позволяет загружать все модули как ESM (без автоматического определения).

Я бот, который следит за проблемами на предмет бездействия.
В последнее время по этой проблеме не было никаких действий, и я помечаю ее как stale . Через 14 дней, если не будет дальнейших комментариев или активности, я закрою эту тему.
Спасибо за вклад в Mocha!

Узел 12 должен включать новую реализацию ESM. Это будет повод проверить, как поддерживать модули ES в Mocha.

Я столкнулся с ошибкой GC при использовании Mocha и ESM, но о ней сообщается и подтверждается, поэтому она должна быть исправлена: https://github.com/nodejs/node/issues/27492.

Помимо этой ошибки, стратегия, описанная в моем комментарии выше , все еще работает для использования Mocha с ESM.

Привет, люди Mocha, спасибо за создание и поддержку хорошего инструмента!

Это просто комментарий к вашему сведению. Последние несколько месяцев я работал над Mocha и * -test.mjs , используя патчи, как показано ниже. Практически нет проблем с запуском mocha test/*.mjs (без транспайлера или модуля esm npm).
https://gist.github.com/tadd/756d21bad38933c179f10e59bddee6b4

Конечно, этот патч не «готов к производству» для коммиттеров Mocha; это просто хак для пользователей Mocha, которые хотят как можно скорее использовать ESM в тестовых кодах.
Я использовал Node.js v11 с опцией --experimental-modules . В настоящее время я с v12 и тоже работает.

Это другая история, но Node v12 представил расширение $#$4 .cjs "type" в package.json . Кажется, их тоже нужно учитывать.

Привет, люди Mocha, спасибо за создание и поддержку хорошего инструмента!

Действительно, и я тоже хочу поблагодарить 😄

Я использовал другой подход, чтобы заставить loadFiles оставаться синхронными, см. ниже. У меня работает с февраля. В отличие от некоторых других хаков, этот по-прежнему позволяет использовать все флаги, инструменты проверки/разработчика и точное покрытие кода с помощью c8 . Именно из-за этой последней функции мне действительно нужен встроенный ESM, потому что пакет esm имеет разные смещения для каждого файла. (Экспорт модуля отображается в списке и сбивает с толку Стамбул).

https://gist.github.com/maxnordlund/a860dd67013beaf0f31ce776536f0a47

Привет! Это также необходимо для тестирования любого кода, который зависит от собственного проекта ES6, например, lit-element . В противном случае вылетает так:

node_modules/lit-element/lit-element.js:14
import { TemplateResult } from 'lit-html';
       ^

SyntaxError: Unexpected token {
    at Module._compile (internal/modules/cjs/loader.js:703:23)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:770:10)
    at Module.load (internal/modules/cjs/loader.js:628:32)
    at Function.Module._load (internal/modules/cjs/loader.js:555:12)
    at Module.require (internal/modules/cjs/loader.js:666:19)
    at require (internal/modules/cjs/helpers.js:16:16)
    ...

Я не знаю, есть ли обходной путь для этого, но в настоящее время я не думаю, что есть способ использовать Mocha с собственной структурой ES6.

@heruan Я разместил решение, работающее с Node 8, в комментариях выше. Вот обновленная версия, для которой требуется Node 10.12 для собственных преобразований URL-адресов файлов:

Добавьте следующий файл test.esm.js :

const {pathToFileURL} = require("url");
const {sync: globSync} = require("glob");
const {resolve} = require("path");

(async () => {
    const matches = globSync("**/*.spec.mjs"); // Change the glob to match your test files
    for (const match of matches) {
        await import(pathToFileURL(resolve(match)).href);
    }
    run();
})();

Затем запустите тесты с помощью mocha --experimental-modules --delay test.esm.js .

Этот код работает, используя test.esm.js в качестве моста commonjs для загрузки тестов ESM.

В узле 12 сообщается о проблеме, из-за которой IIAFE собирается сборщиком мусора (nodejs/node#27492), она должна быть исправлена ​​в одной из следующих второстепенных версий (могут быть некоторые обходные пути, но я их еще не изучал). Я рекомендую использовать последнюю версию Node 10, пока она не будет исправлена.

Thar вызовет предупреждение UnhandledPromiseRejectionWarning , если есть какая-либо ошибка. Лучше связать console.error или иным образом обработать ошибку.

import glob from "glob"
import { pathToFileURL } from "url"
import { resolve } from "path"
import { promisify } from "util"

const globAsync = promisify(glob)

async function main() {
  const matches = await glob("test/**/*.mjs")

  for (const match of matches) {
    await import(pathToFileURL(resolve(match)).href)
  }

  run()
}

main().catch(console.error)

_Я знаю, что это использует import вместо require , но см. мою суть для решения, которое позволит вам остаться в стране ESM_

@demurgos Спасибо за фрагмент кода для Node 10.12, который вы опубликовали десять дней назад!

Я использую Node 12.1, и он работает нормально. Будет ли это скоро добавлено в Mocha, или есть еще более простой способ сделать это с Node 12? Кроме того, как мне использовать это в режиме --watch ?

https://github.com/standard-things/esm, кажется, работает из коробки с --require esm , но было бы здорово отказаться от другой зависимости :) Спасибо.

Если бы Mocha переключился на ESM в исходном коде, Rollup мог бы предоставить файл дистрибутива ESM, а также файлы CommonJS и/или UMD.

Еще одним преимуществом здесь является то, что HTML-код браузера не нужно засорять дополнительными тегами скрипта для загрузки Mocha. Тестовые файлы (или основной тестовый входной файл) могут выполнять импорт (и избегать «магии» в тестовых файлах, чтобы выяснить, откуда берутся переменные - нужно только отследить пути импорта).

Можно также использовать плагины CSS для Rollup, чтобы разрешить вставку mocha.css , что еще больше минимизирует потребность в беспорядке HTML.

Я бот, который следит за проблемами на предмет бездействия.
В последнее время по этой проблеме не было никаких действий, и я помечаю ее как stale . Через 14 дней, если не будет дальнейших комментариев или активности, я закрою эту тему.
Спасибо за вклад в Mocha!

Я думаю, что это все еще актуально.

Удалось ли кому-нибудь запустить Mocha с модулями ES6 на узле (edit: ~Travis~) >=12.11.0?
На 12.10.0 вроде успешно настроил:
мокко-run.js

(async () => {
    await import("./tests.js");
    run();
})();

Тогда mocha --experimental-modules --delay ./mocha-run.js работает как шарм.

Но по какой-то неизвестной причине на 12.11.0 он ведет себя так, как будто не было бы параметра --delay :

>  mocha --experimental-modules --delay ./mocha-run.js

(node:6439) ExperimentalWarning: The ESM module loader is experimental.

internal/modules/cjs/loader.js:1007

      internalBinding('errors').triggerUncaughtException(

                                ^

Error [ERR_REQUIRE_ESM]: Must use import to load ES Module: /home/travis/build/Palindrom/Palindrom/mocha-run.js

@tomalec Я запускаю mocha с модулями ES на узле 12.11.1:

__mocha-run.js__

(async () => {
    await import("./tests.mjs");
    run();
})();

Однако режим часов не работает. mocha ожидает изменения файла, но не запускает новый тестовый прогон после изменения файла.

@vanslly Вам повезло ;)
Для меня с Node 12.12.0 (https://travis-ci.org/Palindrom/Palindrom/builds/597771311#L450) и mocha-run.js , как вы предложили выше (https://github.com/Palindrom/ Палиндром/commit/49835962bdd61c849f115e271bbc6c3f82d30511#diff-24eabf03aee8844b2b4747aa95a6af7d),

mocha --experimental-modules --delay test/mocha-run.js https://travis-ci.org/Palindrom/Palindrom/builds/597771311#L643 , выдает ту же ошибку

Безумие, что это все еще проблема! ESM больше не прячется за --experimental-modules. Это будущее.

эээ, на самом деле это было объявлено всего пару дней назад...

Слишком поздно — мы все перешли на Jest.

Эй, ребята, просто хочу убедиться, что это сохраняется. Пожалуйста, сделайте это главным приоритетом, и спасибо за всю отличную работу!

@luijar Над этим работают в #4038

Вчера мы опубликовали экспериментальный релиз v7.0.0-esm1 : см. примечания к релизу .

Это здорово видеть!

Могу ли я спросить: означает ли отсутствие ссылки на браузер, что использование ESM недоступно в браузере или просто вам не нужно указывать версии браузера, как в случае с Node. Я думаю, что было бы полезно упомянуть в примечаниях к выпуску статус для браузеров (и, если не поддерживается, какие планы могут быть на его поддержку).

@brettz9
NodeJs ESM никак не влияет на браузер Mocha. Тесты, которые вы запускаете в своем браузере, не загружаются NodeJ, вы должны сделать это самостоятельно в своем HTML-коде.

Насколько я помню, вы должны установить для тега $# <script> type="module" атрибут type="module". Как для ваших тестовых файлов, так и для скрипта Mocha, чтобы сохранить последовательность загрузки. ESM должен был работать с браузером годами.

@juergba : да, конечно, но нужен файл экспортного дистрибутива ESM, чтобы можно было использовать, например, import mocha from '../node_modules/mocha/mocha-esm.js'; без компиляции - и для тех, кто использует компиляцию (например, чтобы иметь возможность просто использовать import mocha from 'mocha'; ), им потребуется module в package.json , чтобы сборщики могли автоматически обнаружить сборку ESM.

мокко написан на языке commonjs; мы не можем поместить поле «модуль» в package.json. Mocha будет поддерживать выполнение тестов в узле, написанном на ESM.

Если вы не хотите проводить рефакторинг для внутреннего использования ESM, вы все равно сможете использовать Rollup с его подключаемым модулем CommonJS и указать целевой файл ESM для поддержки module (например, предложения Sinon и большинство пакетов обратите внимание, что я столкнулся с jQuery, являющимся единственным другим заметным исключением, и они проводили рефакторинг для использования ESM).

Я создал пример проекта для тестирования мокко с помощью ESM. Я могу успешно провести тесты, но (_пока_) не смог запустить покрытие с nyc/istanbul. Ваша помощь будет приветствоваться.

@concatime Пока nyc не станет совместимым, вы можете использовать c8 : https://www.npmjs.com/package/c8

c8 --all --include=lib/**/*.js --reporter=lcovonly node_modules/.bin/mocha --recursive

@cedx Я обновил репозиторий шаблонов, и он работает. Аккуратный!

Мы реализовали встроенную поддержку Node ESM в Mocha v7.1.0.

Была ли эта страница полезной?
0 / 5 - 0 рейтинги