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

userEvent.click() fails when used with vi.useFakeTimers(), all available solutions are not working #3184

Closed
6 tasks done
xsjcTony opened this issue Apr 12, 2023 · 3 comments
Closed
6 tasks done

Comments

@xsjcTony
Copy link
Contributor

xsjcTony commented Apr 12, 2023

Describe the bug

I have a React component which is a timer (minimal reproduction), that starts automatically after mounted, and there's a button to RESET the timer.

In the test, I'm using vi.useFakeTimers() and await vi.advanceTimersByTimeAsync(500) to test the timer segmentally.

However, I'm not able to use await user.click() to click the button.

This is a known issue with fake timers, however, none of the existing solutions works.

None of these works

const user = userEvent.setup({
  advanceTimers: vi.advanceTimersByTime,
  // advanceTimers: vi.advanceTimersByTimeAsync
  // advanceTimers: vi.advanceTimersByTime.bind(vi)
  // advanceTimers: vi.advanceTimersByTimeAsync.bind(vi)
  // delay: null,
})

And I cannot use vi.useRealTimers() before clicking button, since it will break the fake timer to further test the component's reset functionality.


Those solutions above are all based on Jest since almost all resources on the internet are for Jest. But since I've never used Jest, so I'm not sure if it's working in Jest, and is this an issue with @testing-library/user-event or Vitest

Reproduction

https://stackblitz.com/edit/vitejs-vite-askvcq?file=src/__tests__/App.test.tsx

System Info

System:
  OS: Windows 10 10.0.22000
  CPU: (8) x64 11th Gen Intel(R) Core(TM) i5-1135G7 @ 2.40GHz
  Memory: 9.23GB / 31.69GB
Binaries:
  Node: 16.18.0 - C:\Program Files\nodejs\node.EXE
  npm: 8.19.2 - C:\Program Files\nodejs\npm.CMD
Browsers:
  Edge: Spartan (44.22000.120.0), Chromium (112.0.1722.39)
  Internet Explorer: 11.0.22000.120
npmPackages:
  @vitejs/plugin-react: ^3.1.0 => 3.1.0
  vite: ^4.2.1 => 4.2.1
  vitest: ^0.30.1 => 0.30.1
  @testing-library/jest-dom: ^5.16.5 => 5.16.5
  @testing-library/react: ^14.0.0 => 14.0.0
  @testing-library/user-event: ^14.4.3 => 14.4.3
  jsdom: ^21.1.1 => 21.1.1
  react: ^18.2.0 => 18.2.0
  react-dom: ^18.2.0 => 18.2.0

Used Package Manager

npm

Validations

@stackblitz
Copy link

stackblitz bot commented Apr 12, 2023

Fix this issue in StackBlitz Codeflow Start a new pull request in StackBlitz Codeflow.

@xsjcTony
Copy link
Contributor Author

xsjcTony commented Apr 13, 2023

Seems it's not related to Vitest, as @testing-library/react is using jest.advanceTimersByTime straight away and it's not testing-framework agnostic.

testing-library/react-testing-library#1197

One workaround could be like this:

In your test suites using fake timers

import { beforeAll, vi, describe } from 'vitest';

describe('this suite uses fake timers', () => {
  // Temporarily workaround for bug in @testing-library/react when use user-event with `vi.useFakeTimers()`
  beforeAll(() => {
    const _jest = globalThis.jest;
  
    globalThis.jest = {
      ...globalThis.jest,
      advanceTimersByTime: vi.advanceTimersByTime.bind(vi)
    };
  
    return () => void (globalThis.jest = _jest);
  });
})

@sheremet-va sheremet-va closed this as not planned Won't fix, can't repro, duplicate, stale Apr 13, 2023
@xsjcTony
Copy link
Contributor Author

Hey @sheremet-va, a simple question here that is not clear in the documentation:

Regarding vi.unstubAllGlobals(), is there any scope for it?

E.g. consider the following code

  1. Are those test suites running one by one? or in parallel?
  2. Will the teardown function for the first suite clear the global value stubbed for the whole file too? (Like is there any scope for this function)
import { beforeAll, vi, describe, it, expect } from 'vitest'

// This applies to the whole file, which is the outer scope
beforeAll(() => {
  vi.stubGlobal('innerWidth', 100)
  return () => void vi.unstubAllGlobals()
})


describe('A test suite, which is a inner scope', () => {
  // This applies only to this test suite
  beforeAll(() => {
    vi.stubGlobal('innerHeight', 200)
    return () => void vi.unstubAllGlobals() // Will this restore `innerWidth` as well?
  })

  it('is a test', () => {
    expect(window.innerHeight).toBe(200) // This is guaranteed to be true
    expect(window.innerWidth).toBe(100) // This is guaranteed to be true as well
  )}
)}


// Is my assumption correct?
describe('Another test suite, which runs after the first one OR NOT?', () => {
  it('is a test', () => {
    // This is guaranteed to be FALSE this it's cleared after the previous test suite has been done
    expect(window.innerHeight).toBe(200)
    // But what about this one? Is `innerWidth` cleared in teardown for the first suite?
    expect(window.innerWidth).toBe(100)
  )}
})

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

No branches or pull requests

2 participants