diff --git a/spec/core/EnvSpec.js b/spec/core/EnvSpec.js index f731d36b..3b34e2e2 100644 --- a/spec/core/EnvSpec.js +++ b/spec/core/EnvSpec.js @@ -46,6 +46,23 @@ describe("Env", function() { })); }); + it('can configure a custom promise library', function() { + var myLibrary = { resolve: jasmine.createSpy(), reject: jasmine.createSpy() }; + expect(env.getPromise()).toBeUndefined(); + + env.configure({ promiseLibrary: myLibrary }); + expect(env.getPromise()).toBe(myLibrary); + }); + + it('fails to configure a custom promise library if library is invalid', function() { + var myLibrary = {}; + expect(env.getPromise()).toBeUndefined(); + + expect(function() { + env.configure({ promiseLibrary: myLibrary }); + }).toThrowError('Custom promise library missing `resolve`/`reject` functions'); + }); + it('defaults to multiple failures for specs', function() { spyOn(jasmineUnderTest, 'Spec'); env.it('bar', function() {}); diff --git a/spec/core/SpyStrategySpec.js b/spec/core/SpyStrategySpec.js index 10e4f583..25078e4c 100644 --- a/spec/core/SpyStrategySpec.js +++ b/spec/core/SpyStrategySpec.js @@ -110,6 +110,62 @@ describe("SpyStrategy", function() { }) }); + describe("#resolveValue", function() { + it("allows a resolved promise to be returned", function(done) { + if (!jasmineUnderTest.getPromise()) { + pending('Environment does not support promises.'); + } + + var originalFn = jasmine.createSpy("original"), + spyStrategy = new jasmineUnderTest.SpyStrategy({fn: originalFn}); + + spyStrategy.resolveValue(37); + spyStrategy.exec().then(function (returnValue) { + expect(returnValue).toEqual(37); + done(); + }).catch(done.fail); + }); + + it("fails if promises are not available", function() { + var originalFn = jasmine.createSpy("original"), + spyStrategy = new jasmineUnderTest.SpyStrategy({fn: originalFn}); + + spyOn(jasmineUnderTest, 'getPromise'); + + expect(function() { + spyStrategy.resolveValue(37); + }).toThrowError('resolveValue is unavailable because the environment does not support promises.'); + }); + }); + + describe("#rejectValue", function() { + it("allows a rejected promise to be returned", function(done) { + if (!jasmineUnderTest.getPromise()) { + pending('Environment does not support promises.'); + } + + var originalFn = jasmine.createSpy("original"), + spyStrategy = new jasmineUnderTest.SpyStrategy({fn: originalFn}); + + spyStrategy.rejectValue(new Error('oops')); + spyStrategy.exec().then(done.fail).catch(function (error) { + expect(error).toEqual(new Error('oops')); + done(); + }).catch(done.fail); + }); + + it("fails if promises are not available", function() { + var originalFn = jasmine.createSpy("original"), + spyStrategy = new jasmineUnderTest.SpyStrategy({fn: originalFn}); + + spyOn(jasmineUnderTest, 'getPromise'); + + expect(function() { + spyStrategy.rejectValue(new Error('oops')); + }).toThrowError('rejectValue is unavailable because the environment does not support promises.'); + }); + }); + it("allows a custom strategy to be used", function() { var plan = jasmine.createSpy('custom strategy') .and.returnValue('custom strategy result'), diff --git a/spec/core/baseSpec.js b/spec/core/baseSpec.js index 7f17265b..d7be476f 100644 --- a/spec/core/baseSpec.js +++ b/spec/core/baseSpec.js @@ -27,4 +27,19 @@ describe('base helpers', function() { }, 100); }); }); + + describe('getPromise', function() { + it('returns a custom library if configured', function() { + var myLibrary = { resolve: jasmine.createSpy(), reject: jasmine.createSpy() }; + jasmineUnderTest.getEnv().configure({ promiseLibrary: myLibrary }); + expect(jasmineUnderTest.getPromise()).toBe(myLibrary); + }); + + it('returns global library if not configured', function() { + var globalLibrary = {}; + var global = { Promise: globalLibrary }; + spyOn(jasmineUnderTest, 'getGlobal').and.returnValue(global); + expect(jasmineUnderTest.getPromise()).toBe(globalLibrary); + }); + }); }); diff --git a/src/core/Env.js b/src/core/Env.js index 680d0d49..7841fe34 100644 --- a/src/core/Env.js +++ b/src/core/Env.js @@ -76,7 +76,16 @@ getJasmineRequireObj().Env = function(j$) { * @type Boolean * @default false */ - hideDisabled: false + hideDisabled: false, + /** + * Set to provide a custom promise library that Jasmine will use if it needs + * to create a promise. If not set, it will default to whatever global promise + * library is available (if any). + * @name Configuration#promiseLibrary + * @type function + * @default undefined + */ + promiseLibrary: undefined }; var currentSuite = function() { @@ -142,6 +151,15 @@ getJasmineRequireObj().Env = function(j$) { if (configuration.hasOwnProperty('hideDisabled')) { config.hideDisabled = configuration.hideDisabled; } + + if (configuration.hasOwnProperty('promiseLibrary')) { + if (typeof configuration.promiseLibrary.resolve === 'function' && + typeof configuration.promiseLibrary.reject === 'function') { + config.promiseLibrary = configuration.promiseLibrary; + } else { + throw new Error('Custom promise library missing `resolve`/`reject` functions'); + } + } }; /** @@ -193,6 +211,10 @@ getJasmineRequireObj().Env = function(j$) { } }; + this.getPromise = function() { + return config.promiseLibrary; + }; + j$.Expectation.addCoreMatchers(j$.matchers); j$.Expectation.addAsyncCoreMatchers(j$.asyncMatchers); diff --git a/src/core/SpyStrategy.js b/src/core/SpyStrategy.js index ae5d4451..27a42f8e 100644 --- a/src/core/SpyStrategy.js +++ b/src/core/SpyStrategy.js @@ -84,6 +84,44 @@ getJasmineRequireObj().SpyStrategy = function(j$) { return this.getSpy(); }; + /** + * Tell the spy to return a promise resolving to the specified value when invoked. + * @name SpyStrategy#resolveValue + * @function + * @param {*} value The value to return. + */ + SpyStrategy.prototype.resolveValue = function(value) { + var Promise = j$.getPromise(); + + if (!Promise) { + throw new Error('resolveValue is unavailable because the environment does not support promises.'); + } + + this.plan = function() { + return Promise.resolve(value); + }; + return this.getSpy(); + }; + + /** + * Tell the spy to return a promise rejecting with the specified value when invoked. + * @name SpyStrategy#rejectValue + * @function + * @param {*} value The value to return. + */ + SpyStrategy.prototype.rejectValue = function(value) { + var Promise = j$.getPromise(); + + if (!Promise) { + throw new Error('rejectValue is unavailable because the environment does not support promises.'); + } + + this.plan = function() { + return Promise.reject(value); + }; + return this.getSpy(); + }; + /** * Tell the spy to throw an error when invoked. * @name SpyStrategy#throwError diff --git a/src/core/base.js b/src/core/base.js index 3a584f09..6609ef81 100644 --- a/src/core/base.js +++ b/src/core/base.js @@ -45,6 +45,10 @@ getJasmineRequireObj().base = function(j$, jasmineGlobal) { return env; }; + j$.getPromise = function() { + return j$.getEnv().getPromise() || j$.getGlobal().Promise; + }; + j$.isArray_ = function(value) { return j$.isA_('Array', value); };