Skip to content

Commit 1928ec5

Browse files
committed
remove default timer mode, add flow types
export other timer helpers, adjust tests and docs
1 parent c433020 commit 1928ec5

File tree

7 files changed

+46
-74
lines changed

7 files changed

+46
-74
lines changed

src/__tests__/timerUtils.js

Lines changed: 5 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,14 @@
1-
import { setTimeout } from '../helpers/getTimerFuncs';
1+
// @flow
2+
3+
import { setTimeout } from '../helpers/timers';
24

35
const TimerMode = {
4-
Default: 'default',
56
Legacy: 'legacy',
67
Modern: 'modern', // broken for now
78
};
89

9-
function setupFakeTimers(fakeTimerType) {
10-
switch (fakeTimerType) {
11-
case TimerMode.Legacy:
12-
case TimerMode.Modern: {
13-
jest.useFakeTimers(fakeTimerType);
14-
break;
15-
}
16-
case TimerMode.Default:
17-
default: {
18-
jest.useFakeTimers();
19-
}
20-
}
21-
}
22-
23-
async function sleep(ms) {
10+
async function sleep(ms: number): Promise<void> {
2411
return new Promise((resolve) => setTimeout(resolve, ms));
2512
}
2613

27-
export { TimerMode, setupFakeTimers, sleep };
14+
export { TimerMode, sleep };

src/__tests__/timers.test.js

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
import waitFor from '../waitFor';
2-
import { TimerMode, setupFakeTimers } from './timerUtils';
2+
import { TimerMode } from './timerUtils';
33

4-
describe.each([TimerMode.Default, TimerMode.Legacy])(
4+
describe.each([TimerMode.Legacy, TimerMode.Modern])(
55
'%s fake timers tests',
66
(fakeTimerType) => {
7-
beforeEach(() => setupFakeTimers(fakeTimerType));
7+
beforeEach(() => {
8+
jest.useFakeTimers(fakeTimerType);
9+
});
810

911
test('it successfully runs tests', () => {
1012
expect(true).toBeTruthy();

src/__tests__/waitFor.test.js

Lines changed: 8 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
import * as React from 'react';
33
import { Text, TouchableOpacity, View } from 'react-native';
44
import { fireEvent, render, waitFor } from '..';
5-
import { TimerMode, setupFakeTimers, sleep } from './timerUtils';
5+
import { TimerMode } from './timerUtils';
66

77
class Banana extends React.Component<any> {
88
changeFresh = () => {
@@ -77,13 +77,13 @@ test('waits for element with custom interval', async () => {
7777
// suppress
7878
}
7979

80-
expect(mockFn).toHaveBeenCalledTimes(3);
80+
expect(mockFn).toHaveBeenCalledTimes(2);
8181
});
8282

83-
test.each([TimerMode.Default, TimerMode.Legacy])(
83+
test.each([TimerMode.Legacy, TimerMode.Modern])(
8484
'waits for element until it stops throwing using %s fake timers',
8585
async (fakeTimerType) => {
86-
setupFakeTimers(fakeTimerType);
86+
jest.useFakeTimers(fakeTimerType);
8787
const { getByText, queryByText } = render(<BananaContainer />);
8888

8989
fireEvent.press(getByText('Change freshness!'));
@@ -96,10 +96,10 @@ test.each([TimerMode.Default, TimerMode.Legacy])(
9696
}
9797
);
9898

99-
test.each([TimerMode.Default, TimerMode.Legacy])(
99+
test.each([TimerMode.Legacy, TimerMode.Modern])(
100100
'waits for assertion until timeout is met with %s fake timers',
101101
async (fakeTimerType) => {
102-
setupFakeTimers(fakeTimerType);
102+
jest.useFakeTimers(fakeTimerType);
103103

104104
const mockFn = jest.fn(() => {
105105
throw Error('test');
@@ -115,10 +115,10 @@ test.each([TimerMode.Default, TimerMode.Legacy])(
115115
}
116116
);
117117

118-
test.each([TimerMode.Default, TimerMode.Legacy])(
118+
test.each([TimerMode.Legacy, TimerMode.Legacy])(
119119
'awaiting something that succeeds before timeout works with %s fake timers',
120120
async (fakeTimerType) => {
121-
setupFakeTimers(fakeTimerType);
121+
jest.useFakeTimers(fakeTimerType);
122122

123123
let calls = 0;
124124
const mockFn = jest.fn(() => {
@@ -137,30 +137,3 @@ test.each([TimerMode.Default, TimerMode.Legacy])(
137137
expect(mockFn).toHaveBeenCalledTimes(3);
138138
}
139139
);
140-
141-
// this test leads to a console error: Warning: You called act(async () => ...) without await, but does not fail the test
142-
// it is included to show that the previous approach of faking modern timers still works
143-
// the gotcha is that the try catch will fail to catch the final error, which is why we need to stop throwing
144-
test('non-awaited approach is not affected by fake modern timers', async () => {
145-
setupFakeTimers(TimerMode.Modern);
146-
147-
let calls = 0;
148-
const mockFn = jest.fn(() => {
149-
calls += 1;
150-
if (calls < 3) {
151-
throw Error('test');
152-
}
153-
});
154-
155-
try {
156-
waitFor(() => mockFn(), { timeout: 400, interval: 200 });
157-
} catch (e) {
158-
// suppress
159-
}
160-
jest.advanceTimersByTime(400);
161-
expect(mockFn).toHaveBeenCalledTimes(0);
162-
163-
jest.useRealTimers();
164-
await sleep(500);
165-
expect(mockFn).toHaveBeenCalledTimes(3);
166-
});

src/__tests__/waitForElementToBeRemoved.test.js

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
import React, { useState } from 'react';
33
import { View, Text, TouchableOpacity } from 'react-native';
44
import { render, fireEvent, waitForElementToBeRemoved } from '..';
5-
import { TimerMode, setupFakeTimers } from './timerUtils';
5+
import { TimerMode } from './timerUtils';
66

77
const TestSetup = ({ shouldUseDelay = true }) => {
88
const [isAdded, setIsAdded] = useState(true);
@@ -121,7 +121,7 @@ test('waits with custom interval', async () => {
121121

122122
try {
123123
await waitForElementToBeRemoved(() => mockFn(), {
124-
timeout: 400,
124+
timeout: 600,
125125
interval: 200,
126126
});
127127
} catch (e) {
@@ -131,10 +131,10 @@ test('waits with custom interval', async () => {
131131
expect(mockFn).toHaveBeenCalledTimes(4);
132132
});
133133

134-
test.each([TimerMode.Default, TimerMode.Legacy])(
134+
test.each([TimerMode.Legacy, TimerMode.Modern])(
135135
'works with %s fake timers',
136136
async (fakeTimerType) => {
137-
setupFakeTimers(fakeTimerType);
137+
jest.useFakeTimers(fakeTimerType);
138138

139139
const mockFn = jest.fn(() => <View />);
140140

@@ -146,6 +146,6 @@ test.each([TimerMode.Default, TimerMode.Legacy])(
146146
} catch (e) {
147147
// Suppress expected error
148148
}
149-
expect(mockFn).toHaveBeenCalledTimes(4);
149+
expect(mockFn).toHaveBeenCalledTimes(2);
150150
}
151151
);

src/flushMicroTasks.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
// @flow
22
import { printDeprecationWarning } from './helpers/errors';
3-
import { setImmediate } from './helpers/getTimerFuncs';
3+
import { setImmediate } from './helpers/timers';
44

55
type Thenable<T> = { then: (() => T) => mixed };
66

src/helpers/getTimerFuncs.js renamed to src/helpers/timers.js

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
1-
/* eslint-disable no-undef */
2-
3-
// Contents of this file sourced directly from https://github.com/testing-library/dom-testing-library/blob/master/src/helpers.js
1+
// Most content of this file sourced directly from https://github.com/testing-library/dom-testing-library/blob/master/src/helpers.js
2+
// @flow
3+
/* globals jest */
44

55
const globalObj = typeof window === 'undefined' ? global : window;
66

77
// Currently this fn only supports jest timers, but it could support other test runners in the future.
8-
function runWithRealTimers(callback) {
8+
function runWithRealTimers<T>(callback: () => T): T {
99
const fakeTimersType = getJestFakeTimersType();
1010
if (fakeTimersType) {
1111
jest.useRealTimers();
@@ -21,6 +21,7 @@ function runWithRealTimers(callback) {
2121
}
2222

2323
function getJestFakeTimersType() {
24+
// istanbul ignore if
2425
if (
2526
typeof jest === 'undefined' ||
2627
typeof globalObj.setTimeout === 'undefined'
@@ -37,10 +38,12 @@ function getJestFakeTimersType() {
3738

3839
if (
3940
typeof globalObj.setTimeout.clock !== 'undefined' &&
41+
// $FlowIgnore[prop-missing]
4042
typeof jest.getRealSystemTime !== 'undefined'
4143
) {
4244
try {
4345
// jest.getRealSystemTime is only supported for Jest's `modern` fake timers and otherwise throws
46+
// $FlowExpectedError
4447
jest.getRealSystemTime();
4548
return 'modern';
4649
} catch {
@@ -50,24 +53,35 @@ function getJestFakeTimersType() {
5053
return null;
5154
}
5255

56+
const jestFakeTimersAreEnabled = (): boolean =>
57+
Boolean(getJestFakeTimersType());
58+
5359
// we only run our tests in node, and setImmediate is supported in node.
5460
function setImmediatePolyfill(fn) {
5561
return globalObj.setTimeout(fn, 0);
5662
}
5763

58-
function getTimeFunctions() {
64+
type BindTimeFunctions = {
65+
clearTimeoutFn: typeof clearTimeout,
66+
setImmediateFn: typeof setImmediate,
67+
setTimeoutFn: typeof setTimeout,
68+
};
69+
70+
function bindTimeFunctions(): BindTimeFunctions {
5971
return {
6072
clearTimeoutFn: globalObj.clearTimeout,
6173
setImmediateFn: globalObj.setImmediate || setImmediatePolyfill,
6274
setTimeoutFn: globalObj.setTimeout,
6375
};
6476
}
6577

66-
const { clearTimeoutFn, setImmediateFn, setTimeoutFn } = runWithRealTimers(
67-
getTimeFunctions
68-
);
78+
const { clearTimeoutFn, setImmediateFn, setTimeoutFn } = (runWithRealTimers(
79+
bindTimeFunctions
80+
): BindTimeFunctions);
6981

7082
export {
83+
runWithRealTimers,
84+
jestFakeTimersAreEnabled,
7185
clearTimeoutFn as clearTimeout,
7286
setImmediateFn as setImmediate,
7387
setTimeoutFn as setTimeout,

website/docs/API.md

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -366,8 +366,6 @@ test('waiting for an Banana to be ready', async () => {
366366
In order to properly use `waitFor` you need at least React >=16.9.0 (featuring async `act`) or React Native >=0.60 (which comes with React >=16.9.0).
367367
:::
368368

369-
If you're using Jest's [Timer Mocks](https://jestjs.io/docs/en/timer-mocks#docsNav), remember not to await the return of `waitFor` as it will stall your tests.
370-
371369
## `waitForElementToBeRemoved`
372370

373371
- [`Example code`](https://github.com/callstack/react-native-testing-library/blob/master/src/__tests__/waitForElementToBeRemoved.test.js)
@@ -404,8 +402,6 @@ You can use any of `getBy`, `getAllBy`, `queryBy` and `queryAllBy` queries for `
404402
In order to properly use `waitForElementToBeRemoved` you need at least React >=16.9.0 (featuring async `act`) or React Native >=0.60 (which comes with React >=16.9.0).
405403
:::
406404

407-
If you're using Jest's [Timer Mocks](https://jestjs.io/docs/en/timer-mocks#docsNav), remember not to await the return of `waitFor` as it will stall your tests.
408-
409405
## `within`, `getQueriesForElement`
410406

411407
- [`Example code`](https://github.com/callstack/react-native-testing-library/blob/master/src/__tests__/within.test.js)

0 commit comments

Comments
 (0)