Mocha: Admite pruebas de estilo ES6 sin uso de transpilador

Creado en 18 sept. 2017  ·  75Comentarios  ·  Fuente: mochajs/mocha

requisitos previos

  • [x] Se verificó que su problema aún no se haya presentado haciendo referencia cruzada a los problemas con la etiqueta common mistake
  • [x] Se verificaron los problemas de ES de próxima generación y los problemas de sintaxis usando el mismo entorno y/o la configuración del transpilador sin Mocha para garantizar que no sea solo una función que en realidad no es compatible con el entorno en cuestión o un error en su código .
  • [x] 'Smoke probado' el código que se probará ejecutándolo fuera del conjunto de pruebas real para tener una mejor idea de si el problema está en el código bajo prueba, su uso de Mocha o Mocha en sí mismo
  • [x] Se aseguró de que no haya discrepancias entre las versiones de Mocha instaladas local y globalmente. Puedes encontrarlos con:
    node node_modules/.bin/mocha --version (Local) y mocha --version (Global). Recomendamos evitar el uso de Mocha instalado globalmente.

Descripción

Antes de comenzar, ya hay algunos temas cerrados con respecto a este tema, pero como los requisitos previos han cambiado, me gustaría comenzar un nuevo intento.

Ahora que el nodo admite la ejecución de módulos EMCAScript (sí, sé que es experimental), sería genial ver que mocha funcione junto con las definiciones de prueba mjs .

Pasos para reproducir

tengo una prueba muy simple

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

Que he guardado como test.js y test.mjs

Comportamiento esperado: Me gustaría que ambas pruebas mostraran

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

Comportamiento real: mientras que la prueba js funciona, la prueba mjs me da

- 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

Reproduce con qué frecuencia: 100%

Versiones

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

información adicional

Creo que esto podría ser que el corredor de mocha está usando commonjs y la implementación actual de nodejs no permite usar módulos ECMAScript desde un contexto commonjs.

No responda con "usar un transpilador", quiero explícitamente no usar uno.

Editar: en una versión anterior, accidentalmente usé jsx en lugar de mjs.

feature usability

Comentario más útil

Implementamos el soporte ESM nativo de Node en Mocha v7.1.0.

Todos 75 comentarios

Pensamientos iniciales en la parte superior de mi cabeza, antes de seguir investigando:

  • Me parece recordar que la gente de Node específicamente cambió el estándar para permitir la compatibilidad con versiones anteriores de los módulos CommonJS. Si eso es (¿todavía?) cierto, entonces espero que eventualmente sea compatible sin necesidad de hacer nada con/para Mocha. (Y por "eventualmente" me refiero a "posiblemente incluso más rápido que los cambios de Mocha", dada la velocidad del ciclo de lanzamiento de Node; consulte el penúltimo énfasis a continuación para obtener una explicación más detallada de esto).
  • ¿Puedo suponer que esto se ejecutó como node --experimental-modules node_modules/mocha/bin/_mocha ?
  • ¿Cómo está involucrado exactamente .jsx ? Veo que el ejemplo de error que se muestra se refiere a .mjs ; no está claro, por lo que se ha publicado, dónde está el jsx .
  • También recuerdo vagamente haber escuchado que la implementación inicial de Node requería la extensión de archivo .mjs ; si eso .jsx export .jsx import import .jsx en un archivo .mjs o cargando un archivo .jsx que contiene import / export ), ¿podría ser ese el problema en lugar de Mocha?
  • Tendríamos que idear una forma de asegurarnos de que los cambios en la función experimental no requieran cambios en Mocha que tendrían que esperar a un semestre mayor ; de lo contrario, podría terminar donde estamos ahora, excepto que esperaría aún más .
  • Hablando puramente desde mi propia opinión y no en nombre del equipo, si el nuevo formato de módulo no puede interoperar con el antiguo formato de módulo sin modificar las bibliotecas existentes escritas en el antiguo formato, entonces el nuevo formato de módulo aún no está listo .

Me parece recordar que la gente de Node específicamente cambió el estándar para permitir la compatibilidad con versiones anteriores de los módulos CommonJS. Si eso es (¿todavía?) cierto, entonces espero que eventualmente sea compatible sin necesidad de hacer nada con/para Mocha. (Y por "eventualmente" me refiero a "posiblemente incluso más rápido que los cambios de Mocha", dada la velocidad del ciclo de lanzamiento de Node; consulte el penúltimo énfasis a continuación para obtener una explicación más detallada de esto).

Según mi (pequeña) investigación, parece que al menos por ahora está permitido usar require de un módulo ECMAScript pero no import de un módulo commonjs.

¿Puedo suponer que esto se ejecutó como node --experimental-modules node_modules/mocha/bin/_mocha?
¿Cómo se involucra exactamente .jsx? Veo que el ejemplo de error que se muestra se refiere a .mjs; no está claro, por lo que se ha publicado, dónde está el jsx.

Sí, se ejecutó con --experimental-modules . jsx es un error tipográfico, quise decir mjs , actualizará la publicación inicial.

También recuerdo vagamente haber escuchado que la implementación inicial de Node requería la extensión de archivo .mjs; si eso es (¿todavía?) cierto, y si está tratando de usar la importación/exportación con un archivo .jsx (ya sea importando un archivo .jsx en un archivo .mjs o cargando un archivo .jsx que contiene la importación/exportación), ¿podría eso ser el problema en lugar de Mocha?

El problema parece ser, y podría estar perdiéndome algo aquí, que mocha usa require para cargar la prueba (esa es al menos mi suposición actual ya que no soy un experto en mocha, más bien un usuario) que luego incluye otros módulos a través import . Esto en conjunto con el primer punto explicaría el error.

Tendríamos que idear una forma de asegurarnos de que los cambios en la función experimental no requieran cambios en Mocha que tendrían que esperar a un semestre mayor; de lo contrario, podría terminar donde estamos ahora, excepto que esperaría aún más. (ya que el ciclo de lanzamiento principal de Mocha no está bloqueado a dos veces al año como el de Node).
Hablando puramente desde mi propia opinión y no en nombre del equipo, si el nuevo formato del módulo no puede interoperar con el antiguo formato del módulo sin modificar las bibliotecas existentes escritas en el antiguo formato, entonces el nuevo formato del módulo aún no está listo.

Tenía miedo de que esta fuera la respuesta y entiendo que no es una prioridad. Si mi suposición de la causa del error anterior es correcta, algo como #956 podría ayudar ya que el punto de entrada de la prueba podría ser un módulo mjs en lugar de commonjs, que probablemente sea difícil de lograr de otra manera. Parece estar en la hoja de ruta del equipo de nodejs admitir import de los módulos actuales, sin embargo, no está claro acerca de los plazos.

Según mi (pequeña) investigación, parece que al menos por ahora está permitido usar require desde un módulo ECMAScript pero no importar desde un módulo commonjs.

Parece estar en la hoja de ruta del equipo de nodejs admitir la importación desde los módulos actuales, sin embargo, no está claro acerca de los plazos.

Para aclarar: dado que en entornos "más antiguos" (en algunos casos no experimentales actuales) import es un error de sintaxis, que no se puede evitar con lógica de bifurcación o algo por el estilo, lo que necesita Mocha no es para poder usar import en sí mismo sino para poder usar require para cargar módulos que usan (o que usan módulos que usan) el nuevo formato.

jsx es un error tipográfico, quise decir mjs, actualizará la publicación inicial.

¡Gracias, eso elimina un ángulo posible!

Si mi suposición de la causa del error anterior es correcta, algo como # 956 podría ayudar, ya que el punto de entrada de la prueba podría ser un módulo mjs en lugar de commonjs, que probablemente sea difícil de lograr de otra manera.

Desafortunadamente, hacer que Mocha no cree variables globales no es posible sin una reescritura exhaustiva de algunas de las funciones internas más arcanas (lo intenté y no pude resolverlo yo mismo 😿); sin embargo, ahora es posible usar su propio punto de entrada JS a través de la API "programática" (que podría no estar documentada fuera de una página wiki antigua y los comentarios JSDoc en los archivos fuente, pero es compatible oficialmente):

// 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

En realidad, no lo he intentado para ver si hace una diferencia (primero necesito obtener la última versión de Node), pero avíseme si funciona para usted ...

En primer lugar gracias por su apoyo en esto!

probé esto

// 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);
    });
});

Básicamente, hizo que el punto de entrada del nodo fuera un módulo ECMAScript.

Lo ejecuto a través node --experimental-modules --harmony ./runner.mjs

yo obtengo

(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)

lo que Mocha necesita no es poder usar import en sí mismo, sino poder usar require para cargar módulos que usan (o que usan módulos que usan) el nuevo formato.

Me temo que actualmente no es posible en el nodo, solo puede usar require en los módulos que importó a través import . ¿Hay alguna forma de evitar mocha.addFile('./test/frontend/components/global/test.mjs'); y, en su lugar, importar la prueba y agregar el script importado de esta manera?

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

?

No hay una función como esa en Mocha en este momento, pero puedes hacer algo en ese sentido. addFile simplemente agrega el archivo a una lista que luego es require d por la función run . La función run llama a loadFiles a require :

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

Lo que querría hacer es para cualquier archivo que deba ser import ed en lugar de require d no llame a addFile (para que Mocha no intente require en run ) y, en su lugar, antes de llamar a run llama a un código que es como el que está en loadFiles pero usando import en lugar de require . No recuerdo si hay restricciones en el uso de import que impidan esto, pero si es posible, me imagino que se parecería bastante a:

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);
});

También puede ver cómo https://github.com/mochajs/mocha/blob/master/bin/_mocha usa la API programática de Mocha para tener una idea de cómo proporcionar otras opciones y cómo usar cosas como la funcionalidad de búsqueda de archivos de Mocha. No está muy bien organizado, pero todo lo que hace la interfaz de línea de comandos está allí (ya sea directamente o porque hay una llamada a las funciones en la API programática de Mocha).

Puedo dar un paso más, pero la prueba importada ahora se queja de que no sabe describir ( ReferenceError: describe is not defined ). ¿Cuál es la forma correcta de inyectarlo? Si lo hago

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

se queja TypeError: describe is not a function

Entonces, mi distribución finalmente obtuvo NodeJS 8.5, y tuve la oportunidad de jugar con esto y confirmar un par de corazonadas que tenía pero que no quería decir hasta que pude verificar:

  1. No puedo encontrar ninguna forma de cargar un módulo ES sin codificar su nombre en un archivo de secuencia de comandos/módulo. Eso significa que Mocha no puede cargarlos a través de la interfaz de línea de comandos sin importar lo que hagamos e independientemente de cualquier otra semántica de ES frente a CommonJS. Si eso cambia y cuándo, querremos saberlo, supongo. (Si cambia de tal manera que el módulo ES se puede cargar a través de una variable require , probablemente no necesitemos cambiar nada, pero no creo que podamos decir nada sobre cómo funcionan los módulos con seguridad hasta que suceda). .)
  2. Mientras que Mocha configura la interfaz en la emisión del evento pre-require (no cuando el módulo se carga por primera vez; la interfaz elegida es específica para la instancia new Mocha ), el nuevo sistema del módulo en realidad analiza el árbol de dependencia y carga las dependencias antes que los módulos que dependen de ellas, por lo que la razón por la que describe no está definido es que Mocha no lo configura hasta que se cargan los módulos de prueba. Eso significa que será complicado lograr que esto suceda (nuevamente, a menos que y hasta que require(file) esté permitido y cargue la dependencia en esa línea específica, preferiblemente sincrónicamente para que no tengamos que cambiar nada más ).

Sin embargo, descubrí que puedo hacer que funcione aprovechando el hecho de que los módulos de edición import se cargan en el orden de las llamadas a import . (Sería mucho más redundante si usa la interfaz de Exportaciones o un reportero que necesita el nombre de cada archivo individual, como se describe en el código que estoy a punto de vincular, pero en principio funciona). Si ese hecho fuera cambiar sin que cambie ninguno de los otros hechos anteriores, incluso esto no sería posible en absoluto. Pero por ahora creo que esto es lo que tendrías que hacer.

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

node --experimental-modules ./run.mjs

Desafortunadamente, estoy bastante seguro de que es lo mejor que podemos hacer dada la forma en que funcionan los módulos ES y lo que permite Node en este momento.

Piénsalo de otra manera:

  • import es sintaxis.
  • require es una función.

No puede import dinámicamente nada, al igual que no puede ejecutar código dinámicamente sin el uso de, por ejemplo, eval() .

Existe esta propuesta de etapa 3 que permitiría este comportamiento, pero no estoy seguro de si algún tiempo de ejecución lo está enviando todavía.

Como tal, Mocha no puede importar un archivo .mjs cuando se ejecuta a través mocha sin agregar quizás @std/esm y usar su implementación require para archivos con .mjs extensión. Esa puede ser una solución viable y algo que podríamos considerar apoyar, pero es probable que una discusión (y tal PR) deba provenir de la comunidad, al menos hasta que este comportamiento no esté detrás de una bandera.

import describe from 'mocha' está bastante bajo en la lista de prioridades, desafortunadamente, debido a la dificultad inherente a este tipo de cosas (#956). Lo mejor es correr con node y seguir consumiendo los globales.

En realidad, se me ocurre que podríamos cargar las pruebas y aprovechar vm.runInContext , suponiendo que tal cosa admita módulos. Debido a que el comportamiento de carga de Node está vinculado a la extensión .mjs , y vm.runInContext espera una cadena , no veo cómo podría hacerlo, y no se menciona nada al respecto en los documentos. ¿Quizás un problema en alguna parte?

(por otra parte, ¡esto puede ser exactamente lo que hace @std/esm bajo el capó!)

Tengo pruebas de mocha que funcionan sin transpiler en un navegador . Tal vez ayude para este problema.

eso no está relacionado ya que no estás incorporando mocha como un módulo, sino como un script...

lo siento me confundí. es diferente en un navegador.

Quiero opinar con un voto de apoyo por hacer algo para permitir que Mocha ejecute pruebas ubicadas en un Módulo ES. Aterricé aquí después de intentar escribir una prueba de este tipo y obtener un error raro del cargador de módulos de Node.js. Estoy usando Node.js 9.5, que admite módulos ES6 de forma nativa.

Tal como está actualmente, Node.js 9.5 no permite que un módulo CommonJS requiera () un módulo ES6. Tal vez están trabajando en la dirección de permitir eso, no lo sé.

Escribí la prueba como un módulo ES6 con la extensión .mjs e intenté ejecutarlo. Recibí el error del cargador: supongo que el comando mocha da como resultado el uso require() y es por eso que falló.

Rehizo la prueba con la extensión .js e intentó usar require() para cargar el módulo que se iba a probar. Eso también recibió el error del cargador.

Soy de la opinión de que el mundo de Node.js debe considerar cómo se trasladarán a los módulos ES6 y los admitirán. Dado que Mocha es una herramienta muy popular en este mundo, sería mejor que el equipo de Mocha considerara cómo admitir módulos ES6.

Para seguir ... Después de reflexionar y buscar, pude hacer que esta secuencia funcionara como una solución.

Asigne un nombre al script de prueba con la extensión .js (lo que lo convierte en un script CommonJS)

Luego agregue esto en el script de prueba:

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

Entonces puedo require() un módulo ES así:

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

@robogeek O podría ser aún mejor usar el precargador @std/esm desde la línea de comandos, para que no tenga que saturar sus archivos de especificaciones con soluciones alternativas y pueda tener extensiones .mjs .

mocha -r @std/esm spec.mjs

La importación dinámica se envía con el nodo v9.6 detrás de la marca --harmony-dynamic-import . Las importaciones dinámicas permiten que mocha cargue las pruebas contenidas en los módulos es6 sin necesidad de un transpilador.

@harrysarson No va a funcionar de inmediato. Mocha usa módulos cjs y require , tendrías que escribir los archivos de prueba usando cjs, con algún código adicional para manejar la naturaleza asíncrona de import . ¿O me estoy perdiendo algo?

Soy un bot que vigila problemas por inactividad.
Este problema no ha tenido actividad reciente y lo estoy etiquetando como stale . En 14 días, si no hay más comentarios o actividad, cerraré este tema.
¡Gracias por contribuir a Mocha!

El problema sigue siendo relevante, pero depende del soporte nativo para ESM. Los navegadores lo tienen, Node aún no.

Estaba jugando, familiarizándome con ESM/.mjs y decidí que necesitaba pruebas para mi juguete. Al darme cuenta de que mocha aún no es compatible oficialmente con archivos .mjs , analicé juntos un módulo provisional rápido (hasta que alguien tenga tiempo de agregar soporte completo a mocha):

https://www.npmjs.com/package/mocha-esm
Relaciones públicas/Problemas bienvenidos: https://github.com/stefanpenner/mocha-esm

Puede que haya algo mejor por ahí, pero fue divertido hacerlo juntos. entonces \o/

Decidí bifurcar mocha en sí mismo para admitir importaciones dinámicas (basado en algunas ideas anteriores, pero no pude hacer que se ejecutara de otra manera).

Esto significa que puede ejecutar usando, por ejemplo node --experimental-modules --harmony-dynamic-import test.mjs

Luego en 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);
  });
});

