简体   繁体   English

React组件可以在浏览器中正确渲染,但是Jest在渲染时会测试错误:“只有ReactOwner可以具有引用”

[英]React components render correctly in browser, but Jest test errors when rendering: “Only a ReactOwner can have refs”

I have two components in React that render just fine and produce expected behavior in the browser, but can't seem to be rendered when running a test via Jest. 我在React中有两个组件,它们可以很好地呈现并在浏览器中产生预期的行为,但是通过Jest运行测试时似乎无法呈现。

descriptions.js descriptions.js

var React = require('react/addons');
var $ = require('jquery');
var Description = require('./description.js');

var Descriptions = React.createClass({
    getInitialState: function () { //container always starts with at least one description field that is empty, or whatever is contained in props
        var descriptions = [];
        if (this.props.info == null) {
            descriptions.push({num: 0, data: ''});
        } else {
            $.each(this.props.info, function (i, string) {
                descriptions.push({num: i, data: string});
            });
            if (descriptions.length == 0) { //we want at least one description field at all times
                descriptions.push({num: 0, data: ''});
            }
        }
        return {descriptions: descriptions, focus: -1};
    },
    componentWillReceiveProps: function (nextProps) { //props are updated
        var descriptions = []; //we don't care about previous values, so we will make a new list
        $.each(nextProps.info, function (i, string) {
            descriptions.push({num: i, data: string});
        });
        if (descriptions.length == 0) { //we want at least one description field at all times
            descriptions.push({num: 0, data: ''});
        }
        this.setState({descriptions: descriptions});
    },
    addDescription: function (pos) { //adds a new description underneath the last one in the container
        var descriptions = this.state.descriptions;
        var max = 0;
        $.each(descriptions, function (i, item) {
            if (item.num > max) max = item.num;
        });
        descriptions.splice(pos + 1, 0, {num: max + 1, data: ''});
        this.setState({descriptions: descriptions, focus: pos + 1}); //focus the new description
    },
    removeDescription: function (pos) { //remove a description from the array given its array position
        var descriptions = this.state.descriptions;
        if (descriptions.length != 1) {
            descriptions.splice(pos, 1);
            this.setState({descriptions: descriptions, focus: pos == 0 ? 0 : pos - 1});
        }
    },
    render: function () {
        var items = this.state.descriptions.map(function (item, i) { //add one Description for every item in the array
            return (
                <Description key={item.num} addDescription={this.addDescription}
                             removeDescription={this.removeDescription}
                             descriptionNum={i} focus={i == this.state.focus} data={item.data}/>
            );
        }.bind(this));
        return (
            <div className="descriptions">
                {items}
            </div>
        );

    }
});

module.exports = Descriptions;

Essentially, this component is a container for one or more child "Description" components, and the amount of "Description" components that need to be rendered depends on the passed info prop, which holds an array of strings. 本质上,此组件是一个或多个子“描述”组件的容器,并且需要呈现的“描述”组件的数量取决于传递的info道具,该info道具包含一串字符串。

description.js description.js

var React = require('react/addons');

var Description = React.createClass({
    mixins: [React.addons.LinkedStateMixin],
    componentDidMount: function () { //focus the input if it was added after page load
        if (this.props.focus) {
            this.refs.descInput.getDOMNode().focus();
        }
    },
    componentWillReceiveProps: function (nextProps) {
        if (nextProps.focus) {
            this.refs.descInput.getDOMNode().focus();
        }
        this.setState({description: nextProps.data});
    },
    getInitialState: function () {
        return({description: this.props.data});
    },
    handleKeyDown: function (e) {
        var key = e.keyCode;
        if (key == 13) { //enter is pressed, we need to add a new line underneath this one
            e.preventDefault();
            this.props.addDescription(this.props.descriptionNum);
        } else if (key == 8) { //backspace was pressed, check to see if line is empty and remove if so
            var value = this.refs.descInput.getDOMNode().value;
            if (value == null || value == '') {
                e.preventDefault();
                this.props.removeDescription(this.props.descriptionNum);
            }
        }
    },
    render: function () {
        return (
            <div className="description">
                <input type="text" onKeyDown={this.handleKeyDown} valueLink={this.linkState('description')} ref="descInput"/>
            </div>
        )
    }
});

module.exports = Description;

This component receives a string (or nothing), sets its state to contain that string, and uses the LinkedStateMixin to update the state whenever the value of the input changes, and vice-versa. 此组件接收字符串(或不接收任何字符串),将其状态设置为包含该字符串,并在每次输入的值更改时使用LinkedStateMixin更新状态,反之亦然。

I thought I had no issues with these components, but the following Jest test... 我以为这些组件没有问题,但是下面的Jest测试...

descriptions-test.js descriptions-test.js

jest.dontMock('../js/descriptions.js');
var React = require('react/addons');
var TestUtils = React.addons.TestUtils;

describe('Descriptions', function () {
    it('creates exactly two Description components when given a string array of length 2', function() {
        jest.dontMock('../js/description.js');
        var Description = require('../js/description.js');
        var info = ['foo','bar'];
        var Descriptions = require('../js/descriptions.js');
        var descriptions = TestUtils.renderIntoDocument(<Descriptions info={info}/>);
        var array = TestUtils.scryRenderedComponentsWithType(descriptions, Description);
        expect(array.length).toEqual(2);
    });
});

...fails with the following error: ...失败,并出现以下错误:

● Descriptions › it mocks Description exactly twice when given info array of length 2
  - Error: Invariant Violation: addComponentAsRefTo(...): Only a ReactOwner can have refs. This usually means that you're trying to add a ref to a component that doesn't have an owner (that is, was not created inside of another component's `render` method). Try rendering this component inside of a new top-level component which will hold the ref.

...on this line: ...在此行上:

var descriptions = TestUtils.renderIntoDocument(<Descriptions info={info}/>);

This makes no sense to me as the components render fine in the browser without any issues. 这对我来说毫无意义,因为这些组件在浏览器中可以正常显示而没有任何问题。 It seems to only break when React's TestUtils attempts to do it. 它似乎只有在React的TestUtils尝试执行时才会中断。

Here are my dependencies: 这是我的依赖项:

package.json package.json

"dependencies": {
  "jquery": "^2.1.4",
  "react": "^0.13.3",
  "react-tools": "^0.13.3"
},
"devDependencies": {
  "browserify": "^10.2.1",
  "gulp": "^3.8.11",
  "gulp-react": "^3.0.1",
  "gulp-shell": "^0.4.1",
  "gulp-streamify": "0.0.5",
  "gulp-uglify": "~1.1.0",
  "jest-cli": "^0.4.5",
  "node-libs-browser": "^0.5.2",
  "reactify": "^1.1.1",
  "vinyl-source-stream": "^1.1.0",
  "watchify": "^3.2.1",
  "webpack": "^1.9.10"
}

Does anyone know what might be causing this error? 有人知道什么可能导致此错误吗?

Move the require out of the test function. require移出测试功能。

jest.dontMock('../js/descriptions.js');
var React = require('react/addons');
var Description = require('../js/description.js');
var Descriptions = require('../js/descriptions.js');

describe('Descriptions', function () {
    it('creates exactly two Description components when given a string array of length 2', function() {
        var TestUtils = React.addons.TestUtils;
        var info = ['foo','bar'];
        var descriptions = TestUtils.renderIntoDocument(<Descriptions info={info}/>);
        var array = TestUtils.scryRenderedComponentsWithType(descriptions, Description);
        expect(array.length).toEqual(2);
    });
});

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 只有ReactOwner可以具有引用 - Only a ReactOwner can have refs 未捕获的不变违反:addComponentAsRefTo(…):只有ReactOwner可以具有引用 - Uncaught Invariant Violation: addComponentAsRefTo(…): Only a ReactOwner can have refs addComponentAsRefTo(…):只有ReactOwner可以拥有refs-选择列表形式的错误 - addComponentAsRefTo(…): Only a ReactOwner can have refs - Error in Form with Select List 只有ReactOwner可以有refs。 您可能正在向组件的render方法中未创建的组件添加ref - Only a ReactOwner can have refs. You might be adding a ref to a component that was not created inside a component's render method 测试:`错误:永久违反:addComponentAsRefTo(...):只有ReactOwner可以具有引用。`错误 - Testing: `Error: Invariant Violation: addComponentAsRefTo(…): Only a ReactOwner can have refs.` error React动态组件缺少ReactOwner - React dynamic components missing ReactOwner 与多个反应组件一起使用时,svg 无法正确呈现 - svg not rendering correctly when used with by multiple react components 当父级和子级是功能组件时,反应引用 - React refs when parent and child are function components React context api 仅呈现使用已更改值的组件 - React context api only render components that use values that have changed 在使用 react-test-renderer 的 Jest 快照测试中,Refs 为空 - Refs are null in Jest snapshot tests with react-test-renderer
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM