Skip to content

Commit

Permalink
Add support for globalSetup and globalTeardown in projects (#6865)
Browse files Browse the repository at this point in the history
  • Loading branch information
ranyitz authored and SimenB committed Dec 25, 2018
1 parent 1eb8747 commit 698c33c
Show file tree
Hide file tree
Showing 21 changed files with 386 additions and 29 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
- `[jest-haste-map]` [**BREAKING**] Remove name from hash in `HasteMap.getCacheFilePath` ([#7218](https://github.com/facebook/jest/pull/7218))
- `[babel-preset-jest]` [**BREAKING**] Export a function instead of an object for Babel 7 compatibility ([#7203](https://github.com/facebook/jest/pull/7203))
- `[jest-haste-map]` [**BREAKING**] Expose relative paths when getting the file iterator ([#7321](https://github.com/facebook/jest/pull/7321))
- `[jest-cli]` Add Support for `globalSetup` and `globalTeardown` in projects ([#6865](https://github.com/facebook/jest/pull/6865))
- `[jest-runtime]` Add `extraGlobals` to config to load extra global variables into the execution vm ([#7454](https://github.com/facebook/jest/pull/7454))
- `[jest-util]` Export `specialChars` containing Unicode characters and ANSI escapes for console output ([#7532](https://github.com/facebook/jest/pull/7532))
- `[jest-config]` Handle typescript (`ts` and `tsx`) by default ([#7533](https://github.com/facebook/jest/pull/7533))
Expand Down
2 changes: 2 additions & 0 deletions TestUtils.js
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,8 @@ const DEFAULT_PROJECT_CONFIG: ProjectConfig = {
extraGlobals: [],
filter: null,
forceCoverageMatch: [],
globalSetup: null,
globalTeardown: null,
globals: {},
haste: {
providesModuleNodeModules: [],
Expand Down
4 changes: 4 additions & 0 deletions docs/Configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -350,6 +350,8 @@ Default: `undefined`

This option allows the use of a custom global setup module which exports an async function that is triggered once before all test suites. This function gets Jest's `globalConfig` object as a parameter.

_Note: A global setup module configured in a project (using multi-project runner) will be triggered only when you run at least one test from this project._

_Note: Any global variables that are defined through `globalSetup` can only be read in `globalTeardown`. You cannot retrieve globals defined here in your test suites._

Example:
Expand All @@ -376,6 +378,8 @@ Default: `undefined`

This option allows the use of a custom global teardown module which exports an async function that is triggered once after all test suites. This function gets Jest's `globalConfig` object as a parameter.

_Note: A global teardown module configured in a project (using multi-project runner) will be triggered only when you run at least one test from this project._

### `moduleDirectories` [array<string>]

Default: `["node_modules"]`
Expand Down
2 changes: 2 additions & 0 deletions e2e/__tests__/__snapshots__/show_config.test.js.snap
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ exports[`--showConfig outputs config info and exits 1`] = `
\\"errorOnDeprecated\\": false,
\\"filter\\": null,
\\"forceCoverageMatch\\": [],
\\"globalSetup\\": null,
\\"globalTeardown\\": null,
\\"globals\\": {},
\\"haste\\": {
\\"computeSha1\\": false,
Expand Down
54 changes: 51 additions & 3 deletions e2e/__tests__/global_setup.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,27 @@ import runJest, {json as runWithJson} from '../runJest';
import {cleanup} from '../Utils';

const DIR = path.join(os.tmpdir(), 'jest-global-setup');
const project1DIR = path.join(os.tmpdir(), 'jest-global-setup-project-1');
const project2DIR = path.join(os.tmpdir(), 'jest-global-setup-project-2');

beforeEach(() => cleanup(DIR));
afterAll(() => cleanup(DIR));
beforeEach(() => {
cleanup(DIR);
cleanup(project1DIR);
cleanup(project2DIR);
});
afterAll(() => {
cleanup(DIR);
cleanup(project1DIR);
cleanup(project2DIR);
});

test('globalSetup is triggered once before all test suites', () => {
const setupPath = path.resolve(__dirname, '../global-setup/setup.js');
const result = runWithJson('global-setup', [`--globalSetup=${setupPath}`]);
const result = runWithJson('global-setup', [
`--globalSetup=${setupPath}`,
`--testPathPattern=__tests__`,
]);

expect(result.status).toBe(0);
const files = fs.readdirSync(DIR);
expect(files).toHaveLength(1);
Expand All @@ -32,6 +46,7 @@ test('jest throws an error when globalSetup does not export a function', () => {
const setupPath = path.resolve(__dirname, '../global-setup/invalid_setup.js');
const {status, stderr} = runJest('global-setup', [
`--globalSetup=${setupPath}`,
`--testPathPattern=__tests__`,
]);

expect(status).toBe(1);
Expand All @@ -55,3 +70,36 @@ test('globalSetup function gets jest config object as a parameter', () => {

expect(result.stdout).toBe(testPathPattern);
});

test('should call globalSetup function of multiple projects', () => {
const configPath = path.resolve(
__dirname,
'../global-setup/projects.jest.config.js',
);

const result = runWithJson('global-setup', [`--config=${configPath}`]);

expect(result.status).toBe(0);

expect(fs.existsSync(DIR)).toBe(true);
expect(fs.existsSync(project1DIR)).toBe(true);
expect(fs.existsSync(project2DIR)).toBe(true);
});

test('should not call a globalSetup of a project if there are no tests to run from this project', () => {
const configPath = path.resolve(
__dirname,
'../global-setup/projects.jest.config.js',
);

const result = runWithJson('global-setup', [
`--config=${configPath}`,
'--testPathPattern=project-1',
]);

expect(result.status).toBe(0);

expect(fs.existsSync(DIR)).toBe(true);
expect(fs.existsSync(project1DIR)).toBe(true);
expect(fs.existsSync(project2DIR)).toBe(false);
});
50 changes: 48 additions & 2 deletions e2e/__tests__/global_teardown.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,19 @@ import runJest, {json as runWithJson} from '../runJest';
import {cleanup} from '../Utils';

const DIR = path.join(os.tmpdir(), 'jest-global-teardown');
const project1DIR = path.join(os.tmpdir(), 'jest-global-teardown-project-1');
const project2DIR = path.join(os.tmpdir(), 'jest-global-teardown-project-2');

beforeEach(() => cleanup(DIR));
afterAll(() => cleanup(DIR));
beforeEach(() => {
cleanup(DIR);
cleanup(project1DIR);
cleanup(project2DIR);
});
afterAll(() => {
cleanup(DIR);
cleanup(project1DIR);
cleanup(project2DIR);
});

test('globalTeardown is triggered once after all test suites', () => {
mkdirp.sync(DIR);
Expand All @@ -27,7 +37,9 @@ test('globalTeardown is triggered once after all test suites', () => {
);
const result = runWithJson('global-teardown', [
`--globalTeardown=${teardownPath}`,
`--testPathPattern=__tests__`,
]);

expect(result.status).toBe(0);
const files = fs.readdirSync(DIR);
expect(files).toHaveLength(1);
Expand All @@ -42,6 +54,7 @@ test('jest throws an error when globalTeardown does not export a function', () =
);
const {status, stderr} = runJest('global-teardown', [
`--globalTeardown=${teardownPath}`,
`--testPathPattern=__tests__`,
]);

expect(status).toBe(1);
Expand All @@ -65,3 +78,36 @@ test('globalTeardown function gets jest config object as a parameter', () => {

expect(result.stdout).toBe(testPathPattern);
});

test('should call globalTeardown function of multiple projects', () => {
const configPath = path.resolve(
__dirname,
'../global-teardown/projects.jest.config.js',
);

const result = runWithJson('global-teardown', [`--config=${configPath}`]);

expect(result.status).toBe(0);

expect(fs.existsSync(DIR)).toBe(true);
expect(fs.existsSync(project1DIR)).toBe(true);
expect(fs.existsSync(project2DIR)).toBe(true);
});

test('should not call a globalTeardown of a project if there are no tests to run from this project', () => {
const configPath = path.resolve(
__dirname,
'../global-teardown/projects.jest.config.js',
);

const result = runWithJson('global-teardown', [
`--config=${configPath}`,
'--testPathPattern=project-1',
]);

expect(result.status).toBe(0);

expect(fs.existsSync(DIR)).toBe(true);
expect(fs.existsSync(project1DIR)).toBe(true);
expect(fs.existsSync(project2DIR)).toBe(false);
});
22 changes: 22 additions & 0 deletions e2e/global-setup/project-1/setup.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
/**
* Copyright (c) 2014-present, Facebook, Inc. All rights reserved.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
const crypto = require('crypto');
const fs = require('fs');
const mkdirp = require('mkdirp');
const os = require('os');
const path = require('path');

const DIR = path.join(os.tmpdir(), 'jest-global-setup-project-1');

module.exports = function() {
return new Promise((resolve, reject) => {
mkdirp.sync(DIR);
const fileId = crypto.randomBytes(20).toString('hex');
fs.writeFileSync(path.join(DIR, fileId), 'setup');
resolve();
});
};
20 changes: 20 additions & 0 deletions e2e/global-setup/project-1/setup.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
/**
* Copyright (c) 2014-present, Facebook, Inc. All rights reserved.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
'use strict';

const fs = require('fs');
const os = require('os');
const path = require('path');

const DIR = path.join(os.tmpdir(), 'jest-global-setup-project-1');

test('should exist setup file', () => {
const files = fs.readdirSync(DIR);
expect(files).toHaveLength(1);
const setup = fs.readFileSync(path.join(DIR, files[0]), 'utf8');
expect(setup).toBe('setup');
});
22 changes: 22 additions & 0 deletions e2e/global-setup/project-2/setup.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
/**
* Copyright (c) 2014-present, Facebook, Inc. All rights reserved.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
const crypto = require('crypto');
const fs = require('fs');
const mkdirp = require('mkdirp');
const os = require('os');
const path = require('path');

const DIR = path.join(os.tmpdir(), 'jest-global-setup-project-2');

module.exports = function() {
return new Promise((resolve, reject) => {
mkdirp.sync(DIR);
const fileId = crypto.randomBytes(20).toString('hex');
fs.writeFileSync(path.join(DIR, fileId), 'setup');
resolve();
});
};
20 changes: 20 additions & 0 deletions e2e/global-setup/project-2/setup.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
/**
* Copyright (c) 2014-present, Facebook, Inc. All rights reserved.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
'use strict';

const fs = require('fs');
const os = require('os');
const path = require('path');

const DIR = path.join(os.tmpdir(), 'jest-global-setup-project-2');

test('should exist setup file', () => {
const files = fs.readdirSync(DIR);
expect(files).toHaveLength(1);
const setup = fs.readFileSync(path.join(DIR, files[0]), 'utf8');
expect(setup).toBe('setup');
});
26 changes: 26 additions & 0 deletions e2e/global-setup/projects.jest.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
/**
* Copyright (c) 2014-present, Facebook, Inc. All rights reserved.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/

const path = require('path');

module.exports = {
globalSetup: '<rootDir>/setup.js',
projects: [
{
displayName: 'project-1',
globalSetup: '<rootDir>/setup.js',
rootDir: path.resolve(__dirname, './project-1'),
testMatch: ['<rootDir>/**/*.test.js'],
},
{
displayName: 'project-2',
globalSetup: '<rootDir>/setup.js',
rootDir: path.resolve(__dirname, './project-2'),
testMatch: ['<rootDir>/**/*.test.js'],
},
],
};
22 changes: 22 additions & 0 deletions e2e/global-teardown/project-1/teardown.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
/**
* Copyright (c) 2014-present, Facebook, Inc. All rights reserved.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
const crypto = require('crypto');
const fs = require('fs');
const mkdirp = require('mkdirp');
const os = require('os');
const path = require('path');

const DIR = path.join(os.tmpdir(), 'jest-global-teardown-project-1');

module.exports = function() {
return new Promise((resolve, reject) => {
mkdirp.sync(DIR);
const fileId = crypto.randomBytes(20).toString('hex');
fs.writeFileSync(path.join(DIR, fileId), 'teardown');
resolve();
});
};
17 changes: 17 additions & 0 deletions e2e/global-teardown/project-1/teardown.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
/**
* Copyright (c) 2014-present, Facebook, Inc. All rights reserved.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
'use strict';

const fs = require('fs');
const os = require('os');
const path = require('path');

const DIR = path.join(os.tmpdir(), 'jest-global-teardown-project-1');

test('should not exist teardown file', () => {
expect(fs.existsSync(DIR)).toBe(false);
});
22 changes: 22 additions & 0 deletions e2e/global-teardown/project-2/teardown.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
/**
* Copyright (c) 2014-present, Facebook, Inc. All rights reserved.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
const crypto = require('crypto');
const fs = require('fs');
const mkdirp = require('mkdirp');
const os = require('os');
const path = require('path');

const DIR = path.join(os.tmpdir(), 'jest-global-teardown-project-2');

module.exports = function() {
return new Promise((resolve, reject) => {
mkdirp.sync(DIR);
const fileId = crypto.randomBytes(20).toString('hex');
fs.writeFileSync(path.join(DIR, fileId), 'teardown');
resolve();
});
};
17 changes: 17 additions & 0 deletions e2e/global-teardown/project-2/teardown.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
/**
* Copyright (c) 2014-present, Facebook, Inc. All rights reserved.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
'use strict';

const fs = require('fs');
const os = require('os');
const path = require('path');

const DIR = path.join(os.tmpdir(), 'jest-global-teardown-project-2');

test('teardown file should not exist', () => {
expect(fs.existsSync(DIR)).toBe(false);
});

0 comments on commit 698c33c

Please sign in to comment.