Used to recursively dynamically generate an object where the properties are jest.fn()
functions.
Behind the scenes it uses a JavaScript Proxy to detect if a property on the created object is being
accessed or being invoked. If it's being invoked it generates a jest.fn()
and uses that, if it's
being accessed it creates a new mock proxy. This allows for mocks to be generated for objects
dynamically and deeply.
import { DynamicMock } from 'jest-dynamic-mock';
const target = new DynamicMock();
// "baz" is automatically converted into a jest.fn() when it's called
target.baz('buzz');
console.log(target.baz.mock.calls[0][0] === 'buzz');
// "foo" is accessed as a property so it becomes another proxy
// "foo.bar" is invoked so it becomes a jest.fn()
target.foo.bar('foobar');
console.log(target.foo.bar.mock.calls[0][0] === 'foobar');
Normally this would be paired with a TypeScript interface
import { DynamicMock } from 'jest-dynamic-mock';
interface Foobar {
foo(): string;
bar(): string;
}
const target = new DynamicMock<Foobar>();
target.foo();
target.bar();
This is the expected usage in a jest test
// target.ts
export interface TestFuncOptions {
bar(): number;
foo: {
bar(): number;
};
}
export function targetFunc(options: TestFuncOptions) {
const a = options.bar();
const b = options.foo.bar();
return a + b;
}
// target.spec.ts
import { DynamicMock } from 'jest-dynamic-mock';
import { targetFunc, TestFuncOptions } from './target';
describe('targetFunc', () => {
let options: DynamicMock<TestFuncOptions>;
beforeEach(() => {
options = new DynamicMock();
});
it('Should call functions', async () => {
targetFunc(options);
expect(options.bar).toBeCalledTimes(1);
expect(options.foo.bar).toBeCalledTimes(1);
});
it('Should call functions', async () => {
options.bar.mockReturnValue(40);
options.foo.bar.mockReturnValue(2);
const result = targetFunc(options);
expect(result).toBe(42);
});
});