Jest - do something before every test - jestjs

Jest provides some useful methods for executing something before your tests: beforeEach() and beforeAll(). Jest docs on setup
The issue with these is they can only be placed inside of a describe block. So if I have many files, each with their own describe block, I need to place to beforeEach() in every file.
How can I run some code before & after every test, while only adding it once (instead of adding it in every describe block)?

You can try the globalSetup Jest config key. It is an optional key and it can be used to run an async function once before all test suites.
Please see https://github.com/facebook/jest/blob/master/docs/Configuration.md#globalsetup-string
Example of setting up globalSetup in package.json:
jest: {
globalSetup: "./path-to-global-setup.js"
}
... or in jest.config.js:
module.exports = {
globalSetup: "./path-to-global-setup.js"
};
Example of global-setup.js file:
module.exports = async function() {
// do something
};
This file will not be transformed by babel when you run your test suite.

Related

Express +Jest. Test files are running sequentially instead of in parallel

I have an Express.JS server which uses jest and supertest as a testing framework.
It has been working excellently.
When I call my test npm script, it runs npx jest and all of my test files run in parallel.
However I ran my tests recently and they ran sequentially which takes a very long time, they have done this ever since.
I haven't changed any jest or npm configuration, nor have I changed my test files themselves.
Has anyone experienced this? Or is it possible that something in my configuration is incorrect?
jest.config
export default {
setupFilesAfterEnv: ['./__tests__/jest.setup.js'],
}
jest.setup.js
import { connectToDatabase } from '/conn'
// Override the dotenv to use different .env file
require('dotenv').config({
path: '.env.test',
})
beforeAll(() => {
connectToDatabase()
})
test('', () => {
// just a dummy test case
})
EDIT: Immediately after posting the question, I re ran the tests and they ran in parallel, without me changing anything. If anyone has any knowledge around this i'd be interested to get a second opinion
After intermittent switching between parallel and sequential for unknown reasons. I have found it work consistently by adding the --no-cache arg to the npx jest call.
See below where I found the answer
Github -> jest not always running in parallel

why is jest not required?

I have a react app and I don't know why I don't need to require the jest module.
import Task from './Task';
describe('class Task', () => {
it('inProgress()', () => {
var t = new Task("prova");
expect(t.isInProgress()).not.toBeTruthy();
});
});
The test command for create-react-app runs react-scripts test --env=jsdom.
The script for react-scripts test requires jest on this line and after configuring everything it runs jest on this line.
jest then finds your test files, loads them, and runs them.
In other words, your tests don't load and run jest, it's jest that loads and runs your tests.
Since your tests run within jest they can take advantage of the globals, expect, environment, etc. provided by jest without having to "require or import anything to use them".

Mocha --require wait until migration

I have a challenge to run a database migration before start my mocha suite test.
I am using the flag --require to load a bootstrap.js module that I have created and where I run the database migration.
The problem is that migration is an async function and as you know it returns immediately. So, there is any way to wait for the module to be ready until everything it's finished?
I can use some sync lib to convert migration to be synchronous but I would like to hear more strategies.
You could define a global before hook, like so:
import {runMigration} from './bootstrap';
before(done => {
runMigration().then(done);
});
describe('some part of my suite', () => {
/* ... */
If you write this hook in "root suite" - that is, outside any of your own describe blocks - it will run before all tests, regardless of which file you put this block in.
Docs on root level hooks
Note, that your hooks take too long, you might start getting an error like "Timeout of 2000ms exceeded", which can be solved by running mocha with --timeout flag - like mocha --timeout 10000

Why can't get the global variable which was set in globalSetup in test code?

I use Jest to do unit test in node.
And I use the new feature globalSetup which come in Jest v22.
I have defined a global variable in globalSetup.
But I can't get it in the test code. Console log is undefined.
Anyone in this question?
Thanks.
Jest version: 22.0.0
node version: 8.9.0
yarn version: 1.3.2
OS: mac High Sierra 10.13.2
The code as follow:
// package.json
{
"jest": {
"globalSetup": "<rootDir>/src/globalSetupTest.js"
}
}
// globalSetupTest.js
module.exports = async function() {
global.foo = 'foo';
console.log(`global setup: ${global.foo}`);
};
// App.test.js
describe('APP test', () => {
it('renders without crashing', () => {
console.log({ foo: global.foo });
});
});
// test result
yarn run v1.3.2
$ node scripts/test.js --env=node --colors
global setup: foo
PASS src/App.test.js
APP test
✓ renders without crashing (5ms)
console.log src/App.test.js:3
{ foo: undefined }
Test Suites: 1 passed, 1 total
Tests: 1 passed, 1 total
Snapshots: 0 total
Time: 0.354s, estimated 1s
Ran all test suites.
There's a solution offered from Jest people themselves: https://jestjs.io/docs/en/puppeteer.html. Note that if you're using CRA, this won't work out of the box (solution below), cause it currently doesn't support testEnvironment option for Jest.
Anyways:
In Jest config file you setup paths to global setup, teardown and test environment scripts
In global setup script, you create a browser and write it's WSEndpoint to a file
In global teardown script, you simply close the browser
In testEnvironment script, you read WSEndpoint from the file you saved before and then use it to connect to the running browser - after this, browser is available in your tests by using a global variable
If you're using CRA, you can use a custom setup for these tests and run them completely separately. And if you're using Puppeteer for e2e tests, this is probably what you want to do anyway.
You just add another script to your package.json: "test:e2e": "jest -c ./jest-e2e.config.js" and set it up as you want. Now you will have npm run test for unit tests and npm run test:e2e for end to end tests.
For what I understood is a design decision of Jest because is considered a bad practice to share state across different tests. Tests run in parallel and they should keep their own state.
See:
https://github.com/facebook/jest/issues/6007#issuecomment-381743011
https://github.com/facebook/jest/issues/4118
Can you try..
global.foo = 'foo';
console.log(`global setup: ${global.foo}`);
(remove the exports)
You can try changing globalSetup to setupFiles. That one, won't expect a function.
https://facebook.github.io/jest/docs/en/configuration.html#setupfiles-array

Squirejs causing random tests to intermittently fail or not run at all

We're using Karma and Mocha along with Squire for mocking dependencies loaded with RequireJs. Without Squire, our tests run fine however as soon as we initialize a Squire object, everything start breaking:
define(['squire'], function (Squire) {
var injector = new Squire(); // comment this out and everything works again
});
We found that sometimes Karma reported that no tests were run (even though breakpoints set inside test functions would be hit) and sometimes it would report random errors that shouldn't have been failing. Karma just goes a bit crazy.
How do I use Squire without my tests going crazy?
Ok, I resolved this issue after finding a random github issue. My Karma test-main.js file loaded tests and ran a callback like so:
var tests = Object.keys(window.__karma__.files).filter(function (file) {
return /Spec\.js$/.test(file);
});
requirejs.config({
// ... more code here
// ask Require.js to load these files (all our tests)
deps: tests,
// start test run, once Require.js is done
callback: function () {
mocha.setup('bdd');
mocha.ignoreLeaks();
mocha.run();
}
});
Now instead of defining deps and callback in the requirejs.config, I added the following code at the end of test-main.js:
// load all tests
require(tests, function () {
// start test run once requirejs is done
mocha.setup('bdd');
mocha.ignoreLeaks();
mocha.run();
});
And everything works swimmingly again! Big thanks to #FabienDeshayes on GitHub for this.

Resources