esm icon indicating copy to clipboard operation
esm copied to clipboard

jest transform support

Open kenotron opened this issue 5 years ago • 36 comments

I'm collecting some esm + jest + react + enzyme "real world" issues as I'm going here: https://github.com/kenotron/esm-jest/

  1. On https://github.com/standard-things/esm/blob/33ee0ac7e8c7aec7db176143f833560f7a09f069/esm.js#L178, _runResult can be undefined it seems, so add a conditional there will help
  2. A package like domutils that is used by jsdom & htmlparser2 will do silly things like this: https://github.com/fb55/domutils/blob/master/index.js where they loop through all the object keys and start calling ".bind" because they didn't expect something else to inject properties into the object (could be a jest + domutils goober? not necessarily esm??)

Anyway, it's almost there with jest as far as I can tell! If I just hack-patch this stuff conditional around the problematic code, jest works with esm!

kenotron avatar Jan 16 '19 23:01 kenotron

What we shipped in v3.1.0 is the beginnings of support.

You can use esm as a Jest transform with --no-cache to run simple ESM test files. I need to abstract our Jest wiring into a hook to allow it to tap more cleanly into the exposed transform method of process() and getCacheKey().

jdalton avatar Jan 16 '19 23:01 jdalton

Thanks so much for working on this tirelessly. I'll try out that --no-cache and report some findings here. I think what I want to do is to create several examples of jest test suites to test out just how "simple" we need to get with our tests.

kenotron avatar Jan 17 '19 17:01 kenotron

@jdalton Does it work now?))

TrySound avatar Jan 19 '19 21:01 TrySound

Hi @TrySound!

Not yet. The v3.1.1 had to be released sooner to address more critical bugs that shook out after the v3.1.0 release. I'm still going to work on wrapping up Jest support soon though :)

jdalton avatar Jan 19 '19 21:01 jdalton

I noticed 3.1.4 is out, but didn't see any commits relating to this in the git history. I guess you'll update this issue when it's ready @jdalton. Thanks for your amazing work on this!

ephemer avatar Jan 28 '19 13:01 ephemer

Thanks for all your great work @jdalton.

Should anyone else be curious, I can confirm we're still not quite there yet. My testing with [email protected] and [email protected] commonly yields the following errors:

TypeError: _.a(...) is not a constructor
TypeError: Cannot read property 'next' of undefined

kellengreen avatar Jan 29 '19 13:01 kellengreen

Same result as @kellengreen here, any news?

ashton avatar Jan 29 '19 20:01 ashton

Maybe just wait till finished?

matsp avatar Jan 29 '19 20:01 matsp

Thanks for the interest y'all! I'll be sure to update this issue when support 🚢

jdalton avatar Jan 29 '19 20:01 jdalton

Not sure if the following is a known issue in terms of the work remaining required for jest compatibility (so feel free to ignore this if it is known @jdalton):

The globals defined in jest.config.js are not available in the tests when using esm as a transform in jest ([email protected] and [email protected])

avaly avatar Feb 04 '19 08:02 avaly

Does the v12 release make this work any easier? What would be the recommended way to use Jest with ESM now?

dandv avatar Apr 28 '19 19:04 dandv

Any updates?

chungchi300 avatar May 06 '19 07:05 chungchi300

@dandv

Does the v12 release make this work any easier?

It does not unfortunately.

@dandv @chungchi300

What would be the recommended way to use Jest with ESM now?

Continuing to use Babel is the way at the moment until I can get to making esm work.

jdalton avatar May 06 '19 13:05 jdalton

If that's any help here's how I made it work in the build tool I maintain for work.

I created a small transformer which has only the job of converting import/export, and tries to do so only if needed : https://github.com/swissquote/crafty/blob/master/packages/crafty-preset-jest/src/esm-transformer.js

Which is then added as a jest transform (https://github.com/swissquote/crafty/blob/master/packages/crafty-preset-jest/src/index.js#L50) So I guess you could use that in your own projects by installing:

yarn add @swissquote/crafty-preset-jest

And adding this to your Jest configuration:

{
    "transformIgnorePatterns": [],
    "transform": {
        "[/\\\\]node_modules[/\\\\].+\\.m?js$": "@swissquote/crafty-preset-jest/src/esm-transformer"
    }
}

onigoetz avatar May 06 '19 14:05 onigoetz

@onigoetz Awesome, thanks for posting this! I had a small issue with some of the checks that were in your file (I think it had to do with the version of Babel I was using?), so I stripped it all back to just parse everything. Works well for my use case, but probably not so well for others.

I've credited you here: https://github.com/ActuallyACat/jest-esm-transformer

ActuallyACat avatar May 09 '19 08:05 ActuallyACat

@ActuallyACat cool :) You didn't specify the dependencies in the package.json, maybe add at least peerDependencies so that yarn PNP is happy

