jest icon indicating copy to clipboard operation
jest copied to clipboard

[Feature]: Stubbing Classes

Open christoph-fricke opened this issue 3 years ago • 8 comments

🚀 Feature Proposal

I would like to complete the mocking/stubbing picture with an easy way to create a stub instance of an class.

This feature should be similar to Sinon's createStubInstance function. It should create an instance of an class (or from an object prototype) that has all methods and properties stubbed. Similar to jest.fn(), the created instance should enable assertions about calls to the instance's methods and should provide the ability to define the return-value/implementation of the stubbed methods.

Motivation

It is not always possible to stub a class by providing a mock for the containing module as it is suggested in the docs. For example, stubbing native web APIs, such as WebSocket or BroadcastChannel does not appear to work with the approach suggested in the documentation.

I have yet to find a good solution to create a stub instance of these classes when I want to test a function/class that expects an instance of these classes as an argument. In particular, spying on WebSocket methods would not be sufficient because the internal behavior of an instance should be removed, since it automatically tries to create a WebSocket connection.

An API similar to Sinon's [createStubInstance] would simplify tests when stub objects are required and would align them with tests that use jest.fn() to create stub callbacks.

Example

No response

Pitch

Such class stub has already been implemented by @asvetliakov^1 but the package does no longer appear to be maintained. As mentioned above, I think it would complete the picture around stubbing/mocking in Jest if an API similar to jest.fn() is available for classes/object-prototypes in the core.

christoph-fricke avatar Oct 25 '21 10:10 christoph-fricke

Since I opened this issue, I stumbled upon jest-mocked-extended, which works just as proposed and is actively developed.

christoph-fricke avatar Oct 26 '21 20:10 christoph-fricke

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

github-actions[bot] avatar Oct 26 '22 20:10 github-actions[bot]

Still relevant. Coming from the Ruby world where this was a standard, I’d love to have this feature.

ravicious avatar Oct 26 '22 21:10 ravicious

I recently ended up writing a util to use Jest's mocking tools to do this. Jest actually already has all the machinery we need, it's just a matter of exposing it in a convenient way rather than only via mocking entire modules. The advantage of using Jest's mocking instead of jest-mock-extended is that the API is completely consistent, mocks are automatically cleared by jest.clearAllMocks, and so on.

Specifically, the util I have takes a constructor and uses ModuleMocker.getMetadata and ModuleMocker.generateFromMetadata to build a mock for it, then calls the mock to create an instance of the class. Then you can pass that instance into code under tests, use mockImplementation and friends to customize the mock, and so on.

If this is something Jest would be interested in adding, I may be able to add it ~once my company signs the CLA~. The implementation is just a few lines, so it could also easily be rewritten if someone else gets there first.

benjaminjkraft avatar Jan 24 '23 23:01 benjaminjkraft

@benjaminjkraft even though jest-mock-extended is covering all of my concerns really well, I can relate to your argument about consistency. Would you be able to share that snippet of code here for future reference?

killthekitten avatar Aug 07 '23 12:08 killthekitten

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

github-actions[bot] avatar Aug 06 '24 13:08 github-actions[bot]

Still relevant I believe.

ravicious avatar Aug 06 '24 13:08 ravicious