Mantuve los cambios en mocha para admitir este mínimo , y no tuve tiempo de integrar esto correctamente para un PR potencial ni agregué un módulo npm especializado, pero puede instalar esta bifurcación desde github directamente "mocha": "git+https://[email protected]/odolha/mocha" .

Tenga en cuenta que puede usar este enfoque para cargar archivos de cualquier manera asincrónica que desee, no solo a través de la importación dinámica, ya que mocha espera una función que proporcione una Promesa.

EDITAR

Olvidé mencionar que sus pruebas no pueden ser scripts puros con este enfoque, porque no podemos inyectar contexto, por lo que deberá:

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

@odolha
Gracias por vincular tu fork.
Ya había un PR para admitir ESM nativo , pero se cerró porque el soporte del módulo aún es experimental.

Su implementación me consuela que agregar soporte para esto debería ser fácil. Somos muchos los que esperamos con ansias esta función :)

@demurgos :no_mouth: sí... Acabo de ver ese PR después de hacer lo mío, d'oh 😃.

@harrysarson @boneskull
El paquete esm (anteriormente denominado @std/esm ) dejó de admitir archivos .mjs en esta confirmación .
Significa que ya no es posible usarlo con Mocha para probar archivos .mjs . Esto se discute en este número .

Todavía quiero poder probar los módulos ES para poder ejecutarlos de manera segura en Node o navegadores.

Con respecto a las discusiones del módulo actual, hay consenso en que .mjs debería estar disponible en el resultado final (quizás no como la única solución, pero al menos disponible) y que import("./foo.mjs") devolverá una promesa para el espacio de nombres ES correspondiente. El hecho de que los módulos CJS se conviertan en un módulo con una exportación de default correspondiente a module.exports es más debatido, pero parece ser una suposición segura.

