使用 React、Jest、Redux 和 Thunk 进行无限循环测试

Posted

技术标签:

【中文标题】使用 React、Jest、Redux 和 Thunk 进行无限循环测试【英文标题】:Infinite Loop in Test with React, Jest, Redux and Thunk 【发布时间】:2020-12-03 17:12:16 【问题描述】:

我有一个带有 Jest 测试套件的 React 应用程序。应用程序使用 redux,测试套件使用 redux-mock-store。我正在使用 react-thunk 中间件来延迟调度操作,因为应用程序需要与远程 Firebase 数据库同步数据。我希望我的测试套件在向 Redux 发送操作后验证某些条件,如下所示:

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();
    );
);

测试使用 Jest 返回的 done 处理程序等待 store.dispatch 返回的承诺完成。但是,promise 从未执行,测试进入无限循环,Jest 失败并出现以下异常:

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

一开始我以为我的自定义异步动作生成器返回的promise有问题,但是注意它是如何从Firebase返回一个promise的(看内部的return语句,外部的return语句是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 );
        );
    ;
; 

然后我想我设置 Firebase 的方式可能有问题,但我已经验证了应用程序和测试套件都成功地保存了数据。这是 Firebase 配置:

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

firebase.initializeApp( ... );

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

然后我认为可能是 Redux 或 redux-thunk 中间件有问题,但我已经验证应用程序正在成功保存数据。这是我的 Redux 配置:

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);
;

我觉得这一切都很好。我无法确定是什么导致 Jest 进入无限循环。提前感谢您的帮助。

【问题讨论】:

你在哪里模拟 database 对象? 你在节点 >= 14.6.0 上吗? (它包含对 Ice Lake cpu 的 libuv 的修复) @Ishank:那个特定的测试是一个集成测试,所以它故意使用实际的 Fireabase 数据库。 @Caramiriel:很好的建议!事实证明,我使用的是 Ice Lake CPU 和旧版本的 Node.js。升级到最新版本(撰写本文时为 14.8.0)解决了这个问题。我认为我的测试没有那么复杂,因此在 Jest 中处理异步逻辑肯定存在更大的问题,导致 Node 进入无限循环。如果您想要赏金,请写下答案,我会将其标记为已接受。谢谢! 【参考方案1】:

所以我在 Github 上偶然发现了 this lengthy issue(Google 上的关键字“Assertion failed: new_time >= loop->time”),约会时间大约是三年前。它是(libuv)Node 用于其异步 I/O 的库,也是问题所在。经过短暂阅读,问题似乎只存在于英特尔的 Ice Lake CPU(目前)。虽然该问题已在库中得到修复,但它需要至少 14.6.0 的 Node 版本,其中包括已修复的库实现。建议更新到这个版本(可能是最简单的选择,但不是唯一的选择)。

【讨论】:

【参考方案2】:

断言失败:new_time >= loop->time, file c:\ws\deps\uv\src\win\core.c,第 309 行错误命令失败并退出 代码3221226505。

这似乎发生在系统时钟漂移时。您可以通过尝试以下任何方法来解决它:

    在 Windows 10 的日期和时间设置下同步您的时钟。

    选择不同的时钟源,例如ACPI 而不是 TSC ,或者通过调整 Bios 中的设置。

    在您的系统上执行 CMOS 重置。

    检查您的板载 CMOS 备用电池

    安装 WSL(适用于 Linux 的 Windows 子系统)。此解决方法适用于许多人

    或卸载/重新安装 Node 和 libuv/更新到最新版本,以受益于针对特定代处理器的任何修复。

【讨论】:

感谢您的建议。我的系统已经有 WSL。如上所述,升级到最新版本的 Node 后问题已解决。但是,您的建议也有可能解决问题。也许从 14.6.0 开始在 Node 中修复的任何内容都与您提到的系统时钟方案有关。再次感谢。 @ChristianCorrea 是的,如果你用谷歌搜索这个错误,很多人都会以不同的方式解决它。我认为在这里收集所有这些是个好主意。

以上是关于使用 React、Jest、Redux 和 Thunk 进行无限循环测试的主要内容,如果未能解决你的问题,请参考以下文章

react状态管理器(分模块)之redux和redux + react-redux + reducer和redux + react-redux + reducer分模块 + 异步操作redux-thu

Jest/Enzyme 单元测试:如何将存储传递给使用 redux 4 和 react-redux 6 连接功能的浅层组件

React Redux:使用 Enzyme/Jest 测试 mapStateToProps 和 mapDispatchToProps

如何使用 Jest 和 Enzyme 测试具有 Router、Redux 和两个 HOC 的 React 组件?

用 Jest 模拟 React-Redux 商店

React-Redux/Jest 不变违规:找不到“商店”