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

globalSetup is executed in different context than tests #6007

Closed
kirill-konshin opened this issue Apr 16, 2018 · 11 comments
Closed

globalSetup is executed in different context than tests #6007

kirill-konshin opened this issue Apr 16, 2018 · 11 comments
Labels

Comments

@kirill-konshin
Copy link

Currently if globalSetup is used to asynchronously prepare something, and then the same file is imported in tests it results in two separate module instances.

Repo to reproduce: https://github.com/kirill-konshin/jest-globalsetup-bug

// jest.globalSetup.js
const doSomethingAsync = () => new Promise(resolve => resolve(Math.random()));
let browser;
const globalSetup = () => doSomethingAsync().then((res) => {
    browser = res;
    console.log('Setup', module.exports.getBrowser());
});
module.exports = globalSetup;
module.exports.getBrowser = () => browser;

// jest.globalTeardown.js
const setup = require('./globalSetup');
module.exports = () => {
    console.log('Teardown', setup.getBrowser());
};

// one of test files
const setup = require('./globalSetup');
describe('browser test', () => {
  it('opens a page', async () => {
      console.log('Test', setup.getBrowser());
  });
});

After npm test console shows that test had it undefined while setup and teardown both printed same value:

> [email protected] test /Users/dis/Sites/jest-bug
> NODE_ENV=test jest

Determining test suites to run...
Setup 0.23915022164799082
 PASS  ./index.test.js
  browser test
    ✓ opens a page (11ms)

  console.log index.test.js:4
    Test undefined

Test Suites: 1 passed, 1 total
Tests:       1 passed, 1 total
Snapshots:   0 total
Time:        0.992s, estimated 1s
Ran all test suites.
Teardown 0.23915022164799082

In my use case inside doSomethingAsync an instance of puppeteer browser would be created.

AFAIK there is no other way to do something before all tests and after all tests.

NPX:

LMRC6785:jest-bug dis$ npx envinfo --preset jest
npx: installed 1 in 1.526s

  System:
    OS: macOS High Sierra 10.13.4
    CPU: x64 Intel(R) Core(TM) i7-4980HQ CPU @ 2.80GHz
  Binaries:
    Node: 9.4.0 - /usr/local/bin/node
    Yarn: yarn install v0.24.6
info No lockfile found.
[1/4] Resolving packages...
[2/4] Fetching packages...
[3/4] Linking dependencies...
[4/4] Building fresh packages...
success Saved lockfile.
Done in 5.90s. - ~/.yarn/bin/yarn
    npm: 5.6.0 - /usr/local/bin/npm
  npmPackages:
    jest: 22.4.3 => 22.4.3 
@SimenB SimenB added the Wontfix label Apr 16, 2018
@SimenB
Copy link
Member

SimenB commented Apr 16, 2018

This is by design - every single test file gets its own context. If you want to access something set up in a globalSetup you need to do something like what https://github.com/smooth-code/jest-puppeteer is doing.

Importing your globalSetup from a file is not supported (and it won't be).

If you have more questions about this topic, we recommend using StackOverflow or our discord channel.

If you think anything can be clarified in the docs, a PR is most welcome!

@SimenB SimenB closed this as completed Apr 16, 2018
@kirill-konshin
Copy link
Author

Thanks a lot for the explanation.

@gluxon
Copy link
Contributor

gluxon commented May 21, 2018

@SimenB I think this is more of an issue of the resetModules configuration not being respected for globalSetup and globalTeardown. By default, tests all share the same context (or module registry). It seems strange then that the setup and teardown files run in their own separate context from that. If the current behavior is desired, I think those users would simply toggle resetModules to true.

But I think the strange in-between behavior we have now will be unexpected by most users. If I've convinced any of the maintainers, would this change be welcome as a pull request?

@SimenB
Copy link
Member

SimenB commented May 21, 2018

Tests do not share the same context, each individual test file has their own. global{Setup,Teardown} is not part of a single test's context (otherwise it'd have to run multiple times instead of exactly once), and it's impossible for it to be.

If you want to run setup a single time (typically starting up some long-running service), use globalSetup. If you need something to run in context before each test, use setupFiles

@gluxon
Copy link
Contributor

gluxon commented May 21, 2018

Thanks for the quick response. I had a misunderstanding while reading the documentation on resetModules. It says that tests share module state by default but not test files. I had thought it meant test files share state by default.

@SimenB
Copy link
Member

SimenB commented May 21, 2018

PRs clarifying the docs are always welcome 🙂

gluxon added a commit to gluxon/jest that referenced this issue Jul 5, 2018
The documentation at the moment describes the behavior of Jest when
`resetModules` is set to `true`, but leaves the default/false case
unclarified. I had a misconception that the module registry would not be
reset at all in the false case, where it's still reset between different
test files. This misconception was clarified by SimienB in issue jestjs#6007.

