EDIT: guia rápido para começar: https://jestjs.io/docs/en/ecmascript-modules
O suporte ESM será sem sinalização em uma versão futura do Nó 12 (talvez não antes de abril https://github.com/nodejs/node/pull/29866#issuecomment-574055057) e já não está sinalizado no Nó 13.2, então acho que é hora de avaliar como podemos adicionar suporte nativo no Jest. Tentarei listar quais recursos Jest fornece atualmente que são afetados pelo suporte do ESM e como podemos resolvê-los / investigá-los.
Há o problema nº 4842, mas acho que é mais um problema de discussão, embora esse problema seja voltado para a implementação de suporte e mais adequado para rastrear para aqueles que desejam apenas obter o status de implementação atual. Quaisquer comentários adicionados a este problema _não_ relacionados a como podemos implementar suporte para os recursos enumerados abaixo serão marcados como spam - direcione quaisquer soluções alternativas / discussões para problemas separados. Sinta-se à vontade para nos dizer se algo relacionado aos recursos do ESM estiver faltando na lista!
Observe que Jest usará a API vm
(https://nodejs.org/api/vm.html) e no momento da escrita (nó v13.6) as partes ESM desta API ainda estão sinalizadas ( --experimental-vm-modules
). Portanto, dizer que ESM não é sinalizado é um pouco incorreto no momento. Mas acho que devemos começar a experimentar e, potencialmente, fornecer feedback para o WG de Módulos .
Por último, estou escrevendo esta edição principalmente para pessoas que implementarão o suporte, portanto, será um pouco de baixo nível e específico para o funcionamento do Jest. Para as pessoas que _just_ querem saber se o suporte foi recebido ou não, recomendo usar a maravilhosa "notificação personalizada" do GH e se inscrever apenas para receber notificações no fechamento / reabertura.
Alcançamos sandboxes executando um script dentro de um determinado vm.Context
(fornecido por JSDOM ou APIs de núcleo de nó). Precisamos fazer o mesmo para o ESM, mas precisaremos acessar context
durante a construção do módulo, não apenas durante a execução do módulo. Abri o # 9428, que adiciona as APIs necessárias a JestEnvironment
.
expect
, test
, beforeEach
etc ainda serão adicionados como globais, nada deve mudar aqui. jasmine
global também estará aqui.
jest
propriedade "global"Este não é realmente um global - é injetado no escopo do módulo. Como o escopo do módulo foi eliminado no ESM, precisamos movê-lo para algum lugar. Adicioná-lo a import.meta
parece natural - há uma opção chamada initializeImportMeta
que podemos usar.
EDITAR: a solução aqui é buscá-lo por meio de import {jest} from '@jest/globals'
. Ainda podemos adicioná-lo por meio de import.meta
no futuro, mas isso deve ser o suficiente por enquanto.
jest.(do|un)mock
Como o ESM tem diferentes "estágios" ao avaliar um módulo, jest.mock
não funcionará para importações estáticas. No entanto, ele pode funcionar para importações dinâmicas, então acho que só temos que deixar claro nos documentos o que ele suporta e o que não é.
jest.mock
chamadas são suspensas, mas isso não ajuda no ESM. Podemos considerar a transformação de import 'thing'
em import('thing')
que deve permitir que o içamento funcione, mas é assíncrono. Usar await
é provavelmente uma necessidade para tal abordagem. Também acho que é invasivo o suficiente para justificar uma opção separada. Algo para discutir - não precisamos oferecer suporte a tudo que jest.mock
pode para um lançamento inicial.
jest.requireActual
Não tenho certeza se como ele deve se comportar no ESM. Devemos fornecer jest.importActual
e deixar requireActual
avaliar em CJS
sempre?
import.meta
O nó tem url
como sua única propriedade (pelo menos por enquanto). Precisamos ter certeza de que ele está preenchido em Jest também. Fornecemos identifier
vez de filename
ao construir o módulo, então não acho que isso acontecerá automaticamente, mas url
é essencialmente filename
passado por pathToFileURL
.
Também há um PR aberto para import.meta.resolve
: https://github.com/nodejs/node/pull/31032
import thing from 'thing'
Isso deve ser bastante simples, só precisamos implementar linker
onde também podemos transformar a fonte antes de retorná-la, o que significa que não precisamos da API do carregador (que ainda não existe). Isso nos permite retornar simulações também (embora elas tenham que vir de um diretório __mocks__
).
import('thing')
Essencialmente o mesmo que acima, mas passado como importModuleDynamically
ao construir o módulo. Também suportará jest.mock
, jest.resetModules
etc de maneira mais limpa, portanto, provavelmente será usado um pouco.
Isso também pode ser feito por vm.Script
por meio da mesma opção.
No momento, é um erro de tempo de execução (por exemplo, módulo não encontrado), mas isso não é necessariamente verdadeiro com o ESM. Isso importa para nós? Devemos verificar se os erros ainda parecem bons.
module.createRequire
Precisamos lidar com isso para as pessoas que desejam usar o CJS do ESM. Abri o número 9426 para rastrear isso separadamente, pois implementá-lo não está realmente relacionado ao suporte ESM.
EDITAR: Implementado em # 9469
module.syncBuiltinESMExports
https://nodejs.org/api/modules.html#modules_module_syncbuiltinesmexports. Nós nos preocupamos com isso, ou apenas torná-lo um ambiente autônomo o suficiente? Não tenho certeza de qual seria o caso de uso em Jest. Mexer com os embutidos já está quebrando a caixa de areia e eu não acho que isso deveria importar.
EDIT: # 9469 tornou isso um autônomo. Eu acho que está bom?
Inspecionar o campo type
no package.json
um módulo parece razoável: https://nodejs.org/api/esm.html#esm_enabling. Devemos também ter nosso próprio sinalizador de configuração? Também deve respeitar as terminações do arquivo.
https://github.com/nodejs/modules/issues/393
moduleNameMapper
Não tenho certeza se isso afeta alguma coisa. _Acho_ que não, já que ligaremos os módulos nós mesmos. Precisa de investigação, no entanto.
EDIT: Esta é toda a lógica de resolução, que controlamos. Portanto, nenhuma mudança aqui.
jest.config.mjs
Por meio do # 9291, apoiamos jest.config.cjs
- precisamos fazer algo especial para .mjs
? Provavelmente use import('path/to/configFile.mjs')
que significa que terá que ser assíncrono. Isso é um problema? Pode valer a pena fazer a resolução de configuração async
no Jest 25, portanto, não é um bloqueador para suporte incremental do ESM no Jest 25.
EDITAR: # 9431
O Node suporta exportações de pacote , que são mapeadas para moduleNameMapper
Jest, mas também fornece recursos de encapsulamento. Esperançosamente resolve
irão implementar isso, mas se não, precisaremos fazer algo. Pode ser o suficiente para usar a opção pathFilter
? Não tenho certeza.
https://nodejs.org/api/esm.html#esm_experimental_json_modules. Precisamos nos preocupar? Provavelmente, especialmente por json
. É trivial para nós oferecer suporte a import thing from './package.json'
uma vez que controlamos a fase de vinculação, mas provavelmente não devemos fazer isso por padrão, pois será diferente do nó padrão. Devemos forçar as pessoas a definir uma transformação para isso?
Isso importa? Não acho que seja afetado, pois ainda podemos transformar a fonte com babel (talvez seja confundido por import
instruções, provavelmente não) e a cobertura V8 definitivamente não deveria se importar. Devemos verificar embora.
Isso não é absolutamente nenhum bloqueador, pois a resolução de sincronização funcionará perfeitamente. Mas nós _podemos_ usar a resolução assíncrona agora, o que é ótimo. Eu me pergunto se devemos olhar apenas para usar o módulo resolve
fora do npm novamente, pois ele já oferece suporte ao assíncrono. Consulte # 9505.
Semelhante ao anterior, sem bloqueio, mas seria bom apoiá-lo. Pode tornar @jest/transformer
mais utilizável em outros ambientes também. Veja # 9504.
Devido ao # 5163, temos a opção extraGlobals
como uma solução alternativa - essa solução alternativa não é mais viável no ESM. Abri um problema com o nó aqui: https://github.com/nodejs/node/issues/31658
Consegui suporte básico com o # 9772. Eu testei apenas os casos mais simples, e há muitas limitações conhecidas (principalmente sem suporte a objeto jest
e semântica quebrada ao misturar CJS e ESM), mas pelo menos é _algo_. Ele será lançado na próxima versão do Jest (espero que em breve, apenas bloqueado por # 9806)
25.4.0 foi lançado com as primeiras peças de suporte. Além do # 9772 mencionado acima, também incluí o # 9842. Na _teoria_, a mistura de CJS e ESM deve funcionar corretamente agora (🤞).
O único recurso que falta é o suporte ao objeto jest
. Ainda não decidi se devemos mantê-lo em import.meta
ou exigir que as pessoas o importem através de import {jest} from '@jest/globals'
. Agradecemos o feedback!
Eu não escrevi documentos para isso ainda, mas para ativá-lo, você precisa fazer três coisas
import
(defina transform: {}
na configuração ou então certifique-se de que babel
não transforme o arquivo em CJS, evitando o modules
opção para predefinir o env)node@^12.16.0 || >=13.2.0
com a bandeira --experimental-vm-modules
jest-environment-node
ou jest-environment-jsdom-sixteen
Experimente e forneça comentários! Se relatar bugs, seria maravilhoso se você também pudesse incluir como a execução do mesmo código (sem qualquer código específico de teste) é executado no Node. Eu li https://nodejs.org/api/esm.html _muito_ nas últimas semanas, mas provavelmente deixei passar algo.
A única característica que falta é apoiar o objeto de brincadeira. Ainda não decidi se devemos colar em import.meta ou exigir que as pessoas importem por meio de import {jest} de '@ jest / globals'.
Para o caso de uso de texto digitado, é melhor ter uma importação explícita.
Sim, eu adicionei (e reverti temporariamente) um pacote @jest/globals
que suporta isso, então estará disponível de qualquer maneira. Estou me perguntando se faz sentido _também_ expô-lo em import.meta
. Atualmente inclinado a não fazer isso, principalmente porque é mais fácil adicionar do que remover depois (e, pessoalmente, não sou fã de globais)
+1 para a importação explícita, é um pouco mais prolixo, mas mais simples de entender
Estou recebendo isso no Nó 13.2 e Jest 25.4: ES Modules are only supported if your test environment has the
getVmContext function
O que estou perdendo?
@zandaqo Oh, desculpe, esqueci esse ponto. Adicionado acima, mas é
Execute seus testes com
jest-environment-node
oujest-environment-jsdom-sixteen
ReferenceError: jest is not defined
Suponho que isso seja devido à falta de @jest/globals
Sim, conforme mencionado, isso só funcionará se você não usar o objeto jest
.
Provavelmente, as simulações também estão quebradas, não as testei 😃
Compilei um projeto muito básico a partir do que vejo no diretório de testes e2e ( e2e/native-esm/__tests__/native-esm.test.js
) e nesta edição. E, infelizmente, ainda não consigo fazer funcionar 🙃Alguém pode verificar por acaso?
https://drive.google.com/file/d/1vyDZjsVKOTu6j55QA11GjO9E7kM5WX8_/view?usp=sharing
Executando script de amostra (apenas importando double
function e imprimindo 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
Executando o jest com apenas um teste para função dupla:
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.
Você precisa executar o nó com --experimental-vm-modules
e nomear o arquivo .mjs
ou "type": "module"
em package.json
.
EDIT: Você provavelmente tem o último visto que funciona fora do Jest para você, faltando apenas o sinalizador experimental para Node
@SimenB oh uau, existem --experimental-vm-modules
E --experimental-modules
. Fiquei confuso com o fato de que --experimental-modules
não é necessário a partir de alguma versão do nó 13. Obrigado!
TLDR: node --experimental-vm-modules node_modules/jest/bin/jest.js
funciona para mim
Sim, do OP
Observe que Jest usará a API
vm
(https://nodejs.org/api/vm.html) e no momento da escrita (nó v13.6) as partes ESM desta API ainda estão sinalizadas (--experimental-vm-modules
). Portanto, dizer que ESM não é sinalizado é um pouco incorreto no momento.
É incrível que funcione para você, no entanto!
(Vou marcar esses comentários como resolvidos)
@SimenB Obrigado por isso! Dois problemas que estou vendo até agora.
ReferenceError: module is not defined
no arquivo do pacote CJSEntão, estou pensando que isso pode não estar implementado corretamente?
Uma instrução de importação pode fazer referência a um módulo ES ou um módulo CommonJS
Isso funciona bem ao executar o aplicativo. As exportações nomeadas do CJS só podem ser importadas usando createRequire, mas as exportações padrão podem apenas ser importadas.
Quando não estou acertando o erro acima, estou acertando este:
TypeError: _vm(...).SyntheticModule is not a constructor
at Runtime._importCoreModule (node_modules/jest-runtime/build/index.js:1198:12)
targets: { node: 12 }
e 2 plug-ins: babel-plugin-transform-import-meta
e rewire-exports
. (Tentei remover o plugin import-meta
mas ocorreu um erro dizendo para adicioná-lo novamente.)testEnvironment: "node"
é praticamente a única configuraçãonode --experimental-vm-modules node_modules/jest/bin/jest.js
Se um repositório de reprodução for útil, me avise.
Obrigado @aldeed!
Vou analisar a questão 1, que realmente parece um bug. EDITAR: Deve ser corrigido via # 9850
O problema 2 precisa do nó 12.16.0: https://nodejs.org/docs/latest-v12.x/api/vm.html#vm_class_vm_syntheticmodule
Vou mudar a verificação no Jest (agora ele verifica vm.SourceTextModule
que está disponível em mais versões, mas precisamos de SyntheticModule
também).
Confirmei que executar com 12.16.0 corrige meu problema 2. Testarei novamente o problema 1 depois que a correção for lançada. Caso contrário, aguardando o objeto jest
para mais testes, e eu concordo que ele deve precisar ser importado.
Excelente trabalho, @SimenB! Estou tentando fazer isso em um pequeno projeto, mas tive problemas com importações dinâmicas. Este é o erro que estou vendo:
Module status must not be unlinked or linkingError [ERR_VM_MODULE_STATUS]: Module status must not be unlinked or linking
Se eu remover as importações dinâmicas, o teste será executado (mas falhará por outros motivos, é claro). O mesmo teste está funcionando atualmente com o Mocha (que forneceu suporte ESM recentemente).
Se ajudar, as importações dinâmicas em questão podem ser vistas aqui: https://github.com/beejunk/firn.js/blob/switch-to-jest/lib/renderPage.js#L43 -L55
O arquivo de teste está aqui: https://github.com/beejunk/firn.js/blob/switch-to-jest/test/build.test.js. A versão funcional do Mocha pode ser vista no branch master.
Avise-me se houver alguma outra informação que possa ser útil.
Obrigado @beejunk! Eu estive pensando se poderia haver condições de corrida entre import
s que importam o mesmo módulo antes de estar totalmente vinculado. _Parece_ que é isso que você está acertando aqui. Vou consertar isso hoje, obrigado pelo relatório!
EDITAR: corrigido em # 9858. Copiou a correção para o seu repo:
Alguém conseguiu fazer isso funcionar com o TypeScript? node --experimental-vm-modules node_modules/jest/bin/jest.js
retorna o mesmo SyntaxError: Cannot use import statement outside a module
, embora meu package.json
tenha "type": "module"
.
babel.config.cjs
module.exports = {
presets: [
'@babel/preset-typescript',
],
};
jest.config.cjs
module.exports = {
testEnvironment: 'jest-environment-node',
transform: {},
};
@dandv Você está basicamente acertando este caso: https://github.com/facebook/jest/pull/9772/files#r407255029
Você poderia abrir um problema separado? Precisará descobrir o que fazer com extensões não-js
@SimenB : # 9860. Obrigado por dar uma olhada.
@aldeed @beejunk 25.5.0 foi lançado com correções para seus problemas. Continue com os relatórios de bug 😀
Além disso, inclui suporte para import { jest } from '@jest/globals'
para aqueles que estão esperando por isso 👍
Obrigado pelo trabalho rápido em tudo isso, @SimenB! Acho que encontrei outro problema.
Tenho feito experiências com o uso de parâmetros de consulta em um caminho de importação como uma forma de invadir o cache do módulo em um servidor de desenvolvimento. A ideia é ter um inspetor de arquivos que detecta mudanças em um componente e então atualiza o caminho de importação com um parâmetro de consulta arbitrário para que o novo código seja imediatamente puxado na próxima página carregada sem ter que reiniciar o servidor. Isso funciona ao executar o servidor de desenvolvimento. No entanto, Jest está gerando o seguinte erro:
Cannot find module '/path/to/project/components/BasePage.js?cache=0' from 'renderPage.js'
Aqui está um exemplo de onde os parâmetros de consulta estão sendo usados: https://github.com/beejunk/firn.js/blob/switch-to-jest/lib/renderPage.js#L55 -L56
Se eu remover os parâmetros da consulta, os testes serão aprovados, embora não de forma consistente. Se eu executar um único pacote (por exemplo, npm test -- test/build.test.js
), os testes serão aprovados, mas se eu executar todos os testes de uma vez, eles falharão na maioria das vezes com erros ambíguos. Ainda estou investigando o problema com os testes inconsistentes, mas pensei em relatar o problema do parâmetro de consulta primeiro.
Obrigado pelo relatório @beejunk. # 6282 deve lidar com isso, mas também quer passar a consulta para transformadores e outras coisas, de que não precisamos aqui. Portanto, pode fazer sentido apenas suportar a consulta internamente no tempo de execução por enquanto, e deixar # 6282 lidar apenas com a transmissão dessa consulta.
Eu adicionei um pouco de código para fazer o cache do módulo variar por consulta: https://github.com/facebook/jest/blob/d425a49bd575e7167bc786f3c4f2833589091fa1/packages/jest-runtime/src/index.ts#L330 -L334
Mas nenhum código jamais o chama com uma consulta. Acho que devemos ser capazes de fazer apenas resolvePath.split('?')
e tudo deve funcionar.
Com relação aos erros inconsistentes, vou dar uma olhada se aquele repo os reproduz. Não testei o código ESM com testes em paralelo, apenas um único teste. Não sei por que isso afetaria as coisas, mas quem sabe 😀
O item de consulta
Tenho um problema que acho que pode estar relacionado a isso, mas não foi corrigido em 25.X
.
Vou tentar resumir o cenário abaixo:
{ default: generator } = require(path.resolve(f))
f
não é transpilado causando o "erro inesperado de importação de identificador".Isso também acontece se eu tentar com import ()
Já que você mencionou a transpilação; se você tiver uma configuração que transpila import
em require
esse problema não é o lugar correto - esse problema é sobre o suporte nativo.
Dito isso - você não pode require
ESM, e eu não fui capaz de adicionar suporte para import()
do CJS ainda porque o Node não tem API para ele. O suporte para isso chegou ao Node master, mas ainda não foi lançado: https://github.com/nodejs/node/pull/32985. Como pode ser visto nos PRs de lançamento vinculados, ele virá em 13.14.0 e 14.1.0. Nesse ponto, implementarei suporte para ele 👍
Você deve ser capaz de usar um arquivo de configuração .mjs
.
@SimenB Isso é ótimo, parece estar funcionando em vários arquivos de teste agora! É um pouco complicado resolver as diferenças entre as importações do Babel e do Node em cada arquivo, adicionar a importação jest etc., portanto, posso encontrar mais problemas ao fazer isso em centenas de arquivos de teste.
Algumas coisas que são mais perguntas:
import()
de cjs, isso também permitirá que o arquivo de configuração do Jest seja nomeado jest.config.js
? Atualmente, só funciona para mim quando denominado jest.config.cjs
e usando module.exports =
(o erro é TypeError [ERR_VM_DYNAMIC_IMPORT_CALLBACK_MISSING]: A dynamic import callback was not specified
)node/no-extraneous-import
devido a não ser um pacote listado em package-lock
. Existe algum motivo para essa convenção de nomenclatura? É possível usar jest
sem o @
? É fácil ignorar a regra, mas estou apenas pensando.jest
global é diferente de fns mágicos como test
, describe
, before
, etc.? Todos esses devem ser importados agora também?--experimental-vm-modules
? Isso meio que faz com que isso pareça fora do padrão se não funcionar apenas com o comando jest
. Se você não puder passar sinalizadores diretamente, possivelmente pode definir / alterar a variável NODE_OPTIONS
env?isso também permitirá que o arquivo de configuração do Jest seja nomeado jest.config.js?
Ele pode ser denominado .js
se seu mais próximo package.json
tiver type: 'module'
. Caso contrário, para usar o ESM no arquivo de configuração, ele precisa ser nomeado .mjs
. Consulte https://nodejs.org/api/esm.html#esm_enabling. Observe que o arquivo de configuração é executado fora do Jest, portanto, não temos muito controle. No momento, não oferecemos suporte à configuração assíncrona, mas await
ing uma promessa exportada seria trivial, PR welcome 🙂 # 8357 estagnou.
Estou muito surpreso que você receba A dynamic import callback was not specified
, no entanto, não carregamos o arquivo de configuração em uma VM ... Você poderia abrir um problema separado?
O nome "@ jest / globals" falha na regra eslint
node/no-extraneous-import
devido a não ser um pacote listado empackage-lock
. Existe algum motivo para essa convenção de nomenclatura? É possível usarjest
sem o@
? É fácil ignorar a regra, mas estou apenas pensando.
Você deve adicionar devDependency
em @jest/globals
. O pacote em si é apenas definições de tipo. É um pacote separado de jest
para que as definições de tipo funcionem corretamente e, portanto, podemos lançar um erro se for carregado fora do tempo de execução do Jest.
No momento, não tenho planos de mudar isso, mas podemos suspender o uso desse pacote e exportar os tipos de jest
. Essa é uma mudança importante, então vamos ver mais tarde 🙂
Pergunta relacionada, por que
jest
global é diferente de fns mágicos comotest
,describe
,before
, etc.? Todos esses devem ser importados agora também?
jest
é como require
ou module
objeto do CJS no sentido de que é único por arquivo, não é realmente um global (ou seja, globalThis.jest === undefined
). Isso permite que jest.mock('../../file.js')
etc funcione corretamente em relação ao arquivo em que foi injetado. Você pode escolher importar também os globais reais, mas eles ainda estão disponíveis como globalThis.expect
etc.
Quando isso for finalizado, Jest poderá definir a bandeira
--experimental-vm-modules
?
Acho que vamos esperar que o nó os desmarque em vez de configurá-los silenciosamente - eles estão sinalizados por um motivo, a API pode mudar em algum ponto. Poderíamos adicionar uma opção que defina NODE_OPTIONS
Eu acho, não tenho certeza se isso muda o tempo de execução atual? Apesar de tudo, não há planos atuais para isso.
Parece que agora recebo um erro um pouco diferente do que antes ao tentar isso em um Node mais antigo, mas nenhum dos erros ficou claro de que a versão mínima do Node era o problema. É fácil adicionar uma verificação da versão mínima com uma mensagem de erro mais útil?
Sim, adicionarei uma mensagem de erro melhor junto com alguma documentação assim que a implementação se estabilizar um pouco. Visto que a implementação é protegida por um sinalizador experimental, não acho que alguém vá tropeçar nisso.
@SimenB , atualizei o Jest para 25.5.2 e agora todos os testes estão passando. Os parâmetros de consulta estão funcionando e os erros intermitentes que eu estava vendo antes não estão mais acontecendo. Obrigado novamente por todo o seu trabalho!
Ok, eu vi os erros novamente na minha última execução dos testes, então isso ainda está acontecendo. Vou ver se consigo descobrir uma maneira de reproduzir e relatar de forma consistente.
Acredito ter encontrado uma maneira consistente de reproduzir o problema. Aqui está o branch em que estou trabalhando: https://github.com/beejunk/firn.js/tree/switch-to-jest
Reproduzir:
/tmp/jest_rs
.npm test
três vezes. As duas primeiras execuções devem ser bem-sucedidas. No entanto, a terceira execução deve falhar.Este é o rastreamento de pilha que vejo quando o erro ocorre:
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)
O erro parece ter origem nas importações dinâmicas. Não há mensagem de erro, então não tenho certeza do que está acontecendo.
Uma observação adicional: se eu limpar o cache do Jest e atualizar o script de teste adicionando --no-cache
, não poderei reproduzir o problema.
Heh, fui preguiçoso e não enviei uma mensagem de erro adequada. O problema é que o ambiente de teste foi destruído, então estou supondo que está faltando await
algum lugar. Não vi nada no seu código, então terei que pesquisar mais
@SimenB Aqui está uma reprodução desse problema de configuração do ESM: https://github.com/facebook/jest/issues/9935
@SimenB Eu criei um exemplo mínimo para reproduzir os erros do Jest que mencionei acima ao usar importações dinâmicas:
Obrigado pela ótima reprodução @beejunk! Passei mais horas que gostaria de admitir aqui, sem realmente entender se é um bug no Jest ou no Node. Eu reproduzi o comportamento usando apenas módulos de núcleo de nó e o relatei upstream, então vamos ver o que eles dizem: https://github.com/nodejs/node/issues/33216
Obrigado por investigar, @SimenB. Os testes parecem passar consistentemente se eu adicionar o sinalizador --no-cache
, o que é bom para o meu caso de uso. Agradeço todo o trabalho!
Sim, também percebi isso. Acho que é algum tipo de problema de tempo - sem cache as coisas são lentas o suficiente para funcionar.
@SimenB Obrigado por resolver o # 9935. Mencionei uma segunda preocupação ali, que acho que ainda é válida. Quando type: "module"
, jest --init
ainda está gerando o arquivo de configuração com module.exports
nele. Isso é relativamente pequeno para alterar manualmente se você sabe o que está fazendo, mas acho que se ESM não estiver sinalizado no Node e muitas pessoas começarem a fazer projetos ESM, ele começará a se parecer mais com um bug confuso (ou seja, caminho feliz de jest --init && jest
em um novo projeto ESM causará um erro). Devo enviar um problema diferente especificamente sobre como melhorar a lógica do init?
@aldeed tem certeza? O teste agora me dá um arquivo mjs
com export default
nele. Acho que poderíamos gerar js
e não mjs
, mas ainda assim. Ele usa sintaxe ESM
@SimenB Bem, eu tinha certeza até você perguntar. “Eu tentei e você está correto. Talvez eu tenha feito isso inicialmente com uma versão mais antiga do Node or Jest? Desprezo.
Isso é incrível! Acabei de refazer os testes em uma de minhas bibliotecas para usar os Módulos ES e larguei o Babel. Obrigado @SimenB!
Detectar se um arquivo deve estar no modo ESM ou CJS
Falando nisso, há muitos pacotes orientados a navegador / empacotador usando a sintaxe "module":"<path to es module>"
para denotar suas exportações de módulo ES. Pode ser prudente ter alguma maneira de especificar como resolver um determinado pacote, independentemente das configurações do próprio pacote. Algo como moduleNameMapper
mas para especificar se é CJS ou ESM.
oi @SimenB , assim que este problema for ts-jest
também pode cancelar commonjs
certo? A extensão do arquivo é necessária para mudar do lado do transformador para funcionar com o ESM?
Por exemplo, agora ts-jest
compila ts
para js
para commonjs
, esm
requer extensão de arquivo mjs
ao compilar de ts
a js
?
@zandaqo não suportamos o campo modules
, estaremos seguindo as especificações do nó e usaremos exports
: # 9771. Você pode conectar seu próprio resolvedor para oferecer suporte a modules
se desejar: https://jestjs.io/docs/en/configuration#resolver -string. Podemos adicionar alguma outra opção ( mainFields
, como webpack talvez?), Mas isso virá mais adiante quando a implementação se estabilizar e tivermos menos incógnitas desconhecidas 🙂
@ahnpnl # 9860
Ciao galera!
Só uma pergunta: a postagem do blog menciona que, como os módulos ES6 são estáticos, eles não podem ser simulados; então, na verdade, não há como simular um módulo A importado por um módulo B no ES6?
@gabrieledarrigo Eu uso moduleNameMapper
para isso, por exemplo:
"moduleNameMapper": {
"moduleA": "<rootDir>/test/moduleA-mock.js"
},
@gabrieledarrigo você pode fazer
jest.mock('the-thing-i-want-to-mock', () => /* do whatever in here */);
let importedThing;
beforeAll(async () => {
importedThing = await import('thing-that-imports-mocked-module');
});
Portanto, você só precisa tornar a importação não estática e a simulação funcionará.
Não tenho certeza se funciona agora, pois ainda não conectei resoluções de simulação no caminho do código ESM. Farei isso em algum momento em breve. Mas _provavelmente_ será assim que documentaremos simulações de módulo para ESM nativo.
Conforme mencionado nos pots do blog, iremos documentar esses padrões em algum momento, só temos que descobri-los 🙂
Uma ideia que tivemos foi esperar pelo nível superior, então poderíamos fazer isso com um plugin babel.
@SimenB Em primeiro lugar, obrigado pelo excelente trabalho aqui :)
Na verdade, eu enfrento um problema quando gostaria de criar um ambiente personalizado estendido de jest-environment-node
. Preciso importar minha implementação de servidor para lá, que está escrita como ESM. Mas parece que o ambiente deve ser definido como cjs
.
Minha pergunta é: há uma opção para definir testEnvironment personalizado como esm para poder importar meu módulo de servidor? Obrigado por qualquer conselho.
@ kuka-radovan você poderia abrir uma solicitação de recurso separada para isso?
ATUALIZAÇÃO: este problema agora é rastreado em https://github.com/facebook/jest/issues/10025
@SimenB Obrigado pelo conselho jest.mock
acima. Acontece que estou convertendo alguns arquivos que precisam disso hoje. Posso confirmar que seu exemplo funciona quando o módulo simulado é um pacote node_modules
, mas não está funcionando para mim simular um módulo no mesmo projeto.
Aqui está um exemplo simples:
// 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);
});
O mesmo padrão funciona exatamente quando "./secondary.js"
é um nome de pacote. (Acho que o pacote que experimentei exporta CommonJS, se isso importa.)
Jest 26.0.1 com Nó 12.16.3
Alguma ideia ou devo enviar uma edição totalmente separada?
EDITAR: transform: {}
na configuração, então nada de Babel
EDIT 2: Isso também não funciona:
jest.mock("./secondary.js", () => ({
default: jest.fn()
}));
Trabalho incrível nisso.
No entanto, a menos que eu esteja fazendo algo errado, ainda não parece ser possível usar import()
em um arquivo de teste CJS.
Estou executando o Jest com node --experimental-vm-modules node_modules/jest/bin/jest.js
e tenho testEnvironment: 'node', transform: {}
em jest.config.js
. Isso está no Nó 14.2.0.
A expressão de importação produz erro:
TypeError [ERR_VM_DYNAMIC_IMPORT_CALLBACK_MISSING]:
A dynamic import callback was not specified.
Esta é uma limitação conhecida no momento? Vejo que https://github.com/nodejs/node/pull/32985 agora está no Nó 14.1.0.
Sim, ainda não comecei a implementá-lo. Provavelmente vou pousar neste fim de semana.
@aldeed você poderia abrir um problema separado? Preciso verificar se as simulações fazem parte da resolução e o seu exemplo parece um bom caso de teste 🙂
@SimenB Obrigado pela resposta rápida. Vou ficar atento para quando ele pousar.
Vendo como import
em scripts pode ser revertido devido a uma regressão (https://github.com/nodejs/node/issues/33166), vamos esperar até que se resolva
Estou tendo problemas ao tentar usar isso com .mjs
arquivos de teste. Se eu tiver __tests__/my-test.mjs
, recebo
$ 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.
Se eu adicionar
"testMatch": ["**/__tests__/**/*.mjs"]
para o meu package.json, eu recebo
$ 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.
No entanto, se eu remover "testMatch"
e renomear meu arquivo para __tests__/my-test.js
, ele funcionará.
Eu gostaria de poder usar consistentemente extensões .mjs em meu projeto. Isso é possível com Jest?
@domenic também encontrei isso. A solução é adicionar a configuração "moduleFileExtensions": ["js", "mjs"]
(além de "testMatch"
).
Dei uma olhada e moduleFileExtensions
é realmente necessário.
Jest obtém uma lista de todos os arquivos do projeto executando hasteFS.getAllFiles()
aqui:
hasteFS
é criado como parte de HasteMap
com a seguinte configuração extensions
:
No entanto, não acho que seja necessário especificar moduleFileExtensions
neste caso. Já forçamos .snap
a ser encontrado, devemos forçar extensões JS conhecidas também? Aqueles sendo (em cima da minha cabeça) js
, mjs
, cjs
, jsx
, ts
e tsx
? Isso tornará o rastreamento mais lento, mas não acho que tenha um grande impacto. Posso estar errado, entretanto? Como padrão, não deve ser muito mais lento, pois apenas cjs
e mjs
já não fazem parte dos padrões padrão, mas para pessoas que têm padrões personalizados isso pode desacelerar as coisas?
Sim, seria ideal se, pelo menos no modo de módulos ES, .mjs funcionasse, sem ter que adicionar moduleFileExtensions ou modificar o testMatch padrão.
Também seria bom se eu pudesse excluir arquivos .js; quando eu tentei isso eu consegui
Validation Error:
moduleFileExtensions must include 'js':
but instead received:
["mjs"]
Please change your configuration to include 'js'.
Estou me perguntando se faz sentido ter algum "modo ESM" que adicionaria as extensões de arquivo esm do nó e também ajudaria na compilação para js usando esm para ativar (# 9860).
Sem js
algumas coisas quebram internamente que carregamos dentro da sandbox (já que usa a mesma implementação require
etc). Provavelmente devemos consertar isso para que o usuário não possa nos quebrar.
Em relação à desaceleração, já é bastante lento em grandes projetos, mas não sei se o número de extensões impacta tanto. Mas concordo que mjs e cjs devem ser adicionados como padrões. Especificar moduleFileExtensions: ['js']
substituiria os padrões e aceleraria, certo? Então, talvez apenas documente isso como um ajuste de desempenho.
Obrigado por todo esse trabalho! Certamente é incrível. Eu segui as 3 etapas ( "type": "module"
no meu package.json, "testEnvironment": "jest-environment-node"
na minha configuração de brincadeira e --experimental-vm-modules
na CLI) e parece estar funcionando bem 🎉
Mas então estou tentando ler e usar import.meta
conforme descrito na documentação do Node.js (e que parece já ter sido implementado a julgar pela caixa de seleção) para criar __dirname
, mas parece que import.meta
está falhando:
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.
Não tenho nenhuma babel e pensei que a babel estava ficando para trás com esse trabalho. Voltarei para relatar se posso consertar de alguma forma sem instalar o babel.
Node.js v14.3.0, Jest v25.5.4
Eu encontrei uma solução alternativa por enquanto. Como estou executando o script do mesmo diretório em que meu arquivo está em minha biblioteca , posso apenas fazer:
const __dirname = process.cwd();
const __filename = __dirname + "/files.test.js";
Seguirei este repositório caso haja alguma atualização, obrigado novamente por fazer isso!
Você precisa cancelar explicitamente o Babel usando transform: {}
como configuração
@SimenB Posso confirmar que adicionar transform: {}
funcionou, obrigado! Eu entendi mal esse ponto como "não adicione transformações" e não como "retire as transformações" como pretendido.
BTW, o teste foi de 2,4 segundos para apenas 1,3 segundos e eles parecem consistentemente mais rápidos.
O Nó 12 foi lançado com ESM não sinalizado (https://nodejs.org/en/blog/release/v12.17.0/). Porém, conforme observado no OP, o uso de APIs Jest _não_ não está marcado
@SimenB Eu
Ao executar o Jest 26.0.1, recebo este erro:
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.
Tenho transform: {},
e executando node --experimental-vm-modules node_modules/jest/bin/jest.js
.
o que estou perdendo?
@aldarund não tem certeza, você poderia fazer uma reprodução mínima?
@SimenB aqui está um repo mínimo para repro, apenas execute yarn test
https://github.com/aledalgrande/jest-example - Eu tentei com o Nó 13/14 e é o mesmo resultado. Parece-me que o fluxo da configuração global não foi atualizado para funcionar com o ESM.
Além disso, você mencionou outra pessoa 😆
~ Não @simenB , mas @aledalgrande parece que tudo está correto aqui pelo que tentei, veja meu projeto totalmente rodando no ESM para comparação (configuração de jest em package.json
). ~
~ Para depurar, se possível, sugiro simplificar sua configuração de brincadeira para _apenas_ ter as duas propriedades relevantes, talvez até mesmo no package.json
primeiro. Em seguida, adicione cada uma das outras propriedades que você tem atualmente para ver qual funciona / não funcionou. ~
Ah o segundo comentário menciona globalSetup
e não testes normais, nvm meu comentário então. Se eu remover a chave globalSetup
no Jest, o teste será executado conforme o esperado naquele exemplo, mas a chave globalSetup
não funciona como você disse.
Aha, esqueci-me da configuração e desmontagem global. Pode consertar 👍
Olá @SimenB , eu de novo. As exportações nomeadas são suportadas? Com o Node.js, posso importar e usar um pacote como este:
import { customAlphabet } from "nanoid";
No entanto, ao tentar fazer um teste, o mesmo código dá este erro:
SyntaxError: The requested module 'nanoid' does not provide an export named 'customAlphabet'
Para os testes, posso alterar o código para este e funciona:
import nanoid from "nanoid";
const { customAlphabet } = nanoid;
Mas então a versão Node.js para de funcionar, pois não há esporte padrão (mas por algum motivo a exportação padrão funciona com Jest):
SyntaxError: The requested module 'nanoid' does not provide an export named 'default'
O código publicado (o repo parece estar em fluxo agora) nanoid
termina assim, sem exportação padrão:
export { nanoid, customAlphabet, customRandom, urlAlphabet, random }
Jest consome apenas o ponto de entrada "principal". as "exportações" ainda não são consideradas. Você acabou de importar a versão commonjs que tem apenas exportação padrão.
Ah, entendo, o package.json
parece incluir isto:
"main": "index.cjs",
"module": "index.js",
"exports": {
"./package.json": "./package.json",
".": {
"require": "./index.cjs",
"import": "./index.js",
"browser": "./index.browser.js"
},
...
}
...
Portanto, provavelmente Node.js está encontrando a versão do módulo, enquanto Jest está usando a versão CommonJS que não tem uma exportação nomeada, certo?
Vou esperar até que Package Exports
seja verificado e depois testarei, obrigado por todo o trabalho novamente! Marcando esses 2 comentários como resolvidos até então. O teste a que me refiro é este .
Estou revisitando isso para ver como está funcionando - atualizado para Jest 26.0.1 e nó 14.4. Defina package.json como o tipo de módulo, defina transform como {}
, env como jest-environment-node
e execute node --experimental-vm-modules
. Agora recebo este novo erro:
ES Modules are only supported if your test environment has the `getVmContext` function
Não consegui encontrar informações sobre isso, exceto um changelog de Jest dizendo que getVmContext
tinha sido adicionado um tempo atrás.
Alguma ideia?
Você poderia compartilhar as partes relevantes do seu package.json
please @cyberwombat ? Incluindo o script de lançamento que você está usando para Jest.
Para referência, é assim que parece para mim em um projeto de trabalho :
{
...
"type": "module",
"scripts": {
...
"test": "node --experimental-vm-modules node_modules/jest/bin/jest.js",
},
"jest": {
"transform": {},
"testEnvironment": "jest-environment-node"
},
...
Em seguida, inicie-o com npm test
@franciscop O meu basicamente é o mesmo. Nó 14.4.0. Eu posso administrar o seu bem. Vou mergulhar nas coisas para ver o diff.
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>'
]
}
Roteiro:
node --experimental-vm-modules node_modules/jest/bin/jest.js
Não tenho certeza, mas tentaria fazer o contrário. Remova tudo, exceto transform: {}
e testEnvironment: 'jest-environment-node'
, e comece a adicionar cada uma das opções até ver qual delas dispara o erro anterior. Suspeito especialmente que transformIgnorePatterns
_pode_ estar em conflito com transform
, mas não estou familiarizado com as opções de jest.
Olá pessoal! Tive alguns problemas ao usar o Jest para testar um aplicativo Express. Mais detalhes aqui . Não tenho certeza se isso é útil para o que você está fazendo / rastreando aqui: roll_eyes:
@ x80486 Encontrei exatamente o mesmo problema ontem . Eu respondi no StackOverflow com uma explicação mais longa do meu entendimento.
Edit: Eu mostrei meu comentário anterior, pois parece que pode ser relevante, este "exports"
parece ser popular, muito provavelmente deste artigo sobre pacotes híbridos .
exports
é rastreado em # 9771
@franciscop ok problema resolvido - acontece que há um conflito nos pacotes - eu tinha serverless-bundle
instalado que causava o erro ES Modules are only supported if your test environment has the
getVmContext function
. Não tenho certeza do porquê - eu presumiria que instalá-lo não causaria um conflito de execução, mas evidentemente causa.
@franciscop Acho que a razão pela qual pkg.exports
problemas relacionados comecem a surgir agora é porque esse recurso não estava sinalizado no Node.js 14.x
e alguns mantenedores de pacotes (como eu por uuid
) começaram adicionando campos pkg.exports
. Portanto, embora você precisasse de um sinalizador de linha de comando para ativar esse recurso no Node.js 12.x
você obtém esse comportamento por padrão agora.
Vai demorar um pouco para que todo o ecossistema se adapte, então, obrigado por relatar problemas em torno desse tópico!
Para aqueles que postam sobre exports
, caso tenha se perdido no longo tópico deste problema, meu problema encerrado sobre ele (https://github.com/facebook/jest/issues/9565) tem um exemplo da solução alternativa moduleNameMapper
nele.
O problema globalSetup
relatado em maio provavelmente ainda está lá (Jest 26.1.0)? Obtendo os mesmos erros que no exemplo repo @aledalgrande fornece:
$ 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
Sem pressa. Verificado CHANGELOG
e não mencionou uma correção para globalSetup / globalTeardown com ES6.
Node.js 14.4.0, Jest 26.1.0
Atualização (13 de agosto de 20):
Ainda não é possível, Node.js 14.7.0, Jest 26.4.0
Opinião lateral, mas esse problema deveria ser um problema fixo, já que é o foco de brincadeira no momento?
Alguma ideia do que precisa ser feito para consumir repórteres de teste escritos em módulos ES? ...
com a versão mais recente do jest, estou recebendo um erro que diz essencialmente que o testScheduler espera um repórter personalizado no formato commonjs.para ver o erro
~ / projects / esw-ts / lib / dist / test / testReporter.js: 1
importar os de 'os';
^^^^^^
SyntaxError: Não é possível usar a instrução de importação fora de um módulo
em wrapSafe (internal / modules / cjs / loader.js: 1116: 16)
em Module._compile (internal / modules / cjs / loader.js: 1164: 27)
em Object.Module._extensions..js (internal / modules / cjs / loader.js: 1220: 10)
em Module.load (internal / modules / cjs / loader.js: 1049: 32)
em Function.Module._load (internal / modules / cjs / loader.js: 937: 14)
em Module.require (internal / modules / cjs / loader.js: 1089: 19)
em require (internal / modules / cjs / helpers.js: 73: 18)
em /Users/manish.gowardipe/Desktop/projects/esw-ts/lib/node_modules/@jest/core/build/TestScheduler.js:418:65
em Array.forEach (
em TestScheduler._addCustomReporters (/Users/manish.gowardipe/Desktop/projects/esw-ts/lib/node_modules/@jest/core/build/TestScheduler.js:411:15)
Olá, quero testar o suporte nativo para módulos ES em meu pequeno projeto, mas sou novo no NodeJS e me perdi nesta edição. Adoraria alguma orientação, por favor.
node --version
: v14.5.0yarn jest --version
: 26.1.0package.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);
});
Eu corro yarn jest .
e isso me dá este erro:
Tentei com node node_modules/jest/bin/jest.js .
e deu o mesmo erro.
@ pepetorres1998 Este tópico é sobre a execução de Jest com módulos esm nativos que envolvem a execução de coisas com certas sinalizações / opções - veja o comentário acima para saber o que fazer (e definir "type": "module" em package.json). Honestamente, porém, neste momento não está totalmente pronto para o horário nobre, então se você está precisando que seu projeto funcione, posso ficar com Babel. Há uma série de problemas não verificados que realmente impedem o show. Eu tentei mudar alegremente algumas semanas atrás e voltei chorando para Babel.
Alguém está recebendo um ReferenceError: jest is not defined
ao tentar fazer coisas como jest.setTimeout(...)
em um arquivo de teste com esta configuração? Tentar descobrir se isso está relacionado ao ambiente do módulo, versão do nó, versão da brincadeira ou alguma combinação dessas coisas. (Atualmente usando o nó v14.5.0, jest 26.1.0, ambiente jest-ambiente-nó)
EDITAR
Agora vejo a caixa de seleção desmarcada na descrição do problema para a propriedade 'global' do jest. 🙃
@bdentino , acho que você pode tentar importá-lo explicitamente import {jest} from '@jest/globals';
25.4.0 foi lançado com as primeiras peças de suporte. Além do # 9772 mencionado acima, também incluí o # 9842. Na _teoria_, a mistura de CJS e ESM deve funcionar corretamente agora (🤞).
O único recurso que falta é o suporte ao objeto
jest
. Ainda não decidi se devemos mantê-lo emimport.meta
ou exigir que as pessoas o importem através deimport {jest} from '@jest/globals'
. Agradecemos o feedback!Eu não escrevi documentos para isso ainda, mas para ativá-lo, você precisa fazer três coisas
- certifique-se de não executar as instruções transform
import
(definatransform: {}
na configuração ou então certifique-se de quebabel
não transforme o arquivo em CJS, evitando omodules
opção para predefinir o env)- Execute
node@^12.16.0 || >=13.2.0
com a bandeira--experimental-vm-modules
- Execute seu teste com
jest-environment-node
oujest-environment-jsdom-sixteen
Experimente e forneça comentários! Se relatar bugs, seria maravilhoso se você também pudesse incluir como a execução do mesmo código (sem qualquer código específico de teste) é executado no Node. Eu li https://nodejs.org/api/esm.html _muito_ nas últimas semanas, mas provavelmente deixei passar algo.
@SimenB
Este tópico se tornou enorme, e eu acho que aqueles que querem começar com módulos ES de brincadeira / uso - terão dificuldade em encontrar e entender as diretrizes básicas para começar a fazê-lo.
Existe uma explicação formal nos documentos sobre como adicionar jest a um projeto de módulos ES (ou algum 'início rápido')?
@aldeed Com relação ao seu problema com módulos de simulação do mesmo projeto, você encontrou uma solução? Estou tendo exatamente o mesmo problema
(Aliás, nós também usamos o responsecommerce, então brinde a isso haha)
@guilhermetelles não, e é rastreado em https://github.com/facebook/jest/issues/10025 agora.
Estou usando o Jest 26.1.0, node
versão 14.6.0 com --experimental-vm-modules
, mas ainda estou vendo ERR_VM_DYNAMIC_IMPORT_CALLBACK_MISSING
ao usar import()
dentro do CommonJS . Devo tentar criar uma reprodução mínima e abrir um novo problema?
Como um aparte, existe uma maneira fácil de yarn link
uma cópia de jest
pacotes em um projeto agora que Jest usa yarn berry? Eu queria experimentar o master
mais recente apenas no caso de isso ter sido implementado por ainda não lançado. Eu estava tentando fazer algo como path/to/facebook/jest/.yarn/releases/yarn-sources.cjs link --all path/to/jest
, mas não deu certo. Executar 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
também não estava funcionando, não sei por quê.
@vvanpo import()
no CJS foi revertido no Node, você pode seguir https://github.com/nodejs/node/issues/31860
Quanto à execução local, geralmente desinstalo jest
do projeto que quero testar e faço ../jest/jest
. Potencialmente nose ../jest/packages/jest/bin/jest.js
. Apenas certifique-se de executar yarn
e yarn build:js
primeiro. Se essas instruções não funcionarem (estou escrevendo de memória em um telefone em um avião), abra um problema (ou PR) para que possamos escrever corretamente no arquivo CONTRIBUTING.md
Você planeja oferecer suporte a importações cíclicas?
Se eu tiver um arquivo de teste fictício que importa apenas um dos dois arquivos que importam apenas um ao outro, obtenho RangeError: Maximum call stack size exceeded
. Se eu remover uma das importações, o teste será aprovado. Repo que reproduz o problema .
Ei! Eu configurei isso em um projeto de nó vazio e funcionou muito bem, no entanto, em nossa configuração de produção, recebo a seguinte mensagem de erro quando estou tentando executar testes:
ES Modules are only supported if your test environment has the 'getVmContext' function
Eu vi outra pessoa tendo algum problema em uma resposta anterior (por @cyberwombat ), mas o pacote que eles descobriram ser o culpado não está presente em nosso arquivo package.json
. Como deduzir o pacote (ou configuração) que causa o problema? Tentei remover sistematicamente todas as configurações de gracejo desnecessárias para fazer este trabalho, mas não tive sucesso.
ATUALIZAÇÃO : consegui progredir fazendo uma pequena alteração em jest-runtime
. Parei o depurador na linha que tenta acessar o contexto da VM e, embora a função realmente não exista, this.context
(que deve retornar) existe, então mudei essa linha para acessar a propriedade diretamente. Eu sei que provavelmente não é o ideal, mas talvez @SimenB isso possa lhe dar uma ideia do que está errado.
Obrigado desde já por qualquer ajuda
Você planeja oferecer suporte a importações cíclicas?
Com certeza! Você poderia abrir um problema separado?
@zsombro parece que você está executando uma versão antiga do ambiente de teste. Se você executar jest --show-config
, o que é exibido por testEnvironment
?
parece que você está executando uma versão antiga do ambiente de teste. Se você executar
jest --show-config
, o que é exibido portestEnvironment
?
@SimenB diz o seguinte:
"testEnvironment": "/Users/zberki/git/project-name/node_modules/jest-environment-node/build/index.js",
"testEnvironmentOptions": {},
Acabei de definir como jest-environment-node
base nas suas instruções
Antes de iniciar este processo, atualizei o jest usando yarn add jest@latest
. Devo atualizar o ambiente separadamente?
ATUALIZAÇÃO: Acontece que eu tinha que fazer. Excluí node_modules
e yarn.lock
para fazer uma instalação limpa e ainda não funcionou. No entanto, se eu adicionar manualmente usando yarn add -D jest-environment-node
, parece funcionar. Existe uma maneira melhor de gerenciar isso? Fiz um projeto de teste minimalista antes de fazer isso em nossa base de código e não tive que fazer isso
yarn list jest-environemnt-node
(ou npm list jest-environemnt-node
) provavelmente listará vários, é meu palpite
├─ [email protected]
│ └─ [email protected]
└─ [email protected]
a versão 26.2.0
é provavelmente a que instalei manualmente (pelo menos com base em package.json
, o que significa que jest-config
instalou uma versão aparentemente desatualizada?
Você tem outra coisa puxando uma versão mais antiga de jest-config
( react-scripts
talvez (parte de create-react-app
)?). Este assunto não é o lugar para discuti-lo, embora 🙂
Não poder usar módulos ES em meu globalSetup
está começando a doer.
Dois pontos:
EU:
"testEnvironment": "jest-environment-node",
em jest.config.jsonimport { jest } from '@jest/globals';
sempre que o jest foi usado--experimental-vm-modules
executando-os com NODE_OPTIONS='--experimental-vm-modules' yarn jest
E ele trava no seguinte código:
jest.mock('../../some/other/path', () => ({
someOtherMethod: jest.fn().mockImplementation(…),
}));
com o seguinte erro (abreviado - nota "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.
Não posso usar o Babel porque ele analisa incorretamente as importações que corrigi para executar no Nó 14 sem Babel:
-import { map } from 'lodash';
+import lodash from 'lodash';
+const { map } = lodash;
Que, infelizmente, é analisado incorretamente por @babel/preset-env
, resultando em TypeError: Cannot destructure property 'map' of '_lodash.default' as it is undefined.
.
Alguém pode me ajudar a solucionar esse problema?
Edit: Parece que você _pode_ usar Jest + Babel em código compatível com módulos ES nativos usando importações CommonJS fazendo esta correção absolutamente nojenta:
jest.mock('common-js-module', () => ({
__esModule: false,
...jest.requireActual('common-js-module'),
}));
Por aqui,
import lodash from 'lodash';
const { map } = lodash;
é perfeitamente consumido pelo Nó 14, e o código resultante da execução de Jest + Babel,
var _lodash = _interopRequireDefault(require("lodash"));
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
const {
map
} = _lodash.default;
também funciona.
convertemos com sucesso todos os nossos testes de jest para usar e importar nosso código ES6, mas ficamos presos em alguns pacotes: a saber puppeteer
e uuid
O aplicativo só funciona se nós os importarmos para um objeto (como import uuid from 'uuid'
), mas os testes não serão executados dessa forma. No entanto, se substituirmos essa importação pela sintaxe de desconstrução (como import { v4 } from 'uuid'
, será o contrário: o teste funciona, mas o aplicativo lança uma exceção.
originalmente, seguimos o guia e desligamos todas as transformações, mas também tentamos criar um espaço de trabalho de fios onde instalamos o babel com uma configuração de nó mínima, mas isso não resolveu (ou piorou) este problema específico
No entanto, se substituirmos essa importação pela sintaxe de desconstrução (como import {v4} de 'uuid', será o contrário: o teste funciona, mas o aplicativo lança uma exceção.
Parece que seu aplicativo foi compilado para CommonJS e não está usando módulos na prática. Do ESM "real" import uuid from 'uuid'
não deve funcionar porque uuid
não tem exportação padrão e expõe uma construção ESM para o nó .
Olá @SimenB , você acha que alguma documentação preliminar sobre isso seria uma boa ideia?
@grantcarthew definitivamente! Eu esperava poder gastar mais tempo nisso e estabilizá-lo para Jest 27, mas duvido que consiga fazer isso. Mas escrever uma página de documento sobre o que está lá agora (e que é experimental) parece uma boa ideia
@SimenB Não sei qual é o estado atual do problema e se Jest já deve trabalhar com meu caso ou não, mas talvez possa ajudá-lo de alguma forma.
Estou tentando carregar uma biblioteca somente ESM (sua extensão é cjs, mas o tipo é módulo e o nó parece estar ok com isso), mas Jest não consegue carregá-la corretamente com o erro:
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) {
Aqui, o problema que abri originalmente https://github.com/codemirror/codemirror.next/issues/310. E uma reprodução para Jest + ESM falhando com o nó 14.13.1 https://github.com/dubzzz/codemirror-next-repro-cra/tree/main/test-in-jest-esm
@dubzzz você não pode ter ESM em um arquivo cjs
. O nó também falha
$ 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
Oups, desculpe, tentei muito rapidamente no lado do nó. @ nicolo-ribaudo já notificou o autor da lib sobre este problema.
Muito obrigado pela sua resposta rápida.
Abri um PR para alguns documentos (praticamente stub) aqui: # 10611. Não me incomodei em enumerar os recursos / bugs ausentes, pois acho que será difícil manter a sincronia com a realidade, e olhar para os problemas do github é uma abordagem melhor, visto que estão (com sorte ...) atualizados.
@Pomax como um novo problema, por favor 🙂
Acabei de abrir o # 10620, que adiciona suporte para import()
da CJS. Solicitados algumas vezes são como https://github.com/facebook/jest/issues/9430#issuecomment -626054595
Olá. É muito difícil para mim abraçar rapidamente toda a história por trás do ESM em node / jest, então, provavelmente, estou perguntando algo óbvio ou já respondido. Eu entendi corretamente que o caso a seguir ainda não é compatível? Ou, espero, estou fazendo algo que não está da maneira correta? Percebi que import x from 'x'
funciona, mas a desestruturação de import { sub } from 'x'
não.
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('', () => {});
teste 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.
Você está esperando pelo # 9771. Antes disso, Jest não sabe que é seguro carregar uuid
como ESM (ou melhor, qual arquivo carregar em qual ponto ele saberia que é ESM)
Isso seguirá a convenção do próprio Node, em que CJS só pode ser carregado como namespace, ou isso "melhorará" permitindo uma sintaxe que não funciona no próprio Node? (por exemplo, o Node não permite import { readdirSync } from "fs-extra"
porque é um pacote CJS, mas permite import fs from "fs-extra";
que pode então ser descompactado usando const { readdirSync } = fs
).
(por exemplo, o Node não permite importar {spawn} de "child_process" porque é um pacote CJS, mas permite importar child_process de "child_process"; que pode então ser descompactado usando const {spawn} = child_process;).
Este é um exemplo infeliz porque o nó considera "child_process" como um módulo "embutido" (e não CJS), então as exportações nomeadas funcionam. O nodejs mais recente também usa uma heurística para fazer muitas exportações nomeadas funcionarem para módulos CJS. Essa pode ser a parte mais difícil de imitar.
exemplo atualizado para usar fs-extra
lugar. Mas se a exportação nomeada está no roteiro do Node para pousar neste ou no próximo importante, então Jest antecipar isso faz sentido.
Isso já deve estar implementado - os módulos principais do nó expõem as exportações nomeadas, o CJS "normal" não.
O nodejs mais recente também usa uma heurística para fazer muitas exportações nomeadas funcionarem para módulos CJS. Essa pode ser a parte mais difícil de imitar.
Você tem um link para o PR que o implementa? Devemos tentar imitá-lo pelo menos 🙂
O PR está aqui: https://github.com/nodejs/node/pull/35249
A heurística por trás disso é publicada como cjs-module-lexer
(https://github.com/guybedford/cjs-module Budaper ), mas
Acabei de dar uma olhada e parece que fs-extra
está usando um padrão de exportação 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')
}
Este não é atualmente um caso de análise de reexportação que detectamos, mas pode ser possível adicionar a cjs-module-lexer se esse for um caso útil para lidar com a detecção de exportações nomeadas.
Obrigado @jkrems & @guybedford! Eu abri um PR agora usando esse módulo: # 10673
O suporte fs-extra exato descrito em https://github.com/facebook/jest/issues/9430#issuecomment -713204282 agora está implementado em cjs-module [email protected] , rastreamento upstream em https: // github. com / nodejs / node / pull / 35745.
_Update: testando esta compilação, ele detecta corretamente todas as funções fs-extra, mas infelizmente não detecta as funções nativas do Node.js, pois elas não são estaticamente analisáveis devido a serem preenchidas por um loop for._
talento: suporta exportações nomeadas de CJS como importações ESM # 10673
Achei que o ESM nativo só oferecesse suporte à importação de exports
um módulo CommonJS como default
?
@trusktr não mais: https://github.com/nodejs/node/pull/35249
Olá. É muito difícil para mim abraçar rapidamente toda a história por trás do ESM em node / jest, então, provavelmente, estou perguntando algo óbvio ou já respondido. Eu entendi corretamente que o caso a seguir ainda não é compatível? Ou, espero, estou fazendo algo que não está da maneira correta? Percebi que
import x from 'x'
funciona, mas a desestruturação deimport { sub } from 'x'
não....
importar {v4} de 'uuid';
Os módulos ESM não oferecem suporte a importações de desestruturação, embora a sintaxe seja semelhante a isso. Para que isso funcione, 'export v4' é necessário. 'export default' não corresponderá.
https://kentcdodds.com/blog/misunderstanding-es6-modules-upgrading-babel-tears-and-a-solution
@sdwlig uuid
fornece exportações nomeadas e não possui uma padrão. Deve funcionar, mas o carregamento do esm de pacotes com o campo "exportações" ainda não é suportado pelo jest. Em vez disso, o Commonjs é carregado, o que só está disponível por meio da exportação padrão.
https://github.com/uuidjs/uuid/blob/master/src/index.js
Podemos adicionar suporte de auto-referência de pacote (# 10883) a isso?
Comentários muito úteis
Consegui suporte básico com o # 9772. Eu testei apenas os casos mais simples, e há muitas limitações conhecidas (principalmente sem suporte a objeto
jest
e semântica quebrada ao misturar CJS e ESM), mas pelo menos é _algo_. Ele será lançado na próxima versão do Jest (espero que em breve, apenas bloqueado por # 9806)