Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow setting a test environment per file #2859

Merged
merged 2 commits into from
Mar 3, 2017
Merged

Conversation

SimenB
Copy link
Member

@SimenB SimenB commented Feb 10, 2017

Summary

Fixes #2587. This is WIP, opening a PR now to get feedback on direction.

Test plan

Source:

export default (num) => num * 2;

Test:

/**
 * @testEnvironment jsdom
 */

import add from '../index.js';

test('add should work', () => {
  expect(add(2)).toEqual(4);
  document.createElement('a');
});

Command run without these changes:

$ ../jest/packages/jest/bin/jest.js --env node
 FAIL  __tests__/index.js
  ● add should work

    ReferenceError: document is not defined

      at Object.<anonymous> (__tests__/index.js:9:3)

  ✕ add should work (4ms)

Test Suites: 1 failed, 1 total
Tests:       1 failed, 1 total
Snapshots:   0 total
Time:        0.569s, estimated 3s
Ran all test suites.

Command run with these changes:

$ ../jest/packages/jest/bin/jest.js --env node
 PASS  __tests__/index.js
  ✓ add should work (4ms)

Test Suites: 1 passed, 1 total
Tests:       1 passed, 1 total
Snapshots:   0 total
Time:        1.032s
Ran all test suites.

}
}

/* $FlowFixMe */
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@@ -48,6 +49,7 @@ const readRawConfig = (argv, root) => {
};

