diff --git a/spec/core/SuiteSpec.js b/spec/core/SuiteSpec.js index be884a20..38ada7d6 100644 --- a/spec/core/SuiteSpec.js +++ b/spec/core/SuiteSpec.js @@ -52,6 +52,31 @@ describe("Suite", function() { expect(suite.beforeFns).toEqual([innerBefore, outerBefore]); }); + it("runs beforeAll functions in order of needed execution", function() { + var env = new j$.Env(), + fakeQueueRunner = jasmine.createSpy('fake queue runner'), + suite = new j$.Suite({ + env: env, + description: "I am a suite", + queueRunner: fakeQueueRunner + }), + firstBefore = jasmine.createSpy('outerBeforeAll'), + lastBefore = jasmine.createSpy('insideBeforeAll'), + fakeIt = {execute: jasmine.createSpy('it'), isExecutable: function() { return true; } }; + + suite.beforeAll(firstBefore); + suite.beforeAll(lastBefore); + suite.addChild(fakeIt); + + suite.execute(); + var suiteFns = fakeQueueRunner.calls.mostRecent().args[0].fns; + + suiteFns[0](); + expect(firstBefore).toHaveBeenCalled(); + suiteFns[1](); + expect(lastBefore).toHaveBeenCalled(); + }); + it("adds after functions in order of needed execution", function() { var env = new j$.Env(), suite = new j$.Suite({ @@ -67,6 +92,31 @@ describe("Suite", function() { expect(suite.afterFns).toEqual([innerAfter, outerAfter]); }); + it("runs afterAll functions in order of needed execution", function() { + var env = new j$.Env(), + fakeQueueRunner = jasmine.createSpy('fake queue runner'), + suite = new j$.Suite({ + env: env, + description: "I am a suite", + queueRunner: fakeQueueRunner + }), + firstAfter = jasmine.createSpy('outerAfterAll'), + lastAfter = jasmine.createSpy('insideAfterAll'), + fakeIt = {execute: jasmine.createSpy('it'), isExecutable: function() { return true; } }; + + suite.afterAll(firstAfter); + suite.afterAll(lastAfter); + suite.addChild(fakeIt); + + suite.execute(); + var suiteFns = fakeQueueRunner.calls.mostRecent().args[0].fns; + + suiteFns[1](); + expect(firstAfter).toHaveBeenCalled(); + suiteFns[2](); + expect(lastAfter).toHaveBeenCalled(); + }); + it("can be disabled", function() { var env = new j$.Env(), fakeQueueRunner = jasmine.createSpy('fake queue runner'), @@ -85,7 +135,7 @@ describe("Suite", function() { expect(fakeQueueRunner).not.toHaveBeenCalled(); }); - it("delegates execution of its specs and suites", function() { + it("delegates execution of its specs, suites, beforeAlls, and afterAlls", function() { var env = new j$.Env(), parentSuiteDone = jasmine.createSpy('parent suite done'), fakeQueueRunnerForParent = jasmine.createSpy('fake parent queue runner'), @@ -101,22 +151,59 @@ describe("Suite", function() { queueRunner: fakeQueueRunner }), fakeSpec1 = { - execute: jasmine.createSpy('fakeSpec1') - }; + execute: jasmine.createSpy('fakeSpec1'), + isExecutable: function() { return true; } + }, + beforeAllFn = jasmine.createSpy('beforeAll'), + afterAllFn = jasmine.createSpy('afterAll'); spyOn(suite, "execute"); parentSuite.addChild(fakeSpec1); parentSuite.addChild(suite); + parentSuite.beforeAll(beforeAllFn); + parentSuite.afterAll(afterAllFn); parentSuite.execute(parentSuiteDone); var parentSuiteFns = fakeQueueRunnerForParent.calls.mostRecent().args[0].fns; parentSuiteFns[0](); - expect(fakeSpec1.execute).toHaveBeenCalled(); + expect(beforeAllFn).toHaveBeenCalled(); parentSuiteFns[1](); + expect(fakeSpec1.execute).toHaveBeenCalled(); + parentSuiteFns[2](); expect(suite.execute).toHaveBeenCalled(); + parentSuiteFns[3](); + expect(afterAllFn).toHaveBeenCalled(); + }); + + it("does not run beforeAll or afterAll if there are no child specs to run", function() { + var env = new j$.Env(), + fakeQueueRunnerForParent = jasmine.createSpy('fake parent queue runner'), + fakeQueueRunnerForChild = jasmine.createSpy('fake child queue runner'), + parentSuite = new j$.Suite({ + env: env, + description: "I am a suite", + queueRunner: fakeQueueRunnerForParent + }), + childSuite = new j$.Suite({ + env: env, + description: "I am a suite", + queueRunner: fakeQueueRunnerForChild, + parentSuite: parentSuite + }), + spec1 = new j$.Spec({expectationFactory: function() {}}), + spec2 = new j$.Spec({expectationFactory: function() {}}), + beforeAllFn = jasmine.createSpy('beforeAll'), + afterAllFn = jasmine.createSpy('afterAll'); + + parentSuite.addChild(childSuite); + parentSuite.addChild(spec1); + childSuite.addChild(spec1); + + parentSuite.execute(); + expect(fakeQueueRunnerForParent).toHaveBeenCalledWith(jasmine.objectContaining({fns: []})); }); it("calls a provided onStart callback when starting", function() { @@ -130,7 +217,8 @@ describe("Suite", function() { queueRunner: fakeQueueRunner }), fakeSpec1 = { - execute: jasmine.createSpy('fakeSpec1') + execute: jasmine.createSpy('fakeSpec1'), + isExecutable: function() { return true; } }; suite.execute(); diff --git a/spec/core/integration/EnvSpec.js b/spec/core/integration/EnvSpec.js index 3aef1360..668d0db6 100644 --- a/spec/core/integration/EnvSpec.js +++ b/spec/core/integration/EnvSpec.js @@ -165,6 +165,77 @@ describe("Env integration", function() { env.execute(); }); + it("calls associated beforeAlls/afterAlls only once per suite", function(done) { + var env = new j$.Env(), + before = jasmine.createSpy('beforeAll'), + after = jasmine.createSpy('afterAll'); + + env.addReporter({ + jasmineDone: function() { + expect(after).toHaveBeenCalled(); + expect(after.calls.count()).toBe(1); + expect(before.calls.count()).toBe(1); + done(); + } + }); + + env.describe("with beforeAll and afterAll", function() { + env.it("spec", function() { + expect(before).toHaveBeenCalled(); + expect(after).not.toHaveBeenCalled(); + }); + + env.it("another spec", function() { + expect(before).toHaveBeenCalled(); + expect(after).not.toHaveBeenCalled(); + }); + + env.beforeAll(before); + env.afterAll(after); + }); + + env.execute(); + }); + + it("calls associated beforeAlls/afterAlls only once per suite for async", function(done) { + var env = new j$.Env(), + before = jasmine.createSpy('beforeAll'), + after = jasmine.createSpy('afterAll'); + + env.addReporter({ + jasmineDone: function() { + expect(after).toHaveBeenCalled(); + expect(after.calls.count()).toBe(1); + expect(before.calls.count()).toBe(1); + done(); + } + }); + + env.describe("with beforeAll and afterAll", function() { + env.it("spec", function() { + expect(before).toHaveBeenCalled(); + expect(after).not.toHaveBeenCalled(); + }); + + env.it("another spec", function() { + expect(before).toHaveBeenCalled(); + expect(after).not.toHaveBeenCalled(); + }); + + env.beforeAll(function(beforeCallbackUnderTest) { + before(); + beforeCallbackUnderTest(); + }); + + env.afterAll(function(afterCallbackUnderTest) { + after(); + afterCallbackUnderTest(); + }); + }); + + env.execute(); + }); + it("Allows specifying which specs and suites to run", function(done) { var env = new j$.Env(), calls = [], diff --git a/src/core/Env.js b/src/core/Env.js index fc2fd27f..682a3923 100644 --- a/src/core/Env.js +++ b/src/core/Env.js @@ -324,10 +324,18 @@ getJasmineRequireObj().Env = function(j$) { currentSuite.beforeEach(beforeEachFunction); }; + this.beforeAll = function(beforeAllFunction) { + currentSuite.beforeAll(beforeAllFunction); + }; + this.afterEach = function(afterEachFunction) { currentSuite.afterEach(afterEachFunction); }; + this.afterAll = function(afterAllFunction) { + currentSuite.afterAll(afterAllFunction); + }; + this.pending = function() { throw j$.Spec.pendingSpecExceptionMessage; }; diff --git a/src/core/Spec.js b/src/core/Spec.js index 94c51522..0e1135f7 100644 --- a/src/core/Spec.js +++ b/src/core/Spec.js @@ -105,6 +105,10 @@ getJasmineRequireObj().Spec = function(j$) { } }; + Spec.prototype.isExecutable = function() { + return !this.disabled && !this.markedPending; + }; + Spec.prototype.getFullName = function() { return this.getSpecName(this); }; diff --git a/src/core/Suite.js b/src/core/Suite.js index 4b5e573d..ebdc9c4a 100644 --- a/src/core/Suite.js +++ b/src/core/Suite.js @@ -10,6 +10,8 @@ getJasmineRequireObj().Suite = function() { this.beforeFns = []; this.afterFns = []; + this.beforeAllFns = []; + this.afterAllFns = []; this.queueRunner = attrs.queueRunner || function() {}; this.disabled = false; @@ -41,10 +43,18 @@ getJasmineRequireObj().Suite = function() { this.beforeFns.unshift(fn); }; + Suite.prototype.beforeAll = function(fn) { + this.beforeAllFns.push(fn); + }; + Suite.prototype.afterEach = function(fn) { this.afterFns.unshift(fn); }; + Suite.prototype.afterAll = function(fn) { + this.afterAllFns.push(fn); + }; + Suite.prototype.addChild = function(child) { this.children.push(child); }; @@ -58,8 +68,18 @@ getJasmineRequireObj().Suite = function() { var allFns = []; - for (var i = 0; i < this.children.length; i++) { - allFns.push(wrapChildAsAsync(this.children[i])); + if (this.isExecutable()) { + for (var b = 0; b < this.beforeAllFns.length; b++) { + allFns.push(this.beforeAllFns[b]); + } + + for (var i = 0; i < this.children.length; i++) { + allFns.push(wrapChildAsAsync(this.children[i])); + } + + for (var a = 0; a < this.afterAllFns.length; a++) { + allFns.push(this.afterAllFns[a]); + } } this.onStart(this); @@ -82,6 +102,17 @@ getJasmineRequireObj().Suite = function() { } }; + Suite.prototype.isExecutable = function() { + var foundActive = false; + for(var i = 0; i < this.children.length; i++) { + if(this.children[i].isExecutable()) { + foundActive = true; + break; + } + } + return foundActive; + }; + return Suite; };