diff --git a/lib/jasmine-core/jasmine.js b/lib/jasmine-core/jasmine.js index b723372f..59c0ed6d 100644 --- a/lib/jasmine-core/jasmine.js +++ b/lib/jasmine-core/jasmine.js @@ -71,6 +71,7 @@ var getJasmineRequireObj = (function (jasmineGlobal) { j$.SpyRegistry = jRequire.SpyRegistry(j$); j$.SpyStrategy = jRequire.SpyStrategy(j$); j$.StringMatching = jRequire.StringMatching(j$); + j$.UserContext = jRequire.UserContext(j$); j$.Suite = jRequire.Suite(j$); j$.Timer = jRequire.Timer(); j$.TreeProcessor = jRequire.TreeProcessor(); @@ -3956,7 +3957,7 @@ getJasmineRequireObj().QueueRunner = function(j$) { this.clearStack = attrs.clearStack || function(fn) {fn();}; this.onException = attrs.onException || function() {}; this.catchException = attrs.catchException || function() { return true; }; - this.userContext = attrs.userContext || {}; + this.userContext = attrs.userContext || new j$.UserContext(); this.timeout = attrs.timeout || {setTimeout: setTimeout, clearTimeout: clearTimeout}; this.fail = attrs.fail || function() {}; this.globalErrors = attrs.globalErrors || { pushListener: function() {}, popListener: function() {} }; @@ -4820,14 +4821,14 @@ getJasmineRequireObj().Suite = function(j$) { Suite.prototype.sharedUserContext = function() { if (!this.sharedContext) { - this.sharedContext = this.parentSuite ? clone(this.parentSuite.sharedUserContext()) : {}; + this.sharedContext = this.parentSuite ? this.parentSuite.clonedSharedUserContext() : new j$.UserContext(); } return this.sharedContext; }; Suite.prototype.clonedSharedUserContext = function() { - return clone(this.sharedUserContext()); + return j$.UserContext.fromExisting(this.sharedUserContext()); }; Suite.prototype.onException = function() { @@ -4879,17 +4880,6 @@ getJasmineRequireObj().Suite = function(j$) { return !args[0]; } - function clone(obj) { - var clonedObj = {}; - for (var prop in obj) { - if (obj.hasOwnProperty(prop)) { - clonedObj[prop] = obj[prop]; - } - } - - return clonedObj; - } - return Suite; }; @@ -5127,6 +5117,25 @@ getJasmineRequireObj().TreeProcessor = function() { return TreeProcessor; }; +getJasmineRequireObj().UserContext = function(j$) { + function UserContext() { + } + + UserContext.fromExisting = function(oldContext) { + var context = new UserContext(); + + for (var prop in oldContext) { + if (oldContext.hasOwnProperty(prop)) { + context[prop] = oldContext[prop]; + } + } + + return context; + }; + + return UserContext; +}; + getJasmineRequireObj().version = function() { return '2.6.4'; }; diff --git a/spec/core/QueueRunnerSpec.js b/spec/core/QueueRunnerSpec.js index 3d6a4aa3..a237135b 100644 --- a/spec/core/QueueRunnerSpec.js +++ b/spec/core/QueueRunnerSpec.js @@ -51,7 +51,7 @@ describe("QueueRunner", function() { queueRunner.execute(); var context = queueableFn1.fn.calls.first().object; - expect(context).toEqual({}); + expect(context).toEqual(new jasmineUnderTest.UserContext()); expect(queueableFn2.fn.calls.first().object).toBe(context); expect(asyncContext).toBe(context); }); @@ -565,4 +565,53 @@ describe("QueueRunner", function() { expect(completeCallback).toHaveBeenCalled(); }); }); + + describe('when user context has not been defined', function() { + beforeEach(function() { + var fn; + + this.fn = fn = jasmine.createSpy('fn1'); + this.queueRunner = new jasmineUnderTest.QueueRunner({ + queueableFns: [{ fn: fn }] + }); + }); + + it('runs the functions on the scope of a UserContext', function() { + var calls = [], + context; + + this.fn.and.callFake(function() { + context = this; + }); + + this.queueRunner.execute(); + + expect(context.constructor).toBe(jasmineUnderTest.UserContext); + }); + }); + + describe('when user context has been defined', function() { + beforeEach(function() { + var fn, context; + + this.fn = fn = jasmine.createSpy('fn1'); + this.context = context = new jasmineUnderTest.UserContext(); + this.queueRunner = new jasmineUnderTest.QueueRunner({ + queueableFns: [{ fn: fn }], + userContext: context + }); + }); + + it('runs the functions on the scope of a UserContext', function() { + var calls = [], + context; + this.fn.and.callFake(function() { + context = this; + }); + + this.queueRunner.execute(); + + expect(context).toBe(this.context); + }); + }); }); diff --git a/spec/core/SuiteSpec.js b/spec/core/SuiteSpec.js index f14d7089..ca45fe3d 100644 --- a/spec/core/SuiteSpec.js +++ b/spec/core/SuiteSpec.js @@ -141,5 +141,15 @@ describe("Suite", function() { suite.onException(new jasmineUnderTest.errors.ExpectationFailed()); expect(suite.getResult().failedExpectations).toEqual([]); - }) + }); + + describe('#sharedUserContext', function() { + beforeEach(function() { + this.suite = new jasmineUnderTest.Suite({}); + }); + + it('returns a UserContext', function() { + expect(this.suite.sharedUserContext().constructor).toBe(jasmineUnderTest.UserContext); + }); + }); }); diff --git a/spec/core/UserContextSpec.js b/spec/core/UserContextSpec.js new file mode 100644 index 00000000..f4c0f3f0 --- /dev/null +++ b/spec/core/UserContextSpec.js @@ -0,0 +1,54 @@ +describe("UserContext", function() { + it("Behaves just like an plain object", function() { + var context = new jasmineUnderTest.UserContext(), + properties = []; + + for (var prop in context) { + if (obj.hasOwnProperty(prop)) { + properties.push(prop); + } + } + + expect(properties).toEqual([]); + }); + + describe('.fromExisting', function() { + describe('when using an already built context as model', function() { + beforeEach(function() { + this.context = new jasmineUnderTest.UserContext(); + this.context.key = 'value'; + this.cloned = jasmineUnderTest.UserContext.fromExisting(this.context); + }); + + it('returns a cloned object', function() { + expect(this.cloned).toEqual(this.context); + }); + + it('does not return the same object', function() { + expect(this.cloned).not.toBe(this.context); + }); + }); + + describe('when using a regular object as parameter', function() { + beforeEach(function() { + this.context = {}; + this.value = 'value' + this.context.key = this.value; + this.cloned = jasmineUnderTest.UserContext.fromExisting(this.context); + }); + + it('returns an object with the same attributes', function() { + expect(this.cloned.key).toEqual(this.value); + }); + + it('does not return the same object', function() { + expect(this.cloned).not.toBe(this.context); + }); + + it('returns an UserContext', function() { + expect(this.cloned.constructor).toBe(jasmineUnderTest.UserContext); + }); + }); + }); +}); + diff --git a/spec/core/integration/EnvSpec.js b/spec/core/integration/EnvSpec.js index 75103ab2..ccbde18e 100644 --- a/spec/core/integration/EnvSpec.js +++ b/spec/core/integration/EnvSpec.js @@ -243,7 +243,7 @@ describe("Env integration", function() { } else { secondSpecContext = this; } - expect(this).toEqual({}); + expect(this).toEqual(new jasmineUnderTest.UserContext()); }); env.it("sync spec", function() { @@ -277,7 +277,7 @@ describe("Env integration", function() { env.beforeEach(function() { specContext = this; - expect(this).toEqual({}); + expect(this).toEqual(new jasmineUnderTest.UserContext()); }); env.it("sync spec", function(underTestCallback) { diff --git a/src/core/QueueRunner.js b/src/core/QueueRunner.js index 9cdef983..8af19fa1 100644 --- a/src/core/QueueRunner.js +++ b/src/core/QueueRunner.js @@ -19,7 +19,7 @@ getJasmineRequireObj().QueueRunner = function(j$) { this.clearStack = attrs.clearStack || function(fn) {fn();}; this.onException = attrs.onException || function() {}; this.catchException = attrs.catchException || function() { return true; }; - this.userContext = attrs.userContext || {}; + this.userContext = attrs.userContext || new j$.UserContext(); this.timeout = attrs.timeout || {setTimeout: setTimeout, clearTimeout: clearTimeout}; this.fail = attrs.fail || function() {}; this.globalErrors = attrs.globalErrors || { pushListener: function() {}, popListener: function() {} }; diff --git a/src/core/Suite.js b/src/core/Suite.js index 81827151..eecd1bb3 100644 --- a/src/core/Suite.js +++ b/src/core/Suite.js @@ -88,14 +88,14 @@ getJasmineRequireObj().Suite = function(j$) { Suite.prototype.sharedUserContext = function() { if (!this.sharedContext) { - this.sharedContext = this.parentSuite ? clone(this.parentSuite.sharedUserContext()) : {}; + this.sharedContext = this.parentSuite ? this.parentSuite.clonedSharedUserContext() : new j$.UserContext(); } return this.sharedContext; }; Suite.prototype.clonedSharedUserContext = function() { - return clone(this.sharedUserContext()); + return j$.UserContext.fromExisting(this.sharedUserContext()); }; Suite.prototype.onException = function() { @@ -147,17 +147,6 @@ getJasmineRequireObj().Suite = function(j$) { return !args[0]; } - function clone(obj) { - var clonedObj = {}; - for (var prop in obj) { - if (obj.hasOwnProperty(prop)) { - clonedObj[prop] = obj[prop]; - } - } - - return clonedObj; - } - return Suite; }; diff --git a/src/core/UserContext.js b/src/core/UserContext.js new file mode 100644 index 00000000..3b82ce8e --- /dev/null +++ b/src/core/UserContext.js @@ -0,0 +1,18 @@ +getJasmineRequireObj().UserContext = function(j$) { + function UserContext() { + } + + UserContext.fromExisting = function(oldContext) { + var context = new UserContext(); + + for (var prop in oldContext) { + if (oldContext.hasOwnProperty(prop)) { + context[prop] = oldContext[prop]; + } + } + + return context; + }; + + return UserContext; +}; diff --git a/src/core/requireCore.js b/src/core/requireCore.js index 57831e78..b72caac7 100644 --- a/src/core/requireCore.js +++ b/src/core/requireCore.js @@ -49,6 +49,7 @@ var getJasmineRequireObj = (function (jasmineGlobal) { j$.SpyRegistry = jRequire.SpyRegistry(j$); j$.SpyStrategy = jRequire.SpyStrategy(j$); j$.StringMatching = jRequire.StringMatching(j$); + j$.UserContext = jRequire.UserContext(j$); j$.Suite = jRequire.Suite(j$); j$.Timer = jRequire.Timer(); j$.TreeProcessor = jRequire.TreeProcessor();