Jest: global beforeAll

Created on 15 Jun 2017  ·  36Comments  ·  Source: facebook/jest

is there any way for a global beforeAll?

I can define beforeAll in each test file but this will run the beforeAll once for each test file.

is there any global beforeAll that will be run once and finishes before the first test start?

Most helpful comment

+1 for global setup. Like other users, I'd like to setup and tear down the app/DB only once.

All 36 comments

Have you seen setupFiles?

For reference my project uses setupFiles like this:

package.json

{
  "jest": {
    "setupFiles": [
      "./private/mocks/runtime.js"
    ]
  }
}

./private/mocks/runtime.js

global.__meteor_runtime_config__ = {ROOT_URL: 'localhost'};

FYI Stack Overflow might be a better place for this kind of question. (question about usage instead of a bug report / feature request).

Also I've unsubscribed from this issue so won't get any notifications if you reply.

I am using create-react-app.
and setupFiles run again for each test file.

giving an answer that isn't correct and closing an issue after it. bravo!

@cpojer @ashtonsix I don't think that this should be closed and the answer is not correct, both setupFiles or setupTestFrameworkScriptFile runs for each test suite, so there is not a "global" beforeAll where we can set thinks like cleaning a test db before testing on

You can have a pretest in package.json?

@Negan1911 - maybe, but it's difficult to tell what's meant in the OP. You could consider creating a second issue if you think it's a useful feature & want to bring more clarity to this feature request?

@cpojer @ashtonsix If I understand it correctly, currently it's not possible to have global setup and teardown like discussed here in Mocha.
The use-case that I (and probably the OP) have is that I want to run a server and only then all of my integration tests (and probably after all of them have run drop the test DB).
Do you have any advice or best-practices for doing this?
What I've found is people mostly telling to startup a server and close it for each test suite in "local" beforeAll/afterAll, e.g. here by @kentcdodds, but implies a lot of duplication, no?

+1 on having a global setup, in my use case I wanna run a proxy server as well

@ashtonsix for what it’s worth, the OP was clear in my opinion. I’d like this issue to be re-opened.

You can create a custom jest-environment, see jest-environment-node or jest-environment-jsdom and subclass it. It should allow you to set up the environment in any way you like. We discussed adding an async hook for this also, and I'm happy to accept PRs for it.

+1 Wanted to try jest coming from mocha and was impressed with the ease of jest-codemods and the docs, up until I got stuck with this same issue.

Every first describe of each seperate file was taking surprisingly long to execute. Turns out the setup was - as explained by previous comments - run once per file, resulting in tons of unecessary time consuming operations such as DROP DATABASE, CREATE DATABASE, and more.

Unfortunately there's no workaround in the docs (which in turn brought me here) except to run node setup.js && jest which is not ideal..

+1 for global setup. Like other users, I'd like to setup and tear down the app/DB only once.

+1

Fixed in #4506

There are the following jest options globalSetup and globalTeardown. https://facebook.github.io/jest/docs/en/configuration.html#globalsetup-string

I have tried using globalSetup, however I keep on getting the following error.. I think this option might do the trick @shai32. However, I can't seem to get it working 🤣 ...

"jest": "^21.2.1"
 "jest": {
    "globalSetup": "./jest-config.js"
  }



md5-d3a1dcf99642fcf0b9c99c838aadb689



● Validation Warning:

  Unknown option "globalSetup" with value "./jest-setup.js" was found.
  This is probably a typing mistake. Fixing it will remove this message.

  Configuration Documentation:
  https://facebook.github.io/jest/docs/configuration.html

It has not been released yet. Jest 22 incoming any day now 🙂

Fixed in #4506

I know it's linked therein, but for anyone looking: https://github.com/facebook/jest/pull/4716

@btav that's 2 bugs 😓

  1. you have to use absolute path for now, or ("../../../~ root ~")
  2. the validation warnings are false positive

see here
also #5093

bugs should be fixed with #5095 #5096

Can this be used to set a global variable? I tried, but it doesn't work....is this by design?

My use case is I have a custom log function that I want to set globally. I tried _setup.test.js, but my global variables aren't transferred.

@zwhitchcox use setupFiles config option: https://facebook.github.io/jest/docs/en/configuration.html#setupfiles-array

Sometimes it might be useful to share a global variable that is setup via an async function. For example, it would be useful to setup the puppeteer browser once in globalSetup and then spawn a new page in each test / test suite.

@tdenovan Thats exactly what I'm trying to do right now. But it doesn't seem to work. I've done this in mocha before and it was a breeze, but with jest I think I need to find out other ways.
This is my jest config

"jest": {
    "verbose": true,
    "testEnvironment": "node",
    "globalSetup": "<rootDir>/scripts/testSetup.js",
    "globalTeardown": "<rootDir>/scripts/testTeardown.js"
  },
// globalSetup.js
module.exports = async () => {
  const browser = await puppeteer.launch({ headless: false });
  const page = await browser.newPage();
  bot = Bot(browser, page);
  await bot.goto(bot.baseUrl);
  global.bot = bot;
}

But I'm not able to access bot in my test cases.

GGWP! Just solved it.

"e2e": "jest --testRegex '.*.e2e.js'"
// globalTeardown.js
module.exports = async () => {
  if (process.testSetup) {
    process.testSetup.bot.close();
  }
}

 process.testSetup = { bot };
// and then im my tests
const { bot } = process.testSetup;

and anyone is wondering what bot is,

const Bot = (browser, page) => ({
  browser: browser,
  page: page,
  baseUrl: 'http://localhost:4000',
  user: {
    name: faker.name.findName(),
    email: faker.internet.email(),
    password: 'Test@123',
  },
  oldUser: {
    email: '[email protected]',
    password: 'Test@123',
  },
  clearSession: async () => {
    await page.evaluate(() => sessionStorage.clear());
  },
  goto: async (url) => {
    await page.goto(url);
  },
  clickButton: async (id) => {
    await page.waitForSelector(id);
    await page.click(id);
  },
  checkText: async (expect, id, text) => {
    await page.waitForSelector(id);
    const elText = await page.$eval(id, el => el.innerHTML);
    expect(elText).toContain(text);
  },
  type: async (id, text) => {
    await page.waitForSelector(id);
    await page.$eval(id, el => el.value = '');
    await page.type(id, text);
  },
  wait: async () => {
    await page.waitForNavigation();
  },
  close: () => {
    browser.close();
  },
});

There is a guide for puppeteer on the website: https://facebook.github.io/jest/docs/en/puppeteer.html

Yep but that suggests that setting a global in the globalSetup async method is possible, which per the above it doesn’t seem to be b

@SimenB ahh.. man... I was trying to figure this out and also was in the jest docs for quite a long time and never noticed that section. Waste of my time.

I have an issue where the global objects I set in globalSetup are not available if there are multiple test suites ran in parallel (this is by default). Running a single suite test the objects are available or if I set --runInBand to run tests serially. How can I get access to the variables I set in globalSetup if tests run in parallel?
I tried the example used above (using process object) and I also tried the version where I am using a custom TestEnvironment but with no luck:

const PuppeteerJsdomEnvironment = require('jest-puppe-shots/lib/jsdom-environment');

class JestPuppeShotsEnv extends PuppeteerJsdomEnvironment {

  async setup(config) {
    await super.setup(config);
    const { allThemesCss } = global;

    // make the allThemesCss object available in test suites
    Object.assign(this.global, {
      allThemesCss
    });
  }
}

module.exports = JestPuppeShotsEnv;

This is getting the allThemesCss from the globalSetup.js and is making sure it is passing down to test suites.

@ovidiu-lapadus I was able to get globalSetup working by using process instead of global. It works with and without --runInBand. E.g.

// globalSetup.js
module.exports = async () => {
  process.FOOT = 'BALL';
};
// globalTeardown.js
module.exports = async () => {
  console.log(process.FOOT) // BALL 
};
// some.test.js
it('expects 1 to be 1', () => {
    expect(1).toBe(1);
     console.log(process.FOOT); // BALL
});

And to the jest team, I'm not sure why globals are undefined in tests ( babel-jest 22.2.2 ), but defined in the globalTeardown.js. Perhaps it's a bug. For now I'll just use process. Cheers!

Thanks @cellis you saved my day ! I've been banging my head against a wall trying to understand why global.FOO was not working. process.FOO does the trick :-)

@kalutheo There are a couple caveats to using process.FOO. First, I don't think you can do deeply nested variables on process or process.env. I figured out an even better way to get globals working, but was I waiting to post it. What I've done, is use the jest-environment package to create my own dbEnvironment. In there, I check for global dbs to be defined and if not, I redefine them. The database environment is only run for db tests, I have another config for frontend only tests. That way, I don't waste time running db tests for every frontend change. Secondly, I have a way of setting up multiple "replica" dbs that are always hot -- you don't need to migrate or dump them on every jest run, as I migrate them along with the dev db ( you can see glimpses of this in the gist I've shared ), which allows the tests to run even faster. I setup a pool of these replicas so I can get maximum parellelism in the tests. It is kind of documented in the jest documentation, but not explained well enough. Anyways, here's the gist: https://gist.github.com/cellis/08cc332dacf9a548005e8cf35d4b16e2

@ovidiu-lapadus Upon closer inspection I think perhaps your problem is that you called super.setup() before assigning your globals. Please see the gist I posted above for a working solution.

@cellis thanks for these valuable informations. I will try with a custom environment like you described

Guys, isn't globalSetup supposed to include here all heave tasks like babel-polyfill, combine with chai, require jest-extended ?
Seems that globalSetup works far differently than setupTestFrameworkScriptFile and what worked there doesn't work in globalSetup.
I know, that every jest test case is run in his snadboxed environment but doin't things in setupTestFrameworkScriptFile makes test to run veeeeeeeeeeery slow.

Mocha: 9s
Jest: 60s, in watch mode: 170s-200s

?

Using process is a hack that will probably break (it's a bug).

You probably want to follow #7184

This is no global beforeAll() all as asked on the question, but with this, you easily avoid code duplication. You can create a node environment, which will be setup for all your tests files: https://stackoverflow.com/a/61260044/4934640


Update

I just find out I can set an environment variable on globalSetup, meaning I can share the server address between the tests cases/suites/files: https://github.com/facebook/jest/issues/7184#issuecomment-612003555

Was this page helpful?
0 / 5 - 0 ratings