@corez/mock
Advanced tools
Comparing version 0.13.4 to 0.14.0
import { mock } from './mock.js'; | ||
export { AsyncMockedFunction, Constructor, CreateSpy, DeepPartial, EnhancedMockOptionsInput, FakerOptions, JestMatcherExtensions, JestMockedFunction, KeepOriginalFn, KeepOriginalMatcher, KeepOriginalPattern, MockAPI, MockBehavior, MockCallback, MockConfig, MockConfigObject, MockData, MockDecorator, MockMultipleConfig, MockOptions, MockOptionsInput, MockProperty, MockValue, MockedClass, MockedFunction, MockedObject, PromiseOrValue } from './types.js'; | ||
export { DecoratorError, Mock } from './decorators.js'; | ||
export { AsyncMockedFunction, Constructor, CreateSpy, DeepPartial, EnhancedMockOptionsInput, FakerOptions, JestMatcherExtensions, JestMockedFunction, KeepOriginalFn, KeepOriginalMatcher, KeepOriginalPattern, MockAPI, MockBehavior, MockCallback, MockConfig, MockConfigObject, MockData, MockDecorator, MockMultipleConfig, MockOptionsInput, MockProperty, MockValue, MockedClass, MockedFunction, MockedObject, PromiseOrValue } from './types.js'; | ||
export { Faker } from '@faker-js/faker'; | ||
@@ -5,0 +4,0 @@ |
@@ -27,9 +27,7 @@ "use strict"; | ||
__reExport(index_exports, require("./types"), module.exports); | ||
__reExport(index_exports, require("./decorators"), module.exports); | ||
var index_default = import_mock.mock; | ||
// Annotate the CommonJS export names for ESM import in node: | ||
0 && (module.exports = { | ||
...require("./types"), | ||
...require("./decorators") | ||
...require("./types") | ||
}); | ||
//# sourceMappingURL=index.js.map |
@@ -99,6 +99,68 @@ "use strict"; | ||
} | ||
const mock2 = Object.create(Object.getPrototypeOf(target)); | ||
defineMockProperties(mock2, target, options); | ||
metadata.set(mock2, { type: "object", original: target, options }); | ||
return mock2; | ||
const existingMeta = metadata.get(target); | ||
if (existingMeta) { | ||
return target; | ||
} | ||
const normalizedOptions = typeof options === "function" || typeof options === "string" || options instanceof RegExp || Array.isArray(options) ? { keepOriginal: options } : options; | ||
const { inPlace = false, ...otherOptions } = normalizedOptions; | ||
if (!inPlace) { | ||
const mock2 = Object.create(Object.getPrototypeOf(target)); | ||
defineMockProperties(mock2, target, otherOptions); | ||
metadata.set(mock2, { | ||
type: "object", | ||
original: target, | ||
options: otherOptions, | ||
inPlace: false | ||
}); | ||
return mock2; | ||
} | ||
const mockMethodsKey = Symbol("mockMethods"); | ||
const mockMethods = /* @__PURE__ */ new Map(); | ||
const props = /* @__PURE__ */ new Set(); | ||
let current = target; | ||
while (current && current !== Object.prototype) { | ||
Object.getOwnPropertyNames(current).forEach((prop) => props.add(prop)); | ||
Object.getOwnPropertySymbols(current).forEach((prop) => props.add(prop)); | ||
current = Object.getPrototypeOf(current); | ||
} | ||
props.forEach((prop) => { | ||
let current2 = target; | ||
let descriptor; | ||
while (current2 && !descriptor) { | ||
descriptor = Object.getOwnPropertyDescriptor(current2, prop); | ||
current2 = Object.getPrototypeOf(current2); | ||
} | ||
if (!descriptor) return; | ||
if (typeof descriptor.value === "function") { | ||
const keepArgs = { property: prop.toString(), descriptor, original: target, mock: target }; | ||
if (shouldKeepMockOriginal(keepArgs, otherOptions)) { | ||
return; | ||
} | ||
const mockFn2 = otherOptions.createSpy?.() || mockFunction(); | ||
mockMethods.set(prop, mockFn2); | ||
try { | ||
Object.defineProperty(target, prop, { | ||
configurable: true, | ||
enumerable: descriptor.enumerable, | ||
writable: true, | ||
value: mockFn2 | ||
}); | ||
} catch { | ||
mockMethods.delete(prop); | ||
} | ||
} | ||
}); | ||
Object.defineProperty(target, mockMethodsKey, { | ||
value: mockMethods, | ||
enumerable: false, | ||
configurable: false | ||
}); | ||
metadata.set(target, { | ||
type: "object", | ||
original: target, | ||
options: otherOptions, | ||
inPlace: true, | ||
mockMethodsKey | ||
}); | ||
return target; | ||
} | ||
@@ -105,0 +167,0 @@ function mockClassState() { |
@@ -54,6 +54,22 @@ import { Faker } from '@faker-js/faker'; | ||
createSpy?: CreateSpy; | ||
/** | ||
* Whether to modify the target object directly instead of creating a clone | ||
*/ | ||
inPlace?: boolean; | ||
} | ||
type MockOptions = KeepOriginalMatcher | MockConfigObject; | ||
type MockOptionsInput = MockConfigObject | KeepOriginalMatcher; | ||
/** | ||
* Mock options can be either a matcher pattern or a config object | ||
*/ | ||
type MockOptionsInput = KeepOriginalMatcher | MockConfigObject; | ||
/** | ||
* Metadata for mock tracking | ||
*/ | ||
interface MockData<T = unknown> { | ||
type: 'function' | 'object' | 'class'; | ||
original: T; | ||
options: MockOptionsInput; | ||
inPlace?: boolean; | ||
mockMethodsKey?: symbol; | ||
} | ||
/** | ||
* Enhanced mock options that can be passed to Mock decorator | ||
@@ -113,10 +129,2 @@ */ | ||
/** | ||
* Metadata for mock tracking | ||
*/ | ||
interface MockData<T = unknown> { | ||
type: 'function' | 'object' | 'class'; | ||
original: T; | ||
options: MockOptionsInput; | ||
} | ||
/** | ||
* Core mock API | ||
@@ -199,2 +207,2 @@ */ | ||
export type { AsyncMockedFunction, Constructor, CreateSpy, DeepPartial, EnhancedMockOptionsInput, FakerOptions, JestMatcherExtensions, JestMockedFunction, KeepOriginalFn, KeepOriginalMatcher, KeepOriginalPattern, MockAPI, MockBehavior, MockCallback, MockConfig, MockConfigObject, MockData, MockDecorator, MockMultipleConfig, MockOptions, MockOptionsInput, MockProperty, MockValue, MockedClass, MockedFunction, MockedObject, PromiseOrValue }; | ||
export type { AsyncMockedFunction, Constructor, CreateSpy, DeepPartial, EnhancedMockOptionsInput, FakerOptions, JestMatcherExtensions, JestMockedFunction, KeepOriginalFn, KeepOriginalMatcher, KeepOriginalPattern, MockAPI, MockBehavior, MockCallback, MockConfig, MockConfigObject, MockData, MockDecorator, MockMultipleConfig, MockOptionsInput, MockProperty, MockValue, MockedClass, MockedFunction, MockedObject, PromiseOrValue }; |
import { mock } from "./mock"; | ||
export * from "./types"; | ||
export * from "./decorators"; | ||
var index_default = mock; | ||
@@ -5,0 +4,0 @@ export { |
@@ -66,6 +66,68 @@ import micromatch from "micromatch"; | ||
} | ||
const mock2 = Object.create(Object.getPrototypeOf(target)); | ||
defineMockProperties(mock2, target, options); | ||
metadata.set(mock2, { type: "object", original: target, options }); | ||
return mock2; | ||
const existingMeta = metadata.get(target); | ||
if (existingMeta) { | ||
return target; | ||
} | ||
const normalizedOptions = typeof options === "function" || typeof options === "string" || options instanceof RegExp || Array.isArray(options) ? { keepOriginal: options } : options; | ||
const { inPlace = false, ...otherOptions } = normalizedOptions; | ||
if (!inPlace) { | ||
const mock2 = Object.create(Object.getPrototypeOf(target)); | ||
defineMockProperties(mock2, target, otherOptions); | ||
metadata.set(mock2, { | ||
type: "object", | ||
original: target, | ||
options: otherOptions, | ||
inPlace: false | ||
}); | ||
return mock2; | ||
} | ||
const mockMethodsKey = Symbol("mockMethods"); | ||
const mockMethods = /* @__PURE__ */ new Map(); | ||
const props = /* @__PURE__ */ new Set(); | ||
let current = target; | ||
while (current && current !== Object.prototype) { | ||
Object.getOwnPropertyNames(current).forEach((prop) => props.add(prop)); | ||
Object.getOwnPropertySymbols(current).forEach((prop) => props.add(prop)); | ||
current = Object.getPrototypeOf(current); | ||
} | ||
props.forEach((prop) => { | ||
let current2 = target; | ||
let descriptor; | ||
while (current2 && !descriptor) { | ||
descriptor = Object.getOwnPropertyDescriptor(current2, prop); | ||
current2 = Object.getPrototypeOf(current2); | ||
} | ||
if (!descriptor) return; | ||
if (typeof descriptor.value === "function") { | ||
const keepArgs = { property: prop.toString(), descriptor, original: target, mock: target }; | ||
if (shouldKeepMockOriginal(keepArgs, otherOptions)) { | ||
return; | ||
} | ||
const mockFn2 = otherOptions.createSpy?.() || mockFunction(); | ||
mockMethods.set(prop, mockFn2); | ||
try { | ||
Object.defineProperty(target, prop, { | ||
configurable: true, | ||
enumerable: descriptor.enumerable, | ||
writable: true, | ||
value: mockFn2 | ||
}); | ||
} catch { | ||
mockMethods.delete(prop); | ||
} | ||
} | ||
}); | ||
Object.defineProperty(target, mockMethodsKey, { | ||
value: mockMethods, | ||
enumerable: false, | ||
configurable: false | ||
}); | ||
metadata.set(target, { | ||
type: "object", | ||
original: target, | ||
options: otherOptions, | ||
inPlace: true, | ||
mockMethodsKey | ||
}); | ||
return target; | ||
} | ||
@@ -72,0 +134,0 @@ function mockClassState() { |
{ | ||
"name": "@corez/mock", | ||
"version": "0.13.4", | ||
"version": "0.14.0", | ||
"description": "A powerful and flexible TypeScript mocking library for testing", | ||
@@ -71,3 +71,3 @@ "keywords": [ | ||
"pretty-format": "29.7.0", | ||
"release-it": "^18.1.1", | ||
"release-it": "^18.1.2", | ||
"ts-jest": "^29.2.5", | ||
@@ -74,0 +74,0 @@ "tsup": "^8.3.5", |
@@ -6,6 +6,3 @@ import {mock} from './mock'; | ||
// Re-export all decorators and errors | ||
export * from './decorators'; | ||
// Default export | ||
export default mock; |
102
src/mock.ts
@@ -16,3 +16,2 @@ import micromatch from 'micromatch'; | ||
MockedObject, | ||
MockOptions, | ||
MockOptionsInput, | ||
@@ -107,6 +106,97 @@ MockProperty, | ||
const mock = Object.create(Object.getPrototypeOf(target)); | ||
defineMockProperties(mock, target, options); | ||
metadata.set(mock, {type: 'object', original: target, options}); | ||
return mock as MockedObject<T>; | ||
// Check if target is already mocked | ||
const existingMeta = metadata.get(target); | ||
if (existingMeta) { | ||
return target as MockedObject<T>; | ||
} | ||
// Normalize options | ||
const normalizedOptions = | ||
typeof options === 'function' || typeof options === 'string' || options instanceof RegExp || Array.isArray(options) | ||
? {keepOriginal: options} | ||
: options; | ||
const {inPlace = false, ...otherOptions} = normalizedOptions; | ||
// Clone mode: create new mock object | ||
if (!inPlace) { | ||
const mock = Object.create(Object.getPrototypeOf(target)); | ||
defineMockProperties(mock, target, otherOptions); | ||
metadata.set(mock, { | ||
type: 'object', | ||
original: target, | ||
options: otherOptions, | ||
inPlace: false, | ||
}); | ||
return mock as MockedObject<T>; | ||
} | ||
// InPlace mode: modify target object directly | ||
const mockMethodsKey = Symbol('mockMethods'); | ||
const mockMethods = new Map<string | symbol, MockedFunction>(); | ||
// Get all properties including those from prototype chain | ||
const props = new Set<string | symbol>(); | ||
let current = target; | ||
while (current && current !== Object.prototype) { | ||
Object.getOwnPropertyNames(current).forEach(prop => props.add(prop)); | ||
Object.getOwnPropertySymbols(current).forEach(prop => props.add(prop)); | ||
current = Object.getPrototypeOf(current); | ||
} | ||
// Create proxies for each method | ||
props.forEach(prop => { | ||
// Get descriptor from target or its prototype chain | ||
let current = target; | ||
let descriptor; | ||
while (current && !descriptor) { | ||
descriptor = Object.getOwnPropertyDescriptor(current, prop); | ||
current = Object.getPrototypeOf(current); | ||
} | ||
if (!descriptor) return; | ||
// Only mock functions | ||
if (typeof descriptor.value === 'function') { | ||
const keepArgs = {property: prop.toString(), descriptor, original: target, mock: target}; | ||
if (shouldKeepMockOriginal(keepArgs, otherOptions)) { | ||
return; | ||
} | ||
// Create mock function using provided spy creator or default | ||
const mockFn = otherOptions.createSpy?.() || mockFunction(); | ||
mockMethods.set(prop, mockFn); | ||
try { | ||
// Try to define property on target object | ||
Object.defineProperty(target, prop, { | ||
configurable: true, | ||
enumerable: descriptor.enumerable, | ||
writable: true, | ||
value: mockFn, | ||
}); | ||
} catch { | ||
// For non-configurable properties, keep original and remove from mockMethods | ||
mockMethods.delete(prop); | ||
} | ||
} | ||
}); | ||
// Store mock methods on target object | ||
Object.defineProperty(target, mockMethodsKey, { | ||
value: mockMethods, | ||
enumerable: false, | ||
configurable: false, | ||
}); | ||
// Store metadata | ||
metadata.set(target, { | ||
type: 'object', | ||
original: target, | ||
options: otherOptions, | ||
inPlace: true, | ||
mockMethodsKey, | ||
}); | ||
return target as MockedObject<T>; | ||
} | ||
@@ -440,3 +530,3 @@ | ||
overrides?: Partial<T>, | ||
options?: MockOptions, | ||
options?: MockOptionsInput, | ||
): T | MockedObject<T> { | ||
@@ -443,0 +533,0 @@ // Handle null/undefined |
@@ -59,7 +59,23 @@ import type {Faker} from '@faker-js/faker'; | ||
createSpy?: CreateSpy; | ||
/** | ||
* Whether to modify the target object directly instead of creating a clone | ||
*/ | ||
inPlace?: boolean; | ||
} | ||
export type MockOptions = KeepOriginalMatcher | MockConfigObject; | ||
/** | ||
* Mock options can be either a matcher pattern or a config object | ||
*/ | ||
export type MockOptionsInput = KeepOriginalMatcher | MockConfigObject; | ||
export type MockOptionsInput = MockConfigObject | KeepOriginalMatcher; | ||
/** | ||
* Metadata for mock tracking | ||
*/ | ||
export interface MockData<T = unknown> { | ||
type: 'function' | 'object' | 'class'; | ||
original: T; | ||
options: MockOptionsInput; | ||
inPlace?: boolean; | ||
mockMethodsKey?: symbol; | ||
} | ||
@@ -130,11 +146,2 @@ /** | ||
/** | ||
* Metadata for mock tracking | ||
*/ | ||
export interface MockData<T = unknown> { | ||
type: 'function' | 'object' | 'class'; | ||
original: T; | ||
options: MockOptionsInput; | ||
} | ||
/** | ||
* Core mock API | ||
@@ -141,0 +148,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
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
Sorry, the diff of this file is not supported yet
235753
2945