question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Run globalSetup and globalTeardown only once in watch mode

See original GitHub issue

🚀 Feature Proposal

Hey there 👋 I’d like to propose running globalSetup and globalTeardown functions only once before actually entering watch mode and then after exiting it. I can’t think of any side-effects atm, it could be opt-in/out configuration flag if there’s any.

Motivation

Global setup hooks are great to prepare performance-wise expensive environment, and it would be helpful to run it just once before starting and stopping Jest. Currently Jest re-runs whole global setup/teardown on each change detected in watch mode.

Example

puppeteer and any other expensive server-kind processes, e.g. webpack-serve are good examples. Having single instance running in background during --watch mode would be amazing performance boost.

Issue Analytics

  • State:closed
  • Created 5 years ago
  • Reactions:22
  • Comments:34 (6 by maintainers)

github_iconTop GitHub Comments

12reactions
samwymacommented, Nov 19, 2018

I’ve just faced this problem and noticed that the first argument to both globalSetup and globalTeardown comes with a watch and watchAll property. You can check if either property is true and then not do your teardown (your setup function has to cache it’s result so it doesn’t execute more than once). You can then use the ‘signal-exit’ npm package to do proper teardown.

It’s a bit of a work-around, but I’m running a test elasticsearch cluster locally using this method and it saves a bunch of time in not setting that up each test run

7reactions
samwymacommented, Nov 27, 2018

Yeah, the above isn’t exactly what you need.

Here’s pretty much the setup I’m using for elasticsearch (but some other database or service should work too):

// setup.js
const { startServer, ES_PORT } = require("./elasticsearch");
module.exports = async () => {
  await startServer();

  process.env.AWS_ES_ENDPOINT = `http://localhost:${ES_PORT}`;
}

// teardown.js
const { destroyCluster } = require("./elasticsearch");

module.exports = async function(opts) {
  if (!opts.watch && !opts.watchAll) {
    await destroyCluster();
  }
};

// jest.config.js
module.exports = {
  globalSetup: "<rootDir>/setup.js",
  globalTeardown: "<rootDir>/teardown.js",
};

// elasticsearch.js
const onExit = require("signal-exit");

let clusterSetupPromise;
async function setupServer() {
  let cluster = createCluster(); //This uses the package esvm

  onExit(function() {
    cluster.shutdown().then(function() {
      process.exit();
    });
  });

  // ...setup elasticsearch...

  runningCluster = cluster;

  return cluster;
}

module.exports = {
  async startServer() {
    if (clusterSetupPromise) {
      return clusterSetupPromise;
    } else {
      clusterSetupPromise = setupServer();
      return clusterSetupPromise;
    }
  },
  async destroyCluster() {
    if (runningCluster) {
      await runningCluster.shutdown();
      clusterSetupPromise = null;
      runningCluster = null;
    }
  }
};

I apologise that the example is somewhat verbose, but there are a few key things to it:

  • Your setup script has to cache the result such that it only executes once, even if it’s called multiple times (in this example this is done by setting the clusterSetupPromise variable)
  • Use the signal-exit module to ensure your service is always destroyed. I’m not sure whether this will work in all cases, but it’s working well for me
  • Your teardown script is where you check for the watch flags. That way, it’ll not teardown anything when you’re doing jest --watch, but a normal run of jest will tear everything down fine (I suppose that, since I’m using signal-exit I don’t need the teardown script at all, but I figure it makes it a bit clearer what’s going on)

I have to admit this seems like a bit of a hack. I’d advocate for something like a flag to be set on the options given to the setup/teardown the first time setup is run and the last time teardown will be run. Not sure how possible this is, but it would make my code clearer.

But, for the purposes of just getting on with what you’re doing, this is working well for me 😃.

Hopefully this helps! Feel free to ask any questions

Read more comments on GitHub >

github_iconTop Results From Across the Web

Jest run async function ONCE before all tests - Stack Overflow
Is there a way I can run async function before all tests start (init purposes) only once and not for every test file?...
Read more >
Configuring Jest
Any global variables that are defined through globalSetup can only be read in globalTeardown . You cannot retrieve globals defined here in your...
Read more >
Running Tests | Create React App
The test command will force Jest to run in CI-mode, and tests will only run once instead of launching the watcher. For non-CI...
Read more >
Top 5 jest-dev-server Code Examples - Snyk
wsEndpoint() // If we are in watch mode, - only setupServer() once. if ... workspaces run dev`, launchTimeout: 50000, port: 7000 }); //...
Read more >
Test-driven develop your API with Jest & SuperTest in Node.js
Run your tests using Jest: jest to run them once or jest --watchAll to enable watch mode. Optional: measure the test coverage by...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found