New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

@corez/mock

Package Overview
Dependencies
Maintainers
0
Versions
24
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@corez/mock - npm Package Compare versions

Comparing version 0.6.0 to 0.7.0

src/mocks/__tests__/class.property-descriptor.spec.ts

25

dist/cjs/index.d.ts

@@ -17,2 +17,7 @@ /**

/**
* Mock identification symbol
*/
declare const IS_MOCKED: unique symbol;
/**
* Mock behavior interface

@@ -194,3 +199,3 @@ */

*/
interface MockFunction<T extends Fn = Fn> extends Function {
interface MockFunction<T extends Fn = Fn> {
(...args: Parameters<T>): ReturnType<T>;

@@ -236,17 +241,11 @@ _isMockFunction: boolean;

/**
* Makes all methods in T into MockFunction types
* Mock class type that extends the original class type
* Includes all mock-related properties and methods
*/
type MockOf<T> = {
[P in keyof T]: T[P] extends Fn ? MockFunction<T[P]> : T[P] extends object ? MockOf<T[P]> : T[P];
type ClsMock<T extends Constructor<any>> = T & {
__is_mocked__: boolean;
[IS_MOCKED]: true;
new (...args: ConstructorParameters<T>): InstanceType<T>;
};
/**
* Represents a mocked class constructor
*/
type ClsMock<T extends new (...args: any[]) => any> = {
new (...args: ConstructorParameters<T>): MockOf<InstanceType<T>>;
prototype: MockOf<InstanceType<T>>;
} & {
[K in keyof T]: T[K] extends (...args: any[]) => any ? MockFunction<T[K]> : T[K];
};
/**
* Mock object interface that includes utility methods

@@ -253,0 +252,0 @@ */

@@ -210,2 +210,3 @@ 'use strict';

// src/constants/mock-symbols.ts
var IS_MOCKED = Symbol("__is_mocked__");
var MOCK_SYMBOLS = {

@@ -222,3 +223,5 @@ // State tracking

// Debug info
DEBUG_CONTEXT: Symbol("__mock_debug_context__")
DEBUG_CONTEXT: Symbol("__mock_debug_context__"),
// Mock identification
IS_MOCKED
};

@@ -738,35 +741,4 @@

// src/utils/method-spy.ts
function createMethodSpy(target, methodName, options = {}, originalMethod) {
const tracker = new MethodTracker(target, options);
const method = originalMethod || target[methodName];
const spy = createSpy();
if (!options.preservePrototype) {
return spy;
}
spy.mockImplementation(function(...args) {
tracker.trackMethodCall(methodName, args);
try {
const result = method.apply(this, args);
if (result instanceof Promise) {
return result.then((asyncResult) => {
tracker.trackMethodReturn(methodName, asyncResult);
return asyncResult;
}).catch((error) => {
tracker.trackError(methodName, error);
throw error;
});
}
tracker.trackMethodReturn(methodName, result);
return result;
} catch (error) {
tracker.trackError(methodName, error);
throw error;
}
});
return spy;
}
// src/mocks/class.ts
function handleStaticMethodInheritance(mockClass, originalClass, options = {}) {
function handleStaticMethodInheritance(mockClass, originalClass, _options = {}) {
let currentProto = Object.getPrototypeOf(originalClass);

@@ -777,3 +749,3 @@ while (currentProto && currentProto !== Function.prototype) {

const method = currentProto[methodName].bind(mockClass);
mockClass[methodName] = createMethodSpy(mockClass, methodName, options, method);
mockClass[methodName] = createSpy(method);
}

@@ -784,13 +756,2 @@ });

}
function createPropertyDescriptor(target, name, descriptor, config) {
const getterSpy = descriptor.get ? createMethodSpy(target, name, config, descriptor.get.bind(target)) : void 0;
const setterSpy = descriptor.set ? createMethodSpy(target, name, config, descriptor.set.bind(target)) : void 0;
return {
...descriptor,
get: getterSpy,
set: setterSpy,
configurable: true,
enumerable: descriptor.enumerable
};
}
function initializeMockInstance(instance, config) {

@@ -806,2 +767,8 @@ instance[MOCK_SYMBOLS.STATES] = /* @__PURE__ */ new Map();

function cls(target, options = {}) {
if (target[IS_MOCKED]) {
if (options.debug) {
console.debug("Class is already mocked:", target.name);
}
return target;
}
const config = {

@@ -814,78 +781,38 @@ ...DEFAULT_CLASS_OPTIONS,

}
const handleDescriptor = (name, descriptor, context) => {
if (!descriptor) {
return {
configurable: true,
enumerable: true,
writable: true,
value: void 0
};
}
const { value, get, set } = descriptor;
if (typeof value === "function") {
const override = typeof name === "string" && config.overrides?.[name];
if (override) {
return {
...descriptor,
value: createMethodSpy(context, name, config, override)
};
}
return {
...descriptor,
value: config.preservePrototype ? createMethodSpy(context, name, config, value) : createSpy()
};
}
if (get || set) {
const getterOverride = typeof name === "string" && config.overrides?.[`get${name.charAt(0).toUpperCase()}${name.slice(1)}`];
const setterOverride = typeof name === "string" && config.overrides?.[`set${name.charAt(0).toUpperCase()}${name.slice(1)}`];
const getterSpy = get && (getterOverride ? createMethodSpy(context, name, config, getterOverride) : config.preservePrototype ? createMethodSpy(context, name, config, get) : createSpy());
const setterSpy = set && (setterOverride ? createMethodSpy(context, name, config, setterOverride) : config.preservePrototype ? createMethodSpy(context, name, config, set) : createSpy());
return {
...descriptor,
get: getterSpy,
set: setterSpy
};
}
return descriptor;
};
const processMembers = (target2, source) => {
Object.getOwnPropertyNames(source).forEach((name) => {
if (name === "constructor") return;
const descriptor = Object.getOwnPropertyDescriptor(source, name);
if (!descriptor) return;
if (descriptor.value && typeof descriptor.value === "function") {
const override = config.overrides?.[name];
const method = override || descriptor.value;
target2[name] = createMethodSpy(target2, name, config, method.bind(target2));
} else if (descriptor.get || descriptor.set) {
Object.defineProperty(target2, name, createPropertyDescriptor(target2, name, descriptor, config));
} else {
const value = source[name];
if (typeof value === "function") {
target2[name] = createMethodSpy(target2, name, config, value.bind(target2));
} else {
target2[name] = value;
if (config.mockInPlace) {
target[IS_MOCKED] = true;
target.__is_mocked__ = true;
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(target.prototype, prop, {
...descriptor,
value: createSpy(override)
});
} else if (typeof descriptor.value === "function") {
Object.defineProperty(target.prototype, prop, {
...descriptor,
value: config.preservePrototype ? createSpy(descriptor.value) : createSpy()
});
}
}
});
};
if (config.mockInPlace) {
const proto = target.prototype;
Object.getOwnPropertyNames(proto).forEach((name) => {
if (name === "constructor") return;
const descriptor = Object.getOwnPropertyDescriptor(proto, name);
if (typeof proto[name] === "function") {
proto[name] = createMethodSpy(proto, name, config, proto[name]);
} else if (descriptor) {
Object.defineProperty(proto, name, createPropertyDescriptor(proto, name, descriptor, config));
}
});
Object.getOwnPropertyNames(target).forEach((name) => {
if (name === "length" || name === "prototype" || name === "name") return;
if (typeof target[name] === "function") {
target[name] = createMethodSpy(target, name, config, target[name]);
} else {
const descriptor = Object.getOwnPropertyDescriptor(target, name);
if (descriptor) {
Object.defineProperty(target, name, createPropertyDescriptor(target, name, descriptor, config));
Object.getOwnPropertyNames(target).forEach((prop) => {
if (prop === "length" || prop === "prototype" || prop === "name") return;
const descriptor = Object.getOwnPropertyDescriptor(target, prop);
if (descriptor) {
const override = config.overrides?.[prop];
if (override) {
Object.defineProperty(target, prop, {
...descriptor,
value: createSpy(override)
});
} else if (typeof descriptor.value === "function") {
Object.defineProperty(target, prop, {
...descriptor,
value: config.preservePrototype ? createSpy(descriptor.value) : createSpy()
});
}

@@ -904,9 +831,12 @@ }

initializeMockInstance(instance, config);
try {
const temp = new target(...args);
Object.getOwnPropertyNames(temp).forEach((prop) => {
const descriptor = Object.getOwnPropertyDescriptor(temp, prop);
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") {
instance[prop] = createMethodSpy(instance, prop, config, descriptor.value.bind(instance));
Object.defineProperty(instance, prop, {
...descriptor,
value: createSpy(descriptor.value.bind(instance))
});
} else {

@@ -917,8 +847,41 @@ Object.defineProperty(instance, prop, descriptor);

});
} catch {
}
processMembers(instance, target.prototype);
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) {
processMembers(instance, proto);
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);

@@ -929,11 +892,24 @@ }

MockClass.prototype = Object.create(target.prototype);
MockClass.prototype.constructor = MockClass;
Object.getOwnPropertyNames(target).forEach((name) => {
if (name === "length" || name === "prototype" || name === "name") return;
const descriptor = Object.getOwnPropertyDescriptor(target, name);
Object.setPrototypeOf(MockClass, target);
Object.getOwnPropertyNames(target).forEach((prop) => {
if (prop === "length" || prop === "prototype" || prop === "name") return;
const descriptor = Object.getOwnPropertyDescriptor(target, prop);
if (descriptor) {
Object.defineProperty(MockClass, name, handleDescriptor(name, descriptor, target));
const override = config.overrides?.[prop];
if (override) {
Object.defineProperty(MockClass, prop, {
...descriptor,
value: createSpy(override)
});
} else if (typeof descriptor.value === "function") {
Object.defineProperty(MockClass, prop, {
...descriptor,
value: config.preservePrototype ? createSpy(descriptor.value) : createSpy()
});
}
}
});
handleStaticMethodInheritance(MockClass, target, { debug: config.debug });
MockClass[IS_MOCKED] = true;
MockClass.__is_mocked__ = true;
return MockClass;

@@ -987,3 +963,3 @@ }

}
function createMethodSpy2(method, mockTarget, isArrowFn) {
function createMethodSpy(method, mockTarget, isArrowFn) {
const spy = createSpy();

@@ -1013,3 +989,3 @@ const boundMethod = function(...args) {

const isArrowFn = !method.prototype;
const spy = createMethodSpy2(method, mockTarget, isArrowFn);
const spy = createMethodSpy(method, mockTarget, isArrowFn);
Object.defineProperty(mockTarget, key, {

@@ -1028,3 +1004,3 @@ ...descriptor,

const isArrowFn = !method.prototype;
const spy = createMethodSpy2(method, mockTarget, isArrowFn);
const spy = createMethodSpy(method, mockTarget, isArrowFn);
Object.defineProperty(mockTarget, key, {

@@ -1031,0 +1007,0 @@ ...descriptor,

@@ -204,2 +204,3 @@ import rfdc from 'rfdc';

// src/constants/mock-symbols.ts
var IS_MOCKED = Symbol("__is_mocked__");
var MOCK_SYMBOLS = {

@@ -216,3 +217,5 @@ // State tracking

// Debug info
DEBUG_CONTEXT: Symbol("__mock_debug_context__")
DEBUG_CONTEXT: Symbol("__mock_debug_context__"),
// Mock identification
IS_MOCKED
};

@@ -732,35 +735,4 @@

// src/utils/method-spy.ts
function createMethodSpy(target, methodName, options = {}, originalMethod) {
const tracker = new MethodTracker(target, options);
const method = originalMethod || target[methodName];
const spy = createSpy();
if (!options.preservePrototype) {
return spy;
}
spy.mockImplementation(function(...args) {
tracker.trackMethodCall(methodName, args);
try {
const result = method.apply(this, args);
if (result instanceof Promise) {
return result.then((asyncResult) => {
tracker.trackMethodReturn(methodName, asyncResult);
return asyncResult;
}).catch((error) => {
tracker.trackError(methodName, error);
throw error;
});
}
tracker.trackMethodReturn(methodName, result);
return result;
} catch (error) {
tracker.trackError(methodName, error);
throw error;
}
});
return spy;
}
// src/mocks/class.ts
function handleStaticMethodInheritance(mockClass, originalClass, options = {}) {
function handleStaticMethodInheritance(mockClass, originalClass, _options = {}) {
let currentProto = Object.getPrototypeOf(originalClass);

@@ -771,3 +743,3 @@ while (currentProto && currentProto !== Function.prototype) {

const method = currentProto[methodName].bind(mockClass);
mockClass[methodName] = createMethodSpy(mockClass, methodName, options, method);
mockClass[methodName] = createSpy(method);
}

@@ -778,13 +750,2 @@ });

}
function createPropertyDescriptor(target, name, descriptor, config) {
const getterSpy = descriptor.get ? createMethodSpy(target, name, config, descriptor.get.bind(target)) : void 0;
const setterSpy = descriptor.set ? createMethodSpy(target, name, config, descriptor.set.bind(target)) : void 0;
return {
...descriptor,
get: getterSpy,
set: setterSpy,
configurable: true,
enumerable: descriptor.enumerable
};
}
function initializeMockInstance(instance, config) {

@@ -800,2 +761,8 @@ instance[MOCK_SYMBOLS.STATES] = /* @__PURE__ */ new Map();

function cls(target, options = {}) {
if (target[IS_MOCKED]) {
if (options.debug) {
console.debug("Class is already mocked:", target.name);
}
return target;
}
const config = {

@@ -808,78 +775,38 @@ ...DEFAULT_CLASS_OPTIONS,

}
const handleDescriptor = (name, descriptor, context) => {
if (!descriptor) {
return {
configurable: true,
enumerable: true,
writable: true,
value: void 0
};
}
const { value, get, set } = descriptor;
if (typeof value === "function") {
const override = typeof name === "string" && config.overrides?.[name];
if (override) {
return {
...descriptor,
value: createMethodSpy(context, name, config, override)
};
}
return {
...descriptor,
value: config.preservePrototype ? createMethodSpy(context, name, config, value) : createSpy()
};
}
if (get || set) {
const getterOverride = typeof name === "string" && config.overrides?.[`get${name.charAt(0).toUpperCase()}${name.slice(1)}`];
const setterOverride = typeof name === "string" && config.overrides?.[`set${name.charAt(0).toUpperCase()}${name.slice(1)}`];
const getterSpy = get && (getterOverride ? createMethodSpy(context, name, config, getterOverride) : config.preservePrototype ? createMethodSpy(context, name, config, get) : createSpy());
const setterSpy = set && (setterOverride ? createMethodSpy(context, name, config, setterOverride) : config.preservePrototype ? createMethodSpy(context, name, config, set) : createSpy());
return {
...descriptor,
get: getterSpy,
set: setterSpy
};
}
return descriptor;
};
const processMembers = (target2, source) => {
Object.getOwnPropertyNames(source).forEach((name) => {
if (name === "constructor") return;
const descriptor = Object.getOwnPropertyDescriptor(source, name);
if (!descriptor) return;
if (descriptor.value && typeof descriptor.value === "function") {
const override = config.overrides?.[name];
const method = override || descriptor.value;
target2[name] = createMethodSpy(target2, name, config, method.bind(target2));
} else if (descriptor.get || descriptor.set) {
Object.defineProperty(target2, name, createPropertyDescriptor(target2, name, descriptor, config));
} else {
const value = source[name];
if (typeof value === "function") {
target2[name] = createMethodSpy(target2, name, config, value.bind(target2));
} else {
target2[name] = value;
if (config.mockInPlace) {
target[IS_MOCKED] = true;
target.__is_mocked__ = true;
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(target.prototype, prop, {
...descriptor,
value: createSpy(override)
});
} else if (typeof descriptor.value === "function") {
Object.defineProperty(target.prototype, prop, {
...descriptor,
value: config.preservePrototype ? createSpy(descriptor.value) : createSpy()
});
}
}
});
};
if (config.mockInPlace) {
const proto = target.prototype;
Object.getOwnPropertyNames(proto).forEach((name) => {
if (name === "constructor") return;
const descriptor = Object.getOwnPropertyDescriptor(proto, name);
if (typeof proto[name] === "function") {
proto[name] = createMethodSpy(proto, name, config, proto[name]);
} else if (descriptor) {
Object.defineProperty(proto, name, createPropertyDescriptor(proto, name, descriptor, config));
}
});
Object.getOwnPropertyNames(target).forEach((name) => {
if (name === "length" || name === "prototype" || name === "name") return;
if (typeof target[name] === "function") {
target[name] = createMethodSpy(target, name, config, target[name]);
} else {
const descriptor = Object.getOwnPropertyDescriptor(target, name);
if (descriptor) {
Object.defineProperty(target, name, createPropertyDescriptor(target, name, descriptor, config));
Object.getOwnPropertyNames(target).forEach((prop) => {
if (prop === "length" || prop === "prototype" || prop === "name") return;
const descriptor = Object.getOwnPropertyDescriptor(target, prop);
if (descriptor) {
const override = config.overrides?.[prop];
if (override) {
Object.defineProperty(target, prop, {
...descriptor,
value: createSpy(override)
});
} else if (typeof descriptor.value === "function") {
Object.defineProperty(target, prop, {
...descriptor,
value: config.preservePrototype ? createSpy(descriptor.value) : createSpy()
});
}

@@ -898,9 +825,12 @@ }

initializeMockInstance(instance, config);
try {
const temp = new target(...args);
Object.getOwnPropertyNames(temp).forEach((prop) => {
const descriptor = Object.getOwnPropertyDescriptor(temp, prop);
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") {
instance[prop] = createMethodSpy(instance, prop, config, descriptor.value.bind(instance));
Object.defineProperty(instance, prop, {
...descriptor,
value: createSpy(descriptor.value.bind(instance))
});
} else {

@@ -911,8 +841,41 @@ Object.defineProperty(instance, prop, descriptor);

});
} catch {
}
processMembers(instance, target.prototype);
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) {
processMembers(instance, proto);
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);

@@ -923,11 +886,24 @@ }

MockClass.prototype = Object.create(target.prototype);
MockClass.prototype.constructor = MockClass;
Object.getOwnPropertyNames(target).forEach((name) => {
if (name === "length" || name === "prototype" || name === "name") return;
const descriptor = Object.getOwnPropertyDescriptor(target, name);
Object.setPrototypeOf(MockClass, target);
Object.getOwnPropertyNames(target).forEach((prop) => {
if (prop === "length" || prop === "prototype" || prop === "name") return;
const descriptor = Object.getOwnPropertyDescriptor(target, prop);
if (descriptor) {
Object.defineProperty(MockClass, name, handleDescriptor(name, descriptor, target));
const override = config.overrides?.[prop];
if (override) {
Object.defineProperty(MockClass, prop, {
...descriptor,
value: createSpy(override)
});
} else if (typeof descriptor.value === "function") {
Object.defineProperty(MockClass, prop, {
...descriptor,
value: config.preservePrototype ? createSpy(descriptor.value) : createSpy()
});
}
}
});
handleStaticMethodInheritance(MockClass, target, { debug: config.debug });
MockClass[IS_MOCKED] = true;
MockClass.__is_mocked__ = true;
return MockClass;

@@ -981,3 +957,3 @@ }

}
function createMethodSpy2(method, mockTarget, isArrowFn) {
function createMethodSpy(method, mockTarget, isArrowFn) {
const spy = createSpy();

@@ -1007,3 +983,3 @@ const boundMethod = function(...args) {

const isArrowFn = !method.prototype;
const spy = createMethodSpy2(method, mockTarget, isArrowFn);
const spy = createMethodSpy(method, mockTarget, isArrowFn);
Object.defineProperty(mockTarget, key, {

@@ -1022,3 +998,3 @@ ...descriptor,

const isArrowFn = !method.prototype;
const spy = createMethodSpy2(method, mockTarget, isArrowFn);
const spy = createMethodSpy(method, mockTarget, isArrowFn);
Object.defineProperty(mockTarget, key, {

@@ -1025,0 +1001,0 @@ ...descriptor,

{
"name": "@corez/mock",
"version": "0.6.0",
"version": "0.7.0",
"description": "A powerful and flexible TypeScript mocking library for testing",

@@ -5,0 +5,0 @@ "keywords": [

@@ -171,2 +171,6 @@ # @corez/mock

// Check if class is mocked
console.log(MockDatabase.__is_mocked__); // true
console.log(MockDatabase[IS_MOCKED]); // true
const db = new MockDatabase();

@@ -194,2 +198,21 @@ // Access call information

### Type Definitions
The library provides comprehensive type definitions for mocked classes:
```typescript
// Mock class type that includes mock markers
type ClsMock<T extends Constructor<any>> = T & {
__is_mocked__: boolean;
[IS_MOCKED]: true;
new (...args: ConstructorParameters<T>): InstanceType<T>;
};
// Usage with type checking
const mockDb: ClsMock<typeof Database> = mock.cls(Database);
if (mockDb.__is_mocked__) {
console.log('Class is mocked');
}
```
## API Reference

@@ -253,43 +276,57 @@

#### `mock.cls<T extends Constructor<any>>(target: T, options?: ClsMockOptions<T>): ClsMock<T>`
#### `mock.cls<T extends Constructor<any>>(target: T, options?: ClassMockOptions<T>): ClsMock<T>`
Creates a mock class with automatic method tracking:
Creates a mock class with automatic method tracking and type safety:
```typescript
class Database {
async connect() {
/* ... */
}
async query(sql: string) {
/* ... */
}
}
// Create a mock class with options
const MockDatabase = mock.cls(Database, {
// Modify original class instead of creating new one
mockInPlace: false,
// Create a new mock class
const MockDatabase = mock.cls(Database, {
// Preserve original method implementations
preservePrototype: true,
// Call original constructor
preserveConstructor: true,
// Override specific methods
overrides: {
query: async () => [{id: 1}],
},
// Enable debug logging
debug: false,
});
const db = new MockDatabase();
// Access call information
const queryMock = db.query as MockFunction;
// Type checking and verification
if (MockDatabase.__is_mocked__) {
console.log('Class is properly mocked');
}
// Access mock information
const instance = new MockDatabase();
const queryMock = instance.query as MockFunction;
console.log(queryMock.calls.count());
```
// Or modify the original class
mock.cls(Database, {
mockInPlace: true,
overrides: {
query: async () => [{id: 1}],
},
});
The `ClassMockOptions` interface provides fine-grained control:
// Store original methods for restoration
const originalQuery = Database.prototype.query;
const originalConnect = Database.prototype.connect;
```typescript
interface ClassMockOptions<T> {
// Whether to modify the original class
mockInPlace?: boolean;
// Later, restore original methods
Database.prototype.query = originalQuery;
Database.prototype.connect = originalConnect;
// Whether to preserve original method implementations
preservePrototype?: boolean;
// Whether to call original constructor
preserveConstructor?: boolean;
// Method overrides
overrides?: Partial<T>;
// Enable debug logging
debug?: boolean;
}
```

@@ -296,0 +333,0 @@

/**
* Mock identification symbol
*/
export const IS_MOCKED = Symbol('__is_mocked__');
/**
* Mock-related symbols used for internal state tracking and property access.

@@ -20,2 +25,5 @@ * Using symbols ensures no naming conflicts with mocked objects.

DEBUG_CONTEXT: Symbol('__mock_debug_context__'),
// Mock identification
IS_MOCKED: IS_MOCKED,
} as const;

@@ -22,0 +30,0 @@

@@ -1,2 +0,2 @@

import type {MockFunction} from '../../types';
import type {ClsMock, MockFunction} from '../../types';
import {cls} from '../class';

@@ -46,3 +46,3 @@

expect(typeof mockAnimal.makeSound).toBe('function');
expect(mockAnimal.makeSound.mock).toBeDefined();
expect((mockAnimal.makeSound as MockFunction<() => string>).mock).toBeDefined();
});

@@ -55,3 +55,3 @@

(mockAnimal.makeSound as MockFunction).mockImplementation(mockSound);
(mockAnimal.makeSound as MockFunction<() => string>).mockImplementation(mockSound);
expect(mockAnimal.makeSound()).toBe('custom sound');

@@ -371,3 +371,3 @@ expect(mockSound).toHaveBeenCalled();

(mockAnimal.makeSound as MockFunction).mockImplementation(mockSound);
(mockAnimal.makeSound as MockFunction<() => string>).mockImplementation(mockSound);
expect(mockAnimal.makeSound()).toBe('mocked sound');

@@ -385,3 +385,3 @@ expect(mockSound).toHaveBeenCalled();

(mockAnimal.makeSound as MockFunction).mockImplementation(mockSound);
(mockAnimal.makeSound as MockFunction<() => string>).mockImplementation(mockSound);
mockAnimal.makeSound();

@@ -495,2 +495,37 @@ expect(mockSound).toHaveBeenCalled();

});
describe('IS_MOCKED symbol', () => {
class TestClass {
value: string = 'test';
getValue(): string {
return this.value;
}
}
it('should mark mock class with IS_MOCKED symbol', () => {
const MockClass = cls(TestClass);
expect((MockClass as ClsMock<typeof TestClass>).__is_mocked__).toBe(true);
});
it('should mark mock class with IS_MOCKED symbol when mockInPlace is true', () => {
const MockClass = cls(TestClass, {mockInPlace: true});
expect((MockClass as ClsMock<typeof TestClass>).__is_mocked__).toBe(true);
});
it('should not create mock if class is already mocked', () => {
const FirstMock = cls(TestClass);
const SecondMock = cls(FirstMock);
expect(SecondMock).toBe(FirstMock);
});
it('should preserve IS_MOCKED symbol after inheritance', () => {
class ChildClass extends TestClass {
getUpperValue(): string {
return this.getValue().toUpperCase();
}
}
const MockChildClass = cls(ChildClass);
expect((MockChildClass as ClsMock<typeof ChildClass>).__is_mocked__).toBe(true);
});
});
});

@@ -1,2 +0,2 @@

import {MOCK_SYMBOLS} from '../constants/mock-symbols';
import {IS_MOCKED, MOCK_SYMBOLS} from '../constants/mock-symbols';
import {DEFAULT_CLASS_OPTIONS} from '../defaults';

@@ -6,3 +6,2 @@ import {createSpy} from '../spy';

import {createDebugContext} from '../utils/debug';
import {createMethodSpy} from '../utils/method-spy';

@@ -12,3 +11,3 @@ function handleStaticMethodInheritance(

originalClass: any,
options: Partial<ClassMockOptions> = {},
_options: Partial<ClassMockOptions> = {},
): void {

@@ -23,3 +22,3 @@ let currentProto = Object.getPrototypeOf(originalClass);

const method = currentProto[methodName].bind(mockClass);
mockClass[methodName] = createMethodSpy(mockClass, methodName, options, method);
mockClass[methodName] = createSpy(method);
}

@@ -31,24 +30,2 @@ });

function createPropertyDescriptor<T>(
target: any,
name: string | symbol,
descriptor: PropertyDescriptor,
config: ClassMockOptions<T>,
): PropertyDescriptor {
const getterSpy = descriptor.get
? createMethodSpy(target, name as string, config, descriptor.get.bind(target))
: undefined;
const setterSpy = descriptor.set
? createMethodSpy(target, name as string, config, descriptor.set.bind(target))
: undefined;
return {
...descriptor,
get: getterSpy as (() => any) | undefined,
set: setterSpy as ((v: any) => void) | undefined,
configurable: true,
enumerable: descriptor.enumerable,
};
}
function initializeMockInstance(instance: any, config: ClassMockOptions): void {

@@ -91,2 +68,10 @@ // Use symbols for all mock-related properties

): ClsMock<T> {
// Check if the class is already mocked
if ((target as any)[IS_MOCKED]) {
if (options.debug) {
console.debug('Class is already mocked:', target.name);
}
return target as unknown as ClsMock<T>;
}
const config = {

@@ -101,116 +86,44 @@ ...DEFAULT_CLASS_OPTIONS,

// Helper to handle property descriptor
const handleDescriptor = (
name: string | symbol,
descriptor: PropertyDescriptor | undefined,
context: any,
): PropertyDescriptor => {
if (!descriptor) {
return {
configurable: true,
enumerable: true,
writable: true,
value: undefined,
};
}
if (config.mockInPlace) {
// Modify the original class (when mockInPlace is true)
// Mark the class as mocked
(target as any)[IS_MOCKED] = true;
(target as any).__is_mocked__ = true;
const {value, get, set} = descriptor;
if (typeof value === 'function') {
// Check if there's an override implementation
const override = typeof name === 'string' && config.overrides?.[name];
if (override) {
return {
...descriptor,
value: createMethodSpy(context, name as string, config, override),
};
}
return {
...descriptor,
value: config.preservePrototype ? createMethodSpy(context, name as string, config, value) : createSpy(),
};
}
if (get || set) {
// Check if there are getter/setter overrides
const getterOverride =
typeof name === 'string' && config.overrides?.[`get${name.charAt(0).toUpperCase()}${name.slice(1)}`];
const setterOverride =
typeof name === 'string' && config.overrides?.[`set${name.charAt(0).toUpperCase()}${name.slice(1)}`];
const getterSpy =
get &&
(getterOverride
? createMethodSpy(context, name as string, config, getterOverride)
: config.preservePrototype
? createMethodSpy(context, name as string, config, get)
: createSpy());
const setterSpy =
set &&
(setterOverride
? createMethodSpy(context, name as string, config, setterOverride)
: config.preservePrototype
? createMethodSpy(context, name as string, config, set)
: createSpy());
return {
...descriptor,
get: getterSpy,
set: setterSpy,
};
}
return descriptor;
};
// Process instance properties and methods
const processMembers = (target: any, source: any) => {
Object.getOwnPropertyNames(source).forEach(name => {
if (name === 'constructor') return;
const descriptor = Object.getOwnPropertyDescriptor(source, name);
if (!descriptor) return;
if (descriptor.value && typeof descriptor.value === 'function') {
const override = config.overrides?.[name];
const method = override || descriptor.value;
target[name] = createMethodSpy(target, name, config, method.bind(target));
} else if (descriptor.get || descriptor.set) {
Object.defineProperty(target, name, createPropertyDescriptor(target, name, descriptor, config));
} else {
// Handle prototype methods defined as properties
const value = source[name];
if (typeof value === 'function') {
target[name] = createMethodSpy(target, name, config, value.bind(target));
} else {
target[name] = value;
// 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(target.prototype, prop, {
...descriptor,
value: createSpy(override),
});
} else if (typeof descriptor.value === 'function') {
Object.defineProperty(target.prototype, prop, {
...descriptor,
value: config.preservePrototype ? createSpy(descriptor.value) : createSpy(),
});
}
}
});
};
if (config.mockInPlace) {
// Modify the original class (when mockInPlace is true)
// First, process prototype methods
const proto = target.prototype;
Object.getOwnPropertyNames(proto).forEach(name => {
if (name === 'constructor') return;
const descriptor = Object.getOwnPropertyDescriptor(proto, name);
if (typeof proto[name] === 'function') {
(proto as any)[name] = createMethodSpy(proto, name, config, proto[name]);
} else if (descriptor) {
Object.defineProperty(proto, name, createPropertyDescriptor(proto, name, descriptor, config));
}
});
// Handle static members
Object.getOwnPropertyNames(target).forEach(name => {
if (name === 'length' || name === 'prototype' || name === 'name') return;
if (typeof (target as any)[name] === 'function') {
(target as any)[name] = createMethodSpy(target, name, config, (target as any)[name]);
} else {
const descriptor = Object.getOwnPropertyDescriptor(target, name);
if (descriptor) {
Object.defineProperty(target, name, createPropertyDescriptor(target, name, descriptor, config));
// Mock static methods
Object.getOwnPropertyNames(target).forEach(prop => {
if (prop === 'length' || prop === 'prototype' || prop === 'name') return;
const descriptor = Object.getOwnPropertyDescriptor(target, prop);
if (descriptor) {
const override = config.overrides?.[prop];
if (override) {
Object.defineProperty(target, prop, {
...descriptor,
value: createSpy(override),
});
} else if (typeof descriptor.value === 'function') {
Object.defineProperty(target, prop, {
...descriptor,
value: config.preservePrototype ? createSpy(descriptor.value) : createSpy(),
});
}

@@ -240,12 +153,14 @@ }

try {
// Create a temporary instance to get instance properties
const temp = new target(...args);
// Call original constructor if preserving constructor
if (config.preserveConstructor) {
const constructedInstance = Reflect.construct(target, args);
// Copy instance properties
Object.getOwnPropertyNames(temp).forEach(prop => {
const descriptor = Object.getOwnPropertyDescriptor(temp, prop);
Object.getOwnPropertyNames(constructedInstance).forEach(prop => {
const descriptor = Object.getOwnPropertyDescriptor(constructedInstance, prop);
if (descriptor) {
if (typeof descriptor.value === 'function') {
// Handle arrow function class fields
instance[prop] = createMethodSpy(instance, prop, config, descriptor.value.bind(instance));
Object.defineProperty(instance, prop, {
...descriptor,
value: createSpy(descriptor.value.bind(instance)),
});
} else {

@@ -256,13 +171,45 @@ Object.defineProperty(instance, prop, descriptor);

});
} catch {
// Silently continue if constructor fails
}
// Process prototype methods
processMembers(instance, target.prototype);
// 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 members
// Handle inherited methods
let proto = Object.getPrototypeOf(target.prototype);
while (proto && proto !== Object.prototype) {
processMembers(instance, proto);
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);

@@ -272,15 +219,25 @@ }

return instance;
} as unknown as T;
};
// Set up prototype chain
MockClass.prototype = Object.create(target.prototype);
MockClass.prototype.constructor = MockClass;
Object.setPrototypeOf(MockClass, target);
// Handle static members
Object.getOwnPropertyNames(target).forEach(name => {
if (name === 'length' || name === 'prototype' || name === 'name') return;
const descriptor = Object.getOwnPropertyDescriptor(target, name);
// Copy static properties
Object.getOwnPropertyNames(target).forEach(prop => {
if (prop === 'length' || prop === 'prototype' || prop === 'name') return;
const descriptor = Object.getOwnPropertyDescriptor(target, prop);
if (descriptor) {
Object.defineProperty(MockClass, name, handleDescriptor(name, descriptor, target));
const override = config.overrides?.[prop];
if (override) {
Object.defineProperty(MockClass, prop, {
...descriptor,
value: createSpy(override),
});
} else if (typeof descriptor.value === 'function') {
Object.defineProperty(MockClass, prop, {
...descriptor,
value: config.preservePrototype ? createSpy(descriptor.value) : createSpy(),
});
}
}

@@ -292,3 +249,7 @@ });

// 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>;
}

@@ -153,3 +153,3 @@ import {Fn, MockFunction} from './types';

spy._this = thisArg;
const result = target.apply(thisArg, argumentsList);
const result = target.apply(thisArg, argumentsList as unknown as Parameters<T>);
spy._this = null;

@@ -156,0 +156,0 @@ return result;

@@ -0,1 +1,2 @@

import {IS_MOCKED} from '../constants/mock-symbols';
import type {Constructor, DeepPartial, Fn, PropertyDescriptor, RecursivePartial} from './common';

@@ -201,3 +202,3 @@

*/
export interface MockFunction<T extends Fn = Fn> extends Function {
export interface MockFunction<T extends Fn = Fn> {
(...args: Parameters<T>): ReturnType<T>;

@@ -372,9 +373,9 @@ _isMockFunction: boolean;

/**
* Represents a mocked class constructor
* Mock class type that extends the original class type
* Includes all mock-related properties and methods
*/
export type ClsMock<T extends new (...args: any[]) => any> = {
new (...args: ConstructorParameters<T>): MockOf<InstanceType<T>>;
prototype: MockOf<InstanceType<T>>;
} & {
[K in keyof T]: T[K] extends (...args: any[]) => any ? MockFunction<T[K]> : T[K];
export type ClsMock<T extends Constructor<any>> = T & {
__is_mocked__: boolean;
[IS_MOCKED]: true;
new (...args: ConstructorParameters<T>): InstanceType<T>;
};

@@ -381,0 +382,0 @@

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

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc