Skip to content

Commit

Permalink
Merge pull request #1297 from lucasfcosta/getters-setters-new-api
Browse files Browse the repository at this point in the history
Add getters/setters stub behaviors new API
  • Loading branch information
fatso83 authored Mar 13, 2017
2 parents 1bda7c4 + ad58467 commit fee959d
Show file tree
Hide file tree
Showing 4 changed files with 265 additions and 25 deletions.
35 changes: 35 additions & 0 deletions docs/release-source/release/stubs.md
Original file line number Diff line number Diff line change
Expand Up @@ -448,3 +448,38 @@ var stub = sinon.stub().returnsNum(42);

assert.equals(stub(), 42);
```

#### `stub.get(getterFn)`

Replaces a new getter for this stub.

```javascript
var myObj = {
prop: 'foo'
};

createStub(myObj, 'prop').get(function getterFn() {
return 'bar';
});

myObj.example; // 'bar'
```

#### `stub.set(setterFn)`

Defines a new setter for this stub.

```javascript
var myObj = {
example: 'oldValue',
prop: 'foo'
};

createStub(myObj, 'prop').set(function setterFn(val) {
myObj.example = val;
});

myObj.prop = 'baz';

myObj.example; // 'baz'
```
20 changes: 20 additions & 0 deletions lib/sinon/default-behaviors.js
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,26 @@ module.exports = {

callThrough: function callThrough(fake) {
fake.callsThrough = true;
},

get: function get(fake, getterFunction) {
var rootStub = fake.stub || fake;

Object.defineProperty(rootStub.rootObj, rootStub.propName, {
get: getterFunction
});

return fake;
},

set: function set(fake, setterFunction) {
var rootStub = fake.stub || fake;

Object.defineProperty(rootStub.rootObj, rootStub.propName, { // eslint-disable-line accessor-pairs
set: setterFunction
});

return fake;
}
};

Expand Down
25 changes: 20 additions & 5 deletions lib/sinon/stub.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ var behaviors = require("./default-behaviors");
var spy = require("./spy");
var extend = require("./util/core/extend");
var functionToString = require("./util/core/function-to-string");
var getPropertyDescriptor = require("./util/core/get-property-descriptor");
var wrapMethod = require("./util/core/wrap-method");
var stubEntireObject = require("./stub-entire-object");
var stubDescriptor = require("./stub-descriptor");
Expand All @@ -13,27 +14,41 @@ var throwOnFalsyObject = require("./throw-on-falsy-object");
function stub(object, property, descriptor) {
throwOnFalsyObject.apply(null, arguments);

var actualDescriptor = getPropertyDescriptor(object, property);
var isStubbingEntireObject = typeof property === "undefined" && typeof object === "object";
var isCreatingNewStub = !object && typeof property === "undefined";
var isStubbingDescriptor = object && property && Boolean(descriptor);
var isStubbingNonFuncProperty = typeof object === "object"
&& typeof property !== "undefined"
&& (typeof actualDescriptor === "undefined"
|| typeof actualDescriptor.value !== "function")
&& typeof descriptor === "undefined";
var isStubbingExistingMethod = !isStubbingDescriptor
&& typeof object === "object"
&& typeof object[property] === "function";
&& typeof actualDescriptor !== "undefined"
&& typeof actualDescriptor.value === "function";
var arity = isStubbingExistingMethod ? object[property].length : 0;

if (isStubbingEntireObject) {
return stubEntireObject(stub, object);
}

if (isStubbingDescriptor) {
return stubDescriptor.apply(null, arguments);
}

if (isCreatingNewStub) {
return stub.create();
}

if (isStubbingDescriptor) {
return stubDescriptor.apply(null, arguments);
}
var s = stub.create(arity);
s.rootObj = object;
s.propName = property;
s.restore = function restore() {
Object.defineProperty(object, property, actualDescriptor);
};

return wrapMethod(object, property, stub.create(arity));
return isStubbingNonFuncProperty ? s : wrapMethod(object, property, s);
}

stub.createStubInstance = function (constructor) {
Expand Down
210 changes: 190 additions & 20 deletions test/stub-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -800,16 +800,6 @@ describe("stub", function () {
assert.isFalse(stub.called);
});

it("throws if property is not a function", function () {
var obj = { someProp: 42 };

assert.exception(function () {
createStub(obj, "someProp");
});

assert.equals(obj.someProp, 42);
});

it("successfully stubs falsey properties", function () {
var obj = { 0: function () { } };

Expand Down Expand Up @@ -943,16 +933,6 @@ describe("stub", function () {
});

describe("stubbed function", function () {
it("throws if stubbing non-existent property", function () {
var myObj = {};

assert.exception(function () {
createStub(myObj, "ouch");
});

refute.defined(myObj.ouch);
});

it("has toString method", function () {
var obj = { meth: function () {} };
createStub(obj, "meth");
Expand Down Expand Up @@ -2301,4 +2281,194 @@ describe("stub", function () {
assert.equals(reference, myObj);
});
});

describe(".get", function () {
it("allows users to stub getter functions for properties", function () {
var myObj = {
prop: "foo"
};

createStub(myObj, "prop").get(function getterFn() {
return "bar";
});

assert.equals(myObj.prop, "bar");
});

it("allows users to stub getter functions for functions", function () {
var myObj = {
prop: function propGetter() {
return "foo";
}
};

createStub(myObj, "prop").get(function getterFn() {
return "bar";
});

assert.equals(myObj.prop, "bar");
});

it("replaces old getters", function () {
var myObj = {
get prop() {
fail("should not call the old getter");
}
};

createStub(myObj, "prop").get(function getterFn() {
return "bar";
});

assert.equals(myObj.prop, "bar");
});

it("can set getters for non-existing properties", function () {
var myObj = {};

createStub(myObj, "prop").get(function getterFn() {
return "bar";
});

assert.equals(myObj.prop, "bar");
});

it("can restore stubbed setters for functions", function () {
var propFn = function propFn() {
return "bar";
};

var myObj = {
prop: propFn
};

var stub = createStub(myObj, "prop");

stub.get(function getterFn() {
return "baz";
});

stub.restore();

assert.equals(myObj.prop, propFn);
});

it("can restore stubbed getters for properties", function () {
var myObj = {
get prop() {
return "bar";
}
};

var stub = createStub(myObj, "prop");

stub.get(function getterFn() {
return "baz";
});

stub.restore();

assert.equals(myObj.prop, "bar");
});
});

describe(".set", function () {
it("allows users to stub setter functions for properties", function () {
var myObj = {
prop: "foo"
};

createStub(myObj, "prop").set(function setterFn() {
myObj.example = "bar";
});

myObj.prop = "baz";

assert.equals(myObj.example, "bar");
});

it("allows users to stub setter functions for functions", function () {
var myObj = {
prop: function propSetter() {
return "foo";
}
};

createStub(myObj, "prop").set(function setterFn() {
myObj.example = "bar";
});

myObj.prop = "baz";

assert.equals(myObj.example, "bar");
});

it("replaces old setters", function () {
var myObj = { // eslint-disable-line accessor-pairs
set prop(val) {
fail("should not call the old setter");
}
};

createStub(myObj, "prop").set(function setterFn() {
myObj.example = "bar";
});

myObj.prop = "foo";

assert.equals(myObj.example, "bar");
});

it("can set setters for non-existing properties", function () {
var myObj = {};

createStub(myObj, "prop").set(function setterFn() {
myObj.example = "bar";
});

myObj.prop = "foo";

assert.equals(myObj.example, "bar");
});

it("can restore stubbed setters for functions", function () {
var propFn = function propFn() {
return "bar";
};

var myObj = {
prop: propFn
};

var stub = createStub(myObj, "prop");

stub.set(function setterFn() {
myObj.otherProp = "baz";
});

stub.restore();

assert.equals(myObj.prop, propFn);
});

it("can restore stubbed setters for properties", function () {
var myObj = { // eslint-disable-line accessor-pairs
set prop(val) {
this.otherProp = "bar";
return "bar";
}
};

var stub = createStub(myObj, "prop");

stub.set(function setterFn() {
myObj.otherProp = "baz";
});

stub.restore();

myObj.prop = "foo";
assert.equals(myObj.otherProp, "bar");
});
});
});

0 comments on commit fee959d

Please sign in to comment.