Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Inner async functions screw up plan count? #420

Closed
jsumners opened this issue Jan 2, 2018 · 1 comment
Closed

Inner async functions screw up plan count? #420

jsumners opened this issue Jan 2, 2018 · 1 comment

Comments

@jsumners
Copy link
Contributor

jsumners commented Jan 2, 2018

Consider:

foo.js:

'use strict'

const test = require('tap').test

test('parent promise', async (t) => {
  const a = await (async function () { return 1 }())

  setTimeout(async () => {
    t.is(a, 1)
  }, 100)
})

Running tap foo.js will yield:

foo.js ................................................ 1/2
  not ok test count exceeds plan
    stack: |
      Timeout.setTimeout (foo.js:9:7)
    at:
      line: 9
      column: 7
      file: foo.js
      function: Timeout.setTimeout
    test: parent promise
    plan: 0
    source: |
      t.is(1, 1)

total ................................................. 1/2


  1 passing (318.045ms)
  1 failing

Hmm, let's specify a definite plan:

foo.js:

'use strict'

const test = require('tap').test

test('parent promise', async (t) => {
  t.plan(1)
  const a = await (async function () { return 1 }())

  setTimeout(async () => {
    t.is(a, 1)
  }, 100)
})

Again, running tap foo.js fails, but this time with a different error:

foo.js ..1..1
foo.js ................................................ 1/3
  parent promise
  not ok test count !== plan
    +++ found
    --- wanted
    -1
    +0
    results:
      ok: false
      count: 0
      pass: 0
      fail: 1
      bailout: false
      todo: 0
      skip: 0
      plan:
        start: 1
        end: 1
        skipAll: false
        skipReason: ''
        comment: ''
      failures:
        - tapError: incorrect number of tests

  not ok parent promise
    failures:
      - tapError: incorrect number of tests

total ................................................. 1/3


  1 passing (331.531ms)
  2 failing

This example is a bit silly, but it reproduces the scenario that is causing this error for me:

  1. Determine a free port via the get-port module
  2. child_process.fork a script that needs the determined port
  3. Run tests after the forked process issues process.send('ready'), i.e. proc.on('message', (m) => { t.is(1, 1) })

Is there a way that I should be doing this instead? I really don't want to fall back to callbacks because I'm going to have a lot of asynchronous operations to test in this test.

@isaacs
Copy link
Member

isaacs commented Jan 2, 2018

Tap is behaving as designed. Let's unpack what's going on here:

'use strict'

const test = require('tap').test

test('parent promise', async (t) => {
  const a = await (async function () { return 1 }())

  setTimeout(async () => {
    t.is(a, 1)
  }, 100)
})

An async function is a function that returns a promise. That promise resolves when all of the async function's awaited promises are resolved.

In this case, you aren't awaiting any promises in the outer async function, so the promise it returns resolves immediately. It's (roughly) equivalent to this:

'use strict'

const test = require('tap').test

test('parent promise', (t) => {
  const a = 1

  setTimeout(() => {
    t.is(a, 1)
  }, 100)

  return new Promise((resolve) => { resolve() }|)
})

The flow of events:

  1. Outer function starts
  2. Schedule a timeout for 100ms in the future
  3. Return promise
  4. Promise resolves, ending test
  5. Timeout fires, make assertion

This would work as you expect, and verify that 100ms after creating the promise, it has resolved to the expected value:

'use strict'

const test = require('tap').test

test('parent promise', (t) => {
  t.plan(1)

  ;(async function () {
    const a = await (async function () { return 1 }())

    setTimeout(() => {
      t.is(a, 1)
    }, 100)
  })()
})

You can also use the t.resolveMatch() available in tap v11 to make this even more elegant.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants