Tape: Test using async/await does not end

Created on 14 Apr 2017  路  6Comments  路  Source: substack/tape

I looked at many issues in this repo, such as #222, #262, etc. but I still don't know why the following test does not end:

test('connection to database', async (assert) => {
  const res = await connectToDatabase(mongoose);
  assert.equal(res, 0, 'It should connect to the database without errors');
  assert.end();
});

when connectToDatabase is an async function.

When I run the test, I get the following result:

# connection to database
  ok 1 It should connect to the database without errors

but the test does not finish. Shouldn't assert.end() finish the test after promise resolution? What is the reason behind this behavior?

Most helpful comment

Ah - the likely issue is that one of your tests has a rejected promise, and that's causing the end never to be reached. This pattern should work:

test('async test 1', async (assert) => {
  assert.plan(1);
  try {
    const res = await someAsyncCall();
    assert.equal(res, 0);
    assert.end();
  } catch (e) {
    assert.fail(e);
  }
});

Using await forces you to use try/catch, or to .catch() on the promise that the async function returns.

All 6 comments

You can't really pass an async function to tape because tape does not do anything with the promise it returns.

You might have slightly more success though using assert.plan(1) prior to the first await.

@ljharb

You can't really pass an async function to tape because tape does not do anything with the promise it returns.

I don't understand. Why the test passes, but assert.end() does not work?

You might have slightly more success though using assert.plan(1) prior to the first await.

I tried that, but the problem didn't resolve.

Furthermore, if I add more async tests, i.e.:

test('async test 1', async (assert) => {
  const res = await someAsyncCall();
  assert.equal(res, 0);
  assert.end();
});
test('async test 2', async (assert) => {
  const res = await anotherAsyncCall();
  assert.equal(res, 0);
  assert.end();
});
test('async test 3', async (assert) => {
  const res = await yetAnotherAsyncCall();
  assert.equal(res, 0);
  assert.end();
});

only the last one doesn't finish. The others pass and finish correctly.

An async function is just sugar for a function that returns a promise.

Tape does not do anything special with promises.

Without a synchronous call to .plan(), tape can't know when your test is expected to end, so having multiple async tests like this can confuse it.

You need to only pass a function to tape, not an async function; unless you're willing to jump through all the hoops required, which includes calling .plan before the first await, in every test.

@ljharb As I said, using .plan(1) doesn't help me. Even if I call .plan(1) before each of the awaits, I still get the same result.
I think, however, this issue should be closed, as async/await and Promises are not supported by Tape (currently).

Ah - the likely issue is that one of your tests has a rejected promise, and that's causing the end never to be reached. This pattern should work:

test('async test 1', async (assert) => {
  assert.plan(1);
  try {
    const res = await someAsyncCall();
    assert.equal(res, 0);
    assert.end();
  } catch (e) {
    assert.fail(e);
  }
});

Using await forces you to use try/catch, or to .catch() on the promise that the async function returns.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

callumlocke picture callumlocke  路  4Comments

vasiliicuhar picture vasiliicuhar  路  7Comments

t3hmrman picture t3hmrman  路  7Comments

JoshuaGrams picture JoshuaGrams  路  5Comments

frankandrobot picture frankandrobot  路  4Comments