Skip to content

docs: clarify fake timer usage with user-event #1391

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

Merged
merged 4 commits into from
May 15, 2024
Merged
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 29 additions & 10 deletions docs/guides-using-fake-timers.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,13 @@ flaky.

To solve these problems, or if you need to rely on specific timestamps in your
code, most testing frameworks offer the option to replace the real timers in
your tests with fake ones. This should be used sporadically and not on a regular
basis since using it contains some overhead.
your tests with fake ones. This has a side effect - when using fake timers in
your tests, _all_ of the code inside your test uses fake timers.

When using fake timers in your tests, all of the code inside your test uses fake
timers.
This becomes apparent when using [`user-event`](user-event/intro.mdx) to test
user interactions. Internally, it uses `setTimeout` to
[`delay`](user-event/options.mdx#delay) subsequent actions and allow
asynchronous code to run between the inputs.

The common pattern to setup fake timers is usually within the `beforeEach`, for
example:
Expand All @@ -26,12 +28,10 @@ beforeEach(() => {
})
```

When using fake timers, you need to remember to restore the timers after your
test runs.

The main reason to do that is to prevent 3rd party libraries running after your
test finishes (e.g cleanup functions), from being coupled to your fake timers
and use real timers instead.
Since fake timers are mocking native timer functions, it is necessary to restore
the timers after your test runs, just like regular mocks. This prevents fake
timers leaking into other test cases and cleanup functions, where real timers
are expected.

For that you usually call `useRealTimers` in `afterEach`.

Expand All @@ -51,3 +51,22 @@ afterEach(() => {
jest.useRealTimers()
})
```

## Using fake timers together with `user-event`
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the PR @domnantas !
I do think that we shouldn't mention anything about user-event on this page though.
The reason for this is that this a "core" page.

For this PR the changes on this page can be reverted, and

Or do you see this differently @MatanBobi ?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I 100% agree with you @timdeschryver :)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should I remove

`user-event` internally uses `setTimeout` to delay subsequent actions. Using
fake timers in such tests will cause timeouts, since the `setTimeout` callbacks
do not get executed. In order to allow `user-event` to advance the fake timers,
it is necessary to set [`advanceTimers`](user-event/options.mdx#advancetimers)
option in `userEvent.setup()`:

```js
const user = userEvent.setup({advanceTimers: jest.advanceTimersByTime})
```

section entirely, or move it somewhere else?

I understand "user-event" and "core" are separate scopes, but when tests break due to fake timers, the Using fake timers page in docs is the first thing I checked. Maybe there should at least a note in this page linking to the advanceTimers option?

:::note

Using fake timers together with `user-event` may cause test timeouts. See [`advanceTimers`](user-event/options.mdx#advancetimers) option for clarification.

:::

Copy link
Member

@timdeschryver timdeschryver May 10, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it can be removed, or moved to the user-event docs at the advance timers option (but I think it already mentions it).

I like the note 👍, let's add it to the core page (and revert the other changes).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Simplified and moved the explanation to user-event/options.mdx. Left a short note on guides-using-fake-timers


`user-event` internally uses `setTimeout` to delay subsequent actions. Using
fake timers in such tests will cause timeouts, since the `setTimeout` callbacks
do not get executed. In order to allow `user-event` to advance the fake timers,
it is necessary to set [`advanceTimers`](user-event/options.mdx#advancetimers)
option in `userEvent.setup()`:

```js
const user = userEvent.setup({advanceTimers: jest.advanceTimersByTime})
```

:::caution

You may find suggestions to set `delay: null` in `userEvent.setup()` in order to
solve this issue. That is not recommended, as it may cause unexpected behaviour.

:::