6

I'm trying to generate tests dynamically using a for-loop, but the number of tests to generate is obtained from a async task. Here is my code:

var noOfTestsToRun;

before(function() {
    return someAsyncTask().then(function(result) {
        noOfTestsToRun = result;
    })
});

describe('My Test Suite', function() {
    for (var i = 0; i < noOfTestsToRun; i++) {
        it('Test ' + i, function() {
            //...
        });
    }
});

However, noOfTestsToRun = result doesn't seem to be executed when it reaches the for loop.

I was wondering if there are any solutions to this kind of problems. Thank you.

batluck
  • 61
  • 1
  • 2
  • Mehdi, the link above is about running async task before all 'it', mine is about running async task before 'describe' – batluck Jul 26 '16 at 22:56
  • Louis, it works, thank you very much. But one more question, what if I want some async task to be executed before a `describe` within another `describe`? – batluck Jul 26 '16 at 23:27
  • Execute the async code first, then define all the `mocha` stuff, like the `before`, `describe` and all. – MarcoL Jul 27 '16 at 11:10

1 Answers1

2

Pass the done callback to your before function.

var noOfTestsToRun;

before(function(done) {
    return someAsyncTask().then(function(result) {
        noOfTestsToRun = result;

        // Complete the async stuff
        done();
    })
});

describe('My Test Suite', function() {
    for (var i = 0; i < noOfTestsToRun; i++) {
        it('Test ' + i, function() {
            //...
        });
    }
});

When your async task is finished and done() is called, we are telling Mocha that the async stuff is finished and it can move on to the expectations.

UPDATE

So, your goal is to have mocha run your dynamic tests.

You can achieve that with a bit of a hack. You will need an it block to force before to execute. And within the before, you can dynamically generate it tests based on your asynchronous result.

before(function() {
    return someAsyncTask().then(function(result) {
        describe('My Test Suite (dynamic)', function() {
            for (var i = 0; i < result; i++) {
                it('Test ' + i, function() {
                    // ...
                });
            }
        });
    });
});

it('should force before to execute', function() {
    console.log('Hack to force before to execute');
});

Working pen

Prashant
  • 7,340
  • 2
  • 25
  • 24
  • Thank you for your quick reply. But it is not working. I've replaced `someAsyncTask()` with `Promise.resolve(1)` and tried your solution. `noOfTestsToRun` is still undefined when it reaches the `for` loop – batluck Jul 26 '16 at 22:48
  • 1
    Try this http://stackoverflow.com/questions/22465431/how-can-i-dynamically-generate-test-cases-in-javascript-node – Prashant Jul 26 '16 at 23:01
  • The solution above has a constant value `['nl', 'fr', 'de']` for the `forEach` to generate tests. Mine needs a value from a async task. It doesn't solve my problem. – batluck Jul 26 '16 at 23:09
  • 1
    Actually, the answer below the approved answer was the one that would work for you. I have updated the answer here for you. – Prashant Jul 27 '16 at 08:23
  • 1
    Both code snippets in this answer are wrong. The first one uses the `done` callback *and* returns a promise. It is unnecessary to use the `done` callback when returning promises. The 2nd code snippet calls `describe` and `it` from inside `before`. That's something that Mocha does not support. A tiny demo will *seem* to work but a full-fledged suite trying to use the same technique will execute tests in an unexpected way. – Louis Jul 27 '16 at 08:41
  • Mocha documentation says nesting `it` calls is a no-no. [S.O thread](https://stackoverflow.com/questions/32749262/mocha-test-case-are-nested-it-functions-kosher) – Ivan Rubinson Feb 24 '19 at 11:16
  • In modern environments you can do a top level `await` to get async data, as documented here https://mochajs.org/#dynamically-generating-tests – WickyNilliams Sep 01 '21 at 11:34