Fix test flakiness by using jest timers

Summary: Some tests were occasionally flaky, by emulating delays, time variation should no longer influence tests.

Reviewed By: passy

Differential Revision: D28572946

fbshipit-source-id: f4134a6509a0ec0be2e8f36e5623c4882b5531b8
This commit is contained in:
Michel Weststrate
2021-05-25 02:21:03 -07:00
committed by Facebook GitHub Bot
parent 8d508c8634
commit d9c986fcf8
2 changed files with 40 additions and 27 deletions

View File

@@ -7,6 +7,8 @@
* @format
*/
jest.useFakeTimers();
import React from 'react';
import produce from 'immer';
import {FlipperPlugin} from '../plugin';
@@ -24,7 +26,6 @@ import {
import {selectPlugin} from '../reducers/connections';
import {updateSettings} from '../reducers/settings';
import {switchPlugin} from '../reducers/pluginManager';
import {sleep} from 'flipper-plugin/src/utils/sleep';
interface PersistedState {
count: 1;
@@ -521,7 +522,7 @@ test('PluginContainer + Sandy plugin supports deeplink', async () => {
);
});
await sleep(10);
jest.runAllTimers();
expect(linksSeen).toEqual(['universe!']);
expect(renderer.baseElement).toMatchInlineSnapshot(`
<body>
@@ -552,7 +553,7 @@ test('PluginContainer + Sandy plugin supports deeplink', async () => {
}),
);
});
await sleep(10);
jest.runAllTimers();
expect(linksSeen).toEqual(['universe!']);
// ...nor does a random other store update that does trigger a plugin container render
@@ -575,7 +576,7 @@ test('PluginContainer + Sandy plugin supports deeplink', async () => {
}),
);
});
await sleep(10);
jest.runAllTimers();
expect(linksSeen).toEqual(['universe!', 'london!']);
// and same link does trigger if something else was selected in the mean time
@@ -597,7 +598,7 @@ test('PluginContainer + Sandy plugin supports deeplink', async () => {
}),
);
});
await sleep(10);
jest.runAllTimers();
expect(linksSeen).toEqual(['universe!', 'london!', 'london!']);
});
@@ -798,7 +799,7 @@ test('PluginContainer + Sandy device plugin supports deeplink', async () => {
);
});
await sleep(10);
jest.runAllTimers();
expect(linksSeen).toEqual([theUniverse]);
expect(renderer.baseElement).toMatchInlineSnapshot(`
<body>
@@ -829,7 +830,7 @@ test('PluginContainer + Sandy device plugin supports deeplink', async () => {
}),
);
});
await sleep(10);
jest.runAllTimers();
expect(linksSeen).toEqual([theUniverse]);
// ...nor does a random other store update that does trigger a plugin container render
@@ -852,7 +853,7 @@ test('PluginContainer + Sandy device plugin supports deeplink', async () => {
}),
);
});
await sleep(10);
jest.runAllTimers();
expect(linksSeen).toEqual([theUniverse, 'london!']);
// and same link does trigger if something else was selected in the mean time
@@ -874,7 +875,7 @@ test('PluginContainer + Sandy device plugin supports deeplink', async () => {
}),
);
});
await sleep(10);
jest.runAllTimers();
expect(linksSeen).toEqual([theUniverse, 'london!', 'london!']);
});
@@ -976,7 +977,7 @@ test('Sandy plugins support isPluginSupported + selectPlugin', async () => {
pluginInstance.selectPlugin(definition.id, 'data');
expect(store.getState().connections.selectedPlugin).toBe(definition.id);
expect(pluginInstance.activatedStub).toBeCalledTimes(2);
await sleep(10);
jest.runAllTimers();
expect(renderer.baseElement.querySelector('h1')).toMatchInlineSnapshot(`
<h1>
Plugin1

View File

@@ -12,6 +12,8 @@ import {createStore, Store} from 'redux';
import produce from 'immer';
import {sleep} from '../promiseTimeout';
jest.useFakeTimers();
const initialState = {
counter: {count: 0},
somethingUnrelated: false,
@@ -73,13 +75,13 @@ describe('sideeffect', () => {
expect(events.length).toBe(0);
// arrive as a single effect
await sleep(10);
jest.advanceTimersByTime(10);
expect(events).toEqual(['counter: 2']);
// no more events arrive after unsubscribe
unsubscribe();
store.dispatch({type: 'inc'});
await sleep(10);
jest.advanceTimersByTime(10);
expect(events).toEqual(['counter: 2']);
expect(warn).not.toBeCalled();
expect(error).not.toBeCalled();
@@ -99,13 +101,13 @@ describe('sideeffect', () => {
expect(events.length).toBe(0);
// unrelated event doesn't trigger
await sleep(10);
jest.advanceTimersByTime(10);
expect(events.length).toBe(0);
// counter increment does
store.dispatch({type: 'inc'});
await sleep(10);
jest.advanceTimersByTime(10);
expect(events).toEqual(['counter: 1']);
expect(warn).not.toBeCalled();
expect(error).not.toBeCalled();
@@ -125,13 +127,13 @@ describe('sideeffect', () => {
expect(events.length).toBe(0);
// unrelated event doesn't trigger
await sleep(10);
jest.advanceTimersByTime(10);
expect(events.length).toBe(0);
// counter increment does
store.dispatch({type: 'inc'});
await sleep(10);
jest.advanceTimersByTime(10);
expect(events).toEqual(['counter: 1']);
expect(warn).not.toBeCalled();
expect(error).not.toBeCalled();
@@ -151,7 +153,7 @@ describe('sideeffect', () => {
store.dispatch({type: 'inc'});
}).not.toThrow();
await sleep(10);
jest.advanceTimersByTime(10);
expect(error.mock.calls).toMatchInlineSnapshot(`
Array [
Array [
@@ -178,7 +180,7 @@ describe('sideeffect', () => {
);
store.dispatch({type: 'inc'});
await sleep(200);
jest.advanceTimersByTime(200);
expect(done).toBe(true);
expect(warn.mock.calls[0][0]).toContain("Side effect 'test' took");
});
@@ -195,30 +197,40 @@ describe('sideeffect', () => {
// Fires immediately
store.dispatch({type: 'inc'});
await sleep(100);
jest.advanceTimersByTime(100);
expect(events).toEqual(['counter: 1']);
// no new tick in the next 100 ms
await sleep(300);
jest.advanceTimersByTime(300);
store.dispatch({type: 'inc'});
await sleep(300);
jest.advanceTimersByTime(300);
store.dispatch({type: 'inc'});
expect(events).toEqual(['counter: 1']);
await sleep(1000);
jest.advanceTimersByTime(1000);
expect(events).toEqual(['counter: 1', 'counter: 3']);
// long time now effect, it will fire right away again
await sleep(2000);
// long time no effect, it will fire right away again
// N.b. we need call sleep here to create a timeout, as time wouldn't progress otherwise
const p = sleep(2000);
jest.advanceTimersByTime(2000);
await p;
// ..but firing an event that doesn't match the selector doesn't reset the timer
store.dispatch({type: 'unrelated'});
await sleep(100);
expect(events).toEqual(['counter: 1', 'counter: 3']);
jest.advanceTimersByTime(100);
store.dispatch({type: 'inc'});
store.dispatch({type: 'inc'});
await sleep(100);
jest.advanceTimersByTime(100);
const p2 = sleep(2000);
jest.advanceTimersByTime(2000);
await p2;
expect(events).toEqual(['counter: 1', 'counter: 3', 'counter: 5']);
});
@@ -239,7 +251,7 @@ describe('sideeffect', () => {
store.dispatch({type: 'inc'});
store.dispatch({type: 'inc'});
// arrive as a single effect
await sleep(10);
jest.advanceTimersByTime(10);
expect(events).toEqual(['counter: 2', 'counter: 4']);
unsubscribe?.();
});