Jest: Change `testEnvironment` on a per test basis

Created on 13 Jan 2017  Â·  22Comments  Â·  Source: facebook/jest

Do you want to request a feature or report a bug?

Feature

What is the current behavior?

At the moment, I can set the testEnvironment to either node or jsdom in package.json.

My exact problem is that I have a few tests that use Knex, which in turn uses node-uuid, which outputs a console.warn if window exists, but window.crypto is not available.

See also this issue on jsdom: https://github.com/tmpvar/jsdom/issues/1612

The console.warns are not that bad (just annoying), but I can imagine that other modules may have wildly different behaviours for running in node or jsdom, which may lead to obscure bugs.

console.warn node_modules/node-uuid/uuid.js:48
      [SECURITY] node-uuid: crypto not usable, falling back to insecure Math.random()

What is the expected behavior?

Allow every test file to overwrite the setting in package.json. If I understand correctly, every test is run separately, anyways, so this should help?

Please provide your exact Jest configuration and mention your Jest, node, yarn/npm version and operating system.

yarn 0.17.10,
macOS 10.12.2

From package.json:

"jest": {
  "testEnvironment": "jsdom"
},
...
"babel-jest": "^18.0.0",
"jest": "^18.1.0",
Question

Most helpful comment

We could add:

/**
 * @testEnvironment jsdom
 */

and toggle based on the specified value. I'd be supportive of such a change to Jest.

All 22 comments

You should be able to mock console.warn and window.crypto for every test

If I mock console.warn, I lose every warning, not just that one warning that I don't want.

If I mock window.crypto, I have to match the part of the implementation that node-uuid uses, which seems very brittle to me. Any suggestions how to do this?

for the this particular test suite or even test case you can do something like:

const warn = console.warn;
console.warn = jest.fn(); // mock console
// tests...
console.warn = warn // restore console

You should be able to mock node-uuid too:

jest.mock('node-uuid', () => {
  return {
    v4: jest.fn(() => 1)
  };
});

Oh, thanks, that did it! (For this case)

Should I close this, or could the feature request in general be considered for jest?

If you're interested in creating something like this, feel free to send a PR.
But it won't be high on our priorities list I guess.
@cpojer what do you think?

But it won't be high on our priorities list I guess.

I mean implementing such feature by us, not your PR – pull requests are always welcome, but it's often good to discuss the topic before diving in.

I would also welcome a feature like this. With the jsdom versus node envs, is it just the bootstrapping of the former that takes longer or is it a bit slower generally speaking?

As a side question, how would one go about testing code that's meant to run both in the browser and in node, but that behaves slightly differently depending on where it runs?

We could add:

/**
 * @testEnvironment jsdom
 */

and toggle based on the specified value. I'd be supportive of such a change to Jest.

I'd like to look into this, but I'm unsure where to start.

It looks like the environment is bootstrapped before tests are ready (which is fine for the default even if this is implemented, I suppose) here: https://github.com/facebook/jest/blob/7ca7dac05797a6ba2beac4e423504be6ea858c44/packages/jest-runtime/src/cli/index.js#L79-L90

But where would I hook in to check for a @testEnvironment and then potentially create a new env and run that test on there?
A small push in the right direction, and hopefully I can implement this. 😄

@SimenB it's right here: https://github.com/cpojer/jest/blob/master/packages/jest-cli/src/runTest.js#L32 you have the path to the test file and this is where the env is created.

PR opened #2859

As a side question, how would one go about testing code that's meant to run both in the browser and in node, but that behaves slightly differently depending on where it runs?

I suppose we could add support for a comma based pragma, and then just run the same file twice? If there's interest in it, I can look into it after #2859 is done. 😄

@SimenB have you had a chance to look into https://github.com/facebook/jest/issues/2587#issuecomment-279097635 ? We'd like to always run our tests with both jsdom and node testEnvironments, since we server-render everything - is there an easy way to do that in the same jest run?

You should be able to use Jest’s multi project runner to duplicate your config and change the test environment. That would run all tests twice in a single run.

Thanks! Is there documentation on that you could link to?

@cpojer thanks - all the documentation I found talks about how to use "projects", but not how, in a JSON config, to share configuration values across projects. Specifically, I tried to put things top-level, and only put per-project overrides in "projects", but that didn't work - it seemed to ignore all the top-level keys when "projects" was present, so I had to manually duplicate them.

Jest also supports JS configs nowadays, so I probably recommend using a top level JSON config that includes two JS configs that are proxies to the config object that's in a third file and only toggle the env. It's a bit complex but in the end it's a pretty powerful setup. For fewer files you can also only have two files: one that exports the default setup and one that exports that with the env overwritten.

If that’s the only way, I’d prefer to duplicate it; i don’t like having logic in configs :-/

Is there any way that top-level values could get inherited down into projects when both are specified?

Can you open up a separate issue for that? It kinda goes back to the discussion here: https://github.com/facebook/jest/pull/5176#issuecomment-353873177

The difference between GlobalConfig and ProjectConfig is not easy to understand, and things like the inheritance you mention is not really possible (and it's non-obvious).

To answer your question - I have not looked into it. jest-docblock supports multiple identical pragmas now, so in theory it should be possible. But I think multiple projects makes more sense for that use case

I think I've lost the thread. Is this work complete? Is the way to change the test environment on a per file basis documented somewhere?

Was this page helpful?
0 / 5 - 0 ratings