module.exports = {
getTestEnvironment,
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this OK?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yep!

@codecov-io
Copy link

codecov-io commented Feb 11, 2017

Codecov Report

Merging #2859 into master will decrease coverage by -0.06%.
The diff coverage is 10.52%.

@@            Coverage Diff             @@
##           master    #2859      +/-   ##
==========================================
- Coverage   67.12%   67.07%   -0.06%     
==========================================
  Files         142      142              
  Lines        5126     5136      +10     
==========================================
+ Hits         3441     3445       +4     
- Misses       1685     1691       +6
Impacted Files Coverage Δ
packages/jest-config/src/index.js 0% <ø> (ø)
packages/jest-cli/src/runTest.js 19.51% <10.81%> (+7.01%)

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 8c17c0f...e33ef93. Read the comment docs.

@SimenB SimenB changed the title [WIP] Allow setting a test environment per file Allow setting a test environment per file Feb 22, 2017
@SimenB
Copy link
Member Author

SimenB commented Feb 22, 2017

@cpojer Added a test to this, should be ready for review

* @testEnvironment jsdom
*/

test('use document in a mostly node environment', () => {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should be "use jsdom in this test file"

*/

test('use document in a mostly node environment', () => {
const ele = document.createElement('div');
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

element!

const testFixturePackage = require('../test-environment/package.json');

it('respects testEnvironment pragma', () => {
expect(testFixturePackage.jest.testEnvironment).toEqual('node');
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think you really need to check this. Can you remove this line?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's there to prevent a false positive if the package.json is changed in the future. You don't think that's necessary?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, good point actually. Let's keep it then!

*/

test('stub', () => {
const ele = document.createElement('div');
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

element!


/**
* @testEnvironment jsdom
*/
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The file should look like this:

/**
 * Copyright (c) 2014-present, Facebook, Inc. All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 *
 * @testEnvironment jsdom
 */
/* eslint-env browser*/

const {
Console,
NullConsole,
setGlobal,
} = require('jest-util');
const getConsoleOutput = require('./reporters/getConsoleOutput');

const testEnvironmentPragmaRegex = /@testEnvironment\s+(.*)/;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is a docblock parser in jest-haste-map. Please let's use that instead. Feel free to extract it into a separate package "jest-docblock".

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, I was thinking we could call this @jest-environment instead. That way we can add more of these in the future with the same prefix :)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, nice! Will do

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Didn't see the comment about @jest-environment (no idea how I missed it), will push a change to it

const BufferedConsole = require('./lib/BufferedConsole');
const promisify = require('./lib/promisify');
const {
Console,
NullConsole,
setGlobal,
} = require('jest-util');
const getConsoleOutput = require('./reporters/getConsoleOutput');
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please keep the requires consistent. Here is how it should work with Jest:

const Capitalized = require('MyClass');

const {getTestEnvironment} = require('jest-config');
const lowercase = require('myfunction');

We have this weird spacing rule at FB, let's keep that for now :)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's correct now...

const TestRunner = require(config.testRunner);
/* $FlowFixMe */
const ModuleLoader = require(config.moduleLoader || 'jest-runtime');
return promisify(fs.readFile)(path, 'utf8').then(data => {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you switch this to fs.readFileSync?

I'm a bit worried about the fact that this will end up reading every test file twice and we could potentially change things around by passing a fake FS into ModuleLoader that has a cache, like this:

new ModuleLoader({
…,
cacheFS: {
[path]: source,
},
});

and then later pass that source to transform inside of jest-runtime so that we don't read the same file twice. What do you think?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why sync? The function already returns a promise.

But yes, I agree the file should only have to be read once, I'll see what I can do 😄

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because there is no other work that can be done in Jest at the same time, so there is no benefit in using async code for reading the file :)

Copy link
Member

@cpojer cpojer left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks pretty good! I left a few comments inline – would you mind making another iteration?

@SimenB
Copy link
Member Author

SimenB commented Mar 2, 2017

@cpojer Pushed with the changes requested except for the reading of the source file twice. From what I can see in the code, Runtime::requireModule just does require, which is not the same as reading the file itself. How would I populate the cache?

I can require(path) and do toString() on it, but that will make node choke if it's not been transpiled yet.

@SimenB SimenB force-pushed the env-per-test branch 4 times, most recently from f4b2b7b to a19e8a6 Compare March 2, 2017 17:13
@@ -0,0 +1,10 @@
{
"name": "jest-docblock",
"version": "19.0.0",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you set the version here (and where it is used) to 19.0.2? :)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will do!

data = fs.readFileSync(path, 'utf8');
} catch (e) {
return Promise.reject(e);
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nice!

return Promise.reject(e);
}
let testEnvironment = config.testEnvironment;

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

code style: can you remove this newline and move the const above the let? :)


const fs = require('fs');
const docblock = require('jest-docblock');
const {getTestEnvironment} = require('jest-config');
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this one goes on top of all the requires (because of the {)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You should add eslint-plugin-imports on this stuff 😄

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would love to use a lint plugin to enforce the current rules we have. Mind sending a separate PR for that? :)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can give it a try, at least. No promises

}
let testEnvironment = config.testEnvironment;

const testEnvironmentDocblock = docblock.parse(docblock.extract(data));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

could we just do:

const customEnvironment = docblock.parse(docblock.extract(data))['jest-environment']

and then re-use that? We only need that one prop :)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I had it that way, but your way is more than 80 chars wide...

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  const parsedDocblock = docblock.parse(docblock.extract(data));
  const customJestEnvironment = parsedDocblock['jest-environment'];

?

Copy link
Member Author

@SimenB SimenB Mar 3, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Or add a method to docblock, extractAndParse? I'm guessing they're separate for testing purposes, you wouldn't use one without the other in "real" code, would you?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like the code example up there, maybe just call it customEnvironment instead? :)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So

const parsedDocblock = docblock.parse(docblock.extract(testSource));
const customEnvironment = parsedDocblock['jest-environment'];

?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah that seems reasonable! :)

@cpojer
Copy link
Member

cpojer commented Mar 3, 2017

Nice! I guess we could make the change to jest-rutnime in a follow-up. The idea was to change jest-runtime to accept a cacheFS property in the constructor which is just a map from path -> source. Then inside of _execModule we could pass on the source that we already read to the transform function somehow. Basically we could do transform(…, {source: this._cacheFS[pathToFile] || null}) – does that make sense?

@SimenB
Copy link
Member Author

SimenB commented Mar 3, 2017

Runtime changes in a separate commit makes sense.
And yes, what you say makes sense, I just don't know the code enough to be able to thread it through properly. Want me to add a TODO comment?

@cpojer
Copy link
Member

cpojer commented Mar 3, 2017

Not a todo, but maybe an issue here that links to this PR :)

@SimenB
Copy link
Member Author

SimenB commented Mar 3, 2017

@cpojer OK, everything addressed except for reading the file twice (I can open up an issue for it)

@cpojer cpojer merged commit 62c4e9a into jestjs:master Mar 3, 2017
@cpojer
Copy link
Member

cpojer commented Mar 3, 2017

Really solid work @SimenB. Thank you!

@danieldiekmeier
Copy link

@SimenB Thanks for doing the work! I'm excited to try it out soon. :)

@SimenB
Copy link
Member Author

SimenB commented Mar 3, 2017

Opened up #3060 for the fs cache we discussed here

@SimenB Thanks for doing the work! I'm excited to try it out soon. :)

We "need" this at work, so just happy to see it done 😄

skovhus pushed a commit to skovhus/jest that referenced this pull request Apr 29, 2017
* Extract docblock into its own module

* Allow setting a test environment per file

Fixes jestjs#2587
@SimenB SimenB mentioned this pull request Apr 30, 2017
tushardhole pushed a commit to tushardhole/jest that referenced this pull request Aug 21, 2017
* Extract docblock into its own module

* Allow setting a test environment per file

Fixes jestjs#2587
@jcksncllwy
Copy link

jcksncllwy commented Aug 7, 2018

I have a component that does some fancy work with image processing and canvases that requires images to load in the test. For this, I'm setting {resources: "usable"} in the testEnvironmentOptions and it works great. However, all other tests really don't need to load resources.

Would it be possible to somehow use this per-file test environment specification for testEnvironmentOptions as well?

@thymikee
Copy link
Collaborator

thymikee commented Aug 8, 2018

@jcksncllwy you can create another project in Jest config that will only match certain tests and load them with your testEnvironmentOptions. I see how this would be nice to have in docblock, but that's yet another option to maintain.

@github-actions
Copy link

This pull request has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.
Please note this issue tracker is not a help forum. We recommend using StackOverflow or our discord channel for questions.

@github-actions github-actions bot locked as resolved and limited conversation to collaborators May 12, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Change testEnvironment on a per test basis
7 participants