Skip to content

Commit fe799e7

Browse files
authoredAug 11, 2023
Fix issue 2534: spies are not restored (#2535)
* Document the custom property descriptor type used in Sinon * Fix issue #2534 * prettify
1 parent 305fb6c commit fe799e7

File tree

4 files changed

+80
-5
lines changed

4 files changed

+80
-5
lines changed
 

‎lib/sinon/sandbox.js

+7-2
Original file line numberDiff line numberDiff line change
@@ -218,6 +218,7 @@ function Sandbox() {
218218
delete object[property];
219219
}
220220
}
221+
221222
restorer.object = object;
222223
restorer.property = property;
223224
return restorer;
@@ -355,8 +356,7 @@ function Sandbox() {
355356
};
356357

357358
function commonPostInitSetup(args, spy) {
358-
const object = args[0];
359-
const property = args[1];
359+
const [object, property, types] = args;
360360

361361
const isSpyingOnEntireObject =
362362
typeof property === "undefined" && typeof object === "object";
@@ -369,6 +369,11 @@ function Sandbox() {
369369
});
370370

371371
usePromiseLibrary(promiseLib, ownMethods);
372+
} else if (Array.isArray(types)) {
373+
for (const accessorType of types) {
374+
addToCollection(spy[accessorType]);
375+
usePromiseLibrary(promiseLib, spy[accessorType]);
376+
}
372377
} else {
373378
addToCollection(spy);
374379
usePromiseLibrary(promiseLib, spy);

‎lib/sinon/util/core/get-property-descriptor.js

+26-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,28 @@
11
"use strict";
22

3-
module.exports = function getPropertyDescriptor(object, property) {
3+
/* eslint-disable jsdoc/valid-types */
4+
/*
5+
* The following type def is strictly an illegal JSDoc, but the expression forms a
6+
* legal Typescript union type and is understood by Visual Studio and the IntelliJ
7+
* family of editors. The "TS" flavor of JSDoc is becoming the de-facto standard these
8+
* days for that reason (and the fact that JSDoc is essentially unmaintained)
9+
*/
10+
11+
/**
12+
* @typedef {{isOwn: boolean} & PropertyDescriptor} SinonPropertyDescriptor
13+
* a slightly enriched property descriptor
14+
* @property {boolean} isOwn true if the descriptor is owned by this object, false if it comes from the prototype
15+
*/
16+
/* eslint-enable jsdoc/valid-types */
17+
18+
/**
19+
* Returns a slightly modified property descriptor that one can tell is from the object or the prototype
20+
*
21+
* @param {*} object
22+
* @param {string} property
23+
* @returns {SinonPropertyDescriptor}
24+
*/
25+
function getPropertyDescriptor(object, property) {
426
let proto = object;
527
let descriptor;
628
const isOwn = Boolean(
@@ -19,4 +41,6 @@ module.exports = function getPropertyDescriptor(object, property) {
1941
}
2042

2143
return descriptor;
22-
};
44+
}
45+
46+
module.exports = getPropertyDescriptor;

‎test/issues/issues-test.js

+15
Original file line numberDiff line numberDiff line change
@@ -899,4 +899,19 @@ describe("issues", function () {
899899
this.sandbox.restore();
900900
});
901901
});
902+
903+
it("#2534 - spies on accessors are not being cleaned up", function () {
904+
const object = {
905+
get prop() {
906+
return "bar";
907+
},
908+
};
909+
const spy = sinon.spy(object, "prop", ["get"]);
910+
/* eslint-disable no-unused-expressions */
911+
object.prop;
912+
assert.equals(spy.get.callCount, 1);
913+
sinon.restore();
914+
object.prop;
915+
assert.equals(spy.get.callCount, 1); // should remain unchanged
916+
});
902917
});

‎test/sandbox-test.js

+32-1
Original file line numberDiff line numberDiff line change
@@ -2205,7 +2205,7 @@ describe("Sandbox", function () {
22052205
assert.equals(object.prop, "blabla");
22062206
});
22072207

2208-
it("allows restoring setters", function () {
2208+
it("allows putting setters on fields and subsequently restoring them", function () {
22092209
const object = {
22102210
prop: "bar",
22112211
};
@@ -2221,6 +2221,37 @@ describe("Sandbox", function () {
22212221

22222222
assert.equals(object.prop, "bla");
22232223
});
2224+
2225+
it("allows replacing setters on fields and subsequently restoring them", function () {
2226+
const object = {
2227+
get prop() {
2228+
return "bar";
2229+
},
2230+
};
2231+
2232+
const sandbox = new Sandbox();
2233+
const getter = sandbox.spy(() => "foobar");
2234+
sandbox.stub(object, "prop").get(getter);
2235+
assert.equals(object.prop, "foobar");
2236+
assert.equals(getter.callCount, 1);
2237+
2238+
sandbox.restore();
2239+
assert.equals(object.prop, "bar");
2240+
});
2241+
2242+
it("allows spying on accessors and subsequently restoring them", function () {
2243+
const object = {
2244+
get prop() {
2245+
return "bar";
2246+
},
2247+
};
2248+
const sandbox = new Sandbox();
2249+
const spy = sandbox.spy(object, "prop", ["get"]);
2250+
sandbox.restore();
2251+
const descriptor = Object.getOwnPropertyDescriptor(object, "prop");
2252+
const getter = descriptor.get;
2253+
refute.equals(getter, spy.get);
2254+
});
22242255
});
22252256

22262257
describe(".assert", function () {

0 commit comments

Comments
 (0)
Please sign in to comment.