Skip to content

node test mock timer promisified setTimeout & setInterval don't always return the specified value #50307

@mika-fischer

Description

@mika-fischer

Version

v20.5.1

Platform

Microsoft Windows NT 10.0.22621.0 x64

Subsystem

test

What steps will reproduce the bug?

Mocked promisified setTimeout & setInterval don't return falsy values, and instead return numbers.

The reason for setTimeout is here. It works correctly for truthy values, but returns an id for falsy values.

setInterval completely captures the value parameter for its own purposes so that it never resturns the value given to setInterval (see here).

import assert from "node:assert";
import { test } from "node:test";
import timers from "node:timers/promises";

test("original setTimeout", async () => {
  for (const val of [true, false]) {
    const result = await timers.setTimeout(1, val);
    assert.equal(result, val);
  }
});

test("mocked setTimeout", async (context) => {
  context.mock.timers.enable();
  for (const val of [true, false]) {
    const promise = timers.setTimeout(1, val);
    context.mock.timers.tick();
    const result = await promise;
    assert.strictEqual(result, val);
  }
});

test("original setInterval", async () => {
  const iter = timers.setInterval(1, "foo");
  const result = await iter.next();
  iter.return();
  assert.deepStrictEqual(result, { done: false, value: "foo" });
});

test("mocked setInterval", async (context) => {
  context.mock.timers.enable();
  const iter = timers.setInterval(1, "foo");
  const promise = iter.next();
  context.mock.timers.tick();
  const result = await promise;
  iter.return();
  assert.deepStrictEqual(result, { done: false, value: "foo" });
});

fails with

❯ node .\index.mjs
✔ original setTimeout (6.8319ms)
✖ mocked setTimeout (2.0594ms)
  AssertionError [ERR_ASSERTION]: Expected values to be strictly equal:
  
  2 !== false
  
      at TestContext.<anonymous> (file:///C:/Users/mfischer/src/test/node-mock-timer-setTimeout/index.mjs:18:12)
      at async Test.run (node:internal/test_runner/test:581:9)
      at async Test.processPendingSubtests (node:internal/test_runner/test:325:7) {
    generatedMessage: true,
    code: 'ERR_ASSERTION',
    actual: 2,
    expected: false,
    operator: 'strictEqual'
  }

(node:38604) ExperimentalWarning: The MockTimers API is an experimental feature and might change at any time
(Use `node --trace-warnings ...` to show where the warning was created)
✔ original setInterval (2.2276ms)
✖ mocked setInterval (1.0964ms)
  AssertionError [ERR_ASSERTION]: Expected values to be strictly deep-equal:
  + actual - expected
  
    {
      done: false,
  +   value: 'foo1'
  -   value: 'foo'
    }
      at TestContext.<anonymous> (file:///C:/Users/mfischer/src/test/node-mock-timer-setTimeout/index.mjs:36:10)
      at async Test.run (node:internal/test_runner/test:581:9)
      at async Test.processPendingSubtests (node:internal/test_runner/test:325:7) {
    generatedMessage: true,
    code: 'ERR_ASSERTION',
    actual: [Object],
    expected: [Object],
    operator: 'deepStrictEqual'
  }
[...]

How often does it reproduce? Is there a required condition?

Always

What is the expected behavior? Why is that the expected behavior?

The mocked functions should return the value specified by the caller.

What do you see instead?

The mocked functions (sometimes) return something else.

Additional information

No response

Metadata

Metadata

Assignees

No one assigned

    Labels

    confirmed-bugIssues with confirmed bugs.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