ReactWrapper::state() 只能在类组件单元测试 Jest 和 Enzyme 上调用

Posted

技术标签:

【中文标题】ReactWrapper::state() 只能在类组件单元测试 Jest 和 Enzyme 上调用【英文标题】:ReactWrapper::state() can only be called on class components Unit Testing Jest and Enzyme 【发布时间】:2020-02-14 05:00:24 【问题描述】:

使用 jest 和酶编写反应单元测试。在检查组件状态时,它会抛出错误“ReactWrapper::state() 只能在类组件上调用”。

import React from 'react';
import  mount  from 'enzyme';
import expect from 'expect';
import CustomerAdd from '../CustomerAdd'
import MUITheme from '../../../../Utilities/MUITheme';
import  ThemeProvider  from '@material-ui/styles';

describe('<CustomerAdd />', () => 
    const wrapper = mount(
        <ThemeProvider theme=MUITheme>
          <CustomerAdd ...mockProps></CustomerAdd>
        </ThemeProvider>
        );
        test('something', () => 
            expect(wrapper.find(CustomerAdd).state('addNewOnSubmit')).toEqual(true);
        );
);

在上面的代码中,CustomerAdd 组件是类组件。我的代码没有什么问题。任何人都可以帮我解决这个问题。提前致谢。

【问题讨论】:

很难确定。检查您的导入/导出。我的意思是默认导出可以是基于类的组件的包装,而您需要使用命名导出。 PS无论如何,你最好不要反对state(),测试变得脆弱。 我认为在基于类的组件中使用用作包装器的功能组件时会出现问题。有什么解决办法吗? 如何声明的? ThemeProvider 是 Material ui ThemeProvider 组件。它是一个功能组件。如果我从 CustomerAdd 中删除这个和相应的依赖项。它工作正常。但我需要带有 ThemeProvider 的 CustomerAdd '../CustomerAdd' 的默认导出是什么样的? 【参考方案1】:

所以你的默认导出

export default withStyles(styles)(CustomerAdd);

导出有关基于类的组件的功能(HOC)包装器。如果类名和导入无关紧要

import CustomerAdd from '../CustomerAdd'

相等。您的测试导入包装版本,并在调用 .find(CustomerAdd) 后返回 HOC 而不是您的课程。而且您无法使用实例。

短期解决方案:直接将类导出为命名导出。

export class CustomerAdd extends React.Component
  ...


export default withStyles(styles)(CustomerAdd);

在测试中使用命名导入:

import  CustomerAdd  from '../CusomerAdd';

Quick'n'dirty 解决方案:使用.dive 访问您的底层基于类的组件:

expect(wrapper.find(CustomerAdd).dive().state('addNewOnSubmit')).toEqual(true);

这是一种反模式,因为如果您在默认导出中添加任何额外的 HOC,您将需要通过添加适当数量的 .dive().dive()....dive() 调用来猴子修补所有相关测试。

长期解决方案:避免测试状态,这是实现细节。

而是专注于验证渲染的内容。然后,在许多不同的重构技术(例如用功能组件替换类、重命名状态/实例成员、提升状态、将组件连接到 Redux 等)的情况下,您是安全的。

【讨论】:

expect(wrapper.find('CustomerAdd').state('addNewOnSubmit')).toEqual(true);这对我有用:) 很好,但这是一种最棘手的方式,因为您依赖于 React 本身基于类名称隐式设置的 displayName。假设你用 const CustomerAdd = function ... 之类的功能组件替换类,使用命名导入的方法仍然有效,而 find('CustomerAdd') 将中断。 @skyboyer “长期解决方案:避免测试状态,这是实现细节” - 如果我想根据状态变化测试渲染。那我会这样做吗? @Liron,你的状态可以通过一系列事件的刺激和模拟外部来源(fetchMath.random 等)返回来实现。所以模拟和模拟。

以上是关于ReactWrapper::state() 只能在类组件单元测试 Jest 和 Enzyme 上调用的主要内容,如果未能解决你的问题,请参考以下文章

属性只能在构造函数中定义,在其他函数中不能定义,只能引用,

怎样限制WPF只能打开一个相同界面

Unity里做等待只能用协程吗

为啥在匿名类中只能访问最终变量?

报表项表达式只能引用当前数据集范围内的字段,如果在聚合内,则只能引用指定的数据集范围

为啥 Haskell 异常只能在 IO monad 中捕获?