diff --git a/lib/sinon.js b/lib/sinon.js index 695a11301..8381a70b0 100644 --- a/lib/sinon.js +++ b/lib/sinon.js @@ -1,15 +1,16 @@ "use strict"; exports.assert = require("./sinon/assert"); -exports.collection = require("./sinon/collection"); exports.match = require("./sinon/match"); exports.spy = require("./sinon/spy"); exports.spyCall = require("./sinon/call"); exports.stub = require("./sinon/stub"); exports.mock = require("./sinon/mock"); -var sandbox = require("./sinon/sandbox"); -exports.sandbox = sandbox; +var Sandbox = require("./sinon/sandbox"); +exports.sandbox = new Sandbox(); +exports.createSandbox = require("./sinon/create-sandbox"); + exports.expectation = require("./sinon/mock-expectation"); exports.createStubInstance = require("./sinon/stub").createStubInstance; @@ -28,7 +29,6 @@ exports.useFakeXMLHttpRequest = nise.fakeXhr.useFakeXMLHttpRequest; exports.fakeServer = nise.fakeServer; exports.fakeServerWithClock = nise.fakeServerWithClock; -exports.createSandbox = sandbox.create; exports.createFakeServer = nise.fakeServer.create.bind(nise.fakeServer); exports.createFakeServerWithClock = nise.fakeServerWithClock.create.bind(nise.fakeServerWithClock); diff --git a/lib/sinon/collection.js b/lib/sinon/collection.js deleted file mode 100644 index 85a88c189..000000000 --- a/lib/sinon/collection.js +++ /dev/null @@ -1,161 +0,0 @@ -"use strict"; - -var sinonSpy = require("./spy"); -var sinonStub = require("./stub"); -var sinonMock = require("./mock"); -var collectOwnMethods = require("./collect-own-methods"); -var valueToString = require("./util/core/value-to-string"); - -var push = Array.prototype.push; -var filter = Array.prototype.filter; - -function getFakes(fakeCollection) { - if (!fakeCollection.fakes) { - fakeCollection.fakes = []; - } - - return fakeCollection.fakes; -} - -function each(fakeCollection, method) { - var fakes = getFakes(fakeCollection); - var matchingFakes = filter.call(fakes, function (fake) { - return typeof fake[method] === "function"; - }); - - matchingFakes.forEach(function (fake) { - fake[method](); - }); -} - -var collection = { - verify: function verify() { - each(this, "verify"); - }, - - restore: function restore() { - each(this, "restore"); - this.fakes = []; - }, - - reset: function reset() { - each(this, "reset"); - }, - - resetBehavior: function resetBehavior() { - each(this, "resetBehavior"); - }, - - resetHistory: function resetHistory() { - function privateResetHistory(f) { - var method = f.resetHistory || f.reset; - if (method) { - method.call(f); - } - } - - getFakes(this).forEach(function (fake) { - if (typeof fake === "function") { - privateResetHistory(fake); - return; - } - - var methods = []; - if (fake.get) { - methods.push(fake.get); - } - - if (fake.set) { - methods.push(fake.set); - } - - methods.forEach(privateResetHistory); - }); - }, - - verifyAndRestore: function verifyAndRestore() { - var exception; - - try { - this.verify(); - } catch (e) { - exception = e; - } - - this.restore(); - - if (exception) { - throw exception; - } - }, - - add: function add(fake) { - push.call(getFakes(this), fake); - return fake; - }, - - addUsingPromise: function (fake) { - fake.usingPromise(this.promiseLibrary); - return fake; - }, - - spy: function spy() { - 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)) { - throw new TypeError("Cannot stub non-existent own property " + valueToString(property)); - } - - var stubbed = sinonStub.apply(null, arguments); - var isStubbingEntireObject = typeof property === "undefined" && typeof object === "object"; - - if (isStubbingEntireObject) { - var ownMethods = collectOwnMethods(stubbed); - ownMethods.forEach(this.add.bind(this)); - if (this.promiseLibrary) { - ownMethods.forEach(this.addUsingPromise.bind(this)); - } - } else { - this.add(stubbed); - if (this.promiseLibrary) { - stubbed.usingPromise(this.promiseLibrary); - } - } - - return stubbed; - }, - - mock: function mock() { - return this.add(sinonMock.apply(null, arguments)); - }, - - inject: function inject(obj) { - var col = this; - - obj.spy = function () { - return col.spy.apply(col, arguments); - }; - - obj.stub = function () { - return col.stub.apply(col, arguments); - }; - - obj.mock = function () { - return col.mock.apply(col, arguments); - }; - - return obj; - } -}; - -module.exports = collection; diff --git a/lib/sinon/create-sandbox.js b/lib/sinon/create-sandbox.js new file mode 100644 index 000000000..8ae94eb01 --- /dev/null +++ b/lib/sinon/create-sandbox.js @@ -0,0 +1,64 @@ +"use strict"; + +var Sandbox = require("./sandbox"); +var push = [].push; + +function prepareSandboxFromConfig(config) { + var sandbox = new Sandbox(); + + if (config.useFakeServer) { + if (typeof config.useFakeServer === "object") { + sandbox.serverPrototype = config.useFakeServer; + } + + sandbox.useFakeServer(); + } + + if (config.useFakeTimers) { + if (typeof config.useFakeTimers === "object") { + sandbox.useFakeTimers.call(sandbox, config.useFakeTimers); + } else { + sandbox.useFakeTimers(); + } + } + + return sandbox; +} + +function exposeValue(sandbox, config, key, value) { + if (!value) { + return; + } + + if (config.injectInto && !(key in config.injectInto)) { + config.injectInto[key] = value; + sandbox.injectedKeys.push(key); + } else { + push.call(sandbox.args, value); + } +} + +function createSandbox(config) { + if (!config) { + return new Sandbox(); + } + + var configuredSandbox = prepareSandboxFromConfig(config); + configuredSandbox.args = configuredSandbox.args || []; + configuredSandbox.injectedKeys = []; + configuredSandbox.injectInto = config.injectInto; + var exposed = configuredSandbox.inject({}); + + if (config.properties) { + config.properties.forEach(function (prop) { + var value = exposed[prop] || prop === "sandbox" && configuredSandbox; + exposeValue(configuredSandbox, config, prop, value); + }); + } else { + exposeValue(configuredSandbox, config, "sandbox"); + } + + return configuredSandbox; +} + +module.exports = createSandbox; diff --git a/lib/sinon/sandbox.js b/lib/sinon/sandbox.js index 9f0a7aa5b..14b4111a2 100644 --- a/lib/sinon/sandbox.js +++ b/lib/sinon/sandbox.js @@ -1,113 +1,135 @@ "use strict"; -var extend = require("./util/core/extend"); -var sinonCollection = require("./collection"); +var collectOwnMethods = require("./collect-own-methods"); var sinonMatch = require("./match"); var sinonAssert = require("./assert"); var sinonClock = require("./util/fake_timers"); +var sinonMock = require("./mock"); +var sinonSpy = require("./spy"); +var sinonStub = require("./stub"); +var valueToString = require("./util/core/value-to-string"); var fakeServer = require("nise").fakeServer; var fakeXhr = require("nise").fakeXhr; +var usePromiseLibrary = require("./util/core/use-promise-library"); -var push = [].push; +// cache original versions, to prevent issues when they are stubbed in user space +var push = Array.prototype.push; +var filter = Array.prototype.filter; +var forEach = Array.prototype.filter; -var sinonSandbox = Object.create(sinonCollection); +function applyOnEach(fakes, method) { + var matchingFakes = filter.call(fakes, function (fake) { + return typeof fake[method] === "function"; + }); -function exposeValue(sandbox, config, key, value) { - if (!value) { - return; - } - - if (config.injectInto && !(key in config.injectInto)) { - config.injectInto[key] = value; - sandbox.injectedKeys.push(key); - } else { - push.call(sandbox.args, value); - } + forEach.call(matchingFakes, function (fake) { + fake[method](); + }); } -function prepareSandboxFromConfig(config) { - var sandbox = Object.create(sinonSandbox); +function Sandbox() { + var sandbox = this; + var collection = []; + var promiseLib; - if (config.useFakeServer) { - if (typeof config.useFakeServer === "object") { - sandbox.serverPrototype = config.useFakeServer; - } + sandbox.serverPrototype = fakeServer; - sandbox.useFakeServer(); - } + // this is for testing only + sandbox.getFakes = function getFakes() { + return collection; + }; - if (config.useFakeTimers) { - if (typeof config.useFakeTimers === "object") { - sandbox.useFakeTimers.call(sandbox, config.useFakeTimers); - } else { - sandbox.useFakeTimers(); + sandbox.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)); + }; - return sandbox; -} - -extend(sinonSandbox, { - useFakeTimers: function (args) { - this.clock = sinonClock.useFakeTimers.call(null, args); + sandbox.inject = function inject(obj) { + obj.spy = function () { + return sandbox.spy.apply(null, arguments); + }; - return this.add(this.clock); - }, + obj.stub = function () { + return sandbox.stub.apply(null, arguments); + }; - serverPrototype: fakeServer, + obj.mock = function () { + return sandbox.mock.apply(null, arguments); + }; - useFakeServer: function useFakeServer() { - var proto = this.serverPrototype || fakeServer; + if (sandbox.clock) { + obj.clock = sandbox.clock; + } - if (!proto || !proto.create) { - return null; + if (sandbox.server) { + obj.server = sandbox.server; + obj.requests = sandbox.server.requests; } - this.server = proto.create(); - return this.add(this.server); - }, + obj.match = sinonMatch; - useFakeXMLHttpRequest: function useFakeXMLHttpRequest() { - var xhr = fakeXhr.useFakeXMLHttpRequest(); - return this.add(xhr); - }, + return obj; + }; - inject: function (obj) { - sinonCollection.inject.call(this, obj); + sandbox.mock = function mock() { + var m = sinonMock.apply(null, arguments); - if (this.clock) { - obj.clock = this.clock; - } + push.call(collection, m); - if (this.server) { - obj.server = this.server; - obj.requests = this.server.requests; - } + return m; + }; - obj.match = sinonMatch; + sandbox.reset = function reset() { + applyOnEach(collection, "reset"); + }; - return obj; - }, + sandbox.resetBehavior = function resetBehavior() { + applyOnEach(collection, "resetBehavior"); + }; + + sandbox.resetHistory = function resetHistory() { + function privateResetHistory(f) { + var method = f.resetHistory || f.reset; + if (method) { + method.call(f); + } + } + + forEach.call(collection, function (fake) { + if (typeof fake === "function") { + privateResetHistory(fake); + return; + } - usingPromise: function (promiseLibrary) { + var methods = []; + if (fake.get) { + methods.push(fake.get); + } - this.promiseLibrary = promiseLibrary; + if (fake.set) { + methods.push(fake.set); + } - return this; - }, + methods.forEach(privateResetHistory); + }); + }; - restore: function () { + sandbox.restore = function restore() { if (arguments.length) { throw new Error("sandbox.restore() does not take any parameters. Perhaps you meant stub.restore()"); } - sinonCollection.restore.apply(this, arguments); - this.restoreContext(); - }, + applyOnEach(collection, "restore"); + collection = []; + + sandbox.restoreContext(); + }; - restoreContext: function () { - var injectedKeys = this.injectedKeys; - var injectInto = this.injectInto; + sandbox.restoreContext = function restoreContext() { + var injectedKeys = sandbox.injectedKeys; + var injectInto = sandbox.injectInto; if (!injectedKeys) { return; @@ -118,34 +140,97 @@ extend(sinonSandbox, { }); injectedKeys = []; - }, + }; + + sandbox.spy = function spy() { + var s = sinonSpy.apply(sinonSpy, arguments); - create: function (config) { - if (!config) { - return Object.create(sinonSandbox); + push.call(collection, s); + + return s; + }; + + sandbox.stub = function stub(object, property) { + if (object && typeof property !== "undefined" + && !(property in object)) { + throw new TypeError("Cannot stub non-existent own property " + valueToString(property)); } - var sandbox = prepareSandboxFromConfig(config); - sandbox.args = sandbox.args || []; - sandbox.injectedKeys = []; - sandbox.injectInto = config.injectInto; - var exposed = sandbox.inject({}); + var stubbed = sinonStub.apply(null, arguments); + var isStubbingEntireObject = typeof property === "undefined" && typeof object === "object"; + + if (isStubbingEntireObject) { + var ownMethods = collectOwnMethods(stubbed); - if (config.properties) { - config.properties.forEach(function (prop) { - var value = exposed[prop] || prop === "sandbox" && sandbox; - exposeValue(sandbox, config, prop, value); + ownMethods.forEach(function (method) { + push.call(collection, method); }); + + usePromiseLibrary(promiseLib, ownMethods); } else { - exposeValue(sandbox, config, "sandbox"); + push.call(collection, stubbed); + usePromiseLibrary(promiseLib, stubbed); } - return sandbox; - }, + return stubbed; + }; + + sandbox.useFakeTimers = function useFakeTimers(args) { + var clock = sinonClock.useFakeTimers.call(null, args); + + sandbox.clock = clock; + push.call(collection, clock); + + return clock; + }; + + sandbox.verify = function verify() { + applyOnEach(collection, "verify"); + }; + + sandbox.verifyAndRestore = function verifyAndRestore() { + var exception; + + try { + sandbox.verify(); + } catch (e) { + exception = e; + } + + sandbox.restore(); + + if (exception) { + throw exception; + } + }; - match: sinonMatch, + sandbox.useFakeServer = function useFakeServer() { + var proto = sandbox.serverPrototype || fakeServer; + + if (!proto || !proto.create) { + return null; + } + + sandbox.server = proto.create(); + push.call(collection, sandbox.server); + + return sandbox.server; + }; + + sandbox.useFakeXMLHttpRequest = function useFakeXMLHttpRequest() { + var xhr = fakeXhr.useFakeXMLHttpRequest(); + return push.call(collection, xhr); + }; + + sandbox.usingPromise = function usingPromise(promiseLibrary) { + promiseLib = promiseLibrary; + collection.promiseLibrary = promiseLibrary; + + return sandbox; + }; +} - assert: sinonAssert -}); +Sandbox.prototype.assert = sinonAssert; +Sandbox.prototype.match = sinonMatch; -module.exports = sinonSandbox; +module.exports = Sandbox; diff --git a/lib/sinon/util/core/use-promise-library.js b/lib/sinon/util/core/use-promise-library.js new file mode 100644 index 000000000..007858eb1 --- /dev/null +++ b/lib/sinon/util/core/use-promise-library.js @@ -0,0 +1,21 @@ +"use strict"; + +var forEach = Array.prototype.forEach; + +function usePromiseLibrary(library, fakes) { + if (typeof library === "undefined") { + return; + } + + if (Array.isArray(fakes)) { + forEach.call(fakes, usePromiseLibrary.bind(null, library)); + + return; + } + + if (typeof fakes.usingPromise === "function") { + fakes.usingPromise(library); + } +} + +module.exports = usePromiseLibrary; diff --git a/test/collection-test.js b/test/collection-test.js deleted file mode 100644 index 16dd9ce36..000000000 --- a/test/collection-test.js +++ /dev/null @@ -1,542 +0,0 @@ -"use strict"; - -var referee = require("@sinonjs/referee"); -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 () { - it("creates fake collection", function () { - var collection = Object.create(sinonCollection); - - assert.isFunction(collection.verify); - assert.isFunction(collection.restore); - assert.isFunction(collection.verifyAndRestore); - assert.isFunction(collection.stub); - 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 - // eslint-disable-next-line no-loop-func, ie11/no-loop-func - assert.exception(function () { - this.collection.createStubInstance(types[i]); - }); - } - }); - }); - - describe(".stub", function () { - beforeEach(function () { - this.collection = Object.create(sinonCollection); - }); - - it("fails if stubbing property on null", function () { - var collection = this.collection; - - assert.exception( - function () { - collection.stub(null, "prop"); - }, - { - message: "Trying to stub property 'prop' of null" - } - ); - }); - - it("fails if stubbing symbol on null", function () { - if (typeof Symbol === "function") { - var collection = this.collection; - - assert.exception( - function () { - collection.stub(null, Symbol()); - }, - { - message: "Trying to stub property 'Symbol()' of null" - } - ); - } - }); - - it("creates a stub", function () { - var object = { method: function () {} }; - - this.collection.stub(object, "method"); - - assert.equals(typeof object.method.restore, "function"); - }); - - it("adds stub to fake array", function () { - var object = { method: function () {} }; - - this.collection.stub(object, "method"); - - assert.equals(this.collection.fakes, [object.method]); - }); - - it("appends stubs to fake array", function () { - this.collection.stub({ method: function () {} }, "method"); - this.collection.stub({ method: function () {} }, "method"); - - assert.equals(this.collection.fakes.length, 2); - }); - - it("adds all object methods to fake array", function () { - var object = { - method: function () {}, - method2: function () {}, - method3: function () {} - }; - - Object.defineProperty(object, "method3", { - enumerable: false - }); - - this.collection.stub(object); - - assert.contains(this.collection.fakes, object.method); - assert.contains(this.collection.fakes, object.method2); - assert.contains(this.collection.fakes, object.method3); - assert.equals(this.collection.fakes.length, 3); - }); - - it("returns a stubbed object", function () { - var object = { method: function () {} }; - assert.equals(this.collection.stub(object), object); - }); - - it("returns a stubbed method", function () { - var object = { method: function () {} }; - assert.equals(this.collection.stub(object, "method"), object.method); - }); - - if (typeof process !== "undefined") { - describe("on node", function () { - beforeEach(function () { - process.env.HELL = "Ain't too bad"; - }); - - it("stubs environment property", function () { - var originalPrintWarning = deprecated.printWarning; - deprecated.printWarning = function () {}; - - this.collection.stub(process.env, "HELL").value("froze over"); - assert.equals(process.env.HELL, "froze over"); - - deprecated.printWarning = originalPrintWarning; - }); - }); - } - }); - - describe("stub anything", function () { - beforeEach(function () { - this.object = { property: 42 }; - this.collection = Object.create(sinonCollection); - }); - - it("stubs number property", function () { - var originalPrintWarning = deprecated.printWarning; - deprecated.printWarning = function () {}; - - this.collection.stub(this.object, "property").value(1); - - assert.equals(this.object.property, 1); - - deprecated.printWarning = originalPrintWarning; - }); - - it("restores number property", function () { - var originalPrintWarning = deprecated.printWarning; - deprecated.printWarning = function () {}; - - this.collection.stub(this.object, "property").value(1); - this.collection.restore(); - - assert.equals(this.object.property, 42); - - deprecated.printWarning = originalPrintWarning; - }); - - it("fails if property does not exist", function () { - var originalPrintWarning = deprecated.printWarning; - deprecated.printWarning = function () {}; - - var collection = this.collection; - var object = {}; - - assert.exception(function () { - collection.stub(object, "prop", 1); - }); - - deprecated.printWarning = originalPrintWarning; - }); - - it("fails if Symbol does not exist", function () { - if (typeof Symbol === "function") { - var collection = this.collection; - var object = {}; - - var originalPrintWarning = deprecated.printWarning; - deprecated.printWarning = function () {}; - - assert.exception(function () { - collection.stub(object, Symbol()); - }, {message: "Cannot stub non-existent own property Symbol()"}, TypeError); - - deprecated.printWarning = originalPrintWarning; - } - }); - }); - - describe(".mock", function () { - beforeEach(function () { - this.collection = Object.create(sinonCollection); - }); - - it("returns a mock", function () { - var object = { method: function () { }}; - - var actual = this.collection.mock(object); - actual.expects("method"); - - assert.equals(typeof actual.verify, "function"); - assert.equals(typeof object.method.restore, "function"); - }); - - it("adds mock to fake array", function () { - var object = { method: function () { }}; - - var expected = this.collection.mock(object); - - assert.equals(this.collection.fakes, [expected]); - }); - - it("appends mocks to fake array", function () { - this.collection.mock({}); - this.collection.mock({}); - - assert.equals(this.collection.fakes.length, 2); - }); - }); - - describe("stub and mock test", function () { - beforeEach(function () { - this.collection = Object.create(sinonCollection); - }); - - it("appends mocks and stubs to fake array", function () { - this.collection.mock({ method: function () {} }, "method"); - this.collection.stub({ method: function () {} }, "method"); - - assert.equals(this.collection.fakes.length, 2); - }); - }); - - describe(".verify", function () { - beforeEach(function () { - this.collection = Object.create(sinonCollection); - }); - - it("calls verify on all fakes", function () { - this.collection.fakes = [{ - verify: sinonSpy() - }, { - verify: sinonSpy() - }]; - - this.collection.verify(); - - assert(this.collection.fakes[0].verify.called); - assert(this.collection.fakes[1].verify.called); - }); - }); - - describe(".restore", function () { - beforeEach(function () { - this.collection = Object.create(sinonCollection); - this.collection.fakes = [{ - restore: sinonSpy() - }, { - restore: sinonSpy() - }]; - }); - - it("calls restore on all fakes", function () { - var fake0 = this.collection.fakes[0]; - var fake1 = this.collection.fakes[1]; - - this.collection.restore(); - - assert(fake0.restore.called); - assert(fake1.restore.called); - }); - - it("removes from collection when restored", function () { - this.collection.restore(); - assert(this.collection.fakes.length === 0); - }); - - it("restores functions when stubbing entire object", function () { - var a = function () {}; - var b = function () {}; - var obj = { a: a, b: b }; - this.collection.stub(obj); - - this.collection.restore(); - - assert.same(obj.a, a); - assert.same(obj.b, b); - }); - }); - - describe("verify and restore", function () { - beforeEach(function () { - this.collection = Object.create(sinonCollection); - }); - - it("calls verify and restore", function () { - this.collection.verify = sinonSpy(); - this.collection.restore = sinonSpy(); - - this.collection.verifyAndRestore(); - - assert(this.collection.verify.called); - assert(this.collection.restore.called); - }); - - it("throws when restore throws", function () { - this.collection.verify = sinonSpy(); - this.collection.restore = sinonStub().throws(); - - assert.exception(function () { - this.collection.verifyAndRestore(); - }); - }); - - it("calls restore when restore throws", function () { - var collection = this.collection; - - collection.verify = sinonSpy(); - collection.restore = sinonStub().throws(); - - assert.exception(function () { - collection.verifyAndRestore(); - }); - - assert(collection.restore.called); - }); - }); - - describe(".reset", function () { - beforeEach(function () { - this.collection = Object.create(sinonCollection); - this.collection.fakes = [{ - reset: sinonSpy() - }, { - reset: sinonSpy() - }]; - }); - - it("calls reset on all fakes", function () { - var fake0 = this.collection.fakes[0]; - var fake1 = this.collection.fakes[1]; - - this.collection.reset(); - - assert(fake0.reset.called); - assert(fake1.reset.called); - }); - }); - - describe(".resetBehavior", function () { - beforeEach(function () { - this.collection = Object.create(sinonCollection); - this.collection.fakes = [{ - resetBehavior: sinonSpy() - }, { - resetBehavior: sinonSpy() - }]; - }); - - it("calls resetBehavior on all fakes", function () { - var fake0 = this.collection.fakes[0]; - var fake1 = this.collection.fakes[1]; - - this.collection.resetBehavior(); - - assert(fake0.resetBehavior.called); - assert(fake1.resetBehavior.called); - }); - }); - - describe(".resetHistory", function () { - beforeEach(function () { - this.collection = Object.create(sinonCollection); - var spy1 = sinonSpy(); - spy1(); - - var spy2 = sinonSpy(); - spy2(); - - this.collection.fakes = [ - spy1, - spy2 - ]; - }); - - it("resets the history on all fakes", function () { - var fake0 = this.collection.fakes[0]; - var fake1 = this.collection.fakes[1]; - - this.collection.resetHistory(); - - refute(fake0.called); - refute(fake1.called); - }); - - it("calls reset on fake that do not have a resetHistory", function () { - var noop = function noop() {}; - - noop.reset = function reset() { - noop.reset.called = true; - }; - - this.collection.fakes.push(noop); - - this.collection.resetHistory(); - - assert.isTrue(noop.reset.called); - }); - }); - - describe("inject test", function () { - beforeEach(function () { - this.collection = Object.create(sinonCollection); - }); - - it("injects fakes into object", function () { - var obj = {}; - this.collection.inject(obj); - - assert.isFunction(obj.spy); - assert.isFunction(obj.stub); - assert.isFunction(obj.mock); - }); - - it("returns argument", function () { - var obj = {}; - - assert.same(this.collection.inject(obj), obj); - }); - - it("injects spy, stub, mock bound to collection", function () { - var obj = {}; - this.collection.inject(obj); - sinonStub(this.collection, "spy"); - sinonStub(this.collection, "stub"); - sinonStub(this.collection, "mock"); - - obj.spy(); - var fn = obj.spy; - fn(); - - obj.stub(); - fn = obj.stub; - fn(); - - obj.mock(); - fn = obj.mock; - fn(); - - assert(this.collection.spy.calledTwice); - assert(this.collection.stub.calledTwice); - assert(this.collection.mock.calledTwice); - }); - }); -}); diff --git a/test/issues/issues-test.js b/test/issues/issues-test.js index 4d8cd25c2..48b76bd3f 100644 --- a/test/issues/issues-test.js +++ b/test/issues/issues-test.js @@ -8,7 +8,7 @@ var refute = referee.refute; describe("issues", function () { beforeEach(function () { - this.sandbox = sinon.sandbox.create(); + this.sandbox = sinon.createSandbox(); }); afterEach(function () { @@ -291,7 +291,7 @@ describe("issues", function () { beforeEach(function () { if (typeof window === "undefined" || throwsOnUnconfigurableProperty()) { this.skip(); } - sandbox = sinon.sandbox.create(); + sandbox = sinon.createSandbox(); }); afterEach(function () { @@ -325,7 +325,7 @@ describe("issues", function () { var sandbox; beforeEach(function () { - sandbox = sinon.sandbox.create(); + sandbox = sinon.createSandbox(); }); afterEach(function () { diff --git a/test/sandbox-test.js b/test/sandbox-test.js index 124b22083..5e0700046 100644 --- a/test/sandbox-test.js +++ b/test/sandbox-test.js @@ -3,12 +3,13 @@ var referee = require("@sinonjs/referee"); var samsam = require("samsam"); var assert = referee.assert; +var deprecated = require("../lib/sinon/util/core/deprecated"); var refute = referee.refute; var fakeXhr = require("nise").fakeXhr; var fakeServerWithClock = require("nise").fakeServerWithClock; var fakeServer = require("nise").fakeServer; -var sinonSandbox = require("../lib/sinon/sandbox"); -var sinonCollection = require("../lib/sinon/collection"); +var Sandbox = require("../lib/sinon/sandbox"); +var createSandbox = require("../lib/sinon/create-sandbox"); var sinonSpy = require("../lib/sinon/spy"); var sinonStub = require("../lib/sinon/stub"); var sinonConfig = require("../lib/sinon/util/core/get-config"); @@ -33,49 +34,479 @@ referee.add("fakeServerWithClock", { assertMessage: "Expected object ${0} to be a fake server with clock" }); -describe("sinonSandbox", function () { - it("inherits collection", function () { - assert(sinonCollection.isPrototypeOf(sinonSandbox)); - }); - - it("creates sandboxes", function () { - var sandbox = sinonSandbox.create(); - - assert.isObject(sandbox); - assert(sinonSandbox.isPrototypeOf(sandbox)); - }); - +describe("Sandbox", function () { it("exposes match", function () { - var sandbox = sinonSandbox.create(); + var sandbox = new Sandbox(); assert.same(sandbox.match, sinonMatch); }); it("exposes assert", function () { - var sandbox = sinonSandbox.create(); + var sandbox = new Sandbox(); assert.same(sandbox.assert, sinonAssert); }); it("can be reset without failing when pre-configured to use a fake server", function () { - var sandbox = sinonSandbox.create({useFakeServer: true}); + var sandbox = createSandbox({useFakeServer: true}); refute.exception(function () { sandbox.reset(); }); }); it("can be reset without failing when configured to use a fake server", function () { - var sandbox = sinonSandbox.create(); + var sandbox = new Sandbox(); sandbox.useFakeServer(); refute.exception(function () { sandbox.reset(); }); }); + describe(".mock", function () { + beforeEach(function () { + this.sandbox = createSandbox(); + }); + + it("returns a mock", function () { + var object = { method: function () { }}; + + var actual = this.sandbox.mock(object); + actual.expects("method"); + + assert.equals(typeof actual.verify, "function"); + assert.equals(typeof object.method.restore, "function"); + }); + + it("adds mock to fake array", function () { + var fakes = this.sandbox.getFakes(); + var object = { method: function () { }}; + var expected = this.sandbox.mock(object); + + assert(fakes.indexOf(expected) !== -1); + }); + + it("appends mocks to fake array", function () { + var fakes = this.sandbox.getFakes(); + + this.sandbox.mock({}); + this.sandbox.mock({}); + + assert.equals(fakes.length, 2); + }); + }); + + describe("stub and mock test", function () { + beforeEach(function () { + this.sandbox = createSandbox(); + }); + + it("appends mocks and stubs to fake array", function () { + var fakes = this.sandbox.getFakes(); + + this.sandbox.mock({ method: function () {} }, "method"); + this.sandbox.stub({ method: function () {} }, "method"); + + assert.equals(fakes.length, 2); + }); + }); + + describe(".spy", function () { + it("should return a spy", function () { + var sandbox = createSandbox(); + var spy = sandbox.spy(); + + assert.isFunction(spy); + assert.equals(spy.displayName, "spy"); + }); + + it("should add a spy to the internal collection", function () { + var sandbox = createSandbox(); + var fakes = sandbox.getFakes(); + var expected; + + expected = sandbox.spy(); + + assert.isTrue(fakes.indexOf(expected) !== -1); + }); + }); + + describe(".createStubInstance", function () { + beforeEach(function () { + this.sandbox = createSandbox(); + }); + + it("stubs existing methods", function () { + var Class = function () {}; + Class.prototype.method = function () {}; + + var stub = this.sandbox.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.sandbox.createStubInstance(Class); + stub.method1.returns(1); + stub.method2.returns(2); + stub.method3.returns(3); + + assert.equals(3, stub.method3()); + + this.sandbox.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.sandbox.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.sandbox.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.sandbox.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.sandbox.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.sandbox.createStubInstance(types[i]); + }); + } + }); + }); + + describe(".stub", function () { + beforeEach(function () { + this.sandbox = createSandbox(); + }); + + it("fails if stubbing property on null", function () { + var sandbox = this.sandbox; + + assert.exception( + function () { + sandbox.stub(null, "prop"); + }, + { + message: "Trying to stub property 'prop' of null" + } + ); + }); + + it("fails if stubbing symbol on null", function () { + if (typeof Symbol === "function") { + var sandbox = this.sandbox; + + assert.exception( + function () { + sandbox.stub(null, Symbol()); + }, + { + message: "Trying to stub property 'Symbol()' of null" + } + ); + } + }); + + it("creates a stub", function () { + var object = { method: function () {} }; + + this.sandbox.stub(object, "method"); + + assert.equals(typeof object.method.restore, "function"); + }); + + it("adds stub to fake array", function () { + var fakes = this.sandbox.getFakes(); + var object = { method: function () {} }; + var stub = this.sandbox.stub(object, "method"); + + assert.isTrue(fakes.indexOf(stub) !== -1); + }); + + it("appends stubs to fake array", function () { + var fakes = this.sandbox.getFakes(); + + this.sandbox.stub({ method: function () {} }, "method"); + this.sandbox.stub({ method: function () {} }, "method"); + + assert.equals(fakes.length, 2); + }); + + it("adds all object methods to fake array", function () { + var fakes = this.sandbox.getFakes(); + var object = { + method: function () {}, + method2: function () {}, + method3: function () {} + }; + + Object.defineProperty(object, "method3", { + enumerable: false + }); + + this.sandbox.stub(object); + + assert.isTrue(fakes.indexOf(object.method) !== -1); + assert.isTrue(fakes.indexOf(object.method2) !== -2); + assert.isTrue(fakes.indexOf(object.method3) !== -3); + assert.equals(fakes.length, 3); + }); + + it("returns a stubbed object", function () { + var object = { method: function () {} }; + assert.equals(this.sandbox.stub(object), object); + }); + + it("returns a stubbed method", function () { + var object = { method: function () {} }; + assert.equals(this.sandbox.stub(object, "method"), object.method); + }); + + if (typeof process !== "undefined") { + describe("on node", function () { + beforeEach(function () { + process.env.HELL = "Ain't too bad"; + }); + + it("stubs environment property", function () { + var originalPrintWarning = deprecated.printWarning; + deprecated.printWarning = function () {}; + + this.sandbox.stub(process.env, "HELL").value("froze over"); + assert.equals(process.env.HELL, "froze over"); + + deprecated.printWarning = originalPrintWarning; + }); + }); + } + }); + + describe("stub anything", function () { + beforeEach(function () { + this.object = { property: 42 }; + this.sandbox = new Sandbox(); + }); + + it("stubs number property", function () { + var originalPrintWarning = deprecated.printWarning; + deprecated.printWarning = function () {}; + + this.sandbox.stub(this.object, "property").value(1); + + assert.equals(this.object.property, 1); + + deprecated.printWarning = originalPrintWarning; + }); + + it("restores number property", function () { + var originalPrintWarning = deprecated.printWarning; + deprecated.printWarning = function () {}; + + this.sandbox.stub(this.object, "property").value(1); + this.sandbox.restore(); + + assert.equals(this.object.property, 42); + + deprecated.printWarning = originalPrintWarning; + }); + + it("fails if property does not exist", function () { + var originalPrintWarning = deprecated.printWarning; + deprecated.printWarning = function () {}; + + var sandbox = this.sandbox; + var object = {}; + + assert.exception(function () { + sandbox.stub(object, "prop", 1); + }); + + deprecated.printWarning = originalPrintWarning; + }); + + it("fails if Symbol does not exist", function () { + if (typeof Symbol === "function") { + var sandbox = this.sandbox; + var object = {}; + + var originalPrintWarning = deprecated.printWarning; + deprecated.printWarning = function () {}; + + assert.exception(function () { + sandbox.stub(object, Symbol()); + }, {message: "Cannot stub non-existent own property Symbol()"}, TypeError); + + deprecated.printWarning = originalPrintWarning; + } + }); + }); + + describe(".verifyAndRestore", function () { + beforeEach(function () { + this.sandbox = createSandbox(); + }); + + it("calls verify and restore", function () { + this.sandbox.verify = sinonSpy(); + this.sandbox.restore = sinonSpy(); + + this.sandbox.verifyAndRestore(); + + assert(this.sandbox.verify.called); + assert(this.sandbox.restore.called); + }); + + it("throws when restore throws", function () { + this.sandbox.verify = sinonSpy(); + this.sandbox.restore = sinonStub().throws(); + + assert.exception(function () { + this.sandbox.verifyAndRestore(); + }); + }); + + it("calls restore when restore throws", function () { + var sandbox = this.sandbox; + + sandbox.verify = sinonSpy(); + sandbox.restore = sinonStub().throws(); + + assert.exception(function () { + sandbox.verifyAndRestore(); + }); + + assert(sandbox.restore.called); + }); + }); + + describe(".reset", function () { + beforeEach(function () { + var sandbox = this.sandbox = createSandbox(); + var fakes = sandbox.getFakes(); + + fakes.push({reset: sinonSpy()}); + fakes.push({reset: sinonSpy()}); + }); + + it("calls reset on all fakes", function () { + var fake0 = this.sandbox.getFakes()[0]; + var fake1 = this.sandbox.getFakes()[1]; + + this.sandbox.reset(); + + assert(fake0.reset.called); + assert(fake1.reset.called); + }); + }); + + describe(".resetBehavior", function () { + beforeEach(function () { + var sandbox = this.sandbox = createSandbox(); + var fakes = sandbox.getFakes(); + + fakes.push({resetBehavior: sinonSpy()}); + fakes.push({resetBehavior: sinonSpy()}); + }); + + it("calls resetBehavior on all fakes", function () { + var fake0 = this.sandbox.getFakes()[0]; + var fake1 = this.sandbox.getFakes()[1]; + + this.sandbox.resetBehavior(); + + assert(fake0.resetBehavior.called); + assert(fake1.resetBehavior.called); + }); + }); + + describe(".resetHistory", function () { + beforeEach(function () { + var sandbox = this.sandbox = createSandbox(); + var fakes = this.fakes = sandbox.getFakes(); + + var spy1 = sinonSpy(); + spy1(); + fakes.push(spy1); + + var spy2 = sinonSpy(); + spy2(); + fakes.push(spy2); + }); + + it("resets the history on all fakes", function () { + var fake0 = this.fakes[0]; + var fake1 = this.fakes[1]; + + this.sandbox.resetHistory(); + + refute(fake0.called); + refute(fake1.called); + }); + + it("calls reset on fake that does not have a resetHistory", function () { + var noop = function noop() {}; + + noop.reset = function reset() { + noop.reset.called = true; + }; + + this.fakes.push(noop); + + this.sandbox.resetHistory(); + + assert.isTrue(noop.reset.called); + }); + }); describe(".useFakeTimers", function () { beforeEach(function () { - this.sandbox = Object.create(sinonSandbox); + this.sandbox = new Sandbox(); }); afterEach(function () { @@ -128,7 +559,7 @@ describe("sinonSandbox", function () { describe(".usingPromise", function () { beforeEach(function () { - this.sandbox = Object.create(sinonSandbox); + this.sandbox = new Sandbox(); }); afterEach(function () { @@ -136,7 +567,6 @@ describe("sinonSandbox", function () { }); it("must be a function", function () { - assert.isFunction(this.sandbox.usingPromise); }); @@ -161,7 +591,6 @@ describe("sinonSandbox", function () { return stub() .then(function (action) { - assert.same(resolveValue, action); assert(mockPromise.resolve.calledOnce); }); @@ -199,7 +628,7 @@ describe("sinonSandbox", function () { describe("fake XHR/server", function () { describe(".useFakeXMLHttpRequest", function () { beforeEach(function () { - this.sandbox = sinonSandbox.create(); + this.sandbox = new Sandbox(); }); afterEach(function () { @@ -231,7 +660,7 @@ describe("sinonSandbox", function () { describe(".useFakeServer", function () { beforeEach(function () { - this.sandbox = Object.create(sinonSandbox); + this.sandbox = new Sandbox(); }); afterEach(function () { @@ -284,7 +713,7 @@ describe("sinonSandbox", function () { describe(".inject", function () { beforeEach(function () { this.obj = {}; - this.sandbox = sinonSandbox.create(); + this.sandbox = new Sandbox(); }); afterEach(function () { @@ -366,9 +795,25 @@ describe("sinonSandbox", function () { } }); + describe(".verify", function () { + it("calls verify on all fakes", function () { + var sandbox = createSandbox(); + var fakes = sandbox.getFakes(); + + fakes.push.call(fakes, {verify: sinonSpy()}); + fakes.push.call(fakes, {verify: sinonSpy()}); + + sandbox.verify(); + + fakes.forEach(function (fake) { + assert(fake.verify.calledOnce); + }); + }); + }); + describe(".restore", function () { it("throws when passed arguments", function () { - var sandbox = sinonSandbox.create(); + var sandbox = new Sandbox(); assert.exception(function () { sandbox.restore("args"); @@ -393,7 +838,7 @@ describe("sinonSandbox", function () { }); it("yields stub, mock as arguments", function () { - var sandbox = sinonSandbox.create(sinonConfig({ + var sandbox = createSandbox(sinonConfig({ injectIntoThis: false, properties: ["stub", "mock"] })); @@ -406,7 +851,7 @@ describe("sinonSandbox", function () { }); it("yields spy, stub, mock as arguments", function () { - var sandbox = sinonSandbox.create(sinonConfig({ + var sandbox = createSandbox(sinonConfig({ injectIntoThis: false, properties: ["spy", "stub", "mock"] })); @@ -419,7 +864,7 @@ describe("sinonSandbox", function () { }); it("does not yield server when not faking xhr", function () { - var sandbox = sinonSandbox.create(sinonConfig({ + var sandbox = createSandbox(sinonConfig({ injectIntoThis: false, properties: ["server", "stub", "mock"], useFakeServer: false @@ -437,7 +882,7 @@ describe("sinonSandbox", function () { var clock = {}; var spy = false; var object = { server: server, clock: clock, spy: spy}; - var sandbox = sinonSandbox.create(sinonConfig({ + var sandbox = createSandbox(sinonConfig({ properties: ["server", "clock", "spy"], injectInto: object })); @@ -453,7 +898,7 @@ describe("sinonSandbox", function () { describe("ajax options", function () { it("yields server when faking xhr", function () { - var sandbox = sinonSandbox.create(sinonConfig({ + var sandbox = createSandbox(sinonConfig({ injectIntoThis: false, properties: ["server", "stub", "mock"] })); @@ -467,7 +912,7 @@ describe("sinonSandbox", function () { }); it("uses serverWithClock when faking xhr", function () { - var sandbox = sinonSandbox.create(sinonConfig({ + var sandbox = createSandbox(sinonConfig({ injectIntoThis: false, properties: ["server"], useFakeServer: fakeServerWithClock @@ -479,13 +924,13 @@ describe("sinonSandbox", function () { }); it("uses fakeServer as the serverPrototype by default", function () { - var sandbox = sinonSandbox.create(); + var sandbox = createSandbox(); assert.same(sandbox.serverPrototype, fakeServer); }); it("uses configured implementation as the serverPrototype", function () { - var sandbox = sinonSandbox.create({ + var sandbox = createSandbox({ useFakeServer: fakeServerWithClock }); @@ -493,7 +938,7 @@ describe("sinonSandbox", function () { }); it("yields clock when faking timers", function () { - var sandbox = sinonSandbox.create(sinonConfig({ + var sandbox = createSandbox(sinonConfig({ injectIntoThis: false, properties: ["server", "clock"] })); @@ -507,7 +952,7 @@ describe("sinonSandbox", function () { it("injects properties into object", function () { var object = {}; - var sandbox = sinonSandbox.create(sinonConfig({ + var sandbox = createSandbox(sinonConfig({ properties: ["server", "clock"], injectInto: object })); @@ -526,7 +971,7 @@ describe("sinonSandbox", function () { it("should inject server and clock when only enabling them", function () { var object = {}; - var sandbox = sinonSandbox.create(sinonConfig({ + var sandbox = createSandbox(sinonConfig({ injectInto: object, useFakeTimers: true, useFakeServer: true @@ -549,7 +994,7 @@ describe("sinonSandbox", function () { // This is currently testing the internals of useFakeTimers, we could possibly change it to be based on // behavior. it("fakes specified timers", function () { - var sandbox = sinonSandbox.create(sinonConfig({ + var sandbox = createSandbox(sinonConfig({ injectIntoThis: false, properties: ["clock"], useFakeTimers: {toFake: ["Date", "setTimeout"]} @@ -563,7 +1008,7 @@ describe("sinonSandbox", function () { it("injects sandbox", function () { var object = {}; - var sandbox = sinonSandbox.create(sinonConfig({ + var sandbox = createSandbox(sinonConfig({ properties: ["sandbox", "spy"], injectInto: object })); @@ -578,7 +1023,7 @@ describe("sinonSandbox", function () { it("injects match", function () { var object = {}; - var sandbox = sinonSandbox.create(sinonConfig({ + var sandbox = createSandbox(sinonConfig({ properties: ["match"], injectInto: object })); @@ -595,7 +1040,7 @@ describe("sinonSandbox", function () { foo: "bar" }; - var sandbox = sinonSandbox.create(); + var sandbox = new Sandbox(); sandbox.stub(object, "foo").get(function () { return "baz"; }); @@ -608,7 +1053,7 @@ describe("sinonSandbox", function () { foo: "bar" }; - var sandbox = sinonSandbox.create(); + var sandbox = new Sandbox(); sandbox.stub(object, "foo").get(function () { return "baz"; }); @@ -624,7 +1069,7 @@ describe("sinonSandbox", function () { prop: "bar" }; - var sandbox = sinonSandbox.create(); + var sandbox = new Sandbox(); sandbox.stub(object, "foo").set(function (val) { object.prop = val + "bla"; }); @@ -639,7 +1084,7 @@ describe("sinonSandbox", function () { prop: "bar" }; - var sandbox = sinonSandbox.create(); + var sandbox = new Sandbox(); sandbox.stub(object, "prop").set(function setterFn(val) { object.prop = val + "bla"; }); diff --git a/test/sinon-test.js b/test/sinon-test.js index ee99e260c..82406013f 100644 --- a/test/sinon-test.js +++ b/test/sinon-test.js @@ -11,7 +11,6 @@ var proxyquire = require("proxyquire"); describe("sinon module", function () { var sinon, - fakeSandbox, fakeNise; beforeEach(function () { @@ -32,19 +31,17 @@ describe("sinon module", function () { useFakeXMLHttpRequest: "ba8bd609-c921-4a62-a1b9-49336bd426a4" } }; - fakeSandbox = { - create: "dc61d622-407f-46eb-af24-7a83bb30b8bf" - }; sinon = proxyquire("../lib/sinon", { - nise: fakeNise, - "./sinon/sandbox": fakeSandbox + nise: fakeNise }); }); describe("exports", function () { describe("createSandbox", function () { - it("should be sandbox.create", function () { - assert.equals(sinon.createSandbox, fakeSandbox.create); + it("should be a unary Function named 'createSandbox'", function () { + assert.isFunction(sinon.createSandbox); + assert.equals(sinon.createSandbox.length, 1); + assert.equals(sinon.createSandbox.name, "createSandbox"); }); });