Skip to content

Commit

Permalink
Correct pass fallbackMockImplementation
Browse files Browse the repository at this point in the history
  • Loading branch information
skovhus committed Feb 27, 2023
1 parent 63c027b commit 02eb750
Show file tree
Hide file tree
Showing 2 changed files with 19 additions and 6 deletions.
17 changes: 12 additions & 5 deletions src/CalledWithFn.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,12 @@ function isJestAsymmetricMatcher(obj: any): obj is JestAsymmetricMatcher {
return !!obj && typeof obj === 'object' && 'asymmetricMatch' in obj && typeof obj.asymmetricMatch === 'function';
}

const checkCalledWith = <T, Y extends any[]>(calledWithStack: CalledWithStackItem<T, Y>[], actualArgs: Y): T => {
const calledWithInstance = calledWithStack.find(instance =>
const checkCalledWith = <T, Y extends any[]>(
calledWithStack: CalledWithStackItem<T, Y>[],
actualArgs: Y,
fallbackMockImplementation?: (...args: Y) => T
): T => {
const calledWithInstance = calledWithStack.find((instance) =>
instance.args.every((matcher, i) => {
if (matcher instanceof Matcher) {
return matcher.asymmetricMatch(actualArgs[i]);
Expand All @@ -29,7 +33,9 @@ const checkCalledWith = <T, Y extends any[]>(calledWithStack: CalledWithStackIte
);

// @ts-ignore cannot return undefined, but this will fail the test if there is an expectation which is what we want
return calledWithInstance ? calledWithInstance.calledWithFn(...actualArgs) : undefined;
return calledWithInstance
? calledWithInstance.calledWithFn(...actualArgs)
: fallbackMockImplementation && fallbackMockImplementation(...actualArgs);
};

export const calledWithFn = <T, Y extends any[]>({
Expand All @@ -42,9 +48,10 @@ export const calledWithFn = <T, Y extends any[]>({
// We create new function to delegate any interactions (mockReturnValue etc.) to for this set of args.
// If that set of args is matched, we just call that jest.fn() for the result.
const calledWithFn = jest.fn(fallbackMockImplementation);
if (!fn.getMockImplementation()) {
const mockImplementation = fn.getMockImplementation();
if (!mockImplementation || mockImplementation === fallbackMockImplementation) {
// Our original function gets a mock implementation which handles the matching
fn.mockImplementation((...args: Y) => checkCalledWith(calledWithStack, args));
fn.mockImplementation((...args: Y) => checkCalledWith(calledWithStack, args, fallbackMockImplementation));
calledWithStack = [];
}
calledWithStack.unshift({ args, calledWithFn });
Expand Down
8 changes: 7 additions & 1 deletion src/Mock.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -244,7 +244,7 @@ describe('jest-mock-extended', () => {
mockObj.getSomethingWithArgs.calledWith(1, 2).mockReturnValue(3);

expect(mockObj.getSomethingWithArgs(1, 2)).toBe(3);
})
});

test('Support jest matcher', () => {
const mockObj = mock<MockInt>();
Expand Down Expand Up @@ -328,7 +328,9 @@ describe('jest-mock-extended', () => {
throw new Error('not mocked');
},
});
mockObj.deepProp.getAnotherString.calledWith('foo'); // no mock implementation
expect(() => mockObj.getNumber()).toThrowError('not mocked');
expect(() => mockObj.deepProp.getAnotherString('foo')).toThrowError('not mocked');
});

test('fallback mock implementation can be overridden while also providing a mock implementation', () => {
Expand All @@ -344,8 +346,12 @@ describe('jest-mock-extended', () => {
},
}
);
mockObj.deepProp.getAnotherString.calledWith('?').mockReturnValue('mocked');
expect(mockObj.getNumber()).toBe(150);
expect(mockObj.deepProp.getAnotherString('?')).toBe('mocked');

expect(() => mockObj.deepProp.getNumber(1)).toThrowError('not mocked');
expect(() => mockObj.deepProp.getAnotherString('!')).toThrowError('not mocked');
});
});

Expand Down

0 comments on commit 02eb750

Please sign in to comment.