Esm: Jest compatibility

Created on 17 Sep 2017  路  28Comments  路  Source: standard-things/esm

Hello,
This is less of an issue and more like a compatibility request. I've been trying to use Jest with this package and it doesn't seem that the two packages currently work very harmoniously. In my test files, I'm using the regular, un-modified require function to load index.js, which uses @std/esm to load other ESM files.

// index.js
require = require('@std/esm')(module);

module.exports = require('./Registry').default;
// ... other exports

This is the resulting error when I try to run my tests with Jest. I'm using npm run test which runs jest. I saw this same stack trace in #28 but I thought I'd open a new issue just to keep things more organized.
image

Thanks!

duplicate

Most helpful comment

Hi @dandv!

There isn't a clean way at the moment. However, in the next esm release you'll be able to specify esm as a transform in your jest.config.json:

  "transform": {
    "\\.m?js$": "esm"
  },
  "transformIgnorePatterns": []

All 28 comments

Hi @aemino!

What version of @std/esm are you using?
It shouldn't be exposing its internals when erroring (an older version accidentally did though).

Can you create a simple repro repo?

I'm using the latest version of @std/esm, version 0.9.2.
I've created a simple repro at aemino/esm-repro.

Interesting... Jest is somehow creating a module object without an exports property.

Update:
It looks like Jest is mocking the Module constructor. When it does though it forgot to set its constructor property up so the modules it produces have a .constructor of Object instead of the actual constructor. So when I use module.constructor I get Object and when I pass an id to it I get a string object back which doesn't have an exports property. What's even more interesting is its Object of another realm so checks for module.constructor === Object fail.

Awesome! This solved the issue for me. Thank you very much for your work. 馃憤

I am having a different problem, where I get Unexpected token import errors when trying to run Jest tests. Here is a repro repo:

https://github.com/eliw00d/jest-esm

@eliw00d Your src/main/index.js isn't being loaded by the loader. You've set it up for the loader to load a few test files but beyond that the trail runs cold. I'm guessing Jest picks things up and loads them with its own loader (it is mocking things). Your package entry script should have a loader hook-up like your test script.

Ah, I see now. But that could mean a lot of work rewriting tests to require the index rather than the file itself. Thanks.

@eliw00d For testing you can enable the omnipresent hook using node -r @std/esm
or the NODE_OPTIONS environment variable.

For package consumption heads up that your module entry is just a bare ESM module which won't work without a loader. Your package's entry point should be a CJS module that initializes the loader as our getting started section suggests.

Seeing as how this is the first google result from people search "esm jest," I'd like to post a solution that works.

Hacked up something that would work even if your tests are use esnext modules (say, from a typescript compile output):

https://github.com/kenotron/esm-jest

Inspiration is from here:

https://stackoverflow.com/questions/46433678/specify-code-to-run-before-any-jest-setup-happens

I've updated this example with your PR, @jdalton - thanks! It looks much cleaner and adds caching 馃憤
My next trick is to integrate this in a large codebase written in Typescript to see if it still works!

@jdalton: how exactly can NODE_OPTIONS be used to just run jest when the test file uses import syntax?

NODE_OPTIONS='-r esm' npx jest fails with SyntaxError: Unexpected token {.

index.test.js is import { foo } from './main';

@kenotron's solution is far from simple and it doesn't support import.

TL;DR - what's the recipe for using Jest to test ES modules? I couldn't find that in the README or in the Medium post.

Hi @dandv!

There isn't a clean way at the moment. However, in the next esm release you'll be able to specify esm as a transform in your jest.config.json:

  "transform": {
    "\\.m?js$": "esm"
  },
  "transformIgnorePatterns": []

@jdalton We are really looking forward to this solution <3

Thanks @pi0!

Still in the process of cleaning it up. I got caught up with the Node+JS Interactive conference and improving support for new dynamic import() test262 tests.

@jdalton I presume the next esm release will resolve the current jest with esm issue if you configure esm as a transform as above?

Putting this here to let you know in case you were not aware already.

TypeError: Jest: a transform must export a `process` function.

@cabbiepete

I presume the next esm release will resolve the current jest with esm issue if you configure esm as a transform as above?

Correct. It's not available in the current installable release. It will be in the next release though.

Do you know when you will have that release? Is that code available in a branch we can poke at?

@kenotron It's in master branch but is not suitable for shipping and may be broken at the moment. Fixing some things so its support is in flux.

ooh ooh i'll settle for playing around with on master branch :) That's SOMETHING to hang on to :P

@jdalton I know that this feature is still in progress, but installing esm from the master fails jest:

 TypeError: Cannot destructure property `dir` of 'undefined' or 'null'.

      at Object.<anonymous> (../../node_modules/esm/esm.js:233:26)
 ```

The snippet:

if (cachePath !== "") {
const { dir } = shared.package // HERE package is undefined!
```

May be it helps you to land the upcoming release faster.

esm 3.1.0 came out! Will have to mess around with jest + esm to see how that is done

I am trying out esm 3.1.0 with https://github.com/kenotron/esm-jest

It still fails :(

TypeError: Cannot read property 'next' of undefined
      at Object.n.(anonymous function) (node_modules/esm/esm.js:1:1796)

Basically it fails to find a ".next" from the _runResults

Correct @kenotron! When trying to get Jest support finished I ran into some blockers that prevented it from making it into the 3.1.0 release. I'll be in a follow-up release for sure.

you're not far! i started a new issue to track some issues that i'm finding here #706.

Hmmm, maybe you can edit it and enumerate the blockers on this support? I would love to see this happen - am willing to roll up my sleeves to help test / help fix

For anyone wondering, you can still use the esm require approach in your tests without the jest transform option. e.g.

my-module.test.js

const esmRequire = require('esm')(module)
const { foo } = esmRequire('./my-module.js')

describe('my es-module', () => {
//...

my-module.js

export function foo () {
  //...
}

Any news?

Moved to #706.

Was this page helpful?
0 / 5 - 0 ratings