对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.'
我想要测试的是属性的更新,而不是使用不同的属性创建元素的新实例。有没有更好的方法来进行此属性更新?
答案 0 :(得分:53)
答案 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.renderIntoDocument
和ReactDOM.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);
});