The reason I added the checks is that Babel has a cost for processing that is quite high if you have to run it on all the files you require from node_modules (for example trying to change all imports in React ... which has none)

onigoetz avatar May 09 '19 11:05 onigoetz

@jdalton is the following statement still valid?

You can use esm as a Jest transform with --no-cache to run simple ESM test files. I need to abstract our Jest wiring into a hook to allow it to tap more cleanly into the exposed transform method of process() and getCacheKey().

I'm trying to run a simple spec with:

npx -n '-r esm' jest func.spec.js

and transforms: {} in my package.json jest section but the:

    ({"Object.<anonymous>":function(module,exports,require,__dirname,__filename,global,jest){import func from './func.js';
                                                                                                    ^^^^
    SyntaxError: Unexpected identifier

is still afflicting me xD

damianobarbati avatar May 23 '19 16:05 damianobarbati

I tried to use esm with jest as a loader. I had the following problems, maybe it will help for the next steps.

You can find a minimal reproducible case on that repo.

  1. Due to the following error:
TypeError: Jest: a transform must export a `process` function.

I had to downgrade from [email protected] to [email protected].

  1. Then I encountered the following error:
    TypeError: Cannot read property 'next' of undefined

      at Object.n.(anonymous function) (node_modules/esm/esm.js:1:1796)

Which might be due to the fact that might be due to the fact that the src/common.js file is being imported:

  • directly in one of the tests
  • indirectly by the components I'm testing in the 2 other tests

Those are basic tests (add, sub, concat), only for example. See topheman/jest-esm-experiments

It is fixable if I use babel-jest as a loader (which I did on the original project where I spotted the bug)

topheman avatar Aug 08 '19 10:08 topheman

A salute to the brave people in this thread. It's amazing/unfortunate that this giant thread (with associated repositories and whatnot) exists, and yet using the amazing esm module with Mocha is trivial.

I just don't understand why the Jest people won't simply add a --require arg ... but since they won't, personally I'm going back to Mocha.

machineghost avatar Sep 17 '19 00:09 machineghost

@jdalton

Continuing to use Babel is the way at the moment until I can get to making esm work.

Is this still the recommendation? jest is the last barrier between converting our entire code base to esm...

scamden avatar Nov 22 '19 01:11 scamden

If I understand this correctly, this "issue" is not anymore existing with the newest Node version which enables ESM modules?

matsp avatar Nov 22 '19 07:11 matsp

The latest version of node now implemented the new module loader. Does it work on Jest?

victorperin avatar Nov 22 '19 14:11 victorperin

From my scans of GitHub threads, it seems like jest has its own require implementation so even on the new experimental module system in node it wasn’t working, but I don’t know for sure and that’s why I was hoping @jdalton might update this thread :)

scamden avatar Nov 22 '19 18:11 scamden

Node's ES modules don't solve it at all (they require package.json with "type": "module", require explicit extensions in imports, and they don't allow interop between CJS and ES6 modules).

I'm cheering for this to be added @jdalton Maybe you could publish some simplified (or slow) implementation in the meantime?

sheerun avatar Jan 15 '20 00:01 sheerun

@sheerun instead of the "type": "modules" entry in package.json you can also use the .mjs extension :scream: :scream_cat: ... you know, instead of the .js extension which we've all used, and which has worked just great for over two decades :wink:

Seriously, why does the Node org hate us all so much? Thank god for @jdalton.

machineghost avatar Jan 15 '20 15:01 machineghost

Yeah Node guys are definitely making a mess. We won't have ESM working for years because of the incompatibility and exports/type requirement. But I trust those guys so it was probably inevitable.

The only choice nowadays is ESM, thanks @jdalton.

damianobarbati avatar Jan 15 '20 15:01 damianobarbati

What's the suggested solution to work with jest and esm in its current state?

bencondon avatar Jan 19 '20 10:01 bencondon

@bencondon the solution is using jasmine and wait for better times 😂

damianobarbati avatar Jan 19 '20 10:01 damianobarbati

I've been adding this to the top of my jest test files and it works great:

const esmImport = require('esm')(module);
const moduleBeingTested = esmImport('../src/module');

E.G.

// ./src/add.js
export function add (a,b) {
  return a + b;
}
// ./test/add.test.js
const esmImport = require('esm')(module);
const add = esmImport('../src/add).add;

describe('add', () => {
  it('works as expected', () => {
    expect(add(1,1).toBe(2);
  });
)};

JakeChampion avatar Jan 19 '20 11:01 JakeChampion

See also the Native support for ES Modules.

dandv avatar Jan 22 '20 21:01 dandv