mirror of
https://github.com/hanzoai/jest.git
synced 2026-09-24 16:59:57 +00:00
fix(runtime): resolve expect and @jest/expect from the internal module registry (#16130)
This commit is contained in:
@@ -26,6 +26,7 @@
|
||||
- `[jest-circus, jest-jasmine2]` Include `Error.cause` in JSON `failureMessages` output ([#15949](https://github.com/jestjs/jest/issues/15949))
|
||||
- `[jest-config]` Fix preset path resolution on Windows when the preset uses subpath `exports` ([#15961](https://github.com/jestjs/jest/pull/15961))
|
||||
- `[jest-environment-node]` Fix `--localstorage-file` warning on Node 25+ ([#16086](https://github.com/jestjs/jest/pull/16086))
|
||||
- `[jest-runtime]` Resolve `expect` and `@jest/expect` from the internal module registry so test-file imports share the same `JestAssertionError` as the global `expect` ([#16130](https://github.com/jestjs/jest/pull/16130))
|
||||
- `[jest-runtime]` Improve CJS-from-ESM interop: `__esModule`/Babel default unwrap, broader named-export coverage, and shared CJS singleton across importers ([#16050](https://github.com/jestjs/jest/pull/16050))
|
||||
- `[jest-runtime]` Load `.js` files with ESM syntax but no `"type":"module"` marker as native ESM ([#16050](https://github.com/jestjs/jest/pull/16050))
|
||||
- `[jest-runtime]` Extend the `.js`-with-ESM-syntax fallback to `require()` on Node v24.9+ - falls back to `require(esm)` when the CJS parser rejects ESM syntax ([#16078](https://github.com/jestjs/jest/pull/16078))
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
/**
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
import runJest from '../runJest';
|
||||
|
||||
test('toThrow(JestAssertionError) passes when imported from a separate require call', () => {
|
||||
const result = runJest('jest-assertion-error-import');
|
||||
expect(result.exitCode).toBe(0);
|
||||
});
|
||||
@@ -0,0 +1,18 @@
|
||||
/**
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
// `require('expect')` in a test file must resolve to the same module instance
|
||||
// that backs the global `expect`, so JestAssertionError is the same class.
|
||||
const {JestAssertionError} = require('expect');
|
||||
|
||||
test('toThrow(JestAssertionError) passes when a matcher assertion fails', () => {
|
||||
expect(() => {
|
||||
expect('1').toBe(2);
|
||||
}).toThrow(JestAssertionError);
|
||||
});
|
||||
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"jest": {
|
||||
"testEnvironment": "node"
|
||||
}
|
||||
}
|
||||
@@ -197,6 +197,58 @@ it('mock dispatch computes moduleID once per requireModuleOrMock call', async ()
|
||||
getModuleIdSpy.mockRestore();
|
||||
});
|
||||
|
||||
describe.each(['expect', '@jest/expect'])(
|
||||
'framework singleton module: %s',
|
||||
moduleName => {
|
||||
it('requireModuleOrMock returns the internal instance', async () => {
|
||||
const runtime = await createRuntime(__filename);
|
||||
const internal = runtime.requireInternalModule(
|
||||
runtime.__mockRootPath,
|
||||
moduleName,
|
||||
);
|
||||
const user = runtime.requireModuleOrMock(
|
||||
runtime.__mockRootPath,
|
||||
moduleName,
|
||||
);
|
||||
expect(user).toBe(internal);
|
||||
});
|
||||
|
||||
it('requireActual returns the internal instance', async () => {
|
||||
const runtime = await createRuntime(__filename);
|
||||
const internal = runtime.requireInternalModule(
|
||||
runtime.__mockRootPath,
|
||||
moduleName,
|
||||
);
|
||||
const actual = runtime.requireActual(runtime.__mockRootPath, moduleName);
|
||||
expect(actual).toBe(internal);
|
||||
});
|
||||
|
||||
it('jest.mock() is respected and does not affect the global expect', async () => {
|
||||
const runtime = await createRuntime(__filename);
|
||||
const root = runtime.requireModule(runtime.__mockRootPath);
|
||||
const mockImpl = {isMock: true};
|
||||
root.jest.mock(moduleName, () => mockImpl);
|
||||
|
||||
const mocked = runtime.requireModuleOrMock(
|
||||
runtime.__mockRootPath,
|
||||
moduleName,
|
||||
);
|
||||
expect(mocked).toBe(mockImpl);
|
||||
|
||||
// The internal instance backing the global must be unaffected.
|
||||
const internal = runtime.requireInternalModule(
|
||||
runtime.__mockRootPath,
|
||||
moduleName,
|
||||
);
|
||||
expect(internal).not.toBe(mockImpl);
|
||||
|
||||
// requireActual always bypasses the mock and returns the shared instance.
|
||||
const actual = runtime.requireActual(runtime.__mockRootPath, moduleName);
|
||||
expect(actual).toBe(internal);
|
||||
});
|
||||
},
|
||||
);
|
||||
|
||||
it('unmocks virtual mocks after they have been mocked previously', async () => {
|
||||
const runtime = await createRuntime(__filename);
|
||||
const root = runtime.requireModule(runtime.__mockRootPath);
|
||||
|
||||
@@ -57,6 +57,11 @@ import type {EnvironmentGlobals} from './internals/types';
|
||||
// through the VM.
|
||||
const INTERNAL_MODULE_REQUIRE_OUTSIDE_OPTIMIZED_MODULES = new Set(['chalk']);
|
||||
|
||||
// Framework modules that define shared singleton state (e.g. `JestAssertionError`).
|
||||
// Redirecting user requires to the internal registry ensures test code and the
|
||||
// framework see the same class instances.
|
||||
const FRAMEWORK_SINGLETON_MODULES = new Set(['@jest/expect', 'expect']);
|
||||
|
||||
const esmIsAvailable = typeof SourceTextModule === 'function';
|
||||
|
||||
type HasteMapOptions = {
|
||||
@@ -400,6 +405,9 @@ export default class Runtime {
|
||||
}
|
||||
|
||||
requireActual<T = unknown>(from: string, moduleName: string): T {
|
||||
if (FRAMEWORK_SINGLETON_MODULES.has(moduleName)) {
|
||||
return this.requireInternalModule<T>(from, moduleName);
|
||||
}
|
||||
return this.requireModule<T>(from, moduleName, undefined, true);
|
||||
}
|
||||
|
||||
@@ -490,6 +498,9 @@ export default class Runtime {
|
||||
if (shouldMock) {
|
||||
return this._requireMockWithId<T>(from, moduleName, moduleID);
|
||||
}
|
||||
if (FRAMEWORK_SINGLETON_MODULES.has(moduleName)) {
|
||||
return this.requireInternalModule<T>(from, moduleName);
|
||||
}
|
||||
return this.requireModule<T>(from, moduleName);
|
||||
} catch (error) {
|
||||
const moduleNotFound = Resolver.tryCastModuleNotFoundError(error);
|
||||
|
||||
Reference in New Issue
Block a user