diff --git a/docs/release-source/release/sandbox.md b/docs/release-source/release/sandbox.md index ed6824943..4ff9524bf 100644 --- a/docs/release-source/release/sandbox.md +++ b/docs/release-source/release/sandbox.md @@ -62,19 +62,28 @@ sinon.defaultConfig = { } ``` -
injectInto
injectInto
configuration option can name an object to add properties to.properties
server
property show up in the target object, you also have to set useFakeServer
to true
.
- useFakeTimers
true
, the sandbox will have a clock
property. Can also be an Array
of timer properties to fake.useFakeServer
true
, server
and requests
properties are added to the sandbox. Can also be an object to use for fake server. The default one is sinon.fakeServer
, but if you're using jQuery 1.3.x or some other library that does not set the XHR's onreadystatechange
handler, you might want to do:
+What properties to inject. Note that simply naming "server" here is not
+sufficient to have a `server` property show up in the target object, you also
+have to set `useFakeServer` to `true`.
+
+##### useFakeTimers
+
+If `true`, the sandbox will have a `clock` property. Can also be an `Array` of
+timer properties to fake.
+
+##### useFakeServer
+
+If `true`, `server` and `requests` properties are added to the sandbox. Can
+also be an object to use for fake server. The default one is `sinon.fakeServer`,
+but if you're using jQuery 1.3.x or some other library that does not set the XHR's
+`onreadystatechange` handler, you might want to do:
```javascript
sinon.config = {
@@ -124,6 +133,13 @@ Fakes XHR and binds a server object to the sandbox such that it too is restored
Access requests through `sandbox.requests` and server through `sandbox.server`
+#### `sandbox.usingPromise(promiseLibrary);`
+
+Causes all stubs created from the sandbox to return promises using a specific
+Promise library instead of the global one when using `stub.rejects` or
+`stub.resolves`. Returns the stub to allow chaining.
+
+*Since `sinon@2.0.0`*
#### `sandbox.restore();`
diff --git a/docs/release-source/release/stubs.md b/docs/release-source/release/stubs.md
index 24360dd52..e3f1ffec6 100644
--- a/docs/release-source/release/stubs.md
+++ b/docs/release-source/release/stubs.md
@@ -248,10 +248,10 @@ Causes the stub to return a Promise which resolves to the provided value.
When constructing the Promise, sinon uses the `Promise.resolve` method. You are
responsible for providing a polyfill in environments which do not provide `Promise`.
+The Promise library can be overwritten using the `usingPromise` method.
*Since `sinon@2.0.0`*
-
#### `stub.throws();`
Causes the stub to throw an exception (`Error`).
@@ -273,6 +273,7 @@ Causes the stub to return a Promise which rejects with an exception (`Error`).
When constructing the Promise, sinon uses the `Promise.reject` method. You are
responsible for providing a polyfill in environments which do not provide `Promise`.
+The Promise library can be overwritten using the `usingPromise` method.
*Since `sinon@2.0.0`*
@@ -333,8 +334,28 @@ Like `callsArg`, but with arguments to pass to the callback.
#### `stub.callsArgOnWith(index, context, arg1, arg2, ...);`
+
Like above but with an additional parameter to pass the `this` context.
+#### `stub.usingPromise(promiseLibrary);`
+
+Causes the stub to return promises using a specific Promise library instead of
+the global one when using `stub.rejects` or `stub.resolves`. Returns the stub
+to allow chaining.
+
+```javascript
+var myObj = {
+ saveSomething: sinon.stub().usingPromise(bluebird.Promise).resolves("baz");
+}
+
+myObj.saveSomething()
+ .tap(function(actual) {
+ console.log(actual); // baz
+ });
+```
+
+*Since `sinon@2.0.0`*
+
#### `stub.yields([arg1, arg2, ...])`
Similar to `callsArg`.
diff --git a/lib/sinon/behavior.js b/lib/sinon/behavior.js
index 8ccd5b4fa..404b31c37 100644
--- a/lib/sinon/behavior.js
+++ b/lib/sinon/behavior.js
@@ -129,9 +129,9 @@ var proto = {
} else if (this.fakeFn) {
return this.fakeFn.apply(context, args);
} else if (this.resolve) {
- return Promise.resolve(this.returnValue);
+ return (this.promiseLibrary || Promise).resolve(this.returnValue);
} else if (this.reject) {
- return Promise.reject(this.returnValue);
+ return (this.promiseLibrary || Promise).reject(this.returnValue);
} else if (this.callsThrough) {
return this.stub.wrappedMethod.apply(context, args);
}
diff --git a/lib/sinon/collection.js b/lib/sinon/collection.js
index bf0c46de1..a41575a3d 100644
--- a/lib/sinon/collection.js
+++ b/lib/sinon/collection.js
@@ -71,6 +71,11 @@ var collection = {
return fake;
},
+ addUsingPromise: function (fake) {
+ fake.usingPromise(this.promiseLibrary);
+ return fake;
+ },
+
spy: function spy() {
return this.add(sinonSpy.apply(sinonSpy, arguments));
},
@@ -85,9 +90,16 @@ var collection = {
sinonStub.apply(null, arguments);
if (isStubbingEntireObject) {
- collectOwnMethods(stubbed).forEach(this.add.bind(this));
+ 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;
diff --git a/lib/sinon/default-behaviors.js b/lib/sinon/default-behaviors.js
index 469dd75d3..f5bdc46e2 100644
--- a/lib/sinon/default-behaviors.js
+++ b/lib/sinon/default-behaviors.js
@@ -68,6 +68,10 @@ module.exports = {
fake.callbackAsync = false;
},
+ usingPromise: function usingPromise(fake, promiseLibrary) {
+ fake.promiseLibrary = promiseLibrary;
+ },
+
yields: function (fake) {
fake.callArgAt = useLeftMostCallback;
fake.callbackArguments = slice.call(arguments, 1);
diff --git a/lib/sinon/sandbox.js b/lib/sinon/sandbox.js
index 71cb434cb..4a3d7ce30 100644
--- a/lib/sinon/sandbox.js
+++ b/lib/sinon/sandbox.js
@@ -90,6 +90,13 @@ extend(sinonSandbox, {
return obj;
},
+ usingPromise: function (promiseLibrary) {
+
+ this.promiseLibrary = promiseLibrary;
+
+ return this;
+ },
+
restore: function () {
if (arguments.length) {
throw new Error("sandbox.restore() does not take any parameters. Perhaps you meant stub.restore()");
diff --git a/test/sandbox-test.js b/test/sandbox-test.js
index 89d0ad1f7..d512bd51d 100644
--- a/test/sandbox-test.js
+++ b/test/sandbox-test.js
@@ -109,6 +109,71 @@ describe("sinonSandbox", function () {
});
});
+ describe(".usingPromise", function () {
+ beforeEach(function () {
+ this.sandbox = Object.create(sinonSandbox);
+ });
+
+ afterEach(function () {
+ this.sandbox.restore();
+ });
+
+ it("must be a function", function () {
+
+ assert.isFunction(this.sandbox.usingPromise);
+ });
+
+ it("must return the sandbox", function () {
+ var mockPromise = {};
+
+ var actual = this.sandbox.usingPromise(mockPromise);
+
+ assert.same(actual, this.sandbox);
+ });
+
+ it("must set all stubs created from sandbox with mockPromise", function () {
+
+ var resolveValue = {};
+ var mockPromise = {
+ resolve: sinonStub.create().resolves(resolveValue)
+ };
+
+ this.sandbox.usingPromise(mockPromise);
+ var stub = this.sandbox.stub().resolves();
+
+ return stub()
+ .then(function (action) {
+
+ assert.same(resolveValue, action);
+ assert(mockPromise.resolve.calledOnce);
+ });
+ });
+
+ it("must set all stubs created from sandbox with mockPromise", function () {
+
+ var resolveValue = {};
+ var mockPromise = {
+ resolve: sinonStub.create().resolves(resolveValue)
+ };
+ var stubbedObject = {
+ stubbedMethod: function () {
+ return;
+ }
+ };
+
+ this.sandbox.usingPromise(mockPromise);
+ this.sandbox.stub(stubbedObject);
+ stubbedObject.stubbedMethod.resolves({});
+
+ return stubbedObject.stubbedMethod()
+ .then(function (action) {
+
+ assert.same(resolveValue, action);
+ assert(mockPromise.resolve.calledOnce);
+ });
+ });
+ });
+
// These were not run in browsers before, as we were only testing in node
if (typeof window !== "undefined") {
describe("fake XHR/server", function () {
diff --git a/test/stub-test.js b/test/stub-test.js
index 0ae518ced..9e4bfc657 100644
--- a/test/stub-test.js
+++ b/test/stub-test.js
@@ -317,6 +317,59 @@ describe("stub", function () {
});
});
+ describe(".usingPromise", function () {
+ it("should exist and be a function", function () {
+ var stub = createStub.create();
+
+ assert(stub.usingPromise);
+ assert.isFunction(stub.usingPromise);
+ });
+
+ it("should return the current stub", function () {
+ var stub = createStub.create();
+
+ assert.same(stub.usingPromise(Promise), stub);
+ });
+
+ it("should set the promise used by resolve", function () {
+ var stub = createStub.create();
+ var promise = {
+ resolve: createStub.create().callsFake(function (value) {
+ return Promise.resolve(value);
+ })
+ };
+ var object = {};
+
+ stub.usingPromise(promise).resolves(object);
+
+ return stub().then(function (actual) {
+ assert.same(actual, object, "Same object resolved");
+ assert.isTrue(promise.resolve.calledOnce, "Custom promise resolve called once");
+ assert.isTrue(promise.resolve.calledWith(object), "Custom promise resolve called once with expected");
+ });
+ });
+
+ it("should set the promise used by reject", function () {
+ var stub = createStub.create();
+ var promise = {
+ reject: createStub.create().callsFake(function (err) {
+ return Promise.reject(err);
+ })
+ };
+ var reason = new Error();
+
+ stub.usingPromise(promise).rejects(reason);
+
+ return stub().then(function () {
+ referee.fail("this should not resolve");
+ }).catch(function (actual) {
+ assert.same(actual, reason, "Same object resolved");
+ assert.isTrue(promise.reject.calledOnce, "Custom promise reject called once");
+ assert.isTrue(promise.reject.calledWith(reason), "Custom promise reject called once with expected");
+ });
+ });
+ });
+
describe(".throws", function () {
it("throws specified exception", function () {
var stub = createStub.create();