javascriptpromiseava

How can I use ava's t.throws to test the error message of a function that returns a Promise?


I have a function that returns a Promise. I want to create a test for it that requires it to reject with a specific error message in order for it to pass.

I've created some example tests to demonstrate what I mean:

import test from 'ava';

const returnsPromise = () => Promise.reject(new Error('foo'));

const awaitsPromise = async () => {
  await Promise.reject(new Error('foo'));
};

test('for comparison, t.throws works with this syntax (this passes)', async t => {
  const error = await t.throws(Promise.reject(new Error('foo')));
  t.is(error.message, 'foo');
});

test('throws works with functions that return promises (this fails)', async t => {
  const error = await t.throws(returnsPromise);
  t.is(error.message, 'foo');
});

test('throws works with async functions that await promises (this fails)', async t => {
  const error = await t.throws(awaitsPromise);
  t.is(error.message, 'foo');
});

For reference, the code for the first test is copied from this GitHub comment: https://github.com/avajs/ava/issues/1120#issuecomment-261783315

When run with ava --verbose (version 0.17.0), it gives the following output:

❯ ava --verbose test/promise.js

  √ for comparison, t.throws works with this syntax (this passes)
  × throws works with functions that return promises (this fails) Missing expected exception..
  × throws works with async functions that await promises (this fails) Missing expected exception..
Unhandled Rejection: test\promise.js
  Error: foo
    returnsPromise (test/promise.js:3:45)
    _tryBlock (node_modules/core-assert/index.js:311:5)
    _throws (node_modules/core-assert/index.js:330:12)
    Function.assert.throws (node_modules/core-assert/index.js:360:3)
    Test.<anonymous> (test/promise.js:15:25)
    Test.__dirname [as fn] (test/promise.js:14:1)



Unhandled Rejection: test\promise.js
  Error: foo
    test/promise.js:6:24
    awaitsPromise (test/promise.js:5:7)
    _tryBlock (node_modules/core-assert/index.js:311:5)
    _throws (node_modules/core-assert/index.js:330:12)
    Function.assert.throws (node_modules/core-assert/index.js:360:3)
    Test.<anonymous> (test/promise.js:20:25)
    Test.__dirname [as fn] (test/promise.js:19:1)




  2 tests failed [16:55:55]
  2 unhandled rejections


  1. throws works with functions that return promises (this fails)
  AssertionError: Missing expected exception..
    Test.<anonymous> (test/promise.js:15:25)
    Test.__dirname [as fn] (test/promise.js:14:1)


  2. throws works with async functions that await promises (this fails)
  AssertionError: Missing expected exception..
    Test.<anonymous> (test/promise.js:20:25)
    Test.__dirname [as fn] (test/promise.js:19:1)

As you can see, the first test passes, but the other two tests fail.

How can I use t.throws to test the error message of a function that returns a Promise?


Solution

  • The test that passes is of the form :

    test('...', async t => {
        const error = await t.throws(<Promise>);
        t.is(error.message, '...');
    });
    

    The two test that fail are of the form :

    test('...', async t => {
        const error = await t.throws(<Function>);
        t.is(error.message, '...');
    });
    

    Try calling the functions and passing whatever is returned to t.throws().

    eg. :

    test('throws works with functions that return promises (this fails)', async t => {
        const error = await t.throws(returnsPromise());
        t.is(error.message, 'foo');
    });