如何测试React组件的prop更新

时间:2015-06-03 08:15:30

标签: unit-testing jasmine reactjs

对React组件支持更新进行单元测试的正确方法是什么。

这是我的测试夹具;

describe('updating the value', function(){
        var component;
        beforeEach(function(){
            component = TestUtils.renderIntoDocument(<MyComponent value={true} />);
        });

        it('should update the state of the component when the value prop is changed', function(){
            // Act
            component.props.value = false;
            component.forceUpdate();
            // Assert
            expect(component.state.value).toBe(false);
        });
});

这很好,测试通过了,但是这会显示一条反应警告信息

'Warning: Dont set .props.value of the React component <exports />. Instead specify the correct value when initially creating the element or use React.cloneElement to make a new element with updated props.'

我想要测试的是属性的更新,而不是使用不同的属性创建元素的新实例。有没有更好的方法来进行此属性更新?

8 个答案:

答案 0 :(得分:53)

AirBnB&#39; Enzyme库为这个问题提供了一个优雅的解决方案。

它提供了一个setProps方法,可以在浅层或jsdom包装器上调用。

echo json_encode($data)

答案 1 :(得分:46)

如果在同一容器节点中重新呈现具有不同props的元素,则将更新它而不是重新装入。请参阅React.render

在您的情况下,您应该直接使用ReactDOM.render而不是TestUtils.renderIntoDocument。后来的creates a new container node every time it is called,也是一个新组件。

var node, component;
beforeEach(function(){
    node = document.createElement('div');
    component = ReactDOM.render(<MyComponent value={true} />, node);
});

it('should update the state of the component when the value prop is changed', function(){
    // `component` will be updated instead of remounted
    ReactDOM.render(<MyComponent value={false} />, node);
    // Assert that `component` has updated its state in response to a prop change
    expect(component.state.value).toBe(false);
});

答案 2 :(得分:14)

警告:这实际上不会改变道具。

但对我来说,我想要的只是在componentWillReceiveProps中测试我的逻辑。所以我直接打电话给myComponent.componentWillReceiveProps(/*new props*/)

我不需要/想要测试React在道具改变时调用方法,或者当道具改变时React设置道具,只是如果道具与传入的内容不同,则会触发一些动画。

答案 3 :(得分:1)

这是我一直在使用的解决方案,它使用ReactDOM.render,但不依赖于函数的(不推荐的)返回值。它使用回调(ReactDOM.render的第三个参数)代替。

如果没有在浏览器中测试,请设置jsdom:

var jsdom = require('jsdom').jsdom;
var document = jsdom('<!doctype html><html><body><div id="test-div"></div></body></html>');
global.document = document;
global.window = doc.defaultView;

使用带有异步回调的react-dom渲染进行测试:

var node, component;
beforeEach(function(done){
    node = document.getElementById('test-div')
    ReactDOM.render(<MyComponent value={true} />, node, function() {
        component = this;
        done();
    });
});

it('should update the state of the component when the value prop is changed', function(done){
    // `component` will be updated instead of remounted
    ReactDOM.render(<MyComponent value={false} />, node, function() {
        component = this;
        // Assert that `component` has updated its state in response to a prop change
        expect(component.state.value).toBe(false);
        done();
    });
});

答案 4 :(得分:1)

快速添加,因为我在寻找 testing-library 的答案,但在这里找不到它:this issue中有一个示例,它看起来像这样:< / p>

const {container} = render(<Foo bar={true} />)

// update the props, re-render to the same container
render(<Foo bar={false} />, {container})

或者,testing-library现在提供了一种“ rerender”方法,可以完成相同的任务。

答案 5 :(得分:0)

这是一个较旧的问题,但如果其他人偶然发现这一点,以下设置对我很有帮助:

it('updates component on property update', () => {
    let TestParent = React.createClass({
        getInitialState() {
            return {value: true};
        },
        render() {
            return <MyComponent value={this.state.value}/>;
        }
    });
    component = TestUtils.renderIntoDocument(<TestParent/>);
    component.setState({value: false});
    // Verification code follows
});

这使得React运行通常的组件更新。

答案 6 :(得分:0)

TestUtils.renderIntoDocumentReactDOM.render都使用ReactDOM.render返回的值。根据{{​​3}}:

  

ReactDOM.render()当前返回对根ReactComponent实例的引用。但是,使用此返回值是遗留的,应该避免使用,因为在某些情况下,React的未来版本可能会异步呈现组件。如果需要对根ReactComponent实例的引用,首选的解决方案是将回调引用附加到根元素

如果我们采取这种建议并做这样的事情会怎样:

let component, node;

const renderComponent = (props = {}) => {
  ReactDOM.render(<MyComponent ref={r => component = r} {...props} />, node);
}

beforeEach(function(){
    node = document.createElement('div');
    renderComponent({value: true}, node); 
});

it('should update the state of the component when the value prop is changed', function(){
    // `component` will be updated instead of remounted
    renderComponent({value: false}, node); 
    // Assert that `component` has updated its state in response to a prop change
    expect(component.state.value).toBe(false);
});

答案 7 :(得分:0)

您可以使用酶来安装组件并向其中添加道具:

import React form 'react';
import component;
import {configure, mount} form 'enzyme';
import Adapter from 'enzyme-adapter-react-16';
import {expect} from 'chai';

configure({adapter: new Adapter()});

describe('Testing component', () => {
  let wrapper;
  beforeEach(() => {
    component = mount(<MyComponent value={false} />);
  });
  it('should update the state of the component when the value prop is changed', function(){

    expect(component.props().children.props.value).toBe(false);
});