From 95cf9183f4a52c10f4f516bf2ee1aace8d5472a0 Mon Sep 17 00:00:00 2001 From: Domantas Petrauskas Date: Wed, 8 May 2024 17:09:27 +0000 Subject: [PATCH 1/4] docs: clarify fake timer usage with user-event --- docs/guides-using-fake-timers.mdx | 38 +++++++++++++++++++++++-------- 1 file changed, 28 insertions(+), 10 deletions(-) diff --git a/docs/guides-using-fake-timers.mdx b/docs/guides-using-fake-timers.mdx index 68bee9c5d..63311f7c5 100644 --- a/docs/guides-using-fake-timers.mdx +++ b/docs/guides-using-fake-timers.mdx @@ -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: @@ -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`. @@ -51,3 +51,21 @@ afterEach(() => { jest.useRealTimers() }) ``` + +## Using fake timers together with `user-event` + +`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. +::: From 66e2daecbac2bbeb561fd5fa4412c726898f6515 Mon Sep 17 00:00:00 2001 From: Domantas Petrauskas Date: Wed, 8 May 2024 17:29:40 +0000 Subject: [PATCH 2/4] format fake timer document --- docs/guides-using-fake-timers.mdx | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/docs/guides-using-fake-timers.mdx b/docs/guides-using-fake-timers.mdx index 63311f7c5..4d15ba518 100644 --- a/docs/guides-using-fake-timers.mdx +++ b/docs/guides-using-fake-timers.mdx @@ -65,7 +65,8 @@ 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. + +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. + ::: From edf5539f057d8edb26752f34dda265e01976be54 Mon Sep 17 00:00:00 2001 From: Domantas Petrauskas Date: Sat, 11 May 2024 10:07:59 +0000 Subject: [PATCH 3/4] docs: move fake timer timeout explanation from core to user-event --- docs/guides-using-fake-timers.mdx | 24 ++++-------------------- docs/user-event/options.mdx | 15 +++++++++++++-- 2 files changed, 17 insertions(+), 22 deletions(-) diff --git a/docs/guides-using-fake-timers.mdx b/docs/guides-using-fake-timers.mdx index 4d15ba518..bc7ab201e 100644 --- a/docs/guides-using-fake-timers.mdx +++ b/docs/guides-using-fake-timers.mdx @@ -13,11 +13,6 @@ code, most testing frameworks offer the option to replace the real timers in 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. -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: @@ -52,21 +47,10 @@ afterEach(() => { }) ``` -## Using fake timers together with `user-event` - -`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 +:::note -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. +Combining fake timers with `user-event` may cause test timeouts. Refer to +[`advanceTimers`](user-event/options.mdx#advancetimers) option to prevent this +issue. ::: diff --git a/docs/user-event/options.mdx b/docs/user-event/options.mdx index 13ec10768..6fa5c34eb 100644 --- a/docs/user-event/options.mdx +++ b/docs/user-event/options.mdx @@ -8,8 +8,19 @@ can be applied per [`setup()`](setup.mdx). ### advanceTimers -If you are using fake timers, you need to advance your timers when we internally -[delay](#delay) subsequent code. +`user-event` adds a [delay](#delay) between some subsequent inputs. When using +[fake timers](/guides-using-fake-timers.mdx) it is necessary to set this option +to your test runner's time advancement function. For example, +`jest.advanceTimersByTime`, `vi.advanceTimersByTime`, or `mock.timers.tick` for +`node:test`. + +:::caution + +You may find suggestions to set `delay: null` to prevent test timeouts when +using fake timers. That is not recommended, as it may cause unexpected +behaviour. Starting from v14.1, we suggest using `advanceTimers` option instead. + +::: ```ts (delay: number) => Promise | void From aded0b0cd19fc9ff5b89a69f0ea737a95b8a2ea7 Mon Sep 17 00:00:00 2001 From: Domantas Petrauskas Date: Sun, 12 May 2024 09:32:12 +0000 Subject: [PATCH 4/4] docs: give more context in advanceTimers example --- docs/user-event/options.mdx | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/docs/user-event/options.mdx b/docs/user-event/options.mdx index 6fa5c34eb..014912680 100644 --- a/docs/user-event/options.mdx +++ b/docs/user-event/options.mdx @@ -10,9 +10,11 @@ can be applied per [`setup()`](setup.mdx). `user-event` adds a [delay](#delay) between some subsequent inputs. When using [fake timers](/guides-using-fake-timers.mdx) it is necessary to set this option -to your test runner's time advancement function. For example, -`jest.advanceTimersByTime`, `vi.advanceTimersByTime`, or `mock.timers.tick` for -`node:test`. +to your test runner's time advancement function. For example: + +```js +const user = userEvent.setup({advanceTimers: jest.advanceTimersByTime}) +``` :::caution