-
-
Notifications
You must be signed in to change notification settings - Fork 769
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
Sandbox throws error 'cannot stub non-existent own property' #1537
Comments
Related to #1512. |
If the property doesn't exist you don't need to add it to the sandbox. Simply overwrite it. But yeah, if it worked before, and we haven't explicitly said it should change, then it's a regression. Not sure what we should do here. Update the docs to say stubbing non-existing values doesn't make sense and is unsupported, or make it possible? |
* sandbox.stub(obj, 'meth', val) * sinon.stub(obj, 'meth', fn) * sinon/util/core
The nice thing about adding the property to the sandbox is that sinon then helps me keep my global test environment clean between each test via Also I just noticed that I committed the sin of not providing a complete example. My sandbox is being created with 2.4.1 format:
Not sure if that's important; apologies for not providing it sooner. |
I think that in the scenarios like the one @ZebraFlesh describes, I would prefer to have the text fixture be more explicit. // not so explicit, doesn't work with [email protected]
beforeEach(function() {
const spy = sandbox.spy();
sandbox.stub(window, 'google').value({
maps: {
LatLng: x => x,
Map: spy
}
});
}); // more explicit, works with sinon@2, sinon@3
function setGoogleMapsFixture(sandbox) {
window.google = {
maps: {
LatLng: x => x,
Map: sandbox.spy()
}
};
}
function removeGoogleMapsFixture() {
delete window.google;
}
beforeEach(function() {
setGoogleMapsFixture(sandbox)
});
// not using afterEach, as this only needs to happen
// after the last test in this block is run
after(function() {
removeGoogleMapsFixture();
}); With more explicit setting of the fixture like outlined above, you don't need a feature in Sinon that would allow stubbing of non-existing own properties.
While I recognise that it might be convenient in some scenarios (like the one described by @ZebraFlesh), I think that stubbing non-existing own properties is likely to lead to mistakes in tests, where the test passes because the author mistyped the name of the existing property they were aiming to stub. We should aim to eliminate the possibility of mistakes where we can without being too restrictive. I think stubbing non-existing own properties should remain unsupported. We should update the documentation. |
@mroderick I concur with you in that it might make for less bugs, but we already support this for normal stubs. If we should stop supporting this behavior, we need to remove it there as well, to be consistent. It would be strange to only support this feature outside of sandboxes, as sandboxes usually add some possibilities. And removing the support is a breaking feature, so a major bump would be required as well. So either:
or/and(?)
|
I think that works well if your fixture never varies among your tests. However, my fixture does. A simple example is covering both success and failure cases:
The behavior in 2.x has the advantage of everything being properly cleaned up after each test via To solve the problem of introducing potential mistakes by inadvertently typing the name of an existing own property, sinon could modify the public API:
The API becomes more explicit and the consumer is forced to choose the appropriate tool for the task at hand. |
This is very much related to the discussion in #1508 (although it deals with normal stubs)h, where @lucasfcosta has the opposing view - that we should not throw for Right now, the situation is:
So for a while we had feature parity, but then we lost it again ... I don't think this zig-zagging is very beneficial for the users, so we should land this discussion. While I do agree with Morgan in that it might make for more specific tests, I don't like dropping a behavior for two major releases, then re-adding it again. I think it would make the least noise (fixes for clients, questions/issues on this tracker) just to revert this regression. |
While I understand the inconvenience, it seems like there's an easy workaround with minimal code changes. before(function() {
window.google = 'This is a placeholder for sinon to overwrite.';
});
after(function() {
delete window.google;
}); This allows the sinon code to stay unchanged. Regression vs poor documentationThis appears to be expected behavior since there are tests for it. We should update the docs to reflect that in my opinion. It came in a major so breaking changes are tolerated. |
@fearphage Keeping the status quo means stubbing non-existing fields is unsupported behavior for sandboxes, while it is supported behavior for normal stubs. Isn't a bit unfortunate that the two feature sets don't align? |
This was a longer discussion that can be found in the issues sinonjs#1508, sinonjs#1552 and sinonjs#1537 - and internally amongst the core team. Support for stubbing props using get()/set() was added in sinonjs#1237 and also worked for undefined properties. This type of behavior (stubbing undefined props) has been explicitly disabled for sandboxes, so in order for Sinon to behave in a consistent way, we should do the same here. This change will bring normal stubs back to how it has used to be historically, and will make sandbox stubs and normal sinon stubs behave the same. It might break things for people relying on the behavior that has been present since Sinon 2.0, but it should make things more reliable going forward.
This was a longer discussion that can be found in the issues sinonjs#1508, sinonjs#1552 and sinonjs#1537 - and internally amongst the core team. Support for stubbing props using get()/set() was added in sinonjs#1237 and also worked for undefined properties. This type of behavior (stubbing undefined props) has been explicitly disabled for sandboxes, so in order for Sinon to behave in a consistent way, we should do the same here. This change will bring normal stubs back to how it has used to be historically, and will make sandbox stubs and normal sinon stubs behave the same. It might break things for people relying on the behavior that has been present since Sinon 2.0, but it should make things more reliable going forward.
This was a longer discussion that can be found in the issues #1508, #1552 and #1537 - and internally amongst the core team. Support for stubbing props using get()/set() was added in #1237 and also worked for undefined properties. This type of behavior (stubbing undefined props) has been explicitly disabled for sandboxes, so in order for Sinon to behave in a consistent way, we should do the same here. This change will bring normal stubs back to how it has used to be historically, and will make sandbox stubs and normal sinon stubs behave the same. It might break things for people relying on the behavior that has been present since Sinon 2.0, but it should make things more reliable going forward.
Resolution was implemented in #1557 |
I've read the various threads and I can see why this happened, but it's a real pain in Typescript where you've often got functions that are implemented on a class prototype, in which case sinon spits the dummy even though everything looks fine type wise (since I get that Typescript probably isn't a priority for you guys, but even in JS it seems counter intuitive that I really think this is an important use case to make a happy path for, considering classes are getting more native support in JS. |
If you get an error saying that the method is undefined on the object, you know the error is probably up the prototype. Then directly modifing the object using |
Yeah, I guess it's not overly difficult to work around, it's just putting more cognitive load on me to be aware of how things are implemented. It also just seems unexpected, so that I felt the need to add a comment in the test to explain why the stubbing code on 2 consecutive lines for the same object was different, and why I was manually deleting one of the stubs in my teardown, but the other was handled by the sandbox. |
Wanted to add a use case that supports stubbing nonexistint properties. In my use case, I'm stubbing a property on a config object. The config object has various optional keys, and is initialized by loading a file from the developer's machine. When I run a particular test, I need one of those keys set to a known value, and then want to restore the developer's object as it was.
|
This was a longer discussion that can be found in the issues sinonjs#1508, sinonjs#1552 and sinonjs#1537 - and internally amongst the core team. Support for stubbing props using get()/set() was added in sinonjs#1237 and also worked for undefined properties. This type of behavior (stubbing undefined props) has been explicitly disabled for sandboxes, so in order for Sinon to behave in a consistent way, we should do the same here. This change will bring normal stubs back to how it has used to be historically, and will make sandbox stubs and normal sinon stubs behave the same. It might break things for people relying on the behavior that has been present since Sinon 2.0, but it should make things more reliable going forward.
I just tried upgrading from 2.4.1 to 3.2.1 and encountered the following issue. This code works in 2.4.1:
But in 3.2.1 it throws an exception:
TypeError: Cannot stub non-existent own property google
It's not mentioned in the migration guide so it appears to be a regression.
The text was updated successfully, but these errors were encountered: