用酶进行React / Redux测试 [英] React/Redux Testing w/ Enzyme

查看:60
本文介绍了用酶进行React / Redux测试的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在学习如何使用酶测试React / Redux组件。该组件将app级别状态视为道具。当我运行测试时,我得到错误:

I'm learning how to test React/Redux components using enzyme. The component takes app-level state as props. When I run the test, I get the errors:

警告:React.createElement:type不应为null,undefined,boolean或number 。它应该是一个字符串(对于DOM元素)或一个ReactClass(对于复合组件)。

TypeError:不能读取属性'contextTypes'未定义

使用我的console.log 包装器 in以下测试文件记录为 undefined

with my console.log of wrapper in the below test file logging as undefined.

我知道我的设置有问题,并且花了几个小时试图解决这个问题。任何人都可以看到我导入和尝试使用该组件的方式有什么明显之处吗?我无法弄清楚为什么它是 undefined 。提前感谢您的任何帮助或见解!

I know that there's something wrong with my setup here, and have spent a couple hours trying to figure this out. Can anybody see anything obvious in the way that I'm importing and trying to use the component? I can't figure out why it is undefined. Thanks in advance for any help or insight!

BackendDisplay.js

import React from 'react';
import { connect } from 'react-redux';
import moment from 'moment';

var BackendDisplay = React.createClass({

  render() {

    const { username, node_version, app_path, timestamp } = this.props.loginState;
    const dateTime = moment(timestamp).format('MMMM Do YYYY, h:mm:ss a');

    return (
      <div>
        <h1>Welcome, {username}!</h1>
        <p><span className="bold">Node Version:</span> {node_version}</p>
        <p><span className="bold">Application Path:</span> {app_path}</p>
        <p><span className="bold">Date/Time:</span> {dateTime}</p>
      </div>
    );
  }
});

const mapStateToProps = function(store) {
  return store;
}

module.exports = connect(mapStateToProps)(BackendDisplay);

BackendDisplay.test.js

'use strict';

import React from 'react';
import {shallow} from 'enzyme';
import { connect } from 'react-redux';
import { BackendDisplay } from '../components/BackendDisplay';

describe('<BackendDisplay />', () => {

  it('Correctly displays username, node_version, app_path, and timestamp', () => {

    const wrapper = shallow(<BackendDisplay />);
    console.log(wrapper);

  });

});

更改后编辑:
BackendDisplay.js

import React from 'react';
import { connect } from 'react-redux';
import moment from 'moment';

var BackendDisplay = React.createClass({

  render() {

    const { username, node_version, app_path, timestamp } = this.props.loginState;
    const dateTime = moment(timestamp).format('MMMM Do YYYY, h:mm:ss a');

    return (
      <div>
        <h1>Welcome, {username}!</h1>
        <p><span className="bold">Node Version:</span> {node_version}</p>
        <p><span className="bold">Application Path:</span> {app_path}</p>
        <p><span className="bold">Date/Time:</span> {dateTime}</p>
      </div>
    );
  }
});

const mapStateToProps = function(store) {
  return store;
}

// module.exports = connect(mapStateToProps)(BackendDisplay);
export default connect(mapStateToProps)(BackendDisplay);

BackendDisplay.test.js

'use strict';

import React from 'react';
import {shallow} from 'enzyme';
import { connect } from 'react-redux';
import store from '../store';
import { Provider } from 'react-redux';
import ConnectedBackendDisplay, {BackendDisplay} from '../components/BackendDisplay';

describe('<BackendDisplay />', () => {

  it('Correctly displays username, node_version, app_path, and timestamp', () => {

    const wrapper = shallow(
      <Provider store={store}>
        <BackendDisplay />
      </Provider>
    );

    console.log(wrapper.find(BackendDisplay));
    expect(wrapper.find(BackendDisplay).length).to.equal(1);

  });

});

错误消息:
TypeError :Enzyme :: Selector需要一个字符串,对象或组件构造函数

推荐答案

你的BackendDisplay是一个容器组件,它通过使用connect api连接到Redux商店。

Your BackendDisplay is a container component and it is connected to the Redux store through the use of the connect api.

您应该导出未修饰的组件以进行测试。由于它是未修饰的,因此不会使用react-redux的Connect组件包装此导出的组件。

You should export the undecorated component for testing purposes. Since it is undecorated this exported component will not be wrapped with react-redux's Connect component.

