jestjs / jest

Delightful JavaScript Testing.
https://jestjs.io
MIT License
44.33k stars 6.47k forks source link

Meta: Native support for ES Modules #9430

Open SimenB opened 4 years ago

SimenB commented 4 years ago

EDIT: quick guide for getting started: https://jestjs.io/docs/ecmascript-modules

ESM support will be unflagged in a future release of Node 12 (maybe not before April https://github.com/nodejs/node/pull/29866#issuecomment-574055057) and it is already unflagged in Node 13.2, so I think it's time to evaluate how we can add native support in Jest. I'll try to list which features Jest currently provides that are impacted by ESM support, and how we can solve/investigate them.

There is issue #4842, but I think that's more of a discussion issue, while this issue will be geared towards actually implementing support and more suitable to track for those who just want to get the current implementation status. Any comments added to this issue not related to how we can implement support for the below enumerated features will be marked as spam - please direct any workarounds/discussions to separate issues. Also feel free to tell us if anything related to ESM features is missing from the list!

Please note that Jest will use the vm API (https://nodejs.org/api/vm.html) and as of writing (node ~v13.6~ v16.10) the ESM parts of this API is still flagged (--experimental-vm-modules). So saying ESM is unflagged is a bit of a misnomer at the moment. But I think we should start experimenting and potentially provide feedback to the Modules WG.

EDIT: Tracking issue for stabilization in Node: https://github.com/nodejs/node/issues/37648

Lastly, I'm writing this issue mostly for people who will implement support, so it'll be somewhat low-level and specific to how Jest works. For people who just want to know whether support has landed or not, I recommend using GH's wonderful "custom notification" and only subscribe to notifications on closing/reopening.


We achieve sandboxes by running a script within a given vm.Context (either provided by JSDOM or node core APIs). We need to do the same for ESM, but we'll need access to the context during construction of the module, not just when executing the module. I've opened up #9428 which adds the necessary APIs to JestEnvironment.

expect, test, beforeEach etc will still be added as globals, nothing should change here. jasmine global will also still be here.

This is not really a global - it's injected into the module scope. Since the module scope is gone in ESM, we need to move it somewhere. Adding it to import.meta seems natural - there's an option called initializeImportMeta which we can use.

EDIT: Solution here is to fetch it via import {jest} from '@jest/globals'. We might still add it via import.meta in the future, but this should be enough for now.

Since ESM has different "stages" when evaluating a module, jest.mock will not work for static imports. It can work for dynamic imports though, so I think we just have to be clear in the docs about what it supports and what it doesn't.

jest.mock calls are hoisted, but that doesn't help in ESM. We might consider transforming import 'thing' to import('thing') which should allow hoisting to work, but then it's async. Using top-level await is probably a necessity for such an approach. I also think it's invasive enough to warrant a separate option. Something to discuss - we don't need to support everything jest.mock can for for an initial release.

PR: #10976

Not sure if how it should behave in ESM. Should we provide a jest.importActual and let requireActual evaluate in CJS always?

Node has url as its only property (for now, at least). We need to make sure it's populated in Jest as well. We provide identifier instead of filename when constructing the module so I don't think it'll happen automatically, but url is essentially filename passed though pathToFileURL.

There's also an open PR for import.meta.resolve: https://github.com/nodejs/node/pull/31032

This should actually be fairly straightforward, we just need to implement a linker where we can also transform the source before returning it, meaning we don't need the loader API (which doesn't exist yet). This allows us to return mocks as well (albeit they'll have to come from a __mocks__ directory).

Essentially the same as above, but passed as importModuleDynamically when constructing the module. Will also support jest.mock, jest.resetModules etc more cleanly, so likely to be used quite a bit.

This can also be done for vm.Script via the same option.

Right now it's a runtime error (e.g. module not found), but that's not necessarily true with ESM. Does it matter for us? We should verify errors still look nice.

We need to deal with this for people wanting to use CJS from ESM. I've opened up #9426 to track this separately as implementing it is not really related to ESM support.

EDIT: Implemented in #9469

https://nodejs.org/api/modules.html#modules_module_syncbuiltinesmexports. Do we care about it, or is just making it a no-op enough? Not sure what the use case in Jest would be. Messing with the builtins is already breaking the sandbox and I don't think this should matter.

EDIT: #9469 made this into a no-op. I think that's fine?

Inspecting type field in a module's package.json seems reasonable: https://nodejs.org/api/esm.html#esm_enabling. Should we also have our own config flag? Also needs to respect file endings.

https://github.com/nodejs/node/issues/49446

Not sure if this impacts anything. I think not since we'll be linking the modules together ourselves. Needs investigation, though.

EDIT: This is all resolution logic, which we control. So no changes here.

Through #9291 we support jest.config.cjs - do we need to do anything special for .mjs? Probably use import('path/to/configFile.mjs') which means it'll have to be async. Is this an issue? Might be worth making config resolution async in Jest 25 so it's not a blocker for incremental support of ESM in Jest 25.

EDIT: #9431

Node supports package exports, which sorta maps to Jest's moduleNameMapper, but also provides encapsulation features. Hopefully resolve will implement this, but if they do not we'll need to do something. Might be enough to use the pathFilter option? Unsure.

EDIT: #9771

https://nodejs.org/api/esm.html#esm_experimental_json_modules. Do we need to care? Probably, especially for json. It's trivial for us to support import thing from './package.json' since we control the linking phase, but we probably shouldn't do it by default as it'll differ from default node. Should we force people to define a transform for it?

WASM: #13505

Does it matter? I don't think it's affected as we can still transform the source with babel (maybe it'll be confused by import statements, probably not) and V8 coverage definitely shouldn't care. We should verify though.

This is absolutely no blocker as sync resolution will work just fine. But we can use async resolution now, which is great. I wonder if we should look into just using the resolve module off of npm again, as it already supports async. See #9505.

Similar to above, not blocking, but would be nice to support it. Might make @jest/transformer more usable in other environments as well. See #9504.

EDIT: #9889 & #11191

Due to #5163 we have the extraGlobals option as a workaround - that workaround is no longer viable in ESM. I've opened up and issue with node here: https://github.com/nodejs/node/issues/31658

https://nodejs.org/api/esm.html#import-assertions

aldeed commented 4 years ago

UPDATE: This issue is now tracked in https://github.com/facebook/jest/issues/10025

@SimenB Thanks for the jest.mock advice above. As it happens I'm converting a few files that need that today. I can confirm that your example works when the mocked module is a node_modules package, but it isn't working for me mocking a module in the same project.

Here's a simple example:

// 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);
});

Exact same pattern works when "./secondary.js" is a package name instead. (I think the package I tried with exports CommonJS, if that matters.)

Jest 26.0.1 w/ Node 12.16.3

Any ideas, or should I submit a full separate issue?

EDIT: transform: {} in config, so no Babel at all

EDIT 2: This doesn't work either:

jest.mock("./secondary.js", () => ({
  default: jest.fn()
}));
overlookmotel commented 4 years ago

Amazing work on this.

However, unless I'm doing something wrong, it doesn't yet seem to be possible to use import() in a CJS test file.

I'm running Jest with node --experimental-vm-modules node_modules/jest/bin/jest.js and have testEnvironment: 'node', transform: {} in jest.config.js. This is on Node 14.2.0.

The import expression produces error:

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

Is this a known limitation at present? I see https://github.com/nodejs/node/pull/32985 has now landed in Node 14.1.0.

SimenB commented 4 years ago

Yeah, I haven't gotten to implementing it yet. I'll probably land it this weekend.

@aldeed could you open up a separate issue? I need to go through and make sure mocks are part of the resolution, and your example seems like a good test case πŸ™‚

overlookmotel commented 4 years ago

@SimenB Thanks for swift reply. I'll keep a look out for when it lands.

SimenB commented 4 years ago

Seeing as import in scripts might be reverted due to a regression (https://github.com/nodejs/node/issues/33166), let's hold off until that settles

domenic commented 4 years ago

I'm having issues trying to use this with .mjs test files. If I have __tests__/my-test.mjs, I get

$ 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.

If I add

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

to my package.json, I get

$ 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.

However if I remove the "testMatch" and then rename my file to __tests__/my-test.js, it works.

I'd like to be able to consistently use .mjs extensions in my project. Is that possible with Jest?

overlookmotel commented 4 years ago

@domenic I ran into this too. Solution is to add to config "moduleFileExtensions": ["js", "mjs"] (in addition to "testMatch").

SimenB commented 4 years ago

Took a look, and moduleFileExtensions is indeed necessary.

Jest gets a list of all files in the project by running hasteFS.getAllFiles() here:

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

hasteFS is created as part of the HasteMap with the the following extensions config:

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


However, I don't think it should be necessary to specify moduleFileExtensions in this case though. We already force .snap to be found, should we force well-known JS extensions as well? Those being (off the top of my head) js, mjs, cjs, jsx, ts and tsx? It'll make the crawl slower, but I wouldn't think it has a huge impact. I might be wrong though? As a default it shouldn't be much slower since only cjs and mjs is not part of default patterns already, but for people who have custom patterns it might slow things down?

domenic commented 4 years ago

Yeah, it would be ideal if, at least in ES modules mode, .mjs just worked, without having to add moduleFileExtensions or modify the default testMatch.

It would also be nice if I could exclude .js files; when I tried that I got

 Validation Error:

  moduleFileExtensions must include 'js':
  but instead received:
    ["mjs"]
  Please change your configuration to include 'js'.
SimenB commented 4 years ago

I'm wondering if it makes sense to have some "ESM mode" which would add the node esm file extensions and also help with compile-to-js using esm to opt in (#9860).


Without js some stuff internally breaks that we load inside the sandbox (as it uses the same require implementation etc). We should probably fix that so the user cannot break us.

aldeed commented 4 years ago

Regarding slowing down, it's already quite slow on large projects, but I don't know that the number of extensions impacts that much. But I agree mjs and cjs should be added as defaults. Specifying moduleFileExtensions: ['js'] would override the defaults and speed it up, right? So maybe just document that as a performance tweak.

franciscop commented 4 years ago

Thanks for all of this work! It is certainly amazing. I followed the 3 steps ("type": "module" on my package.json, "testEnvironment": "jest-environment-node" in my jest config and --experimental-vm-modules on the CLI) and it seems too be working well πŸŽ‰

But then I'm trying to read and use import.meta as described in Node.js docs (and which seems to be already implemented judging from the checkbox) to create __dirname, but it seems like import.meta is failing:

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.

I don't have any babel and I thought babel was being left behind with this work. I'll come back to report if I can fix it somehow without installing babel.

Node.js v14.3.0, Jest v25.5.4

franciscop commented 4 years ago

I found a workaround for now. Since I am running the script from the same directory where my file is in my library, I can just do:

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

I'll follow this repo in case there's any update, thanks again for doing this!

SimenB commented 4 years ago

You need to explicitly opt-out of Babel by using transform: {} as config

franciscop commented 4 years ago

@SimenB I can confirm that adding transform: {} worked, thanks! I misunderstood that point as "don't add transforms" and not as "take transforms away" as intended.

BTW, testing has gone from 2.4 seconds to only 1.3 seconds and they consistently feel faster.

SimenB commented 4 years ago

Node 12 has been released with unflagged ESM (https://nodejs.org/en/blog/release/v12.17.0/). As noted in the OP though, the APIs Jest use are not unflagged

aledalgrande commented 4 years ago

@SimenB I went over this thread several times but I am still stuck (using node 12.17).

When running Jest 26.0.1 I get this error:

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

I have transform: {}, and running with node --experimental-vm-modules node_modules/jest/bin/jest.js.

What am I missing?

SimenB commented 4 years ago

@aldarund not sure, could you put together a minimal reproduction?

aledalgrande commented 4 years ago

@SimenB here's a minimal repo to repro, just run yarn test https://github.com/aledalgrande/jest-example - I've tried with Node 13/14 and it's the same outcome. It seems to me that the flow for the global setup has not been updated to work with ESM.

also, you mentioned someone else πŸ˜†

franciscop commented 4 years ago

~Not @simenB, but @aledalgrande you seem to have everything correct here from what I tried, see my project fully running on ESM for comparison (jest config in the package.json).~

~To debug it if possible, I would suggest to simplify your jest config to only have the two relevant properties, perhaps even in the package.json first. Then add each of the other properties you currently have to see which one works/didn't work.~

Ah the second comment mentions globalSetup and not normal tests, nvm my comment then. If I remove the globalSetup key in Jest, then the test runs as expected in that example, but the globalSetup key doesn't work as you said.

SimenB commented 4 years ago

Aha, I've forgotten about global setup and teardown. Can fix πŸ‘

franciscop commented 4 years ago

Hi @SimenB , me again. Are named exports supported? With Node.js I can import and use a package like this:

import { customAlphabet } from "nanoid";

However, when trying to do a test that same code gives this error:

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

For the tests, I can change the code to this and it works:

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

But then the Node.js version stops working since there's actually no default sport (but for some reason the default export works with Jest):

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

The published (the repo seems to be in flux right now) nanoid code ends like this, with no default export:

export { nanoid, customAlphabet, customRandom, urlAlphabet, random }
TrySound commented 4 years ago

Jest consumes only "main" entry point. "exports" is not considered yet. You just import commonjs version which has only default export.

franciscop commented 4 years ago

Ah I see, the package.json seems to include this:

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

So probably Node.js is finding the module version, while Jest is using the CommonJS version that does not have a named export, right?

I'll wait until Package Exports is checked and then test it, thanks for all the work again! Marking these 2 comments as resolved until then. The test I'm referring to is this one.

cyberwombat commented 4 years ago

I'm revisiting this to see how its working - upgraded to Jest 26.0.1 and node 14.4. Set package.json to module type, set transform to {}, env to jest-environment-node and running with node --experimental-vm-modules. Now I get this new error:

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

I have been unable to find info on this except a changelog from Jest saying getVmContext had been added a while back.

Any ideas?

franciscop commented 4 years ago

Could you share the relevant parts of your package.json please @cyberwombat ? Including the launching script that you are using for Jest.

franciscop commented 4 years ago

For reference, this is how it looks for me on a working project:

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

Then launch it with npm test

cyberwombat commented 4 years ago

@franciscop Mine basically is the same. Node 14.4.0. I can run yours fine. I will dive into things to see the 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>'
  ]
}

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

franciscop commented 4 years ago

Not sure, but I'd try to work the other way around. Remove everything except transform: {} and testEnvironment: 'jest-environment-node', and start adding each of the options until you see which one triggers the previous error. I specially suspect transformIgnorePatterns might be conflicting with transform, but I'm not that familiar with jest options.

x80486 commented 4 years ago

Hello everyone! I ran into some issue while using Jest to test an Express application. More details here. Not sure if that's useful for what you are doing/tracking here :roll_eyes:

franciscop commented 4 years ago

@x80486 I encountered exactly the same issue yesterday. I've replied in StackOverflow with a longer explanation from my understanding.

Edit: I unhided my previous comment since it seems it might be relevant, this "exports" seems to be popular, very likely from this article on hybrid packages.

SimenB commented 4 years ago

exports is tracked in #9771

cyberwombat commented 4 years ago

@franciscop ok problem solved - it turns out there is a conflict in packages - I had serverless-bundle installed which causes the ES Modules are only supported if your test environment has thegetVmContextfunction error. I am not sure why - I would assume installing it would not cause a running conflict w Jest but evidently it does.

ctavan commented 4 years ago

@franciscop I think the reason why pkg.exports related issues start surfacing now is because that feature was unflagged in Node.js 14.x and some package maintainers (like me for uuid) started adding pkg.exports fields. So while you needed a commandline flag to activate that feature in Node.js 12.x you get that behavior by default now.

It will take a while for the whole ecosystem to adapt, so thanks for reporting issues around that topic!

aldeed commented 4 years ago

For those posting about exports, in case it has been lost in the long thread of this issue, my closed issue about it (https://github.com/facebook/jest/issues/9565) has an example of the moduleNameMapper workaround in it.

akauppi commented 4 years ago

The globalSetup problem reported in May is likely still there (Jest 26.1.0)? Getting the same errors as in the example repo @aledalgrande provides:

$ git clone git@github.com: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 

No rush. Checked CHANGELOG and it didn't mention a fix to globalSetup/globalTeardown with ES6.

Node.js 14.4.0, Jest 26.1.0


Update (13-Aug-20):

Still not possible, Node.js 14.7.0, Jest 26.4.0

ahnpnl commented 4 years ago

Side opinion but should this issue be a pinned issue since it’s the focus for jest at the moment ?

Manish3323 commented 4 years ago

Any thoughts on what needs to be done to consume test reporters written in ES modules?... with the latest jest version, i am getting error which essentialy says testScheduler expects custom reporter in commonjs format.

to see error
~/projects/esw-ts/lib/dist/test/testReporter.js:1
import os from 'os';
^^^^^^

SyntaxError: Cannot use import statement outside a module
    at wrapSafe (internal/modules/cjs/loader.js:1116:16)
    at Module._compile (internal/modules/cjs/loader.js:1164:27)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:1220:10)
    at Module.load (internal/modules/cjs/loader.js:1049:32)
    at Function.Module._load (internal/modules/cjs/loader.js:937:14)
    at Module.require (internal/modules/cjs/loader.js:1089:19)
    at require (internal/modules/cjs/helpers.js:73:18)
    at /Users/manish.gowardipe/Desktop/projects/esw-ts/lib/node_modules/@jest/core/build/TestScheduler.js:418:65
    at Array.forEach ()
    at TestScheduler._addCustomReporters (/Users/manish.gowardipe/Desktop/projects/esw-ts/lib/node_modules/@jest/core/build/TestScheduler.js:411:15)
pepetorres1998 commented 4 years ago

Hi, I want to test Native support for ES Modules in my little project, but I'm new to NodeJS and I got lost in this Issue, I would love some guidance please.

package.json

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

markov.test.js

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

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

test("Generates sentence with especified words", () => {
  expect(markov.makeSentence(8).length).toBe(8);
});
cyberwombat commented 4 years ago

@pepetorres1998 This thread is about running Jest with native esm modules which involves running things with certain flags/options - see the comment above for what to do (and set "type": "module" in package.json). Honestly though at this point it's not quite ready for prime time so if you are needing your project to work I might stick with Babel. There are a number of unchecked issues that are real show stoppers. I gleefully tried to switch a couple of weeks ago and came back crying to Babel.

bdentino commented 4 years ago

Is anyone else getting a ReferenceError: jest is not defined when trying to do things like jest.setTimeout(...) in a test file with this setup? Trying to figure out if this is related to es module environment, node version, jest version, or some combination of those things. (Currently using node v14.5.0, jest 26.1.0, environment jest-environment-node)

EDIT I now see the unchecked checkbox in the issue description for the jest 'global' property. πŸ™ƒ

alexey-detr commented 4 years ago

@bdentino I think you can try to import it explicitly import {jest} from '@jest/globals';

Tzahile commented 4 years ago

25.4.0 has been released with the first pieces of support. In addition to #9772 mentioned above, I've also included #9842. In theory mixing CJS and ESM should work correctly now (🀞).

The one main missing feature is supporting the jest object. I haven't decided if we should stick it to import.meta or require people to import it through import {jest} from '@jest/globals'. Feedback appreciated!

I haven't written docs for this yet, but to activate it you need to do 3 things

  1. make sure you don't run transform away import statements (set transform: {} in config or otherwise ensure babel doesn't transform the file to CJS, such as avoiding the modules option to preset-env)
  2. Run node@^12.16.0 || >=13.2.0 with --experimental-vm-modules flag
  3. Run your test with jest-environment-node or jest-environment-jsdom-sixteen