The reporter of issue jestjs#4413 also had this question.

This commit updates the documentation of `resetModules` to explain the
default case more explicitly.
gluxon added a commit to gluxon/jest that referenced this issue Jul 5, 2018
The documentation at the moment describes the behavior of Jest when
`resetModules` is set to `true`, but leaves the default/false case
unclarified. I had a misconception that the module registry would not be
reset at all in the false case, where it's still reset between different
test files. This misconception was clarified by SimienB in issue jestjs#6007.

The reporter of issue jestjs#4413 also had this question.

This commit updates the documentation of `resetModules` to explain the
default case more explicitly.
gluxon added a commit to gluxon/jest that referenced this issue Jul 5, 2018
The documentation at the moment describes the behavior of Jest when
`resetModules` is set to `true`, but leaves the default/false case
unclarified. I had a misconception that the module registry would not be
reset at all in the false case, where it's still reset between different
test files. This misconception was clarified by SimienB in issue jestjs#6007.

The reporter of issue jestjs#4413 also had this question.

This commit updates the documentation of `resetModules` to explain the
default case more explicitly.
gluxon added a commit to gluxon/jest that referenced this issue Jul 5, 2018
The documentation at the moment describes the behavior of Jest when
`resetModules` is set to `true`, but leaves the default/false case
unclarified. I had a misconception that the module registry would not be
reset at all in the false case, where it's still reset between different
test files. This misconception was clarified by SimienB in issue jestjs#6007.

The reporter of issue jestjs#4413 also had this question.

This commit updates the documentation of `resetModules` to explain the
default case more explicitly.
rickhanlonii pushed a commit that referenced this issue Jul 6, 2018
The documentation at the moment describes the behavior of Jest when
`resetModules` is set to `true`, but leaves the default/false case
unclarified. I had a misconception that the module registry would not be
reset at all in the false case, where it's still reset between different
test files. This misconception was clarified by SimienB in issue #6007.

The reporter of issue #4413 also had this question.

This commit updates the documentation of `resetModules` to explain the
default case more explicitly.
@kevinbarabash
Copy link

I'm writing a jest environment that enables coverage in the selenium environment. I'd like to communicate the coverage maps from the environment object back to the global teardown so that I can merge them and write out a single file. I was looking at using node-ipc to do that. I was wondering if there might be a more official way of doing this using jest APIs.

@andreialecu
Copy link

If you just need to pass a simple reference, such as a connection string from your globalSetup script, and not an entire object, setting something like process.env.MONGO_URL = getConnectionString() from the setup script will work. You can then access the env variable in any test script afterwards.

@compulim
Copy link

@kevinbarabash You can see how we did it, https://github.com/microsoft/BotFramework-WebChat/blob/master/__tests__/html/__jest__/setupRunHTMLTest.js#L66.

We grab the window.__coverage__ object from containerized Chromium via Selenium, and merge it with global.__coverage__ inside Jest test agent VM. Jest will pick up the coverage from multiple agents and merge them correctly.

@spencerwilson
Copy link

spencerwilson commented Mar 5, 2021

For anyone else wondering what this referred to:

If you want to access something set up in a globalSetup you need to do something like what https://github.com/smooth-code/jest-puppeteer is doing.

As far as I can tell (as of [email protected]) it refers to what's happening in this function. In particular, this line where a string value is stashed on process.env and then recalled during environment setup here. So @SimenB was just suggesting what @andreialecu noted above. Note that this is different from the documented "roll your own jest-puppeteer", which demonstrates using the filesystem to pass data.

Assuming that's right, as far as I can tell there are two approaches to this:

  1. Exploit process.env (AKA global.process.env) being the same object(?) during globalSetup as it is in the test context. Empirically, you can stash any JS value on process.env, and access it in the test. Oddly this is contra the docs which state "Any global variables that are defined through globalSetup can only be read in globalTeardown. You cannot retrieve globals defined here in your test suites.". Empirically this is true for custom properties on global; not sure how it's working for @compulim and their global.__coverage__ above. Additionally not sure why global.process.env behaves inconsistently from other global data. Seems like in light of all this, this method might be considered an unsupported hack.
  2. Out-of-band data transfer: Have globalSetup and test code agree on some out-of-band location to write and read data (e.g., a location on the filesystem). Maybe this is known via process.env.PATH_TO_DATA, or maybe is just a constant in code.

edit: Some of my above assertions are false; see #7184, which is a really useful thread.

@github-actions
Copy link

This issue 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 10, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Projects
None yet
Development

No branches or pull requests

7 participants