jest-mock
Advanced tools
Comparing version 29.3.1 to 29.7.0
/** | ||
* Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved. | ||
* Copyright (c) Meta Platforms, Inc. and affiliates. | ||
* | ||
@@ -236,2 +236,6 @@ * This source code is licensed under the MIT license found in the | ||
/** | ||
* Check whether the given property of an object has been already replaced. | ||
*/ | ||
private _findReplacedProperty; | ||
/** | ||
* @see README.md | ||
@@ -281,2 +285,7 @@ * @param metadata Metadata for the mock in the schema returned by the | ||
private _spyOnProperty; | ||
replaceProperty<T extends object, K extends keyof T>( | ||
object: T, | ||
propertyKey: K, | ||
value: T[K], | ||
): Replaced<T[K]>; | ||
clearAllMocks(): void; | ||
@@ -308,2 +317,19 @@ resetAllMocks(): void; | ||
export declare interface Replaced<T = unknown> { | ||
/** | ||
* Restore property to its original value known at the time of mocking. | ||
*/ | ||
restore(): void; | ||
/** | ||
* Change the value of the property. | ||
*/ | ||
replaceValue(value: T): this; | ||
} | ||
export declare const replaceProperty: <T extends object, K extends keyof T>( | ||
object: T, | ||
propertyKey: K, | ||
value: T[K], | ||
) => Replaced<T[K]>; | ||
declare type ResolveType<T extends FunctionLike> = | ||
@@ -310,0 +336,0 @@ ReturnType<T> extends PromiseLike<infer U> ? U : never; |
@@ -6,3 +6,8 @@ 'use strict'; | ||
}); | ||
exports.spyOn = exports.mocked = exports.fn = exports.ModuleMocker = void 0; | ||
exports.spyOn = | ||
exports.replaceProperty = | ||
exports.mocked = | ||
exports.fn = | ||
exports.ModuleMocker = | ||
void 0; | ||
function _jestUtil() { | ||
@@ -16,3 +21,3 @@ const data = require('jest-util'); | ||
/** | ||
* Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved. | ||
* Copyright (c) Meta Platforms, Inc. and affiliates. | ||
* | ||
@@ -25,2 +30,16 @@ * This source code is licensed under the MIT license found in the | ||
// TODO remove re-export in Jest 30 | ||
// TODO remove re-export in Jest 30 | ||
// TODO in Jest 30 remove `SpyInstance` in favour of `Spied` | ||
// eslint-disable-next-line @typescript-eslint/no-empty-interface | ||
/** | ||
* All what the internal typings need is to be sure that we have any-function. | ||
* `FunctionLike` type ensures that and helps to constrain the type as well. | ||
* The default of `UnknownFunction` makes sure that `any`s do not leak to the | ||
* user side. For instance, calling `fn()` without implementation will return | ||
* a mock of `(...args: Array<unknown>) => unknown` type. If implementation | ||
* is provided, its typings are inferred correctly. | ||
*/ | ||
const MOCK_CONSTRUCTOR_NAME = 'mockConstructor'; | ||
@@ -285,4 +304,3 @@ const FUNCTION_NAME_RESERVED_PATTERN = /[\s!-/:-@[-`{-~]/; | ||
mockName: 'jest.fn()', | ||
specificMockImpls: [], | ||
specificReturnValues: [] | ||
specificMockImpls: [] | ||
}; | ||
@@ -468,3 +486,5 @@ } | ||
const previousImplementation = mockConfig.mockImpl; | ||
const previousSpecificImplementations = mockConfig.specificMockImpls; | ||
mockConfig.mockImpl = fn; | ||
mockConfig.specificMockImpls = []; | ||
const returnedValue = callback(); | ||
@@ -474,5 +494,7 @@ if ((0, _jestUtil().isPromise)(returnedValue)) { | ||
mockConfig.mockImpl = previousImplementation; | ||
mockConfig.specificMockImpls = previousSpecificImplementations; | ||
}); | ||
} else { | ||
mockConfig.mockImpl = previousImplementation; | ||
mockConfig.specificMockImpls = previousSpecificImplementations; | ||
} | ||
@@ -588,2 +610,19 @@ } | ||
/** | ||
* Check whether the given property of an object has been already replaced. | ||
*/ | ||
_findReplacedProperty(object, propertyKey) { | ||
for (const spyState of this._spyState) { | ||
if ( | ||
'object' in spyState && | ||
'property' in spyState && | ||
spyState.object === object && | ||
spyState.property === propertyKey | ||
) { | ||
return spyState; | ||
} | ||
} | ||
return; | ||
} | ||
/** | ||
* @see README.md | ||
@@ -683,13 +722,11 @@ * @param metadata Metadata for the mock in the schema returned by the | ||
spyOn(object, methodKey, accessType) { | ||
if (typeof object !== 'object' && typeof object !== 'function') { | ||
if ( | ||
object == null || | ||
(typeof object !== 'object' && typeof object !== 'function') | ||
) { | ||
throw new Error( | ||
`Cannot spyOn on a primitive value; ${this._typeOf(object)} given` | ||
`Cannot use spyOn on a primitive value; ${this._typeOf(object)} given` | ||
); | ||
} | ||
if (!object) { | ||
throw new Error( | ||
`spyOn could not find an object to spy upon for ${String(methodKey)}` | ||
); | ||
} | ||
if (!methodKey) { | ||
if (methodKey == null) { | ||
throw new Error('No property name supplied'); | ||
@@ -701,10 +738,23 @@ } | ||
const original = object[methodKey]; | ||
if (!original) { | ||
throw new Error( | ||
`Property \`${String( | ||
methodKey | ||
)}\` does not exist in the provided object` | ||
); | ||
} | ||
if (!this.isMockFunction(original)) { | ||
if (typeof original !== 'function') { | ||
throw new Error( | ||
`Cannot spy the ${String( | ||
`Cannot spy on the \`${String( | ||
methodKey | ||
)} property because it is not a function; ${this._typeOf( | ||
)}\` property because it is not a function; ${this._typeOf( | ||
original | ||
)} given instead` | ||
)} given instead.${ | ||
typeof original !== 'object' | ||
? ` If you are trying to mock a property, use \`jest.replaceProperty(object, '${String( | ||
methodKey | ||
)}', value)\` instead.` | ||
: '' | ||
}` | ||
); | ||
@@ -766,12 +816,18 @@ } | ||
if (!descriptor) { | ||
throw new Error(`${String(propertyKey)} property does not exist`); | ||
throw new Error( | ||
`Property \`${String( | ||
propertyKey | ||
)}\` does not exist in the provided object` | ||
); | ||
} | ||
if (!descriptor.configurable) { | ||
throw new Error(`${String(propertyKey)} is not declared configurable`); | ||
throw new Error( | ||
`Property \`${String(propertyKey)}\` is not declared configurable` | ||
); | ||
} | ||
if (!descriptor[accessType]) { | ||
throw new Error( | ||
`Property ${String( | ||
`Property \`${String( | ||
propertyKey | ||
)} does not have access type ${accessType}` | ||
)}\` does not have access type ${accessType}` | ||
); | ||
@@ -783,7 +839,13 @@ } | ||
throw new Error( | ||
`Cannot spy the ${String( | ||
`Cannot spy on the ${String( | ||
propertyKey | ||
)} property because it is not a function; ${this._typeOf( | ||
original | ||
)} given instead` | ||
)} given instead.${ | ||
typeof original !== 'object' | ||
? ` If you are trying to mock a property, use \`jest.replaceProperty(object, '${String( | ||
propertyKey | ||
)}', value)\` instead.` | ||
: '' | ||
}` | ||
); | ||
@@ -809,2 +871,93 @@ } | ||
} | ||
replaceProperty(object, propertyKey, value) { | ||
if ( | ||
object == null || | ||
(typeof object !== 'object' && typeof object !== 'function') | ||
) { | ||
throw new Error( | ||
`Cannot use replaceProperty on a primitive value; ${this._typeOf( | ||
object | ||
)} given` | ||
); | ||
} | ||
if (propertyKey == null) { | ||
throw new Error('No property name supplied'); | ||
} | ||
let descriptor = Object.getOwnPropertyDescriptor(object, propertyKey); | ||
let proto = Object.getPrototypeOf(object); | ||
while (!descriptor && proto !== null) { | ||
descriptor = Object.getOwnPropertyDescriptor(proto, propertyKey); | ||
proto = Object.getPrototypeOf(proto); | ||
} | ||
if (!descriptor) { | ||
throw new Error( | ||
`Property \`${String( | ||
propertyKey | ||
)}\` does not exist in the provided object` | ||
); | ||
} | ||
if (!descriptor.configurable) { | ||
throw new Error( | ||
`Property \`${String(propertyKey)}\` is not declared configurable` | ||
); | ||
} | ||
if (descriptor.get !== undefined) { | ||
throw new Error( | ||
`Cannot replace the \`${String( | ||
propertyKey | ||
)}\` property because it has a getter. Use \`jest.spyOn(object, '${String( | ||
propertyKey | ||
)}', 'get').mockReturnValue(value)\` instead.` | ||
); | ||
} | ||
if (descriptor.set !== undefined) { | ||
throw new Error( | ||
`Cannot replace the \`${String( | ||
propertyKey | ||
)}\` property because it has a setter. Use \`jest.spyOn(object, '${String( | ||
propertyKey | ||
)}', 'set').mockReturnValue(value)\` instead.` | ||
); | ||
} | ||
if (typeof descriptor.value === 'function') { | ||
throw new Error( | ||
`Cannot replace the \`${String( | ||
propertyKey | ||
)}\` property because it is a function. Use \`jest.spyOn(object, '${String( | ||
propertyKey | ||
)}')\` instead.` | ||
); | ||
} | ||
const existingRestore = this._findReplacedProperty(object, propertyKey); | ||
if (existingRestore) { | ||
return existingRestore.replaced.replaceValue(value); | ||
} | ||
const isPropertyOwner = Object.prototype.hasOwnProperty.call( | ||
object, | ||
propertyKey | ||
); | ||
const originalValue = descriptor.value; | ||
const restore = () => { | ||
if (isPropertyOwner) { | ||
object[propertyKey] = originalValue; | ||
} else { | ||
delete object[propertyKey]; | ||
} | ||
}; | ||
const replaced = { | ||
replaceValue: value => { | ||
object[propertyKey] = value; | ||
return replaced; | ||
}, | ||
restore: () => { | ||
restore(); | ||
this._spyState.delete(restore); | ||
} | ||
}; | ||
restore.object = object; | ||
restore.property = propertyKey; | ||
restore.replaced = replaced; | ||
this._spyState.add(restore); | ||
return replaced.replaceValue(value); | ||
} | ||
clearAllMocks() { | ||
@@ -836,1 +989,3 @@ this._mockState = new WeakMap(); | ||
exports.mocked = mocked; | ||
const replaceProperty = JestMock.replaceProperty.bind(JestMock); | ||
exports.replaceProperty = replaceProperty; |
{ | ||
"name": "jest-mock", | ||
"version": "29.3.1", | ||
"version": "29.7.0", | ||
"repository": { | ||
"type": "git", | ||
"url": "https://github.com/facebook/jest.git", | ||
"url": "https://github.com/jestjs/jest.git", | ||
"directory": "packages/jest-mock" | ||
@@ -20,9 +20,9 @@ }, | ||
"dependencies": { | ||
"@jest/types": "^29.3.1", | ||
"@jest/types": "^29.6.3", | ||
"@types/node": "*", | ||
"jest-util": "^29.3.1" | ||
"jest-util": "^29.7.0" | ||
}, | ||
"devDependencies": { | ||
"@tsd/typescript": "~4.8.2", | ||
"tsd-lite": "^0.6.0" | ||
"@tsd/typescript": "^5.0.4", | ||
"tsd-lite": "^0.7.0" | ||
}, | ||
@@ -35,3 +35,3 @@ "engines": { | ||
}, | ||
"gitHead": "05deb8393c4ad71e19be2567b704dfd3a2ab5fc9" | ||
"gitHead": "4e56991693da7cd4c3730dc3579a1dd1403ee630" | ||
} |
Sorry, the diff of this file is not supported yet
47481
1328
+ Added@types/node@22.0.1(transitive)
+ Addedundici-types@6.11.1(transitive)
- Removed@types/node@22.1.0(transitive)
- Removedundici-types@6.13.0(transitive)
Updated@jest/types@^29.6.3
Updatedjest-util@^29.7.0