diff --git a/docs/release-source/release/sandbox.md b/docs/release-source/release/sandbox.md index a67cd9185..f65ab15a8 100644 --- a/docs/release-source/release/sandbox.md +++ b/docs/release-source/release/sandbox.md @@ -131,6 +131,9 @@ A convenience reference for [`sinon.assert`](./assertions) Works exactly like `sinon.spy`, only also adds the returned spy to the internal collection of fakes for easy restoring through `sandbox.restore()` +#### `sandbox.createStubInstance();` + +Works almost exactly like `sinon.createStubInstance`, only also adds the returned stubs to the internal collection of fakes for easy restoring through `sandbox.restore()`. #### `sandbox.stub();` diff --git a/lib/sinon/collection.js b/lib/sinon/collection.js index 7a487a20c..1579f634a 100644 --- a/lib/sinon/collection.js +++ b/lib/sinon/collection.js @@ -86,6 +86,13 @@ var collection = { return this.add(sinonSpy.apply(sinonSpy, arguments)); }, + createStubInstance: function createStubInstance(constructor) { + if (typeof constructor !== "function") { + throw new TypeError("The constructor should be a function."); + } + return this.stub.call(this, Object.create(constructor.prototype)); + }, + stub: function stub(object, property) { if (object && typeof property !== "undefined" && !(property in object)) { diff --git a/package.json b/package.json index 68cc59e29..07731c69f 100644 --- a/package.json +++ b/package.json @@ -22,7 +22,7 @@ "test-webworker": "browserify --no-commondir --full-paths -p [ mocaccino -R spec --color ] test/webworker/webworker-support-assessment.js | phantomic --web-security false", "test": "run-s test-node test-headless test-webworker", "check-dependencies": "dependency-check package.json --unused --no-dev", - "build": "./build.js", + "build": "node ./build.js", "lint": "eslint .", "precommit": "lint-staged", "pretest-webworker": "npm run build", diff --git a/test/collection-test.js b/test/collection-test.js index 11c3f67f6..90eff9d2b 100644 --- a/test/collection-test.js +++ b/test/collection-test.js @@ -5,6 +5,7 @@ var sinonCollection = require("../lib/sinon/collection"); var sinonSpy = require("../lib/sinon/spy"); var sinonStub = require("../lib/sinon/stub"); var assert = referee.assert; +var refute = referee.refute; var deprecated = require("../lib/sinon/util/core/deprecated"); describe("collection", function () { @@ -18,6 +19,96 @@ describe("collection", function () { assert.isFunction(collection.mock); }); + describe(".createStubInstance", function () { + beforeEach(function () { + this.collection = Object.create(sinonCollection); + }); + + it("stubs existing methods", function () { + var Class = function () {}; + Class.prototype.method = function () {}; + + var stub = this.collection.createStubInstance(Class); + stub.method.returns(3); + assert.equals(3, stub.method()); + }); + + it("resets all stub methods on reset()", function () { + var Class = function () {}; + Class.prototype.method1 = function () {}; + Class.prototype.method2 = function () {}; + Class.prototype.method3 = function () {}; + + var stub = this.collection.createStubInstance(Class); + stub.method1.returns(1); + stub.method2.returns(2); + stub.method3.returns(3); + + assert.equals(3, stub.method3()); + + this.collection.reset(); + assert.equals(undefined, stub.method1()); + assert.equals(undefined, stub.method2()); + assert.equals(undefined, stub.method3()); + }); + + it("doesn't stub fake methods", function () { + var Class = function () {}; + + var stub = this.collection.createStubInstance(Class); + assert.exception(function () { + stub.method.returns(3); + }); + }); + + it("doesn't call the constructor", function () { + var Class = function (a, b) { + var c = a + b; + throw c; + }; + Class.prototype.method = function () {}; + + var stub = this.collection.createStubInstance(Class); + refute.exception(function () { + stub.method(3); + }); + }); + + it("retains non function values", function () { + var TYPE = "some-value"; + var Class = function () {}; + Class.prototype.type = TYPE; + + var stub = this.collection.createStubInstance(Class); + assert.equals(TYPE, stub.type); + }); + + it("has no side effects on the prototype", function () { + var proto = { + method: function () { + throw "error"; + } + }; + var Class = function () {}; + Class.prototype = proto; + + var stub = this.collection.createStubInstance(Class); + refute.exception(stub.method); + assert.exception(proto.method); + }); + + it("throws exception for non function params", function () { + var types = [{}, 3, "hi!"]; + + for (var i = 0; i < types.length; i++) { + // yes, it's silly to create functions in a loop, it's also a test + assert.exception(function () { // eslint-disable-line no-loop-func + this.collection.createStubInstance(types[i]); + }); + } + }); + }); + describe(".stub", function () { beforeEach(function () { this.collection = Object.create(sinonCollection);