34
describe('some test', function(){
    // Could put here a shared variable
    it('should pass a value', function(done){
        done(null, 1);
    });
    it('and then double it', function(value, done){
        console.log(value * 2);
        done();
    });
});

The above currently would not work in mocha.

A solution would be to have a variable shared between the tests, as shown above.

With async.waterfall() this is very possible and I really like it. Is there any way to make it happen in mocha?

Thanks!

Poni
  • 11,061
  • 25
  • 80
  • 121

3 Answers3

66

It is much preferable to keep the tests isolated so that one test does not depend on a computation performed in another. Let's call the test that should pass a value test A and the test that should get it test B. Some question to consider:

  1. Are test A and test B really two different tests? If not, they could be combined.

  2. Is test A meant to provide test B with a fixture to test against? If so, test A should become the callback for a before or beforeEach call. You basically pass the data around by assigning it to variables in the closure of describe.

    describe('some test', function(){
        var fixture;
    
        before(function(done){
            fixture = ...;
            done();
        });
    
        it('do something', function(done){
            fixture.blah(...);
            done();
        });
    });
    

I've read Mocha's code, and provided I'm not forgetting something, there is no way to call describe, it, or the done callback to pass values around. So the method above is it.

Louis
  • 146,715
  • 28
  • 274
  • 320
  • 6
    What about nested describes? I get an access token in a before() method that almost every subsequent test needs to use. – metaColin Aug 17 '15 at 21:35
13

Very much agree with what Louis said, and those are the reasons that Mocha doesn't actually support it. Think of the async method you referenced; if your first test fails you get a waterfall failure across the rest of them.

Your only way to go about it is, as you say, to stick a variable at the top:

describe('some test', function(){
    var value = 0;
    it('should pass a value', function(done){
        value = 5;
        done();
    });
    it('and then double it', function(done){
        console.log(value * 2); // 10
        done();
    });
});
whitfin
  • 4,539
  • 6
  • 39
  • 67
  • Hi, a small fix to your statement (quoting async's docs): `if any of the functions pass an error to the callback, the next function is not executed and the main callback is immediately called with the error`... But thank you though – Poni Dec 27 '13 at 12:44
  • Yeah, but the issue with that method is you then cancel any execution of the following tests altogether, rather than failing the first test and continuing onto the next stage - does that make sense? – whitfin Dec 27 '13 at 16:51
  • 1
    @AnthonyMayfield post some code? :) maybe in a gist. – whitfin Nov 15 '15 at 21:58
  • Think I've figured it out now! In your example both tests are synchronous, in my case I'm trying to update the variable after running some async. Pretty sure I need to use Mocha's after method, reading up the docs on that now. Thanks for the offer though :) – Anthony Nov 15 '15 at 22:11
  • Nope, turns out the describe suites are run in sequential order. Mystery solved! Haha – Anthony Nov 15 '15 at 22:25
  • My issue with all this is that I have each subtest (the 'it' callbacks) in separate files which I then include. It all goes well until you need to start a session, then run through a series of tests. I'd like to be able to save the session (for example using the agent feature) but it's just not possible it seems. – Spock Aug 29 '17 at 15:39
9

It is also possible to add to the suit or context object.

In this example, It's added to the suit object

describe('suit', function(){
    before(() => {
        this.suitData = 'suit';
    });

    beforeEach(() => {
        this.testData = 'test';
    });


    it('test', done => {
         console.log(this.suitData)// => suit
         console.log(this.testData)// => test
    })
});
Yaki Klein
  • 3,978
  • 3
  • 37
  • 34
  • 7
    Be aware that the `this` here is a different `this` to if you were not using arrow functions... I think. (At least, in my case, what I was trying to do didn't work, until I realized I was mixing arrow and normal functions.) mocha recommends to not use arrow functions: https://mochajs.org/#arrow-functions – Darren Cook Feb 27 '18 at 15:55
  • this is correct. This will work only with arrow functions. – Yaki Klein Jun 10 '18 at 06:35
  • And a wrap of a non-arrow function – JGleason Apr 29 '19 at 15:22