Skip to content

Planned assertion count / Hook into timeout? (for testing runtime) #44125

Closed
@markwylde

Description

@markwylde

What is the problem this feature will solve?

When writing tests, I really like the plan function in tape.

In summary it lets you specify how many assertions you expect to have, then the test will fail if there are fewer/more than planned.

I'm really loving the new built in testing runtime, but I'm really missing plan. So I've built a wrapper around assert that implements the plan function in a similar way.

import assertPlan from 'assert-plan';

test('test 1 assertion', async t => {
  const assert = assertPlan(1);

  assert.strictEqual(1, 1);

  await assert.wait();
});

https://github.com/markwylde/assert-plan#example-usage

It's working really well, but there's a problem when the test timesout. I would like to log out the test timed out due to not receiving enough planned assertions.

To get around this I have to provide two timeouts, as below: (it works, but it's not very nice):

For example

Notes:

  • You can see there is a top timeout of 2000ms, then the assert will timeout at 1500ms.
  • When the assertPlan times out, it throws and error that is outputted to the user.
  • this test will hang because it's expecting 2 asserions
  • it only receives 1 assertion, therefore throws after 1500
test('test 2 assertions will timeout', { timeout: 2000 }, async t => {
  const assert = assertPlan(2, { timeout: 1500 });

  assert.strictEqual(1, 1);

  await assert.wait();
});

What is the feature you are proposing to solve the problem?

I think there's probably an obvious existing solution, or I'm trying to solve something in a strange way. So I'm really open to criticism on my approach. But some ideas off the top of my head are:

Proposal 1 - expose the timeout on t

test('test 2 assertions will timeout', { timeout: 2000 }, async t => {
  const assert = assertPlan(2, { timeout: t.timeout });
});

Proposal 2 - expose an event when a test timesout

test('test 2 assertions will timeout', { timeout: 2000 }, async t => {
  const assert = assertPlan(2);
  t.onTimeout(assert.cancel);
});

Proposal 3 - test timeout hook

import { onTimeout } from 'node:test';

// triggered anytime a test times out
onTimeout((testFunction) => {
  assertPlan.outputPendingAssertPlans();
});

test('test 2 assertions will timeout', { timeout: 2000 }, async t => {
  const assert = assertPlan(2);
  t.onTimeout(assert.cancel);
});

What alternatives have you considered?

I originally thought if we could add a plan function to the test runtime, like tape does:

For example:

import assertPlan from 'assert-plan';

test('test 2 assertions will timeout', { timeout: 2000 }, async t => {
  t.plan(2);
 assert(1 + 1, 2, '1+1=2');
});

But it breaks the cleanest of the test module, and how it's not coupled with assert at all. So I feel the right solution is to wrap/use an alternative assert library.

Maybe we could add a plan to the assert module, but you could be running multiple tests in parallel and assert wouldn't have a way of accumulating counts for just the specific test you are running.

You could make assert a constructor, but even then the problem of how to timeout the wait when the test timeouts still exists.

Thank you for humoring my idea and sorry if there is some really obvious stuff I'm missing here.

Metadata

Metadata

Assignees

No one assigned

    Labels

    feature requestIssues that request new features to be added to Node.js.test_runnerIssues and PRs related to the test runner subsystem.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions