@hexancore/mocker
Version:
Simple and magical mocks for TypeScript, works with jest and vitest
130 lines (129 loc) • 3.88 kB
JavaScript
"use strict";
/* eslint-disable @typescript-eslint/ban-types */
Object.defineProperty(exports, "__esModule", { value: true });
exports.mock = exports.Mocker = exports.MethodMock = void 0;
class MethodMock {
mock;
constructor(mock) {
this.mock = mock;
}
andReturnWith(implementation) {
this.mock.mockImplementationOnce(implementation);
}
andReturn(value) {
this.mock.mockReturnValueOnce(value);
}
andReturnThis() {
this.mock.mockReturnThis();
}
andReturnResolved(value) {
this.mock.mockResolvedValueOnce(value);
}
andReturnRejected(error) {
this.mock.mockRejectedValueOnce(error);
}
}
exports.MethodMock = MethodMock;
class Mocker {
name;
mock;
mockProxy;
methodCallExpections;
checkedExpections;
notExistingDynamicSet;
static __MockFnFactory = null;
constructor(name = 'mock') {
this.name = name;
this.mock = {};
this.mockProxy = this.createMockProxy();
this.methodCallExpections = [];
this.notExistingDynamicSet = new Set();
this.checkedExpections = false;
}
createMockProxy() {
// eslint-disable-next-line @typescript-eslint/no-this-alias
const m = this;
return new Proxy(this.mock, {
get: (target, prop) => {
if (m.notExistingDynamicSet.has(prop)) {
return undefined;
}
if (target[prop]) {
return target[prop];
}
return (...args) => {
let message = `expect(${m.name}.${prop}).not.toBeCalled`;
message += args.length > 0 ? `With(${args.join(', ')})` : '()';
const e = new Error(message);
const split = e.stack.split('\n');
e.stack = [split[0], split[2]].join('\n');
throw e;
};
},
});
}
static of(name = 'mock') {
return new Mocker(name);
}
/**
* @return Returns mock instance
*/
get i() {
return this.mockProxy;
}
allowsNotExistingDynamic(names) {
if (Array.isArray(names)) {
names.forEach((v) => this.notExistingDynamicSet.add(v));
}
else {
this.notExistingDynamicSet.add(names);
}
return this;
}
expects(name, ...args) {
const mockFunction = this.createMockFn(name);
this.methodCallExpections.push({ method: name, args });
return new MethodMock(mockFunction);
}
createMockFn(name) {
let mockFunction;
if (!this.mock[name]) {
mockFunction = this.mock[name] = Mocker.__MockFnFactory(this.name + '.' + name);
}
else {
mockFunction = this.mock[name];
}
return mockFunction;
}
reset() {
this.methodCallExpections = [];
for (const m in this.mock) {
this.mock[m].mockReset();
}
this.checkedExpections = false;
}
checkExpections(reset = false) {
if (this.checkedExpections) {
throw new Error(`Mock[${this.name}]: checking same expections second time(fix code or reset mock)`);
}
this.methodCallExpections.forEach((expection) => {
this.checkExpection(expection);
});
this.checkedExpections = true;
if (reset) {
this.reset();
}
}
checkExpection(expection) {
const callMatcher = expect(this.mock[expection.method]);
if (expection.args.length > 0) {
callMatcher.toBeCalledWith(...expection.args);
}
else {
callMatcher.toBeCalled();
}
}
}
exports.Mocker = Mocker;
const mock = (name = 'mock') => Mocker.of(name);
exports.mock = mock;