vitest-dev / vitest-dev/vitest

setInterval with 0 or negative value has unexpected behavior

Open
#3,874 0 comments 1 reaction 0 assignees View on GitHub

Nobody has claimed this yet.

pending triage
Dominant language
TypeScript
Stars
17.1k
Forks
2k
Avg merge
1d 22h
Merged PRs (30d)
94

Description

Describe the bug

Hello vitest team !

When running tests for a setInterval function with vi fake timers, I ran into some unexpected behavior with 0 or negative value.
Normally the delay is expected to be 1ms if you write a setInterval with 0 or a negative values, but in my case I just got the following behavior:

  • with 0: if I call vi.advanceTimersToNextTimer(); or vi.advanceTimersByTime(1); the set Interval just completes right away and runs all of the callbacks until clearInterval() is called, similar tovi.runAllTimers();.
  • with negative value: vi.advanceTimersToNextTimer(); works, however vi.advanceTimersByTime(1); does not, so I guess some other value is set as the timer delay.

I had already run some similar tests with setTimeout, and in this case it works perfectly as expected.

Thanks for your help !

Reproduction

This is the test file I used.

import {
  afterEach, beforeEach, describe, expect, it, vi,
} from 'vitest';

describe('set interval', () => {
  beforeEach(() => {
    vi.useFakeTimers();
  });

  afterEach(() => {
    vi.useRealTimers();
  });

  it('should set interval with 0', () => {
    let i = 0;
    const interval = setInterval(() => {
      i += 1;
      if (i === 3) { clearInterval(interval); }
    }, 0);
    expect(i).toBe(0);
    vi.advanceTimersToNextTimer(); // same result with vi.advanceTimersByTime(1);
    expect(i).toBe(1); // AssertionError: expected 3 to be 1 // Object.is equality
  });

  it('should set interval with negative value', () => {
    let i = 0;
    const interval = setInterval(() => {
      i += 1;
      if (i === 3) { clearInterval(interval); }
    }, -300);
    expect(i).toBe(0);
    vi.advanceTimersToNextTimer();
    expect(i).toBe(1); // OK
    vi.advanceTimersByTime(1);
    expect(i).toBe(2); // AssertionError: expected 1 to be 2 // Object.is equality
  });
});
System Info
System:
    OS: Windows 10 10.0.19045
    CPU: (16) x64 11th Gen Intel(R) Core(TM) i7-11850H @ 2.50GHz
    Memory: 6.54 GB / 15.67 GB
  Binaries:
    Node: 19.5.0 - C:\Program Files\nodejs\node.EXE
    npm: 9.3.1 - C:\Program Files\nodejs\npm.CMD
  npmPackages:
    @vitejs/plugin-legacy: ^2.3.1 => 2.3.1
    @vitest/coverage-istanbul: ^0.33.0 => 0.33.0
    vite: ^3.2.5 => 3.2.7
    vitest: ^0.33.0 => 0.33.0
Used Package Manager

npm

Validations

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with the supplied TypeScript reproduction and run it with vi.useFakeTimers(), comparing setInterval behavior for 0 and -300 with the setTimeout case. Trace the fake-timer interval scheduling and add regression coverage so advancing by the next timer or by 1ms produces one callback before clearInterval().

Written by the indexing model from the issue text.

Assessment

Tech stack
node.js, typescript
Domain
testing-qa
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Stale
Clarity
Clearly specified
Newbie friendliness
55/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.