Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Infinite Loop in Test with React, Jest, Redux and Thunk

I have a React application with a Jest test suite. The application uses redux and the test suite uses redux-mock-store. I am using the react-thunk middleware to delay dispatching actions, since the application needs to sync data with a remote Firebase database. I would like my test suite to verify some condition after dispatching an action to Redux, like this:

import configureMockStore from 'redux-mock-store';
import thunk from 'redux-thunk';

// This is my custom async action generator.
import { asyncAction } from './some/path';

const createMockStore = configureMockStore([thunk]);

test("Test", (done) => {
    const store = createMockStore({});
    const data = { ... };
    store.dispatch(asyncAction(data)).then(() => {
        expect(someCondition);
        done();
    });
});

The test uses the done handler returned by Jest to wait until the promise returned by store.dispatch completes. However, the promise is never executed, the test enters an infinite loop, and Jest fails with this exception:

Assertion failed: new_time >= loop->time, file c:\ws\deps\uv\src\win\core.c, line 309
error Command failed with exit code 3221226505.

At first I thought there was a problem with the promise returned by my custom async action generator, but notice how it is returning a promise from Firebase (look at the inner return statement, the outer return statement is the function dispatched by redux-thunk):

import database from '../firebase/firebase';

export const asyncAction = (data = {}) => {
    return (dispatch) => {
        return database.ref('someCollection').push(data).then((ref) => {
            dispatch({ type: 'SOME_TYPE', id: ref.key, ...data });
        });
    };
}; 

Then I thought maybe there's something wrong with how I set up Firebase, but I've verified that both the application and the test suite are saving data successfully. Here is the Firebase configuration:

import * as firebase from 'firebase/app';
import 'firebase/database';

firebase.initializeApp({ ... });

const database = firebase.database();
export { database as default };

Then I thought maybe there's something wrong with Redux or the redux-thunk middleware, but I've verified that the application is saving data successfully. Here is my Redux configuration:

import { applyMiddleware, createStore, combineReducers, compose } from 'redux';
import thunk from 'redux-thunk';

const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;

export default () => {
    const reducer = combineReducers({ ... });
    const enhancer = composeEnhancers(applyMiddleware(thunk));
    return createStore(reducer, enhancer);
};

That all seems fine to me. I can't determine what is causing Jest to enter an infinite loop. Thanks in advance for your help.

like image 518
Christian Correa Avatar asked Aug 13 '20 19:08

Christian Correa


People also ask

How to prevent an infinite loop in react?

React limits the number of renders to prevent an infinite loop. Here are 3 potential causes of the infinite loop in React. function App() { const [count, setCount] = useState(0); setCount(1); // infinite loop return ... } If you update the state directly inside your render method or a body of a functional component, it will cause an infinite loop.

What does useeffect() do in ReactJS?

That's an infinite loop. it generates an infinite loop of component re-renderings. After initial rendering, useEffect () executes the side-effect callback that updates the state. The state update triggers re-rendering.

How do you test a react app with Redux?

I.e. for a React app using Redux, render a <Provider> with a real store instance wrapping the component/s being tested. Interactions with the page being tested should use real Redux logic, with API calls mocked out so app code doesn't have to change, and assert that the UI is updated appropriately.

Do I need to write unit tests for action creators and Redux?

If you prefer, or are otherwise required to write unit tests for your action creators or thunks, refer to the tests that Redux Toolkit uses for createAction and createAsyncThunk. Reducers are pure functions that return the new state after applying the action to the previous state.


Video Answer


2 Answers

So I've stumbled upon this lengthy issue on Github (keywords 'Assertion failed: new_time >= loop->time' on Google), dating almost three years ago. It's (libuv) a library Node uses for their asynchronous I/O, also the place where the problem resides. After a short read, the issue only seems to exist for Intel's Ice Lake CPU's (for now). While the issue is already fixed in the library, it requires a Node version of at least 14.6.0 which includes the fixed library implementation. Advised is updating to this version (probably the easiest option, but not the only option).

like image 120
Caramiriel Avatar answered Oct 24 '22 11:10

Caramiriel


Assertion failed: new_time >= loop->time, file c:\ws\deps\uv\src\win\core.c, line 309 error Command failed with exit code 3221226505.

This seems to occur when the system clock is drifting. You can resolve it by trying any of the following:

  1. Synchronize your Clock under Date & Time Settings on Windows 10.

or

  1. selecting a different clock source, e.g. ACPI instead of TSC , or by tweaking settings in the BIOS.

or

  1. doing a CMOS reset on your system.

or

  1. check your onboard CMOS backup battery

or

  1. Install WSL (Windows Subsystem for Linux). This workaround works for many people

or

  1. Or uninstall / reinstall Node and libuv / update to the latest version to benefit from any fixes for specific generations of processors.
like image 1
Rahul Iyer Avatar answered Oct 24 '22 11:10

Rahul Iyer