Fabian
Fabian

Reputation: 407

Asynchronous Javascript code testing using Jest works when it is not supposed to

Jest's docs provides a negative example of what not to do when testing asynchronous code. I implemented it this way:

const expect = require('expect');

function fetchData(cb) {
    setTimeout(cb('peanut butter2'), 1500);
}

test('the data is peanut butter', () => {
    function callback(data) {
        expect(data).toBe('peanut butter');
    }

    fetchData(callback);
});

I ran npx jest test.js, and this was the output:

Fabians-MacBook-Pro:playground fabian$ npx jest test.js
 FAIL  ./test.js
  ✕ the data is peanut butter (6ms)

  ● the data is peanut butter

    expect(received).toBe(expected)

    Expected value to be (using Object.is):
      "peanut butter"
    Received:
      "peanut butter2"

      at callback (playground/test.js:9:22)
      at fetchData (playground/test.js:4:16)
      at Object.<anonymous>.test (playground/test.js:12:5)

Test Suites: 1 failed, 1 total
Tests:       1 failed, 1 total
Snapshots:   0 total
Time:        0.866s, estimated 1s
Ran all test suites matching /test.js/i.

I don't understand the results.

  1. Why does it work even though I didn't call done(), as Jest recommends you do for testing asynchronous code? I'm pretty sure setTimeout is asynchronous, because I tested it in a blank test script using console.log() statements, and the second one fired before the first one which was enclosed in a setTimeout function.

  2. Furthermore, the test failed in 0.866s, when my timeout was set to 1500ms. How could Jest have received the incorrect callback data (peanut butter2) when my callback should not even have been called?

Upvotes: 0

Views: 120

Answers (1)

Rhys
Rhys

Reputation: 1491

Because your test looks like it should be async, but is actually synchronous due to an error in your code.

You've got the following, which looks like it's designed to call the method cb after 1500ms, but you're calling cb immediately:

setTimeout(cb('peanut butter2'), 1500);

Which in turn passes the string into your callback function which runs the expect immediately/synchronously.

What you probably wanted was something like:

setTimeout(function() { cb('peanut butter2') }, 1500);

Or alternatively, to have setTimeout pass the arg into your cb function and call it:

setTimeout(cb, 1500, 'peanut butter2')

Which would actually call your cb function after 1500ms, as expected.

Upvotes: 1

Related Questions