jest-mock-extended
Version:
Type safe mocking extensions for jest
142 lines (141 loc) • 5.12 kB
JavaScript
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.stub = exports.mockFn = exports.mockDeep = exports.mockReset = exports.mockClear = exports.JestMockExtended = void 0;
const CalledWithFn_1 = __importDefault(require("./CalledWithFn"));
const globals_1 = require("@jest/globals");
const DEFAULT_CONFIG = {
ignoreProps: ['then'],
};
let GLOBAL_CONFIG = DEFAULT_CONFIG;
exports.JestMockExtended = {
DEFAULT_CONFIG,
configure: (config) => {
// Shallow merge so they can override anything they want.
GLOBAL_CONFIG = Object.assign(Object.assign({}, DEFAULT_CONFIG), config);
},
resetConfig: () => {
GLOBAL_CONFIG = DEFAULT_CONFIG;
},
};
const mockClear = (mock) => {
for (let key of Object.keys(mock)) {
if (mock[key] === null || mock[key] === undefined) {
continue;
}
if (mock[key]._isMockObject) {
(0, exports.mockClear)(mock[key]);
}
if (mock[key]._isMockFunction) {
mock[key].mockClear();
}
}
// This is a catch for if they pass in a jest.fn()
if (!mock._isMockObject) {
return mock.mockClear();
}
};
exports.mockClear = mockClear;
const mockReset = (mock) => {
for (let key of Object.keys(mock)) {
if (mock[key] === null || mock[key] === undefined) {
continue;
}
if (mock[key]._isMockObject) {
(0, exports.mockReset)(mock[key]);
}
if (mock[key]._isMockFunction) {
mock[key].mockReset();
}
}
// This is a catch for if they pass in a jest.fn()
// Worst case, we will create a jest.fn() (since this is a proxy)
// below in the get and call mockReset on it
if (!mock._isMockObject) {
return mock.mockReset();
}
};
exports.mockReset = mockReset;
function mockDeep(arg1, arg2) {
const [opts, mockImplementation] = typeof arg1 === 'object' && (typeof arg1.fallbackMockImplementation === 'function' || arg1.funcPropSupport === true)
? [arg1, arg2]
: [{}, arg1];
return mock(mockImplementation, { deep: true, fallbackMockImplementation: opts.fallbackMockImplementation });
}
exports.mockDeep = mockDeep;
const overrideMockImp = (obj, opts) => {
const proxy = new Proxy(obj, handler(opts));
for (let name of Object.keys(obj)) {
if (typeof obj[name] === 'object' && obj[name] !== null) {
proxy[name] = overrideMockImp(obj[name], opts);
}
else {
proxy[name] = obj[name];
}
}
return proxy;
};
const handler = (opts) => ({
ownKeys(target) {
return Reflect.ownKeys(target);
},
set: (obj, property, value) => {
obj[property] = value;
return true;
},
get: (obj, property) => {
var _a;
let fn = (0, CalledWithFn_1.default)({ fallbackMockImplementation: opts === null || opts === void 0 ? void 0 : opts.fallbackMockImplementation });
if (!(property in obj)) {
if ((_a = GLOBAL_CONFIG.ignoreProps) === null || _a === void 0 ? void 0 : _a.includes(property)) {
return undefined;
}
// Jest's internal equality checking does some wierd stuff to check for iterable equality
if (property === Symbol.iterator) {
return obj[property];
}
// So this calls check here is totally not ideal - jest internally does a
// check to see if this is a spy - which we want to say no to, but blindly returning
// an proxy for calls results in the spy check returning true. This is another reason
// why deep is opt in.
if ((opts === null || opts === void 0 ? void 0 : opts.deep) && property !== 'calls') {
obj[property] = new Proxy(fn, handler(opts));
obj[property]._isMockObject = true;
}
else {
obj[property] = (0, CalledWithFn_1.default)({ fallbackMockImplementation: opts === null || opts === void 0 ? void 0 : opts.fallbackMockImplementation });
}
}
// @ts-expect-error
if (obj instanceof Date && typeof obj[property] === 'function') {
// @ts-expect-error
return obj[property].bind(obj);
}
return obj[property];
},
});
const mock = (mockImplementation = {}, opts) => {
// @ts-expect-error private
mockImplementation._isMockObject = true;
return overrideMockImp(mockImplementation, opts);
};
const mockFn = () => {
// @ts-expect-error
return (0, CalledWithFn_1.default)();
};
exports.mockFn = mockFn;
const stub = () => {
return new Proxy({}, {
get: (obj, property) => {
if (property in obj) {
// @ts-expect-error
return obj[property];
}
return globals_1.jest.fn();
},
});
};
exports.stub = stub;
exports.default = mock;
;