23

I've got some mocha tests that require data from prior function calls. However, because my code is using a web service, I would like it to wait for a predetermined amount of time before running the next test.

Something like this:

var global;

it('should give some info', function(done) {
  run.someMethod(param, function(err, result) {
    global = result.global
  done();
  });
});

wait(30000); // basically block it from running the next assertion

it('should give more info', function(done) {
  run.anotherMethod(global, function(err, result) {
    expect(result).to.be.an('object');
  done();
  });
});

Any ideas would be appreciated. Thanks!

Olivia Stork
  • 4,660
  • 5
  • 27
  • 40
R.A. Lucas
  • 1,121
  • 1
  • 12
  • 17

6 Answers6

28

setTimeout definitely could help, but there may be a "cleaner" way to do it.

The documentation here actually says to use this.timeout(delay) to avoid timeout errors while testing async code, so be careful.

var global;

it('should give some info', function(done) {
  run.someMethod(param, function(err, result) {
    global = result.global
  done();
  });
});

it('should give more info', function(done) {
    this.timeout(30000);

    setTimeout(function () {
      run.anotherMethod(global, function(err, result) {
        expect(result).to.be.an('object');
        done();
      });
    }, 30000);
 });
Olivia Stork
  • 4,660
  • 5
  • 27
  • 40
Flops
  • 1,410
  • 15
  • 18
  • Thanks, Flops, that'll work for now. I mis-wrote my setTimeout I realize now, when I was testing. Thanks :) – R.A. Lucas Aug 27 '14 at 22:29
  • 1
    I thought the question was about two consecutive tests preserving order? – Zlatko Aug 28 '14 at 15:10
  • Zlatko, the question was about delayed execution of next test in query. this.settimeout in this example is to avid timeout error that default is 20000 in mocha if i`m right. – Flops Aug 28 '14 at 20:10
  • "Got some mocha tests that require data from prior function calls" from the OP's question told me that he merely needed to wait for the previous test to finish, not timeout the current one. I've somehow missed the "would like to literally wait" part. Also, thanks for the comment, but it would be more visible to me if it was on the downvoted question. – Zlatko Aug 29 '14 at 20:50
  • I loved the cleanliness in the first example. Helped me a lot, thanks – kaushik94 Sep 27 '15 at 03:11
  • Is `done` needed to be set to some callback function? – ayjay Nov 30 '15 at 18:34
  • Make sure to not use an arrow function. `this` won't be what you expect inside an arrow function. https://stackoverflow.com/a/28798362/8608146 – Phani Rithvij Jun 01 '20 at 14:05
14

In my case, I was coding a RESTful API in NodeJS that was manipulating some files locally. As I was launching the tests, the API was receiving multiple requests and it makes my API manipulate, concurrently, these files in the machine, which led me to a problem.

So, I needed to put some time (1 sec was enough) between these API calls. For me, the solution was the following one:

beforeEach( async () => {
   await new Promise(resolve => setTimeout(resolve, 1000));
   console.log("----------------------");
});

Now, before each it() test, the previous function is run, and I have a sleep of 1 second between API calls.

David Corral
  • 4,085
  • 3
  • 26
  • 34
10

While this.timeout() will extend the timeout of a single test, it's not the answer to your question. this.timeout() sets the timeout of your current test.

But don't worry, you should be fine anyway. Tests are not running in parallel, they're done in series, so you should not have a problem with your global approach.

Zlatko
  • 18,936
  • 14
  • 70
  • 123
  • Actually, they run in parallel don't they? Or is parallel not the same as asynchronous? https://mochajs.org/ – jntme Aug 22 '17 at 08:35
  • 1
    You're right, parallel !== async. Mocha tests specifically, they run in series. One, than the other, than the next etc. – Zlatko Aug 23 '17 at 15:00
5

First:

This thread has great answers! I personally Liked @Flops answer (got my upvote)

Second:

To clarify this (as much as possible) here is a code sample very similar to the one I ended up with (tested and verified)

function delay(interval) 
{
   return it('should delay', done => 
   {
      setTimeout(() => done(), interval)

   }).timeout(interval + 100) // The extra 100ms should guarantee the test will not fail due to exceeded timeout
}

it('should give some info', function(done) {
  run.someMethod(param, function(err, result) {
    global = result.global
  done();
  });
});

delay(1000)

it('should give more info', function(done) {
  run.anotherMethod(global, function(err, result) {
    expect(result).to.be.an('object');
  done();
  });
});

Side note: you can also use delay functions one after another and still preserve consistency (tests order)

ymz
  • 6,602
  • 1
  • 20
  • 39
1

First of all, for proper unit testing, you should never need some sleep between tests. If you do need a sleep, this means the functions you are testing require a delay before completing its expected task, which must be handled inside that function, with some asynchronous wait or sleep. Upon exit from a function, its lifetime must end and the expected result must be acquired immediately.

Emre Tapcı
  • 1,743
  • 17
  • 16
  • I agree. If you have a UNIT test that requires a long delay that maybe it isn't really a unit test!! A Unit test should only be testing logic and limited integration between functions. You should consider mocking anything that needs to take time. – Intervalia Jul 25 '19 at 16:05
  • "You should never sleep between tests". You should never say never. I need to sleep between tests because the webservice I use has a limited number of API calls per minute. If I simply run the tests without sleeping, multiple tests will fail. Putting a sleep inside the `it()` function works, but adds 12000 ms to execution time of the function, which is simply wrong. – Thomas Wagenaar Aug 09 '20 at 13:25
  • @ThomasW Then you should add the sleep call before calling the API function, inside the test function. Not between test functions. – Emre Tapcı Aug 11 '20 at 05:24
  • As mentioned, this means I get a skewed indication of testing times. All my testing times then turn red to +12000 ms. I'd rather wait in between so the testing times do not have this bias incorporated. If there is a way to remove this from the testing results, then yes, I agree with you. – Thomas Wagenaar Aug 11 '20 at 07:11
  • @ThomasW Do you assume a particular order of test function calls? Ideally, you shouldn't. If there is no order assumed, then there are no constant "between" between calls. – Emre Tapcı Aug 11 '20 at 07:22
1

Here's another, using promises:

it('go, then stop', (done) => {
// this.skip();
go()
  .then((response) => { console.log('go was called'); return response; })
  .then(response => response.should.equal('acknowledged'))
  .then(() => new Promise(resolve => setTimeout(() => { resolve(); }, 3000)))
  .then(() => console.log('3 second wait is over'))
  .then(() => stop())
  .then(response => response.should.equal('acknowledged'))
  .then(() => done());
  }).timeout(15000);
Jeff Lowery
  • 2,492
  • 2
  • 32
  • 40