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

fix: modern jest timers #397

Merged
merged 6 commits into from
Jul 10, 2020
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { View } from 'react-native';
let render;
beforeAll(() => {
process.env.RNTL_SKIP_AUTO_CLEANUP = 'true';
const rtl = require('../');
const rtl = require('..');
render = rtl.render;
thymikee marked this conversation as resolved.
Show resolved Hide resolved
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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);
});
27 changes: 23 additions & 4 deletions src/__tests__/waitFor.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -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 />);

Expand Down Expand Up @@ -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');
Expand All @@ -87,9 +91,24 @@ test('works with fake timers', async () => {
} catch (e) {
// suppress
}
jest.runTimersToTime(400);
jest.advanceTimersByTime(400);

expect(mockFn).toHaveBeenCalledTimes(3);
});

jest.useRealTimers();
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);
});
20 changes: 19 additions & 1 deletion src/__tests__/waitForElementToBeRemoved.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,10 @@ const TestSetup = ({ shouldUseDelay = true }) => {
);
};

afterEach(() => {
jest.useRealTimers();
});

test('waits when using getBy query', async () => {
const screen = render(<TestSetup />);

Expand Down Expand Up @@ -126,8 +130,22 @@ test('waits with custom interval', async () => {
expect(mockFn).toHaveBeenCalledTimes(4);
});

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();
jest.useFakeTimers('modern');

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

Expand Down
15 changes: 11 additions & 4 deletions src/flushMicroTasks.js
Original file line number Diff line number Diff line change
@@ -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);
},
};
}