[Feature]: Add a way to mock a function only for certain arguments (original) (raw)
🚀 Feature Proposal
The idea here is basically equivalent to the when helper provided in some third-party packages, but within Jest. It would work similarly to mockImplementation, but only apply for certain arguments (possibly expect matchers).
If there's interest in this, once my company signs the CLA I may be able to contribute an implementation.
Motivation
This seems to be a quite common need, given the several third-party packages and in my own experience. (See also the pitch below.)
Example
There are a few possible APIs, but the most likely one is similar to jest-mock-extended and jest-when.
// API: export interface MockInstance { mockWhen(...args: Parameters): MockInstance<ReturnType> }
// example:
const mockFn = jest.fn() // or a function/method from a class mocked by jest.mock, etc.
mockFn.mockWhen("hello", expect.anything()).mockReturnValue(3)
The method mockWhen would return a jest mock which is used only when the arguments match, but can be customized in all the usual ways.
Pitch
This is a feature that many test frameworks and tools across many languages seem to grow, which points to its utility!
There are a few alternatives to doing this in Jest, which all seem inferior:
- Use one of the existing third-party packages. The problem with the third-party
whenimplementations is that they don't use the normal Jest API; they instead provide their own which is a bit inconsistent, and there are several different packages people use which leads to fragmentation. Plus, implementing this within Jest could use the existing machinery and thus actually be a lot simpler, and could have the API be a method alongsidemockImplementation. - Mock the function for all return values, and then assert about the arguments with which it was called (either in the
mockImplementationor via.mock.calls). This is a bit more work, and often results in more fragile tests, since if other code executed in the test makes an unrelated call to the function, it will fail the test. (And if we already have several such calls, this method no longer works.) - Mock the function for all potential arguments (e.g. existing
mockReturnValue), and not bother asserting anything further; this leads to weaker tests as well as not allowing different results for different arguments. - Mock the function to have an implementation with conditionals (e.g.
if (arg === ...) return someValue; return otherValue); this is a lot more work in most simple cases -- arguably it's so much work no one will bother.