¿Sería posible reconsiderar la adición de soporte ES nativo usando import dinámicos a Mocha? El indicador de función podría cambiarse de nombre a --experimental-es-modules (de #3253) para señalar mejor que esto depende del avance actual del soporte de Node.
De acuerdo con los plazos, la especificación final no llegaría hasta el Nodo 12, por lo que la implementación actual permanecerá allí durante algún tiempo (y es un subconjunto relativamente seguro de la propuesta final).

@demurgos Personalmente, prefiero esperar un poco más antes de comprometerme con cualquier implementación de código en mocha. ¿Pero tal vez @boneskull o @ScottFreeCode no están de acuerdo?

@demurgos

El paquete esm (anteriormente llamado @std/esm) dejó de admitir archivos .mjs en esta confirmación.

El cargador esm no eliminó el soporte para .mjs . Simplemente seguimos la implementación actual --experimental-modules y arrojamos un error al intentar cargar .mjs con require . Los usuarios aún pueden usar un archivo .js para su archivo de entrada de prueba que usa sintaxis ESM o import() dinámico para cargar archivos de prueba subsiguientes de .mjs o .js , mucho como lo hace esm para sus propias pruebas .

De acuerdo con los plazos, la especificación final no llegaría hasta el Nodo 12, por lo que la implementación actual permanecerá allí durante algún tiempo.

No hay un tiempo establecido para que --experimental-modules aterricen sin bandera. La esperanza es que pueda aterrizar en algún momento del ciclo de soporte del Nodo 10 _(en algún momento en los próximos 2 años)_ pero no hay nada escrito en piedra.

(y es un subconjunto relativamente seguro de la propuesta final).

La implementación actual --experimental-modules puede no ser compatible con la propuesta final. Hay varias discusiones sobre cómo se verá el soporte de ESM en Node. Algunas direcciones propuestas no son compatibles con la implementación experimental actual. Dependiendo de cómo se desarrollen las cosas, es posible que el código que escriba hoy por --experimental-modules no funcione con la forma final que sea.

El cargador esm no eliminó la compatibilidad con .mjs.

Mi punto es que esm ya no permite requerir .mjs por lo que ya no puede usar el descubrimiento de prueba de Mocha para .mjs . Pero tiene razón, no estaba documentado, por lo que no es realmente un cambio importante, incluso si otras personas confiaron en él.

En cuanto a los plazos, me refería a este tema . Parece que hay un intento para el Nodo 11 y una implementación final para el Nodo 12 para que pueda migrarse al Nodo 10 LTS. Algunos desearían que sucediera antes, otros advirtieron que no se apresure.

Mi propuesta es fusionar #3253. Esto solo ofrece un mecanismo de suscripción para usar import(...) en lugar de require para cargar los casos de prueba. Dado que espero que se aplique principalmente por .mjs en el contexto de --experimental-modules , sigo pensando que es seguro. (Es probable que se mantenga la importación dinámica de .mjs que devuelve una promesa de espacio de nombres). Pero te dejaré decidir si puedes fusionarlo y evitar presionar demasiado.

Nuevamente, la razón principal de este PR es que sin él, ya no puede usar el descubrimiento de prueba de Mocha, sino que tiene que usar la solución alternativa descrita anteriormente por @jdalton. ( .js punto de entrada e importaciones manuales)

Mi propuesta es fusionar #3253.

3253 tenía algunas fallas, definitivamente no es una buena idea fusionarlo tal como está.

Siguiendo el ejemplo de @jdalton , configuré un pequeño flujo de trabajo para probar ESM nativo sin el paquete esm (nodo puro + Mocha).
Uso definiciones de prueba asincrónicas (usando --delay ) y --experimental-modules .

Actualmente, _mocha_ solo puede importar CJS, y CJS solo puede importar ESM usando la pseudofunción dinámica import() . Entonces genero el siguiente punto de entrada CJS (su nombre termina con .js ) que importa los archivos de especificaciones y activa la ejecución de la prueba:

prueba.esm.js :

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

(Yo genero el punto de entrada con la lista de importaciones en el momento de la compilación, pero puede escribirlo manualmente o usar glob allí).

Luego lo ejecuto con el siguiente comando:

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

Tengo que pasar por NODE_OPTIONS porque mocha no reconoce la bandera.


Todavía espero que mocha brinde un mejor soporte para ESM experimental, pero al menos es bueno saber que hay una manera de usarlo hoy sin otras herramientas.

@demurgos, esta es una buena solución que has encontrado :+1:.

Es bueno ver que de hecho es posible (si no fácil) usar módulos es con mocha : smile:.

@demurgos Este problema se trata de admitir pruebas de estilo ES6 sin el uso de transpiler . ¿Qué es el "tiempo de construcción"? Ese código que usa para generar los puntos de entrada de prueba es un transpilador, solo uno especializado.

@rulatir
Mencioné que utilizo herramientas de compilación, pero no son del nivel discutido en este problema: Mocha se ejecuta con ESM nativo, no ESM reducido a CJS por un transpiler.

Mira mi mensaje:

Genero el punto de entrada con la lista de importaciones en el momento de la compilación, pero puede escribirlo manualmente o usar glob allí.

Usé un paso de compilación porque quiero que mis importaciones (1) estén definidas estáticamente y (2) no mantengan la lista yo mismo.

Si solo tiene unos pocos archivos de especificaciones, descartar (2) está bien: solo tenga un punto de entrada importando sus 1-2 archivos de especificaciones.
(1) ya es un requisito específico para los archivos de prueba, por lo que en su mayoría es algo "bueno de tener" y puede usar glob en tiempo de ejecución (en lugar de tiempo de compilación como yo). Este es solo un detalle que al final no importa una vez que comprende la idea central.

Si solo desea algo como una solución simple de copiar y pegar para encontrar los archivos de especificaciones mjs en tiempo de ejecución, aquí hay un ejemplo:

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

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

Ejecútelo con NODE_OPTIONS="--experimental-modules" mocha --delay test.esm.js .
Como puede ver, no hay construcción en absoluto, pero hay un poco más de ruido en el código.

Soy un bot que vigila problemas por inactividad.
Este problema no ha tenido actividad reciente y lo estoy etiquetando como stale . En 14 días, si no hay más comentarios o actividad, cerraré este tema.
¡Gracias por contribuir a Mocha!

Este problema sigue siendo válido y no debe cerrarse.

El próximo lanzamiento mocha@6 tendrá el indicador de lista blanca --experimental-modules que permitirá experimentar con módulos ES6 más fácilmente. ¿Sería posible tener una versión menor o un parche antes de la v6? Actualmente estoy finalizando una nueva herramienta de cobertura que usa el depurador V8 en lugar de Istanbul y me gustaría probarlo con los módulos Mocha y ES6 (sin tener que usar una dependencia de git en mi paquete.json).

@demurgos

Cuando intento así...

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

yo obtengo

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

Pero cuando corro así...

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

Funciona perfecto, ¿qué me estoy perdiendo?

@demurgos debe coordinarse con @bcoe; ver https://github.com/bcoe/c8

@demurgos para editar una versión menor, tendríamos que seleccionar todos los cambios no importantes desde v5.2.0 en una rama y compilarlos en CHANGELOG. si usted u otra persona está dispuesto a hacer ese trabajo, entonces podemos cancelar el lanzamiento.

fwiw, recomiendo esm sobre --experimental-modules hasta que Node.js tenga su historia clara. será una espera considerable.

@boneskull
Jaja gracias. Ya estoy trabajando alrededor c8 desde julio (abrí un montón de relaciones públicas y problemas en este repositorio). También hay algunas decisiones de diseño en las que no estamos de acuerdo, así que tratamos de compartir la mayoría de las dependencias (escribí el algoritmo de combinación, por ejemplo) y decidimos publicar otra herramienta: c88 . Lo hice funcionar este fin de semana y ahora lo estoy probando en mis bibliotecas. Puedo usarlo con ESM nativo y mocha en CI. Todavía necesito algo de tiempo para documentarlo y arreglarlo, pero debería estar listo en enero).

@jrgleason
Escribí el código arriba de la parte superior de mi cabeza. Parece que el problema aquí es que globSync devuelve rutas relativas que no comienzan con ./ o ../ . Es posible que desee anteponerlo con ./ : debería funcionar con rutas relativas simples.
También debe tener en cuenta que las importaciones dinámicas usan URL relativas: # , ? y otros caracteres especiales pueden manejarse de manera diferente. Si desea una solución sólida como una roca, debe resolver la ruta absoluta del módulo y luego convertirla en una URL de archivo. Como parte de mi trabajo en la cobertura, escribí una biblioteca para convertir entre rutas absolutas y URL: es posible que desee usar fromSysPath de furi . Las conversiones deben manejar cualquier tipo de ruta (incluso los espacios de nombres de Windows y las rutas UNC...).

Así es como se vería un ejemplo completo:

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();
})();

Quiero decir, ¿no funciona mocha --require esm ? ¿Realmente necesitamos detección automática? Eso suena difícil y agrega gastos generales...

@demurgos para editar una versión menor, tendríamos que seleccionar todos los cambios no importantes desde v5.2.0 en una rama y compilarlos en CHANGELOG. si usted u otra persona está dispuesto a hacer ese trabajo, entonces podemos cancelar el lanzamiento.

Gracias por la propuesta. Todavía es posible obtener --experimental-modules con NODE_OPTIONS , por lo que no es una prioridad alta (y puede complicar el árbol git para seleccionar confirmaciones). Si logro cerrar los problemas que tengo con otras dependencias, veré si puedo dedicarle algo de tiempo. Mientras tanto, solo vigilo el hito v6.

Por cierto, recomiendo esm sobre --experimental-modules hasta que Node.js tenga su historia clara. será una espera considerable.
Quiero decir, ¿no funciona mocha --require esm?

Definitivamente estoy de acuerdo en que es la mejor solución en este momento: es la solución más fácil de configurar y ha estado disponible durante algún tiempo: funciona. En mi caso, mantengo mis propias herramientas de compilación y manejo ESM nativo como alternativa a las compilaciones clásicas de CJS. A pesar de estar realmente ansioso por ESM nativo, sigo recomendando no usarlo como la única forma de ejecutar su código: después de todo, es experimental :stuck_out_ tongue:.

La mayoría de mis mensajes recientes tratan sobre compartir lo que se puede hacer con ESM nativo. Este es principalmente un trabajo experimental y espero tener que cambiarlo cuando el ESM de Node se estabilice. A largo plazo, hay beneficios de tener una solución que no requiere el paquete esm . Aquí están mis razones:

  • Reduce la cantidad de herramientas necesarias (menor complejidad, menos configuración para entender)
  • Puede haber algunas diferencias entre el ESM real y esm en casos extremos (errores de evaluación, ciclos, errores de carga, módulos asíncronos/dinámicos, wasm, etc.). Al escribir código isomorfo, puede ser más seguro reducir cualquier fuente posible de divergencia de comportamiento. Esto también está un poco relacionado con la cobertura nativa: con esm , V8 ve la salida transpilada, por lo que debe lidiar con los mapas de origen (aún no es compatible con c8 , pero estoy preparando una PR, trabajan en c88 ). También pueden aparecer otras diferencias durante la depuración.
  • Evita tener que transpilar dinámicamente el código y ayuda a mejorar el rendimiento.

¿Realmente necesitamos detección automática? Eso suena difícil y agrega gastos generales...

No estoy seguro de a qué detección automática te refieres. ¿Tiene relación con el PR que se envió a principios de este año?


