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

vi.runAllTicks() needs to be awaited but isn't "thenable" #2370

Closed
6 tasks done
mrmckeb opened this issue Nov 23, 2022 · 10 comments
Closed
6 tasks done

vi.runAllTicks() needs to be awaited but isn't "thenable" #2370

mrmckeb opened this issue Nov 23, 2022 · 10 comments
Labels
documentation Improvements or additions to documentation

Comments

@mrmckeb
Copy link

mrmckeb commented Nov 23, 2022

Describe the bug

When using vi.runAllTicks(), the microtask queue isn't exhausted unless I await the call (await vi.runAllTicks()) - but runAllTicks isn't a promise.

I may be doing something else wrong here, but have shared a minimal reproduction.

Reproduction

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

vi.useFakeTimers();

describe('Example', () => {
  it("doesn't work", () => {
    const mockFn = vi.fn();

    const fn = (): void => {
      Promise.reject().finally(mockFn);
    };

    fn();

    vi.runAllTicks();

    expect(mockFn).toHaveBeenCalledTimes(1);
  });

  it('does work', async () => {
    const mockFn = vi.fn();

    const fn = (): void => {
      Promise.reject().finally(mockFn);
    };

    fn();

    await vi.runAllTicks();

    expect(mockFn).toHaveBeenCalledTimes(1);
  });
});

System Info

System:
    OS: macOS 13.0.1
    CPU: (8) arm64 Apple M1
    Memory: 167.50 MB / 16.00 GB
    Shell: 5.8.1 - /bin/zsh
  Binaries:
    Node: 16.18.1 - ~/Library/Caches/fnm_multishells/11960_1669163219625/bin/node
    npm: 8.19.2 - ~/Library/Caches/fnm_multishells/11960_1669163219625/bin/npm
  Browsers:
    Chrome: 107.0.5304.110
    Edge: 107.0.1418.56
    Firefox: 107.0
    Safari: 16.1

Used Package Manager

pnpm

Validations

@sheremet-va
Copy link
Member

sheremet-va commented Nov 23, 2022

Well, this is how js works. Promises are resolved as microtasks at the end of the event loop, so if you have a promise like you described, a simple await will work, you can't expect it to be called synchronously. fake timers don’t change how promises work.

There is also vi.runAllTicksAsync, maybe you want to use it. There is more documentation about this in sinon docs: https://sinonjs.org/releases/latest/fake-timers/

@sheremet-va sheremet-va closed this as not planned Won't fix, can't repro, duplicate, stale Nov 23, 2022
@sheremet-va
Copy link
Member

I do think we need a better documentation about the feature though.

@sheremet-va sheremet-va reopened this Nov 23, 2022
@sheremet-va sheremet-va added the documentation Improvements or additions to documentation label Nov 23, 2022
@mrmckeb
Copy link
Author

mrmckeb commented Nov 23, 2022

Sorry, to be clear, I understand how tasks work in JavaScript and wasn't surprised that it needed to be awaited - but was confused about the implementation.

The documentation says:

Calls every microtask. These are usually queued by proccess.nextTick. This will also run all microtasks scheduled by themselves.

The documentation for the Jest equivalent says:

Exhausts the micro-task queue (usually interfaced in node via process.nextTick).

When this API is called, all pending micro-tasks that have been queued via process.nextTick will be executed. Additionally, if those micro-tasks themselves schedule new micro-tasks, those will be continually exhausted until there are no more micro-tasks remaining in the queue.

However, what I see in usage is that I can't await this method.
image

@mrmckeb mrmckeb changed the title vi.runAllTicks() needs to be awaited in some cases vi.runAllTicks() needs to be awaited but isn't thenable Nov 23, 2022
@mrmckeb mrmckeb changed the title vi.runAllTicks() needs to be awaited but isn't thenable vi.runAllTicks() needs to be awaited but isn't "thenable" Nov 23, 2022
@sheremet-va
Copy link
Member

sheremet-va commented Nov 23, 2022

needs to be awaited but isn't thenable

It doesn't need to be awaited. You can achieve the same with:

vi.runAllTicks()
await function () {}

It just waits until the end of the loop. vi.runAllTicks is not a thenable, and its implementation doesn't have any awaitable code.

As far as I know fake timers only work with nextTick microtasks, not with actual microtasks. Vitest doesn't implement anything new here. It uses the same thing as Jest uses - calls sinon's runMicrotasks:

clock.runMicrotasks()

This runs all pending microtasks scheduled with nextTick but none of the timers and is mostly useful for libraries using FakeTimers underneath and for running nextTick items without any timers.

@sheremet-va
Copy link
Member

About the Async part - I forgot that we did not merge it yet: #2209 :)

@mrmckeb
Copy link
Author

mrmckeb commented Nov 23, 2022

Thanks for the explanation. I looked for something like runAllTicksAsync but didn't find it, so that would be great.

Thanks again for your time!

@sheremet-va
Copy link
Member

I looked for something like runAllTicksAsync but didn't find it, so that would be great.

To be honest, I don't think you need it here. Fake timers process only nextTick microtasks, and you can await event queue with a simple await? Or new Promise(r => setTimeout(r))? In your example, if you didn't use runAllTicks it would still work.

@mrmckeb
Copy link
Author

mrmckeb commented Nov 23, 2022

Yes, that makes sense - awaiting anything would be enough as this is an immediately executed microtask.

@kleinfreund
Copy link
Contributor

When I only need to await anything to get the microtask queue flushed, I usually do await Promise.resolve().

@guillaumeduboc
Copy link
Contributor

@mrmckeb #2209 is now merged and released.
You can now write await vi.runAllTimersAsync(); instead

@github-actions github-actions bot locked and limited conversation to collaborators Jun 7, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
documentation Improvements or additions to documentation
Projects
None yet
Development

No branches or pull requests

4 participants