Skip to content

Commit 3d83dc3

Browse files
committed
support importing node core modules
1 parent d7df13c commit 3d83dc3

File tree

3 files changed

+54
-3
lines changed

3 files changed

+54
-3
lines changed

e2e/__tests__/__snapshots__/nativeEsm.test.ts.snap

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
exports[`on node ^12.16.0 || >=13.0.0 runs test with native ESM 1`] = `
44
Test Suites: 1 passed, 1 total
5-
Tests: 2 passed, 2 total
5+
Tests: 3 passed, 3 total
66
Snapshots: 0 total
77
Time: <<REPLACED>>
88
Ran all test suites.

e2e/native-esm/__tests__/native-esm.test.js

+17
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,13 @@
55
* LICENSE file in the root directory of this source tree.
66
*/
77

8+
import {readFileSync} from 'fs';
9+
import {dirname, resolve} from 'path';
10+
import {fileURLToPath} from 'url';
811
import {double} from '../index';
912

1013
test('should have correct import.meta', () => {
14+
expect(typeof require).toBe('undefined');
1115
expect(typeof jest).toBe('undefined');
1216
expect(import.meta).toEqual({
1317
jest: expect.anything(),
@@ -21,3 +25,16 @@ test('should have correct import.meta', () => {
2125
test('should double stuff', () => {
2226
expect(double(1)).toBe(2);
2327
});
28+
29+
test('should support importing node core modules', () => {
30+
const dir = dirname(fileURLToPath(import.meta.url));
31+
const packageJsonPath = resolve(dir, '../package.json');
32+
33+
expect(JSON.parse(readFileSync(packageJsonPath, 'utf8'))).toEqual({
34+
jest: {
35+
testEnvironment: 'node',
36+
transform: {},
37+
},
38+
type: 'module',
39+
});
40+
});

packages/jest-runtime/src/index.ts

+36-2
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@ import {
1212
// @ts-ignore: experimental, not added to the types
1313
SourceTextModule,
1414
// @ts-ignore: experimental, not added to the types
15+
SyntheticModule,
16+
Context as VMContext,
17+
// @ts-ignore: experimental, not added to the types
1518
Module as VMModule,
1619
compileFunction,
1720
} from 'vm';
@@ -337,6 +340,12 @@ class Runtime {
337340

338341
invariant(context);
339342

343+
if (this._resolver.isCoreModule(modulePath)) {
344+
const core = await this._importCoreModule(modulePath, context);
345+
this._esmoduleRegistry.set(cacheKey, core);
346+
return core;
347+
}
348+
340349
const transformedFile = this.transformFile(modulePath, {
341350
isInternalModule: false,
342351
supportsDynamicImport: true,
@@ -1030,6 +1039,24 @@ class Runtime {
10301039
return require(moduleName);
10311040
}
10321041

1042+
private _importCoreModule(moduleName: string, context: VMContext) {
1043+
const required = this._requireCoreModule(moduleName);
1044+
1045+
return new SyntheticModule(
1046+
['default', ...Object.keys(required)],
1047+
function () {
1048+
// @ts-ignore: TS doesn't know what `this` is
1049+
this.setExport('default', required);
1050+
Object.entries(required).forEach(([key, value]) => {
1051+
// @ts-ignore: TS doesn't know what `this` is
1052+
this.setExport(key, value);
1053+
});
1054+
},
1055+
// should identifier be `node://${moduleName}`?
1056+
{context, identifier: moduleName},
1057+
);
1058+
}
1059+
10331060
private _getMockedNativeModule(): typeof nativeModule.Module {
10341061
if (this._moduleImplementation) {
10351062
return this._moduleImplementation;
@@ -1064,13 +1091,20 @@ class Runtime {
10641091
// should we implement the class ourselves?
10651092
class Module extends nativeModule.Module {}
10661093

1094+
Object.entries(nativeModule.Module).forEach(([key, value]) => {
1095+
// @ts-ignore
1096+
Module[key] = value;
1097+
});
1098+
10671099
Module.Module = Module;
10681100

10691101
if ('createRequire' in nativeModule) {
10701102
Module.createRequire = createRequire;
10711103
}
10721104
if ('createRequireFromPath' in nativeModule) {
1073-
Module.createRequireFromPath = (filename: string | URL) => {
1105+
Module.createRequireFromPath = function createRequireFromPath(
1106+
filename: string | URL,
1107+
) {
10741108
if (typeof filename !== 'string') {
10751109
const error = new TypeError(
10761110
`The argument 'filename' must be string. Received '${filename}'.${
@@ -1087,7 +1121,7 @@ class Runtime {
10871121
};
10881122
}
10891123
if ('syncBuiltinESMExports' in nativeModule) {
1090-
Module.syncBuiltinESMExports = () => {};
1124+
Module.syncBuiltinESMExports = function syncBuiltinESMExports() {};
10911125
}
10921126

10931127
this._moduleImplementation = Module;

0 commit comments

Comments
 (0)