Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP

Loading…

Support for beforeAll and afterAll #56

Closed
wants to merge 1 commit into from
@fat
fat commented

This adds support for beforeAll and afterAll... something i'd really like to see (and something @jasminebdd said you were interested in)

@gmoeck

I know not having a beforeAll and afterAll encourages good habits for unit tests, but it would be quite helpful to have for integration/functional tests. +1

@fat

hm... out of curiosity, how does not having a beforeAll/afterAll encourage good habits?

@gmoeck

I think it was Roy Osherove in his book "The Art Of Unit Testing" who called using beforeAll/afterAll in a unit test a test smell. Basically his point was if your doing setup and teardown in a unit test, your not isolating a single unit, but doing an integration/functional test across multiple units.

@fat

next time i see pivot andrew or pivot Jonathan i'm going to have them attack you for not looking at either of my pull requests O_O

@infews
Owner

Point taken.

Do you want a true beforeAll that runs once? Or are you looking for a top-level beforeEach?

We're not fans of the former as it almost always drives you nuts chasing down what you thought was test pollution.

As for the latter, a beforeEach or afterEach placed in global scope does this.

Knowing this, what's your take on this pull request?

@fat

Hm... my take is that you wont' be pulling this.

@fat fat closed this
@fat

I'm sad that you tricked me though: http://cl.ly/64PF

@fat fat reopened this
@fat

feel free to close after viewing your trickery.

@james-baker

I'm surprised that this doesn't exist ('this' being "suite-level before and after"). A) Why wouldn't you allow functional tests? Is Jasmine really designed to prohibit other types of tests? or B) Even for unit tests, it's sometimes silly to insist that each each test set up and tear down its entire environment.

You can argue that question B is really just question A reframed, but... what's the benefit to trying to be more ideologically pure than RSpec?

@lroal

I really think that BeforeAll is the de-facto way og doing BDD style in unit tests. It is pathetic that jasmine doesn't support it. The BeforeAll should contain the arrange and act. The tests should only contain simple assert ( no acting!!) to verify state after the Act. If you have any kind of acting in the test methods - it is not BDD.

@garrensmith

I would really like to see this functionality added, its in RSpec and is really useful. Nothing wrong with using for functional testing

@searls

There definitely isn't currently a way to do beforeAll/afterAll cleanly. When I have some setup code that needs to run exactly once for my tests, I generally do so at the very top-level in an anonymous function. I presume a beforeAll would run exactly one time for all the specs & example groups beneath it.

That said, I'd love if someone could gist up a practical example of a clean spec that really needs this feature. One year and ~3000 Jasmine specs later and I don't think this topic has ever crossed my mind.

To @lroal's point--do you know about beforeEach? I do my arrange & act in a beforeEach and keep every it to a single line.

@lroal

I agree that doing all the setup in a top-level anonymous function will do just fine - and make the BeforeAll() redundant. Still, there is no way to do AfterAll().

@searl, a practical example where AfterAll is needed: let´s say we do a database test, perhaps with lazy loading of properties. In the AfterAll function we need to close the database connection/transaction. The BeforeAll would typical be: "When Getting A Customer From The Database". The "its" would be it("should set correct CustomerId") and it("should set correct name") .
The BeforeAll act would be composed by two steps 1) Arrange: put the fake customer data into the db 2) Act: retrieve customer from db. The AfterAll: delete the fakedata in the db, close the db connection.
(Usually, the arrange part would also contain the cleanup step to delete fake data from previous tests if the tests throw exception before reaching the AfterAll)

Yes, I do know about beforeEach. Ideally, I think the BeforeEach and AfterEach shouldn´t exist in a BDD testing framework in the first place. Because it encourages non-BDD style. After all, isn´t jasmine supposed to by BDD styled ?

@fat
fat commented

+1 to @lroal

This is made really easy with other bdd style frameworks like vows...

Set up a topic, then have several logic-less asserts executing against the topic.

doing all the setup in a top-level anonymous function will do just fine

It will work... but it's a hack and makes your spec look ugly. It also isn't really explicit what's going on to someone who isn't familiar with jasmine.

@fabiomcosta

+1! what are we waiting for? :S

@lroal

+1 @fat yes, an explicit BeforeAll() method is cleaner.

@raid5

+1 This would be really useful to cleaning my test db before/after all specs are run.

@ghost

+1000. Here is a good example of having this support.

I'm testing search functionalities (full text search) and have to upload approximately 1 000 documents into a database.

I have a lot of tests and right now I have to upload them and then there it down for all tests and that takes a lot of time.

It would be better to allow me to upload them once.

The tests are isolated since each test won't change anything but just doing a search.

So please merge this pull request.

@epeli

+1

One can do simple synchronous stuff without this, but for async setups this is really required.

Edit: Does this patch support async operations? If not, it should like the beforeEach supports with asyncSpecWait.

@jprichardson

I would also like to see this....

@jamuhl

+1

@gimmi

+1

@timoxley

Hey @pivotal, what's your status on this?

@danielstocks

Jumping the bandwagon

+1

Although a possible workaround (for now) is just to run your functions outside the describe block and access the results stored in a variable.

Or am I doing something wrong? ><

@arian

Other workaround:

describe('foo', function(){

    var _beforeAll = false;
    beforeEach(function(){
        if (_beforeAll) return;
        _beforeAll = true;
        // do your thing
    });

    it('should test things', function(){

    });

});
@pacovell

I am looking for a way to do this to integrate my Javascript tests with Browserify -- I need to start a copy of the server and pull down the server Javascript bundle, and it doesn't make sense to do this more than once. Also, I want to do this across every test in the suite, so I don't see a way to do it outside of a beforeAll/afterAll. I can prevent the server from running more than once, but I also need to shut it down when the tests are complete, and I don't see how to do that.

I see a workaround: I can start it and have every suite increment a counter in their local beforeEach and decrement in their afterEach. Yuck.

@ghost

It has gone 9 months without a close or merge.

At least comment on what you are planning to do.

@paulmillr

@pivotal ping ping ping ping ping.

@ghost

For all node.js users there is now: http://visionmedia.github.com/mocha/

It supports before() and after()

@paulmillr

@johnnywengluu thanks for info, mocha seems to be better than jasmine. And it supports node.js out-of-box.

@ghost

@paulmillr: It's written by the author of express, jade and stylus so it's rock solid.

@timoxley

+1 for mocha. DOWN WITH PIVOTAL :D

@abecciu

+1

@fat
fat commented

sorry, everyone, i'm deleting my fork of jasmine. I don't want anything to do with this project.

@fat fat closed this
@ragaskar
Owner

Apologies to fat and everyone else invested in the outcome of this thread for the lack of motion/feedback on this pull request -- most of our Jasmine efforts have been focused on making sure we work with Rails 3.1.

I don't think anyone should plan on seeing this in Jasmine any time soon, although I think we'd like to make it possible for end-users to change how Jasmine works (either via callback hooks or add-ons).

The big obstacle here is adding a beforeAll to the public interface, a feature which none of the maintainers really want to encourage or support.

@lroal

So Jasmine is integrated with the bloated Rails framework - that makes it final to me - Goodbye Jasmine. No more Jasmine , ever.

@jprichardson

@Iroal... I didn't infer that to mean that it's integrated with Rails, but rather it's just made to work with Rails. Regardless, fortunately Mocha is a suitable alternative.

@alexeypetrushin

The same, switching to mocha.

@christophersansone

I'm late to the party here, but I have the same issue in some of my specs where the setup and teardown is too expensive to execute each time. I (as well as everyone here with this issue) am smart enough to know when it makes sense to execute beforeEach vs beforeAll. If I use it incorrectly and wind up with broken specs, I have nobody to blame but myself. I would consider beforeAll / afterAll to be another tool in the toolbox to use where appropriate.

That said, here is a workaround that has suited us well. Just include these definitions in a helper file somewhere:

var beforeAll = function(fn) {
  it('[beforeAll]', fn)
}

var afterAll = function(fn) {
  it('[afterAll]', fn)
}

It is obviously a little silly, but it gets the job done for us. Just be sure the beforeAll() is at the top of your describe block, and the afterAll() is at the bottom of your describe block. If you have issues involving the order of execution between the all() and each() helpers, you should be able to resolve them using a nested describe block.

To the maintainers of jasmine: thank you for an exceptional tool. Don't let the haters get you down. Obviously you can decide what jasmine is and is not, but I still highly encourage you to implement this functionality. It is clear that a lot of people need it, and please do not infer that your user base is not smart enough to use it properly. Yes, it can cause "test smells" and it should be used with caution, but when you need it, you need it.

@infews
Owner

Thanks Christopher.

Your solution is a perfectly fine way to implement before/afterAll and doesn't add to the complexity of Jasmine core.

@dmcinnes

I'm also late to the party but I also gotta say +1 on this, there are legitimate cases where beforeAll is useful.
Christopher's solution is not ideal, it inflates the spec readout.
My problem is that I'm testing library files that I only want to load once per top level suite. I don't want them to all load at the beginning because I reset DOM and global state before every suite is loaded because I don't want stubs and other library modification to bleed into other specs (some libraries are shared between specs).

FWIW here's my MonkeyPatch -- just drop it in your global scope:

var beforeAll = function (func) {
  var beforeAllCalled = false;

  jasmine.getEnv().currentSuite.beforeEach(function () {
    if (!beforeAllCalled) {
      beforeAllCalled = true;
      func();
    }
  });
};
@timoxley

Whoaa, hang on with all that code there @dmcinnes! If a recognised leader in agile like Pivotal Labs doesn't want to take on supporting the complexity of those 9 lines of code, then why do you expect other people to? This is appalling. Do you even know what kind of work is involved @dmcinnes? Are you even agile, at all @dmcinnes???

@MarioLinden

I didn't see in any of the comments of this thread where beforeAll would be more useful:

describe('foo', function () {
  beforeAll(function () {
   // Executed only once, before all examples
  );

  beforeEach(function () {
    // Executed 4 times, once before each example
  });

  it("should foo", function () { /* test stuff */ });
  it("should foo revenge", function () { /* test stuff */ });

  describe('nested foo', function () {
      beforeAll(function () {
        // Executed only once, before all *nested* examples
      );

      beforeEach(function () {
        // Executed 2 times, once before each nested example
      });

      it("should complain...", function () { /* test stuff */ });
      it("Y U NO HAZ BEFOREALL", function () { /* test stuff */ });
  });
});

This is the same behavior as in RSpec and it allows for very flexible setup and performance

@velesin

My use case for this is testing with mongoDB (under jasmine-node).

Currently Jasmine works in such way, that mongo connection hangs and test results never gets displayed. The solution for this is to manually close connection, but it is overkill to open and close connection in beforeEach / afterEach. Collection should be emptied on beforeEach, but connection should be established and then closed only once for the whole suite, in beforeAll / afterAll.

I think this is an example of very legitimate case for having afterAll clean-up method.

@dwt

+1

@mwynholds

I needed an afterAll() for the same Mongo open connection issue as velesin and dwt. I hacked together a solution. First, all of my test files require a 'test_support.coffee' file. Then I put code similar to this in there:

timeout = null

afterAll = ->
  # do whatever you want here! it only runs once at the end.

beforeEach ->
  clearTimeout timeout if timeout?

afterEach ->
  timeout = setTimeout afterAll, 100

The beforeEach() and afterEach() handle the timing for calling afterAll(). Obviously you can put anything you want in the afterAll().

In my case, I had to close the mongodb connection (db.close()), and I also had to stop one or more express servers that had been started by supertest. And then, boom!, the test execution stops without passing --forceexit to jasmine-node.

@rhuelga

+1 for beforeAll / afterAll, I love jasmine but really thinking to switch mocha for this.

@danse

beforeAll could be also useful for asynchronous:

describe("async"
    beforeAll
        runs( ...
        waitsFor( ...

    it( 'first '
        runs(
            expects ...
    it( 'second'
        runs(
            expects ...
    it( 'third'
        runs(
            expects ...

Using beforeEach here can increase a lot the execution time.

The whole handling of this pull request on the part of the Jasmine team makes me less confident about the quality of this tool, given the huge amount of requests from the community which where ignored.

@aeischeid

+1 for adding this tool to Jasmine.

In my personal use case I think beforeAll would be merely a optionally nice way of organizing the test code, the functionality I really need is in the .afterAll()

I hope you are still open to reconsidering

@tylercloke

1+ would really be useful...

@giggio

I have put together some ideas, this is what I came up with:
https://github.com/giggio/open-store/blob/3bf0d3487ce4c92317fa3f9240ab042414090839/src/spec/support/global.coffee
It is still in the begining, but it is working.
Basically:

exports.beforeAll = (func) =>
  @beforeAllFunc = func

exports.afterAll = (func) =>
  @afterAllFunc = func

exports._setupAfterAll = ->
  runner = jasmine.getEnv().currentRunner()
  oldFinishCallback = runner.finishCallback
  self = @
  runner.finishCallback = ->
    oldFinishCallback.apply @, arguments
    self.afterAllFunc() if self.afterAllFunc

beforeEach =>
  return if @beforeAllCalled
  @beforeAllCalled = true
  exports._setupAfterAll()
  @beforeAllFunc() if @beforeAllFunc
@dankohn

Just a note that that BeforeAll is really unnecessary, since any items can be synchronously requireed at the top of a file. However, there is not substitute for AfterAll to have the ability to stop a server when doing integration or acceptance testing (in jasmine-node). Adding a timeout before closing the server is a ludicrous hack compared to just being given a notification that all tests have completed. Therefore, like many others, I'm giving up on Jasmine and switching to Mocha.

@just-boris

+1. I have setup code before all tests and teardown at end. I want to use Mockery with jasmine, and I have to enable/disable mocking before every test, instead of do it one time.

@WhatFreshHellIsThis

Someone with limited imagination or being willfully ignorant asked why anyone would need a before all: I wanted this because the Angular.js newest method of E2E testing (Protractor) uses Jasmine by default, however I need to trigger a complete reset of my database before I run my suite of Angular tests. Kind of an extremely common requirement for testing anything of modern substance.

After reading the comments here I'm guessing that Jasmine was intended for strictly browser testing and the developers are sticking their heads in the sand and covering their ears and humming to themselves so they can not hear one word about all the other, modern uses for their code (which is fully their right but it's coming across as a little childish and defensive rather than accommodating and open minded).

I'm off to figure out how to use Mocha instead of Jasmine with Protractor.

@Droogans

@WhatFreshHellIsThis I gave up on it and just used this:

describe('Something', function () {

    it('beforeAll', function () {
        // Don't assert anything
        setupDatabase();
    });

    it('should test stuff', function () {
        // ...
    });

    it('afterAll', function () {
        // Don't assert anything
        teardownDatabase();
    });

});
@aknuds1

+1. It's not uncommon to need to share a fixture between a suite of tests.

@gburghardt

I'd like to see this added as well. I'm trying to do testing in a browser environment and I am mocking AJAX calls. I really need a "beforeAll" and "afterAll" for a describe block to do all the AJAX call mocking. I really don't see this as functional testing here, because I am isolating one component -- one method in a class, actually.

This whole thread of comments on a highly requested feature is the reason I try not to adhere too strictly to ideologies. Every list of rules I make for programming has this rule at the end:

There is an exception to every rule

I think to most people, Jasmine is a general purpose testing framework first and foremost. We don't look at its utility just through the eyes of one ideology.

I'm also very seriously considering switching to Mocha.

@nonplus

FYI, the nonplus/jasmine-beforeAll library adds before/afterAll support to Jasmine (1.3.1).

@prantlf

This is all about asynchronous tests, where the JavaScript code flow cannot be used to naturally place the setUp and tearDown sections. When a temporary resource needs to be created before the first test starts and destroyed after the last one finishes, an afterAll cannot be simply worked around, There can be scenario-dependent workarounds like artificial test steps, nesting of describes, hooking into the Runner etc. but it makes understanding the test code more difficult. There should be a single way to do this and the framework should offer it. The beforeAll + afterAll plugin by nonplus (right above) is a great solution.

@paulmillr paulmillr referenced this pull request in chaplinjs/chaplin
Closed

Switch from Jasmine to Mocha + Chai #117

@armw4

This is ridiculous!! Guess I will have to join the mocha bandwagon as well.

@armw4 armw4 referenced this pull request from a commit in armw4/auth-demo
@armw4 armw4 Commit latest snapshot.
I've determined why the process blocks after all tests completes. It's
because you have to disconnect from mongodb, or the event loop with be
blocked. This makes sense, but what doesn't is why jasmine doesn't
provide hooks for beforeAll and afterAll. It's here where you'd want to
connect and disconnect from mongodb. Next step is to install the plugin
that monkey patches jasmine to provide this functionality.

* mhevery/jasmine-node#241
* https://github.com/nonplus/jasmine-beforeAll
* jasmine/jasmine#56
0e95b4d
@machineghost

To anyone considering "jumping on the bandwagon", let me just say that I switched to Mocha from Jasmine over a year ago precisely because of this ticket, and I have no regrets. I don't think I expect that much from library authors, but even so I am shocked that a library as popular as Jasmine could be this rude and non-responsive towards its user-base (and for so long!).

At this point I think all anyone can do is vote with their feet. On the plus side, at least there's a superior alternative to switch to, and because Mocha offers a BDD format switching your code over is (mostly) painless. And then once you make the switch everything just works.

@Kazark

+1. This feature is useful in the case that after you mutate state in one way, you have multiple asserts that you want to run against that one state change, and you want to spell each one out cleanly:

describe('MyAngularController', function() {
    describe('loadSuccess', function() {
        beforeAll(function() {
            controller.loadSuccess(...);
            ...
        });
        it('sets the number of items', function() {
            expect(...).toBe(6);
        });
        it('places the loaded items in scope', function() {
            expect(...).toEqual(...);
        });
        ...
    });
});

@gmoeck I fail to see how this is a smell for cases like the code above. Roy Osherove's book is good, but he is speaking of xUnit style unit testing, not Spec style. The nesting ability here is arguably more powerful and means that beforeAll does not have to be a smell.

@dtabuenc

To me in BDD-style testing the real smell is doing anything other than logic-less asserts in your "it" blocks.

Starting with a given state, performing a single action that mutates it to a new state, and then performing several read-only assertions that specify the resulting state is a very desirable pattern when doing BDD-style tests.

@Kazark

@dtabuenc Well said. I like it.

@bradgreens

+1 for beforeAll and afterAll

@Deyine

+1

@chiefy

:+1: Just ran into issue w/ using karma-jasmine and Firefox allocation overflow when loading large data structures in beforeEach.

@joaoafrmartins

+1 this breaks my mocha tests...

@samlecuyer

@joaoafrmartins I'm confused why features of jasmine break your mocha tests?

@joaoafrmartins

tests targeting mocha when run by jasmine dont work if you are using globals not defined by jasmine but defined by mocha like before and after...

@arjansingh

@joaoafrmartins

jasmine != mocha && jasmine !== mocha

They are two completely different BDD frameworks that happen to share some similar definitions.

There is no expectation or intent to make both compatible with or strictly equivalent to each other.

@joaoafrmartins

@arjansingh well... they are not completely different... and you can write the tests in a compatible way... and they have pretty much the same DSL... so... why cant we all just get along...

@JonnyRa

Well this sucks. Just started writing my first jasmine/javascript test which fires off a command which talks to the server to insert some data.

Wanted each of my tests to check specific fields go into the database ok. The call is async so I'd need to be using done so I can't write this as a top level thing. It's a little dissapointing the maintainers dont want to add a feature because of some particular dogma. Its not like there's a shortage of javascript frameworks though!

That the feature is missing is bad but that you aren't going to implement it because it isn't the one true way is much worse.

@prantlf

@JonnyRa: You can try my solution. I included the nonplus/jasmine-beforeAll extension written by @nonplus on my testing pages to get this functionality. I use Jasmine 1.3.1.

Some people here suggested switching to mocha. If you're just starting to write the tests, consider that. I myself will consider switching to mocha+chai+sinon if the beforeAll extension stops working with the next Jasmine version I upgrade to; Jasmine testing framework would become too expensive to maintain in comparison with alternatives which support beforeAll OOTB.

@JonnyRa

@prantlf I'm using jasmine-2.0

However building on @arian 's suggestion I've added the following patch to my jasmineInterface (in bootjs). Modifying the contents of this changes the global level functions that you get.

Here's my patch:

    beforeAll: function (beforeAllFunction) {
        var runSetup = false;

        return beforeEach(function (done) {
            if (runSetup) {
                done();
                return;
            }

            runSetup = true;

            beforeAllFunction(done);
        });
    },
@krisleech

Would a potential use for a global after hook be to reset configuration data after each spec to stop it leaking to other specs:

afterEach(function() {
  MyApp.config = { };
});
@princed

One more hack to hook into start and done (using fake reporter):

jasmine.getEnv().addReporter({
  jasmineStarted: function() {
    console.log('start');
  },
  jasmineDone: function() {
    console.log('done');
  }
});
@whitneyit whitneyit referenced this pull request from a commit in eslint/eslint
@whitneyit whitneyit New: Adds support for the `jasmine` env (fixes #1176) e3e55ba
@slackersoft
Owner

We've added an implementation of beforeAll and afterAll in this commit ba0982d.

@just-boris

:+1: can't belive this. Good!

@SirLenz0rlot

:+1: Great! Looking forward to the next release

@dwt
dwt commented

@maintainers: What changed your mind? I understood from previous comments that you think beforeAll/ afterAll is something a test framework should not support?

I'd really like to know, not at least so we can phrase further pull/ feature requests in a way that allows you to agree to them more easily than to this one.

@duereg

Wow

@SirLenz0rlot

Any idea when this (2.0.5?) is going to be released?

@slackersoft
Owner

We're working on getting 2.1.0 out with this feature and more, but we're doing a bit of other prep as well.

@dwt

@maintainers: can you please answer my question on what changed your mind to include this?

From your earlier comments it sounded like you didn't think this should ever be included in a testing framework, so I'd really like to know what swayed you.

@Gerg
Owner

We are planning to release a blog post explaining our decision along with 2.1.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Feb 9, 2011
  1. @fat-bot
This page is out of date. Refresh to see the latest.
View
90 spec/suites/RunnerSpec.js
@@ -13,6 +13,94 @@ describe('RunnerTest', function() {
env.clearInterval = fakeTimer.clearInterval;
});
+ describe('beforeAll', function(){
+ it('should run before all specs for a given suite', function(){
+ var foo = -1;
+ var bar = function(){
+ foo++;
+ };
+ var spy1 = jasmine.createSpy().andCallFake(bar);
+ var spy2 = jasmine.createSpy().andCallFake(bar);
+ var spy3 = jasmine.createSpy().andCallFake(bar);
+
+ env.beforeAll(spy1);
+
+ env.describe('suite 1', function () {
+ env.it('test 1-1', function() {
+ foo++;
+ this.expect(foo).toEqual(2);
+ });
+ env.it('test 1-2', function() {
+ foo++;
+ this.expect(foo).toEqual(3);
+ });
+ env.beforeAll(spy2);
+ });
+
+ env.describe('suite 2', function () {
+ env.beforeAll(spy3);
+ env.it('test 2-1', function() {
+ foo++;
+ this.expect(foo).toEqual(5);
+ });
+ });
+
+ env.currentRunner().execute();
+
+ var runnerResults = env.currentRunner().results();
+ expect(runnerResults.totalCount).toEqual(3);
+ expect(runnerResults.passedCount).toEqual(3);
+
+ expect(spy1.callCount).toEqual(1);
+ expect(spy2.callCount).toEqual(1);
+ expect(spy3.callCount).toEqual(1);
+ });
+ });
+
+ describe('afterAll', function(){
+ it('should run after all specs for a given suite', function(){
+ var foo = -1;
+ var bar = function(){
+ foo++;
+ };
+ var spy1 = jasmine.createSpy().andCallFake(bar);
+ var spy2 = jasmine.createSpy().andCallFake(bar);
+ var spy3 = jasmine.createSpy().andCallFake(bar);
+
+ env.afterAll(spy1);
+
+ env.describe('suite 1', function () {
+ env.it('test 1-1', function() {
+ foo++;
+ this.expect(foo).toEqual(0);
+ });
+ env.it('test 1-2', function() {
+ foo++;
+ this.expect(foo).toEqual(1);
+ });
+ env.afterAll(spy2);
+ });
+
+ env.describe('suite 2', function () {
+ env.afterAll(spy3);
+ env.it('test 2-1', function() {
+ foo++;
+ this.expect(foo).toEqual(3);
+ });
+ });
+
+ env.currentRunner().execute();
+
+ var runnerResults = env.currentRunner().results();
+ expect(runnerResults.totalCount).toEqual(3);
+ expect(runnerResults.passedCount).toEqual(3);
+
+ expect(spy1.callCount).toEqual(1);
+ expect(spy2.callCount).toEqual(1);
+ expect(spy3.callCount).toEqual(1);
+ });
+ });
+
describe('beforeEach', function() {
it('should run before each spec for all suites', function () {
var foo;
@@ -264,4 +352,4 @@ describe('RunnerTest', function() {
expect(suiteNames(suites)).toEqual([suite1.getFullName(), suite3.getFullName()]);
});
});
-});
+});
View
16 src/Env.js
@@ -115,6 +115,22 @@ jasmine.Env.prototype.describe = function(description, specDefinitions) {
return suite;
};
+jasmine.Env.prototype.beforeAll = function(beforeAllFunction) {
+ if (this.currentSuite) {
+ this.currentSuite.beforeAll(beforeAllFunction);
+ } else {
+ this.currentRunner_.beforeAll(beforeAllFunction);
+ }
+};
+
+jasmine.Env.prototype.afterAll = function(afterAllFunction) {
+ if (this.currentSuite) {
+ this.currentSuite.afterAll(afterAllFunction);
+ } else {
+ this.currentRunner_.afterAll(afterAllFunction);
+ }
+};
+
jasmine.Env.prototype.beforeEach = function(beforeEachFunction) {
if (this.currentSuite) {
this.currentSuite.beforeEach(beforeEachFunction);
View
15 src/Runner.js
@@ -8,6 +8,8 @@ jasmine.Runner = function(env) {
var self = this;
self.env = env;
self.queue = new jasmine.Queue(env);
+ self.beforeAll_ = [];
+ self.afterAll_ = [];
self.before_ = [];
self.after_ = [];
self.suites_ = [];
@@ -23,6 +25,16 @@ jasmine.Runner.prototype.execute = function() {
});
};
+jasmine.Runner.prototype.beforeAll = function(beforeAllFunction) {
+ beforeAllFunction.typeName = 'beforeAll';
+ this.beforeAll_.unshift(beforeAllFunction);
+};
+
+jasmine.Runner.prototype.afterAll = function(afterAllFunction) {
+ afterAllFunction.typeName = 'afterAll';
+ this.afterAll_.unshift(afterAllFunction);
+};
+
jasmine.Runner.prototype.beforeEach = function(beforeEachFunction) {
beforeEachFunction.typeName = 'beforeEach';
this.before_.splice(0,0,beforeEachFunction);
@@ -33,7 +45,6 @@ jasmine.Runner.prototype.afterEach = function(afterEachFunction) {
this.after_.splice(0,0,afterEachFunction);
};
-
jasmine.Runner.prototype.finishCallback = function() {
this.env.reporter.reportRunnerResults(this);
};
@@ -74,4 +85,4 @@ jasmine.Runner.prototype.topLevelSuites = function() {
jasmine.Runner.prototype.results = function() {
return this.queue.results();
-};
+};
View
21 src/Spec.js
@@ -201,6 +201,27 @@ jasmine.Spec.prototype.addBeforesAndAftersToQueue = function() {
for (i = 0; i < runner.after_.length; i++) {
this.queue.add(new jasmine.Block(this.env, runner.after_[i], this));
}
+
+ if (!this.suite.queue.index) {
+ for (i = 0, l = this.suite.beforeAll_.length; i < l; i++) {
+ this.queue.addBefore(new jasmine.Block(this.env, this.suite.beforeAll_[i], this));
+ }
+ if (!runner.queue.index) {
+ for (i = 0, l = runner.beforeAll_.length; i < l; i++) {
+ this.queue.addBefore(new jasmine.Block(this.env, runner.beforeAll_[i], this));
+ }
+ }
+ }
+ if (this.suite.queue.index == this.suite.queue.blocks.length - 1) {
+ for (i = 0, l = this.suite.afterAll_.length; i < l; i++) {
+ this.queue.add(new jasmine.Block(this.env, this.suite.afterAll_[i], this));
+ }
+ if (runner.queue.index == runner.queue.blocks.length - 1) {
+ for (i = 0, l = runner.afterAll_.length; i < l; i++) {
+ this.queue.add(new jasmine.Block(this.env, runner.afterAll_[i], this));
+ }
+ }
+ }
};
jasmine.Spec.prototype.explodes = function() {
View
14 src/Suite.js
@@ -14,6 +14,8 @@ jasmine.Suite = function(env, description, specDefinitions, parentSuite) {
self.queue = new jasmine.Queue(env);
self.parentSuite = parentSuite;
self.env = env;
+ self.beforeAll_ = [];
+ self.afterAll_ = [];
self.before_ = [];
self.after_ = [];
self.children_ = [];
@@ -37,6 +39,16 @@ jasmine.Suite.prototype.finish = function(onComplete) {
}
};
+jasmine.Suite.prototype.beforeAll = function(beforeAllFunction) {
+ beforeAllFunction.typeName = 'beforeAll';
+ this.beforeAll_.push(beforeAllFunction);
+};
+
+jasmine.Suite.prototype.afterAll = function(afterAllFunction) {
+ afterAllFunction.typeName = 'afterAll';
+ this.afterAll_.push(afterAllFunction);
+};
+
jasmine.Suite.prototype.beforeEach = function(beforeEachFunction) {
beforeEachFunction.typeName = 'beforeEach';
this.before_.unshift(beforeEachFunction);
@@ -79,4 +91,4 @@ jasmine.Suite.prototype.execute = function(onComplete) {
this.queue.start(function () {
self.finish(onComplete);
});
-};
+};
View
24 src/base.js
@@ -516,6 +516,28 @@ var waitsFor = function(latchFunction, optional_timeoutMessage, optional_timeout
};
/**
+ * A function that is called before all spec in a suite.
+ *
+ * Used for suite setup, including validating assumptions.
+ *
+ * @param {Function} beforeAllFunction
+ */
+var beforeAll = function(beforeAllFunction) {
+ jasmine.getEnv().beforeAll(beforeAllFunction);
+};
+
+/**
+ * A function that is called after all spec in a suite.
+ *
+ * Used for suite setup, including validating assumptions.
+ *
+ * @param {Function} afterAllFunction
+ */
+var afterAll = function(afterAllFunction) {
+ jasmine.getEnv().afterAll(afterAllFunction);
+};
+
+/**
* A function that is called before each spec in a suite.
*
* Used for spec setup, including validating assumptions.
@@ -541,7 +563,7 @@ var afterEach = function(afterEachFunction) {
* Defines a suite of specifications.
*
* Stores the description and all defined specs in the Jasmine environment as one suite of specs. Variables declared
- * are accessible by calls to beforeEach, it, and afterEach. Describe blocks can be nested, allowing for specialization
+ * are accessible by calls to beforeAll, afterAll, beforeEach, it, and afterEach. Describe blocks can be nested, allowing for specialization
* of setup in some tests.
*
* @example
Something went wrong with that request. Please try again.