fix: modern jest timers (#397)

* fix: modern jest timers

* treat modern timers as default, but be explicit in tests

* we're node-only

* rename to Thenable

* add clarifications; unify test names

* Update src/__tests__/auto-cleanup-skip.test.js

Co-authored-by: Maciej Jastrzebski <mdjastrzebski@gmail.com>

Co-authored-by: Maciej Jastrzebski <mdjastrzebski@gmail.com>
This commit is contained in:
Michał Pierzchała
2020-07-10 16:18:31 +02:00
committed by GitHub
parent 859cb82b87
commit 111b1c9277
5 changed files with 74 additions and 13 deletions
@@ -4,8 +4,8 @@ import { View } from 'react-native';
let render;
beforeAll(() => {
process.env.RNTL_SKIP_AUTO_CLEANUP = 'true';
const rtl = require('../');
render = rtl.render;
const rntl = require('..');
render = rntl.render;
});
let isMounted = false;
@@ -20,14 +20,31 @@ class Test extends React.Component<*> {
}
}
afterEach(() => {
jest.useRealTimers();
});
// This just verifies that by importing RNTL in an environment which supports afterEach (like jest)
// we'll get automatic cleanup between tests.
test('component is mounted, but not umounted before test ends', () => {
const fn = jest.fn();
render(<Test onUnmount={fn} />);
expect(isMounted).toEqual(true);
expect(fn).not.toHaveBeenCalled();
});
test('component is automatically umounted after first test ends', () => {
expect(isMounted).toEqual(false);
});
test('does not time out with legacy fake timers', () => {
jest.useFakeTimers('legacy');
render(<Test />);
expect(isMounted).toEqual(true);
});
test('does not time out with fake timers', () => {
jest.useFakeTimers('modern');
render(<Test />);
expect(isMounted).toEqual(true);
});
+24 -5
View File
@@ -35,6 +35,10 @@ class BananaContainer extends React.Component<{}, any> {
}
}
afterEach(() => {
jest.useRealTimers();
});
test('waits for element until it stops throwing', async () => {
const { getByText, queryByText } = render(<BananaContainer />);
@@ -75,8 +79,8 @@ test('waits for element with custom interval', async () => {
expect(mockFn).toHaveBeenCalledTimes(3);
});
test('works with fake timers', async () => {
jest.useFakeTimers();
test('works with legacy fake timers', async () => {
jest.useFakeTimers('legacy');
const mockFn = jest.fn(() => {
throw Error('test');
@@ -87,9 +91,24 @@ test('works with fake timers', async () => {
} catch (e) {
// suppress
}
jest.runTimersToTime(400);
jest.advanceTimersByTime(400);
expect(mockFn).toHaveBeenCalledTimes(3);
});
test('works with fake timers', async () => {
jest.useFakeTimers('modern');
const mockFn = jest.fn(() => {
throw Error('test');
});
try {
waitFor(() => mockFn(), { timeout: 400, interval: 200 });
} catch (e) {
// suppress
}
jest.advanceTimersByTime(400);
expect(mockFn).toHaveBeenCalledTimes(3);
jest.useRealTimers();
});
@@ -25,6 +25,10 @@ const TestSetup = ({ shouldUseDelay = true }) => {
);
};
afterEach(() => {
jest.useRealTimers();
});
test('waits when using getBy query', async () => {
const screen = render(<TestSetup />);
@@ -126,8 +130,22 @@ test('waits with custom interval', async () => {
expect(mockFn).toHaveBeenCalledTimes(4);
});
test('works with fake timers', async () => {
jest.useFakeTimers();
test('works with legacy fake timers', async () => {
jest.useFakeTimers('legacy');
const mockFn = jest.fn(() => <View />);
waitForElementToBeRemoved(() => mockFn(), {
timeout: 400,
interval: 200,
});
jest.advanceTimersByTime(400);
expect(mockFn).toHaveBeenCalledTimes(4);
});
test('works with fake timers', async () => {
jest.useFakeTimers('modern');
const mockFn = jest.fn(() => <View />);
+11 -4
View File
@@ -1,15 +1,22 @@
// @flow
import { printDeprecationWarning } from './helpers/errors';
type Thenable<T> = { then: (() => T) => mixed };
/**
* Wait for microtasks queue to flush
*/
export default function flushMicrotasksQueue(): Promise<any> {
export default function flushMicrotasksQueue<T>(): Thenable<T> {
printDeprecationWarning('flushMicrotasksQueue');
return flushMicroTasks();
}
export function flushMicroTasks(): Promise<any> {
return new Promise((resolve) => setImmediate(resolve));
export function flushMicroTasks<T>(): Thenable<T> {
return {
// using "thenable" instead of a Promise, because otherwise it breaks when
// using "modern" fake timers
then(resolve) {
setImmediate(resolve);
},
};
}