0

Hei guys,

I'd like to execute this test-cases sequentially with mocha. This means using the result of a previous test for the next one. But how to do that?

describe('some test', function(){
   var x;

   it('do something', function(done){
       x = [10, 20, 30];
       done();
   });

  // dynamic test
  x.forEach(function(i){
      it('test number '+i, function(done){
        setTimeout(function(){
          done();
        }, 500);
      });
    });

    it('do something else', function(done){
        done();
    });

});

The current issue is that the forEach is always executed before x being assigned and this raise a Cannot ready property 'forEach' of undefined error.

This is the output I'd like to have:

some test:
 - do something
 - test number 1
 - test number 2
 - test number 3
 - do something else
Rocco Musolino
  • 610
  • 10
  • 22
  • Does this answer your question? [How do I dynamically generate Mocha tests in a describe()'s before() block?](https://stackoverflow.com/questions/53200246/how-do-i-dynamically-generate-mocha-tests-in-a-describes-before-block) – Malvineous Nov 21 '20 at 09:05

3 Answers3

1

The body of a describe() block is always executed immediately. This allows dynamic tests to be created (like you're trying to do), but also registers all test parts with Mocha.

However, because of this, any parts of the actual testing, like before() blocks, can't be used to configure the dynamic test setup.

Instead, you can just use this (I've also taken the liberty of rewriting the for loop into something a bit more readable, IMO):

describe('some test', function() {
  var x = [ 10, 20, 30 ];

  // dynamic test
  x.forEach(function(value, i) {
    it('test number ' + i, function(done){
      setTimeout(function(){
        done();
      }, 500);
    });
  });

  it('do something else', function(done){
      done();
  });
});

However, if it's your intention that x is somehow retrieved dynamically during testing, this won't work either, and I'm not actually sure if it's possible to create dynamic tests based on a value that itself is dynamicly generated as part of a test.

robertklep
  • 198,204
  • 35
  • 394
  • 381
  • I've updated my question, yeah the problem is that **x** is retrieved dynamically. With your code I'll still have a *cannot ready property 'forEach' of undefined* error. – Rocco Musolino May 23 '16 at 11:26
  • Is `x` going to be a one-time value that you need to retrieve (in other words: is it independent of the actual tests)? In that case, there might be a workaround. Otherwise, I don't think you can create dynamic test cases like you want, and you need to test the contents of `x` within a single `it()`. – robertklep May 23 '16 at 11:35
  • **x** is not independent from the actual tests, it would be retrieved through a REST call. Btw I've opened also an issue here: https://github.com/mochajs/mocha/issues/2277 I think it's worth a discussion.. – Rocco Musolino May 23 '16 at 11:43
1

This is not the answer you want, but I believe it's worth mentioning.

You should always strive for independent tests. Having tests depend on each other leaves you with unnecessary issues.

Just to mention a few; you'll have to deal with running tests in the right order and you'll find that when one test fails, the test dependent on the first will fail as well.

Look at this excellent answer about what makes a good unit test

Community
  • 1
  • 1
Lars de Bruijn
  • 1,430
  • 10
  • 15
0

This might be the right way to handle this. Using run with the delay option (mocha.delay() in the browser, --delay on the commandline), which allows mocha to wait to run till you call run() to tell it you're done adding tests:

describe('using asynchronously acquired data', function(){
  var x; // This is only needed if also using non-dynamically-generated tests on the same data.

  getDataFromSomewhereAsynchronously(function(data){
      x = data; // This is only needed if also using non-dynamically-generated tests on the same data.
      data.forEach(function(dataItem, index){
          it('dynamically generated test number ' + (index + 1), function(){
            assert.whateverYouDoWithThisData(dataItem);
          });
        });
      run();
    });

  it('non-dynamically-generated test using asynchronously acquired data', function() {
    assert.whateverYouNeedToCheck(x);
  });
});

Thanks @ScottFreeCode for the answer.

If your "x" data is retrieved from a test itself, the above solution wouldn't work. So a better workaround would be doing all the job inside one unique it-statement (so use a loop inside the it-statement). But in that way we'll have to deal with timeout issues probably (especially for chained REST calls). So better put a this.timeout() increasing linearly.

this.timeout(x.length * 1000); // 1 second per single-data
Rocco Musolino
  • 610
  • 10
  • 22
  • 1
    It is hard to explain in a short comment but while `delay` will make Mocha wait for `run` to start the suite and thus allows obtaining the *whole* suite asynchronously, Mocha *still* does not allow the `it` that appear inside specific `describe`s to be generated asynchronously. To put it simply: the `it`s you generate asynchronously in your code above will run *outside* the `describe` block because by the time they are registered with Mocha, Mocha will be done with the `describe`. So this solution does not work. – Louis May 24 '16 at 13:35
  • I can't edit this answer since the edit queue is full, but parts of the answer came from https://github.com/mochajs/mocha/issues/2277#issuecomment-221084392, linking as requested. – Drazisil Mar 30 '17 at 16:32