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鈥檒l occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Feature]: Replace property value in tests #13465

Closed
michal-kocarek opened this issue Oct 18, 2022 · 11 comments 路 Fixed by #13496
Closed

[Feature]: Replace property value in tests #13465

michal-kocarek opened this issue Oct 18, 2022 · 11 comments 路 Fixed by #13496

Comments

@michal-kocarek
Copy link
Contributor

michal-kocarek commented Oct 18, 2022

馃殌 Feature Proposal

It would be great to have interface to replace object's property value as part of Jest API.

Similar to Sinon's sandbox.replace(object, property, replacement);

Ref: https://sinonjs.org/releases/v14/sandbox/#sandboxreplaceobject-property-replacement

Motivation

Quite often there are parts of an object, we have to mock in tests. For example process.argv, process.env or some configuration settings coming out of whichever piece in codebase.

Usually we end up writing code like:

const oldProcessEnv = process.env;

beforeEach(() => process.env = {EXTRA_VAR: 'foo'});

afterEach(() => process.env = oldProcessEnv);

Problem is, that for trivial property replace, one needs to split it across multiple pieces, store old value and then properly return it. This might be cause for errors.

Example

// jest.mockProperty(<object>, <property>, <new value>);
jest.mockProperty(process, env, {EXTRA_VAR: 'foo'});

Property would be replaced back by calling jest.restoreAllMocks();

It is questionable, what should the mock return. If it should return something to intercept the calls and other stuff (probably yes, but I do not have opinion on that).

Pitch

Jest provides great and extensive way for mocking modules and methods. One piece, that is missing, is mocking individual properties for arbitrary object.

Of course, this is doable manually. However the biggest benefit of integrating this functionality to Jest API would be the integration into 'autoclean' feature that will simplify the boilerplate for individual property mocking, and thus making the code more error prone.

@SimenB
Copy link
Member

SimenB commented Oct 18, 2022

This seems reasonable to me.

It is questionable, what should the mock return.

Agreed. We currently return mock functions. I guess we could add a proxy and count accesses or something? that way it'd still be a "mock object" of sorts?


Would you be up for sending a PR? I cannot make any promises it'll land, but looking at code might make it easier to decide if this feature fits into Jest?

@michal-kocarek
Copy link
Contributor Author

Would you be up for sending a PR?

I can try something.


If you have any thoughts upfront, I'd appreciate them. I have been looking at the existing implementation of sandbox.replace(object, property, value) in Sinon.js, where the feature is write quite straightforward: https://github.com/sinonjs/sinon/blob/c4345dc1/lib/sinon/sandbox.js#L213-L280

@SimenB
Copy link
Member

SimenB commented Oct 18, 2022

You can start with playing around in jest-mock which is where the implementation would live

@koshic
Copy link

koshic commented Oct 18, 2022

It's better to name it with 'spyOn', because it's a bit different variation of spy, IMHO.

@michal-kocarek
Copy link
Contributor Author

michal-kocarek commented Oct 23, 2022

When you'll have time, you might take a look at draft PR #13496, which contains complete implementation of mockProperty() in jest-mock package.

I have been thinking about reusing same interface and allow spying property access. Then I discarded the idea (reasons below) and decided just to provide simple property value replacement.

Why I think, that spying on property access is not ideal idea:

  • As far as I am aware, we cannot spy on simple property access. We would need to replace it with getter, which would change the object shape, which might be quite fragile. (Or is there some way?)
  • I still see property replacement as sort of hack. Ideally, people should be mocking methods or modules. Classical use case (subjective thoughts) for this is to mock process.env, something deep in global configuration object, etc.
  • If someone is interested in checking whether property is accessed, maybe they should replace that specific piece with getter/or wrap the call in method. I think this is a bit different use case, as this one I understand more like mocking "global state" that is used by methods I am going to test.

I will be really interested in your thoughts if this is
a) meaningful as a contribution to Jest
b) any thoughts regarding the feature set or implementation.

Thank you a lot!

@michal-kocarek
Copy link
Contributor Author

michal-kocarek commented Oct 23, 2022

It's better to name it with 'spyOn', because it's a bit different variation of spy, IMHO.

I've opted for mockProperty() in the kick-off PR, as... as I wrote above, didn't find suitable way how to spy on property access. If there is such a way, I can implement it (then spyOnProperty could be good adept). But if the access cannot be spied without changing the object shape, I am not sure if spy* prefix wouldn't be misleading...

@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 Nov 22, 2022
@eps1lon
Copy link
Contributor

eps1lon commented Dec 8, 2022

Struggled with this scenario a lot and jest.spyOn(object, propertyKey, 'get').mockReturnValue(mockedValue) doesn't work if the property only has a value and no getter.

Would be great if we can move this forward. #13496 is still in draft though it looks ready for review to me?

@github-actions github-actions bot removed the Stale label Dec 8, 2022
@michal-kocarek
Copy link
Contributor Author

@eps1lon I've improved the PR, it's not draft anymore. I will be looking forward for your feedback.

@SimenB
Copy link
Member

SimenB commented Jan 24, 2023

@github-actions
Copy link

This issue has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.
Please note this issue tracker is not a help forum. We recommend using StackOverflow or our discord channel for questions.

@github-actions github-actions bot locked as resolved and limited conversation to collaborators Feb 24, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants