Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Feature]: Add a way to mock a function only for certain arguments #13811

Open
benjaminjkraft opened this issue Jan 24, 2023 · 14 comments
Open

Comments

@benjaminjkraft
Copy link
Contributor

benjaminjkraft commented Jan 24, 2023

🚀 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<T> {
  mockWhen(...args: Parameters<T>): MockInstance<ReturnType<T>>
}

// 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:

  1. Use one of the existing third-party packages. The problem with the third-party when implementations 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 alongside mockImplementation.
  2. Mock the function for all return values, and then assert about the arguments with which it was called (either in the mockImplementation or 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.)
  3. 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.
  4. 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.
@github-actions
Copy link

This issue is stale because it has been open 30 days with no activity. Remove stale label or comment or this will be closed in 30 days.

@github-actions github-actions bot added the Stale label Feb 27, 2023
@benjaminjkraft
Copy link
Contributor Author

still relevant, I may even have time to make a PR soon

@github-actions github-actions bot removed the Stale label Feb 27, 2023
@michalsnik
Copy link

Agree, this would be super useful. In terms of possible API I suggest looking at jest-mock-extended it implements proper typesafe mocks with support for stubbing matched calls and the API is very straightforward and easy to follow.

@github-actions
Copy link

This issue is stale because it has been open 30 days with no activity. Remove stale label or comment or this will be closed in 30 days.

@github-actions github-actions bot added the Stale label Apr 11, 2023
@michalsnik
Copy link

Still relevant

@github-actions
Copy link

This issue is stale because it has been open 30 days with no activity. Remove stale label or comment or this will be closed in 30 days.

@github-actions github-actions bot added the Stale label May 12, 2023
@benjaminjkraft
Copy link
Contributor Author

Still active! I have a PR up but need to rethink some details around withImplementation, as well as a few other comments. I'll hopefully have more time in the next few weeks.

@github-actions github-actions bot removed the Stale label May 12, 2023
@github-actions
Copy link

This issue is stale because it has been open 30 days with no activity. Remove stale label or comment or this will be closed in 30 days.

@github-actions github-actions bot added the Stale label Jun 11, 2023
@benjaminjkraft
Copy link
Contributor Author

Still working on this! I haven't had time to get back to the issues above but hope to Soon™.

@github-actions github-actions bot removed the Stale label Jun 26, 2023
@AlexMcConnell
Copy link

I stumbled across this searching for something else, and... wow, I can't believe that jest mocking lacks this basic, essential feature.

@github-actions
Copy link

This issue is stale because it has been open 30 days with no activity. Remove stale label or comment or this will be closed in 30 days.

@github-actions github-actions bot added the Stale label Aug 11, 2023
@benjaminjkraft
Copy link
Contributor Author

still haven't had a chance to get back to this, still intend to though!

@github-actions github-actions bot removed the Stale label Aug 29, 2023
@github-actions
Copy link

This issue is stale because it has been open 30 days with no activity. Remove stale label or comment or this will be closed in 30 days.

@github-actions github-actions bot added the Stale label Sep 28, 2023
@SimenB SimenB added Pinned and removed Stale labels Sep 28, 2023
@landon912
Copy link

This is a pretty annoying gap in jest. It forces you to lean towards building unit tests based on implementation details rather than behavior. Would be great to get more traction on this

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants