UNPKG

@hexancore/mocker

Version:

Simple and magical mocks for TypeScript, works with jest and vitest

130 lines (129 loc) 3.88 kB
"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;