Jest: Meta: soporte nativo para módulos ES

Creado en 19 ene. 2020  ·  131Comentarios  ·  Fuente: facebook/jest

EDITAR: guía rápida para comenzar: https://jestjs.io/docs/en/ecmascript-modules

El soporte de ESM no estará marcado en una versión futura del Nodo 12 (tal vez no antes de abril https://github.com/nodejs/node/pull/29866#issuecomment-574055057) y ya no está marcado en el Nodo 13.2, así que creo que lo está Es hora de evaluar cómo podemos agregar soporte nativo en Jest. Intentaré enumerar qué funciones proporciona Jest actualmente que se ven afectadas por el soporte de ESM y cómo podemos resolverlas / investigarlas.

Existe el problema # 4842, pero creo que es más un tema de discusión, mientras que este problema estará orientado a la implementación real del soporte y será más adecuado para realizar un seguimiento para aquellos que solo quieren obtener el estado de implementación actual. Cualquier comentario agregado a este problema _no_ relacionado con cómo podemos implementar el soporte para las funciones enumeradas a continuación se marcará como spam; dirija cualquier solución alternativa / discusión a problemas separados. ¡También no dude en decirnos si falta algo relacionado con las funciones de ESM en la lista!

Tenga en cuenta que Jest utilizará la API vm (https://nodejs.org/api/vm.html) y, en el momento de la escritura (nodo v13.6), las partes de ESM de esta API todavía están marcadas ( --experimental-vm-modules ). Por lo tanto, decir que ESM no está etiquetado es un nombre poco apropiado en este momento. Pero creo que deberíamos empezar a experimentar y potencialmente proporcionar comentarios al Grupo de Trabajo de Módulos .

Por último, escribo este número principalmente para personas que implementarán soporte, por lo que será algo de bajo nivel y específico sobre cómo funciona Jest. Para las personas que _solo_ quieren saber si el soporte ha llegado o no, les recomiendo usar la maravillosa "notificación personalizada" de GH y suscribirse solo a las notificaciones sobre el cierre / reapertura.


  • [x] Ejecutar el módulo en el contexto correcto

Logramos sandboxes ejecutando un script dentro de un vm.Context dado (ya sea proporcionado por JSDOM o API de núcleo de nodo). Necesitamos hacer lo mismo para ESM, pero necesitaremos acceso a context durante la construcción del módulo, no solo al ejecutarlo. Abrí # 9428 que agrega las API necesarias a JestEnvironment .

  • [x] Globales

expect , test , beforeEach etc aún se agregarán como globales, nada debería cambiar aquí. jasmine global también seguirá estando aquí.

  • [x] jest propiedad "global"

Esto no es realmente global, se inyecta en el alcance del módulo. Dado que el alcance del módulo se ha ido en ESM, debemos moverlo a alguna parte. Agregarlo a import.meta parece natural; hay una opción llamada initializeImportMeta que podemos usar.

EDITAR: La solución aquí es buscarlo a través de import {jest} from '@jest/globals' . Es posible que aún lo agreguemos a través de import.meta en el futuro, pero esto debería ser suficiente por ahora.

  • [] jest.(do|un)mock

Dado que ESM tiene diferentes "etapas" al evaluar un módulo, jest.mock no funcionará para importaciones estáticas. Sin embargo, puede funcionar para importaciones dinámicas, por lo que creo que solo tenemos que ser claros en los documentos sobre lo que admite y lo que no.

jest.mock llamadas import 'thing' en import('thing') que debería permitir que el izado funcione, pero luego es asincrónico. El uso de await nivel superior es probablemente una necesidad para este enfoque. También creo que es lo suficientemente invasivo como para justificar una opción separada. Algo para discutir: no necesitamos admitir todo lo que puede jest.mock para una versión inicial.

  • [] jest.requireActual

No estoy seguro de cómo debería comportarse en ESM. ¿Deberíamos proporcionar un jest.importActual y dejar que requireActual evalúe en CJS siempre?

  • [x] import.meta

El nodo tiene url como su única propiedad (al menos por ahora). Necesitamos asegurarnos de que también esté poblado en Jest. Proporcionamos identifier lugar de filename al construir el módulo, así que no creo que suceda automáticamente, pero url es esencialmente filename pasado a través de pathToFileURL .

También hay un PR abierto por import.meta.resolve : https://github.com/nodejs/node/pull/31032

  • [x] import thing from 'thing'

En realidad, esto debería ser bastante sencillo, solo necesitamos implementar un linker donde también podemos transformar la fuente antes de devolverla, lo que significa que no necesitamos la API del cargador (que aún no existe). Esto también nos permite devolver simulacros (aunque tendrán que provenir de un directorio __mocks__ ).

  • [x] import('thing')

Esencialmente lo mismo que el anterior, pero se pasó como importModuleDynamically al construir el módulo. También admitirá jest.mock , jest.resetModules etc. de manera más limpia, por lo que es probable que se use bastante.

Esto también se puede hacer por vm.Script través de la misma opción.

  • [] Manejo de errores durante la evaluación

En este momento es un error de tiempo de ejecución (por ejemplo, módulo no encontrado), pero eso no es necesariamente cierto con ESM. ¿Importa para nosotros? Debemos verificar que los errores aún se vean bien.

  • [x] module.createRequire

Necesitamos ocuparnos de esto para las personas que quieran utilizar CJS de ESM. Abrí el # 9426 para rastrear esto por separado, ya que implementarlo no está realmente relacionado con el soporte de ESM.

EDITAR: Implementado en # 9469

  • [] module.syncBuiltinESMExports

https://nodejs.org/api/modules.html#modules_module_syncbuiltinesmexports. ¿Nos preocupamos por ello, o simplemente lo estamos convirtiendo en una operación no operativa suficiente? No estoy seguro de cuál sería el caso de uso en Jest. Jugar con los elementos integrados ya está rompiendo la caja de arena y no creo que esto deba importar.

EDITAR: # 9469 convirtió esto en una operación no operativa. Creo que eso esta bien

  • [] Detecta si se supone que un archivo está en modo ESM o CJS

Inspeccionar el campo type en el package.json un módulo parece razonable: https://nodejs.org/api/esm.html#esm_enabling. ¿Deberíamos tener también nuestra propia bandera de configuración? También debe respetar las terminaciones de los archivos.

https://github.com/nodejs/modules/issues/393

  • [x] moduleNameMapper

No estoy seguro de si esto afecta algo. _Creo_ que no, ya que enlazaremos los módulos nosotros mismos. Sin embargo, necesita investigación.

EDITAR: Esta es toda la lógica de resolución, que controlamos. Entonces no hay cambios aquí.

  • [x] jest.config.mjs

A través de # 9291 apoyamos jest.config.cjs - ¿necesitamos hacer algo especial por .mjs ? Probablemente use import('path/to/configFile.mjs') que significa que tendrá que ser asíncrono. ¿Es esto un problema? Podría valer la pena hacer la resolución de configuración async en Jest 25 para que no sea un bloqueador para el soporte incremental de ESM en Jest 25.

EDITAR: # 9431

  • [] Exportaciones de paquetes

Node admite la exportación de paquetes , que en cierto modo se asigna a moduleNameMapper Jest, pero también proporciona funciones de encapsulación. Con suerte, resolve implementará esto, pero si no es así, tendremos que hacer algo. ¿Podría ser suficiente para usar la opción pathFilter ? Inseguro.

  • [] Módulo JSON / WASM

https://nodejs.org/api/esm.html#esm_experimental_json_modules. ¿Necesitamos preocuparnos? Probablemente, especialmente por json . Es trivial para nosotros admitir import thing from './package.json' ya que controlamos la fase de vinculación, pero probablemente no deberíamos hacerlo de forma predeterminada, ya que diferirá del nodo predeterminado. ¿Deberíamos obligar a la gente a definir una transformación para ello?

  • [x] Cobertura de código

¿Importa? No creo que se vea afectado, ya que todavía podemos transformar la fuente con babel (tal vez se confunda con las declaraciones import , probablemente no) y la cobertura V8 definitivamente no debería importarle. Sin embargo, deberíamos verificar.

  • [] Resolución de código asincrónico

Esto no es absolutamente ningún bloqueador, ya que la resolución de sincronización funcionará bien. Pero ahora podemos usar la resolución asíncrona, lo cual es genial. Me pregunto si deberíamos considerar simplemente usar el módulo resolve fuera de npm nuevamente, ya que ya es compatible con async. Vea el n. ° 9505.

  • [] Transformación de código asincrónico

Similar a lo anterior, sin bloqueo, pero sería bueno admitirlo. También podría hacer que @jest/transformer más utilizable en otros entornos. Ver # 9504.

  • [] Mal rendimiento al acceder a globales

Debido a # 5163, tenemos la opción extraGlobals como solución alternativa; esa solución ya no es viable en ESM. Me abrí y emití un problema con el nodo aquí: https://github.com/nodejs/node/issues/31658

ES Modules

Comentario más útil

Obtuve un soporte muy básico con # 9772. Solo probé los casos más simples y hay muchas limitaciones conocidas (en particular, no hay soporte de objeto jest y semántica rota al mezclar CJS y ESM), pero al menos es _something_. Saldrá en el próximo lanzamiento de Jest (con suerte pronto, solo bloqueado por # 9806)

Todos 131 comentarios

Obtuve un soporte muy básico con # 9772. Solo probé los casos más simples y hay muchas limitaciones conocidas (en particular, no hay soporte de objeto jest y semántica rota al mezclar CJS y ESM), pero al menos es _something_. Saldrá en el próximo lanzamiento de Jest (con suerte pronto, solo bloqueado por # 9806)

25.4.0 ha sido lanzado con las primeras piezas de soporte. Además del # 9772 mencionado anteriormente, también he incluido el # 9842. En _teoría_, la combinación de CJS y ESM debería funcionar correctamente ahora (🤞).

La única característica principal que falta es la compatibilidad con el objeto jest . No he decidido si deberíamos ceñirlo a import.meta o pedirle a la gente que lo importe a través de import {jest} from '@jest/globals' . ¡Se agradecen los comentarios!

Todavía no he escrito documentos para esto, pero para activarlo debes hacer 3 cosas

  1. asegúrese de no ejecutar las declaraciones transform away import (establezca transform: {} en la configuración o asegúrese de que babel no transforme el archivo a CJS, como evitar el modules opción para preestablecer-env)
  2. Ejecute node@^12.16.0 || >=13.2.0 con --experimental-vm-modules bandera
  3. Ejecute su prueba con jest-environment-node o jest-environment-jsdom-sixteen

¡Pruébelo y envíenos sus comentarios! Si informa errores, sería maravilloso si también pudiera incluir cómo se ejecuta el mismo código (menos cualquier código específico de prueba) en Node. He leído https://nodejs.org/api/esm.html _mucho_ durante las últimas semanas, pero probablemente me he perdido algo.

La única característica principal que falta es admitir el objeto de broma. No he decidido si deberíamos pegarlo en import.meta o pedirle a la gente que lo importe a través de import {jest} de '@ jest / globals'.

Para el caso de uso de mecanografiado, es mejor tener una importación explícita.

Sí, agregué (y lo revertí temporalmente) un paquete @jest/globals que admite esto, por lo que estará disponible independientemente. Me pregunto si tiene sentido _también_ exponerlo en import.meta . Actualmente me inclino a no hacerlo, principalmente porque es más fácil agregar que eliminar más tarde (y personalmente no soy fanático de los globales)

+1 para la importación explícita, es un poco más detallado pero más sencillo de entender

Recibo esto en Node 13.2 & Jest 25.4: ES Modules are only supported if your test environment has the getVmContext function ¿Qué me estoy perdiendo?

@zandaqo Oh lo siento, olvidé ese punto. Agregado arriba, pero es

Ejecute sus pruebas con jest-environment-node o jest-environment-jsdom-sixteen

ReferenceError: jest is not defined Supongo que esto se debe a que faltan @jest/globals

Sí, como se mencionó, esto solo funcionará si no usa el objeto jest .
Los simulacros probablemente también estén rotos, no los he probado 😃

He compilado un proyecto muy básico de lo que veo en el directorio de pruebas de e2e ( e2e/native-esm/__tests__/native-esm.test.js ) y en este número. Y, lamentablemente, todavía no puedo hacer que funcione. ¿Alguien puede comprobarlo por casualidad?

https://drive.google.com/file/d/1vyDZjsVKOTu6j55QA11GjO9E7kM5WX8_/view?usp=sharing

  • [x] broma versión 25.4.0
  • [x] versión de nodo v13.12.0
  • [x] package.json contiene opciones de broma recomendadas y no parece haber transformaciones de babel en su lugar

Ejecutando un script de muestra (solo importando la función double e imprimiendo double(2) ):

npm run main

> [email protected] main /Users/ilya/Projects/jest-esm
> node src/main.js

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

Ejecutando broma con solo una prueba para doble función:

npm run test

> [email protected] test /Users/ilya/Projects/jest-esm
> jest

 FAIL  __tests__/native-esm.test.js
  ● Test suite failed to run

    Jest encountered an unexpected token

    This usually means that you are trying to import a file which Jest cannot parse, e.g. it's not plain JavaScript.

    By default, if Jest sees a Babel config, it will use that to transform your files, ignoring "node_modules".

    Here's what you can do:
     • To have some of your "node_modules" files transformed, you can specify a custom "transformIgnorePatterns" in your config.
     • If you need a custom transformation specify a "transform" option in your config.
     • If you simply want to mock your non-JS modules (e.g. binary assets) you can stub them out with the "moduleNameMapper" config option.

    You'll find more details and examples of these config options in the docs:
    https://jestjs.io/docs/en/configuration.html

    Details:

    /Users/ilya/Projects/jest-esm/__tests__/native-esm.test.js:8
    import {double} from '../src/index.js';
    ^^^^^^

    SyntaxError: Cannot use import statement outside a module

      at Runtime._execModule (node_modules/jest-runtime/build/index.js:1074:58)

Test Suites: 1 failed, 1 total
Tests:       0 total
Snapshots:   0 total
Time:        0.542s
Ran all test suites.

Debe ejecutar el nodo con --experimental-vm-modules y nombrar su archivo .mjs o "type": "module" en package.json .

EDITAR: Probablemente tenga este último ya que funciona fuera de Jest para usted, solo falta la bandera experimental para Node

@SimenB oh wow hay --experimental-vm-modules Y --experimental-modules . Estaba confundido por el hecho de que --experimental-modules no es necesario a partir de alguna versión del nodo 13. ¡Gracias!

TLDR: node --experimental-vm-modules node_modules/jest/bin/jest.js funciona para mí

Sí, del OP

Tenga en cuenta que Jest utilizará la API vm (https://nodejs.org/api/vm.html) y, en el momento de la escritura (nodo v13.6), las partes de ESM de esta API todavía están marcadas ( --experimental-vm-modules ). Por lo tanto, decir que ESM no está etiquetado es un nombre poco apropiado en este momento.

¡Sin embargo, es increíble que funcione para ti!

(Marcaré estos comentarios como resueltos)

@SimenB ¡ Gracias por esto! Dos problemas que estoy viendo hasta ahora.

Número 1

  • El archivo de prueba de la unidad de ESM se importa de forma predeterminada desde el archivo de ESM (se está probando fn)
  • El archivo ESM que se está probando importa de forma predeterminada desde un paquete, que exporta solo CJS
  • Resultados en error: ReferenceError: module is not defined en el archivo del paquete CJS

¿Entonces estoy pensando que esto puede no estar implementado correctamente?

Una declaración de importación puede hacer referencia a un módulo ES o un módulo CommonJS

Esto funciona bien cuando se ejecuta la aplicación. Las exportaciones con nombre de CJS solo se pueden importar mediante createRequire, pero las exportaciones predeterminadas solo se pueden importar.

Número 2

Cuando no llego al error anterior, lo hago con este:

TypeError: _vm(...).SyntheticModule is not a constructor

      at Runtime._importCoreModule (node_modules/jest-runtime/build/index.js:1198:12)

Detalles del proyecto

  • Nodo 12.14.1
  • Jest y babel-jest 25.4.0
  • Babel más reciente con targets: { node: 12 } y 2 complementos: babel-plugin-transform-import-meta y rewire-exports . (Intenté eliminar el complemento import-meta pero recibí un error que decía que lo volviera a agregar).
  • testEnvironment: "node" es prácticamente la única configuración
  • node --experimental-vm-modules node_modules/jest/bin/jest.js

Si un repositorio de reproducción sería útil, hágamelo saber.

¡Gracias @aldeed!

Examinaré el problema 1, que de hecho parece un error. EDITAR: Debería arreglarse a través de # 9850

El problema 2 necesita el nodo 12.16.0: https://nodejs.org/docs/latest-v12.x/api/vm.html#vm_class_vm_syntheticmodule

Cambiaré la verificación en Jest (ahora mismo busca vm.SourceTextModule que está disponible en más versiones, pero también necesitamos SyntheticModule ).

Confirmado que la ejecución con 12.16.0 soluciona mi problema 2. Volveré a probar el problema 1 después de que se publique esa corrección. De lo contrario, espero en el objeto jest para realizar más pruebas, y estoy de acuerdo en que debería ser importado.

¡Excelente trabajo, @SimenB! Estoy probando esto en un proyecto pequeño, pero encontré problemas con las importaciones dinámicas. Este es el error que veo:

Module status must not be unlinked or linkingError [ERR_VM_MODULE_STATUS]: Module status must not be unlinked or linking

Si elimino las importaciones dinámicas, la prueba se ejecutará (pero fallará por otras razones, por supuesto). La misma prueba está funcionando actualmente con Mocha (que envió soporte de ESM recientemente).

Si ayuda, las importaciones dinámicas en cuestión se pueden ver aquí: https://github.com/beejunk/firn.js/blob/switch-to-jest/lib/renderPage.js#L43 -L55

El archivo de prueba está aquí: https://github.com/beejunk/firn.js/blob/switch-to-jest/test/build.test.js. La versión funcional de Mocha se puede ver en la rama maestra.

Avísame si hay alguna otra información que pueda ser útil.

¡Gracias @beejunk! Me preguntaba si podría haber condiciones de carrera entre import s que importen el mismo módulo antes de que esté completamente vinculado. Parece que eso es lo que estás golpeando aquí. Arreglaré esto hoy, ¡gracias por el informe!

EDITAR: Corregido en # 9858. Copió la corrección en su repositorio:
image

¿Alguien ha logrado que esto funcione con TypeScript? node --experimental-vm-modules node_modules/jest/bin/jest.js devuelve el mismo SyntaxError: Cannot use import statement outside a module , aunque mi package.json tiene "type": "module" .

babel.config.cjs

module.exports = {
  presets: [
    '@babel/preset-typescript',
  ],
};

jest.config.cjs

module.exports = {
  testEnvironment: 'jest-environment-node',
  transform: {},
};

@dandv Básicamente, estás golpeando este caso: https://github.com/facebook/jest/pull/9772/files#r407255029

¿Podrías abrir un tema aparte? Necesitará averiguar qué hacer con las extensiones que no son js

@SimenB : # 9860. Gracias por echar un vistazo.

@aldeed @beejunk 25.5.0 ha sido lanzado con correcciones para sus problemas. Que sigan llegando informes de errores 😀

Oh, además incluye soporte para import { jest } from '@jest/globals' para aquellos de ustedes que esperan eso 👍

¡Gracias por el trabajo rápido en todo esto, @SimenB! Creo que me encontré con otro problema.

He estado experimentando con el uso de parámetros de consulta en una ruta de importación como una forma de romper la memoria caché del módulo en un servidor de desarrollo. La idea es tener un observador de archivos que detecte cambios en un componente y luego actualice la ruta de importación con un parámetro de consulta arbitrario para que el nuevo código se extraiga inmediatamente en la siguiente carga de la página sin tener que reiniciar el servidor. Esto funciona cuando se ejecuta el servidor de desarrollo. Sin embargo, Jest arroja el siguiente error:

Cannot find module '/path/to/project/components/BasePage.js?cache=0' from 'renderPage.js'

Aquí hay un ejemplo de dónde se utilizan los parámetros de consulta: https://github.com/beejunk/firn.js/blob/switch-to-jest/lib/renderPage.js#L55 -L56

Si elimino los parámetros de consulta, las pruebas pasarán, aunque no de forma coherente. Si ejecuto una sola suite (por ejemplo, npm test -- test/build.test.js ), las pruebas pasan, pero si ejecuto todas las pruebas a la vez, fallarán la mayor parte del tiempo con errores ambiguos. Todavía estoy investigando el problema con las pruebas inconsistentes, pero pensé en informar primero sobre el problema del parámetro de consulta.

Gracias por el informe @beejunk. Se supone que el # 6282 se ocupa de esto, pero también quiere pasar la consulta a los transformadores y demás, que no necesitamos aquí. Por lo tanto, podría tener sentido admitir la consulta internamente en el tiempo de ejecución por ahora, y dejar que # 6282 solo se ocupe de pasar esa consulta.

Agregué un poco de código para que el caché del módulo varíe según la consulta: https://github.com/facebook/jest/blob/d425a49bd575e7167bc786f3c4f2833589091fa1/packages/jest-runtime/src/index.ts#L330 -L334

Pero ningún código lo llama con una consulta. Creo que deberíamos poder hacer resolvePath.split('?') y todo debería funcionar.

Con respecto a los errores inconsistentes, echaré un vistazo si ese repositorio lo reproduce. No he probado el código ESM con pruebas en paralelo, solo una prueba. No estoy seguro de por qué afectaría las cosas, pero quién sabe 😀

La consulta de

Tengo un problema que creo que puede estar relacionado con esto, sin embargo, no se solucionó en 25.X .

Intentaré resumir el escenario a continuación:

  • Tienes una prueba con un script de configuración
  • Ese script de configuración requerirá un archivo dinámicamente, como en:
    { default: generator } = require(path.resolve(f))
  • Todo lo que hay dentro de f no se transpila, lo que provoca el "error inesperado de importación de identificador".

Esto también sucede si intento con import ()

Ya que mencionas la transpilación; Si tiene una configuración que transpila import a require este problema no es el lugar correcto; se trata de soporte nativo.


Dicho esto, no puede require ESM, y todavía no he podido agregar soporte para import() de CJS debido a que Node no tiene API para ello. El soporte para eso ha aterrizado en Node master, pero aún no se ha lanzado: https://github.com/nodejs/node/pull/32985. Como se puede ver en los PR de la versión vinculada, vendrá en 13.14.0 y 14.1.0. En ese punto, implementaré el soporte para él 👍

Sin embargo, debería poder usar un archivo de configuración .mjs .

@SimenB ¡ Esto es genial, parece estar funcionando en varios archivos de prueba ahora! Es un proceso para resolver las diferencias entre las importaciones de Babel y Node en cada archivo, agregar importación de bromas, etc., por lo que puedo encontrar más problemas al hacer eso en cientos de archivos de prueba.

Algunas cosas que son más preguntas:

  • lo que dijiste en tu comentario anterior sobre el soporte para import() de cjs, ¿eso también permitirá que el archivo de configuración de Jest se llame jest.config.js ? Actualmente solo funciona para mí cuando se llama jest.config.cjs y uso module.exports = (el error es TypeError [ERR_VM_DYNAMIC_IMPORT_CALLBACK_MISSING]: A dynamic import callback was not specified )
  • El nombre "@ jest / globals" no cumple la regla de eslint node/no-extraneous-import debido a que no es un paquete listado en package-lock . ¿Existe alguna razón para esta convención de nomenclatura? ¿Es posible usar jest sin @ ? Es fácil ignorar la regla, pero me lo pregunto.
  • Pregunta relacionada, ¿por qué jest global es diferente de los fns mágicos como test , describe , before , etc.? ¿Deberían importarse todos esos ahora también?
  • Cuando esto esté finalizado, ¿será posible que Jest establezca la bandera --experimental-vm-modules ? Hace que esto parezca no estándar si no solo funciona con el comando jest . Si no puede pasar banderas directamente, posiblemente pueda establecer / modificar la variable NODE_OPTIONS env?
  • Ahora parece que obtengo un error ligeramente diferente al anterior al intentar esto en un Nodo anterior, pero ninguno de los errores estaba claro de que la versión mínima del Nodo era el problema. ¿Es fácil agregar un cheque para la versión mínima con un mensaje de error más útil?

¿Eso también permitirá que el archivo de configuración de Jest se llame jest.config.js?

Puede llamarse .js si su package.json más cercano tiene type: 'module' . De lo contrario, para usar ESM en el archivo de configuración, debe llamarse .mjs . Consulte https://nodejs.org/api/esm.html#esm_enabling. Tenga en cuenta que el archivo de configuración se ejecuta fuera de Jest, por lo que no tenemos mucho control. Por el momento, no admitimos la configuración asíncrona, pero await ing una promesa exportada sería trivial, PR bienvenido 🙂 # 8357 se ha estancado.

Sin embargo, estoy muy sorprendido de que obtenga A dynamic import callback was not specified , no cargamos el archivo de configuración en una máquina virtual ... ¿Podría abrir un problema por separado?

El nombre "@ jest / globals" no cumple la regla de eslint node/no-extraneous-import debido a que no es un paquete listado en package-lock . ¿Existe alguna razón para esta convención de nomenclatura? ¿Es posible usar jest sin @ ? Es fácil ignorar la regla, pero me lo pregunto.

Debe agregar devDependency en @jest/globals . El paquete en sí es únicamente definiciones de tipos. Es un paquete separado de jest para que las definiciones de tipo funcionen correctamente y, por lo tanto, podemos generar un error si se carga fuera del tiempo de ejecución de Jest.

Actualmente no tengo ningún plan para cambiar eso, pero posiblemente podríamos desaprobar ese paquete y exportar los tipos de jest . Sin embargo, ese es un cambio importante, así que veamos más adelante 🙂

Pregunta relacionada, ¿por qué jest global es diferente de los fns mágicos como test , describe , before , etc.? ¿Deberían importarse todos esos ahora también?

jest es como require o module objeto de CJS en que es único por archivo, en realidad no es global (es decir, globalThis.jest === undefined ). Eso permite que jest.mock('../../file.js') etc. funcione correctamente en relación con el archivo en el que se inyectó. Puede elegir importar también los globales reales, pero todavía están disponibles como globalThis.expect etc.

Cuando esto esté finalizado, ¿será posible que Jest establezca la bandera --experimental-vm-modules ?

Creo que esperaremos a que el nodo los quite la marca en lugar de configurarlos silenciosamente; están marcados por una razón, la API podría cambiar en algún momento. Podríamos agregar una opción que establezca NODE_OPTIONS , supongo, ¿no estoy seguro de si eso cambia el tiempo de ejecución actual? Independientemente, no hay planes actuales para ello.

Ahora parece que obtengo un error ligeramente diferente al anterior al intentar esto en un Nodo anterior, pero ninguno de los errores estaba claro de que la versión mínima del Nodo era el problema. ¿Es fácil agregar un cheque para la versión mínima con un mensaje de error más útil?

Sí, agregaré un mensaje de error mejor junto con algo de documentación una vez que la implementación se estabilice un poco. Dado que la implementación está protegida por una bandera experimental, no creo que nadie se tropiece con ella.

@SimenB , actualicé Jest a 25.5.2 y ahora todas las pruebas están pasando. Los parámetros de consulta funcionan y los errores intermitentes que veía antes ya no ocurren. ¡Gracias de nuevo por todo su trabajo!

De acuerdo, vi los errores nuevamente en mi última ejecución de las pruebas, por lo que todavía está sucediendo. Veré si puedo encontrar una manera de reproducir e informar consistentemente.

Creo que he encontrado una forma coherente de reproducir el problema. Aquí está la rama desde la que estoy trabajando: https://github.com/beejunk/firn.js/tree/switch-to-jest

Reproducir:

  1. Elimina la caché de Jest si existe. Acabo de eliminar manualmente /tmp/jest_rs .
  2. Ejecute npm test tres veces. Las dos primeras ejecuciones deberían realizarse correctamente. Sin embargo, la tercera ejecución debería fallar.

Este es el seguimiento de la pila que veo cuando ocurre el error:

    Error: 
        at invariant (/home/brian/Projects/firn.js/node_modules/jest-runtime/build/index.js:1866:11)
        at Runtime.loadEsmModule (/home/brian/Projects/firn.js/node_modules/jest-runtime/build/index.js:480:7)
        at Runtime.linkModules (/home/brian/Projects/firn.js/node_modules/jest-runtime/build/index.js:548:19)
        at importModuleDynamicallyWrapper (internal/vm/module.js:397:21)
        at htmPreactPath (internal/process/esm_loader.js:31:14)
        at renderPage (/home/brian/Projects/firn.js/lib/renderPage.js:53:15)
        at map (/home/brian/Projects/firn.js/lib/build.js:43:12)
        at Array.map (<anonymous>)
        at build (/home/brian/Projects/firn.js/lib/build.js:36:43)
        at Object.<anonymous> (/home/brian/Projects/firn.js/test/build.test.js:57:5)

El error parece tener su origen en las importaciones dinámicas. No hay mensaje de error, así que no estoy completamente seguro de lo que está sucediendo.

Una nota adicional: si borro el caché de Jest y actualizo el script de prueba agregando --no-cache , entonces no puedo reproducir el problema.

Je, fui vago allí y no proporcioné un mensaje de error adecuado. El problema es que el entorno de prueba ha sido derribado, así que supongo que falta un await alguna parte. Sin embargo, no vi nada al revisar su código, así que tendré que investigar un poco más.

@SimenB Aquí hay una reproducción de ese problema de configuración de ESM: https://github.com/facebook/jest/issues/9935

@SimenB He creado un ejemplo mínimo para reproducir los errores de Jest que mencioné anteriormente al usar importaciones dinámicas:

https://github.com/beejunk/jest-esm-dynamic-import-error

¡Gracias por la gran reproducción @beejunk! He pasado más horas de las que me gustaría admitir aquí, sin entender realmente si es un error en Jest o en Node. Reproduje el comportamiento utilizando únicamente módulos de núcleo de nodo y lo informé en sentido ascendente, así que veamos lo que dicen: https://github.com/nodejs/node/issues/33216

Gracias por investigarlo, @SimenB. Las pruebas parecen pasar consistentemente si agrego la bandera --no-cache , que está bien para mi caso de uso. ¡Aprecio todo el trabajo!

Sí, también me di cuenta de eso. Creo que es una especie de problema de tiempo: sin caché, las cosas son lo suficientemente lentas como para funcionar.

@SimenB Gracias por resolver # 9935. Mencioné una segunda preocupación allí, que creo que sigue siendo válida. Cuando type: "module" , jest --init todavía está generando el archivo de configuración con module.exports en él. Esto es relativamente menor para cambiarlo manualmente si sabe lo que está haciendo, pero creo que si ESM no está marcado en Node y mucha gente comienza a hacer proyectos de ESM, comenzará a parecerse más a un error confuso (es decir, un camino feliz de jest --init && jest en un nuevo proyecto de ESM arrojará un error). ¿Debo enviar un problema diferente específicamente sobre cómo mejorar la lógica de inicio?

@aldeed, ¿estás seguro? La prueba ahora me da un archivo mjs con export default en él. Supongo que podríamos generar js y no mjs , pero aún así. Utiliza la sintaxis de ESM

@SimenB Bueno, estaba seguro hasta que me preguntaste. 😄Lo intenté y tienes razón. ¿Quizás inicialmente lo hice con una versión anterior de Node o Jest? Indiferencia.

¡Esto es asombroso! Acabo de reelaborar las pruebas en una de mis bibliotecas para usar módulos ES y abandoné Babel. ¡Gracias @SimenB!

Detectar si se supone que un archivo está en modo ESM o CJS

Hablando de esto, hay muchos paquetes orientados al navegador / agrupador que utilizan la sintaxis "module":"<path to es module>" para indicar sus exportaciones de módulos ES. Puede ser prudente tener alguna forma de especificar cómo resolver un paquete dado independientemente de la configuración del paquete. Algo como moduleNameMapper pero para especificar si es CJS o ESM.

hola @SimenB , una vez que se resuelva este problema, significa que ts-jest también puede anular commonjs ¿verdad? ¿Se requiere la extensión de archivo para cambiar del lado del transformador para trabajar con esm?

Por ejemplo, ahora ts-jest compila ts a js para commonjs , ¿ esm requiere la extensión de archivo mjs al compilar desde ts a js ?

@zandaqo no modules , seguiremos las especificaciones del nodo y usaremos exports : # 9771. Sin embargo, puede conectar su propio resolutor para admitir modules si lo desea: https://jestjs.io/docs/en/configuration#resolver -string. Podríamos agregar alguna otra opción ( mainFields , como paquete web tal vez?), Pero eso vendrá más adelante cuando la implementación se estabilice y tengamos menos incógnitas desconocidas 🙂


@ahnpnl # 9860

¡Ciao chicos!
Solo una pregunta: la publicación del blog menciona que, dado que los módulos ES6 son estáticos, no se pueden burlar de ellos; entonces, en realidad, ¿no hay forma de simular un módulo A importado por un módulo B en ES6?

@gabrieledarrigo Yo uso moduleNameMapper para eso, por ejemplo:

    "moduleNameMapper": {
      "moduleA": "<rootDir>/test/moduleA-mock.js"
    },

@gabrieledarrigo puedes hacer

jest.mock('the-thing-i-want-to-mock', () => /* do whatever in here */);

let importedThing;

beforeAll(async () => {
  importedThing = await import('thing-that-imports-mocked-module');
});

Por lo tanto, solo necesita hacer que la importación no sea estática y la burla funcionará.

Sin embargo, no estoy seguro de que funcione ahora, ya que todavía no he conectado resoluciones simuladas en la ruta del código ESM. Lo haré pronto en algún momento. Pero esa es _probablemente_ la forma en que documentamos las simulaciones de módulos para el ESM nativo.

Como se mencionó en los blogs, estaremos documentando estos patrones en algún momento, solo tenemos que resolverlos 🙂

Una idea que teníamos fue esperar a que el nivel superior aguarde, luego podríamos hacer esto con un complemento de babel.

@SimenB En primer lugar, gracias por el increíble trabajo aquí :)

De hecho, tengo un problema cuando me gustaría crear un entorno personalizado extendido desde jest-environment-node . Necesito importar la implementación de mi servidor allí, que está escrito como esm. Pero parece que el entorno debe definirse como cjs .
Mi pregunta es, ¿hay una opción para definir el entorno de prueba personalizado como esm para poder importar mi módulo de servidor? Gracias por cualquier consejo.

@ kuka-radovan, ¿podrías abrir una solicitud de función separada para eso?

ACTUALIZACIÓN: Este problema ahora se rastrea en https://github.com/facebook/jest/issues/10025

@SimenB Gracias por el jest.mock consejo anterior. Da la casualidad de que estoy convirtiendo algunos archivos que lo necesitan hoy. Puedo confirmar que su ejemplo funciona cuando el módulo simulado es un paquete node_modules , pero no me funciona simulando un módulo en el mismo proyecto.

He aquí un ejemplo sencillo:

// main.js
import secondary from "./secondary.js";

export default function main() {
  return secondary();
}

// secondary.js
export default function secondary() {
  return true;
}

// test.js
import { jest } from "@jest/globals";

jest.mock("./secondary.js");

let main;
let secondary;
beforeAll(async () => {
  ({ default: main } = await import("./main.js"));
  ({ default: secondary } = await import("./secondary.js"));
});

test("works", () => {
  secondary.mockReturnValueOnce(false); // TypeError: Cannot read property 'mockReturnValueOnce' of undefined
  expect(main()).toBe(false);
});

En su lugar, funciona exactamente el mismo patrón cuando "./secondary.js" es un nombre de paquete. (Creo que el paquete que probé con exportaciones CommonJS, si eso importa).

Jest 26.0.1 con nodo 12.16.3

¿Alguna idea o debería enviar un número completo por separado?

EDITAR: transform: {} en la configuración, por lo que no hay Babel en absoluto

EDITAR 2: Esto tampoco funciona:

jest.mock("./secondary.js", () => ({
  default: jest.fn()
}));

Increíble trabajo en esto.

Sin embargo, a menos que esté haciendo algo mal, todavía no parece posible usar import() en un archivo de prueba CJS.

Estoy ejecutando Jest con node --experimental-vm-modules node_modules/jest/bin/jest.js y tengo testEnvironment: 'node', transform: {} en jest.config.js . Esto está en el nodo 14.2.0.

La expresión de importación produce un error:

TypeError [ERR_VM_DYNAMIC_IMPORT_CALLBACK_MISSING]:
A dynamic import callback was not specified.

¿Es esta una limitación conocida en la actualidad? Veo que https://github.com/nodejs/node/pull/32985 ahora ha aterrizado en el Nodo 14.1.0.

Sí, todavía no he llegado a implementarlo. Probablemente lo aterrice este fin de semana.

@aldeed, ¿ podrías abrir un problema por separado? Necesito revisar y asegurarme de que las simulaciones sean parte de la resolución, y tu ejemplo parece un buen caso de prueba 🙂

@SimenB Gracias por la rápida respuesta. Estaré atento a cuando aterrice.

Viendo que import en los scripts podría revertirse debido a una regresión (https://github.com/nodejs/node/issues/33166), esperemos hasta que se resuelva

Tengo problemas al intentar usar esto con .mjs archivos de prueba. Si tengo __tests__/my-test.mjs , obtengo

$ yarn test
yarn run v1.22.4
$ node --experimental-vm-modules node_modules/jest/bin/jest.js
No tests found, exiting with code 1
Run with `--passWithNoTests` to exit with code 0
In C:\Users\Domenic\Dropbox\Programming\WIP\remember-to-eat
  1 file checked.
  testMatch: **/__tests__/**/*.[jt]s?(x), **/?(*.)+(spec|test).[tj]s?(x) - 0 matches
  testPathIgnorePatterns: \\node_modules\\ - 1 match
  testRegex:  - 0 matches
Pattern:  - 0 matches
error Command failed with exit code 1.

Si agrego

"testMatch": ["**/__tests__/**/*.mjs"]

a mi package.json, obtengo

$ yarn test
yarn run v1.22.4
$ node --experimental-vm-modules node_modules/jest/bin/jest.js
No tests found, exiting with code 1
Run with `--passWithNoTests` to exit with code 0
In C:\Users\Domenic\Dropbox\Programming\WIP\remember-to-eat
  1 file checked.
  testMatch: **/__tests__/**/*.mjs - 0 matches
  testPathIgnorePatterns: \\node_modules\\ - 1 match
  testRegex:  - 0 matches
Pattern:  - 0 matches
error Command failed with exit code 1.

Sin embargo, si elimino "testMatch" y luego cambio el nombre de mi archivo a __tests__/my-test.js , funciona.

Me gustaría poder usar extensiones .mjs de manera consistente en mi proyecto. ¿Es eso posible con Jest?

@domenic Me encontré con esto también. La solución es agregar a la configuración "moduleFileExtensions": ["js", "mjs"] (además de "testMatch" ).

Eché un vistazo, y moduleFileExtensions es realmente necesario.

Jest obtiene una lista de todos los archivos del proyecto ejecutando hasteFS.getAllFiles() aquí:

https://github.com/facebook/jest/blob/2460c059ad1dbf124466ac25c8d5ccfd74ae9f25/packages/jest-core/src/SearchSource.ts#L159 -L164

hasteFS se crea como parte de HasteMap con la siguiente configuración extensions :

https://github.com/facebook/jest/blob/2460c059ad1dbf124466ac25c8d5ccfd74ae9f25/packages/jest-runtime/src/index.ts#L291


Sin embargo, no creo que sea necesario especificar moduleFileExtensions en este caso. Ya forzamos la búsqueda de .snap , ¿deberíamos forzar también las extensiones JS conocidas? Esos son (fuera de mi cabeza) js , mjs , cjs , jsx , ts y tsx ? Hará que el rastreo sea más lento, pero no creo que tenga un gran impacto. ¿Aunque podría estar equivocado? De forma predeterminada, no debería ser mucho más lento, ya que solo cjs y mjs ya no forman parte de los patrones predeterminados, pero para las personas que tienen patrones personalizados, ¿podría ralentizar las cosas?

Sí, sería ideal si, al menos en el modo de módulos ES, .mjs simplemente funcionara, sin tener que agregar moduleFileExtensions o modificar el testMatch predeterminado.

También sería bueno si pudiera excluir los archivos .js; cuando intenté que obtuve

 Validation Error:

  moduleFileExtensions must include 'js':
  but instead received:
    ["mjs"]
  Please change your configuration to include 'js'.

Me pregunto si tiene sentido tener algún "modo ESM" que agregaría las extensiones de archivo del nodo esm y también ayudaría con la compilación en js usando esm para participar (# 9860).


Sin js algunas cosas se rompen internamente que cargamos dentro de la caja de arena (ya que usa la misma implementación require , etc.). Probablemente deberíamos arreglar eso para que el usuario no pueda rompernos.

Con respecto a la desaceleración, ya es bastante lento en proyectos grandes, pero no sé si la cantidad de extensiones impacta tanto. Pero estoy de acuerdo en que se deben agregar mjs y cjs como valores predeterminados. Especificar moduleFileExtensions: ['js'] anularía los valores predeterminados y lo aceleraría, ¿verdad? Entonces, tal vez solo documente eso como un ajuste de rendimiento.

¡Gracias por todo este trabajo! Ciertamente es asombroso. Seguí los 3 pasos ( "type": "module" en mi package.json, "testEnvironment": "jest-environment-node" en mi configuración de broma y --experimental-vm-modules en la CLI) y parece que también funciona bien 🎉

Pero luego estoy tratando de leer y usar import.meta como se describe en los documentos de Node.js (y que parece estar ya implementado a juzgar por la casilla de verificación) para crear __dirname , pero parece que import.meta está fallando:

console.log(import.meta);

SyntaxError: [PATH]/files.test.js: Support for the experimental syntax 'importMeta' isn't currently enabled (31:20):
    Add @babel/plugin-syntax-import-meta (https://git.io/vbKK6) to the 'plugins' section of your Babel config to enable parsing.

No tengo ningún babel y pensé que babel se estaba quedando atrás con este trabajo. Volveré para informar si puedo solucionarlo de alguna manera sin instalar babel.

Node.js v14.3.0, Jest v25.5.4

Encontré una solución por ahora. Como estoy ejecutando el script desde el mismo directorio donde está mi archivo en mi biblioteca , puedo hacer lo siguiente:

const __dirname = process.cwd();
const __filename = __dirname + "/files.test.js";

Seguiré este repositorio en caso de que haya alguna actualización, ¡gracias de nuevo por hacer esto!

Necesita excluirse explícitamente de Babel usando transform: {} como configuración

@SimenB Puedo confirmar que agregar transform: {} funcionó, ¡gracias! Entendí mal ese punto como "no agregar transformaciones" y no como "quitar transformaciones" como se pretendía.

Por cierto, las pruebas han pasado de 2,4 segundos a solo 1,3 segundos y siempre se sienten más rápidas.

El nodo 12 se ha lanzado con ESM sin marcar (https://nodejs.org/en/blog/release/v12.17.0/). Sin embargo, como se indica en el OP, las API que usan Jest son _not_ sin marcar

@SimenB Revisé este hilo varias veces pero todavía estoy atascado (usando el nodo 12.17).

Cuando ejecuto Jest 26.0.1, aparece este error:

Error [ERR_REQUIRE_ESM]: Must use import to load ES Module: /app/tests/setup.js
require() of ES modules is not supported.
require() of /app/tests/setup.js from /app/node_modules/@jest/transform/build/ScriptTransformer.js is an ES module file as it is a .js file whose nearest parent package.json contains "type": "module" which defines all .js files in that package scope as ES modules.
Instead rename setup.js to end in .cjs, change the requiring code to use import(), or remove "type": "module" from /app/package.json.

Tengo transform: {}, y estoy corriendo con node --experimental-vm-modules node_modules/jest/bin/jest.js .

¿Qué me estoy perdiendo?

@aldarund no estoy seguro, ¿podrías armar una reproducción mínima?

@SimenB aquí hay un repositorio mínimo para reproducir, simplemente ejecute yarn test https://github.com/aledalgrande/jest-example - Lo intenté con el Nodo 13/14 y es el mismo resultado. Me parece que el flujo de la configuración global no se ha actualizado para que funcione con ESM.

también, mencionaste a alguien más 😆

~ No @simenB , pero @aledalgrande , parece que todo está correcto aquí por lo que intenté, vea mi proyecto ejecutándose completamente en ESM para comparar (configuración de broma en el package.json ). ~

~ Para depurarlo si es posible, sugeriría simplificar su configuración de broma para _sólo_ tener las dos propiedades relevantes, quizás incluso en el package.json primero. Luego agregue cada una de las otras propiedades que tiene actualmente para ver cuál funciona / no funcionó. ~

Ah, el segundo comentario menciona globalSetup y no pruebas normales, nvm mi comentario entonces. Si elimino la clave globalSetup en Jest, entonces la prueba se ejecuta como se esperaba en ese ejemplo, pero la clave globalSetup no funciona como dijiste.

Ajá, me he olvidado de la configuración y el desmontaje global. Puede arreglar 👍

Hola @SimenB , yo de nuevo. ¿Se admiten las exportaciones con nombre? Con Node.js puedo importar y usar un paquete como este:

import { customAlphabet } from "nanoid";

Sin embargo, al intentar hacer una prueba, ese mismo código da este error:

SyntaxError: The requested module 'nanoid' does not provide an export named 'customAlphabet'

Para las pruebas, puedo cambiar el código a esto y funciona:

import nanoid from "nanoid";
const { customAlphabet } = nanoid;

Pero luego la versión de Node.js deja de funcionar ya que en realidad no hay un deporte predeterminado (pero por alguna razón la exportación predeterminada funciona con Jest):

SyntaxError: The requested module 'nanoid' does not provide an export named 'default'

El código publicado (el repositorio parece estar cambiando en este momento) nanoid termina así, sin exportación predeterminada:

export { nanoid, customAlphabet, customRandom, urlAlphabet, random }

Jest consume solo el punto de entrada "principal". Las "exportaciones" aún no se consideran. Simplemente importa la versión commonjs que solo tiene exportación predeterminada.

Ah, ya veo, el package.json parece incluir esto:

  "main": "index.cjs",
  "module": "index.js",
  "exports": {
    "./package.json": "./package.json",
    ".": {
      "require": "./index.cjs",
      "import": "./index.js",
      "browser": "./index.browser.js"
    },
    ...
  }
  ...

Entonces, probablemente Node.js esté encontrando la versión del módulo, mientras que Jest está usando la versión CommonJS que no tiene una exportación con nombre, ¿verdad?

Esperaré hasta que se verifique Package Exports y luego lo probaré, ¡gracias por todo el trabajo nuevamente! Marcando estos 2 comentarios como resueltos hasta entonces. La prueba a la que me refiero es esta .

Estoy revisando esto para ver cómo funciona: actualizado a Jest 26.0.1 y al nodo 14.4. Establezca package.json en el tipo de módulo, establezca transform en {} , env en jest-environment-node y ejecute con node --experimental-vm-modules . Ahora recibo este nuevo error:

ES Modules are only supported if your test environment has the `getVmContext` function

No he podido encontrar información sobre esto, excepto un registro de cambios de Jest que dice que getVmContext había agregado hace un tiempo.

¿Algunas ideas?

¿Podrías compartir las partes relevantes de tu package.json por favor @cyberwombat ? Incluyendo el script de inicio que está utilizando para Jest.

Como referencia, así es como me busca en un proyecto de trabajo :

{
  ...
  "type": "module",
  "scripts": {
    ...
    "test": "node --experimental-vm-modules node_modules/jest/bin/jest.js",
  },
  "jest": {
    "transform": {},
    "testEnvironment": "jest-environment-node"
  },
  ...

Luego ejecútalo con npm test

@franciscop El mío básicamente es el mismo. Nodo 14.4.0. Puedo ejecutar el tuyo bien. Me sumergiré en las cosas para ver la diferencia.
package.json

{
  "type": "module",
  "devDependencies": {
    "jest": "^26.0.1",
  },
}

jest.config.js

export default {
  testEnvironment: 'jest-environment-node',
  setupFilesAfterEnv: ['./test/bootstrap.js'],
  testPathIgnorePatterns: ['<rootDir>/node_modules/', '<rootDir>/config/', '/<rootDir>/src/'],
  testRegex: '(\\.|/)(test|spec)\\.[jt]sx?$',
  transform: {
//    '^.+\\.jsx?$': 'babel-jest' // esm someday
  },
  transformIgnorePatterns: [],
  modulePaths: [
    '<rootDir>/test',
    '<rootDir>/src',
    '<rootDir>'
  ]
}

Texto:
node --experimental-vm-modules node_modules/jest/bin/jest.js

No estoy seguro, pero trataría de trabajar al revés. Elimine todo excepto transform: {} y testEnvironment: 'jest-environment-node' , y comience a agregar cada una de las opciones hasta que vea cuál desencadena el error anterior. Especialmente sospecho que transformIgnorePatterns _ podría estar en conflicto con transform , pero no estoy tan familiarizado con las opciones de broma.

¡Hola a todos! Me encontré con algún problema al usar Jest para probar una aplicación Express. Más detalles aquí . No estoy seguro si eso es útil para lo que está haciendo / rastreando aquí: roll_eyes:

@ x80486 Encontré exactamente el mismo problema ayer . Respondí en StackOverflow con una explicación más larga de mi comprensión.

Editar: Desconocí mi comentario anterior ya que parece que podría ser relevante, este "exports" parece ser popular, muy probablemente por este artículo sobre paquetes híbridos .

exports se rastrea en # 9771

@franciscop ok problema resuelto - resulta que hay un conflicto en los paquetes - Tenía serverless-bundle instalado lo que causa el error ES Modules are only supported if your test environment has the getVmContext function . No estoy seguro de por qué: supongo que instalarlo no causaría un conflicto de ejecución con Jest, pero evidentemente lo hace.

@franciscop Creo que la razón por la que los problemas relacionados con pkg.exports comienzan a aparecer ahora es porque esa función no estaba marcada en Node.js 14.x y algunos mantenedores de paquetes (como yo por uuid ) comenzaron agregando pkg.exports campos. Entonces, aunque necesitaba una marca de línea de comandos para activar esa función en Node.js 12.x , ahora obtiene ese comportamiento de forma predeterminada.

Tomará un tiempo para que todo el ecosistema se adapte, así que gracias por informar problemas relacionados con ese tema.

Para aquellos que publican alrededor de exports , en caso de que se haya perdido en el largo hilo de este problema, mi problema cerrado al respecto (https://github.com/facebook/jest/issues/9565) tiene un ejemplo de la solución moduleNameMapper contiene.

¿Es probable que el problema globalSetup informado en mayo todavía esté ahí (Jest 26.1.0)? Obtener los mismos errores que en el ejemplo de repo @aledalgrande proporciona:

$ git clone [email protected]:aledalgrande/jest-example.git
$ cd jest-example
$ npm test

> @ test /Users/asko/Temp/jest-example
> node --experimental-vm-modules node_modules/jest/bin/jest.js --config=./jest.config.js

Error [ERR_REQUIRE_ESM]: Must use import to load ES Module: /Users/asko/Temp/jest-example/tests/setup.js
require() of ES modules is not supported.
require() of /Users/asko/Temp/jest-example/tests/setup.js from /Users/asko/Temp/jest-example/node_modules/@jest/transform/build/ScriptTransformer.js 

Sin prisa. Marcó CHANGELOG y no mencionó una solución a globalSetup / globalTeardown con ES6.

Node.js 14.4.0, Jest 26.1.0


Actualización (13-agosto-20):

Todavía no es posible, Node.js 14.7.0, Jest 26.4.0

Opinión secundaria, pero ¿debería ser este tema un tema fijo ya que es el foco de la broma en este momento?

¿Alguna idea sobre lo que se debe hacer para consumir reporteros de prueba escritos en módulos ES? ...
con la última versión de broma, recibo un error que esencialmente dice que testScheduler espera un reportero personalizado en formato commonjs.


para ver el error

~ / proyectos / esw-ts / lib / dist / test / testReporter.js: 1
importar sistema operativo desde 'sistema operativo';
^^^^^^

SyntaxError: no se puede utilizar la declaración de importación fuera de un módulo
en wrapSafe (interno / módulos / cjs / loader.js: 1116: 16)
en Module._compile (internal / modules / cjs / loader.js: 1164: 27)
en Object.Module._extensions..js (internal / modules / cjs / loader.js: 1220: 10)
en Module.load (interno / módulos / cjs / loader.js: 1049: 32)
en Function.Module._load (internal / modules / cjs / loader.js: 937: 14)
en Module.require (internal / modules / cjs / loader.js: 1089: 19)
en require (internal / modules / cjs / helpers.js: 73: 18)
en /Users/manish.gowardipe/Desktop/projects/esw-ts/lib/node_modules/@jest/core/build/TestScheduler.js:418:65
en Array.forEach ()
en TestScheduler._addCustomReporters (/Users/manish.gowardipe/Desktop/projects/esw-ts/lib/node_modules/@jest/core/build/TestScheduler.js:411:15)

Hola, quiero probar el soporte nativo para los módulos ES en mi pequeño proyecto, pero soy nuevo en NodeJS y me perdí en este problema, me encantaría recibir una guía, por favor.

  • node --version : v14.5.0
  • yarn jest --version : 26.1.0
  • Estoy tratando de probar este pequeño proyecto , es muy simple.
  • Tengo mis archivos así:

package.json

{
"jest": {
    "transform": {},
    "testEnvironment": "jest-environment-node"
  }
}

markov.test.js

const fs = require("fs");
const Markov = require("./markov.mjs");
// import fs from "fs";
// import Markov from "./markov.mjs";

const file = fs.readFileSync("text.txt", "utf8");
const markov = new Markov(file.toString());

test("Generates sentence with especified words", () => {
  expect(markov.makeSentence(8).length).toBe(8);
});
  • Ejecuto yarn jest . y me da este error:
    imagen

  • Intenté con node node_modules/jest/bin/jest.js . y me da el mismo error.

@ pepetorres1998 Este hilo trata sobre ejecutar Jest con módulos nativos de esm que implica ejecutar cosas con ciertas banderas / opciones - vea el comentario de arriba para saber qué hacer (y establezca "type": "module" en package.json). Honestamente, aunque en este punto no está listo para el horario de máxima audiencia, por lo que si necesita que su proyecto funcione, podría quedarme con Babel. Hay una serie de problemas no controlados que son verdaderos obstáculos. Con alegría intenté cambiarme hace un par de semanas y volví llorando a Babel.

¿Alguien más recibe un ReferenceError: jest is not defined cuando intenta hacer cosas como jest.setTimeout(...) en un archivo de prueba con esta configuración? Tratando de averiguar si esto está relacionado con el entorno del módulo es, la versión del nodo, la versión de broma o alguna combinación de esas cosas. (Actualmente usando el nodo v14.5.0, jest 26.1.0, entorno jest-environment-node)

EDITAR
Ahora veo la casilla de verificación sin marcar en la descripción del problema para la propiedad de broma 'global'. 🙃

@bdentino Creo que puedes intentar importarlo explícitamente import {jest} from '@jest/globals';

25.4.0 ha sido lanzado con las primeras piezas de soporte. Además del # 9772 mencionado anteriormente, también he incluido el # 9842. En _teoría_, la combinación de CJS y ESM debería funcionar correctamente ahora (🤞).

La única característica principal que falta es la compatibilidad con el objeto jest . No he decidido si deberíamos ceñirlo a import.meta o pedirle a la gente que lo importe a través de import {jest} from '@jest/globals' . ¡Se agradecen los comentarios!

Todavía no he escrito documentos para esto, pero para activarlo debes hacer 3 cosas

  1. asegúrese de no ejecutar las declaraciones transform away import (establezca transform: {} en la configuración o asegúrese de que babel no transforme el archivo a CJS, como evitar el modules opción para preestablecer-env)
  2. Ejecute node@^12.16.0 || >=13.2.0 con --experimental-vm-modules bandera
  3. Ejecute su prueba con jest-environment-node o jest-environment-jsdom-sixteen

¡Pruébelo y envíenos sus comentarios! Si informa errores, sería maravilloso si también pudiera incluir cómo se ejecuta el mismo código (menos cualquier código específico de prueba) en Node. He leído https://nodejs.org/api/esm.html _mucho_ durante las últimas semanas, pero probablemente me he perdido algo.

@SimenB
Este hilo se volvió enorme, y creo que aquellos que quieran comenzar con broma / usar módulos ES, tendrán dificultades para encontrar y comprender las pautas básicas para comenzar a hacerlo.
¿Hay una explicación formal en los documentos sobre cómo agregar bromas a un proyecto de módulos ES (o algún 'inicio rápido')?

@aldeed Con respecto a su problema con la

(Por cierto, también usamos el comercio de reacción, así que saludos a eso, jaja)

@guilhermetelles no, y ahora se rastrea en https://github.com/facebook/jest/issues/10025 .

Estoy usando Jest 26.1.0, node versión 14.6.0 con --experimental-vm-modules , pero sigo viendo ERR_VM_DYNAMIC_IMPORT_CALLBACK_MISSING cuando uso import() dentro de CommonJS . ¿Debería intentar crear una reproducción mínima y abrir una nueva edición?

Aparte, ¿hay una manera fácil de yarn link una copia de los paquetes jest en un proyecto ahora que Jest usa yarn berry? Quería probar el último master en caso de que aún no se haya lanzado. Estaba tratando de hacer algo como path/to/facebook/jest/.yarn/releases/yarn-sources.cjs link --all path/to/jest , pero fallaría. Ejecutar manualmente algo como cd node_modules; for p in jest*; do if [[ -d path/to/jest/packages/$p ]]; then rm -rf $p; ln -s path/to/jest/packages/$p; fi; done tampoco funcionaba, no estoy seguro de por qué.

@vvanpo import() en CJS se revirtió en Node, puede seguir https://github.com/nodejs/node/issues/31860

En cuanto a la ejecución local, normalmente solo desinstalo jest del proyecto que quiero probar y hago ../jest/jest . Potencialmente nose ../jest/packages/jest/bin/jest.js . Solo asegúrese de ejecutar yarn y yarn build:js primero. Si estas instrucciones no funcionan (estoy escribiendo desde la memoria en un teléfono en un avión), abra un problema (o PR) para que podamos escribirlo correctamente en el archivo CONTRIBUTING.md

¿Planea apoyar las importaciones cíclicas?

Si tengo un archivo de prueba ficticio que solo importa uno de los dos archivos que solo se importan entre sí, obtengo RangeError: Maximum call stack size exceeded . Si elimino una de las importaciones, la prueba pasa. Repo que reproduce el problema .

¡Oye! Configuré esto en un proyecto de nodo vacío y funcionó muy bien, sin embargo, en nuestra configuración de producción, aparece el siguiente mensaje de error cuando intento ejecutar pruebas:

ES Modules are only supported if your test environment has the 'getVmContext' function

Vi a alguien más que tenía algún problema en una respuesta anterior (por @cyberwombat ), pero el paquete que encontraron que era el culpable no está presente en nuestro archivo package.json . ¿Cómo deducir el paquete (o configuración) que causa el problema? He intentado eliminar sistemáticamente todos los ajustes de broma que no son necesarios para que esto funcione, pero no tuve éxito.

ACTUALIZACIÓN : Me las arreglé para progresar haciendo un ligero cambio en jest-runtime . Detuve el depurador en la línea que intenta acceder al contexto de VM y aunque la función realmente no existe, this.context (que debería devolver) sí, así que cambié esa línea para acceder a la propiedad directamente. Sé que probablemente esto no sea lo ideal, pero tal vez @SimenB esto podría darte una idea de lo que está

Gracias de antemano por cualquier ayuda

¿Planea apoyar las importaciones cíclicas?

¡Definitivamente! ¿Podrías abrir un tema aparte?


@zsombro parece que está ejecutando una versión antigua del entorno de prueba. Si ejecuta jest --show-config , ¿qué muestra testEnvironment ?

parece que está ejecutando una versión antigua del entorno de prueba. Si ejecuta jest --show-config , ¿qué muestra testEnvironment ?

@SimenB dice lo siguiente:

"testEnvironment": "/Users/zberki/git/project-name/node_modules/jest-environment-node/build/index.js",
"testEnvironmentOptions": {},

Solo lo configuré en jest-environment-node según tus instrucciones

Antes de comenzar este proceso, actualicé Jest usando yarn add jest@latest . ¿Tengo que actualizar el entorno por separado?

ACTUALIZACIÓN: Resulta que tenía que hacerlo. Eliminé node_modules y yarn.lock para hacer una instalación limpia y todavía no funcionó. Sin embargo, si lo agrego manualmente usando yarn add -D jest-environment-node , parece funcionar. ¿Existe una mejor manera de gestionar esto? Hice un proyecto de prueba minimalista antes de hacer esto en nuestro código base y no tuve que hacer esto

yarn list jest-environemnt-node (o npm list jest-environemnt-node ) probablemente enumerará varios, es mi suposición

├─ [email protected]
│  └─ [email protected]
└─ [email protected]

la versión 26.2.0 es probablemente la que instalé manualmente (al menos basada en package.json , lo que significa que jest-config ha instalado una versión que aparentemente está desactualizada?

Tiene algo más incorporando una versión anterior de jest-config ( react-scripts quizás (¿parte de create-react-app )?). Este tema no es el lugar para discutirlo, aunque 🙂

No poder usar módulos ES en mi globalSetup está comenzando a doler.

Dos puntos:

  • ¿Debería mencionarse esto como una casilla de verificación al principio de este número (para que se realice un seguimiento)?
  • si hay un alfa / beta que podría probar, dispuesto a hacerlo

I:

  • Me aseguré de que esté ejecutando la versión más reciente de Jest (26.4.0)
  • Agregué jest-environment-node a mi proyecto
  • Se aseguró de que no esté duplicado inspeccionando el archivo de bloqueo
  • Se agregó "testEnvironment": "jest-environment-node", en jest.config.json
  • Se agregó import { jest } from '@jest/globals'; dondequiera que se usó broma
  • Ejecutó la configuración del comando de prueba --experimental-vm-modules ejecutándolos con NODE_OPTIONS='--experimental-vm-modules' yarn jest

Y falla en el siguiente código:

jest.mock('../../some/other/path', () => ({
  someOtherMethod: jest.fn().mockImplementation(…),
}));

con el siguiente error (abreviado - ¡tenga en cuenta "Objetos permitidos"!):

ReferenceError: src/foo/bar.spec.js: The module factory of `jest.mock()` is not allowed to reference any out-of-scope variables.
Invalid variable access: jest
Allowed objects: Array, …, jest, …, unescape.
Note: This is a precaution to guard against uninitialized mock variables. If it is ensured that the mock is required lazily, variable names prefixed with `mock` (case insensitive) are permitted.

No puedo usar Babel, porque analiza incorrectamente las importaciones que arreglé para ejecutar en el Nodo 14 sin Babel:

-import { map } from 'lodash';
+import lodash from 'lodash';
+const { map } = lodash;

Que, lamentablemente, se analiza incorrectamente por @babel/preset-env , lo que resulta en TypeError: Cannot destructure property 'map' of '_lodash.default' as it is undefined. .

¿Alguien puede ayudarme a solucionar este problema?

Editar: Parece que _ puedes_ usar Jest + Babel en código nativo compatible con módulos ES usando importaciones de CommonJS haciendo esta solución absolutamente repugnante:

jest.mock('common-js-module', () => ({
  __esModule: false,
  ...jest.requireActual('common-js-module'),
}));

De esta manera,

import lodash from 'lodash';
const { map } = lodash;

es perfectamente consumido por el Nodo 14, y el código resultante de ejecutar Jest + Babel,

var _lodash = _interopRequireDefault(require("lodash"));

function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }

const {
  map
} = _lodash.default;

también corre.

hemos convertido con éxito todas nuestras pruebas de broma para usar e importar nuestro código ES6, pero nos quedamos atascados en algunos paquetes: a saber, puppeteer y uuid

La aplicación solo funciona si los importamos a un objeto (como import uuid from 'uuid' ), pero las pruebas no se ejecutarán de esta manera. Sin embargo, si reemplazamos esta importación con la sintaxis de deconstrucción (como import { v4 } from 'uuid' , entonces es al revés: la prueba funciona, pero la aplicación arroja una excepción.

originalmente, seguimos la guía y desactivamos cada transformación, pero también intentamos crear un espacio de trabajo de hilo donde instalamos babel con una configuración de nodo mínima, pero esto no resolvió (o empeoró) este problema específico

Sin embargo, si reemplazamos esta importación con la sintaxis de deconstrucción (como import {v4} from 'uuid', entonces es al revés: la prueba funciona, pero la aplicación arroja una excepción.

Parece que su aplicación está compilada para CommonJS y no usa módulos en la práctica. Desde el ESM "real" import uuid from 'uuid' no debería funcionar porque uuid no tiene una exportación predeterminada y expone una compilación de ESM para el nodo .

Hola @SimenB , ¿crees que alguna documentación preliminar sobre esto sería una buena idea?

@grantcarthew definitivamente! Tenía la esperanza de poder dedicar más tiempo a esto y estabilizarlo para Jest 27, pero dudo que pueda hacerlo. Pero escribir una página de documentos sobre lo que hay ahora (y que es experimental) parece una buena idea

@SimenB No sé cuál es el estado actual del problema y si Jest ya debería funcionar con mi caso o no, pero tal vez pueda ayudarlo de alguna manera.

Estoy tratando de cargar una biblioteca solo esm (su extensión es cjs pero el tipo es módulo y el nodo parece estar bien con eso) pero Jest no puede cargarlo correctamente con el error:

    C:\dev\codemirror-next-repro-cra\test-in-jest-esm\node_modules\style-mod\dist\style-mod.cjs:15
    export var StyleModule = function StyleModule(spec, options) {

Aquí el problema que abrí originalmente https://github.com/codemirror/codemirror.next/issues/310. Y una reproducción para Jest + ESM fallando con el nodo 14.13.1 https://github.com/dubzzz/codemirror-next-repro-cra/tree/main/test-in-jest-esm

@dubzzz no puede tener ESM en un archivo cjs . El nodo también falla

$ node node_modules/style-mod/dist/style-mod.cjs
(node:48829) Warning: To load an ES module, set "type": "module" in the package.json or use the .mjs extension.
(Use `node --trace-warnings ...` to show where the warning was created)
/Users/simen/repos/codemirror-next-repro-cra/test-in-jest-esm/node_modules/style-mod/dist/style-mod.cjs:15
export var StyleModule = function StyleModule(spec, options) {
^^^^^^

SyntaxError: Unexpected token 'export'
    at wrapSafe (internal/modules/cjs/loader.js:1172:16)
    at Module._compile (internal/modules/cjs/loader.js:1220:27)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:1277:10)
    at Module.load (internal/modules/cjs/loader.js:1105:32)
    at Function.Module._load (internal/modules/cjs/loader.js:967:14)
    at Function.executeUserEntryPoint [as runMain] (internal/modules/run_main.js:60:12)
    at internal/main/run_main_module.js:17:47

Lo siento mucho, lo intenté demasiado rápido en el lado del nodo. @ nicolo-ribaudo ya notificó al autor de la lib sobre este problema.
Realmente muchas gracias por tu rápida respuesta.

Abrí un PR para algunos documentos (prácticamente stub) aquí: # 10611. No me molesté en enumerar las características / errores faltantes, ya que creo que será difícil mantenerlos sincronizados con la realidad, y analizar los problemas de github es un mejor enfoque, ya que están (con suerte ...) actualizados.

@Pomax como una nueva edición, por favor 🙂

Acabo de abrir # 10620 que agrega soporte para import() de CJS. Algunas veces solicitadas son como https://github.com/facebook/jest/issues/9430#issuecomment -626054595

Hola. Es bastante difícil para mí abrazar rápidamente toda la historia detrás de ESM en node / jest, así que, probablemente, estoy preguntando algo obvio o ya respondido. ¿Entiendo correctamente que el siguiente caso aún no es compatible? O, espero, estoy haciendo algo que no es la forma correcta. Lo experimento como si import x from 'x' funciona, pero la desestructuración de import { sub } from 'x' no.

package.json:

{
  "name": "jest-uuid",
  "version": "1.0.0",
  "type": "module",
  "scripts": {
    "test": "node --experimental-vm-modules node_modules/.bin/jest"
  },
  "devDependencies": {
    "jest": "26.5.2"
  },
  "dependencies": {
    "uuid": "8.3.1"
  }
}

f.spec.js

import { v4 } from 'uuid';
test('', () => {});

prueba npm

> npm test

> [email protected] test /Users/igoro/p/tmp/jest-uuid
> node --experimental-vm-modules node_modules/.bin/jest

 FAIL  ./f.spec.js
  ● Test suite failed to run

    SyntaxError: The requested module 'uuid' does not provide an export named 'v4'

      at jasmine2 (node_modules/jest-jasmine2/build/index.js:228:5)

Test Suites: 1 failed, 1 total
Tests:       0 total
Snapshots:   0 total
Time:        0.879 s
Ran all test suites.
(node:94492) ExperimentalWarning: VM Modules is an experimental feature. This feature could change at any time
(Use `node --trace-warnings ...` to show where the warning was created)
npm ERR! Test failed.  See above for more details.

Estás esperando el número 9771. Antes de eso, Jest no sabe que es seguro cargar uuid como ESM (o más bien, qué archivo cargar y en qué punto sabría que es ESM)

¿Seguirá esto la propia convención de Node, donde CJS solo se puede cargar como espacio de nombres, o esto "mejorará" al permitir una sintaxis que en realidad no funciona en Node? (por ejemplo, Node no permite import { readdirSync } from "fs-extra" porque es un paquete CJS, pero sí permite import fs from "fs-extra"; que luego se puede descomprimir usando const { readdirSync } = fs ).

(por ejemplo, Node no permite importar {spawn} desde "child_process" porque es un paquete CJS, pero sí permite importar child_process desde "child_process"; que luego se puede desempaquetar usando const {spawn} = child_process;).

Este es un ejemplo desafortunado porque el nodo considera que "child_process" es un módulo "incorporado" (y no CJS), por lo que las exportaciones con nombre funcionan. El último nodejs también usa una heurística para hacer que muchas exportaciones con nombre funcionen para los módulos CJS. Esa puede ser la parte más difícil de emular.

ejemplo actualizado para usar fs-extra lugar. Pero si la exportación con nombre está en la hoja de ruta de Node para aterrizar esta o la siguiente importante, entonces Jest tiene sentido adelantarse a eso.

Eso ya debería estar implementado: los módulos del núcleo de nodo exponen exportaciones con nombre, el CJS "normal" no.

El último nodejs también usa una heurística para hacer que muchas exportaciones con nombre funcionen para los módulos CJS. Esa puede ser la parte más difícil de emular.

¿Tiene un enlace para que el RP lo implemente? Deberíamos intentar emularlo al menos 🙂

El RP está aquí: https://github.com/nodejs/node/pull/35249

La heurística detrás de esto se publica como cjs-module-lexer (https://github.com/guybedford/cjs-module-lexer) pero @guybedford podría saber más sobre cualquier desviación potencial.

Solo eché un vistazo a esto y parece que fs-extra está usando un patrón de exportación como:

module.exports = {
  // Export promiseified graceful-fs:
  ...require('./fs'),
  // Export extra methods:
  ...require('./copy-sync'),
  ...require('./copy'),
  ...require('./empty'),
  ...require('./ensure'),
  ...require('./json'),
  ...require('./mkdirs'),
  ...require('./move-sync'),
  ...require('./move'),
  ...require('./output'),
  ...require('./path-exists'),
  ...require('./remove')
}

Actualmente, este no es un caso de análisis de reexportaciones que detectamos, pero podría ser posible agregarlo a cjs-module-lexer si este fuera un caso útil para manejar la detección de exportaciones con nombre.

¡Gracias @jkrems y @guybedford! Abrí un PR ahora usando ese módulo: # 10673

El soporte fs-extra exacto descrito en https://github.com/facebook/jest/issues/9430#issuecomment -713204282 ahora se implementa en [email protected] , seguimiento ascendente en https: // github. com / nodejs / node / pull / 35745.

_Actualización: probando esta compilación, detecta correctamente todas las funciones fs-extra, pero desafortunadamente no detecta las funciones nativas de Node.js ya que no se pueden analizar estáticamente debido a que están pobladas por un bucle for_

hazaña: admite exportaciones con nombre de CJS como importaciones de ESM con nombre # 10673

Pensé que el ESM nativo solo admite la importación de exports un módulo CommonJS como default ?

Hola. Es bastante difícil para mí abrazar rápidamente toda la historia detrás de ESM en node / jest, así que, probablemente, estoy preguntando algo obvio o ya respondido. ¿Entiendo correctamente que el siguiente caso aún no es compatible? O, espero, estoy haciendo algo que no es la forma correcta. Lo experimento como si import x from 'x' funciona, pero la desestructuración de import { sub } from 'x' no.

...
importar {v4} desde 'uuid';

Los módulos ESM no admiten la desestructuración de las importaciones, aunque la sintaxis se parece a ella. Para que esto funcione, se necesita 'exportar v4'. 'export default' no coincidirá.

https://kentcdodds.com/blog/misunderstanding-es6-modules-upgrading-babel-tears-and-a-solution

@sdwlig uuid proporciona exportaciones con nombre y no tiene una predeterminada. Debería funcionar, pero la carga de esm desde paquetes con el campo "exportaciones" aún no es compatible con jest. En su lugar, se carga Commonjs, que solo está disponible a través de la exportación predeterminada.
https://github.com/uuidjs/uuid/blob/master/src/index.js

¿Podríamos agregar soporte de autorreferencia del paquete (# 10883) a esto?

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