Please try it out and provide feedback! If reporting bugs, it'd be wonderful if you can also include how running the same code (minus any test specific code) runs in Node. I've read https://nodejs.org/api/esm.html a lot over the last few weeks, but I've probably missed something.

@SimenB This thread became enormous, and I think those who want to start with jest / use ES modules - will have difficulties finding and understanding the basic guidelines to start doing so. Is there a formal explanation in the docs about adding jest to an ES-modules project (or some 'quick start')?

guilhermetelles commented 4 years ago

@aldeed Regarding your problem with mocking modules from the same project, did you found a fix? I'm having the exact same problem

(Btw, we also use reactioncommerce, so cheers to that haha)

aldeed commented 4 years ago

@guilhermetelles no, and it's tracked in https://github.com/facebook/jest/issues/10025 now.

vvanpo commented 4 years ago

I'm using Jest 26.1.0, node version 14.6.0 with --experimental-vm-modules, but I'm still seeing ERR_VM_DYNAMIC_IMPORT_CALLBACK_MISSING when using import() inside of CommonJS. Should I try to come up with a minimal repro and open a new issue?

As an aside, is there an easy way to yarn link a copy of jest packages into a project now that Jest uses yarn berry? I wanted to try the latest master just in case this was implemented by not yet released. I was trying to do something like path/to/facebook/jest/.yarn/releases/yarn-sources.cjs link --all path/to/jest, but it would fail. Manually running something like 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 was not working either, I'm not sure why.

SimenB commented 4 years ago

@vvanpo import() in CJS was reverted in Node, you can follow https://github.com/nodejs/node/issues/31860

As for running local, I usually just uninstall jest from the project I wanna test and do ../jest/jest. Potentially nose ../jest/packages/jest/bin/jest.js. Just make sure to run yarn and yarn build:js first. If these instructions don't work (I'm writing from memory on a phone on a plane) please open up an issue (or PR) so we can properly write this into the CONTRIBUTING.md file

mik-jozef commented 4 years ago

Do you plan to support cyclic imports?

If I have a dummy test file that only imports one of two files that only import each other, I get RangeError: Maximum call stack size exceeded. If I remove one of the imports, the test passes. Repo that reproduces the issue.

zsombro commented 4 years ago

Hey! I set this up in an empty node project and it worked really well, however in our production setting, I get the following error message when I'm trying to run tests:

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

I saw someone else having the some problem in an earlier reply (by @cyberwombat ), but the package they found to be the culprit is not present in our package.json file. How to deduce the package (or setting) that causes the problem? I have tried systematically removing every jest setting that is not necessary to make this work, but I had no success.

UPDATE: I have managed to make progress by making a slight change in jest-runtime. I stopped the debugger at the line which tries to access the VM context and while the function really does not exist, this.context (which it should return) does, so I changed that line to access the property directly. I know this is probably not ideal, but maybe @SimenB this could give you an idea of what is going wrong?

Thank you in advance for any help

SimenB commented 4 years ago

Do you plan to support cyclic imports?

Definitely! Could you open up a separate issue?


@zsombro seems like you're running some old version of the test environment. If you run jest --show-config, what is displayed by testEnvironment?