Editar : también estoy en el Slack de herramientas de Nodo (principalmente activo en el canal #c8 ) si desea discutirlo.

@demurgos Creo que estaba un poco confundido sobre lo que la gente quería aquí. De todos modos...

Si NODE_OPTIONS=--experimental-modules funciona hasta que --experimental-modules sea compatible con Mocha v6.0.0, ¿hay algún otro trabajo por hacer para este problema? Eso es lo que me falta.

Espero que este problema permanezca abierto hasta que ESM nativo ("Pruebas de estilo ES6 sin uso de transpiler") funcione de manera inmediata / tan fácilmente como funciona CJS actualmente.

La solución que publiqué con --delay y NODE_OPTIONS=--experimental-modules es más una solución alternativa que un soporte adecuado. Consideraría que este problema se solucionó una vez que pueda ejecutar mocha **/*.spec.mjs y obtener un informe.

Desafortunadamente, por el momento siento que todavía tenemos que esperar a que Node descubra el soporte de ESM. Tendría que verificar, pero creo que el PR no usó la detección automática, sino que simplemente importó todos los módulos (CJS o ESM) usando importaciones dinámicas. La implementación dependerá de la historia de interoperabilidad de los módulos.


Editar : me refiero a https://github.com/mochajs/mocha/pull/3253. Permite cargar todos los módulos como ESM (sin detección automática).

Soy un bot que vigila problemas por inactividad.
Este problema no ha tenido actividad reciente y lo estoy etiquetando como stale . En 14 días, si no hay más comentarios o actividad, cerraré este tema.
¡Gracias por contribuir a Mocha!

El nodo 12 debe incluir la nueva implementación de ESM. Será la ocasión de comprobar cómo se soportan los módulos ES en Mocha.

Encontré un error de GC al usar Mocha un ESM, pero se informa y se confirma, por lo que debería corregirse: https://github.com/nodejs/node/issues/27492.

Además de este error, la estrategia descrita en mi comentario anterior todavía funciona para usar Mocha con ESM.

Hola gente de Mocha, ¡gracias por crear y mantener una buena herramienta!

Este es solo un comentario FYI. Durante los últimos meses he estado trabajando en Mocha y * -test.mjs , usando parches como los que se muestran a continuación. Casi no hay problema para ejecutar mocha test/*.mjs (sin transpiler o módulo esm npm).
https://gist.github.com/tadd/756d21bad38933c179f10e59bddee6b4

Por supuesto, este parche no está "listo para producción" para los usuarios de Mocha; esto es solo un truco para los usuarios de Mocha que desean usar ESM en códigos de prueba lo antes posible.
He usado Node.js v11 con la opción --experimental-modules . Actualmente estoy con v12 y también funciona.

Es otra historia, pero Node v12 introdujo la extensión .cjs y el campo "type" en package.json . Parece que estos también deben ser considerados.

Hola gente de Mocha, ¡gracias por crear y mantener una buena herramienta!

De hecho, y también me gustaría dar las gracias 😄

Tomé un enfoque diferente para hacer que loadFiles permanezca sincrónico, vea a continuación. Me ha funcionado desde febrero. A diferencia de otros hacks, esto aún permite todas las banderas, herramientas de inspección/desarrollo y una cobertura de código precisa usando c8 . Esa última característica es la razón por la que realmente necesito ESM nativo, porque el paquete esm tiene diferentes compensaciones para cada archivo. (Las exportaciones del módulo se enumeran y confunden a Estambul).

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

¡Hola! Esto también es necesario para probar cualquier código que dependa del proyecto ES6 nativo, por ejemplo, lit-element . De lo contrario, arroja así:

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)
    ...

No sé si hay una solución para esto, pero actualmente no creo que haya una forma de usar Mocha con el marco nativo ES6.

@heruan Publiqué una solución que funciona desde el Nodo 8 en los comentarios anteriores. Aquí hay una versión actualizada que requiere el Nodo 10.12 para las conversiones de URL de archivos nativos:

Agregue el siguiente archivo 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();
})();

Luego ejecute las pruebas con mocha --experimental-modules --delay test.esm.js .

Este código funciona usando test.esm.js como puente commonjs para cargar las pruebas de ESM.

El nodo 12 tiene un problema informado donde el IIAFE es recopilado por el GC (nodejs/node#27492), debe solucionarse en una de las siguientes versiones menores (puede haber algunas soluciones, pero aún no las he investigado). Recomiendo usar la última versión de Node 10 hasta que se solucione.

Thar activará una advertencia UnhandledPromiseRejectionWarning si hay algún error. Es mejor encadenar un console.error o manejar el error de otra manera.

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)

_Sé que esto está usando import en lugar require , pero vea mi idea general para encontrar una solución que le permita permanecer en ESM land_

@demurgos ¡ Gracias por el fragmento de código para Node 10.12 que publicaste hace diez días!

Estoy ejecutando Node 12.1 y parece funcionar bien. ¿Se agregará esto pronto a Mocha, o hay una manera aún más fácil de hacerlo con Node 12? Además, ¿cómo uso esto en modo --watch ?

https://github.com/standard-things/esm parece funcionar de inmediato con --require esm , pero sería genial deshacerse de otra dependencia :) Gracias.

Si Mocha cambiara a ESM en la fuente, Rollup podría proporcionar un archivo de distribución ESM, así como CommonJS y/o UMD.

Otra ventaja aquí es que el HTML del navegador no necesitaría estar contaminado con etiquetas de secuencias de comandos adicionales para extraer Mocha. Los archivos de prueba (o el archivo de entrada de prueba principal) podrían realizar la importación (y evitar la "magia" dentro de los archivos de prueba en cuanto a averiguar de dónde provienen las variables, solo es necesario rastrear las rutas de importación).

También se pueden usar complementos CSS para Rollup para permitir la inyección mocha.css , minimizando aún más la necesidad de desorden HTML.

Soy un bot que vigila problemas por inactividad.
Este problema no ha tenido actividad reciente y lo estoy etiquetando como stale . En 14 días, si no hay más comentarios o actividad, cerraré este tema.
¡Gracias por contribuir a Mocha!

Creo que esto sigue siendo relevante.

¿Alguien pudo ejecutar Mocha con Módulos ES6 en (editar: ~Travis~) Nodo >=12.11.0?
Parece que en 12.10.0, lo configuré con éxito:
mocha-run.js

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

Entonces mocha --experimental-modules --delay ./mocha-run.js funciona de maravilla.

Pero por alguna razón desconocida, en 12.11.0, se comporta como si no hubiera un parámetro --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 Estoy ejecutando mocha con módulos ES en el nodo 12.11.1:

__mocha-run.js__

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

Sin embargo, el modo reloj no funciona. mocha espera cambios en el archivo, pero no ejecuta otra prueba después de que se haya cambiado un archivo.

@vanslly Suerte ;)
Para mí con Node 12.12.0 (https://travis-ci.org/Palindrom/Palindrom/builds/597771311#L450) y mocha-run.js como sugirió anteriormente (https://github.com/Palindrom/ palíndromo/commit/49835962bdd61c849f115e271bbc6c3f82d30511#diff-24eabf03aee8844b2b4747aa95a6af7d),

mocha --experimental-modules --delay test/mocha-run.js https://travis-ci.org/Palindrom/Palindrom/builds/597771311#L643 , arroja el mismo error

¡Que esto siga siendo un problema es una locura! ESM ya no está escondido detrás de --experimental-modules. Este es el futuro.

err, en realidad se acaba de anunciar hace un par de días...

Demasiado tarde, todos hemos cambiado a Jest.

Hola chicos, solo quiero asegurarme de que esto se mantenga vivo. ¡Haga de esto una prioridad máxima y gracias por todo el gran trabajo!

@luijar Esto se está trabajando en el #4038

Ayer publicamos una versión experimental v7.0.0-esm1 : ver notas de la versión .

¡Esto es genial de ver!

Sin embargo, ¿puedo preguntar si la falta de referencia al navegador significa que el uso de ESM no está disponible en el navegador o simplemente que no ha necesitado especificar las versiones del navegador como con Node. Creo que podría ayudar mencionar en las notas de la versión el estado de los navegadores (y si no son compatibles, cuáles podrían ser los planes para su compatibilidad).

@brettz9
NodeJs ESM no afecta el navegador Mocha de ninguna manera. NodeJs no carga las pruebas que ejecuta en su navegador, debe hacerlo usted mismo en su código HTML.

Si no recuerdo mal, debe configurar la etiqueta $# <script> type="module" atributo type="module". Tanto para sus archivos de prueba como para el script de Mocha, para mantener la secuencia de carga. ESM debería haber estado trabajando con el navegador durante años.

@juergba : sí, claro, pero se necesita un archivo de distribución de exportación ESM para poder usar import mocha from '../node_modules/mocha/mocha-esm.js'; sin compilación, y para aquellos que usan compilación (por ejemplo, para poder usar import mocha from 'mocha'; ), querrían module en package.json para que los empaquetadores puedan descubrir la compilación de ESM automáticamente.

mocha se escribe en commonjs; no podemos poner un campo de "módulo" en package.json. Mocha admitirá la ejecución de pruebas en el nodo escrito en ESM.

Si no desea refactorizar para usar ESM internamente, aún debería poder usar Rollup con su complemento CommonJS e indicar el archivo de destino de ESM para admitir module (como las ofertas de Sinon y la mayoría de los paquetes de nota que he encontrado, jQuery es la única otra excepción notable y han estado refactorizando para usar ESM).

Creé un proyecto de muestra para probar mocha con ESM. Puedo ejecutar las pruebas con éxito, pero (_todavía_) no pude ejecutar la cobertura con nyc/istanbul. Su ayuda será bienvenida.

@concatime Hasta que nyc sea compatible, puede usar c8 : https://www.npmjs.com/package/c8

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

@cedx Actualicé mi repositorio de plantilla y funciona. ¡Limpio!

Implementamos el soporte ESM nativo de Node en Mocha v7.1.0.

¿Fue útil esta página
0 / 5 - 0 calificaciones

Temas relacionados

delta62 picture delta62  ·  3Comentarios

smithamax picture smithamax  ·  4Comentarios

eschwartz picture eschwartz  ·  3Comentarios

wzup picture wzup  ·  3Comentarios

robertherber picture robertherber  ·  3Comentarios