var BackendDisplay = React.createClass({

  render() {

    const { username, node_version, app_path, timestamp } = this.props.loginState;
    const dateTime = moment(timestamp).format('MMMM Do YYYY, h:mm:ss a');

    return (
      <div>
        <h1>Welcome, {username}!</h1>
        <p><span className="bold">Node Version:</span> {node_version}</p>
        <p><span className="bold">Application Path:</span> {app_path}</p>
        <p><span className="bold">Date/Time:</span> {dateTime}</p>
      </div>
    );
  }
});

然后你可以按如下方式导入它以使测试工作

Then you can import it as follows to make the test work

import {BackendDisplay} from 'BackendDisplay'

作为奖励,您还可以通过更改以下行导出装饰的BackendDisplay组件

As a bonus you can also export the decorated BackendDisplay component by changing the following line

module.exports = connect(mapStateToProps)(BackendDisplay);

 export default connect(mapStateToProps)(BackendDisplay);

这是如何导入装饰和未装饰的组件

This is how to import both the decorated and undecorated components

import ConnectedBackendDisplay, {BackendDisplay} from 'BackendDisplay'  

ConnectedBackendDisplay引用装饰组件,即通过未命名导出导出的
(导出默认BackendDisplay)。

ConnectedBackendDisplay refers to the decorated component which is exported through the unnamed export (export default BackendDisplay).

我们只是给它这个名字,以便它清除它包含在连接组件中。

We just give it this name so that its clear it is wrapped in a connect component.

我更新了以下组件以使用导出默认值,它提供了一个未命名的导出。

I have updated the following component to use export default which gives an unnamed export.

BackendDisplay

import React from 'react';
import { connect } from 'react-redux';
import moment from 'moment';

export const BackendDisplay = React.createClass({

  render() {

    const { username, node_version, app_path, timestamp } = this.props;
    // removed reference to this.props.loginState

    const dateTime = moment(timestamp).format('MMMM Do YYYY, h:mm:ss a');

    return (
      <div>
        <h1>Welcome, {username}!</h1>
        <p><span className="bold">Node Version:</span> {node_version}</p>
        <p><span className="bold">Application Path:</span> {app_path}</p>
        <p><span className="bold">Date/Time:</span> {dateTime}</p>
      </div>
    );
  }
});

const mapStateToProps = function(store) {
  return store;
}

export default connect(mapStateToProps)(BackendDisplay);

这是一个测试套件,用于演示如何测试上述组件作为装饰和未修饰的酶组件。

Here is the test suite to demonstrate testing the above component both as a decorated and undecorated component with enzyme.

我正在使用chai库来简化测试断言。
jsdom库也用于创建DOM环境,因此我们可以使用Enzyme的mount函数测试组件,该函数完全呈现组件。

I am using the chai library to make test assertions easier. The jsdom library is also being used to create a DOM environment so we can test components using Enzyme's mount function which fully renders components.

test

'use strict';
import React from 'react';
import jsdom from 'jsdom'
import { expect } from 'chai'
import { shallow , mount} from 'enzyme';
import { Provider } from 'react-redux';
import ConnectedBackendDisplay, // decorated component
   {BackendDisplay} from 'app/components/BackendDisplay';  // undecorated component
// for mocking a store to test the decorated component
import configureMockStore from 'redux-mock-store'; 

// create a fake DOM environment so that we can use Enzyme's mount to
// test decorated components
const doc = jsdom.jsdom('<!doctype html><html><body></body></html>')
global.document = doc
global.window = doc.defaultView


describe.only('<BackendDisplay />', () => {

    it('undecorated component correctly displays username', () => {
        // define the prop we want to pass in
        const username = 'Foo'
        // render the component with the prop
        const wrapper = mount(<BackendDisplay username={username} />);
        // test that the text of the first <p> equals username prop that we passed in       
        expect(wrapper.find('h1').first().text()).to.equal(username);
   });

    it('decorated component correctly displays username', () => {
        // define the prop we want to pass in
        const username = 'Foo'
        const initialState = { }
        // create our mock store with an empyty initial state
        const store = configureMockStore(initialState)

        // render the component with the mockStore
        const wrapper = shallow(<Provider store={store}>
                                <ConnectedBackendDisplay username={username}/>
                              </Provider>);

        // test that the text of the first <p> equals username prop that we passed in       
        expect(wrapper.find('h1').first().text()).to.equal(username);
   });
});

这篇关于用酶进行React / Redux测试的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