Skip to content

Commit

Permalink
feat: override module.createRequire (#9469)
Browse files Browse the repository at this point in the history
  • Loading branch information
doniyor2109 authored Feb 1, 2020
1 parent 5196b71 commit 523ba3b
Show file tree
Hide file tree
Showing 4 changed files with 147 additions and 9 deletions.
69 changes: 69 additions & 0 deletions packages/jest-runtime/src/__tests__/runtime_require_module.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,12 @@

'use strict';

import {builtinModules, createRequire} from 'module';
import path from 'path';
import {pathToFileURL} from 'url';
// eslint-disable-next-line import/default
import slash from 'slash';
import {onNodeVersions} from '@jest/test-utils';

let createRuntime;

Expand Down Expand Up @@ -347,4 +350,70 @@ describe('Runtime requireModule', () => {
);
expect(exports.isJSONModuleEncodedInUTF8WithBOM).toBe(true);
}));

onNodeVersions('>=12.12.0', () => {
it('overrides module.createRequire', () =>
createRuntime(__filename).then(runtime => {
const exports = runtime.requireModule(runtime.__mockRootPath, 'module');

expect(exports.createRequire).not.toBe(createRequire);

// createRequire with string
{
const customRequire = exports.createRequire(runtime.__mockRootPath);
expect(customRequire('./create_require_module').foo).toBe('foo');
}

// createRequire with URL object
{
const customRequire = exports.createRequire(
pathToFileURL(runtime.__mockRootPath),
);
expect(customRequire('./create_require_module').foo).toBe('foo');
}

// createRequire with file URL string
{
const customRequire = exports.createRequire(
pathToFileURL(runtime.__mockRootPath).toString(),
);
expect(customRequire('./create_require_module').foo).toBe('foo');
}

// createRequire with absolute module path
{
const customRequire = exports.createRequire(runtime.__mockRootPath);
expect(customRequire('./create_require_module').foo).toBe('foo');
}

// createRequire with relative module path
expect(() => exports.createRequireFromPath('./relative/path')).toThrow(
new TypeError(
`The argument 'filename' must be a file URL object, file URL string, or absolute path string. Received './relative/path'`,
),
);

// createRequireFromPath with absolute module path
{
const customRequire = exports.createRequireFromPath(
runtime.__mockRootPath,
);
expect(customRequire('./create_require_module').foo).toBe('foo');
}

// createRequireFromPath with file URL object
expect(() =>
exports.createRequireFromPath(pathToFileURL(runtime.__mockRootPath)),
).toThrow(
new TypeError(
`The argument 'filename' must be string. Received '${pathToFileURL(
runtime.__mockRootPath,
)}'. Use createRequire for URL filename.`,
),
);

expect(exports.syncBuiltinESMExports).not.toThrow();
expect(exports.builtinModules).toEqual(builtinModules);
}));
});
});
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.foo = 'foo';
71 changes: 65 additions & 6 deletions packages/jest-runtime/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,10 @@
* LICENSE file in the root directory of this source tree.
*/

import {URL, fileURLToPath} from 'url';
import * as path from 'path';
import {Script, compileFunction} from 'vm';
import {fileURLToPath} from 'url';
import * as nativeModule from 'module';
import {Config} from '@jest/types';
import {
Jest,
Expand All @@ -17,13 +18,9 @@ import {
ModuleWrapper,
} from '@jest/environment';
import {SourceMapRegistry} from '@jest/source-map';
import jestMock = require('jest-mock');
import HasteMap = require('jest-haste-map');
import {formatStackTrace, separateMessageFromStack} from 'jest-message-util';
import Resolver = require('jest-resolve');
import {createDirectory, deepCyclicCopy} from 'jest-util';
import {escapePathForRegex} from 'jest-regex-util';
import Snapshot = require('jest-snapshot');
import {
ScriptTransformer,
ShouldInstrumentOptions,
Expand All @@ -35,11 +32,15 @@ import {
import {V8CoverageResult} from '@jest/test-result';
import {CoverageInstrumenter, V8Coverage} from 'collect-v8-coverage';
import * as fs from 'graceful-fs';
import stripBOM = require('strip-bom');
import {run as cliRun} from './cli';
import {options as cliOptions} from './cli/args';
import {findSiblingsWithFileExtension} from './helpers';
import {Context as JestContext} from './types';
import jestMock = require('jest-mock');
import HasteMap = require('jest-haste-map');
import Resolver = require('jest-resolve');
import Snapshot = require('jest-snapshot');
import stripBOM = require('strip-bom');

type HasteMapOptions = {
console?: Console;
Expand Down Expand Up @@ -887,6 +888,64 @@ class Runtime {
return this._environment.global.process;
}

if (moduleName === 'module') {
const createRequire = (modulePath: string | URL) => {
const filename =
typeof modulePath === 'string'
? modulePath.startsWith('file:///')
? fileURLToPath(new URL(modulePath))
: modulePath
: fileURLToPath(modulePath);

if (!path.isAbsolute(filename)) {
const error = new TypeError(
`The argument 'filename' must be a file URL object, file URL string, or absolute path string. Received '${filename}'`,
);
// @ts-ignore
error.code = 'ERR_INVALID_ARG_TYPE';
throw error;
}

return this._createRequireImplementation({
children: [],
exports: {},
filename,
id: filename,
loaded: false,
});
};

const overriddenModules: Partial<typeof nativeModule> = {};

if ('createRequire' in nativeModule) {
overriddenModules.createRequire = createRequire;
}
if ('createRequireFromPath' in nativeModule) {
overriddenModules.createRequireFromPath = (filename: string | URL) => {
if (typeof filename !== 'string') {
const error = new TypeError(
`The argument 'filename' must be string. Received '${filename}'.${
filename instanceof URL
? ' Use createRequire for URL filename.'
: ''
}`,
);
// @ts-ignore
error.code = 'ERR_INVALID_ARG_TYPE';
throw error;
}
return createRequire(filename);
};
}
if ('syncBuiltinESMExports' in nativeModule) {
overriddenModules.syncBuiltinESMExports = () => {};
}

return Object.keys(overriddenModules).length > 0
? {...nativeModule, ...overriddenModules}
: nativeModule;
}

return require(moduleName);
}

Expand Down
6 changes: 3 additions & 3 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -2244,9 +2244,9 @@
"@types/node" "*"

"@types/node@*", "@types/node@>= 8":
version "13.5.2"
resolved "https://registry.yarnpkg.com/@types/node/-/node-13.5.2.tgz#3de53b55fd39efc428a901a0f6db31f761cfa131"
integrity sha512-Fr6a47c84PRLfd7M7u3/hEknyUdQrrBA6VoPmkze0tcflhU5UnpWEX2kn12ktA/lb+MNHSqFlSiPHIHsaErTPA==
version "13.7.0"
resolved "https://registry.yarnpkg.com/@types/node/-/node-13.7.0.tgz#b417deda18cf8400f278733499ad5547ed1abec4"
integrity sha512-GnZbirvmqZUzMgkFn70c74OQpTTUcCzlhQliTzYjQMqg+hVKcDnxdL19Ne3UdYzdMA/+W3eb646FWn/ZaT1NfQ==

"@types/prettier@^1.16.1":
version "1.19.0"
Expand Down

0 comments on commit 523ba3b

Please sign in to comment.