Skip to content

Commit

Permalink
Merge branch 'runtime-require-resolve-outside' into uglier-inline-sna…
Browse files Browse the repository at this point in the history
…pshots

* runtime-require-resolve-outside:
  lint
  review improvements
  implement require.resolve option outsideJestVm for internal modules only
  basic jest-runtime require.resolve test
  Fix dead link to coverage CLI option (jestjs#9905)
  chore: remove dated node 6 reference from docs (jestjs#9895)
  Use the new serializer plugin API in example (jestjs#9847)
  chore: remove unused catch clauses (jestjs#9893)
  • Loading branch information
jeysal committed Apr 28, 2020
2 parents 27cf6e0 + faed042 commit 49bed60
Show file tree
Hide file tree
Showing 17 changed files with 391 additions and 31 deletions.
8 changes: 5 additions & 3 deletions docs/Configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -830,8 +830,8 @@ Example serializer module:
```js
// my-serializer-module
module.exports = {
print(val, serialize, indent) {
return 'Pretty foo: ' + serialize(val.foo);
serialize(val, config, indentation, depth, refs, printer) {
return 'Pretty foo: ' + printer(val.foo);
},

test(val) {
Expand All @@ -840,7 +840,7 @@ module.exports = {
};
```

`serialize` is a function that serializes a value using existing plugins.
`printer` is a function that serializes a value using existing plugins.

To use `my-serializer-module` as a serializer, configuration would be as follows:

Expand Down Expand Up @@ -879,6 +879,8 @@ Pretty foo: Object {

To make a dependency explicit instead of implicit, you can call [`expect.addSnapshotSerializer`](ExpectAPI.md#expectaddsnapshotserializerserializer) to add a module for an individual test file instead of adding its path to `snapshotSerializers` in Jest configuration.

More about serializers API can be found [here](https://github.com/facebook/jest/tree/master/packages/pretty-format/README.md#serialize).

### `testEnvironment` [string]

Default: `"jsdom"`
Expand Down
4 changes: 0 additions & 4 deletions docs/Troubleshooting.md
Original file line number Diff line number Diff line change
Expand Up @@ -184,10 +184,6 @@ jest --maxWorkers=4
yarn test --maxWorkers=4
```

## Compatibility issues

Jest takes advantage of new features added to Node 6. We recommend that you upgrade to the latest stable release of Node. The minimum supported version is `v6.0.0`. Versions `0.x.x` and `4.x.x` are not supported because the `jsdom` version used in Jest doesn't support Node 4. However, if you need to run Jest on Node 4, you can use the `testEnvironment` config to use a [custom environment](https://jestjs.io/docs/en/configuration.html#testenvironment-string) that supports Node 4, such as [`jest-environment-node`](https://yarnpkg.com/en/package/jest-environment-node).
## `coveragePathIgnorePatterns` seems to not have any effect.

Make sure you are not using the `babel-plugin-istanbul` plugin. Jest wraps Istanbul, and therefore also tells Istanbul what files to instrument with coverage collection. When using `babel-plugin-istanbul`, every file that is processed by Babel will have coverage collection code, hence it is not being ignored by `coveragePathIgnorePatterns`.
Expand Down
2 changes: 1 addition & 1 deletion packages/jest-resolve/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -218,7 +218,7 @@ class Resolver {
resolveNodeModule(module) || require.resolve(module);
this._moduleNameCache.set(key, resolvedModule);
return resolvedModule;
} catch (ignoredError) {}
} catch {}
}

return null;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
/**
* 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 type {Config} from '@jest/types';
import type Runtime from '..';

let createRuntime: (
path: string,
config?: Config.InitialOptions,
) => Promise<Runtime & {__mockRootPath: string}>;

describe('Runtime require.resolve', () => {
beforeEach(() => {
createRuntime = require('createRuntime');
});

it('resolves a module path', async () => {
const runtime = await createRuntime(__filename);
const resolved = runtime.requireModule(
runtime.__mockRootPath,
'./resolve_self.js',
);
expect(resolved).toEqual(require.resolve('./test_root/resolve_self.js'));
});

it('resolves a module path with moduleNameMapper', async () => {
const runtime = await createRuntime(__filename, {
moduleNameMapper: {
'^testMapped/(.*)': '<rootDir>/mapped_dir/$1',
},
});
const resolved = runtime.requireModule(
runtime.__mockRootPath,
'./resolve_mapped.js',
);
expect(resolved).toEqual(
require.resolve('./test_root/mapped_dir/moduleInMapped.js'),
);
});

describe('with the outsideJestVm option', () => {
it('forwards to the real Node require in an internal context', async () => {
const runtime = await createRuntime(__filename);
const module = runtime.requireInternalModule(
runtime.__mockRootPath,
'./resolve_and_require_outside.js',
);
expect(module).toBe(require('./test_root/create_require_module'));
});

it('ignores the option in an external context', async () => {
const runtime = await createRuntime(__filename);
const module = runtime.requireModule<any>(
runtime.__mockRootPath,
'./resolve_and_require_outside.js',
);
expect(module.foo).toBe('foo');
expect(module).not.toBe(require('./test_root/create_require_module'));
});
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
/**
* 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.
*/

'use strict';

const path = require.resolve('./create_require_module', {outsideJestVm: true});
if (typeof path !== 'string') {
throw new Error('require.resolve not spec-compliant: must return a string');
}
module.exports = require(path);
10 changes: 10 additions & 0 deletions packages/jest-runtime/src/__tests__/test_root/resolve_mapped.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
/**
* 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.
*/

'use strict';

module.exports = require.resolve('testMapped/moduleInMapped');
10 changes: 10 additions & 0 deletions packages/jest-runtime/src/__tests__/test_root/resolve_self.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
/**
* 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.
*/

'use strict';

module.exports = require.resolve('./resolve_self');
21 changes: 20 additions & 1 deletion packages/jest-runtime/src/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,25 @@ import slash = require('slash');
import glob = require('glob');
import type {Config} from '@jest/types';

const OUTSIDE_JEST_VM_PROTOCOL = 'jest-main:';
// String manipulation is easier here, fileURLToPath is only in newer Nodes,
// plus setting non-standard protocols on URL objects is difficult.
export const createOutsideJestVmPath = (path: string): string =>
OUTSIDE_JEST_VM_PROTOCOL + '//' + encodeURIComponent(path);
export const decodePossibleOutsideJestVmPath = (
outsideJestVmPath: string,
): string | undefined => {
if (outsideJestVmPath.startsWith(OUTSIDE_JEST_VM_PROTOCOL)) {
return decodeURIComponent(
outsideJestVmPath.replace(
new RegExp('^' + OUTSIDE_JEST_VM_PROTOCOL + '//'),
'',
),
);
}
return undefined;
};

export const findSiblingsWithFileExtension = (
moduleFileExtensions: Config.ProjectConfig['moduleFileExtensions'],
from: Config.Path,
Expand Down Expand Up @@ -48,7 +67,7 @@ export const findSiblingsWithFileExtension = (
`[${mappedModuleFileExtensions}].\n\nSee https://jestjs.io/docs/en/configuration#modulefileextensions-arraystring`
);
}
} catch (ignored) {}
} catch {}
}

return '';
Expand Down
32 changes: 27 additions & 5 deletions packages/jest-runtime/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,11 @@ import {CoverageInstrumenter, V8Coverage} from 'collect-v8-coverage';
import * as fs from 'graceful-fs';
import {run as cliRun} from './cli';
import {options as cliOptions} from './cli/args';
import {findSiblingsWithFileExtension} from './helpers';
import {
createOutsideJestVmPath,
decodePossibleOutsideJestVmPath,
findSiblingsWithFileExtension,
} from './helpers';
import type {Context as JestContext} from './types';
import jestMock = require('jest-mock');
import HasteMap = require('jest-haste-map');
Expand Down Expand Up @@ -81,7 +85,10 @@ const defaultTransformOptions: InternalModuleOptions = {
type InitialModule = Partial<Module> &
Pick<Module, 'children' | 'exports' | 'filename' | 'id' | 'loaded'>;
type ModuleRegistry = Map<string, InitialModule | Module>;
type ResolveOptions = Parameters<typeof require.resolve>[1];

type ResolveOptions = Parameters<typeof require.resolve>[1] & {
outsideJestVm?: true;
};

type BooleanObject = Record<string, boolean>;
type CacheFS = {[path: string]: string};
Expand Down Expand Up @@ -534,6 +541,13 @@ class Runtime {
}

requireInternalModule<T = unknown>(from: Config.Path, to?: string): T {
if (to) {
const outsideJestVmPath = decodePossibleOutsideJestVmPath(to);
if (outsideJestVmPath) {
return require(outsideJestVmPath);
}
}

return this.requireModule(from, to, {
isInternalModule: true,
supportsDynamicImport: false,
Expand Down Expand Up @@ -1269,9 +1283,17 @@ class Runtime {
from: InitialModule,
options?: InternalModuleOptions,
): LocalModuleRequire {
// TODO: somehow avoid having to type the arguments - they should come from `NodeRequire/LocalModuleRequire.resolve`
const resolve = (moduleName: string, options: ResolveOptions) =>
this._requireResolve(from.filename, moduleName, options);
const resolve = (moduleName: string, resolveOptions?: ResolveOptions) => {
const resolved = this._requireResolve(
from.filename,
moduleName,
resolveOptions,
);
if (resolveOptions?.outsideJestVm && options?.isInternalModule) {
return createOutsideJestVmPath(resolved);
}
return resolved;
};
resolve.paths = (moduleName: string) =>
this._requireResolvePaths(from.filename, moduleName);

Expand Down
2 changes: 1 addition & 1 deletion packages/jest-worker/src/WorkerPool.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ const canUseWorkerThreads = () => {
try {
require('worker_threads');
return true;
} catch (_) {
} catch {
return false;
}
};
Expand Down
2 changes: 1 addition & 1 deletion website/pages/en/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -376,7 +376,7 @@ class Index extends React.Component {
content: (
<translate>
Generate code coverage by adding the flag
[`--coverage`](https://jestjs.io/docs/en/cli.html#coverage).
[`--coverage`](https://jestjs.io/docs/en/cli.html#--coverageboolean).
No additional setup needed. Jest can collect code coverage
information from entire projects, including untested
files.
Expand Down
8 changes: 5 additions & 3 deletions website/versioned_docs/version-22.x/Configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -598,8 +598,8 @@ Example serializer module:
```js
// my-serializer-module
module.exports = {
print(val, serialize, indent) {
return 'Pretty foo: ' + serialize(val.foo);
serialize(val, config, indentation, depth, refs, printer) {
return 'Pretty foo: ' + printer(val.foo);
},

test(val) {
Expand All @@ -608,7 +608,7 @@ module.exports = {
};
```

`serialize` is a function that serializes a value using existing plugins.
`printer` is a function that serializes a value using existing plugins.

To use `my-serializer-module` as a serializer, configuration would be as follows:

Expand Down Expand Up @@ -647,6 +647,8 @@ Pretty foo: Object {

To make a dependency explicit instead of implicit, you can call [`expect.addSnapshotSerializer`](ExpectAPI.md#expectaddsnapshotserializerserializer) to add a module for an individual test file instead of adding its path to `snapshotSerializers` in Jest configuration.

More about serializers API can be found [here](https://github.com/facebook/jest/tree/master/packages/pretty-format#serialize).

### `testEnvironment` [string]

Default: `"jsdom"`
Expand Down
8 changes: 5 additions & 3 deletions website/versioned_docs/version-23.x/Configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -662,8 +662,8 @@ Example serializer module:
```js
// my-serializer-module
module.exports = {
print(val, serialize, indent) {
return 'Pretty foo: ' + serialize(val.foo);
serialize(val, config, indentation, depth, refs, printer) {
return 'Pretty foo: ' + printer(val.foo);
},

test(val) {
Expand All @@ -672,7 +672,7 @@ module.exports = {
};
```

`serialize` is a function that serializes a value using existing plugins.
`printer` is a function that serializes a value using existing plugins.

To use `my-serializer-module` as a serializer, configuration would be as follows:

Expand Down Expand Up @@ -711,6 +711,8 @@ Pretty foo: Object {

To make a dependency explicit instead of implicit, you can call [`expect.addSnapshotSerializer`](ExpectAPI.md#expectaddsnapshotserializerserializer) to add a module for an individual test file instead of adding its path to `snapshotSerializers` in Jest configuration.

More about serializers API can be found [here](https://github.com/facebook/jest/tree/master/packages/pretty-format#serialize).

### `testEnvironment` [string]

Default: `"jsdom"`
Expand Down
8 changes: 5 additions & 3 deletions website/versioned_docs/version-24.x/Configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -807,8 +807,8 @@ Example serializer module:
```js
// my-serializer-module
module.exports = {
print(val, serialize, indent) {
return 'Pretty foo: ' + serialize(val.foo);
serialize(val, config, indentation, depth, refs, printer) {
return 'Pretty foo: ' + printer(val.foo);
},

test(val) {
Expand All @@ -817,7 +817,7 @@ module.exports = {
};
```

`serialize` is a function that serializes a value using existing plugins.
`printer` is a function that serializes a value using existing plugins.

To use `my-serializer-module` as a serializer, configuration would be as follows:

Expand Down Expand Up @@ -856,6 +856,8 @@ Pretty foo: Object {

To make a dependency explicit instead of implicit, you can call [`expect.addSnapshotSerializer`](ExpectAPI.md#expectaddsnapshotserializerserializer) to add a module for an individual test file instead of adding its path to `snapshotSerializers` in Jest configuration.

More about serializers API can be found [here](https://github.com/facebook/jest/tree/master/packages/pretty-format#serialize).

### `testEnvironment` [string]

Default: `"jsdom"`
Expand Down
8 changes: 5 additions & 3 deletions website/versioned_docs/version-25.1/Configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -818,8 +818,8 @@ Example serializer module:
```js
// my-serializer-module
module.exports = {
print(val, serialize, indent) {
return 'Pretty foo: ' + serialize(val.foo);
serialize(val, config, indentation, depth, refs, printer) {
return 'Pretty foo: ' + printer(val.foo);
},

test(val) {
Expand All @@ -828,7 +828,7 @@ module.exports = {
};
```

`serialize` is a function that serializes a value using existing plugins.
`printer` is a function that serializes a value using existing plugins.

To use `my-serializer-module` as a serializer, configuration would be as follows:

Expand Down Expand Up @@ -867,6 +867,8 @@ Pretty foo: Object {

To make a dependency explicit instead of implicit, you can call [`expect.addSnapshotSerializer`](ExpectAPI.md#expectaddsnapshotserializerserializer) to add a module for an individual test file instead of adding its path to `snapshotSerializers` in Jest configuration.

More about serializers API can be found [here](https://github.com/facebook/jest/tree/master/packages/pretty-format#serialize).

### `testEnvironment` [string]

Default: `"jsdom"`
Expand Down

0 comments on commit 49bed60

Please sign in to comment.