Mocha: Suporta testes de estilo ES6 sem uso de transpilador

Criado em 18 set. 2017  ·  75Comentários  ·  Fonte: mochajs/mocha

Pré-requisitos

  • [x] Verificado se seu problema ainda não foi arquivado por meio de referência cruzada de problemas com o rótulo common mistake
  • [x] Verificamos problemas de ES de última geração e problemas de sintaxe usando o mesmo ambiente e/ou configuração de transpilador sem Mocha para garantir que não seja apenas um recurso que realmente não é suportado no ambiente em questão ou um bug em seu código .
  • [x] 'Smoke testou' o código a ser testado executando-o fora do conjunto de testes real para ter uma melhor noção se o problema está no código em teste, no uso do Mocha ou no próprio Mocha
  • [x] Garantiu que não há discrepância entre as versões do Mocha instaladas local e globalmente. Você pode encontrá-los com:
    node node_modules/.bin/mocha --version (Local) e mocha --version (Global). Recomendamos evitar o uso de Mocha instalado globalmente.

Descrição

Antes de começar, já existem algumas questões encerradas em relação a este tópico mas como os pré-requisitos mudaram gostaria de iniciar uma nova tentativa.

Agora que o nó suporta a execução de módulos EMCAScript (sim, eu sei que é experimental), seria ótimo ver o mocha trabalhar em conjunto com as definições de teste mjs .

Passos para reproduzir

Eu tenho um teste muito simples

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

Que eu salvei como test.js e test.mjs

Comportamento esperado: gostaria que ambos os testes mostrassem

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

Comportamento real: Enquanto o teste js funciona, o teste mjs me dá

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

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

Reproduz com que frequência: 100%

Versões

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

Informações adicionais

Eu _acho_ que isso pode ser que o runner do mocha esteja usando commonjs e a implementação atual do nodejs não permite usar módulos ECMAScript de um contexto commonjs.

Por favor, não responda com "use um transpiler", eu quero explicitamente não usar um.

Edit: em uma versão anterior, usei acidentalmente jsx em vez de mjs.

feature usability

Comentários muito úteis

Implementamos o suporte nativo ao ESM do Node no Mocha v7.1.0.

Todos 75 comentários

Pensamentos iniciais em cima da minha cabeça, antes de fazer qualquer pesquisa adicional:

  • Parece que me lembro que as pessoas do Node alteraram especificamente o padrão para permitir a compatibilidade com os módulos CommonJS. Se isso for (ainda?) verdade, então eu esperaria que eventualmente ele fosse suportado sem a necessidade de fazer nada com o Mocha. (E por "eventualmente" quero dizer "possivelmente ainda mais rápido que o Mocha muda", dada a taxa do ciclo de lançamento do Node; veja o enfatizado, penúltimo abaixo para uma explicação mais detalhada sobre isso.)
  • Posso assumir que isso foi executado como node --experimental-modules node_modules/mocha/bin/_mocha ?
  • Como exatamente .jsx está envolvido? Vejo que o exemplo de erro mostrado se refere a .mjs ; não está claro, pelo que foi postado, onde está o jsx .
  • Também me lembro vagamente de ter ouvido falar da implementação inicial do Node exigindo a extensão de arquivo .mjs ; se isso for (ainda?) verdade, e se você estiver tentando usar import / export com um arquivo .jsx (ou import ing um .jsx no arquivo .mjs ou carregando um arquivo .jsx que contém import / export ), esse poderia ser o problema em vez do Mocha?
  • Precisaríamos encontrar uma maneira de garantir que as alterações no recurso experimental não exijam alterações no Mocha que teriam que esperar por um semestre maior - caso contrário, você pode acabar de volta onde estamos agora, exceto esperando ainda mais (já que o ciclo de lançamento principal do Mocha não está bloqueado para duas vezes por ano como o do Node).
  • Falando puramente da minha opinião e não em nome da equipe, se o novo formato do módulo não puder interoperar com o formato do módulo antigo sem modificar as bibliotecas existentes escritas no formato antigo, o novo formato do módulo ainda não está pronto .

Parece que me lembro que as pessoas do Node alteraram especificamente o padrão para permitir a compatibilidade com os módulos CommonJS. Se isso for (ainda?) verdade, então eu esperaria que eventualmente ele fosse suportado sem a necessidade de fazer nada com o Mocha. (E por "eventualmente" quero dizer "possivelmente ainda mais rápido que o Mocha muda", dada a taxa do ciclo de lançamento do Node; veja o enfatizado, penúltimo abaixo para uma explicação mais detalhada sobre isso.)

Da minha (pequena) pesquisa, parece que pelo menos por enquanto é permitido usar require de um módulo ECMAScript, mas não import de um módulo commonjs.

Posso assumir que isso foi executado como node --experimental-modules node_modules/mocha/bin/_mocha?
Como exatamente o .jsx está envolvido? Vejo que o exemplo de erro mostrado se refere a .mjs; não está claro, pelo que foi postado, onde está o jsx.

Sim, foi executado com --experimental-modules . jsx é um erro de digitação, eu quis dizer mjs , atualizará o post inicial.

Também me lembro vagamente de ouvir sobre a implementação inicial do Node exigindo a extensão de arquivo .mjs; se isso (ainda?) for verdade, e se você estiver tentando usar importar/exportar com um arquivo .jsx (importando um arquivo .jsx em um arquivo .mjs ou carregando um arquivo .jsx que contém importação/exportação), isso poderia ser o problema em vez de Mocha?

O problema parece ser, e posso estar perdendo algo aqui, que o mocha usa require para carregar o teste (essa é pelo menos minha suposição atual, pois não sou um especialista em mocha, mais um usuário) que então inclui outros módulos via import . Isso em conjunto com o primeiro ponto explicaria o erro.

Precisaríamos encontrar uma maneira de garantir que as alterações no recurso experimental não exijam alterações no Mocha que teriam que esperar por um semestre maior - caso contrário, você pode acabar de volta onde estamos agora, exceto esperando ainda mais (já que o ciclo de lançamento principal do Mocha não está bloqueado para duas vezes por ano como o do Node).
Falando puramente da minha opinião e não em nome da equipe, se o novo formato do módulo não puder interoperar com o formato do módulo antigo sem modificar as bibliotecas existentes escritas no formato antigo, o novo formato do módulo ainda não está pronto.

Eu estava com medo de que essa fosse a resposta e entendo que isso não é uma prioridade. Se minha suposição da causa do erro acima estiver correta, algo como # 956 pode ajudar, pois o ponto de entrada do teste pode ser um módulo mjs em vez de commonjs, o que provavelmente é difícil de alcançar de outra forma. Parece estar no roteiro da equipe do nodejs oferecer suporte a import dos módulos atuais, mas não está claro sobre os cronogramas.

Da minha (pequena) pesquisa, parece que pelo menos por enquanto é permitido usar require de um módulo ECMAScript, mas não importar de um módulo commonjs.

Parece estar no roteiro da equipe do nodejs oferecer suporte à importação dos módulos atuais, mas não está claro sobre os cronogramas.

Para esclarecer: dado que em ambientes "mais antigos" (em alguns casos não experimentais atuais) import é um erro de sintaxe, que não pode ser evitado com lógica de ramificação ou algo assim, o que o Mocha precisa não é poder usar import si, mas sim poder usar require para carregar módulos que usam (ou que usam módulos que usam) o novo formato.

jsx é um erro de digitação, eu quis dizer mjs , atualizará o post inicial.

Obrigado, isso elimina um ângulo possível!

Se minha suposição da causa do erro acima estiver correta, algo como # 956 pode ajudar, pois o ponto de entrada do teste pode ser um módulo mjs em vez de commonjs, o que provavelmente é difícil de alcançar de outra forma.

Fazer com que o Mocha não crie variáveis ​​globais infelizmente não é possível sem uma extensa reescrita de alguns dos internos mais misteriosos (eu tentei e não consegui descobrir sozinho 😿); no entanto, usar seu próprio ponto de entrada JS é possível agora através da API "programática" (que pode não ser documentada fora de uma página wiki antiga e dos comentários JSDoc nos arquivos de origem, mas é oficialmente suportado):

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

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

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

Na verdade, eu não tentei isso para ver se faz diferença (precisa pegar a versão mais recente do Node primeiro), mas deixe-me saber se funciona para você ...

Em primeiro lugar, obrigado por seu apoio sobre isso!

eu tentei isso

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

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

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

Então, basicamente, tornou o ponto de entrada do nó um módulo ECMAScript.

Eu corro por node --experimental-modules --harmony ./runner.mjs

eu recebo

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

o que o Mocha precisa não é poder usar import si, mas sim poder usar require para carregar módulos que usam (ou que usam módulos que usam) o novo formato.

Infelizmente, isso não é possível no momento, você só pode usar require em módulos que você importou via import . Existe uma maneira de evitar mocha.addFile('./test/frontend/components/global/test.mjs'); e, em vez disso, importar o teste e adicionar o script importado assim

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

?

Não há nenhuma função como essa no Mocha no momento, mas você pode fazer algo nesse sentido. addFile apenas anexa o arquivo a uma lista que é posteriormente require d pela função run . A função run chama loadFiles para require eles:

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

O que você gostaria de fazer é para qualquer arquivo que precise ser import ed em vez de require d não chame addFile (para que o Mocha não tente require em run ) e antes de chamar run chame algum código parecido com o que está em loadFiles mas usando import em vez de require . Não me lembro de cabeça se existem restrições ao uso de import que impediriam isso, mas se for possível, imagino que seria bem próximo a:

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

Você também pode ver como https://github.com/mochajs/mocha/blob/master/bin/_mocha usa a API programática do Mocha para ter uma noção de como fornecer outras opções e como usar coisas como a funcionalidade de pesquisa de arquivos do Mocha. Não está muito bem organizado, mas tudo que a interface de linha de comando faz está lá (seja diretamente ou porque há uma chamada para as funções na API programática do Mocha).

Eu posso dar um passo adiante, mas o teste importado agora reclama que não sabe descrever ( ReferenceError: describe is not defined ). Qual é a maneira correta de injetá-lo? Se eu fizer

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

reclama TypeError: describe is not a function

Então, minha distro finalmente obteve o NodeJS 8.5, e eu tive a chance de brincar com isso e confirmar alguns palpites que eu tinha, mas não queria declarar até poder verificar:

  1. Não consigo encontrar nenhuma maneira de carregar um módulo ES sem codificar seu nome em um arquivo de script/módulo. Isso significa que o Mocha não pode carregá-los através da interface de linha de comando, não importa o que façamos e independentemente de qualquer outra semântica ES versus CommonJS. Se e quando isso mudar, vamos querer saber, eu acho. (Se mudar de tal forma que o módulo ES possa ser carregado através de uma variável require provavelmente não precisaremos mudar nada, mas acho que não podemos dizer nada sobre como os módulos funcionam com certeza até que isso aconteça .)
  2. Enquanto o Mocha configura a interface na emissão do evento pre-require (não quando o módulo é carregado pela primeira vez; a interface escolhida é específica para a instância new Mocha ), o novo sistema do módulo analisa a árvore de dependências e carrega as dependências antes dos módulos que dependem delas, então o motivo describe não estar definido é que o Mocha não está configurando até que os módulos de teste sejam carregados. Isso significa que será complicado para que isso aconteça (novamente, a menos que e até que require(file) seja permitido e carregue a dependência nessa linha específica, de preferência de forma síncrona, para não precisarmos alterar mais nada ).

No entanto, descobri que posso fazê-lo funcionar explorando o fato de que os módulos import ed são carregados na ordem das chamadas import . (Seria muito mais redundante se você usasse a interface Exports ou um repórter que precisasse do nome de cada arquivo individual, conforme descrito no código que estou prestes a vincular, mas em princípio funciona.) Se esse fato fosse mudar sem que nenhum dos outros fatos acima mudem, então mesmo isso não seria possível. Mas por enquanto eu acho que isso é o que você teria que fazer.

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

node --experimental-modules ./run.mjs

Infelizmente, tenho quase certeza de que é o melhor que podemos fazer, dada a maneira como os módulos ES funcionam e o que o Node permite no momento.

Pense de outra forma:

  • import é a sintaxe.
  • require é uma função.

Você não pode import dinamicamente nada, assim como você não pode executar código dinamicamente sem o uso de, por exemplo, eval() .

Existe esta proposta de estágio 3 que permitiria esse comportamento, mas não tenho certeza se algum tempo de execução ainda está enviando.

Como tal, não há como o Mocha importar um arquivo .mjs ao executar via mocha sem adicionar talvez @std/esm e usar sua implementação require para arquivos com o .mjs extensão. Essa pode ser uma solução viável e algo que poderíamos considerar apoiar, mas uma discussão (e tal PR) provavelmente precisaria vir da comunidade, pelo menos até que esse comportamento não esteja por trás de uma bandeira.

import describe from 'mocha' está bem baixo na lista de prioridades, infelizmente, devido à dificuldade inerente em torno desse tipo de coisa (#956). Melhor correr com node e continuar consumindo os globais.

Na verdade, me ocorre que poderíamos carregar os testes e alavancar vm.runInContext , supondo que tal coisa suporte módulos. Como o comportamento de carregamento do Node está vinculado à extensão .mjs e vm.runInContext espera uma string , não vejo como isso poderia - e não há nada mencionado sobre isso nos documentos. Talvez um problema em algum lugar?

(então, novamente, isso pode ser exatamente o que @std/esm faz sob o capô!)

Eu tenho testes de mocha funcionando sem transpilador em um navegador . Talvez ajude para esta questão.

isso não está relacionado, pois você não está puxando mocha como um módulo, mas sim como um script ...

desculpe me confundi. é diferente em um navegador.

Eu quero pesar com um voto de apoio para fazer algo para permitir que o Mocha execute testes localizados em um Módulo ES. Cheguei aqui depois de tentar escrever tal teste e receber um erro estranho do carregador de módulo Node.js. Estou usando o Node.js 9.5, que oferece suporte nativo aos módulos ES6.

Como está atualmente, o Node.js 9.5 não permite que um módulo CommonJS requeira() um módulo ES6. Talvez estejam trabalhando no sentido de permitir isso, não sei.

Eu escrevi o teste como um módulo ES6 com a extensão .mjs e tentei executá-lo. Recebi o erro do carregador - suponho que o comando mocha resulta no uso de require() e é por isso que falhou.

Refiz o teste com a extensão .js e tentei usar require() para carregar o módulo que seria testado. Isso também recebeu o erro do carregador.

Eu sou da opinião de que o mundo Node.js precisa considerar como eles vão migrar e oferecer suporte aos módulos ES6. Como o Mocha é uma ferramenta muito popular neste mundo, seria melhor para a equipe do Mocha considerar como oferecer suporte aos módulos ES6.

Para acompanhar... Depois de refletir e pesquisar, consegui fazer com que essa sequência funcionasse como uma solução alternativa.

Nomeie o script de teste com a extensão .js (tornando-o um script CommonJS)

Em seguida, adicione isso no script de teste:

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

Então eu posso require() um módulo ES assim:

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

@robogeek Ou pode ser ainda melhor usar o pré-carregador @std/esm da linha de comando, para que você não precise sobrecarregar seus arquivos de especificação com soluções alternativas e pode ter extensões .mjs .

mocha -r @std/esm spec.mjs

A importação dinâmica é fornecida com o nó v9.6 atrás do sinalizador --harmony-dynamic-import . As importações dinâmicas permitem que o mocha carregue os testes contidos nos módulos es6 sem a necessidade de um transpilador.

@harrysarson Não vai funcionar fora da caixa. Mocha usa módulos cjs e require , você teria que escrever os arquivos de teste usando cjs, com algum código de cola adicional para lidar com a natureza assíncrona de import . Ou eu estou esquecendo de alguma coisa?

Eu sou um bot que observa problemas de inatividade.
Este problema não teve nenhuma atividade recente e estou rotulando-o de stale . Em 14 dias, se não houver mais comentários ou atividades, encerrarei esta questão.
Obrigado por contribuir com o Mocha!

O problema ainda é relevante, mas conta com suporte nativo para ESM. Os navegadores têm, o Node ainda não.

Eu estava apenas brincando, me familiarizando com ESM/.mjs e decidi que precisava de testes para o meu brinquedo. Percebendo que o mocha ainda não suporta oficialmente arquivos .mjs , eu junto um módulo provisório rápido (até que alguém tenha tempo de adicionar suporte completo ao mocha):

https://www.npmjs.com/package/mocha-esm
PRs/questões bem-vindos: https://github.com/stefanpenner/mocha-esm

Pode haver algo melhor lá fora, mas foi divertido passar juntos. então \o/

Decidi fazer o fork do mocha para suportar importações dinâmicas (com base em algumas ideias acima, mas não consegui executá-lo de outra maneira).

Isso significa que você pode executar usando, por exemplo node --experimental-modules --harmony-dynamic-import test.mjs

Então em test.mjs :

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

const mocha = new Mocha();

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

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

Eu mantive as alterações no mocha para suportar isso mínimo , e não tive tempo de integrar isso corretamente para um possível PR nem adicionei um módulo npm especializado, mas você pode instalar este fork do github diretamente "mocha": "git+https://[email protected]/odolha/mocha" .

Observe que você pode usar essa abordagem para carregar arquivos de qualquer maneira assíncrona que desejar, não apenas por meio de importação dinâmica, pois o mocha espera uma função que fornece uma promessa.

EDITAR

Esqueci de mencionar que seus testes não podem ser scripts puros com essa abordagem, porque não podemos injetar contexto, então você precisará:

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

@odolha
Obrigado por vincular seu fork.
Já havia um PR para dar suporte ao ESM nativo , mas foi fechado porque o suporte ao módulo ainda é experimental.

Sua implementação me conforta que adicionar suporte para isso deve ser fácil. Estamos muitos esperando ansiosamente por esse recurso :)

@demurgos :no_mouth: sim... Acabei de ver esse PR depois que fiz minhas próprias coisas, d'oh 😃.

@harrysarson @boneskull
O pacote esm (anteriormente denominado @std/esm ) deixou de dar suporte a arquivos .mjs neste commit .
Isso significa que não é mais possível usá-lo com o Mocha para testar arquivos .mjs . Isso é discutido nesta edição .

Ainda quero poder testar os módulos ES para poder executá-los com segurança no Node ou em navegadores.

Em relação às discussões do módulo atual, há consenso de que .mjs deve estar disponível no resultado final (talvez não como a única solução, mas pelo menos disponível) e que import("./foo.mjs") retornará uma promessa para o namespace ES correspondente. O fato de os módulos CJS serem convertidos em um módulo com uma exportação default correspondente a module.exports é mais debatido, mas parece ser uma suposição segura.

Seria possível reconsiderar a adição de suporte ES nativo usando import dinâmico ao Mocha? O sinalizador de recurso pode ser renomeado para --experimental-es-modules (de #3253) para sinalizar melhor que isso depende do avanço atual do suporte do Node.
De acordo com os prazos, a especificação final não chegaria até o Nó 12, então a implementação atual permanecerá lá por algum tempo (e é um subconjunto relativamente seguro da proposta final).

@demurgos Eu pessoalmente prefiro esperar um pouco mais antes de me comprometer com qualquer implementação de código no mocha. Mas talvez @boneskull ou @ScottFreeCode discordem?

@demurgos

O pacote esm (anteriormente denominado @std/esm) eliminou arquivos de suporte .mjs neste commit.

O carregador esm não abandonou o suporte para .mjs . Nós simplesmente seguimos a implementação atual --experimental-modules e lançamos um erro ao tentar carregar .mjs com require . Os usuários ainda podem usar um arquivo .js para seu arquivo de entrada de teste que usa sintaxe ESM ou import() dinâmico para carregar arquivos de teste subsequentes de .mjs ou .js , muito como esm faz para seus próprios testes .

De acordo com os prazos, a especificação final não chegaria até o Nó 12, então a implementação atual permanecerá lá por algum tempo

Não há tempo definido para --experimental-modules pousar sem bandeira. A esperança é que ele possa pousar em algum momento no ciclo de suporte do Node 10 _(então em algum momento nos próximos 2 anos)_ mas não há nada definido.

(e é um subconjunto relativamente seguro da proposta final).

A implementação atual --experimental-modules pode não ser compatível com a proposta final. Existem várias discussões sobre como será o suporte ao ESM no Node. Algumas direções propostas não são compatíveis com a implementação experimental atual. Dependendo de como as coisas mudam, o código que você escreve hoje para --experimental-modules pode não funcionar com qualquer que seja a forma final.

O carregador esm não eliminou o suporte para .mjs.

Meu ponto é que esm não permite mais exigir .mjs para que você não possa mais usar a descoberta de teste do Mocha para .mjs . Mas você está certo, não foi documentado, então não é realmente uma mudança radical, mesmo que outras pessoas tenham confiado nela.

Quanto aos prazos, referia-me a esta questão . Parece haver uma tentativa para o Nó 11 e uma implementação final para o Nó 12 para que possa ser portado para o Nó 10 LTS. Alguns desejam que isso aconteça mais cedo, outros alertam para não se apressar.

Minha proposta é mesclar #3253. Isso oferece apenas um mecanismo opt-in para usar import(...) em vez de require para carregar os casos de teste. Como espero que seja aplicado principalmente para .mjs no contexto de --experimental-modules , ainda acho que é seguro. (importação dinâmica de .mjs retornando uma promessa de namespace provavelmente permanecerá). Mas vou deixar você decidir se pode mesclá-lo e evitar forçar demais para isso.

Novamente, a principal razão para este PR é que, sem ele, você não pode mais usar a descoberta de teste do Mocha, mas precisa usar a solução alternativa descrita acima por @jdalton. ( .js ponto de entrada e importações manuais)

Minha proposta é mesclar #3253.

3253 tinha algumas falhas, definitivamente não é uma boa ideia mesclá-lo como está.

Seguindo o exemplo @jdalton , configurei um pequeno fluxo de trabalho para testar o ESM nativo sem o pacote esm (Node puro + Mocha).
Eu uso definições de teste assíncronas (usando --delay ) e --experimental-modules .

Atualmente, _mocha_ só pode importar CJS, e CJS só pode importar ESM usando a pseudofunção dinâmica import() . Então eu gero o seguinte ponto de entrada CJS (seu nome termina com .js ) que importa os arquivos de especificação e aciona a execução do teste:

teste.esm.js :

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

(Eu gero o ponto de entrada com a lista de importações em tempo de compilação, mas você pode escrevê-lo manualmente ou usar glob lá.)

Em seguida, executo-o com o seguinte comando:

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

Eu tenho que passar por NODE_OPTIONS porque a bandeira não é reconhecida pelo mocha.


Ainda espero que o mocha forneça um suporte melhor para o ESM experimental, mas pelo menos é bom saber que existe uma maneira de usá-lo hoje sem outras ferramentas.

@demurgos esta é uma pequena solução que você encontrou :+1:.

É bom ver que é realmente possível (se não fácil) usar módulos es com mocha : smile:.

@demurgos Este problema é sobre o suporte a testes de estilo ES6 sem uso de transpilador . O que é "tempo de construção"? Esse código que você usa para gerar os pontos de entrada de teste é um transpilador, apenas um especializado.

@rulatir
Mencionei que uso ferramentas de compilação, mas elas não estão no nível discutido nesta edição: Mocha está sendo executado com ESM nativo, não ESM rebaixado para CJS por um transpilador.

Veja minha mensagem:

Eu gero o ponto de entrada com a lista de importações em tempo de compilação, mas você pode escrevê-lo manualmente ou usar glob lá.

Usei uma etapa de compilação porque quero que minhas importações sejam (1) definidas estaticamente e (2) não mantenham a lista por conta própria.

Se você tiver apenas alguns arquivos de especificação, não há problema em descartar (2): basta ter um ponto de entrada importando seus 1-2 arquivos de especificação.
(1) já é um requisito específico para arquivos de teste, então é apenas uma coisa "bom de se ter" e você pode usar glob em tempo de execução (em vez de tempo de compilação como eu). Este é apenas um detalhe que não importa no final, uma vez que você entenda a ideia central.

Se você quer apenas algo como uma solução simples de copiar e colar encontrando os arquivos de especificação mjs em tempo de execução, aqui está um exemplo:

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

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

Execute-o com NODE_OPTIONS="--experimental-modules" mocha --delay test.esm.js .
Como você vê, nenhuma compilação, mas um pouco mais de ruído no código.

Eu sou um bot que observa problemas de inatividade.
Este problema não teve nenhuma atividade recente e estou rotulando-o de stale . Em 14 dias, se não houver mais comentários ou atividades, encerrarei esta questão.
Obrigado por contribuir com o Mocha!

Este problema ainda é válido e não deve ser encerrado.

A próxima versão mocha@6 terá o sinalizador --experimental-modules na lista de permissões, permitindo experimentar os módulos ES6 com mais facilidade. Seria possível ter uma versão menor ou patch antes da v6? Atualmente estou finalizando uma nova ferramenta de cobertura que usa o depurador V8 ao invés do Istanbul e gostaria de testá-la com os módulos Mocha e ES6 (sem ter que usar uma dependência git no meu package.json).

@demurgos

Quando eu tento assim...

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

eu recebo

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

Mas quando eu corro assim...

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

Ele funciona perfeitamente o que estou perdendo?

@demurgos você deve coordenar com @bcoe; veja https://github.com/bcoe/c8

@demurgos para cortar uma versão menor, precisaríamos selecionar todas as alterações ininterruptas desde a v5.2.0 em uma ramificação e compilá-las no CHANGELOG. se você ou outra pessoa estiver disposta a fazer esse trabalho, podemos cortar a liberação.

fwiw eu recomendo esm over --experimental-modules até que o Node.js tenha sua história clara. será uma espera considerável.

@boneskull
Haha, obrigado. Eu já estou trabalhando em torno de c8 desde julho (abri um monte de PRs e problemas neste repositório). Há também algumas decisões de design em que discordamos, então tentamos compartilhar a maioria das dependências (eu escrevi o algoritmo de mesclagem, por exemplo) e decidimos que publicarei outra ferramenta: c88 . Coloquei para funcionar neste fim de semana e agora estou testando em minhas bibliotecas. Posso usá-lo com ESM nativo e mocha no CI. Ainda preciso de algum tempo para documentar e corrigi-lo, mas deve estar pronto em janeiro).

@jrgleason
Eu escrevi o código acima do topo da minha cabeça. Parece que o problema aqui é que globSync retorna caminhos relativos que não começam com ./ ou ../ . Você pode querer prefixá-lo com ./ : ele deve funcionar com caminhos relativos simples.
Você também deve observar que as importações dinâmicas usam URLs relativos: # , ? e outros caracteres especiais podem ser tratados de forma diferente. Se você deseja uma solução sólida, deve resolver o caminho absoluto do módulo e convertê-lo em um URL de arquivo. Como parte do meu trabalho de cobertura, escrevi uma lib para converter entre caminhos absolutos e URLs: você pode querer usar fromSysPath de furi . As conversões devem lidar com qualquer tipo de caminho (mesmo os namespaces do Windows e caminhos UNC...).

Veja como pode ser um exemplo completo:

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

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

Quero dizer, mocha --require esm não funciona ? Nós realmente precisamos de detecção automática? Isso soa difícil e adiciona sobrecarga ...

@demurgos para cortar uma versão menor, precisaríamos selecionar todas as alterações ininterruptas desde a v5.2.0 em uma ramificação e compilá-las no CHANGELOG. se você ou outra pessoa estiver disposta a fazer esse trabalho, podemos cortar a liberação.

Obrigado pela proposta. Ainda é possível obter --experimental-modules com NODE_OPTIONS , então não é uma prioridade alta (e pode complicar a árvore git para selecionar commits). Se eu conseguir fechar os problemas que tenho com outras dependências, vou ver se consigo passar um tempo nisso. Enquanto isso, fico de olho no marco da v6.

fwiw eu recomendo esm acima --experimental-modules até que o Node.js tenha sua história clara. será uma espera considerável.
Quero dizer, mocha --requer esm simplesmente funciona?

Definitivamente concordo que é a melhor solução no momento: é a solução mais fácil de configurar e já saiu há algum tempo: funciona. No meu caso, estou mantendo minhas próprias ferramentas de compilação e manipulo o ESM nativo como uma alternativa às compilações clássicas do CJS. Apesar de estar realmente ansioso para o ESM nativo, ainda recomendo não usá-lo como a única maneira de executar seu código: afinal, é experimental :stuck_out_ language :.

A maioria das minhas mensagens recentes é sobre compartilhar o que pode ser feito usando o ESM nativo. Este é principalmente um trabalho experimental e espero ter que alterá-lo quando o ESM do Node ficar estável. A longo prazo, há benefícios em ter uma solução que não exija o pacote esm . Aqui estão os meus motivos:

  • Reduz a quantidade de ferramentas necessárias (menor complexidade, menos configuração para entender)
  • Pode haver algumas diferenças entre o ESM real e esm em torno dos casos extremos (erros de avaliação, ciclos, erros de carregamento, módulos assíncronos/dinâmicos, wasm, etc.). Ao escrever código isomórfico, pode ser mais seguro reduzir qualquer possível fonte de divergência de comportamento. Isso também está meio relacionado à cobertura nativa: com esm , V8 vê a saída transpilada então você tem que lidar com mapas de origem (ainda não suportados por c8 , mas estou preparando um PR, eles trabalham em c88 ). Outras diferenças também podem aparecer durante a depuração.
  • Evita ter que transpilar dinamicamente o código e ajuda a melhorar o desempenho.

Nós realmente precisamos de detecção automática? Isso soa difícil e adiciona sobrecarga ...

Não tenho certeza de qual detecção automática você está se referindo. Está relacionado com o PR que foi enviado no início deste ano?


