Warn when accessing .props, .setProps on DOM components

This commit is contained in:
Ben Alpert committed 2015-06-08 10:36:20 -07:00
1 parent ba81b60ad8
commit bfcad9614a
14 files changed
+324 -151

No files matched your search

@@ -15,45 +15,16 @@ describe('sliceChildren', function() {
var React;
var ReactFragment;
var ReactTestUtils;
var sliceChildren;
var reactComponentExpect;
var Partial;
beforeEach(function() {
React = require('React');
ReactFragment = require('ReactFragment');
ReactTestUtils = require('ReactTestUtils');
sliceChildren = require('sliceChildren');
reactComponentExpect = require('reactComponentExpect');
Partial = React.createClass({
render: function() {
return (
<div>
{sliceChildren(
this.props.children,
this.props.start,
this.props.end
)}
</div>
);
},
});
});
function renderAndSlice(set, start, end) {
var instance = <Partial start={start} end={end}>{set}</Partial>;
instance = ReactTestUtils.renderIntoDocument(instance);
var rendered = reactComponentExpect(instance)
.expectRenderedChild()
.instance();
return rendered.props.children;
}
function testKeyValuePairs(children, expectedPairs) {
var obj = ReactFragment.extract(children);
expect(obj).toEqual(expectedPairs);
@@ -65,7 +36,7 @@ describe('sliceChildren', function() {
<div key="B" />,
<div key="C" />,
];
var children = renderAndSlice(fullSet, 0);
var children = sliceChildren(fullSet, 0);
testKeyValuePairs(children, {
'.$A': fullSet[0],
'.$B': fullSet[1],
@@ -79,7 +50,7 @@ describe('sliceChildren', function() {
<div key="B" />,
<div key="C" />,
];
var children = renderAndSlice(fullSet, 1);
var children = sliceChildren(fullSet, 1);
testKeyValuePairs(children, {
'.$B': fullSet[1],
'.$C': fullSet[2],
@@ -93,7 +64,7 @@ describe('sliceChildren', function() {
<div key="C" />,
<div key="D" />,
];
var children = renderAndSlice(fullSet, 1, 2);
var children = sliceChildren(fullSet, 1, 2);
testKeyValuePairs(children, {
'.$B': fullSet[1],
});
@@ -104,13 +75,9 @@ describe('sliceChildren', function() {
var b = <div />;
var c = <div />;
var instance = <Partial start={1} end={2}>{a}{b}{c}</Partial>;
instance = ReactTestUtils.renderIntoDocument(instance);
var rendered = reactComponentExpect(instance)
.expectRenderedChild()
.instance();
testKeyValuePairs(rendered.props.children, {
var el = <div>{a}{b}{c}</div>;
var children = sliceChildren(el.props.children, 1, 2);
testKeyValuePairs(children, {
'.1': b,
});
});
@@ -79,32 +79,32 @@ describe('ReactDOM', function() {
</div>
);
// Warm the cache with theDog
myDiv.setProps({
children: [
myDiv = ReactTestUtils.renderIntoDocument(
<div>
<div key="theDog" className="dogbeforedelete" />,
<div key="theBird" className="bird" />,
],
});
</div>
);
// Remove theDog - this should purge the cache
myDiv.setProps({
children: [
myDiv = ReactTestUtils.renderIntoDocument(
<div>
<div key="theBird" className="bird" />,
],
});
</div>
);
// Now, put theDog back. It's now a different DOM node.
myDiv.setProps({
children: [
myDiv = ReactTestUtils.renderIntoDocument(
<div>
<div key="theDog" className="dog" />,
<div key="theBird" className="bird" />,
],
});
</div>
);
// Change the className of theDog. It will use the same element
myDiv.setProps({
children: [
myDiv = ReactTestUtils.renderIntoDocument(
<div>
<div key="theDog" className="bigdog" />,
<div key="theBird" className="bird" />,
],
});
</div>
);
var root = React.findDOMNode(myDiv);
var dog = root.childNodes[0];
expect(dog.className).toBe('bigdog');
@@ -53,27 +53,41 @@ describe('ReactDOMButton', function() {
});
it('should forward clicks when it becomes not disabled', function() {
var btn = mounted(<button disabled={true} onClick={onClick} />);
btn.setProps({disabled: false});
var container = document.createElement('div');
var btn = React.render(
<button disabled={true} onClick={onClick} />,
container
);
btn = React.render(
<button onClick={onClick} />,
container
);
expectClickThru(btn);
});
it('should not forward clicks when it becomes disabled', function() {
var btn = mounted(<button onClick={onClick} />);
btn.setProps({disabled: true});
var container = document.createElement('div');
var btn = React.render(
<button onClick={onClick} />,
container
);
btn = React.render(
<button disabled={true} onClick={onClick} />,
container
);
expectNoClickThru(btn);
});
it('should work correctly if the listener is changed', function() {
var btn = mounted(
<button disabled={true} onClick={function() {}} />
var container = document.createElement('div');
var btn = React.render(
<button disabled={true} onClick={function() {}} />,
container
);
btn = React.render(
<button disabled={false} onClick={onClick} />,
container
);
btn.setProps({
disabled: false,
onClick: onClick,
});
expectClickThru(btn);
});
});
@@ -75,30 +75,39 @@ describe('ReactDOMInput', function() {
});
it('should allow setting `value` to `true`', function() {
var container = document.createElement('div');
var stub = <input type="text" value="yolo" onChange={emptyFunction} />;
stub = ReactTestUtils.renderIntoDocument(stub);
stub = React.render(stub, container);
var node = React.findDOMNode(stub);
expect(node.value).toBe('yolo');
stub.replaceProps({value: true, onChange: emptyFunction});
stub = React.render(
<input type="text" value={true} onChange={emptyFunction} />,
container
);
expect(node.value).toEqual('true');
});
it('should allow setting `value` to `false`', function() {
var container = document.createElement('div');
var stub = <input type="text" value="yolo" onChange={emptyFunction} />;
stub = ReactTestUtils.renderIntoDocument(stub);
stub = React.render(stub, container);
var node = React.findDOMNode(stub);
expect(node.value).toBe('yolo');
stub.replaceProps({value: false});
stub = React.render(
<input type="text" value={false} onChange={emptyFunction} />,
container
);
expect(node.value).toEqual('false');
});
it('should allow setting `value` to `objToString`', function() {
var container = document.createElement('div');
var stub = <input type="text" value="foo" onChange={emptyFunction} />;
stub = ReactTestUtils.renderIntoDocument(stub);
stub = React.render(stub, container);
var node = React.findDOMNode(stub);
expect(node.value).toBe('foo');
@@ -108,8 +117,10 @@ describe('ReactDOMInput', function() {
return 'foobar';
},
};
stub.replaceProps({value: objToString, onChange: emptyFunction});
stub = React.render(
<input type="text" value={objToString} onChange={emptyFunction} />,
container
);
expect(node.value).toEqual('foobar');
});
@@ -32,13 +32,18 @@ describe('ReactDOMSelect', function() {
<option value="giraffe">A giraffe!</option>
<option value="gorilla">A gorilla!</option>
</select>;
stub = ReactTestUtils.renderIntoDocument(stub);
var options = stub.props.children;
var container = document.createElement('div');
stub = React.render(stub, container);
var node = React.findDOMNode(stub);
expect(node.value).toBe('giraffe');
// Changing `defaultValue` should do nothing.
stub.setProps({defaultValue: 'gorilla'});
React.render(
<select defaultValue="gorilla">{options}</select>,
container
);
expect(node.value).toEqual('giraffe');
});
@@ -51,19 +56,20 @@ describe('ReactDOMSelect', function() {
});
it('should not control when using `defaultValue`', function() {
var stub =
var el =
<select defaultValue="giraffe">
<option value="monkey">A monkey!</option>
<option value="giraffe">A giraffe!</option>
<option value="gorilla">A gorilla!</option>
</select>;
stub = ReactTestUtils.renderIntoDocument(stub);
var container = document.createElement('div');
var stub = React.render(el, container);
var node = React.findDOMNode(stub);
expect(node.value).toBe('giraffe');
node.value = 'monkey';
stub.forceUpdate();
React.render(el, container);
// Uncontrolled selects shouldn't change the value after first mounting
expect(node.value).toEqual('monkey');
});
@@ -75,7 +81,9 @@ describe('ReactDOMSelect', function() {
<option value="giraffe">A giraffe!</option>
<option value="gorilla">A gorilla!</option>
</select>;
stub = ReactTestUtils.renderIntoDocument(stub);
var options = stub.props.children;
var container = document.createElement('div');
stub = React.render(stub, container);
var node = React.findDOMNode(stub);
expect(node.options[0].selected).toBe(false); // monkey
@@ -83,7 +91,10 @@ describe('ReactDOMSelect', function() {
expect(node.options[2].selected).toBe(true); // gorilla
// Changing `defaultValue` should do nothing.
stub.setProps({defaultValue: ['monkey']});
React.render(
<select multiple={true} defaultValue={['monkey']}>{options}</select>,
container
);
expect(node.options[0].selected).toBe(false); // monkey
expect(node.options[1].selected).toBe(true); // giraffe
@@ -97,13 +108,18 @@ describe('ReactDOMSelect', function() {
<option value="giraffe">A giraffe!</option>
<option value="gorilla">A gorilla!</option>
</select>;
stub = ReactTestUtils.renderIntoDocument(stub);
var options = stub.props.children;
var container = document.createElement('div');
stub = React.render(stub, container);
var node = React.findDOMNode(stub);
expect(node.value).toBe('giraffe');
// Changing the `value` prop should change the selected option.
stub.setProps({value: 'gorilla'});
React.render(
<select value="gorilla">{options}</select>,
container
);
expect(node.value).toEqual('gorilla');
});
@@ -122,7 +138,9 @@ describe('ReactDOMSelect', function() {
<option value="giraffe">A giraffe!</option>
<option value="gorilla">A gorilla!</option>
</select>;
stub = ReactTestUtils.renderIntoDocument(stub);
var options = stub.props.children;
var container = document.createElement('div');
stub = React.render(stub, container);
var node = React.findDOMNode(stub);
expect(node.options[0].selected).toBe(false); // monkey
@@ -130,7 +148,10 @@ describe('ReactDOMSelect', function() {
expect(node.options[2].selected).toBe(true); // gorilla
// Changing the `value` prop should change the selected options.
stub.setProps({value: ['monkey']});
React.render(
<select multiple={true} value={['monkey']}>{options}</select>,
container
);
expect(node.options[0].selected).toBe(true); // monkey
expect(node.options[1].selected).toBe(false); // giraffe
@@ -154,15 +175,17 @@ describe('ReactDOMSelect', function() {
it('should reset child options selected when they are changed and `value` is set', function() {
var stub = <select multiple={true} value={['a', 'b']} />;
stub = ReactTestUtils.renderIntoDocument(stub);
var container = document.createElement('div');
stub = React.render(stub, container);
stub.setProps({
children: [
<option value="a">a</option>,
<option value="b">b</option>,
<option value="c">c</option>,
],
});
React.render(
<select multiple={true} value={['a', 'b']}>
<option value="a">a</option>
<option value="b">b</option>
<option value="c">c</option>
</select>,
container
);
var node = React.findDOMNode(stub);
@@ -179,13 +202,14 @@ describe('ReactDOMSelect', function() {
},
};
var stub =
var el =
<select multiple={true} value={[objectToString]}>
<option value="monkey">A monkey!</option>
<option value="giraffe">A giraffe!</option>
<option value="gorilla">A gorilla!</option>
</select>;
stub = ReactTestUtils.renderIntoDocument(stub);
var container = document.createElement('div');
var stub = React.render(el, container);
var node = React.findDOMNode(stub);
expect(node.options[0].selected).toBe(false); // monkey
@@ -194,7 +218,7 @@ describe('ReactDOMSelect', function() {
// Changing the `value` prop should change the selected options.
objectToString.animal = 'monkey';
stub.forceUpdate();
React.render(el, container);
expect(node.options[0].selected).toBe(true); // monkey
expect(node.options[1].selected).toBe(false); // giraffe
@@ -208,7 +232,9 @@ describe('ReactDOMSelect', function() {
<option value="giraffe">A giraffe!</option>
<option value="gorilla">A gorilla!</option>
</select>;
stub = ReactTestUtils.renderIntoDocument(stub);
var options = stub.props.children;
var container = document.createElement('div');
stub = React.render(stub, container);
var node = React.findDOMNode(stub);
expect(node.options[0].selected).toBe(false); // monkey
@@ -216,7 +242,12 @@ describe('ReactDOMSelect', function() {
expect(node.options[2].selected).toBe(false); // gorilla
// When making it multiple, giraffe and gorilla should be selected
stub.setProps({multiple: true, defaultValue: ['giraffe', 'gorilla']});
React.render(
<select multiple={true} defaultValue={['giraffe', 'gorilla']}>
{options}
</select>,
container
);
expect(node.options[0].selected).toBe(false); // monkey
expect(node.options[1].selected).toBe(true); // giraffe
@@ -230,7 +261,9 @@ describe('ReactDOMSelect', function() {
<option value="giraffe">A giraffe!</option>
<option value="gorilla">A gorilla!</option>
</select>;
stub = ReactTestUtils.renderIntoDocument(stub);
var options = stub.props.children;
var container = document.createElement('div');
stub = React.render(stub, container);
var node = React.findDOMNode(stub);
expect(node.options[0].selected).toBe(false); // monkey
@@ -239,7 +272,11 @@ describe('ReactDOMSelect', function() {
// When removing multiple, defaultValue is applied again, being omitted
// means that "monkey" will be selected
stub.setProps({multiple: false, defaultValue: 'gorilla'});
React.render(
<select defaultValue="gorilla">{options}</select>,
container
);
expect(node.options[0].selected).toBe(false); // monkey
expect(node.options[1].selected).toBe(false); // giraffe
@@ -253,14 +290,16 @@ describe('ReactDOMSelect', function() {
<option value="giraffe">A giraffe!</option>
<option value="gorilla">A gorilla!</option>
</select>;
stub = ReactTestUtils.renderIntoDocument(stub);
var options = stub.props.children;
var container = document.createElement('div');
stub = React.render(stub, container);
var node = React.findDOMNode(stub);
expect(node.options[0].selected).toBe(false); // monkey
expect(node.options[1].selected).toBe(true); // giraffe
expect(node.options[2].selected).toBe(false); // gorilla
stub.setProps({value: null});
React.render(<select>{options}</select>, container);
expect(node.options[0].selected).toBe(false); // monkey
expect(node.options[1].selected).toBe(true); // giraffe
@@ -274,16 +313,18 @@ describe('ReactDOMSelect', function() {
<option value="giraffe">A giraffe!</option>
<option value="gorilla">A gorilla!</option>
</select>;
stub = ReactTestUtils.renderIntoDocument(stub);
var options = stub.props.children;
var container = document.createElement('div');
stub = React.render(stub, container);
var node = React.findDOMNode(stub);
stub.setProps({value: 'gorilla'});
React.render(<select value="gorilla">{options}</select>, container);
expect(node.options[0].selected).toBe(false); // monkey
expect(node.options[1].selected).toBe(false); // giraffe
expect(node.options[2].selected).toBe(true); // gorilla
stub.setProps({value: null});
React.render(<select>{options}</select>, container);
expect(node.options[0].selected).toBe(false); // monkey
expect(node.options[1].selected).toBe(false); // giraffe
@@ -26,8 +26,11 @@ describe('ReactDOMTextarea', function() {
ReactLink = require('ReactLink');
ReactTestUtils = require('ReactTestUtils');
renderTextarea = function(component) {
var stub = ReactTestUtils.renderIntoDocument(component);
renderTextarea = function(component, container) {
if (!container) {
container = document.createElement('div');
}
var stub = React.render(component, container);
var node = React.findDOMNode(stub);
// Fixing jsdom's quirky behavior -- in reality, the parser should strip
// off the leading newline but we need to do it by hand here.
@@ -37,14 +40,14 @@ describe('ReactDOMTextarea', function() {
});
it('should allow setting `defaultValue`', function() {
var stub = <textarea defaultValue="giraffe" />;
stub = renderTextarea(stub);
var container = document.createElement('div');
var stub = renderTextarea(<textarea defaultValue="giraffe" />, container);
var node = React.findDOMNode(stub);
expect(node.value).toBe('giraffe');
// Changing `defaultValue` should do nothing.
stub.replaceProps({defaultValue: 'gorilla'});
stub = renderTextarea(<textarea defaultValue="gorilla" />, container);
expect(node.value).toEqual('giraffe');
});
@@ -95,41 +98,54 @@ describe('ReactDOMTextarea', function() {
});
it('should allow setting `value` to `giraffe`', function() {
var container = document.createElement('div');
var stub = <textarea value="giraffe" onChange={emptyFunction} />;
stub = renderTextarea(stub);
stub = renderTextarea(stub, container);
var node = React.findDOMNode(stub);
expect(node.value).toBe('giraffe');
stub.replaceProps({value: 'gorilla', onChange: emptyFunction});
stub = React.render(
<textarea value="gorilla" onChange={emptyFunction} />,
container
);
expect(node.value).toEqual('gorilla');
});
it('should allow setting `value` to `true`', function() {
var container = document.createElement('div');
var stub = <textarea value="giraffe" onChange={emptyFunction} />;
stub = renderTextarea(stub);
stub = renderTextarea(stub, container);
var node = React.findDOMNode(stub);
expect(node.value).toBe('giraffe');
stub.replaceProps({value: true, onChange: emptyFunction});
stub = React.render(
<textarea value={true} onChange={emptyFunction} />,
container
);
expect(node.value).toEqual('true');
});
it('should allow setting `value` to `false`', function() {
var container = document.createElement('div');
var stub = <textarea value="giraffe" onChange={emptyFunction} />;
stub = renderTextarea(stub);
stub = renderTextarea(stub, container);
var node = React.findDOMNode(stub);
expect(node.value).toBe('giraffe');
stub.replaceProps({value: false});
stub = React.render(
<textarea value={false} onChange={emptyFunction} />,
container
);
expect(node.value).toEqual('false');
});
it('should allow setting `value` to `objToString`', function() {
var container = document.createElement('div');
var stub = <textarea value="giraffe" onChange={emptyFunction} />;
stub = renderTextarea(stub);
stub = renderTextarea(stub, container);
var node = React.findDOMNode(stub);
expect(node.value).toBe('giraffe');
@@ -139,7 +155,10 @@ describe('ReactDOMTextarea', function() {
return 'foo';
},
};
stub.replaceProps({value: objToString, onChange: emptyFunction});
stub = React.render(
<textarea value={objToString} onChange={emptyFunction} />,
container
);
expect(node.value).toEqual('foo');
});
@@ -156,15 +175,16 @@ describe('ReactDOMTextarea', function() {
it('should treat children like `defaultValue`', function() {
spyOn(console, 'error');
var container = document.createElement('div');
var stub = <textarea>giraffe</textarea>;
stub = renderTextarea(stub);
stub = renderTextarea(stub, container);
var node = React.findDOMNode(stub);
expect(console.error.argsForCall.length).toBe(1);
expect(node.value).toBe('giraffe');
// Changing children should do nothing, it functions like `defaultValue`.
stub.replaceProps({children: 'gorilla'});
stub = React.render(<textarea>gorilla</textarea>, container);
expect(node.value).toEqual('giraffe');
});
@@ -38,8 +38,27 @@ var ServerReactRootIndex = require('ServerReactRootIndex');
var SimpleEventPlugin = require('SimpleEventPlugin');
var SVGDOMPropertyConfig = require('SVGDOMPropertyConfig');
var warning = require('warning');
var deprecatedDOMMethods = [
'isMounted', 'replaceProps', 'replaceState', 'setProps', 'setState',
'forceUpdate',
];
function getDeclarationErrorAddendum(domWrapperClass) {
var internalInstance = ReactInstanceMap.get(domWrapperClass);
var owner = internalInstance._currentElement._owner || null;
if (owner) {
var name = owner.getName();
if (name) {
return ' This DOM component was rendered by `' + name + '`.';
}
}
return '';
}
function autoGenerateWrapperClass(type) {
return ReactClass.createClass({
var wrapperClass = ReactClass.createClass({
tagName: type.toUpperCase(),
render: function() {
// Copy owner down for debugging info
@@ -49,10 +68,51 @@ function autoGenerateWrapperClass(type) {
null, // key
null, // ref
internalInstance._currentElement._owner, // owner
this.props
this._internalProps
);
},
});
Object.defineProperty(wrapperClass.prototype, 'props', {
enumerable: true,
set: function(props) {
this._internalProps = props;
},
get: function() {
if (__DEV__) {
warning(
false,
'ReactDOMComponent.props: Do not access .props of a DOM component ' +
'directly; instead, recreate the props as `render` did originally ' +
'or use React.findDOMNode and read the DOM properties/attributes ' +
'directly.%s',
getDeclarationErrorAddendum(this)
);
}
return this._internalProps;
},
});
deprecatedDOMMethods.forEach(function(method) {
var old = wrapperClass.prototype[method];
Object.defineProperty(wrapperClass.prototype, method, {
enumerable: true,
get: function() {
if (__DEV__) {
warning(
false,
'ReactDOMComponent.%s(): Do not access .%s() of a DOM component.%s',
method,
method,
getDeclarationErrorAddendum(this)
);
}
return old;
},
});
});
return wrapperClass;
}
var alreadyInjected = false;
@@ -902,4 +902,41 @@ describe('ReactDOMComponent', function() {
});
});
describe('DOM nodes as refs', function() {
var React;
var ReactTestUtils;
beforeEach(function() {
React = require('React');
ReactTestUtils = require('ReactTestUtils');
});
it('warns when accessing properties on DOM components', function() {
spyOn(console, 'error');
var Animal = React.createClass({
render: function() {
return <div ref="div">iguana</div>;
},
componentDidMount: function() {
void this.refs.div.props;
void this.refs.div.setProps;
},
});
ReactTestUtils.renderIntoDocument(<Animal />);
expect(console.error.calls.length).toBe(2);
expect(console.error.calls[0].args[0]).toBe(
'Warning: ReactDOMComponent.props: Do not access .props of a DOM ' +
'component directly; instead, recreate the props as `render` did ' +
'originally or use React.findDOMNode and read the DOM ' +
'properties/attributes directly. This DOM component was rendered ' +
'by `Animal`.'
);
expect(console.error.calls[1].args[0]).toBe(
'Warning: ReactDOMComponent.setProps(): Do not access .setProps() of ' +
'a DOM component. This DOM component was rendered by `Animal`.'
);
});
});
});
@@ -557,11 +557,16 @@ var ReactCompositeComponentMixin = {
) {
var inst = this._instance;
var nextContext = inst.context;
var nextProps = inst.props;
var nextContext;
var nextProps;
// Distinguish between a props update versus a simple state update
if (prevParentElement !== nextParentElement) {
if (prevParentElement === nextParentElement) {
nextContext = inst.context;
// Skip checking prop types again -- we don't read inst.props to avoid
// warning for DOM component props in this upgrade
nextProps = nextParentElement.props;
} else {
nextContext = this._processContext(nextUnmaskedContext);
nextProps = this._processProps(nextParentElement.props);
@@ -663,9 +668,15 @@ var ReactCompositeComponentMixin = {
) {
var inst = this._instance;
var prevProps = inst.props;
var prevState = inst.state;
var prevContext = inst.context;
var hasComponentDidUpdate = Boolean(inst.componentDidUpdate);
var prevProps;
var prevState;
var prevContext;
if (hasComponentDidUpdate) {
prevProps = inst.props;
prevState = inst.state;
prevContext = inst.context;
}
if (inst.componentWillUpdate) {
inst.componentWillUpdate(nextProps, nextState, nextContext);
@@ -679,7 +690,7 @@ var ReactCompositeComponentMixin = {
this._updateRenderedComponent(transaction, unmaskedContext);
if (inst.componentDidUpdate) {
if (hasComponentDidUpdate) {
transaction.getReactMountReady().enqueue(
inst.componentDidUpdate.bind(inst, prevProps, prevState, prevContext),
inst
@@ -135,6 +135,9 @@ describe('ReactComponent', function() {
it('should support new-style refs with mixed-up owners', function() {
var Wrapper = React.createClass({
getTitle: function() {
return this.props.title;
},
render: function() {
return this.props.getContent();
},
@@ -158,8 +161,8 @@ describe('ReactComponent', function() {
},
componentDidMount: function() {
// Check .props.title to make sure we got the right elements back
expect(this.wrapperRef.props.title).toBe('wrapper');
expect(this.innerRef.props.title).toBe('inner');
expect(this.wrapperRef.getTitle()).toBe('wrapper');
expect(React.findDOMNode(this.innerRef).title).toBe('inner');
mounted = true;
},
});
@@ -464,15 +464,20 @@ describe('ReactComponentLifeCycle', function() {
/**
* calls setProps in an componentDidMount.
*/
var Inner = React.createClass({
render: function() {
return <div />;
},
});
var PropsUpdaterInOnDOMReady = React.createClass({
componentDidMount: function() {
this.refs.theSimpleComponent.setProps({
valueToUseInitially: this.props.valueToUseInOnDOMReady,
className: this.props.valueToUseInOnDOMReady,
});
},
render: function() {
return (
<div
<Inner
className={this.props.valueToUseInitially}
ref="theSimpleComponent"
/>
@@ -385,9 +385,14 @@ describe('ReactCompositeComponent', function() {
var innerInstance;
var Inner = React.createClass({
render: function() {
return <div />;
},
});
var Component = React.createClass({
render: function() {
return <div><div ref="inner" /></div>;
return <div><Inner ref="inner" /></div>;
},
componentDidMount: function() {
innerInstance = this.refs.inner;
@@ -31,25 +31,16 @@ var testAllPermutations = function(testCases) {
var updateWithChildren = testCases[j];
var expectedResultAfterUpdate = testCases[j + 1];
var d = renderChildren(renderWithChildren);
var container = document.createElement('div');
var d = React.render(<div>{renderWithChildren}</div>, container);
expectChildren(d, expectedResultAfterRender);
updateChildren(d, updateWithChildren);
d = React.render(<div>{updateWithChildren}</div>, container);
expectChildren(d, expectedResultAfterUpdate);
}
}
};
var renderChildren = function(children) {
return ReactTestUtils.renderIntoDocument(
<div>{children}</div>
);
};
var updateChildren = function(d, children) {
d.replaceProps({children: children});
};
var expectChildren = function(d, children) {
var textNode;
if (typeof children === 'string') {
+13 -5
View File
@@ -77,6 +77,11 @@ var ReactTestUtils = {
},
isCompositeComponent: function(inst) {
if (ReactTestUtils.isDOMComponent(inst)) {
// Accessing inst.setState warns; just return false as that'll be what
// this returns when we have DOM nodes as refs directly
return false;
}
return typeof inst.render === 'function' &&
typeof inst.setState === 'function';
},
@@ -165,11 +170,14 @@ var ReactTestUtils = {
*/
scryRenderedDOMComponentsWithClass: function(root, className) {
return ReactTestUtils.findAllInRenderedTree(root, function(inst) {
var instClassName = inst.props.className;
return ReactTestUtils.isDOMComponent(inst) && (
instClassName &&
(' ' + instClassName + ' ').indexOf(' ' + className + ' ') !== -1
);
if (ReactTestUtils.isDOMComponent(inst)) {
var instClassName = React.findDOMNode(inst).className;
return (
instClassName &&
(' ' + instClassName + ' ').indexOf(' ' + className + ' ') !== -1
);
}
return false;
});
},