Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(jest-haste-map): support dependencyExtractor written in ESM #12008

Merged
merged 9 commits into from
Feb 24, 2022
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

### Features

- `[jest-core, jest-haste-map, jest-runtime]` Add support for `dependencyExtractor` written in ESM ([#12008](https://github.com/facebook/jest/pull/12008))
- `[babel-jest]` Export `createTransformer` function ([#12399](https://github.com/facebook/jest/pull/12399))
- `[expect]` Expose `AsymmetricMatchers`, `MatcherFunction` and `MatcherFunctionWithState` interfaces ([#12363](https://github.com/facebook/jest/pull/12363), [#12376](https://github.com/facebook/jest/pull/12376))
- `[jest-cli, jest-config]` [**BREAKING**] Remove `testURL` config, use `testEnvironmentOptions.url` instead ([#10797](https://github.com/facebook/jest/pull/10797))
Expand Down
50 changes: 50 additions & 0 deletions e2e/__tests__/findRelatedFiles.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,56 @@ describe('--findRelatedTests flag', () => {
expect(stderr).toMatch(summaryMsg);
});

test('runs tests related to filename with a custom dependency extractor written in ESM', () => {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@SimenB I am not sure if this is a valid e2e test of ESM dependency extractor. I just found a commonjs version above and did the same against ESM.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

that's fine 👍

writeFiles(DIR, {
'.watchmanconfig': '',
'__tests__/test-skip-deps.test.js': `
const dynamicImport = path => Promise.resolve(require(path));
test('a', () => dynamicImport('../a').then(a => {
expect(a.foo).toBe(5);
}));
`,
'__tests__/test.test.js': `
const dynamicImport = path => Promise.resolve(require(path));
test('a', () => dynamicImport('../a').then(a => {
expect(a.foo).toBe(5);
}));
`,
'a.js': 'module.exports = {foo: 5};',
'dependencyExtractor.mjs': `
const DYNAMIC_IMPORT_RE = /(?:^|[^.]\\s*)(\\bdynamicImport\\s*?\\(\\s*?)([\`'"])([^\`'"]+)(\\2\\s*?\\))/g;
export function extract(code, filePath) {
const dependencies = new Set();
if (filePath.includes('skip-deps')) {
return dependencies;
}
const addDependency = (match, pre, quot, dep, post) => {
dependencies.add(dep);
return match;
};
code.replace(DYNAMIC_IMPORT_RE, addDependency);
return dependencies;
};
`,
'package.json': JSON.stringify({
jest: {
dependencyExtractor: '<rootDir>/dependencyExtractor.mjs',
testEnvironment: 'node',
},
}),
});

const {stdout} = runJest(DIR, ['a.js']);
expect(stdout).toMatch('');

const {stderr} = runJest(DIR, ['--findRelatedTests', 'a.js']);
expect(stderr).toMatch('PASS __tests__/test.test.js');
expect(stderr).not.toMatch('PASS __tests__/test-skip-deps.test.js');

const summaryMsg = 'Ran all test suites related to files matching /a.js/i.';
expect(stderr).toMatch(summaryMsg);
});

test('generates coverage report for filename', () => {
writeFiles(DIR, {
'.watchmanconfig': '',
Expand Down
4 changes: 2 additions & 2 deletions e2e/__tests__/hasteMapMockChanged.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,11 +37,11 @@ test('should not warn when a mock file changes', async () => {
writeFiles(DIR, {
'__mocks__/fs.js': '"foo fs"',
});
await new JestHasteMap(hasteConfig).build();
await (await JestHasteMap.create(hasteConfig)).build();

// This will throw if the mock file being updated triggers a warning.
writeFiles(DIR, {
'__mocks__/fs.js': '"foo fs!"',
});
await new JestHasteMap(hasteConfig).build();
await (await JestHasteMap.create(hasteConfig)).build();
});
2 changes: 1 addition & 1 deletion e2e/__tests__/hasteMapSha1.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ test('exits the process after test are done but before timers complete', async (
'node_modules/bar/index.js': '"node modules bar"',
});

const haste = new JestHasteMap({
const haste = await JestHasteMap.create({
computeSha1: true,
extensions: ['js', 'json', 'png'],
forceNodeFilesystemAPI: true,
Expand Down
4 changes: 2 additions & 2 deletions e2e/__tests__/hasteMapSize.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,13 +37,13 @@ const options = {
};

test('reports the correct file size', async () => {
const hasteMap = new HasteMap(options);
const hasteMap = await HasteMap.create(options);
const hasteFS = (await hasteMap.build()).hasteFS;
expect(hasteFS.getSize(path.join(DIR, 'file.js'))).toBe(5);
});

test('updates the file size when a file changes', async () => {
const hasteMap = new HasteMap({...options, watch: true});
const hasteMap = await HasteMap.create({...options, watch: true});
await hasteMap.build();

writeFiles(DIR, {
Expand Down
2 changes: 1 addition & 1 deletion packages/jest-core/src/cli/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ const buildContextsAndHasteMaps = async (
const contexts = await Promise.all(
configs.map(async (config, index) => {
createDirectory(config.cacheDirectory);
const hasteMapInstance = Runtime.createHasteMap(config, {
const hasteMapInstance = await Runtime.createHasteMap(config, {
console: new CustomConsole(outputStream, outputStream),
maxWorkers: Math.max(
1,
Expand Down
37 changes: 37 additions & 0 deletions packages/jest-haste-map/src/__tests__/dependencyExtractor.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/**
* 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.
*/

const blockCommentRe = /\/\*[^]*?\*\//g;
const lineCommentRe = /\/\/.*/g;
const LOAD_MODULE_RE =
/(?:^|[^.]\s*)(\bloadModule\s*?\(\s*?)([`'"])([^`'"]+)(\2\s*?\))/g;

export function extract(code, filePath, defaultDependencyExtractor) {
const dependencies = defaultDependencyExtractor(code);

const addDependency = (match, pre, quot, dep, post) => {
dependencies.add(dep);
return match;
};

code
.replace(blockCommentRe, '')
.replace(lineCommentRe, '')
.replace(LOAD_MODULE_RE, addDependency);

return dependencies;
}

let cacheKey;

export function getCacheKey() {
return cacheKey;
}

export function setCacheKey(key) {
cacheKey = key;
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,13 @@ const commonOptions = {
};

test('watchman crawler and node crawler both include dotfiles', async () => {
const hasteMapWithWatchman = new HasteMap({
const hasteMapWithWatchman = await HasteMap.create({
...commonOptions,
name: 'withWatchman',
useWatchman: true,
});

const hasteMapWithNode = new HasteMap({
const hasteMapWithNode = await HasteMap.create({
...commonOptions,
name: 'withNode',
useWatchman: false,
Expand Down
Loading