42

Unless I'm misunderstanding something, the resolves and rejects (https://facebook.github.io/jest/docs/expect.html#resolves) won't be available until vNext. What is the recommended way now/in the meantime to test promises with Jest? Is it just putting expects in the thens and catches?

For example:

describe('Fetching', () => {
    const filters = {
        startDate: '2015-09-01'
    };
    const api = new TestApiTransport();

    it('should reject if no startdate is given', () => {
        MyService.fetch().catch(e => expect(e).toBeTruthy()); // see rejects/resolves in v20+
    });            

    it('should return expected data', () => {
        MyService.fetch(filters, null, api).then(serviceObjects => {
            expect(serviceObjects).toHaveLength(2);
        }).catch(e => console.log(e));
    });            
});

UPDATE 15 June 2019: Not too long after I posted this question, Jest started supporting this out of the box. I changed the accepted answer below to reflect the currently best way to do this.

UPDATE 8 Dec 2021: At some point Jest started supporting async/await. So while other methods noted work, I've taken to simply (for most cases) using something like:

it('should do something', async () => {
    const expected = true; 
    expect(await funcToTest()).toEqual(expected);
});

As with most cases, async/await is much more readable than alternatives. The only case I use resolves or rejects now is for simple cases like:

it('should not throw when doing something', async () => {
    await expect(funcToTest()).resolves.not.toThrow();
});

it('should throw when something is wrong', async () => {
    await expect(funcToTest()).rejects.toThrow();
});
Ambrose Little
  • 2,111
  • 2
  • 15
  • 15

4 Answers4

47

Nowadays you can write it in this way as well: docs

describe('Fetching', () => {
    const filters = {
        startDate: '2015-09-01'
    };
    const api = new TestApiTransport(); 

 it('should reject if no startdate is given', () => {
   expect.assertions(1);
   return expect(MyService.fetch()).rejects.toEqual({
     error: 'Your code message',
   });
 });          


 it('should return expected data', () => {
   expect.assertions(1);
   return expect(MyService.fetch(filters, null, api)).resolves.toEqual(extectedObjectFromApi);
 });            
});

Update (06.01.2019)

Agree that the accepted answer doesn't work correctly as line expect.assertions(1); does all the magic. Link to docs

expect.assertions(number) verifies that a certain number of assertions are called during a test. This is often useful when testing asynchronous code, in order to make sure that assertions in a callback actually got called.

So putting this line at the top will control that the specific number of assertions are made by the time when the test is run.

Yevhenii Herasymchuk
  • 2,047
  • 15
  • 20
17

Either return a promise and expect in the resolve or catch

describe('Fetching', () = > {
  const filters = {
    startDate: '2015-09-01'
  };
  const api = new TestApiTransport();
  it('should reject if no startdate is given', () = > {
    return MyService.fetch()
      .catch (e => expect(e).toBeTruthy()); // see rejects/resolves in v20+
  });
  it('should return expected data', () = > {
    return MyService.fetch(filters, null, api)
      .then(serviceObjects => {
        expect(serviceObjects).toHaveLength(2);
      })
  });
});

or using async/await

describe('Fetching', () = > {
  const filters = {
    startDate: '2015-09-01'
  };
  const api = new TestApiTransport();
  it('should reject if no startdate is given', async() = > {
    try {
      const r = await MyService.fetch()
    } catch (e) {
      expect(e).toBeTruthy()
    }
  });
  it('should return expected data', async() = > {
    const serviceObjects = await MyService.fetch(filters, null, api)
    expect(serviceObjects).toHaveLength(2);
  });
});
Benno
  • 3,008
  • 3
  • 26
  • 41
Andreas Köberle
  • 106,652
  • 57
  • 273
  • 297
  • you have to return the promise. Updated my answer with your example – Andreas Köberle Mar 27 '17 at 13:56
  • 1
    Thanks. I added the returns for now. I don't see a different results, but I'm assuming that lets the framework know to wait to resolve or something? – Ambrose Little Mar 27 '17 at 16:11
  • Why does my test still pass but I get a red message saying the expect did not work? I get all tests passing but the result is false to my then expect. – mjwrazor Jun 02 '17 at 19:09
  • Sounds like the expect is called after the test is finished. Please ask a new question for your specific problem – Andreas Köberle Jun 02 '17 at 19:45
  • 1
    For using `async` I'm pretty sure you need to use the `done()` function and call it manually. – bilby91 Jul 05 '17 at 04:25
  • This will only run the error expectation if the code under test does actually throw an error - if the code is broken, and for whatever reason an exception isn't thrown, the expectation won't run. Yevhenii's answer below avoids this. – Simon Robb Jul 25 '18 at 18:21
  • 1
    you should add `expect.assertions(1)` at the beginning of reject test. Because the test will pass no matter if the `fetch` fail or not. – Boaz Nov 09 '18 at 12:28
  • async/await rocks :) – Chen Ni Feb 23 '22 at 08:39
1

I was able to test JEST with AXIOS for HTTP REST calls like this.

it('has an API worth testing', async () => {
  let httpResult = null;
  await callThefunctionThatReturnsPromiseToMakeTheAxiosApiCall()
    .then(function(result) {httpResult=result;})
    .catch(function(err) {httpResult=err;});
  expect(httpResult.data.myData).toBe("myExpectedValue");
});

or

it('has an API worth testing', async () => {
  let httpResult = await callThefunctionThatReturnsPromiseToMakeTheAxiosApiCall();
  expect(httpResult.data.myData).toBe("myExpectedValue");
});
Sagan
  • 2,033
  • 2
  • 14
  • 12
1

For additional Jest matchers maintained by the Jest Community check out jest-extended.

https://jestjs.io/docs/expect

Using jest-extended you can expect your promise toResolve() or toReject(). Then you can expect the result or the error to match something. For example:

test('OK status', async () => {
  const request = fetch(...)
  await expect(request).toResolve() // First, make sure it resolves
  const data = await request
  expect(data).toEqual(...) // Then test the result
})
test('ERROR status', async () => {
  const request = fetch(...)
  await expect(request).toReject() // First, make sure it rejects
  await request.catch((error) => expect(error).toBe('...')) // Then test the error
})
Mir-Ismaili
  • 13,974
  • 8
  • 82
  • 100