簡體   English   中英

React組件可以在瀏覽器中正確渲染,但是Jest在渲染時會測試錯誤:“只有ReactOwner可以具有引用”

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

我在React中有兩個組件,它們可以很好地呈現並在瀏覽器中產生預期的行為,但是通過Jest運行測試時似乎無法呈現。

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;

本質上,此組件是一個或多個子“描述”組件的容器,並且需要呈現的“描述”組件的數量取決於傳遞的info道具,該info道具包含一串字符串。

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;

此組件接收字符串(或不接收任何字符串),將其狀態設置為包含該字符串,並在每次輸入的值更改時使用LinkedStateMixin更新狀態,反之亦然。

我以為這些組件沒有問題,但是下面的Jest測試...

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);
    });
});

...失敗,並出現以下錯誤:

● 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.

...在此行上:

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

這對我來說毫無意義,因為這些組件在瀏覽器中可以正常顯示而沒有任何問題。 它似乎只有在React的TestUtils嘗試執行時才會中斷。

這是我的依賴項:

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"
}

有人知道什么可能導致此錯誤嗎?

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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM