I have two components in React that perfectly display and produce the expected behavior in the browser, but cannot display when the test runs through Jest.
descriptions.js
var React = require('react/addons'); var $ = require('jquery'); var Description = require('./description.js'); var Descriptions = React.createClass({ getInitialState: function () {
Essentially, this component is a container for one or more child components of the Description, and the number of Description components that need to be visualized depends on the transmitted info prop, which contains an array of strings.
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 this string, and uses LinkedStateMixin to update the state whenever the input value changes and vice versa.
I thought I had no problems with these components, but the next Jest test ...
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 `render` method). Try rendering this component inside of a new top-level component which will hold the ref.
... in this line:
var descriptions = TestUtils.renderIntoDocument(<Descriptions info={info}/>);
This does not make any sense to me, since the components are not displayed in the browser without any problems. It only seems to break when React TestUtils tries to do this.
Here are my dependencies:
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 cause this error?