feat(jest-core): add support for `globalSetup` and `globalTeardown` written in ESM (#11267)

This commit is contained in:
Alessandro Dal Grande 2021-04-15 01:23:02 -07:00 committed by GitHub
parent 7d7f93744b
commit 1be8d737ab
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 174 additions and 10 deletions

View File

@ -16,6 +16,7 @@
- `[jest-core]` Run failed tests interactively the same way we do with snapshots ([#10858](https://github.com/facebook/jest/pull/10858))
- `[jest-core]` more `TestSequencer` methods can be async ([#10980](https://github.com/facebook/jest/pull/10980))
- `[jest-core]` Add support for `testSequencer` written in ESM ([#11207](https://github.com/facebook/jest/pull/11207))
- `[jest-core]` Add support for `globalSetup` and `globalTeardown` written in ESM ([#11267](https://github.com/facebook/jest/pull/11267))
- `[jest-environment-node]` Add AbortController to globals ([#11182](https://github.com/facebook/jest/pull/11182))
- `[@jest/fake-timers]` Update to `@sinonjs/fake-timers` to v7 ([#11198](https://github.com/facebook/jest/pull/11198))
- `[jest-haste-map]` Handle injected scm clocks ([#10966](https://github.com/facebook/jest/pull/10966))

View File

@ -8,6 +8,7 @@
import {tmpdir} from 'os';
import * as path from 'path';
import * as fs from 'graceful-fs';
import {onNodeVersions} from '@jest/test-utils';
import {
cleanup,
createEmptyPackage,
@ -192,3 +193,13 @@ test('properly handle rejections', () => {
expect(stderr).toContain('Error: Jest: Got error running globalSetup');
expect(stderr).toContain('reason: undefined');
});
onNodeVersions('^12.17.0 || >=13.2.0', () => {
test('globalSetup works with ESM modules', () => {
const {exitCode} = runJest('global-setup-esm', [`--no-cache`], {
nodeOptions: '--experimental-vm-modules --no-warnings',
});
expect(exitCode).toBe(0);
});
});

View File

@ -8,6 +8,7 @@
import {tmpdir} from 'os';
import * as path from 'path';
import * as fs from 'graceful-fs';
import {onNodeVersions} from '@jest/test-utils';
import {createDirectory} from 'jest-util';
import {cleanup, runYarnInstall} from '../Utils';
import runJest, {json as runWithJson} from '../runJest';
@ -131,3 +132,13 @@ test('globalTeardown throws with named export', () => {
`globalTeardown file must export a function at ${teardownPath}`,
);
});
onNodeVersions('^12.17.0 || >=13.2.0', () => {
test('globalTeardown works with ESM modules', () => {
const {exitCode} = runJest('global-teardown-esm', [`--no-cache`], {
nodeOptions: '--experimental-vm-modules --no-warnings',
});
expect(exitCode).toBe(0);
});
});

View File

@ -0,0 +1,20 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates. 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.
*/
import os from 'os';
import path from 'path';
import fs from 'graceful-fs';
import greeting from '../';
const DIR = path.join(os.tmpdir(), 'jest-global-setup-esm');
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');
});

View File

@ -0,0 +1,8 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates. 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.
*/
export default 'hello!';

View File

@ -0,0 +1,8 @@
{
"type": "module",
"jest": {
"testEnvironment": "node",
"globalSetup": "<rootDir>/setup.js",
"transform": {}
}
}

View File

@ -0,0 +1,24 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates. 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.
*/
import crypto from 'crypto';
import os from 'os';
import path from 'path';
import fs from 'graceful-fs';
import jestUtil from 'jest-util';
const {createDirectory} = jestUtil;
const DIR = path.join(os.tmpdir(), 'jest-global-setup-esm');
export default function () {
return new Promise(resolve => {
createDirectory(DIR);
const fileId = crypto.randomBytes(20).toString('hex');
fs.writeFileSync(path.join(DIR, fileId), 'setup');
resolve();
});
}

View File

@ -0,0 +1,17 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates. 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.
*/
import os from 'os';
import path from 'path';
import fs from 'graceful-fs';
import greeting from '../';
const DIR = path.join(os.tmpdir(), 'jest-global-teardown-esm');
test('should not exist teardown file', () => {
expect(fs.existsSync(DIR)).toBe(false);
});

View File

@ -0,0 +1,8 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates. 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.
*/
export default 'hello!';

View File

@ -0,0 +1,8 @@
{
"type": "module",
"jest": {
"testEnvironment": "node",
"globalTeardown": "<rootDir>/teardown.js",
"transform": {}
}
}

View File

@ -0,0 +1,24 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates. 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.
*/
import crypto from 'crypto';
import os from 'os';
import path from 'path';
import fs from 'graceful-fs';
import jestUtil from 'jest-util';
const {createDirectory} = jestUtil;
const DIR = path.join(os.tmpdir(), 'jest-global-teardown-esm');
export default function () {
return new Promise(resolve => {
createDirectory(DIR);
const fileId = crypto.randomBytes(20).toString('hex');
fs.writeFileSync(path.join(DIR, fileId), 'teardown');
resolve();
});
}

View File

@ -5,6 +5,7 @@
* LICENSE file in the root directory of this source tree.
*/
import {pathToFileURL} from 'url';
import * as util from 'util';
import pEachSeries = require('p-each-series');
import {createScriptTransformer} from '@jest/transform';
@ -60,18 +61,41 @@ export default async ({
await globalModule(globalConfig);
});
} catch (error) {
if (util.types.isNativeError(error)) {
error.message = `Jest: Got error running ${moduleName} - ${modulePath}, reason: ${error.message}`;
if (error && error.code === 'ERR_REQUIRE_ESM') {
const configUrl = pathToFileURL(modulePath);
throw error;
// node `import()` supports URL, but TypeScript doesn't know that
const importedConfig = await import(configUrl.href);
if (!importedConfig.default) {
throw new Error(
`Jest: Failed to load ESM transformer at ${modulePath} - did you use a default export?`,
);
}
const globalModule = importedConfig.default;
if (typeof globalModule !== 'function') {
throw new TypeError(
`${moduleName} file must export a function at ${modulePath}`,
);
}
await globalModule(globalConfig);
} else {
if (util.types.isNativeError(error)) {
error.message = `Jest: Got error running ${moduleName} - ${modulePath}, reason: ${error.message}`;
throw error;
}
throw new Error(
`Jest: Got error running ${moduleName} - ${modulePath}, reason: ${prettyFormat(
error,
{maxDepth: 3},
)}`,
);
}
throw new Error(
`Jest: Got error running ${moduleName} - ${modulePath}, reason: ${prettyFormat(
error,
{maxDepth: 3},
)}`,
);
}
});
}