如何测试React组件的prop更新

Win*_*Win 38 unit-testing jasmine reactjs

单元测试React组件prop更新的正确方法是什么.

这是我的测试夹具;

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);
        });
});
Run Code Online (Sandbox Code Playgroud)

这工作正常并且测试通过,但是这会显示反应警告消息

'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.'
Run Code Online (Sandbox Code Playgroud)

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

use*_*118 55

AirBnB的库为这个问题提供了优雅的解决方案.

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

    it("Component should call componentWillReceiveProps on update", () => {
        const spy = sinon.spy(Component.prototype, "componentWillReceiveProps");
        const wrapper = shallow(<Component {...props} />);

        expect(spy.calledOnce).to.equal(false);
        wrapper.setProps({ prop: 2 });
        expect(spy.calledOnce).to.equal(true);
    });
Run Code Online (Sandbox Code Playgroud)

  • 但OP没有提到酶,在他们的标签中也没有提到 (3认同)

Ale*_*erg 49

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

在您的情况下,您应该ReactDOM.render直接使用而不是TestUtils.renderIntoDocument.后者在每次调用时都会创建一个新的容器节点,因此也是一个新的组件.

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);
});
Run Code Online (Sandbox Code Playgroud)

  • 答案为+1.请注意,这现在是`ReactDOM.render`而不仅仅是`React.render`(从我认为的版本0.14开始). (4认同)
  • 如果你正在测试对诸如`componentWillReceiveProps`或`componentDidUpdate`之类的道具变化的响应,那么我也会这样做.也就是说,我会尝试重写组件,以便在渲染时动态计算状态值,如果可能的话(而不是使用状态). (2认同)

Dav*_*son 15

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

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

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


kar*_*fus 10

快速添加,因为我正在寻找testing-library的答案,但在这里没有找到它:本期有一个例子它看起来像这样:

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

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

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