@corez/mock
Advanced tools
Comparing version 0.7.0 to 0.8.0
@@ -120,3 +120,3 @@ /** | ||
*/ | ||
mockInPlace?: boolean; | ||
inPlace?: boolean; | ||
/** | ||
@@ -155,6 +155,6 @@ * Partial implementation to override specific properties or methods | ||
* When false, only mocks the top level object's own methods | ||
* Only applies when mockInPlace is false | ||
* Only applies when inPlace is false | ||
* @default false | ||
*/ | ||
mockDeep?: boolean; | ||
prototypeChain?: boolean; | ||
} | ||
@@ -183,3 +183,3 @@ /** | ||
*/ | ||
mockStatic?: boolean; | ||
static?: boolean; | ||
} | ||
@@ -186,0 +186,0 @@ /** |
@@ -21,4 +21,4 @@ 'use strict'; | ||
...DEFAULT_BASE_OPTIONS, | ||
mockInPlace: false, | ||
mockDeep: true, | ||
inPlace: false, | ||
prototypeChain: true, | ||
overrides: {} | ||
@@ -28,6 +28,6 @@ }; | ||
...DEFAULT_BASE_OPTIONS, | ||
mockInPlace: false, | ||
inPlace: false, | ||
preservePrototype: true, | ||
preserveConstructor: true, | ||
mockStatic: false, | ||
static: false, | ||
overrides: {} | ||
@@ -777,5 +777,17 @@ }; | ||
} | ||
if (config.mockInPlace) { | ||
target[IS_MOCKED] = true; | ||
target.__is_mocked__ = true; | ||
if (config.inPlace) { | ||
Object.defineProperties(target, { | ||
[IS_MOCKED]: { | ||
value: true, | ||
enumerable: false, | ||
configurable: false, | ||
writable: false | ||
}, | ||
__is_mocked__: { | ||
value: true, | ||
enumerable: false, | ||
configurable: false, | ||
writable: false | ||
} | ||
}); | ||
Object.getOwnPropertyNames(target.prototype).forEach((prop) => { | ||
@@ -799,2 +811,16 @@ if (prop === "constructor") return; | ||
}); | ||
Object.defineProperties(target.prototype, { | ||
[IS_MOCKED]: { | ||
value: true, | ||
enumerable: false, | ||
configurable: false, | ||
writable: false | ||
}, | ||
__is_mocked__: { | ||
value: true, | ||
enumerable: false, | ||
configurable: false, | ||
writable: false | ||
} | ||
}); | ||
Object.getOwnPropertyNames(target).forEach((prop) => { | ||
@@ -828,13 +854,22 @@ if (prop === "length" || prop === "prototype" || prop === "name") return; | ||
initializeMockInstance(instance, config); | ||
Object.defineProperties(instance, { | ||
[IS_MOCKED]: { | ||
value: true, | ||
enumerable: false, | ||
configurable: false, | ||
writable: false | ||
}, | ||
__is_mocked__: { | ||
value: true, | ||
enumerable: false, | ||
configurable: false, | ||
writable: false | ||
} | ||
}); | ||
if (config.preserveConstructor) { | ||
const constructedInstance = Reflect.construct(target, args); | ||
Object.getOwnPropertyNames(constructedInstance).forEach((prop) => { | ||
const descriptor = Object.getOwnPropertyDescriptor(constructedInstance, prop); | ||
if (descriptor) { | ||
if (typeof descriptor.value === "function") { | ||
Object.defineProperty(instance, prop, { | ||
...descriptor, | ||
value: createSpy(descriptor.value.bind(instance)) | ||
}); | ||
} else { | ||
if (!(prop in instance)) { | ||
const descriptor = Object.getOwnPropertyDescriptor(constructedInstance, prop); | ||
if (descriptor) { | ||
Object.defineProperty(instance, prop, descriptor); | ||
@@ -845,46 +880,52 @@ } | ||
} | ||
Object.getOwnPropertyNames(target.prototype).forEach((prop) => { | ||
if (prop === "constructor") return; | ||
const descriptor = Object.getOwnPropertyDescriptor(target.prototype, prop); | ||
if (descriptor) { | ||
const override = config.overrides?.[prop]; | ||
if (override) { | ||
Object.defineProperty(instance, prop, { | ||
...descriptor, | ||
value: createSpy(override) | ||
}); | ||
} else if (typeof descriptor.value === "function") { | ||
Object.defineProperty(instance, prop, { | ||
...descriptor, | ||
value: config.preservePrototype ? createSpy(descriptor.value.bind(instance)) : createSpy() | ||
}); | ||
} | ||
} | ||
}); | ||
let proto = Object.getPrototypeOf(target.prototype); | ||
while (proto && proto !== Object.prototype) { | ||
Object.getOwnPropertyNames(proto).forEach((prop) => { | ||
if (prop === "constructor") return; | ||
const descriptor = Object.getOwnPropertyDescriptor(proto, prop); | ||
if (descriptor && !instance.hasOwnProperty(prop)) { | ||
const override = config.overrides?.[prop]; | ||
if (override) { | ||
Object.defineProperty(instance, prop, { | ||
...descriptor, | ||
value: createSpy(override) | ||
}); | ||
} else if (typeof descriptor.value === "function") { | ||
Object.defineProperty(instance, prop, { | ||
...descriptor, | ||
value: config.preservePrototype ? createSpy(descriptor.value.bind(instance)) : createSpy() | ||
}); | ||
} | ||
} | ||
}); | ||
proto = Object.getPrototypeOf(proto); | ||
} | ||
return instance; | ||
}; | ||
MockClass.prototype = Object.create(target.prototype); | ||
Object.setPrototypeOf(MockClass, target); | ||
Object.setPrototypeOf(MockClass.prototype, target.prototype); | ||
Object.defineProperties(MockClass, { | ||
[IS_MOCKED]: { | ||
value: true, | ||
enumerable: false, | ||
configurable: false, | ||
writable: false | ||
}, | ||
__is_mocked__: { | ||
value: true, | ||
enumerable: false, | ||
configurable: false, | ||
writable: false | ||
} | ||
}); | ||
Object.defineProperties(MockClass.prototype, { | ||
[IS_MOCKED]: { | ||
value: true, | ||
enumerable: false, | ||
configurable: false, | ||
writable: false | ||
}, | ||
__is_mocked__: { | ||
value: true, | ||
enumerable: false, | ||
configurable: false, | ||
writable: false | ||
} | ||
}); | ||
Object.getOwnPropertyNames(target.prototype).forEach((prop) => { | ||
if (prop === "constructor") return; | ||
const descriptor = Object.getOwnPropertyDescriptor(target.prototype, prop); | ||
if (descriptor) { | ||
const override = config.overrides?.[prop]; | ||
if (override) { | ||
Object.defineProperty(MockClass.prototype, prop, { | ||
...descriptor, | ||
value: createSpy(override) | ||
}); | ||
} else if (typeof descriptor.value === "function") { | ||
Object.defineProperty(MockClass.prototype, prop, { | ||
...descriptor, | ||
value: config.preservePrototype ? createSpy(descriptor.value) : createSpy() | ||
}); | ||
} | ||
} | ||
}); | ||
Object.getOwnPropertyNames(target).forEach((prop) => { | ||
@@ -909,4 +950,2 @@ if (prop === "length" || prop === "prototype" || prop === "name") return; | ||
handleStaticMethodInheritance(MockClass, target, { debug: config.debug }); | ||
MockClass[IS_MOCKED] = true; | ||
MockClass.__is_mocked__ = true; | ||
return MockClass; | ||
@@ -945,3 +984,39 @@ } | ||
function isMocked(target) { | ||
return target && typeof target === "object" && "mockClear" in target && "mockReset" in target && "mockRestore" in target; | ||
if (!target) { | ||
return false; | ||
} | ||
if (typeof target === "function") { | ||
if (Object.prototype.hasOwnProperty.call(target, IS_MOCKED) || IS_MOCKED in target) { | ||
return true; | ||
} | ||
if (target.prototype && (Object.prototype.hasOwnProperty.call(target.prototype, IS_MOCKED) || IS_MOCKED in target.prototype)) { | ||
return true; | ||
} | ||
if ("mockClear" in target && "mockReset" in target && "mockRestore" in target) { | ||
return true; | ||
} | ||
return false; | ||
} | ||
if (typeof target === "object") { | ||
if (Object.prototype.hasOwnProperty.call(target, IS_MOCKED) || IS_MOCKED in target) { | ||
return true; | ||
} | ||
const proto = Object.getPrototypeOf(target); | ||
if (proto) { | ||
let currentProto = proto; | ||
while (currentProto && currentProto !== Object.prototype) { | ||
if (Object.prototype.hasOwnProperty.call(currentProto, IS_MOCKED) || IS_MOCKED in currentProto) { | ||
return true; | ||
} | ||
if (currentProto.constructor && (Object.prototype.hasOwnProperty.call(currentProto.constructor, IS_MOCKED) || IS_MOCKED in currentProto.constructor)) { | ||
return true; | ||
} | ||
currentProto = Object.getPrototypeOf(currentProto); | ||
} | ||
} | ||
if ("mockClear" in target && "mockReset" in target && "mockRestore" in target) { | ||
return true; | ||
} | ||
} | ||
return false; | ||
} | ||
@@ -976,8 +1051,17 @@ | ||
} | ||
if (target.constructor && target.constructor[IS_MOCKED]) { | ||
return target; | ||
} | ||
let mockTarget; | ||
if (options.mockInPlace) { | ||
if (options.inPlace) { | ||
mockTarget = target; | ||
} else { | ||
mockTarget = options.mockDeep ? clone(target) : shallowClone(target); | ||
mockTarget = options.prototypeChain ? clone(target) : shallowClone(target); | ||
} | ||
Object.defineProperty(mockTarget, IS_MOCKED, { | ||
value: true, | ||
enumerable: false, | ||
configurable: false, | ||
writable: false | ||
}); | ||
Object.entries(Object.getOwnPropertyDescriptors(target)).forEach(([key, descriptor]) => { | ||
@@ -994,3 +1078,3 @@ if (typeof descriptor.value === "function") { | ||
}); | ||
if (options.mockDeep) { | ||
if (options.prototypeChain) { | ||
let proto = Object.getPrototypeOf(target); | ||
@@ -997,0 +1081,0 @@ while (proto && proto !== Object.prototype) { |
@@ -15,4 +15,4 @@ import rfdc from 'rfdc'; | ||
...DEFAULT_BASE_OPTIONS, | ||
mockInPlace: false, | ||
mockDeep: true, | ||
inPlace: false, | ||
prototypeChain: true, | ||
overrides: {} | ||
@@ -22,6 +22,6 @@ }; | ||
...DEFAULT_BASE_OPTIONS, | ||
mockInPlace: false, | ||
inPlace: false, | ||
preservePrototype: true, | ||
preserveConstructor: true, | ||
mockStatic: false, | ||
static: false, | ||
overrides: {} | ||
@@ -771,5 +771,17 @@ }; | ||
} | ||
if (config.mockInPlace) { | ||
target[IS_MOCKED] = true; | ||
target.__is_mocked__ = true; | ||
if (config.inPlace) { | ||
Object.defineProperties(target, { | ||
[IS_MOCKED]: { | ||
value: true, | ||
enumerable: false, | ||
configurable: false, | ||
writable: false | ||
}, | ||
__is_mocked__: { | ||
value: true, | ||
enumerable: false, | ||
configurable: false, | ||
writable: false | ||
} | ||
}); | ||
Object.getOwnPropertyNames(target.prototype).forEach((prop) => { | ||
@@ -793,2 +805,16 @@ if (prop === "constructor") return; | ||
}); | ||
Object.defineProperties(target.prototype, { | ||
[IS_MOCKED]: { | ||
value: true, | ||
enumerable: false, | ||
configurable: false, | ||
writable: false | ||
}, | ||
__is_mocked__: { | ||
value: true, | ||
enumerable: false, | ||
configurable: false, | ||
writable: false | ||
} | ||
}); | ||
Object.getOwnPropertyNames(target).forEach((prop) => { | ||
@@ -822,13 +848,22 @@ if (prop === "length" || prop === "prototype" || prop === "name") return; | ||
initializeMockInstance(instance, config); | ||
Object.defineProperties(instance, { | ||
[IS_MOCKED]: { | ||
value: true, | ||
enumerable: false, | ||
configurable: false, | ||
writable: false | ||
}, | ||
__is_mocked__: { | ||
value: true, | ||
enumerable: false, | ||
configurable: false, | ||
writable: false | ||
} | ||
}); | ||
if (config.preserveConstructor) { | ||
const constructedInstance = Reflect.construct(target, args); | ||
Object.getOwnPropertyNames(constructedInstance).forEach((prop) => { | ||
const descriptor = Object.getOwnPropertyDescriptor(constructedInstance, prop); | ||
if (descriptor) { | ||
if (typeof descriptor.value === "function") { | ||
Object.defineProperty(instance, prop, { | ||
...descriptor, | ||
value: createSpy(descriptor.value.bind(instance)) | ||
}); | ||
} else { | ||
if (!(prop in instance)) { | ||
const descriptor = Object.getOwnPropertyDescriptor(constructedInstance, prop); | ||
if (descriptor) { | ||
Object.defineProperty(instance, prop, descriptor); | ||
@@ -839,46 +874,52 @@ } | ||
} | ||
Object.getOwnPropertyNames(target.prototype).forEach((prop) => { | ||
if (prop === "constructor") return; | ||
const descriptor = Object.getOwnPropertyDescriptor(target.prototype, prop); | ||
if (descriptor) { | ||
const override = config.overrides?.[prop]; | ||
if (override) { | ||
Object.defineProperty(instance, prop, { | ||
...descriptor, | ||
value: createSpy(override) | ||
}); | ||
} else if (typeof descriptor.value === "function") { | ||
Object.defineProperty(instance, prop, { | ||
...descriptor, | ||
value: config.preservePrototype ? createSpy(descriptor.value.bind(instance)) : createSpy() | ||
}); | ||
} | ||
} | ||
}); | ||
let proto = Object.getPrototypeOf(target.prototype); | ||
while (proto && proto !== Object.prototype) { | ||
Object.getOwnPropertyNames(proto).forEach((prop) => { | ||
if (prop === "constructor") return; | ||
const descriptor = Object.getOwnPropertyDescriptor(proto, prop); | ||
if (descriptor && !instance.hasOwnProperty(prop)) { | ||
const override = config.overrides?.[prop]; | ||
if (override) { | ||
Object.defineProperty(instance, prop, { | ||
...descriptor, | ||
value: createSpy(override) | ||
}); | ||
} else if (typeof descriptor.value === "function") { | ||
Object.defineProperty(instance, prop, { | ||
...descriptor, | ||
value: config.preservePrototype ? createSpy(descriptor.value.bind(instance)) : createSpy() | ||
}); | ||
} | ||
} | ||
}); | ||
proto = Object.getPrototypeOf(proto); | ||
} | ||
return instance; | ||
}; | ||
MockClass.prototype = Object.create(target.prototype); | ||
Object.setPrototypeOf(MockClass, target); | ||
Object.setPrototypeOf(MockClass.prototype, target.prototype); | ||
Object.defineProperties(MockClass, { | ||
[IS_MOCKED]: { | ||
value: true, | ||
enumerable: false, | ||
configurable: false, | ||
writable: false | ||
}, | ||
__is_mocked__: { | ||
value: true, | ||
enumerable: false, | ||
configurable: false, | ||
writable: false | ||
} | ||
}); | ||
Object.defineProperties(MockClass.prototype, { | ||
[IS_MOCKED]: { | ||
value: true, | ||
enumerable: false, | ||
configurable: false, | ||
writable: false | ||
}, | ||
__is_mocked__: { | ||
value: true, | ||
enumerable: false, | ||
configurable: false, | ||
writable: false | ||
} | ||
}); | ||
Object.getOwnPropertyNames(target.prototype).forEach((prop) => { | ||
if (prop === "constructor") return; | ||
const descriptor = Object.getOwnPropertyDescriptor(target.prototype, prop); | ||
if (descriptor) { | ||
const override = config.overrides?.[prop]; | ||
if (override) { | ||
Object.defineProperty(MockClass.prototype, prop, { | ||
...descriptor, | ||
value: createSpy(override) | ||
}); | ||
} else if (typeof descriptor.value === "function") { | ||
Object.defineProperty(MockClass.prototype, prop, { | ||
...descriptor, | ||
value: config.preservePrototype ? createSpy(descriptor.value) : createSpy() | ||
}); | ||
} | ||
} | ||
}); | ||
Object.getOwnPropertyNames(target).forEach((prop) => { | ||
@@ -903,4 +944,2 @@ if (prop === "length" || prop === "prototype" || prop === "name") return; | ||
handleStaticMethodInheritance(MockClass, target, { debug: config.debug }); | ||
MockClass[IS_MOCKED] = true; | ||
MockClass.__is_mocked__ = true; | ||
return MockClass; | ||
@@ -939,3 +978,39 @@ } | ||
function isMocked(target) { | ||
return target && typeof target === "object" && "mockClear" in target && "mockReset" in target && "mockRestore" in target; | ||
if (!target) { | ||
return false; | ||
} | ||
if (typeof target === "function") { | ||
if (Object.prototype.hasOwnProperty.call(target, IS_MOCKED) || IS_MOCKED in target) { | ||
return true; | ||
} | ||
if (target.prototype && (Object.prototype.hasOwnProperty.call(target.prototype, IS_MOCKED) || IS_MOCKED in target.prototype)) { | ||
return true; | ||
} | ||
if ("mockClear" in target && "mockReset" in target && "mockRestore" in target) { | ||
return true; | ||
} | ||
return false; | ||
} | ||
if (typeof target === "object") { | ||
if (Object.prototype.hasOwnProperty.call(target, IS_MOCKED) || IS_MOCKED in target) { | ||
return true; | ||
} | ||
const proto = Object.getPrototypeOf(target); | ||
if (proto) { | ||
let currentProto = proto; | ||
while (currentProto && currentProto !== Object.prototype) { | ||
if (Object.prototype.hasOwnProperty.call(currentProto, IS_MOCKED) || IS_MOCKED in currentProto) { | ||
return true; | ||
} | ||
if (currentProto.constructor && (Object.prototype.hasOwnProperty.call(currentProto.constructor, IS_MOCKED) || IS_MOCKED in currentProto.constructor)) { | ||
return true; | ||
} | ||
currentProto = Object.getPrototypeOf(currentProto); | ||
} | ||
} | ||
if ("mockClear" in target && "mockReset" in target && "mockRestore" in target) { | ||
return true; | ||
} | ||
} | ||
return false; | ||
} | ||
@@ -970,8 +1045,17 @@ | ||
} | ||
if (target.constructor && target.constructor[IS_MOCKED]) { | ||
return target; | ||
} | ||
let mockTarget; | ||
if (options.mockInPlace) { | ||
if (options.inPlace) { | ||
mockTarget = target; | ||
} else { | ||
mockTarget = options.mockDeep ? clone(target) : shallowClone(target); | ||
mockTarget = options.prototypeChain ? clone(target) : shallowClone(target); | ||
} | ||
Object.defineProperty(mockTarget, IS_MOCKED, { | ||
value: true, | ||
enumerable: false, | ||
configurable: false, | ||
writable: false | ||
}); | ||
Object.entries(Object.getOwnPropertyDescriptors(target)).forEach(([key, descriptor]) => { | ||
@@ -988,3 +1072,3 @@ if (typeof descriptor.value === "function") { | ||
}); | ||
if (options.mockDeep) { | ||
if (options.prototypeChain) { | ||
let proto = Object.getPrototypeOf(target); | ||
@@ -991,0 +1075,0 @@ while (proto && proto !== Object.prototype) { |
{ | ||
"name": "@corez/mock", | ||
"version": "0.7.0", | ||
"version": "0.8.0", | ||
"description": "A powerful and flexible TypeScript mocking library for testing", | ||
@@ -5,0 +5,0 @@ "keywords": [ |
128
README.md
@@ -150,2 +150,34 @@ # @corez/mock | ||
#### Advanced Object Mocking Features | ||
1. **Prototype Chain Mocking** | ||
```typescript | ||
const service = mock.obj(originalService, { | ||
prototypeChain: true, // Will mock methods from entire prototype chain | ||
}); | ||
``` | ||
2. **Arrow Functions vs Regular Methods** The library automatically detects and handles arrow functions differently to | ||
preserve correct `this` binding: | ||
```typescript | ||
class Service { | ||
regularMethod() { | ||
return this; | ||
} | ||
arrowMethod = () => this; | ||
} | ||
const mockedService = mock.obj(new Service()); | ||
// Both methods will maintain correct `this` binding | ||
``` | ||
3. **In-Place Mocking** | ||
```typescript | ||
const service = mock.obj(originalService, { | ||
inPlace: true, // Modifies the original object | ||
}); | ||
``` | ||
### Mock Classes | ||
@@ -167,5 +199,4 @@ | ||
const MockDatabase = mock.cls(Database, { | ||
overrides: { | ||
query: async () => [{id: 1}], | ||
}, | ||
static: true, | ||
preserveConstructor: true, | ||
}); | ||
@@ -184,3 +215,3 @@ | ||
mock.cls(Database, { | ||
mockInPlace: true, | ||
inPlace: true, | ||
overrides: { | ||
@@ -245,34 +276,27 @@ query: async () => [{id: 1}], | ||
#### `mock.obj<T extends object>(target: T | undefined, options?: ObjMockOptions<T>): MockObject<T>` | ||
#### `mock.obj<T extends object>(target: T | undefined, options?: ObjectMockOptions<T>): MockObject<T>` | ||
Creates a mock object with automatic method tracking: | ||
Creates a mock object with automatic method tracking. Available options: | ||
```typescript | ||
interface UserService { | ||
getUser(id: number): Promise<User>; | ||
updateUser(user: User): Promise<void>; | ||
interface ObjectMockOptions<T> { | ||
// If true, modifies the original object instead of creating a clone | ||
inPlace?: boolean; | ||
// If true, mocks methods from the entire prototype chain | ||
prototypeChain?: boolean; | ||
// Override specific properties or methods | ||
overrides?: Partial<T>; | ||
} | ||
``` | ||
const userService = mock.obj<UserService>( | ||
{ | ||
getUser: async id => ({id, name: 'John'}), | ||
updateUser: async user => {}, | ||
}, | ||
{ | ||
overrides: { | ||
getUser: async id => ({id, name: 'Mock User'}), | ||
}, | ||
}, | ||
); | ||
Key features: | ||
// Access call information | ||
const getUserMock = userService.getUser as MockFunction; | ||
console.log(getUserMock.calls.count()); | ||
console.log(getUserMock.calls.all()); | ||
- Deep cloning support using `rfdc` | ||
- Automatic handling of arrow functions vs regular methods | ||
- Prototype chain preservation and mocking | ||
- Property descriptor preservation | ||
- Spy tracking for all methods | ||
// Verify specific calls | ||
expect(getUserMock.calls.count()).toBe(1); | ||
expect(getUserMock.calls.all()[0].args).toEqual([1]); | ||
``` | ||
#### `mock.cls<T extends Constructor<any>>(target: T, options?: ClassMockOptions<T>): ClsMock<T>` | ||
@@ -286,3 +310,3 @@ | ||
// Modify original class instead of creating new one | ||
mockInPlace: false, | ||
inPlace: false, | ||
@@ -320,3 +344,3 @@ // Preserve original method implementations | ||
// Whether to modify the original class | ||
mockInPlace?: boolean; | ||
inPlace?: boolean; | ||
@@ -569,8 +593,8 @@ // Whether to preserve original method implementations | ||
5. **Using mockInPlace** | ||
5. **Using inPlace** | ||
```typescript | ||
// For objects: Use mockInPlace when you need to maintain object references | ||
// For objects: Use inPlace when you need to maintain object references | ||
const mockObj = mock.obj(original, { | ||
mockInPlace: true, | ||
inPlace: true, | ||
overrides: { | ||
@@ -581,3 +605,3 @@ method: () => 'mocked', | ||
// For classes: Be cautious with mockInPlace as it affects the original class | ||
// For classes: Be cautious with inPlace as it affects the original class | ||
const MockClass = mock.cls(Original); // Creates new class by default | ||
@@ -587,3 +611,3 @@ | ||
const ModifiedClass = mock.cls(Original, { | ||
mockInPlace: true, | ||
inPlace: true, | ||
// Remember to restore if needed | ||
@@ -612,15 +636,15 @@ }); | ||
- For classes: Use `preservePrototype: true` (default) | ||
- For objects: Use `mockDeep: true` to mock prototype methods (default) | ||
- For objects: Use `prototypeChain: true` to mock prototype methods (default) | ||
- For type casting: Use `keepPrototype: true` (default) | ||
4. **mockInPlace Issues** | ||
- For objects: Use `mockInPlace: true` if you need to maintain object references | ||
- For classes: Be aware that `mockInPlace: true` modifies the original class | ||
4. **inPlace Issues** | ||
- For objects: Use `inPlace: true` if you need to maintain object references | ||
- For classes: Be aware that `inPlace: true` modifies the original class | ||
- Remember to restore mocked objects/classes if needed: | ||
```typescript | ||
const mock = mock.obj(original, {mockInPlace: true}); | ||
const mock = mock.obj(original, {inPlace: true}); | ||
// ... use mock ... | ||
mock.restore(); // Restore original implementation | ||
``` | ||
- When using `mockInPlace` with inheritance, ensure proper super calls are preserved | ||
- When using `inPlace` with inheritance, ensure proper super calls are preserved | ||
- Consider using a new instance if you don't specifically need to modify the original | ||
@@ -656,8 +680,8 @@ | ||
- `mockInPlace`: Controls whether to modify the original object or create a new one (default: false) | ||
- `mockDeep`: Controls whether to perform deep cloning and mocking of nested objects and prototype chain methods | ||
- `inPlace`: Controls whether to modify the original object or create a new one (default: false) | ||
- `prototypeChain`: Controls whether to perform deep cloning and mocking of nested objects and prototype chain methods | ||
(default: true) | ||
- `overrides`: Allows overriding specific properties or methods with custom implementations | ||
Example of object mocking with mockInPlace: | ||
Example of object mocking with inPlace: | ||
@@ -674,3 +698,3 @@ ```typescript | ||
const modifiedObj = mock.obj(original, { | ||
mockInPlace: true, | ||
inPlace: true, | ||
overrides: { | ||
@@ -683,3 +707,3 @@ method: () => 'mocked', | ||
const deepMockObj = mock.obj(original, { | ||
mockDeep: true, // this is default | ||
prototypeChain: true, // this is default | ||
}); | ||
@@ -692,3 +716,3 @@ ``` | ||
- `mockInPlace`: Controls whether to modify the original class or create a new one (default: false) | ||
- `inPlace`: Controls whether to modify the original class or create a new one (default: false) | ||
- `preservePrototype`: Controls whether to preserve the prototype chain (default: true) | ||
@@ -699,3 +723,3 @@ - `preserveConstructor`: Controls whether to preserve the original constructor behavior (default: true) | ||
Example of class mocking with mockInPlace: | ||
Example of class mocking with inPlace: | ||
@@ -705,3 +729,3 @@ ```typescript | ||
const MockClass = mock.cls(Original, { | ||
mockStatic: true, | ||
static: true, | ||
overrides: { | ||
@@ -714,4 +738,4 @@ method: () => 'mocked', | ||
const ModifiedClass = mock.cls(Original, { | ||
mockInPlace: true, | ||
mockStatic: true, | ||
inPlace: true, | ||
static: true, | ||
overrides: { | ||
@@ -718,0 +742,0 @@ method: () => 'mocked', |
@@ -28,4 +28,4 @@ import {BaseMockOptions, CastMockOptions, ClassMockOptions, FunctionMockOptions, ObjectMockOptions} from './types'; | ||
...DEFAULT_BASE_OPTIONS, | ||
mockInPlace: false, | ||
mockDeep: true, | ||
inPlace: false, | ||
prototypeChain: true, | ||
overrides: {}, | ||
@@ -40,6 +40,6 @@ }; | ||
...DEFAULT_BASE_OPTIONS, | ||
mockInPlace: false, | ||
inPlace: false, | ||
preservePrototype: true, | ||
preserveConstructor: true, | ||
mockStatic: false, | ||
static: false, | ||
overrides: {}, | ||
@@ -46,0 +46,0 @@ }; |
@@ -18,3 +18,3 @@ import {cls} from '../class'; | ||
const MockedClass = cls(CallbackURL, {mockInPlace: true}); | ||
const MockedClass = cls(CallbackURL, {inPlace: true}); | ||
const instance = new MockedClass(); | ||
@@ -21,0 +21,0 @@ |
@@ -209,3 +209,3 @@ import type {ClsMock, MockFunction} from '../../types'; | ||
it('should handle inheritance correctly when mockInPlace is true', () => { | ||
it('should handle inheritance correctly when inPlace is true', () => { | ||
class ExtendedChild extends Base { | ||
@@ -229,3 +229,3 @@ constructor() { | ||
const MockChild = cls(ExtendedChild, {mockInPlace: true}); | ||
const MockChild = cls(ExtendedChild, {inPlace: true}); | ||
const instance = new MockChild(); | ||
@@ -253,3 +253,3 @@ | ||
it('should handle static inheritance when mockInPlace is true', () => { | ||
it('should handle static inheritance when inPlace is true', () => { | ||
class StaticBase { | ||
@@ -282,3 +282,3 @@ protected static states = new Map<any, any>(); | ||
const MockStaticChild = cls(StaticChild, {mockInPlace: true}); | ||
const MockStaticChild = cls(StaticChild, {inPlace: true, static: true}); | ||
@@ -302,3 +302,3 @@ // Verify static inheritance works | ||
it('should handle super calls correctly when mockInPlace is true', () => { | ||
it('should handle super calls correctly when inPlace is true', () => { | ||
class SuperBase { | ||
@@ -339,3 +339,3 @@ protected value: string; | ||
const MockChild = cls(SuperChild, {mockInPlace: true}); | ||
const MockChild = cls(SuperChild, {inPlace: true}); | ||
const instance = new MockChild('test'); | ||
@@ -410,3 +410,3 @@ | ||
describe('mockInPlace option', () => { | ||
describe('inPlace option', () => { | ||
class TestClass { | ||
@@ -422,24 +422,5 @@ value: string = 'original'; | ||
it('should create new mock class and keep original unchanged by default', () => { | ||
const MockClass = cls(TestClass); | ||
it('should modify original class when inPlace is true', () => { | ||
const ModifiedClass = cls(TestClass, {inPlace: true}); | ||
// Verify MockClass is a different class | ||
expect(MockClass).not.toBe(TestClass); | ||
// Verify MockClass has mock methods | ||
const mockInstance = new MockClass(); | ||
expect(mockInstance.getValue).toHaveProperty('mock'); | ||
expect(MockClass.staticMethod).toHaveProperty('mock'); | ||
// Verify original class remains unchanged | ||
const originalInstance = new TestClass(); | ||
expect(originalInstance.getValue).not.toHaveProperty('mock'); | ||
expect(TestClass.staticMethod).not.toHaveProperty('mock'); | ||
expect(originalInstance.getValue()).toBe('original'); | ||
expect(TestClass.staticMethod()).toBe('static'); | ||
}); | ||
it('should modify original class when mockInPlace is true', () => { | ||
const ModifiedClass = cls(TestClass, {mockInPlace: true}); | ||
// Verify returned class is the same as original | ||
@@ -464,35 +445,5 @@ expect(ModifiedClass).toBe(TestClass); | ||
it('should allow restoring original class after modification', () => { | ||
class LocalTestClass { | ||
value: string = 'original'; | ||
getValue(): string { | ||
return this.value; | ||
} | ||
static staticMethod(): string { | ||
return 'static'; | ||
} | ||
} | ||
// Store original methods | ||
const originalGetValue = LocalTestClass.prototype.getValue; | ||
const originalStaticMethod = LocalTestClass.staticMethod; | ||
// Modify class | ||
const ModifiedClass = cls(LocalTestClass, {mockInPlace: true}); | ||
// Verify class is modified | ||
const modifiedInstance = new ModifiedClass(); | ||
expect(modifiedInstance.getValue).toHaveProperty('mock'); | ||
expect(ModifiedClass.staticMethod).toHaveProperty('mock'); | ||
// Restore original methods | ||
LocalTestClass.prototype.getValue = originalGetValue; | ||
LocalTestClass.staticMethod = originalStaticMethod; | ||
// Verify class is restored | ||
const restoredInstance = new LocalTestClass(); | ||
expect(restoredInstance.getValue).not.toHaveProperty('mock'); | ||
expect(LocalTestClass.staticMethod).not.toHaveProperty('mock'); | ||
expect(restoredInstance.getValue()).toBe('original'); | ||
expect(LocalTestClass.staticMethod()).toBe('static'); | ||
it('should mark mock class with IS_MOCKED symbol when inPlace is true', () => { | ||
const MockClass = cls(TestClass, {inPlace: true}); | ||
expect((MockClass as ClsMock<typeof TestClass>).__is_mocked__).toBe(true); | ||
}); | ||
@@ -514,4 +465,4 @@ }); | ||
it('should mark mock class with IS_MOCKED symbol when mockInPlace is true', () => { | ||
const MockClass = cls(TestClass, {mockInPlace: true}); | ||
it('should mark mock class with IS_MOCKED symbol when inPlace is true', () => { | ||
const MockClass = cls(TestClass, {inPlace: true}); | ||
expect((MockClass as ClsMock<typeof TestClass>).__is_mocked__).toBe(true); | ||
@@ -518,0 +469,0 @@ }); |
@@ -0,2 +1,6 @@ | ||
import {IS_MOCKED} from '../../constants/mock-symbols'; | ||
import {MockFunction} from '../../types'; | ||
import {isMocked} from '../../utils/mock-handlers'; | ||
import {obj} from '..'; | ||
import {cls} from '../class'; | ||
@@ -64,18 +68,18 @@ describe('object', () => { | ||
it('should create new instance by default', () => { | ||
const original = new TestClass('test'); | ||
const mock = obj(original); | ||
expect(mock).not.toBe(original); | ||
const _original = new TestClass('test'); | ||
const mock = obj(_original); | ||
expect(mock).not.toBe(_original); | ||
}); | ||
it('should modify original when mockInPlace is true', () => { | ||
const original = new TestClass('test'); | ||
const mock = obj(original, {mockInPlace: true}); | ||
expect(mock).toBe(original); | ||
it('should modify original when inPlace is true', () => { | ||
const _original = new TestClass('test'); | ||
const mock = obj(_original, {inPlace: true}); | ||
expect(mock).toBe(_original); | ||
}); | ||
it('should create shallow clone when not mocking in place', () => { | ||
const original = new TestClass('test'); | ||
const mock = obj(original, {mockInPlace: false, mockDeep: false}); | ||
const _original = new TestClass('test'); | ||
const mock = obj(_original, {inPlace: false, prototypeChain: false}); | ||
mock.increment(); | ||
expect(original.getCounter()).toBe(0); // Original should be unchanged | ||
expect(_original.getCounter()).toBe(0); // Original should be unchanged | ||
}); | ||
@@ -113,5 +117,5 @@ | ||
it('should support super calls and modify original when mockInPlace is true', () => { | ||
it('should support super calls and modify original when inPlace is true', () => { | ||
const child = new Child(); | ||
const mock = obj(child, {mockInPlace: true}); | ||
const mock = obj(child, {inPlace: true}); | ||
expect(mock.getValue()).toBe('child:parent'); | ||
@@ -122,5 +126,5 @@ expect(mock.childMethod()).toBe('child:base'); | ||
it('should support super calls and create new instance when mockInPlace is false', () => { | ||
it('should support super calls and create new instance when inPlace is false', () => { | ||
const child = new Child(); | ||
const mock = obj(child, {mockInPlace: false}); | ||
const mock = obj(child, {inPlace: false}); | ||
expect(mock.getValue()).toBe('child:parent'); | ||
@@ -131,5 +135,5 @@ expect(mock.childMethod()).toBe('child:base'); | ||
it('should support super calls when mockDeep is false', () => { | ||
it('should support super calls when prototypeChain is false', () => { | ||
const child = new Child(); | ||
const mock = obj(child, {mockDeep: false}); | ||
const mock = obj(child, {prototypeChain: false}); | ||
expect(mock.getValue()).toBe('child:parent'); | ||
@@ -142,3 +146,3 @@ expect(mock.childMethod()).toBe('child:base'); | ||
it('should handle deep cloning', () => { | ||
const original = { | ||
const _original = { | ||
nested: { | ||
@@ -152,5 +156,5 @@ value: 123, | ||
const mock = obj(original, {mockDeep: true}); | ||
expect(mock).not.toBe(original); | ||
expect(mock.nested).not.toBe(original.nested); | ||
const mock = obj(_original, {prototypeChain: true}); | ||
expect(mock).not.toBe(_original); | ||
expect(mock.nested).not.toBe(_original.nested); | ||
expect(mock.nested.value).toBe(123); | ||
@@ -175,3 +179,3 @@ expect(mock.nested.method()).toBe(123); | ||
const mock = obj(circular, {mockDeep: true}); | ||
const mock = obj(circular, {prototypeChain: true}); | ||
expect(mock).not.toBe(circular); | ||
@@ -264,2 +268,58 @@ expect(mock.self).toBe(mock); | ||
}); | ||
describe('mock detection', () => { | ||
class TestClass { | ||
value = 'test'; | ||
getValue() { | ||
return this.value; | ||
} | ||
} | ||
it('should mark mocked object with IS_MOCKED symbol', () => { | ||
const testObj = {method: () => 'test'}; | ||
const mock = obj(testObj); | ||
expect(IS_MOCKED in mock).toBe(true); | ||
expect(isMocked(mock)).toBe(true); | ||
}); | ||
it('should detect already mocked objects', () => { | ||
const testObj = {method: () => 'test'}; | ||
const firstMock = obj(testObj); | ||
const secondMock = obj(firstMock); | ||
expect(secondMock).toBe(firstMock); | ||
}); | ||
it('should detect class mocked instances', () => { | ||
const MockTestClass = cls(TestClass); | ||
const instance = new MockTestClass(); | ||
const objectMock = obj(instance); | ||
// Should return the same instance without re-mocking | ||
expect(objectMock).toBe(instance); | ||
expect(isMocked(objectMock)).toBe(true); | ||
}); | ||
it('should handle class mock with inPlace', () => { | ||
const _original = new TestClass(); | ||
const MockTestClass = cls(TestClass, {inPlace: true}); | ||
const instance = new MockTestClass(); | ||
const objectMock = obj(instance); | ||
// Should detect mocked class and return same instance | ||
expect(objectMock).toBe(instance); | ||
expect(isMocked(objectMock)).toBe(true); | ||
}); | ||
it('should preserve mock functionality when detecting class mocked instances', () => { | ||
const MockTestClass = cls(TestClass); | ||
const instance = new MockTestClass(); | ||
// Mock a method on the class instance | ||
(instance.getValue as MockFunction<() => string>).mockImplementation(() => 'mocked'); | ||
// Object mock should return same instance without affecting mocks | ||
const objectMock = obj(instance); | ||
expect(objectMock).toBe(instance); | ||
}); | ||
}); | ||
}); |
@@ -42,3 +42,3 @@ import {IS_MOCKED, MOCK_SYMBOLS} from '../constants/mock-symbols'; | ||
* By default, it returns a new mock class. | ||
* Can optionally modify the original class if mockInPlace option is set to true. | ||
* Can optionally modify the original class if inPlace option is set to true. | ||
* | ||
@@ -82,7 +82,19 @@ * Key features: | ||
if (config.mockInPlace) { | ||
// Modify the original class (when mockInPlace is true) | ||
if (config.inPlace) { | ||
// Modify the original class (when inPlace is true) | ||
// Mark the class as mocked | ||
(target as any)[IS_MOCKED] = true; | ||
(target as any).__is_mocked__ = true; | ||
Object.defineProperties(target, { | ||
[IS_MOCKED]: { | ||
value: true, | ||
enumerable: false, | ||
configurable: false, | ||
writable: false, | ||
}, | ||
__is_mocked__: { | ||
value: true, | ||
enumerable: false, | ||
configurable: false, | ||
writable: false, | ||
}, | ||
}); | ||
@@ -109,2 +121,18 @@ // Mock prototype methods | ||
// Mark prototype as mocked | ||
Object.defineProperties(target.prototype, { | ||
[IS_MOCKED]: { | ||
value: true, | ||
enumerable: false, | ||
configurable: false, | ||
writable: false, | ||
}, | ||
__is_mocked__: { | ||
value: true, | ||
enumerable: false, | ||
configurable: false, | ||
writable: false, | ||
}, | ||
}); | ||
// Mock static methods | ||
@@ -150,2 +178,18 @@ Object.getOwnPropertyNames(target).forEach(prop => { | ||
// Mark instance as mocked | ||
Object.defineProperties(instance, { | ||
[IS_MOCKED]: { | ||
value: true, | ||
enumerable: false, | ||
configurable: false, | ||
writable: false, | ||
}, | ||
__is_mocked__: { | ||
value: true, | ||
enumerable: false, | ||
configurable: false, | ||
writable: false, | ||
}, | ||
}); | ||
// Call original constructor if preserving constructor | ||
@@ -156,10 +200,5 @@ if (config.preserveConstructor) { | ||
Object.getOwnPropertyNames(constructedInstance).forEach(prop => { | ||
const descriptor = Object.getOwnPropertyDescriptor(constructedInstance, prop); | ||
if (descriptor) { | ||
if (typeof descriptor.value === 'function') { | ||
Object.defineProperty(instance, prop, { | ||
...descriptor, | ||
value: createSpy(descriptor.value.bind(instance)), | ||
}); | ||
} else { | ||
if (!(prop in instance)) { | ||
const descriptor = Object.getOwnPropertyDescriptor(constructedInstance, prop); | ||
if (descriptor) { | ||
Object.defineProperty(instance, prop, descriptor); | ||
@@ -171,46 +210,2 @@ } | ||
// Mock prototype methods | ||
Object.getOwnPropertyNames(target.prototype).forEach(prop => { | ||
if (prop === 'constructor') return; | ||
const descriptor = Object.getOwnPropertyDescriptor(target.prototype, prop); | ||
if (descriptor) { | ||
const override = config.overrides?.[prop]; | ||
if (override) { | ||
Object.defineProperty(instance, prop, { | ||
...descriptor, | ||
value: createSpy(override), | ||
}); | ||
} else if (typeof descriptor.value === 'function') { | ||
Object.defineProperty(instance, prop, { | ||
...descriptor, | ||
value: config.preservePrototype ? createSpy(descriptor.value.bind(instance)) : createSpy(), | ||
}); | ||
} | ||
} | ||
}); | ||
// Handle inherited methods | ||
let proto = Object.getPrototypeOf(target.prototype); | ||
while (proto && proto !== Object.prototype) { | ||
Object.getOwnPropertyNames(proto).forEach(prop => { | ||
if (prop === 'constructor') return; | ||
const descriptor = Object.getOwnPropertyDescriptor(proto, prop); | ||
if (descriptor && !instance.hasOwnProperty(prop)) { | ||
const override = config.overrides?.[prop]; | ||
if (override) { | ||
Object.defineProperty(instance, prop, { | ||
...descriptor, | ||
value: createSpy(override), | ||
}); | ||
} else if (typeof descriptor.value === 'function') { | ||
Object.defineProperty(instance, prop, { | ||
...descriptor, | ||
value: config.preservePrototype ? createSpy(descriptor.value.bind(instance)) : createSpy(), | ||
}); | ||
} | ||
} | ||
}); | ||
proto = Object.getPrototypeOf(proto); | ||
} | ||
return instance; | ||
@@ -220,6 +215,58 @@ }; | ||
// Set up prototype chain | ||
MockClass.prototype = Object.create(target.prototype); | ||
Object.setPrototypeOf(MockClass, target); | ||
Object.setPrototypeOf(MockClass.prototype, target.prototype); | ||
// Copy static properties | ||
// Mark mock class as mocked | ||
Object.defineProperties(MockClass, { | ||
[IS_MOCKED]: { | ||
value: true, | ||
enumerable: false, | ||
configurable: false, | ||
writable: false, | ||
}, | ||
__is_mocked__: { | ||
value: true, | ||
enumerable: false, | ||
configurable: false, | ||
writable: false, | ||
}, | ||
}); | ||
// Mark mock class prototype as mocked | ||
Object.defineProperties(MockClass.prototype, { | ||
[IS_MOCKED]: { | ||
value: true, | ||
enumerable: false, | ||
configurable: false, | ||
writable: false, | ||
}, | ||
__is_mocked__: { | ||
value: true, | ||
enumerable: false, | ||
configurable: false, | ||
writable: false, | ||
}, | ||
}); | ||
// Mock prototype methods | ||
Object.getOwnPropertyNames(target.prototype).forEach(prop => { | ||
if (prop === 'constructor') return; | ||
const descriptor = Object.getOwnPropertyDescriptor(target.prototype, prop); | ||
if (descriptor) { | ||
const override = config.overrides?.[prop]; | ||
if (override) { | ||
Object.defineProperty(MockClass.prototype, prop, { | ||
...descriptor, | ||
value: createSpy(override), | ||
}); | ||
} else if (typeof descriptor.value === 'function') { | ||
Object.defineProperty(MockClass.prototype, prop, { | ||
...descriptor, | ||
value: config.preservePrototype ? createSpy(descriptor.value) : createSpy(), | ||
}); | ||
} | ||
} | ||
}); | ||
// Mock static methods | ||
Object.getOwnPropertyNames(target).forEach(prop => { | ||
@@ -247,7 +294,3 @@ if (prop === 'length' || prop === 'prototype' || prop === 'name') return; | ||
// Mark the mock class as mocked | ||
(MockClass as any)[IS_MOCKED] = true; | ||
(MockClass as any).__is_mocked__ = true; | ||
return MockClass as unknown as ClsMock<T>; | ||
} |
import rfdc from 'rfdc'; | ||
import {IS_MOCKED} from '../constants/mock-symbols'; | ||
import {createSpy} from '../spy'; | ||
@@ -54,10 +55,23 @@ import {Fn, MockObject, ObjectMockOptions} from '../types'; | ||
// Check if the object is a class instance that has been mocked | ||
if ((target as any).constructor && (target as any).constructor[IS_MOCKED]) { | ||
return target as MockObject<T>; | ||
} | ||
let mockTarget: T; | ||
if (options.mockInPlace) { | ||
if (options.inPlace) { | ||
mockTarget = target; | ||
} else { | ||
mockTarget = options.mockDeep ? clone(target) : shallowClone(target); | ||
mockTarget = options.prototypeChain ? clone(target) : shallowClone(target); | ||
} | ||
// Mark the object as mocked | ||
Object.defineProperty(mockTarget, IS_MOCKED, { | ||
value: true, | ||
enumerable: false, | ||
configurable: false, | ||
writable: false, | ||
}); | ||
// Process instance methods and properties | ||
@@ -78,3 +92,3 @@ Object.entries(Object.getOwnPropertyDescriptors(target)).forEach(([key, descriptor]) => { | ||
// Mock prototype chain methods if doing deep mocking | ||
if (options.mockDeep) { | ||
if (options.prototypeChain) { | ||
let proto = Object.getPrototypeOf(target); | ||
@@ -81,0 +95,0 @@ while (proto && proto !== Object.prototype) { |
@@ -115,3 +115,3 @@ import {IS_MOCKED} from '../constants/mock-symbols'; | ||
*/ | ||
mockInPlace?: boolean; | ||
inPlace?: boolean; | ||
@@ -154,6 +154,6 @@ /** | ||
* When false, only mocks the top level object's own methods | ||
* Only applies when mockInPlace is false | ||
* Only applies when inPlace is false | ||
* @default false | ||
*/ | ||
mockDeep?: boolean; | ||
prototypeChain?: boolean; | ||
} | ||
@@ -185,3 +185,3 @@ | ||
*/ | ||
mockStatic?: boolean; | ||
static?: boolean; | ||
} | ||
@@ -188,0 +188,0 @@ |
@@ -0,8 +1,66 @@ | ||
import {IS_MOCKED} from '../constants/mock-symbols'; | ||
/** | ||
* Check if an object is already mocked | ||
* This checks both direct mock status and class mock status | ||
*/ | ||
export function isMocked(target: any): boolean { | ||
return ( | ||
target && typeof target === 'object' && 'mockClear' in target && 'mockReset' in target && 'mockRestore' in target | ||
); | ||
if (!target) { | ||
return false; | ||
} | ||
// Check if target is a function (class constructor) | ||
if (typeof target === 'function') { | ||
// Check if class itself is mocked | ||
if (Object.prototype.hasOwnProperty.call(target, IS_MOCKED) || IS_MOCKED in target) { | ||
return true; | ||
} | ||
// Check if class prototype is mocked | ||
if ( | ||
target.prototype && | ||
(Object.prototype.hasOwnProperty.call(target.prototype, IS_MOCKED) || IS_MOCKED in target.prototype) | ||
) { | ||
return true; | ||
} | ||
// Check if class has mock methods | ||
if ('mockClear' in target && 'mockReset' in target && 'mockRestore' in target) { | ||
return true; | ||
} | ||
return false; | ||
} | ||
// Check if target is an object | ||
if (typeof target === 'object') { | ||
// Check if object itself is mocked | ||
if (Object.prototype.hasOwnProperty.call(target, IS_MOCKED) || IS_MOCKED in target) { | ||
return true; | ||
} | ||
// Check if object is an instance of a mocked class | ||
const proto = Object.getPrototypeOf(target); | ||
if (proto) { | ||
// Check prototype chain for IS_MOCKED | ||
let currentProto = proto; | ||
while (currentProto && currentProto !== Object.prototype) { | ||
if (Object.prototype.hasOwnProperty.call(currentProto, IS_MOCKED) || IS_MOCKED in currentProto) { | ||
return true; | ||
} | ||
if ( | ||
currentProto.constructor && | ||
(Object.prototype.hasOwnProperty.call(currentProto.constructor, IS_MOCKED) || | ||
IS_MOCKED in currentProto.constructor) | ||
) { | ||
return true; | ||
} | ||
currentProto = Object.getPrototypeOf(currentProto); | ||
} | ||
} | ||
// Check if object has mock methods | ||
if ('mockClear' in target && 'mockReset' in target && 'mockRestore' in target) { | ||
return true; | ||
} | ||
} | ||
return false; | ||
} |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
547052
56
8701
883