Edit : Eu também estou no Slack de ferramentas do Node (principalmente ativo no canal #c8 ) se você quiser discutir.

@demurgos Acho que fiquei um pouco confuso sobre o que as pessoas queriam aqui. De qualquer forma...

Se NODE_OPTIONS=--experimental-modules funcionar até --experimental-modules ser suportado no Mocha v6.0.0, há algum outro trabalho a ser feito para este problema? Isso é o que eu estou perdendo.

Espero que esse problema permaneça em aberto até que o ESM nativo ("testes de estilo ES6 sem uso de transpilador") funcione imediatamente / tão facilmente quanto o CJS funciona atualmente.

A solução que postei com --delay e NODE_OPTIONS=--experimental-modules é mais uma solução alternativa do que um suporte adequado. Eu consideraria esse problema corrigido assim que você conseguir executar mocha **/*.spec.mjs e obter um relatório.

Infelizmente, no momento, sinto que ainda temos que esperar que o Node descubra o suporte ao ESM. Eu teria que verificar, mas acho que o PR não usou detecção automática, mas simplesmente importou todos os módulos (CJS ou ESM) usando importações dinâmicas. A implementação dependerá da história de interoperabilidade dos módulos.


Editar : estou me referindo a https://github.com/mochajs/mocha/pull/3253. Permite carregar todos os módulos como ESM (sem detecção automática).

Eu sou um bot que observa problemas de inatividade.
Este problema não teve nenhuma atividade recente e estou rotulando-o de stale . Em 14 dias, se não houver mais comentários ou atividades, encerrarei esta questão.
Obrigado por contribuir com o Mocha!

O nó 12 deve incluir a nova implementação do ESM. Será a ocasião de verificar como suportar os módulos ES no Mocha.

Eu bati o bug do GC ao usar o Mocha um ESM, mas ele é relatado e confirmado, então deve ser corrigido: https://github.com/nodejs/node/issues/27492.

Além desse bug, a estratégia descrita no meu comentário acima ainda funciona para usar o Mocha com o ESM.

Oi pessoal do Mocha, obrigado por criar e manter uma ótima ferramenta!

Este é apenas um comentário FYI. Nos últimos meses tenho trabalhado em Mocha e * -test.mjs , usando os patches abaixo. Não há quase nenhum problema para executar mocha test/*.mjs (sem transpiler ou módulo npm esm ).
https://gist.github.com/tadd/756d21bad38933c179f10e59bddee6b4

Claro que este patch não está "pronto para produção" para os committers do Mocha; este é apenas um hack para usuários do Mocha que desejam usar o ESM em códigos de teste o mais rápido possível.
Eu tenho usado Node.js v11 com a opção --experimental-modules . Atualmente estou com v12 e também funciona.

É outra história, mas o Node v12 introduziu a extensão .cjs e o campo "type" em package.json . Parece que estes também precisam ser considerados.

Oi pessoal do Mocha, obrigado por criar e manter uma ótima ferramenta!

De fato, e eu também gostaria de agradecer 😄

Tomei uma abordagem diferente para fazer loadFiles permanecer síncrono, veja abaixo. Tem funcionado para mim desde fevereiro. Ao contrário de alguns outros hacks, isso ainda permite todos os sinalizadores, inspecionar/devtools e cobertura precisa de código usando c8 . Esse último recurso é o motivo pelo qual eu realmente preciso do ESM nativo, porque o pacote esm tem deslocamentos diferentes para cada arquivo. (As exportações do módulo são listadas e confundem Istambul).

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

Olá! Isso também é necessário para testar qualquer código que dependa do projeto ES6 nativo, por exemplo, lit-element . Caso contrário, ele lança assim:

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

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

Não sei se há uma solução para isso, mas atualmente não acho que haja uma maneira de usar o Mocha com a estrutura nativa do ES6.

@heruan postei uma solução funcionando desde o Node 8 nos comentários acima. Aqui está uma versão atualizada que requer o Node 10.12 para conversões de URL de arquivo nativo:

Adicione o seguinte arquivo test.esm.js :

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

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

Em seguida, execute os testes com mocha --experimental-modules --delay test.esm.js .

Esse código funciona usando test.esm.js como a ponte commonjs para carregar os testes do ESM.

O nó 12 tem um problema relatado em que o IIAFE é coletado pelo GC (nodejs/node#27492), ele deve ser corrigido em uma das próximas versões secundárias (pode haver algumas soluções alternativas, mas ainda não as analisei). Eu recomendo usar a versão mais recente do Node 10 até que ela seja corrigida.

Thar irá acionar um aviso UnhandledPromiseRejectionWarning se houver algum erro. Melhor encadear um console.error ou lidar com o erro.

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

const globAsync = promisify(glob)

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

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

  run()
}

main().catch(console.error)

_Eu sei que isso está usando import sobre require , mas veja minha essência para uma solução que permite que você permaneça no território do ESM_

@demurgos Obrigado pelo trecho de código para o Node 10.12 que você postou dez dias atrás!

Estou executando o Node 12.1 e parece funcionar bem. Isso será adicionado em breve ao Mocha ou existe uma maneira ainda mais fácil de fazer isso com o Node 12? Além disso, como usar isso no modo --watch ?

https://github.com/standard-things/esm parece funcionar imediatamente com --require esm , mas seria ótimo abandonar outra dependência :) Obrigado.

Se o Mocha mudasse para o ESM na fonte, o Rollup poderia fornecer um arquivo de distribuição ESM, bem como um CommonJS e/ou UMD.

Outra vantagem aqui é que o HTML do navegador não precisaria ser poluído com tags de script extras para puxar o Mocha. Os arquivos de teste (ou arquivo de entrada de teste principal) podem fazer a importação (e evitar "mágica" dentro dos arquivos de teste, tanto quanto descobrir de onde as variáveis ​​estão vindo - só precisa rastrear os caminhos de importação).

Pode-se usar plugins CSS para Rollup também para permitir a injeção de mocha.css , minimizando ainda mais a necessidade de confusão de HTML.

Eu sou um bot que observa problemas de inatividade.
Este problema não teve nenhuma atividade recente e estou rotulando-o de stale . Em 14 dias, se não houver mais comentários ou atividades, encerrarei esta questão.
Obrigado por contribuir com o Mocha!

Acho que isso ainda é relevante.

Alguém conseguiu rodar o Mocha com Módulos ES6 em (edit: ~Travis~) Node >=12.11.0?
Em 12.10.0, parece que configurei com sucesso:
mocha-run.js

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

Então mocha --experimental-modules --delay ./mocha-run.js funciona como um charme.

Mas por algum motivo desconhecido, em 12.11.0, ele se comporta como se não houvesse --delay param:

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

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

internal/modules/cjs/loader.js:1007

      internalBinding('errors').triggerUncaughtException(

                                ^

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

@tomalec Estou executando mocha com módulos ES no nó 12.11.1:

__mocha-run.js__

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

No entanto, o modo de relógio não está funcionando. O mocha aguarda as alterações do arquivo, mas não executa outro teste após a alteração de um arquivo.

@vanslly Sorte sua ;)
Para mim com o Node 12.12.0 (https://travis-ci.org/Palindrom/Palindrom/builds/597771311#L450) e mocha-run.js como você sugeriu acima (https://github.com/Palindrom/ Palindrom/commit/49835962bdd61c849f115e271bbc6c3f82d30511#diff-24eabf03aee8844b2b4747aa95a6af7d),

mocha --experimental-modules --delay test/mocha-run.js https://travis-ci.org/Palindrom/Palindrom/builds/597771311#L643 , , ainda lança o mesmo erro

Que isso ainda é um problema é uma loucura! O ESM não está mais escondido atrás de --módulos experimentais. Este é o futuro.

err, na verdade, foi anunciado há alguns dias...

Tarde demais, todos nós mudamos para Jest.

Ei pessoal, só quero ter certeza de que isso é mantido vivo. Por favor, faça disso uma prioridade e obrigado por todo o excelente trabalho!

@luijar Isso está sendo trabalhado em #4038

Publicamos ontem um lançamento experimental v7.0.0-esm1 : veja as notas de lançamento .

Isso é ótimo de se ver!

Posso perguntar - a falta de referência ao navegador significa que o uso do ESM não está disponível no navegador ou simplesmente que você não precisou especificar as versões do navegador como no Node. Acho que pode ajudar mencionar nas notas de lançamento o status dos navegadores (e se não houver suporte, quais podem ser os planos para seu suporte).

@brettz9
O ESM do NodeJs não afeta o navegador Mocha de forma alguma. Os testes que você executa em seu navegador não são carregados por NodeJs, você mesmo deve fazer isso em seu código HTML.

Se bem me lembro, você tem que definir a tag type="module" <script> o atributo type="module". Tanto para seus arquivos de teste quanto para o script Mocha, para manter a sequência de carregamento. O ESM deveria estar trabalhando com o navegador há anos.

@juergba : sim, claro, mas é necessário um arquivo de distribuição de exportação ESM para que se possa usar import mocha from '../node_modules/mocha/mocha-esm.js'; sem compilação - e para aqueles que usam compilação (por exemplo, para poder usar apenas import mocha from 'mocha'; ), eles gostariam module em package.json para que os empacotadores pudessem descobrir a compilação do ESM automaticamente.

mocha é escrito em commonjs; não podemos colocar um campo “module” em package.json. O Mocha suportará a execução de testes no nó escrito no ESM.

Se você não quiser refatorar para usar o ESM internamente, ainda poderá usar o Rollup com seu plug-in CommonJS e indicar o arquivo de destino do ESM para suportar module (como ofertas da Sinon e a maioria dos pacotes de note que encontrei, jQuery sendo a única outra exceção notável e eles foram refatorando para usar o ESM).

Eu criei um projeto de amostra para testar mocha com ESM. Eu posso executar os testes com sucesso, mas não consegui (_ainda_) executar a cobertura com nyc/istanbul. Sua ajuda será bem-vinda.

@concatime Até que nyc seja compatível, você pode usar c8 : https://www.npmjs.com/package/c8

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

@cedx Atualizei meu repositório de modelos e funciona. Arrumado!

Implementamos o suporte nativo ao ESM do Node no Mocha v7.1.0.

Esta página foi útil?
0 / 5 - 0 avaliações