Merge pull request #9101 from sebmarkbage/prettier

Use Prettier
This commit is contained in:
James Long
2017-03-14 15:33:27 -07:00
committed by GitHub
328 changed files with 12754 additions and 11395 deletions
+3 -2
View File
@@ -23,7 +23,7 @@ module.exports = {
'dot-notation': ERROR,
'eol-last': ERROR,
'eqeqeq': [ERROR, 'allow-null'],
'indent': [ERROR, 2, {SwitchCase: 1}],
'indent': OFF,
'jsx-quotes': [ERROR, 'prefer-double'],
'keyword-spacing': [ERROR, {after: true, before: true}],
'no-bitwise': OFF,
@@ -33,9 +33,10 @@ module.exports = {
'no-shadow': ERROR,
'no-unused-expressions': ERROR,
'no-unused-vars': [ERROR, {args: 'none'}],
'no-useless-concat': OFF,
'quotes': [ERROR, 'single', {avoidEscape: true, allowTemplateLiterals: true }],
'space-before-blocks': ERROR,
'space-before-function-paren': [ERROR, {anonymous: 'never', named: 'never'}],
'space-before-function-paren': OFF,
// React & JSX
// Our transforms set this automatically
+3 -1
View File
@@ -71,6 +71,7 @@
"merge-stream": "^1.0.0",
"object-assign": "^4.1.1",
"platform": "^1.1.0",
"prettier": "^0.22.0",
"run-sequence": "^1.1.4",
"through2": "^2.0.0",
"tmp": "~0.0.28",
@@ -92,7 +93,8 @@
"lint": "grunt lint",
"postinstall": "node node_modules/fbjs-scripts/node/check-dev-engines.js package.json",
"test": "jest",
"flow": "flow"
"flow": "flow",
"prettier": "prettier --write --no-bracket-spacing --single-quote --jsx-bracket-same-line --trailing-comma all --print-width 80 \"src/**/!(third_party)/*.js\""
},
"jest": {
"modulePathIgnorePatterns": [
+1
View File
@@ -12,3 +12,4 @@
// Noop
// TODO #10932517: Move all initialization callers back into react-native
+3 -3
View File
@@ -16,15 +16,15 @@ var deepDiffer = function(one: any, two: any): boolean {
// Short circuit on identical object references instead of traversing them.
return false;
}
if ((typeof one === 'function') && (typeof two === 'function')) {
if (typeof one === 'function' && typeof two === 'function') {
// We consider all functions equal
return false;
}
if ((typeof one !== 'object') || (one === null)) {
if (typeof one !== 'object' || one === null) {
// Primitives can be directly compared
return one !== two;
}
if ((typeof two !== 'object') || (two === null)) {
if (typeof two !== 'object' || two === null) {
// We know they are different because the previous case would have triggered
// otherwise.
return true;
@@ -11,6 +11,6 @@
// TODO: move into react or fbjs
var deepFreezeAndThrowOnMutationInDev = function() { };
var deepFreezeAndThrowOnMutationInDev = function() {};
module.exports = deepFreezeAndThrowOnMutationInDev;
+1 -1
View File
@@ -11,6 +11,6 @@
// TODO: Move flattenStyle into react
var flattenStyle = function() { };
var flattenStyle = function() {};
module.exports = flattenStyle;
+5 -5
View File
@@ -41,7 +41,7 @@ var ReactFragment = {
warning(
false,
'React.addons.createFragment only accepts a single object. Got: %s',
object
object,
);
return object;
}
@@ -49,7 +49,7 @@ var ReactFragment = {
warning(
false,
'React.addons.createFragment does not accept a ReactElement ' +
'without a wrapper object.'
'without a wrapper object.',
);
return object;
}
@@ -57,7 +57,7 @@ var ReactFragment = {
invariant(
object.nodeType !== 1,
'React.addons.createFragment(...): Encountered an invalid child; DOM ' +
'elements are not valid children of React components.'
'elements are not valid children of React components.',
);
var result = [];
@@ -68,7 +68,7 @@ var ReactFragment = {
warning(
false,
'React.addons.createFragment(...): Child objects should have ' +
'non-numeric keys so ordering is preserved.'
'non-numeric keys so ordering is preserved.',
);
warnedAboutNumeric = true;
}
@@ -77,7 +77,7 @@ var ReactFragment = {
object[key],
result,
key,
emptyFunction.thatReturnsArgument
emptyFunction.thatReturnsArgument,
);
}
+1 -2
View File
@@ -13,8 +13,7 @@
var React = require('react');
var ReactAddonsDOMDependencies = require('ReactAddonsDOMDependencies');
var ReactComponentWithPureRenderMixin =
require('ReactComponentWithPureRenderMixin');
var ReactComponentWithPureRenderMixin = require('ReactComponentWithPureRenderMixin');
var ReactCSSTransitionGroup = require('ReactCSSTransitionGroup');
var ReactFragment = require('ReactFragment');
var ReactTransitionGroup = require('ReactTransitionGroup');
@@ -16,11 +16,9 @@ var ReactComponentWithPureRenderMixin;
var ReactTestUtils;
describe('ReactComponentWithPureRenderMixin', () => {
beforeEach(() => {
React = require('react');
ReactComponentWithPureRenderMixin =
require('ReactComponentWithPureRenderMixin');
ReactComponentWithPureRenderMixin = require('ReactComponentWithPureRenderMixin');
ReactTestUtils = require('ReactTestUtils');
});
@@ -35,12 +33,7 @@ describe('ReactComponentWithPureRenderMixin', () => {
}
render() {
return (
<Apple
color={this.state.color}
ref="apple"
/>
);
return <Apple color={this.state.color} ref="apple" />;
}
}
@@ -141,5 +134,4 @@ describe('ReactComponentWithPureRenderMixin', () => {
instance.setState(getInitialState());
expect(renderCalls).toBe(3);
});
});
+10 -12
View File
@@ -16,7 +16,6 @@ var ReactDOM;
var ReactFragment;
describe('ReactFragment', () => {
beforeEach(() => {
React = require('react');
ReactDOM = require('react-dom');
@@ -33,9 +32,9 @@ describe('ReactFragment', () => {
var container = document.createElement('div');
expect(() => ReactDOM.render(element, container)).toThrowError(
'Objects are not valid as a React child (found: object with keys ' +
'{x, y, z}). If you meant to render a collection of children, use an ' +
'array instead or wrap the object using createFragment(object) from ' +
'the React add-ons.'
'{x, y, z}). If you meant to render a collection of children, use an ' +
'array instead or wrap the object using createFragment(object) from ' +
'the React add-ons.',
);
});
@@ -53,9 +52,9 @@ describe('ReactFragment', () => {
var container = document.createElement('div');
expect(() => ReactDOM.render(<Foo />, container)).toThrowError(
'Objects are not valid as a React child (found: object with keys ' +
'{a, b, c}). If you meant to render a collection of children, use an ' +
'array instead or wrap the object using createFragment(object) from ' +
'the React add-ons.\n\nCheck the render method of `Foo`.'
'{a, b, c}). If you meant to render a collection of children, use an ' +
'array instead or wrap the object using createFragment(object) from ' +
'the React add-ons.\n\nCheck the render method of `Foo`.',
);
});
@@ -66,7 +65,7 @@ describe('ReactFragment', () => {
expectDev(console.error.calls.count()).toBe(1);
expectDev(console.error.calls.argsFor(0)[0]).toContain(
'Child objects should have non-numeric keys so ordering is preserved.'
'Child objects should have non-numeric keys so ordering is preserved.',
);
});
@@ -75,7 +74,7 @@ describe('ReactFragment', () => {
ReactFragment.create(null);
expectDev(console.error.calls.count()).toBe(1);
expectDev(console.error.calls.argsFor(0)[0]).toContain(
'React.addons.createFragment only accepts a single object.'
'React.addons.createFragment only accepts a single object.',
);
});
@@ -84,7 +83,7 @@ describe('ReactFragment', () => {
ReactFragment.create([]);
expectDev(console.error.calls.count()).toBe(1);
expectDev(console.error.calls.argsFor(0)[0]).toContain(
'React.addons.createFragment only accepts a single object.'
'React.addons.createFragment only accepts a single object.',
);
});
@@ -94,8 +93,7 @@ describe('ReactFragment', () => {
expectDev(console.error.calls.count()).toBe(1);
expectDev(console.error.calls.argsFor(0)[0]).toContain(
'React.addons.createFragment does not accept a ReactElement without a ' +
'wrapper object.'
'wrapper object.',
);
});
});
@@ -17,7 +17,6 @@ var ReactTestUtils = require('ReactTestUtils');
var renderSubtreeIntoContainer = require('renderSubtreeIntoContainer');
describe('renderSubtreeIntoContainer', () => {
it('should pass context when rendering subtree elsewhere', () => {
var portal = document.createElement('div');
@@ -47,9 +46,11 @@ describe('renderSubtreeIntoContainer', () => {
}
componentDidMount() {
expect(function() {
renderSubtreeIntoContainer(this, <Component />, portal);
}.bind(this)).not.toThrow();
expect(
function() {
renderSubtreeIntoContainer(this, <Component />, portal);
}.bind(this),
).not.toThrow();
}
}
@@ -296,5 +297,4 @@ describe('renderSubtreeIntoContainer', () => {
ReactDOM.render(<Parent value="foo" />, container);
expect(portal2.textContent).toBe('foo');
});
});
+39 -35
View File
@@ -14,7 +14,6 @@
var update = require('update');
describe('update', () => {
describe('$push', () => {
it('pushes', () => {
expect(update([1], {$push: [7]})).toEqual([1, 7]);
@@ -27,12 +26,12 @@ describe('update', () => {
it('only pushes an array', () => {
expect(update.bind(null, [], {$push: 7})).toThrowError(
'update(): expected spec of $push to be an array; got 7. Did you ' +
'forget to wrap your parameter in an array?'
'forget to wrap your parameter in an array?',
);
});
it('only pushes unto an array', () => {
expect(update.bind(null, 1, {$push: 7})).toThrowError(
'update(): expected target of $push to be an array; got 1.'
'update(): expected target of $push to be an array; got 1.',
);
});
});
@@ -49,12 +48,12 @@ describe('update', () => {
it('only unshifts an array', () => {
expect(update.bind(null, [], {$unshift: 7})).toThrowError(
'update(): expected spec of $unshift to be an array; got 7. Did you ' +
'forget to wrap your parameter in an array?'
'forget to wrap your parameter in an array?',
);
});
it('only unshifts unto an array', () => {
expect(update.bind(null, 1, {$unshift: 7})).toThrowError(
'update(): expected target of $unshift to be an array; got 1.'
'update(): expected target of $unshift to be an array; got 1.',
);
});
});
@@ -71,16 +70,16 @@ describe('update', () => {
it('only splices an array of arrays', () => {
expect(update.bind(null, [], {$splice: 1})).toThrowError(
'update(): expected spec of $splice to be an array of arrays; got 1. ' +
'Did you forget to wrap your parameters in an array?'
'Did you forget to wrap your parameters in an array?',
);
expect(update.bind(null, [], {$splice: [1]})).toThrowError(
'update(): expected spec of $splice to be an array of arrays; got 1. ' +
'Did you forget to wrap your parameters in an array?'
'Did you forget to wrap your parameters in an array?',
);
});
it('only splices unto an array', () => {
expect(update.bind(null, 1, {$splice: 7})).toThrowError(
'Expected $splice target to be an array; got 1'
'Expected $splice target to be an array; got 1',
);
});
});
@@ -96,12 +95,12 @@ describe('update', () => {
});
it('only merges with an object', () => {
expect(update.bind(null, {}, {$merge: 7})).toThrowError(
'update(): $merge expects a spec of type \'object\'; got 7'
"update(): $merge expects a spec of type 'object'; got 7",
);
});
it('only merges with an object', () => {
expect(update.bind(null, 7, {$merge: {a: 'b'}})).toThrowError(
'update(): $merge expects a target of type \'object\'; got 7'
"update(): $merge expects a target of type 'object'; got 7",
);
});
});
@@ -131,32 +130,37 @@ describe('update', () => {
});
it('only applies a function', () => {
expect(update.bind(null, 2, {$apply: 123})).toThrowError(
'update(): expected spec of $apply to be a function; got 123.'
'update(): expected spec of $apply to be a function; got 123.',
);
});
});
it('should support deep updates', () => {
expect(update({
a: 'b',
c: {
d: 'e',
f: [1],
g: [2],
h: [3],
i: {j: 'k'},
l: 4,
},
}, {
c: {
d: {$set: 'm'},
f: {$push: [5]},
g: {$unshift: [6]},
h: {$splice: [[0, 1, 7]]},
i: {$merge: {n: 'o'}},
l: {$apply: (x) => x * 2},
},
})).toEqual({
expect(
update(
{
a: 'b',
c: {
d: 'e',
f: [1],
g: [2],
h: [3],
i: {j: 'k'},
l: 4,
},
},
{
c: {
d: {$set: 'm'},
f: {$push: [5]},
g: {$unshift: [6]},
h: {$splice: [[0, 1, 7]]},
i: {$merge: {n: 'o'}},
l: {$apply: x => x * 2},
},
},
),
).toEqual({
a: 'b',
c: {
d: 'm',
@@ -172,14 +176,14 @@ describe('update', () => {
it('should require a command', () => {
expect(update.bind(null, {a: 'b'}, {a: 'c'})).toThrowError(
'update(): You provided a key path to update() that did not contain ' +
'one of $push, $unshift, $splice, $set, $merge, $apply. Did you ' +
'forget to include {$set: ...}?'
'one of $push, $unshift, $splice, $set, $merge, $apply. Did you ' +
'forget to include {$set: ...}?',
);
});
it('should perform safe hasOwnProperty check', () => {
expect(update({}, {'hasOwnProperty': {$set: 'a'}})).toEqual({
'hasOwnProperty': 'a',
expect(update({}, {hasOwnProperty: {$set: 'a'}})).toEqual({
hasOwnProperty: 'a',
});
});
});
+2 -4
View File
@@ -19,10 +19,8 @@ var shallowEqual = require('fbjs/lib/shallowEqual');
* See also https://facebook.github.io/react/docs/shallow-compare.html
*/
function shallowCompare(instance, nextProps, nextState) {
return (
!shallowEqual(instance.props, nextProps) ||
!shallowEqual(instance.state, nextState)
);
return !shallowEqual(instance.props, nextProps) ||
!shallowEqual(instance.state, nextState);
}
module.exports = shallowCompare;
@@ -26,16 +26,19 @@ function createTransitionTimeoutPropValidator(transitionType) {
// If no timeout duration is provided
if (props[timeoutPropName] == null) {
return new Error(
timeoutPropName + ' wasn\'t supplied to ReactCSSTransitionGroup: ' +
'this can cause unreliable animations and won\'t be supported in ' +
'a future version of React. See ' +
'https://fb.me/react-animation-transition-group-timeout for more ' +
'information.'
timeoutPropName +
" wasn't supplied to ReactCSSTransitionGroup: " +
"this can cause unreliable animations and won't be supported in " +
'a future version of React. See ' +
'https://fb.me/react-animation-transition-group-timeout for more ' +
'information.',
);
// If the duration isn't a number
// If the duration isn't a number
} else if (typeof props[timeoutPropName] !== 'number') {
return new Error(timeoutPropName + ' must be a number (in milliseconds)');
return new Error(
timeoutPropName + ' must be a number (in milliseconds)',
);
}
}
};
@@ -66,7 +69,7 @@ class ReactCSSTransitionGroup extends React.Component {
transitionLeave: true,
};
_wrapChild = (child) => {
_wrapChild = child => {
// We need to provide this childFactory so that
// ReactCSSTransitionGroupChild can receive updates to name, enter, and
// leave while it is leaving.
@@ -81,14 +84,14 @@ class ReactCSSTransitionGroup extends React.Component {
enterTimeout: this.props.transitionEnterTimeout,
leaveTimeout: this.props.transitionLeaveTimeout,
},
child
child,
);
};
render() {
return React.createElement(
ReactTransitionGroup,
Object.assign({}, this.props, {childFactory: this._wrapChild})
Object.assign({}, this.props, {childFactory: this._wrapChild}),
);
}
}
@@ -63,8 +63,10 @@ var ReactCSSTransitionGroupChild = React.createClass({
return;
}
var className = this.props.name[animationType] || this.props.name + '-' + animationType;
var activeClassName = this.props.name[animationType + 'Active'] || className + '-active';
var className = this.props.name[animationType] ||
this.props.name + '-' + animationType;
var activeClassName = this.props.name[animationType + 'Active'] ||
className + '-active';
var timeout = null;
var endListener = function(e) {
@@ -86,7 +86,7 @@ var ReactTransitionChildMapping = {
for (i = 0; i < nextKeysPending[nextKey].length; i++) {
var pendingNextKey = nextKeysPending[nextKey][i];
childMapping[nextKeysPending[nextKey][i]] = getValueForKey(
pendingNextKey
pendingNextKey,
);
}
}
+30 -30
View File
@@ -56,14 +56,14 @@ class ReactTransitionGroup extends React.Component {
componentWillReceiveProps(nextProps) {
var nextChildMapping = ReactTransitionChildMapping.getChildMapping(
nextProps.children
nextProps.children,
);
var prevChildMapping = this.state.children;
this.setState({
children: ReactTransitionChildMapping.mergeChildMappings(
prevChildMapping,
nextChildMapping
nextChildMapping,
),
});
@@ -71,16 +71,22 @@ class ReactTransitionGroup extends React.Component {
for (key in nextChildMapping) {
var hasPrev = prevChildMapping && prevChildMapping.hasOwnProperty(key);
if (nextChildMapping[key] && !hasPrev &&
!this.currentlyTransitioningKeys[key]) {
if (
nextChildMapping[key] &&
!hasPrev &&
!this.currentlyTransitioningKeys[key]
) {
this.keysToEnter.push(key);
}
}
for (key in prevChildMapping) {
var hasNext = nextChildMapping && nextChildMapping.hasOwnProperty(key);
if (prevChildMapping[key] && !hasNext &&
!this.currentlyTransitioningKeys[key]) {
if (
prevChildMapping[key] &&
!hasNext &&
!this.currentlyTransitioningKeys[key]
) {
this.keysToLeave.push(key);
}
}
@@ -98,21 +104,19 @@ class ReactTransitionGroup extends React.Component {
keysToLeave.forEach(this.performLeave);
}
performAppear = (key) => {
performAppear = key => {
this.currentlyTransitioningKeys[key] = true;
var component = this.refs[key];
if (component.componentWillAppear) {
component.componentWillAppear(
this._handleDoneAppearing.bind(this, key)
);
component.componentWillAppear(this._handleDoneAppearing.bind(this, key));
} else {
this._handleDoneAppearing(key);
}
};
_handleDoneAppearing = (key) => {
_handleDoneAppearing = key => {
var component = this.refs[key];
if (component.componentDidAppear) {
component.componentDidAppear();
@@ -121,7 +125,7 @@ class ReactTransitionGroup extends React.Component {
delete this.currentlyTransitioningKeys[key];
var currentChildMapping = ReactTransitionChildMapping.getChildMapping(
this.props.children
this.props.children,
);
if (!currentChildMapping || !currentChildMapping.hasOwnProperty(key)) {
@@ -130,21 +134,19 @@ class ReactTransitionGroup extends React.Component {
}
};
performEnter = (key) => {
performEnter = key => {
this.currentlyTransitioningKeys[key] = true;
var component = this.refs[key];
if (component.componentWillEnter) {
component.componentWillEnter(
this._handleDoneEntering.bind(this, key)
);
component.componentWillEnter(this._handleDoneEntering.bind(this, key));
} else {
this._handleDoneEntering(key);
}
};
_handleDoneEntering = (key) => {
_handleDoneEntering = key => {
var component = this.refs[key];
if (component.componentDidEnter) {
component.componentDidEnter();
@@ -153,7 +155,7 @@ class ReactTransitionGroup extends React.Component {
delete this.currentlyTransitioningKeys[key];
var currentChildMapping = ReactTransitionChildMapping.getChildMapping(
this.props.children
this.props.children,
);
if (!currentChildMapping || !currentChildMapping.hasOwnProperty(key)) {
@@ -162,7 +164,7 @@ class ReactTransitionGroup extends React.Component {
}
};
performLeave = (key) => {
performLeave = key => {
this.currentlyTransitioningKeys[key] = true;
var component = this.refs[key];
@@ -176,7 +178,7 @@ class ReactTransitionGroup extends React.Component {
}
};
_handleDoneLeaving = (key) => {
_handleDoneLeaving = key => {
var component = this.refs[key];
if (component.componentDidLeave) {
@@ -186,7 +188,7 @@ class ReactTransitionGroup extends React.Component {
delete this.currentlyTransitioningKeys[key];
var currentChildMapping = ReactTransitionChildMapping.getChildMapping(
this.props.children
this.props.children,
);
if (currentChildMapping && currentChildMapping.hasOwnProperty(key)) {
@@ -213,10 +215,12 @@ class ReactTransitionGroup extends React.Component {
// already been removed. In case you need this behavior you can provide
// a childFactory function to wrap every child, even the ones that are
// leaving.
childrenToRender.push(React.cloneElement(
this.props.childFactory(child),
{ref: key, key: key}
));
childrenToRender.push(
React.cloneElement(this.props.childFactory(child), {
ref: key,
key: key,
}),
);
}
}
@@ -232,11 +236,7 @@ class ReactTransitionGroup extends React.Component {
delete props.transitionAppearTimeout;
delete props.component;
return React.createElement(
this.props.component,
props,
childrenToRender
);
return React.createElement(this.props.component, props, childrenToRender);
}
}
@@ -32,16 +32,15 @@ describe('ReactCSSTransitionGroup', () => {
spyOn(console, 'error');
});
it('should warn if timeouts aren\'t specified', () => {
it("should warn if timeouts aren't specified", () => {
ReactDOM.render(
<ReactCSSTransitionGroup
transitionName="yolo"
transitionEnter={false}
transitionLeave={true}
>
transitionLeave={true}>
<span key="one" id="one" />
</ReactCSSTransitionGroup>,
container
container,
);
// Warning about the missing transitionLeaveTimeout prop
@@ -54,11 +53,10 @@ describe('ReactCSSTransitionGroup', () => {
transitionName="yolo"
transitionEnter={false}
transitionLeave={true}
transitionLeaveTimeout={0}
>
transitionLeaveTimeout={0}>
<span key="one" id="one" />
</ReactCSSTransitionGroup>,
container
container,
);
expectDev(console.error.calls.count()).toBe(0);
@@ -69,11 +67,10 @@ describe('ReactCSSTransitionGroup', () => {
<ReactCSSTransitionGroup
transitionName="yolo"
transitionEnter={false}
transitionLeaveTimeout={200}
>
transitionLeaveTimeout={200}>
<span key="one" id="one" />
</ReactCSSTransitionGroup>,
container
container,
);
expect(ReactDOM.findDOMNode(a).childNodes.length).toBe(1);
@@ -83,11 +80,10 @@ describe('ReactCSSTransitionGroup', () => {
<ReactCSSTransitionGroup
transitionName="yolo"
transitionEnter={false}
transitionLeaveTimeout={200}
>
transitionLeaveTimeout={200}>
<span key="two" id="two" />
</ReactCSSTransitionGroup>,
container
container,
);
expect(ReactDOM.findDOMNode(a).childNodes.length).toBe(2);
expect(ReactDOM.findDOMNode(a).childNodes[0].id).toBe('two');
@@ -115,14 +111,14 @@ describe('ReactCSSTransitionGroup', () => {
<ReactCSSTransitionGroup transitionName="yolo">
<span key="one" id="one" />
</ReactCSSTransitionGroup>,
container
container,
);
expect(ReactDOM.findDOMNode(a).childNodes.length).toBe(1);
ReactDOM.render(
<ReactCSSTransitionGroup transitionName="yolo">
<span key="two" id="two" />
</ReactCSSTransitionGroup>,
container
container,
);
expect(ReactDOM.findDOMNode(a).childNodes.length).toBe(2);
expect(ReactDOM.findDOMNode(a).childNodes[0].id).toBe('two');
@@ -132,32 +128,32 @@ describe('ReactCSSTransitionGroup', () => {
it('should switch transitionLeave from false to true', () => {
var a = ReactDOM.render(
<ReactCSSTransitionGroup
transitionName="yolo"
transitionEnter={false}
transitionLeave={false}>
transitionName="yolo"
transitionEnter={false}
transitionLeave={false}>
<span key="one" id="one" />
</ReactCSSTransitionGroup>,
container
container,
);
expect(ReactDOM.findDOMNode(a).childNodes.length).toBe(1);
ReactDOM.render(
<ReactCSSTransitionGroup
transitionName="yolo"
transitionEnter={false}
transitionLeave={false}>
transitionName="yolo"
transitionEnter={false}
transitionLeave={false}>
<span key="two" id="two" />
</ReactCSSTransitionGroup>,
container
container,
);
expect(ReactDOM.findDOMNode(a).childNodes.length).toBe(1);
ReactDOM.render(
<ReactCSSTransitionGroup
transitionName="yolo"
transitionEnter={false}
transitionLeave={true}>
transitionName="yolo"
transitionEnter={false}
transitionLeave={true}>
<span key="three" id="three" />
</ReactCSSTransitionGroup>,
container
container,
);
expect(ReactDOM.findDOMNode(a).childNodes.length).toBe(2);
expect(ReactDOM.findDOMNode(a).childNodes[0].id).toBe('three');
@@ -167,7 +163,7 @@ describe('ReactCSSTransitionGroup', () => {
it('should work with no children', () => {
ReactDOM.render(
<ReactCSSTransitionGroup transitionName="yolo" />,
container
container,
);
});
@@ -176,7 +172,7 @@ describe('ReactCSSTransitionGroup', () => {
<ReactCSSTransitionGroup transitionName="yolo">
{[null]}
</ReactCSSTransitionGroup>,
container
container,
);
});
@@ -185,14 +181,14 @@ describe('ReactCSSTransitionGroup', () => {
<ReactCSSTransitionGroup transitionName="yolo">
<span key="one" id="one" />
</ReactCSSTransitionGroup>,
container
container,
);
expect(ReactDOM.findDOMNode(a).childNodes.length).toBe(1);
ReactDOM.render(
<ReactCSSTransitionGroup transitionName="yolo">
{null}
</ReactCSSTransitionGroup>,
container
container,
);
// (Here, we expect the original child to stick around but test that no
// exception is thrown)
@@ -205,20 +201,20 @@ describe('ReactCSSTransitionGroup', () => {
<ReactCSSTransitionGroup transitionName="yolo">
{false}
</ReactCSSTransitionGroup>,
container
container,
);
expect(ReactDOM.findDOMNode(a).childNodes.length).toBe(0);
ReactDOM.render(
<ReactCSSTransitionGroup transitionName="yolo">
<span key="one" id="one" />
</ReactCSSTransitionGroup>,
container
container,
);
expect(ReactDOM.findDOMNode(a).childNodes.length).toBe(1);
expect(ReactDOM.findDOMNode(a).childNodes[0].id).toBe('one');
});
it('should use transition-type specific names when they\'re provided', () => {
it("should use transition-type specific names when they're provided", () => {
var customTransitionNames = {
enter: 'custom-entering',
leave: 'custom-leaving',
@@ -228,11 +224,10 @@ describe('ReactCSSTransitionGroup', () => {
<ReactCSSTransitionGroup
transitionName={customTransitionNames}
transitionEnterTimeout={1}
transitionLeaveTimeout={1}
>
transitionLeaveTimeout={1}>
<span key="one" id="one" />
</ReactCSSTransitionGroup>,
container
container,
);
expect(ReactDOM.findDOMNode(a).childNodes.length).toBe(1);
@@ -241,12 +236,11 @@ describe('ReactCSSTransitionGroup', () => {
<ReactCSSTransitionGroup
transitionName={customTransitionNames}
transitionEnterTimeout={1}
transitionLeaveTimeout={1}
>
transitionLeaveTimeout={1}>
<span key="one" id="one" />
<span key="two" id="two" />
</ReactCSSTransitionGroup>,
container
container,
);
expect(ReactDOM.findDOMNode(a).childNodes.length).toBe(2);
@@ -258,11 +252,10 @@ describe('ReactCSSTransitionGroup', () => {
<ReactCSSTransitionGroup
transitionName={customTransitionNames}
transitionEnterTimeout={1}
transitionLeaveTimeout={1}
>
transitionLeaveTimeout={1}>
<span key="two" id="two" />
</ReactCSSTransitionGroup>,
container
container,
);
expect(ReactDOM.findDOMNode(a).childNodes.length).toBe(2);
@@ -284,7 +277,10 @@ describe('ReactCSSTransitionGroup', () => {
}
ReactDOM.render(<Component />, container);
ReactDOM.render(<Component><span key="yolo" id="yolo" /></Component>, container);
ReactDOM.render(
<Component><span key="yolo" id="yolo" /></Component>,
container,
);
ReactDOM.unmountComponentAtNode(container);
@@ -303,10 +299,10 @@ describe('ReactCSSTransitionGroup', () => {
}
class Component extends React.Component {
state = { showChild: true };
state = {showChild: true};
componentDidMount() {
this.setState({ showChild: false });
this.setState({showChild: false});
}
render() {
@@ -314,8 +310,7 @@ describe('ReactCSSTransitionGroup', () => {
<ReactCSSTransitionGroup
transitionName="yolo"
transitionAppear={true}
transitionAppearTimeout={0}
>
transitionAppearTimeout={0}>
<Child show={this.state.showChild} />
</ReactCSSTransitionGroup>
);
@@ -27,7 +27,7 @@ describe('ReactTransitionChildMapping', () => {
var two = <div key="two" />;
var component = <div>{one}{two}</div>;
expect(
ReactTransitionChildMapping.getChildMapping(component.props.children)
ReactTransitionChildMapping.getChildMapping(component.props.children),
).toEqual({
'.$one': one,
'.$two': two,
@@ -28,7 +28,6 @@ describe('ReactTransitionGroup', () => {
container = document.createElement('div');
});
it('should handle willEnter correctly', () => {
var log = [];
@@ -37,7 +36,7 @@ describe('ReactTransitionGroup', () => {
log.push('didMount');
}
componentWillAppear = (cb) => {
componentWillAppear = cb => {
log.push('willAppear');
cb();
};
@@ -46,7 +45,7 @@ describe('ReactTransitionGroup', () => {
log.push('didAppear');
};
componentWillEnter = (cb) => {
componentWillEnter = cb => {
log.push('willEnter');
cb();
};
@@ -55,7 +54,7 @@ describe('ReactTransitionGroup', () => {
log.push('didEnter');
};
componentWillLeave = (cb) => {
componentWillLeave = cb => {
log.push('willLeave');
cb();
};
@@ -108,7 +107,7 @@ describe('ReactTransitionGroup', () => {
log.push('didMount');
}
componentWillEnter = (cb) => {
componentWillEnter = cb => {
log.push('willEnter');
willEnterCb = cb;
};
@@ -117,7 +116,7 @@ describe('ReactTransitionGroup', () => {
log.push('didEnter');
};
componentWillLeave = (cb) => {
componentWillLeave = cb => {
log.push('willLeave');
cb();
};
@@ -159,8 +158,13 @@ describe('ReactTransitionGroup', () => {
// other animations are blocked until willEnterCb is called
willEnterCb();
expect(log).toEqual([
'didMount', 'didMount', 'willEnter',
'didEnter', 'willLeave', 'didLeave', 'willUnmount',
'didMount',
'didMount',
'willEnter',
'didEnter',
'willLeave',
'didLeave',
'willUnmount',
]);
});
@@ -173,7 +177,7 @@ describe('ReactTransitionGroup', () => {
log.push('didMount');
}
componentWillEnter = (cb) => {
componentWillEnter = cb => {
log.push('willEnter');
willEnterCb = cb;
};
@@ -182,7 +186,7 @@ describe('ReactTransitionGroup', () => {
log.push('didEnter');
};
componentWillLeave = (cb) => {
componentWillLeave = cb => {
log.push('willLeave');
cb();
};
@@ -222,9 +226,7 @@ describe('ReactTransitionGroup', () => {
instance.setState({count: 2});
}
willEnterCb();
expect(log).toEqual([
'didMount', 'didMount', 'willEnter', 'didEnter',
]);
expect(log).toEqual(['didMount', 'didMount', 'willEnter', 'didEnter']);
});
it('should handle entering/leaving several elements at once', () => {
@@ -235,7 +237,7 @@ describe('ReactTransitionGroup', () => {
log.push('didMount' + this.props.id);
}
componentWillEnter = (cb) => {
componentWillEnter = cb => {
log.push('willEnter' + this.props.id);
cb();
};
@@ -244,7 +246,7 @@ describe('ReactTransitionGroup', () => {
log.push('didEnter' + this.props.id);
};
componentWillLeave = (cb) => {
componentWillLeave = cb => {
log.push('willLeave' + this.props.id);
cb();
};
@@ -280,15 +282,26 @@ describe('ReactTransitionGroup', () => {
instance.setState({count: 3});
expect(log).toEqual([
'didMount1', 'didMount2', 'willEnter1', 'didEnter1',
'willEnter2', 'didEnter2',
'didMount1',
'didMount2',
'willEnter1',
'didEnter1',
'willEnter2',
'didEnter2',
]);
log = [];
instance.setState({count: 0});
expect(log).toEqual([
'willLeave0', 'didLeave0', 'willLeave1', 'didLeave1',
'willLeave2', 'didLeave2', 'willUnmount0', 'willUnmount1', 'willUnmount2',
'willLeave0',
'didLeave0',
'willLeave1',
'didLeave1',
'willLeave2',
'didLeave2',
'willUnmount0',
'willUnmount1',
'willUnmount2',
]);
});
@@ -307,15 +320,15 @@ describe('ReactTransitionGroup', () => {
expectDev(console.error.calls.count()).toBe(2);
expectDev(console.error.calls.argsFor(0)[0]).toBe(
'Warning: flattenChildren(...): ' +
'Encountered two children with the same key, `1`. ' +
'Child keys must be unique; when two children share a key, ' +
'only the first child will be used.'
'Encountered two children with the same key, `1`. ' +
'Child keys must be unique; when two children share a key, ' +
'only the first child will be used.',
);
expectDev(console.error.calls.argsFor(1)[0]).toBe(
'Warning: flattenChildren(...): ' +
'Encountered two children with the same key, `1`. ' +
'Child keys must be unique; when two children share a key, ' +
'only the first child will be used.'
'Encountered two children with the same key, `1`. ' +
'Child keys must be unique; when two children share a key, ' +
'only the first child will be used.',
);
});
});
+17 -17
View File
@@ -9,7 +9,7 @@
* @providesModule update
*/
/* global hasOwnProperty:true */
/* global hasOwnProperty:true */
'use strict';
@@ -53,15 +53,15 @@ function invariantArrayCase(value, spec, command) {
Array.isArray(value),
'update(): expected target of %s to be an array; got %s.',
command,
value
value,
);
var specValue = spec[command];
invariant(
Array.isArray(specValue),
'update(): expected spec of %s to be an array; got %s. ' +
'Did you forget to wrap your parameter in an array?',
'Did you forget to wrap your parameter in an array?',
command,
specValue
specValue,
);
}
@@ -73,16 +73,16 @@ function update(value, spec) {
invariant(
typeof spec === 'object',
'update(): You provided a key path to update() that did not contain one ' +
'of %s. Did you forget to include {%s: ...}?',
'of %s. Did you forget to include {%s: ...}?',
ALL_COMMANDS_LIST.join(', '),
COMMAND_SET
COMMAND_SET,
);
if (hasOwnProperty.call(spec, COMMAND_SET)) {
invariant(
Object.keys(spec).length === 1,
'Cannot have more than one key in an object with %s',
COMMAND_SET
COMMAND_SET,
);
return spec[COMMAND_SET];
@@ -94,15 +94,15 @@ function update(value, spec) {
var mergeObj = spec[COMMAND_MERGE];
invariant(
mergeObj && typeof mergeObj === 'object',
'update(): %s expects a spec of type \'object\'; got %s',
"update(): %s expects a spec of type 'object'; got %s",
COMMAND_MERGE,
mergeObj
mergeObj,
);
invariant(
nextValue && typeof nextValue === 'object',
'update(): %s expects a target of type \'object\'; got %s',
"update(): %s expects a target of type 'object'; got %s",
COMMAND_MERGE,
nextValue
nextValue,
);
Object.assign(nextValue, spec[COMMAND_MERGE]);
}
@@ -126,22 +126,22 @@ function update(value, spec) {
Array.isArray(value),
'Expected %s target to be an array; got %s',
COMMAND_SPLICE,
value
value,
);
invariant(
Array.isArray(spec[COMMAND_SPLICE]),
'update(): expected spec of %s to be an array of arrays; got %s. ' +
'Did you forget to wrap your parameters in an array?',
'Did you forget to wrap your parameters in an array?',
COMMAND_SPLICE,
spec[COMMAND_SPLICE]
spec[COMMAND_SPLICE],
);
spec[COMMAND_SPLICE].forEach(function(args) {
invariant(
Array.isArray(args),
'update(): expected spec of %s to be an array of arrays; got %s. ' +
'Did you forget to wrap your parameters in an array?',
'Did you forget to wrap your parameters in an array?',
COMMAND_SPLICE,
spec[COMMAND_SPLICE]
spec[COMMAND_SPLICE],
);
nextValue.splice.apply(nextValue, args);
});
@@ -152,7 +152,7 @@ function update(value, spec) {
typeof spec[COMMAND_APPLY] === 'function',
'update(): expected spec of %s to be a function; got %s.',
COMMAND_APPLY,
spec[COMMAND_APPLY]
spec[COMMAND_APPLY],
);
nextValue = spec[COMMAND_APPLY](nextValue);
}
+1 -4
View File
@@ -45,16 +45,14 @@ if (__DEV__) {
warning(
warnedForCreateMixin,
'React.createMixin is deprecated and should not be used. You ' +
'can use this mixin directly instead.'
'can use this mixin directly instead.',
);
warnedForCreateMixin = true;
return mixin;
};
}
var React = {
// Modern
Children: {
@@ -86,7 +84,6 @@ var React = {
DOM: ReactDOMFactories,
version: ReactVersion,
};
module.exports = React;
+1 -3
View File
@@ -12,7 +12,6 @@
'use strict';
describe('React', () => {
var React;
beforeEach(() => {
@@ -25,8 +24,7 @@ describe('React', () => {
React.createMixin();
expectDev(console.error.calls.count()).toBe(1);
expectDev(console.error.calls.argsFor(0)[0]).toContain(
'React.createMixin is deprecated and should not be used'
'React.createMixin is deprecated and should not be used',
);
});
});
+11 -18
View File
@@ -20,13 +20,11 @@ var traverseAllChildren = require('traverseAllChildren');
var twoArgumentPooler = PooledClass.twoArgumentPooler;
var fourArgumentPooler = PooledClass.fourArgumentPooler;
var userProvidedKeyEscapeRegex = /\/+/g;
function escapeUserProvidedKey(text) {
return ('' + text).replace(userProvidedKeyEscapeRegex, '$&/');
}
/**
* PooledClass representing the bookkeeping associated with performing a child
* traversal. Allows avoiding binding callbacks.
@@ -68,13 +66,14 @@ function forEachChildren(children, forEachFunc, forEachContext) {
if (children == null) {
return children;
}
var traverseContext =
ForEachBookKeeping.getPooled(forEachFunc, forEachContext);
var traverseContext = ForEachBookKeeping.getPooled(
forEachFunc,
forEachContext,
);
traverseAllChildren(children, forEachSingleChild, traverseContext);
ForEachBookKeeping.release(traverseContext);
}
/**
* PooledClass representing the bookkeeping associated with performing a child
* mapping. Allows avoiding binding callbacks.
@@ -109,7 +108,7 @@ function mapSingleChildIntoContext(bookKeeping, child, childKey) {
mappedChild,
result,
childKey,
emptyFunction.thatReturnsArgument
emptyFunction.thatReturnsArgument,
);
} else if (mappedChild != null) {
if (ReactElement.isValidElement(mappedChild)) {
@@ -118,12 +117,10 @@ function mapSingleChildIntoContext(bookKeeping, child, childKey) {
// Keep both the (mapped) and old keys if they differ, just as
// traverseAllChildren used to do for objects as children
keyPrefix +
(
(mappedChild.key && (!child || (child.key !== mappedChild.key))) ?
escapeUserProvidedKey(mappedChild.key) + '/' :
''
) +
childKey
(mappedChild.key && (!child || child.key !== mappedChild.key)
? escapeUserProvidedKey(mappedChild.key) + '/'
: '') +
childKey,
);
}
result.push(mappedChild);
@@ -139,7 +136,7 @@ function mapIntoWithKeyPrefixInternal(children, array, prefix, func, context) {
array,
escapedPrefix,
func,
context
context,
);
traverseAllChildren(children, mapSingleChildIntoContext, traverseContext);
MapBookKeeping.release(traverseContext);
@@ -167,8 +164,6 @@ function mapChildren(children, func, context) {
return result;
}
function forEachSingleChildDummy(traverseContext, child, name) {
return null;
}
@@ -186,7 +181,6 @@ function countChildren(children, context) {
return traverseAllChildren(children, forEachSingleChildDummy, null);
}
/**
* Flatten a children object (typically specified as `props.children`) and
* return an array with appropriately re-keyed children.
@@ -199,12 +193,11 @@ function toArray(children) {
children,
result,
null,
emptyFunction.thatReturnsArgument
emptyFunction.thatReturnsArgument,
);
return result;
}
var ReactChildren = {
forEach: forEachChildren,
map: mapChildren,
@@ -37,7 +37,11 @@ describe('ReactChildren', () => {
React.Children.forEach(instance.props.children, callback, context);
expect(callback).toHaveBeenCalledWith(simpleKid, 0);
callback.calls.reset();
var mappedChildren = React.Children.map(instance.props.children, callback, context);
var mappedChildren = React.Children.map(
instance.props.children,
callback,
context,
);
expect(callback).toHaveBeenCalledWith(simpleKid, 0);
expect(mappedChildren[0]).toEqual(<span key=".$simple" />);
});
@@ -54,7 +58,11 @@ describe('ReactChildren', () => {
React.Children.forEach(instance.props.children, callback, context);
expect(callback).toHaveBeenCalledWith(simpleKid, 0);
callback.calls.reset();
var mappedChildren = React.Children.map(instance.props.children, callback, context);
var mappedChildren = React.Children.map(
instance.props.children,
callback,
context,
);
expect(callback).toHaveBeenCalledWith(simpleKid, 0);
expect(mappedChildren[0]).toEqual(<span key=".0" />);
});
@@ -71,7 +79,11 @@ describe('ReactChildren', () => {
React.Children.forEach(instance.props.children, callback, context);
expect(callback).toHaveBeenCalledWith(simpleKid, 0);
callback.calls.reset();
var mappedChildren = React.Children.map(instance.props.children, callback, context);
var mappedChildren = React.Children.map(
instance.props.children,
callback,
context,
);
expect(callback).toHaveBeenCalledWith(simpleKid, 0);
expect(mappedChildren[0]).toEqual(<span key=".$simple" />);
});
@@ -84,11 +96,10 @@ describe('ReactChildren', () => {
var four = <div key="keyFour" />;
var context = {};
var callback =
jasmine.createSpy().and.callFake(function(kid) {
expect(this).toBe(context);
return kid;
});
var callback = jasmine.createSpy().and.callFake(function(kid) {
expect(this).toBe(context);
return kid;
});
var instance = (
<div>
@@ -112,7 +123,11 @@ describe('ReactChildren', () => {
React.Children.forEach(instance.props.children, callback, context);
assertCalls();
var mappedChildren = React.Children.map(instance.props.children, callback, context);
var mappedChildren = React.Children.map(
instance.props.children,
callback,
context,
);
assertCalls();
expect(mappedChildren).toEqual([
<div key=".$keyZero" />,
@@ -127,11 +142,10 @@ describe('ReactChildren', () => {
var a = <a key="aNode" />;
var context = {};
var callback =
jasmine.createSpy().and.callFake(function(kid) {
expect(this).toBe(context);
return kid;
});
var callback = jasmine.createSpy().and.callFake(function(kid) {
expect(this).toBe(context);
return kid;
});
var instance = (
<div>
@@ -164,7 +178,11 @@ describe('ReactChildren', () => {
React.Children.forEach(instance.props.children, callback, context);
assertCalls();
var mappedChildren = React.Children.map(instance.props.children, callback, context);
var mappedChildren = React.Children.map(
instance.props.children,
callback,
context,
);
assertCalls();
expect(mappedChildren).toEqual([
<div key=".$divNode" />,
@@ -189,34 +207,51 @@ describe('ReactChildren', () => {
// 2. If grouped in an Array, the `key` prop, falling back to array index
var context = {};
var callback =
jasmine.createSpy().and.callFake(function(kid) {
return kid;
});
var callback = jasmine.createSpy().and.callFake(function(kid) {
return kid;
});
var instance = (
<div>{[
ReactFragment.create({
firstHalfKey: [zero, one, two],
secondHalfKey: [three, four],
keyFive: five,
}),
]}</div>
<div>
{[
ReactFragment.create({
firstHalfKey: [zero, one, two],
secondHalfKey: [three, four],
keyFive: five,
}),
]}
</div>
);
function assertCalls() {
expect(callback.calls.count()).toBe(4);
expect(callback).toHaveBeenCalledWith(<div key="firstHalfKey/.$keyZero" />, 0);
expect(callback).toHaveBeenCalledWith(<div key="firstHalfKey/.$keyTwo" />, 1);
expect(callback).toHaveBeenCalledWith(<div key="secondHalfKey/.$keyFour" />, 2);
expect(callback).toHaveBeenCalledWith(<div key="keyFive/.$keyFiveInner" />, 3);
expect(callback).toHaveBeenCalledWith(
<div key="firstHalfKey/.$keyZero" />,
0,
);
expect(callback).toHaveBeenCalledWith(
<div key="firstHalfKey/.$keyTwo" />,
1,
);
expect(callback).toHaveBeenCalledWith(
<div key="secondHalfKey/.$keyFour" />,
2,
);
expect(callback).toHaveBeenCalledWith(
<div key="keyFive/.$keyFiveInner" />,
3,
);
callback.calls.reset();
}
React.Children.forEach(instance.props.children, callback, context);
assertCalls();
var mappedChildren = React.Children.map(instance.props.children, callback, context);
var mappedChildren = React.Children.map(
instance.props.children,
callback,
context,
);
assertCalls();
expect(mappedChildren).toEqual([
<div key=".0:$firstHalfKey/.$keyZero" />,
@@ -230,11 +265,10 @@ describe('ReactChildren', () => {
var zeroForceKey = <div key="keyZero" />;
var oneForceKey = <div key="keyOne" />;
var context = {};
var callback =
jasmine.createSpy().and.callFake(function(kid) {
expect(this).toBe(context);
return kid;
});
var callback = jasmine.createSpy().and.callFake(function(kid) {
expect(this).toBe(context);
return kid;
});
var forcedKeys = (
<div>
@@ -252,7 +286,11 @@ describe('ReactChildren', () => {
React.Children.forEach(forcedKeys.props.children, callback, context);
assertCalls();
var mappedChildren = React.Children.map(forcedKeys.props.children, callback, context);
var mappedChildren = React.Children.map(
forcedKeys.props.children,
callback,
context,
);
assertCalls();
expect(mappedChildren).toEqual([
<div key=".$keyZero" />,
@@ -278,11 +316,10 @@ describe('ReactChildren', () => {
};
var context = {};
var callback =
jasmine.createSpy().and.callFake(function(kid) {
expect(this).toBe(context);
return kid;
});
var callback = jasmine.createSpy().and.callFake(function(kid) {
expect(this).toBe(context);
return kid;
});
var instance = (
<div>
@@ -302,11 +339,15 @@ describe('ReactChildren', () => {
assertCalls();
expectDev(console.error.calls.count()).toBe(1);
expectDev(console.error.calls.argsFor(0)[0]).toContain(
'Warning: Each child in an array or iterator should have a unique "key" prop.'
'Warning: Each child in an array or iterator should have a unique "key" prop.',
);
console.error.calls.reset();
var mappedChildren = React.Children.map(instance.props.children, callback, context);
var mappedChildren = React.Children.map(
instance.props.children,
callback,
context,
);
assertCalls();
expectDev(console.error.calls.count()).toBe(0);
expect(mappedChildren).toEqual([
@@ -333,11 +374,10 @@ describe('ReactChildren', () => {
};
var context = {};
var callback =
jasmine.createSpy().and.callFake(function(kid) {
expect(this).toBe(context);
return kid;
});
var callback = jasmine.createSpy().and.callFake(function(kid) {
expect(this).toBe(context);
return kid;
});
var instance = (
<div>
@@ -356,7 +396,11 @@ describe('ReactChildren', () => {
React.Children.forEach(instance.props.children, callback, context);
assertCalls();
var mappedChildren = React.Children.map(instance.props.children, callback, context);
var mappedChildren = React.Children.map(
instance.props.children,
callback,
context,
);
assertCalls();
expect(mappedChildren).toEqual([
<div key=".$#1" />,
@@ -398,7 +442,11 @@ describe('ReactChildren', () => {
React.Children.forEach(instance.props.children, callback, context);
assertCalls();
var mappedChildren = React.Children.map(instance.props.children, callback, context);
var mappedChildren = React.Children.map(
instance.props.children,
callback,
context,
);
assertCalls();
expect(mappedChildren).toEqual([5, 12, 13]);
} finally {
@@ -435,12 +483,13 @@ describe('ReactChildren', () => {
React.Children.forEach(instance.props.children, callback, context);
assertCalls();
var mappedChildren = React.Children.map(instance.props.children, callback, context);
var mappedChildren = React.Children.map(
instance.props.children,
callback,
context,
);
assertCalls();
expect(mappedChildren).toEqual([
'a',
13,
]);
expect(mappedChildren).toEqual(['a', 13]);
delete String.prototype.key;
delete Number.prototype.key;
@@ -477,8 +526,11 @@ describe('ReactChildren', () => {
React.Children.forEach(instance.props.children, callback, scopeTester);
expect(lastContext).toBe(scopeTester);
var mappedChildren =
React.Children.map(instance.props.children, callback, scopeTester);
var mappedChildren = React.Children.map(
instance.props.children,
callback,
scopeTester,
);
expect(React.Children.count(mappedChildren)).toBe(1);
expect(mappedChildren[0]).toBe(scopeTester);
@@ -492,9 +544,9 @@ describe('ReactChildren', () => {
var four = <div key="keyFour" />;
var mapped = [
<div key="giraffe" />, // Key should be joined to obj key
null, // Key should be added even if we don't supply it!
<div />, // Key should be added even if not supplied!
<div key="giraffe" />, // Key should be joined to obj key
null, // Key should be added even if we don't supply it!
<div />, // Key should be added even if not supplied!
<span />, // Map from null to something.
<div key="keyFour" />,
];
@@ -520,8 +572,7 @@ describe('ReactChildren', () => {
expect(callback).toHaveBeenCalledWith(four, 4);
callback.calls.reset();
var mappedChildren =
React.Children.map(instance.props.children, callback);
var mappedChildren = React.Children.map(instance.props.children, callback);
expect(callback.calls.count()).toBe(5);
expect(React.Children.count(mappedChildren)).toBe(4);
// Keys default to indices.
@@ -530,9 +581,7 @@ describe('ReactChildren', () => {
mappedChildren[1].key,
mappedChildren[2].key,
mappedChildren[3].key,
]).toEqual(
['giraffe/.$keyZero', '.$keyTwo', '.3', '.$keyFour']
);
]).toEqual(['giraffe/.$keyZero', '.$keyTwo', '.3', '.$keyFour']);
expect(callback).toHaveBeenCalledWith(zero, 0);
expect(callback).toHaveBeenCalledWith(one, 1);
@@ -559,15 +608,15 @@ describe('ReactChildren', () => {
// 1. If grouped in an Object, the object key combined with `key` prop
// 2. If grouped in an Array, the `key` prop, falling back to array index
var zeroMapped = <div key="giraffe" />; // Key should be overridden
var twoMapped = <div />; // Key should be added even if not supplied!
var zeroMapped = <div key="giraffe" />; // Key should be overridden
var twoMapped = <div />; // Key should be added even if not supplied!
var fourMapped = <div key="keyFour" />;
var fiveMapped = <div />;
var callback = jasmine.createSpy().and.callFake(function(kid, index) {
return index === 0 ? zeroMapped :
index === 1 ? twoMapped :
index === 2 ? fourMapped : fiveMapped;
return index === 0
? zeroMapped
: index === 1 ? twoMapped : index === 2 ? fourMapped : fiveMapped;
});
var frag = ReactFragment.create({
@@ -577,12 +626,7 @@ describe('ReactChildren', () => {
});
var instance = <div>{[frag]}</div>;
expect([
frag[0].key,
frag[1].key,
frag[2].key,
frag[3].key,
]).toEqual([
expect([frag[0].key, frag[1].key, frag[2].key, frag[3].key]).toEqual([
'firstHalfKey/.$keyZero',
'firstHalfKey/.$keyTwo',
'secondHalfKey/.$keyFour',
@@ -618,9 +662,13 @@ describe('ReactChildren', () => {
'.0:$keyFive/.$keyFiveInner',
]);
expect(mappedChildren[0]).toEqual(<div key="giraffe/.0:$firstHalfKey/.$keyZero" />);
expect(mappedChildren[0]).toEqual(
<div key="giraffe/.0:$firstHalfKey/.$keyZero" />,
);
expect(mappedChildren[1]).toEqual(<div key=".0:$firstHalfKey/.$keyTwo" />);
expect(mappedChildren[2]).toEqual(<div key="keyFour/.0:$secondHalfKey/.$keyFour" />);
expect(mappedChildren[2]).toEqual(
<div key="keyFour/.0:$secondHalfKey/.$keyFour" />,
);
expect(mappedChildren[3]).toEqual(<div key=".0:$keyFive/.$keyFiveInner" />);
});
@@ -645,21 +693,24 @@ describe('ReactChildren', () => {
);
var expectedForcedKeys = ['giraffe/.$keyZero', '.$keyOne'];
var mappedChildrenForcedKeys =
React.Children.map(forcedKeys.props.children, mapFn);
var mappedForcedKeys = mappedChildrenForcedKeys.map((c) => c.key);
var mappedChildrenForcedKeys = React.Children.map(
forcedKeys.props.children,
mapFn,
);
var mappedForcedKeys = mappedChildrenForcedKeys.map(c => c.key);
expect(mappedForcedKeys).toEqual(expectedForcedKeys);
var expectedRemappedForcedKeys = [
'giraffe/.$giraffe/.$keyZero',
'.$.$keyOne',
];
var remappedChildrenForcedKeys =
React.Children.map(mappedChildrenForcedKeys, mapFn);
expect(
remappedChildrenForcedKeys.map((c) => c.key)
).toEqual(expectedRemappedForcedKeys);
var remappedChildrenForcedKeys = React.Children.map(
mappedChildrenForcedKeys,
mapFn,
);
expect(remappedChildrenForcedKeys.map(c => c.key)).toEqual(
expectedRemappedForcedKeys,
);
});
it('should not throw if key provided is a dupe with array key', () => {
@@ -694,10 +745,8 @@ describe('ReactChildren', () => {
element => element,
);
var mappedWithClone = React.Children.map(
instance.props.children,
element => React.cloneElement(element),
);
var mappedWithClone = React.Children.map(instance.props.children, element =>
React.cloneElement(element));
expect(mapped[0].key).toBe(mappedWithClone[0].key);
});
@@ -714,10 +763,8 @@ describe('ReactChildren', () => {
element => element,
);
var mappedWithClone = React.Children.map(
instance.props.children,
element => React.cloneElement(element, {key: 'unique'}),
);
var mappedWithClone = React.Children.map(instance.props.children, element =>
React.cloneElement(element, {key: 'unique'}));
expect(mapped[0].key).toBe(mappedWithClone[0].key);
});
@@ -773,14 +820,16 @@ describe('ReactChildren', () => {
// 2. If grouped in an Array, the `key` prop, falling back to array index
var instance = (
<div>{[
ReactFragment.create({
firstHalfKey: [zero, one, two],
secondHalfKey: [three, four],
keyFive: five,
}),
null,
]}</div>
<div>
{[
ReactFragment.create({
firstHalfKey: [zero, one, two],
secondHalfKey: [three, four],
keyFive: five,
}),
null,
]}
</div>
);
var numberOfChildren = React.Children.count(instance.props.children);
expect(numberOfChildren).toBe(5);
@@ -792,10 +841,8 @@ describe('ReactChildren', () => {
expect(React.Children.toArray(<div />).length).toBe(1);
expect(React.Children.toArray([<div />]).length).toBe(1);
expect(
React.Children.toArray(<div />)[0].key
).toBe(
React.Children.toArray([<div />])[0].key
expect(React.Children.toArray(<div />)[0].key).toBe(
React.Children.toArray([<div />])[0].key,
);
var flattened = React.Children.toArray([
@@ -819,9 +866,10 @@ describe('ReactChildren', () => {
expect(flattened[5].key).toBe(reversed[3].key);
// null/undefined/bool are all omitted
expect(React.Children.toArray([1, 'two', null, undefined, true])).toEqual(
[1, 'two']
);
expect(React.Children.toArray([1, 'two', null, undefined, true])).toEqual([
1,
'two',
]);
});
it('should throw on object', () => {
@@ -829,9 +877,9 @@ describe('ReactChildren', () => {
React.Children.forEach({a: 1, b: 2}, function() {}, null);
}).toThrowError(
'Objects are not valid as a React child (found: object with keys ' +
'{a, b}). If you meant to render a collection of children, use an ' +
'array instead or wrap the object using createFragment(object) from ' +
'the React add-ons.'
'{a, b}). If you meant to render a collection of children, use an ' +
'array instead or wrap the object using createFragment(object) from ' +
'the React add-ons.',
);
});
@@ -842,8 +890,8 @@ describe('ReactChildren', () => {
React.Children.forEach(/abc/, function() {}, null);
}).toThrowError(
'Objects are not valid as a React child (found: /abc/). If you meant ' +
'to render a collection of children, use an array instead or wrap the ' +
'object using createFragment(object) from the React add-ons.'
'to render a collection of children, use an array instead or wrap the ' +
'object using createFragment(object) from the React add-ons.',
);
});
});
@@ -12,7 +12,6 @@
'use strict';
describe('onlyChild', () => {
var React;
var ReactFragment;
var onlyChild;
@@ -35,60 +34,64 @@ describe('onlyChild', () => {
it('should fail when passed two children', () => {
expect(function() {
var instance =
var instance = (
<WrapComponent>
<div />
<span />
</WrapComponent>;
</WrapComponent>
);
onlyChild(instance.props.children);
}).toThrow();
});
it('should fail when passed nully values', () => {
expect(function() {
var instance =
var instance = (
<WrapComponent>
{null}
</WrapComponent>;
</WrapComponent>
);
onlyChild(instance.props.children);
}).toThrow();
expect(function() {
var instance =
var instance = (
<WrapComponent>
{undefined}
</WrapComponent>;
</WrapComponent>
);
onlyChild(instance.props.children);
}).toThrow();
});
it('should fail when key/value objects', () => {
expect(function() {
var instance =
var instance = (
<WrapComponent>
{ReactFragment.create({oneThing: <span />})}
</WrapComponent>;
</WrapComponent>
);
onlyChild(instance.props.children);
}).toThrow();
});
it('should not fail when passed interpolated single child', () => {
expect(function() {
var instance =
var instance = (
<WrapComponent>
{<span />}
</WrapComponent>;
</WrapComponent>
);
onlyChild(instance.props.children);
}).not.toThrow();
});
it('should return the only child', () => {
var instance =
var instance = (
<WrapComponent>
<span />
</WrapComponent>;
</WrapComponent>
);
expect(onlyChild(instance.props.children)).toEqual(<span />);
});
});
+1 -1
View File
@@ -31,7 +31,7 @@ var invariant = require('fbjs/lib/invariant');
function onlyChild(children) {
invariant(
ReactElement.isValidElement(children),
'React.Children.only expected to receive a single React element child.'
'React.Children.only expected to receive a single React element child.',
);
return children;
}
@@ -66,7 +66,9 @@ describe('ReactContextValidator', () => {
},
});
var instance = ReactTestUtils.renderIntoDocument(<ComponentInFooBarContext />);
var instance = ReactTestUtils.renderIntoDocument(
<ComponentInFooBarContext />,
);
expect(instance.refs.child.context).toEqual({foo: 'abc'});
});
@@ -184,9 +186,9 @@ describe('ReactContextValidator', () => {
expectDev(console.error.calls.count()).toBe(1);
expectDev(normalizeCodeLocInfo(console.error.calls.argsFor(0)[0])).toBe(
'Warning: Failed context type: ' +
'The context `foo` is marked as required in `Component`, but its value ' +
'is `undefined`.\n' +
' in Component (at **)'
'The context `foo` is marked as required in `Component`, but its value ' +
'is `undefined`.\n' +
' in Component (at **)',
);
var ComponentInFooStringContext = React.createClass({
@@ -206,7 +208,7 @@ describe('ReactContextValidator', () => {
});
ReactTestUtils.renderIntoDocument(
<ComponentInFooStringContext fooValue={'bar'} />
<ComponentInFooStringContext fooValue={'bar'} />,
);
// Previous call should not error
@@ -228,15 +230,17 @@ describe('ReactContextValidator', () => {
},
});
ReactTestUtils.renderIntoDocument(<ComponentInFooNumberContext fooValue={123} />);
ReactTestUtils.renderIntoDocument(
<ComponentInFooNumberContext fooValue={123} />,
);
expectDev(console.error.calls.count()).toBe(2);
expectDev(normalizeCodeLocInfo(console.error.calls.argsFor(1)[0])).toBe(
'Warning: Failed context type: ' +
'Invalid context `foo` of type `number` supplied ' +
'to `Component`, expected `string`.\n' +
' in Component (at **)\n' +
' in ComponentInFooNumberContext (at **)'
'Invalid context `foo` of type `number` supplied ' +
'to `Component`, expected `string`.\n' +
' in Component (at **)\n' +
' in ComponentInFooNumberContext (at **)',
);
});
@@ -262,9 +266,9 @@ describe('ReactContextValidator', () => {
expectDev(console.error.calls.count()).toBe(1);
expectDev(normalizeCodeLocInfo(console.error.calls.argsFor(0)[0])).toBe(
'Warning: Failed child context type: ' +
'The child context `foo` is marked as required in `Component`, but its ' +
'value is `undefined`.\n' +
' in Component (at **)'
'The child context `foo` is marked as required in `Component`, but its ' +
'value is `undefined`.\n' +
' in Component (at **)',
);
ReactTestUtils.renderIntoDocument(<Component testContext={{foo: 123}} />);
@@ -272,18 +276,16 @@ describe('ReactContextValidator', () => {
expectDev(console.error.calls.count()).toBe(2);
expectDev(normalizeCodeLocInfo(console.error.calls.argsFor(1)[0])).toBe(
'Warning: Failed child context type: ' +
'Invalid child context `foo` of type `number` ' +
'supplied to `Component`, expected `string`.\n' +
' in Component (at **)'
'Invalid child context `foo` of type `number` ' +
'supplied to `Component`, expected `string`.\n' +
' in Component (at **)',
);
ReactTestUtils.renderIntoDocument(
<Component testContext={{foo: 'foo', bar: 123}} />
<Component testContext={{foo: 'foo', bar: 123}} />,
);
ReactTestUtils.renderIntoDocument(
<Component testContext={{foo: 'foo'}} />
);
ReactTestUtils.renderIntoDocument(<Component testContext={{foo: 'foo'}} />);
// Previous calls should not log errors
expectDev(console.error.calls.count()).toBe(2);
@@ -315,8 +317,8 @@ describe('ReactContextValidator', () => {
expectDev(console.error.calls.count()).toBe(1);
expectDev(normalizeCodeLocInfo(console.error.calls.argsFor(0)[0])).toBe(
'Warning: ComponentA.childContextTypes is specified but there is no ' +
'getChildContext() method on the instance. You can either define ' +
'getChildContext() on ComponentA or remove childContextTypes from it.'
'getChildContext() method on the instance. You can either define ' +
'getChildContext() on ComponentA or remove childContextTypes from it.',
);
// Warnings should be deduped by component type
@@ -326,8 +328,8 @@ describe('ReactContextValidator', () => {
expectDev(console.error.calls.count()).toBe(2);
expectDev(normalizeCodeLocInfo(console.error.calls.argsFor(1)[0])).toBe(
'Warning: ComponentB.childContextTypes is specified but there is no ' +
'getChildContext() method on the instance. You can either define ' +
'getChildContext() on ComponentB or remove childContextTypes from it.'
'getChildContext() method on the instance. You can either define ' +
'getChildContext() on ComponentB or remove childContextTypes from it.',
);
});
@@ -375,5 +377,4 @@ describe('ReactContextValidator', () => {
expect(childContext.bar).toBeUndefined();
expect(childContext.foo).toBe('FOO');
});
});
+73 -112
View File
@@ -36,23 +36,19 @@ type SpecPolicy =
/**
* These methods may be defined only once by the class specification or mixin.
*/
'DEFINE_ONCE' |
/**
| 'DEFINE_ONCE' /**
* These methods may be defined by both the class specification and mixins.
* Subsequent definitions will be chained. These methods must return void.
*/
'DEFINE_MANY' |
/**
| 'DEFINE_MANY' /**
* These methods are overriding the base class.
*/
'OVERRIDE_BASE' |
/**
| 'OVERRIDE_BASE' /**
* These methods are similar to DEFINE_MANY, except we assume they return
* objects. We try to merge the keys of the return values of all the mixed in
* functions. If there is a key conflict we throw.
*/
'DEFINE_MANY_MERGED';
| 'DEFINE_MANY_MERGED';
/**
* Composite components are higher-level components that compose other composite
@@ -77,7 +73,6 @@ type SpecPolicy =
* @internal
*/
var ReactClassInterface: {[key: string]: SpecPolicy} = {
/**
* An array of Mixin objects to include when defining your component.
*
@@ -172,8 +167,6 @@ var ReactClassInterface: {[key: string]: SpecPolicy} = {
*/
render: 'DEFINE_ONCE',
// ==== Delegate methods ====
/**
@@ -284,8 +277,6 @@ var ReactClassInterface: {[key: string]: SpecPolicy} = {
*/
componentWillUnmount: 'DEFINE_MANY',
// ==== Advanced methods ====
/**
@@ -299,7 +290,6 @@ var ReactClassInterface: {[key: string]: SpecPolicy} = {
* @overridable
*/
updateComponent: 'OVERRIDE_BASE',
};
/**
@@ -324,30 +314,22 @@ var RESERVED_SPEC_KEYS = {
},
childContextTypes: function(Constructor, childContextTypes) {
if (__DEV__) {
validateTypeDef(
Constructor,
childContextTypes,
'child context'
);
validateTypeDef(Constructor, childContextTypes, 'child context');
}
Constructor.childContextTypes = Object.assign(
{},
Constructor.childContextTypes,
childContextTypes
childContextTypes,
);
},
contextTypes: function(Constructor, contextTypes) {
if (__DEV__) {
validateTypeDef(
Constructor,
contextTypes,
'context'
);
validateTypeDef(Constructor, contextTypes, 'context');
}
Constructor.contextTypes = Object.assign(
{},
Constructor.contextTypes,
contextTypes
contextTypes,
);
},
/**
@@ -358,7 +340,7 @@ var RESERVED_SPEC_KEYS = {
if (Constructor.getDefaultProps) {
Constructor.getDefaultProps = createMergedResultFunction(
Constructor.getDefaultProps,
getDefaultProps
getDefaultProps,
);
} else {
Constructor.getDefaultProps = getDefaultProps;
@@ -366,17 +348,9 @@ var RESERVED_SPEC_KEYS = {
},
propTypes: function(Constructor, propTypes) {
if (__DEV__) {
validateTypeDef(
Constructor,
propTypes,
'prop'
);
validateTypeDef(Constructor, propTypes, 'prop');
}
Constructor.propTypes = Object.assign(
{},
Constructor.propTypes,
propTypes
);
Constructor.propTypes = Object.assign({}, Constructor.propTypes, propTypes);
},
statics: function(Constructor, statics) {
mixStaticSpecIntoComponent(Constructor, statics);
@@ -384,11 +358,7 @@ var RESERVED_SPEC_KEYS = {
autobind: function() {}, // noop
};
function validateTypeDef(
Constructor,
typeDef,
location: string,
) {
function validateTypeDef(Constructor, typeDef, location: string) {
for (var propName in typeDef) {
if (typeDef.hasOwnProperty(propName)) {
// use a warning instead of an invariant so components
@@ -396,40 +366,39 @@ function validateTypeDef(
warning(
typeof typeDef[propName] === 'function',
'%s: %s type `%s` is invalid; it must be a function, usually from ' +
'React.PropTypes.',
'React.PropTypes.',
Constructor.displayName || 'ReactClass',
location,
propName
propName,
);
}
}
}
function validateMethodOverride(isAlreadyDefined, name) {
var specPolicy = ReactClassInterface.hasOwnProperty(name) ?
ReactClassInterface[name] :
null;
var specPolicy = ReactClassInterface.hasOwnProperty(name)
? ReactClassInterface[name]
: null;
// Disallow overriding of base class methods unless explicitly allowed.
if (ReactClassMixin.hasOwnProperty(name)) {
invariant(
specPolicy === 'OVERRIDE_BASE',
'ReactClassInterface: You are attempting to override ' +
'`%s` from your class specification. Ensure that your method names ' +
'do not overlap with React methods.',
name
'`%s` from your class specification. Ensure that your method names ' +
'do not overlap with React methods.',
name,
);
}
// Disallow defining methods more than once unless explicitly allowed.
if (isAlreadyDefined) {
invariant(
specPolicy === 'DEFINE_MANY' ||
specPolicy === 'DEFINE_MANY_MERGED',
specPolicy === 'DEFINE_MANY' || specPolicy === 'DEFINE_MANY_MERGED',
'ReactClassInterface: You are attempting to define ' +
'`%s` on your component more than once. This conflict may be due ' +
'to a mixin.',
name
'`%s` on your component more than once. This conflict may be due ' +
'to a mixin.',
name,
);
}
}
@@ -446,12 +415,12 @@ function mixSpecIntoComponent(Constructor, spec) {
warning(
isMixinValid,
'%s: You\'re attempting to include a mixin that is either null ' +
'or not an object. Check the mixins included by the component, ' +
'as well as any mixins they include themselves. ' +
'Expected object but got %s.',
"%s: You're attempting to include a mixin that is either null " +
'or not an object. Check the mixins included by the component, ' +
'as well as any mixins they include themselves. ' +
'Expected object but got %s.',
Constructor.displayName || 'ReactClass',
spec === null ? null : typeofSpec
spec === null ? null : typeofSpec,
);
}
@@ -460,14 +429,14 @@ function mixSpecIntoComponent(Constructor, spec) {
invariant(
typeof spec !== 'function',
'ReactClass: You\'re attempting to ' +
'use a component class or function as a mixin. Instead, just use a ' +
'regular object.'
"ReactClass: You're attempting to " +
'use a component class or function as a mixin. Instead, just use a ' +
'regular object.',
);
invariant(
!ReactElement.isValidElement(spec),
'ReactClass: You\'re attempting to ' +
'use a component as a mixin. Instead, just use a regular object.'
"ReactClass: You're attempting to " +
'use a component as a mixin. Instead, just use a regular object.',
);
var proto = Constructor.prototype;
@@ -501,11 +470,9 @@ function mixSpecIntoComponent(Constructor, spec) {
// The following member methods should not be automatically bound:
// 1. Expected ReactClass methods (in the "interface").
// 2. Overridden methods (that were mixed in).
var isReactClassMethod =
ReactClassInterface.hasOwnProperty(name);
var isReactClassMethod = ReactClassInterface.hasOwnProperty(name);
var isFunction = typeof property === 'function';
var shouldAutoBind =
isFunction &&
var shouldAutoBind = isFunction &&
!isReactClassMethod &&
!isAlreadyDefined &&
spec.autobind !== false;
@@ -519,14 +486,13 @@ function mixSpecIntoComponent(Constructor, spec) {
// These cases should already be caught by validateMethodOverride.
invariant(
isReactClassMethod && (
specPolicy === 'DEFINE_MANY_MERGED' ||
specPolicy === 'DEFINE_MANY'
),
isReactClassMethod &&
(specPolicy === 'DEFINE_MANY_MERGED' ||
specPolicy === 'DEFINE_MANY'),
'ReactClass: Unexpected spec policy %s for key %s ' +
'when mixing in component specs.',
'when mixing in component specs.',
specPolicy,
name
name,
);
// For methods which are defined more than once, call the existing
@@ -565,19 +531,19 @@ function mixStaticSpecIntoComponent(Constructor, statics) {
invariant(
!isReserved,
'ReactClass: You are attempting to define a reserved ' +
'property, `%s`, that shouldn\'t be on the "statics" key. Define it ' +
'as an instance property instead; it will still be accessible on the ' +
'constructor.',
name
'property, `%s`, that shouldn\'t be on the "statics" key. Define it ' +
'as an instance property instead; it will still be accessible on the ' +
'constructor.',
name,
);
var isInherited = name in Constructor;
invariant(
!isInherited,
'ReactClass: You are attempting to define ' +
'`%s` on your component more than once. This conflict may be ' +
'due to a mixin.',
name
'`%s` on your component more than once. This conflict may be ' +
'due to a mixin.',
name,
);
Constructor[name] = property;
}
@@ -593,7 +559,7 @@ function mixStaticSpecIntoComponent(Constructor, statics) {
function mergeIntoWithNoDuplicateKeys(one, two) {
invariant(
one && two && typeof one === 'object' && typeof two === 'object',
'mergeIntoWithNoDuplicateKeys(): Cannot merge non-objects.'
'mergeIntoWithNoDuplicateKeys(): Cannot merge non-objects.',
);
for (var key in two) {
@@ -601,11 +567,11 @@ function mergeIntoWithNoDuplicateKeys(one, two) {
invariant(
one[key] === undefined,
'mergeIntoWithNoDuplicateKeys(): ' +
'Tried to merge two objects with the same key: `%s`. This conflict ' +
'may be due to a mixin; in particular, this may be caused by two ' +
'getInitialState() or getDefaultProps() methods returning objects ' +
'with clashing keys.',
key
'Tried to merge two objects with the same key: `%s`. This conflict ' +
'may be due to a mixin; in particular, this may be caused by two ' +
'getInitialState() or getDefaultProps() methods returning objects ' +
'with clashing keys.',
key,
);
one[key] = two[key];
}
@@ -675,16 +641,16 @@ function bindAutoBindMethod(component, method) {
warning(
false,
'bind(): React component methods may only be bound to the ' +
'component instance.\n\nSee %s',
componentName
'component instance.\n\nSee %s',
componentName,
);
} else if (!args.length) {
warning(
false,
'bind(): You are binding a component method to the component. ' +
'React does this for you automatically in a high-performance ' +
'way, so you can safely remove this call.\n\nSee %s',
componentName
'React does this for you automatically in a high-performance ' +
'way, so you can safely remove this call.\n\nSee %s',
componentName,
);
return boundMethod;
}
@@ -708,10 +674,7 @@ function bindAutoBindMethods(component) {
for (var i = 0; i < pairs.length; i += 2) {
var autoBindKey = pairs[i];
var method = pairs[i + 1];
component[autoBindKey] = bindAutoBindMethod(
component,
method
);
component[autoBindKey] = bindAutoBindMethod(component, method);
}
}
@@ -720,7 +683,6 @@ function bindAutoBindMethods(component) {
* therefore not already part of the modern ReactComponent.
*/
var ReactClassMixin = {
/**
* TODO: This will be deprecated because state should always keep a consistent
* type signature and the only use case for this, is to avoid that.
@@ -744,7 +706,7 @@ var ReactClassComponent = function() {};
Object.assign(
ReactClassComponent.prototype,
ReactComponent.prototype,
ReactClassMixin
ReactClassMixin,
);
/**
@@ -753,7 +715,6 @@ Object.assign(
* @class ReactClass
*/
var ReactClass = {
/**
* Creates a composite component class given a class specification.
* See https://facebook.github.io/react/docs/react-api.html#createclass
@@ -774,7 +735,7 @@ var ReactClass = {
warning(
this instanceof Constructor,
'Something is calling a React component directly. Use a factory or ' +
'JSX instead. See: https://fb.me/react-legacyfactory'
'JSX instead. See: https://fb.me/react-legacyfactory',
);
}
@@ -796,8 +757,9 @@ var ReactClass = {
var initialState = this.getInitialState ? this.getInitialState() : null;
if (__DEV__) {
// We allow auto-mocks to proceed as if they're returning null.
if (initialState === undefined &&
this.getInitialState._isMockFunction) {
if (
initialState === undefined && this.getInitialState._isMockFunction
) {
// This is probably bad practice. Consider warning here and
// deprecating this convenience.
initialState = null;
@@ -806,7 +768,7 @@ var ReactClass = {
invariant(
typeof initialState === 'object' && !Array.isArray(initialState),
'%s.getInitialState(): must return an object or null',
Constructor.displayName || 'ReactCompositeComponent'
Constructor.displayName || 'ReactCompositeComponent',
);
this.state = initialState;
@@ -837,23 +799,23 @@ var ReactClass = {
invariant(
Constructor.prototype.render,
'createClass(...): Class specification must implement a `render` method.'
'createClass(...): Class specification must implement a `render` method.',
);
if (__DEV__) {
warning(
!Constructor.prototype.componentShouldUpdate,
'%s has a method called ' +
'componentShouldUpdate(). Did you mean shouldComponentUpdate()? ' +
'The name is phrased as a question because the function is ' +
'expected to return a value.',
spec.displayName || 'A component'
'componentShouldUpdate(). Did you mean shouldComponentUpdate()? ' +
'The name is phrased as a question because the function is ' +
'expected to return a value.',
spec.displayName || 'A component',
);
warning(
!Constructor.prototype.componentWillRecieveProps,
'%s has a method called ' +
'componentWillRecieveProps(). Did you mean componentWillReceiveProps()?',
spec.displayName || 'A component'
'componentWillRecieveProps(). Did you mean componentWillReceiveProps()?',
spec.displayName || 'A component',
);
}
@@ -866,7 +828,6 @@ var ReactClass = {
return Constructor;
},
};
module.exports = ReactClass;
@@ -16,9 +16,7 @@ var ReactTestUtils = require('ReactTestUtils');
// TODO: Test render and all stock methods.
describe('autobinding', () => {
it('Holds reference to instance', () => {
var mouseDidEnter = jest.fn();
var mouseDidLeave = jest.fn();
var mouseDidClick = jest.fn();
@@ -115,7 +113,7 @@ describe('autobinding', () => {
spyOn(console, 'error');
var TestBindComponent = React.createClass({
handleClick: function() { },
handleClick: function() {},
render: function() {
return <div onClick={this.handleClick.bind(this)} />;
},
@@ -126,8 +124,8 @@ describe('autobinding', () => {
expectDev(console.error.calls.count()).toBe(1);
expectDev(console.error.calls.argsFor(0)[0]).toBe(
'Warning: bind(): You are binding a component method to the component. ' +
'React does this for you automatically in a high-performance ' +
'way, so you can safely remove this call.\n\nSee TestBindComponent'
'React does this for you automatically in a high-performance ' +
'way, so you can safely remove this call.\n\nSee TestBindComponent',
);
});
@@ -141,9 +139,7 @@ describe('autobinding', () => {
componentDidMount: function() {
this.setState({foo: 2}, this.handleUpdate);
},
handleUpdate: function() {
},
handleUpdate: function() {},
render: function() {
return <div onClick={this.handleClick} />;
},
@@ -153,5 +149,4 @@ describe('autobinding', () => {
expectDev(console.error.calls.count()).toBe(0);
});
});
@@ -16,9 +16,7 @@ var ReactTestUtils = require('ReactTestUtils');
// TODO: Test render and all stock methods.
describe('autobind optout', () => {
it('should work with manual binding', () => {
var mouseDidEnter = jest.fn();
var mouseDidLeave = jest.fn();
var mouseDidClick = jest.fn();
@@ -39,7 +37,7 @@ describe('autobind optout', () => {
onMouseOver={this.onMouseEnter.bind(this)}
onMouseOut={this.onMouseLeave.bind(this)}
onClick={this.onClick.bind(this)}
/>
/>
);
},
});
@@ -95,12 +93,7 @@ describe('autobind optout', () => {
},
render: function() {
return (
<div
ref="child"
onClick={this.onClick}
/>
);
return <div ref="child" onClick={this.onClick} />;
},
});
@@ -178,7 +171,7 @@ describe('autobind optout', () => {
var TestBindComponent = React.createClass({
autobind: false,
handleClick: function() { },
handleClick: function() {},
render: function() {
return <div onClick={this.handleClick.bind(this)} />;
},
@@ -200,9 +193,7 @@ describe('autobind optout', () => {
componentDidMount: function() {
this.setState({foo: 2}, this.handleUpdate.bind(this));
},
handleUpdate: function() {
},
handleUpdate: function() {},
render: function() {
return <div />;
},
@@ -212,5 +203,4 @@ describe('autobind optout', () => {
expectDev(console.error.calls.count()).toBe(0);
});
});
@@ -16,7 +16,6 @@ var ReactDOM;
var ReactTestUtils;
describe('ReactClass-spec', () => {
beforeEach(() => {
React = require('react');
ReactDOM = require('react-dom');
@@ -27,7 +26,7 @@ describe('ReactClass-spec', () => {
expect(function() {
React.createClass({});
}).toThrowError(
'createClass(...): Class specification must implement a `render` method.'
'createClass(...): Class specification must implement a `render` method.',
);
});
@@ -38,8 +37,7 @@ describe('ReactClass-spec', () => {
},
});
expect(TestComponent.displayName)
.toBe('TestComponent');
expect(TestComponent.displayName).toBe('TestComponent');
});
it('should copy prop types onto the Constructor', () => {
@@ -54,8 +52,7 @@ describe('ReactClass-spec', () => {
});
expect(TestComponent.propTypes).toBeDefined();
expect(TestComponent.propTypes.value)
.toBe(propValidator);
expect(TestComponent.propTypes.value).toBe(propValidator);
});
it('should warn on invalid prop types', () => {
@@ -72,7 +69,7 @@ describe('ReactClass-spec', () => {
expectDev(console.error.calls.count()).toBe(1);
expectDev(console.error.calls.argsFor(0)[0]).toBe(
'Warning: Component: prop type `prop` is invalid; ' +
'it must be a function, usually from React.PropTypes.'
'it must be a function, usually from React.PropTypes.',
);
});
@@ -90,7 +87,7 @@ describe('ReactClass-spec', () => {
expectDev(console.error.calls.count()).toBe(1);
expectDev(console.error.calls.argsFor(0)[0]).toBe(
'Warning: Component: context type `prop` is invalid; ' +
'it must be a function, usually from React.PropTypes.'
'it must be a function, usually from React.PropTypes.',
);
});
@@ -108,7 +105,7 @@ describe('ReactClass-spec', () => {
expectDev(console.error.calls.count()).toBe(1);
expectDev(console.error.calls.argsFor(0)[0]).toBe(
'Warning: Component: child context type `prop` is invalid; ' +
'it must be a function, usually from React.PropTypes.'
'it must be a function, usually from React.PropTypes.',
);
});
@@ -126,8 +123,8 @@ describe('ReactClass-spec', () => {
expectDev(console.error.calls.count()).toBe(1);
expectDev(console.error.calls.argsFor(0)[0]).toBe(
'Warning: A component has a method called componentShouldUpdate(). Did you ' +
'mean shouldComponentUpdate()? The name is phrased as a question ' +
'because the function is expected to return a value.'
'mean shouldComponentUpdate()? The name is phrased as a question ' +
'because the function is expected to return a value.',
);
React.createClass({
@@ -142,8 +139,8 @@ describe('ReactClass-spec', () => {
expectDev(console.error.calls.count()).toBe(2);
expectDev(console.error.calls.argsFor(1)[0]).toBe(
'Warning: NamedComponent has a method called componentShouldUpdate(). Did you ' +
'mean shouldComponentUpdate()? The name is phrased as a question ' +
'because the function is expected to return a value.'
'mean shouldComponentUpdate()? The name is phrased as a question ' +
'because the function is expected to return a value.',
);
});
@@ -160,7 +157,7 @@ describe('ReactClass-spec', () => {
expectDev(console.error.calls.count()).toBe(1);
expectDev(console.error.calls.argsFor(0)[0]).toBe(
'Warning: A component has a method called componentWillRecieveProps(). Did you ' +
'mean componentWillReceiveProps()?'
'mean componentWillReceiveProps()?',
);
});
@@ -181,9 +178,9 @@ describe('ReactClass-spec', () => {
});
}).toThrowError(
'ReactClass: You are attempting to define a reserved property, ' +
'`getDefaultProps`, that shouldn\'t be on the "statics" key. Define ' +
'it as an instance property instead; it will still be accessible on ' +
'the constructor.'
'`getDefaultProps`, that shouldn\'t be on the "statics" key. Define ' +
'it as an instance property instead; it will still be accessible on ' +
'the constructor.',
);
});
@@ -209,19 +206,19 @@ describe('ReactClass-spec', () => {
expectDev(console.error.calls.count()).toBe(4);
expectDev(console.error.calls.argsFor(0)[0]).toBe(
'createClass(...): `mixins` is now a static property and should ' +
'be defined inside "statics".'
'be defined inside "statics".',
);
expectDev(console.error.calls.argsFor(1)[0]).toBe(
'createClass(...): `propTypes` is now a static property and should ' +
'be defined inside "statics".'
'be defined inside "statics".',
);
expectDev(console.error.calls.argsFor(2)[0]).toBe(
'createClass(...): `contextTypes` is now a static property and ' +
'should be defined inside "statics".'
'should be defined inside "statics".',
);
expectDev(console.error.calls.argsFor(3)[0]).toBe(
'createClass(...): `childContextTypes` is now a static property and ' +
'should be defined inside "statics".'
'should be defined inside "statics".',
);
});
@@ -315,7 +312,7 @@ describe('ReactClass-spec', () => {
expect(function() {
instance = ReactTestUtils.renderIntoDocument(instance);
}).toThrowError(
'Component.getInitialState(): must return an object or null'
'Component.getInitialState(): must return an object or null',
);
});
});
@@ -329,9 +326,8 @@ describe('ReactClass-spec', () => {
return <span />;
},
});
expect(
() => ReactTestUtils.renderIntoDocument(<Component />)
).not.toThrow();
expect(() =>
ReactTestUtils.renderIntoDocument(<Component />)).not.toThrow();
});
it('should throw when using legacy factories', () => {
@@ -346,8 +342,7 @@ describe('ReactClass-spec', () => {
expectDev(console.error.calls.count()).toBe(1);
expectDev(console.error.calls.argsFor(0)[0]).toBe(
'Warning: Something is calling a React component directly. Use a ' +
'factory or JSX instead. See: https://fb.me/react-legacyfactory'
'factory or JSX instead. See: https://fb.me/react-legacyfactory',
);
});
});
@@ -21,7 +21,6 @@ var mixinPropValidator;
var componentPropValidator;
describe('ReactClass-mixin', () => {
beforeEach(() => {
React = require('react');
ReactTestUtils = require('ReactTestUtils');
@@ -149,23 +148,22 @@ describe('ReactClass-mixin', () => {
it('should validate prop types via mixins', () => {
expect(TestComponent.propTypes).toBeDefined();
expect(TestComponent.propTypes.value)
.toBe(mixinPropValidator);
expect(TestComponent.propTypes.value).toBe(mixinPropValidator);
});
it('should override mixin prop types with class prop types', () => {
// Sanity check...
expect(componentPropValidator).not.toBe(mixinPropValidator);
// Actually check...
expect(TestComponentWithPropTypes.propTypes)
.toBeDefined();
expect(TestComponentWithPropTypes.propTypes.value)
.not.toBe(mixinPropValidator);
expect(TestComponentWithPropTypes.propTypes.value)
.toBe(componentPropValidator);
expect(TestComponentWithPropTypes.propTypes).toBeDefined();
expect(TestComponentWithPropTypes.propTypes.value).not.toBe(
mixinPropValidator,
);
expect(TestComponentWithPropTypes.propTypes.value).toBe(
componentPropValidator,
);
});
it('should support mixins with getInitialState()', () => {
var Mixin = {
getInitialState: function() {
@@ -205,9 +203,9 @@ describe('ReactClass-mixin', () => {
ReactTestUtils.renderIntoDocument(<Component />);
}).toThrowError(
'mergeIntoWithNoDuplicateKeys(): Tried to merge two objects with the ' +
'same key: `x`. This conflict may be due to a mixin; in particular, ' +
'this may be caused by two getInitialState() or getDefaultProps() ' +
'methods returning objects with clashing keys.'
'same key: `x`. This conflict may be due to a mixin; in particular, ' +
'this may be caused by two getInitialState() or getDefaultProps() ' +
'methods returning objects with clashing keys.',
);
});
@@ -276,7 +274,7 @@ describe('ReactClass-mixin', () => {
});
}).toThrowError(
'ReactClass: You are attempting to define `abc` on your component more ' +
'than once. This conflict may be due to a mixin.'
'than once. This conflict may be due to a mixin.',
);
});
@@ -304,7 +302,7 @@ describe('ReactClass-mixin', () => {
});
}).toThrowError(
'ReactClass: You are attempting to define `abc` on your component ' +
'more than once. This conflict may be due to a mixin.'
'more than once. This conflict may be due to a mixin.',
);
});
@@ -321,10 +319,10 @@ describe('ReactClass-mixin', () => {
expectDev(console.error.calls.count()).toBe(1);
expectDev(console.error.calls.argsFor(0)[0]).toBe(
'Warning: ReactClass: You\'re attempting to include a mixin that is ' +
'either null or not an object. Check the mixins included by the ' +
'component, as well as any mixins they include themselves. ' +
'Expected object but got undefined.'
"Warning: ReactClass: You're attempting to include a mixin that is " +
'either null or not an object. Check the mixins included by the ' +
'component, as well as any mixins they include themselves. ' +
'Expected object but got undefined.',
);
});
@@ -341,10 +339,10 @@ describe('ReactClass-mixin', () => {
expectDev(console.error.calls.count()).toBe(1);
expectDev(console.error.calls.argsFor(0)[0]).toBe(
'Warning: ReactClass: You\'re attempting to include a mixin that is ' +
'either null or not an object. Check the mixins included by the ' +
'component, as well as any mixins they include themselves. ' +
'Expected object but got null.'
"Warning: ReactClass: You're attempting to include a mixin that is " +
'either null or not an object. Check the mixins included by the ' +
'component, as well as any mixins they include themselves. ' +
'Expected object but got null.',
);
});
@@ -365,10 +363,10 @@ describe('ReactClass-mixin', () => {
expectDev(console.error.calls.count()).toBe(1);
expectDev(console.error.calls.argsFor(0)[0]).toBe(
'Warning: ReactClass: You\'re attempting to include a mixin that is ' +
'either null or not an object. Check the mixins included by the ' +
'component, as well as any mixins they include themselves. ' +
'Expected object but got undefined.'
"Warning: ReactClass: You're attempting to include a mixin that is " +
'either null or not an object. Check the mixins included by the ' +
'component, as well as any mixins they include themselves. ' +
'Expected object but got undefined.',
);
});
@@ -389,10 +387,10 @@ describe('ReactClass-mixin', () => {
expectDev(console.error.calls.count()).toBe(1);
expectDev(console.error.calls.argsFor(0)[0]).toBe(
'Warning: ReactClass: You\'re attempting to include a mixin that is ' +
'either null or not an object. Check the mixins included by the ' +
'component, as well as any mixins they include themselves. ' +
'Expected object but got null.'
"Warning: ReactClass: You're attempting to include a mixin that is " +
'either null or not an object. Check the mixins included by the ' +
'component, as well as any mixins they include themselves. ' +
'Expected object but got null.',
);
});
@@ -406,8 +404,8 @@ describe('ReactClass-mixin', () => {
},
});
}).toThrowError(
'ReactClass: You\'re attempting to use a component as a mixin. ' +
'Instead, just use a regular object.'
"ReactClass: You're attempting to use a component as a mixin. " +
'Instead, just use a regular object.',
);
});
@@ -427,8 +425,8 @@ describe('ReactClass-mixin', () => {
},
});
}).toThrowError(
'ReactClass: You\'re attempting to use a component class or function ' +
'as a mixin. Instead, just use a regular object.'
"ReactClass: You're attempting to use a component class or function " +
'as a mixin. Instead, just use a regular object.',
);
});
@@ -488,9 +486,8 @@ describe('ReactClass-mixin', () => {
return <span />;
},
});
expect(
() => ReactTestUtils.renderIntoDocument(<Component />)
).not.toThrow();
expect(() =>
ReactTestUtils.renderIntoDocument(<Component />)).not.toThrow();
instance = ReactTestUtils.renderIntoDocument(<Component />);
expect(instance.state).toEqual({foo: 'bar'});
@@ -510,9 +507,8 @@ describe('ReactClass-mixin', () => {
return <span />;
},
});
expect(
() => ReactTestUtils.renderIntoDocument(<Component />)
).not.toThrow();
expect(() =>
ReactTestUtils.renderIntoDocument(<Component />)).not.toThrow();
instance = ReactTestUtils.renderIntoDocument(<Component />);
expect(instance.state).toEqual({foo: 'bar'});
@@ -527,12 +523,10 @@ describe('ReactClass-mixin', () => {
return <span />;
},
});
expect(
() => ReactTestUtils.renderIntoDocument(<Component />)
).not.toThrow();
expect(() =>
ReactTestUtils.renderIntoDocument(<Component />)).not.toThrow();
instance = ReactTestUtils.renderIntoDocument(<Component />);
expect(instance.state).toEqual({foo: 'bar', x: true});
});
});
@@ -12,8 +12,8 @@
'use strict';
import type { ReactInstance } from 'ReactInstanceType';
import type { Fiber } from 'ReactFiber';
import type {ReactInstance} from 'ReactInstanceType';
import type {Fiber} from 'ReactFiber';
/**
* Keeps track of the current owner.
@@ -22,13 +22,11 @@ import type { Fiber } from 'ReactFiber';
* currently being constructed.
*/
var ReactCurrentOwner = {
/**
* @internal
* @type {ReactComponent}
*/
current: (null: null | ReactInstance | Fiber),
};
module.exports = ReactCurrentOwner;
@@ -141,7 +141,7 @@ var ReactDOMFactories = {
track: createDOMFactory('track'),
u: createDOMFactory('u'),
ul: createDOMFactory('ul'),
'var': createDOMFactory('var'),
var: createDOMFactory('var'),
video: createDOMFactory('video'),
wbr: createDOMFactory('wbr'),
@@ -12,8 +12,8 @@
'use strict';
import type { Fiber } from 'ReactFiber';
import type { DebugID } from 'ReactInstanceType';
import type {Fiber} from 'ReactFiber';
import type {DebugID} from 'ReactInstanceType';
const ReactDebugCurrentFrame = {};
@@ -27,12 +27,12 @@ if (__DEV__) {
} = require('ReactFiberComponentTreeHook');
// Component that is being worked on
ReactDebugCurrentFrame.current = (null : Fiber | DebugID | null);
ReactDebugCurrentFrame.current = (null: Fiber | DebugID | null);
// Element that is being cloned or created
ReactDebugCurrentFrame.element = (null : *);
ReactDebugCurrentFrame.element = (null: *);
ReactDebugCurrentFrame.getStackAddendum = function() : string | null {
ReactDebugCurrentFrame.getStackAddendum = function(): string | null {
let stack = null;
const current = ReactDebugCurrentFrame.current;
const element = ReactDebugCurrentFrame.element;
+28 -32
View File
@@ -59,10 +59,10 @@ function defineKeyPropWarningGetter(props, displayName) {
warning(
false,
'%s: `key` is not a prop. Trying to access it will result ' +
'in `undefined` being returned. If you need to access the same ' +
'value within the child component, you should pass it as a different ' +
'prop. (https://fb.me/react-special-props)',
displayName
'in `undefined` being returned. If you need to access the same ' +
'value within the child component, you should pass it as a different ' +
'prop. (https://fb.me/react-special-props)',
displayName,
);
}
};
@@ -80,10 +80,10 @@ function defineRefPropWarningGetter(props, displayName) {
warning(
false,
'%s: `ref` is not a prop. Trying to access it will result ' +
'in `undefined` being returned. If you need to access the same ' +
'value within the child component, you should pass it as a different ' +
'prop. (https://fb.me/react-special-props)',
displayName
'in `undefined` being returned. If you need to access the same ' +
'value within the child component, you should pass it as a different ' +
'prop. (https://fb.me/react-special-props)',
displayName,
);
}
};
@@ -203,8 +203,10 @@ ReactElement.createElement = function(type, config, children) {
source = config.__source === undefined ? null : config.__source;
// Remaining properties are added to a new props object
for (propName in config) {
if (hasOwnProperty.call(config, propName) &&
!RESERVED_PROPS.hasOwnProperty(propName)) {
if (
hasOwnProperty.call(config, propName) &&
!RESERVED_PROPS.hasOwnProperty(propName)
) {
props[propName] = config[propName];
}
}
@@ -239,11 +241,13 @@ ReactElement.createElement = function(type, config, children) {
}
if (__DEV__) {
if (key || ref) {
if (typeof props.$$typeof === 'undefined' ||
props.$$typeof !== REACT_ELEMENT_TYPE) {
var displayName = typeof type === 'function' ?
(type.displayName || type.name || 'Unknown') :
type;
if (
typeof props.$$typeof === 'undefined' ||
props.$$typeof !== REACT_ELEMENT_TYPE
) {
var displayName = typeof type === 'function'
? type.displayName || type.name || 'Unknown'
: type;
if (key) {
defineKeyPropWarningGetter(props, displayName);
}
@@ -260,7 +264,7 @@ ReactElement.createElement = function(type, config, children) {
self,
source,
ReactCurrentOwner.current,
props
props,
);
};
@@ -287,7 +291,7 @@ ReactElement.cloneAndReplaceKey = function(oldElement, newKey) {
oldElement._self,
oldElement._source,
oldElement._owner,
oldElement.props
oldElement.props,
);
return newElement;
@@ -332,8 +336,10 @@ ReactElement.cloneElement = function(element, config, children) {
defaultProps = element.type.defaultProps;
}
for (propName in config) {
if (hasOwnProperty.call(config, propName) &&
!RESERVED_PROPS.hasOwnProperty(propName)) {
if (
hasOwnProperty.call(config, propName) &&
!RESERVED_PROPS.hasOwnProperty(propName)
) {
if (config[propName] === undefined && defaultProps !== undefined) {
// Resolve default props
props[propName] = defaultProps[propName];
@@ -357,15 +363,7 @@ ReactElement.cloneElement = function(element, config, children) {
props.children = childArray;
}
return ReactElement(
element.type,
key,
ref,
self,
source,
owner,
props
);
return ReactElement(element.type, key, ref, self, source, owner, props);
};
/**
@@ -376,11 +374,9 @@ ReactElement.cloneElement = function(element, config, children) {
* @final
*/
ReactElement.isValidElement = function(object) {
return (
typeof object === 'object' &&
return typeof object === 'object' &&
object !== null &&
object.$$typeof === REACT_ELEMENT_TYPE
);
object.$$typeof === REACT_ELEMENT_TYPE;
};
module.exports = ReactElement;
@@ -30,8 +30,8 @@ var getIteratorFn = require('getIteratorFn');
if (__DEV__) {
var warning = require('fbjs/lib/warning');
var ReactDebugCurrentFrame = require('ReactDebugCurrentFrame');
var {
getCurrentStackAddendum,
var {
getCurrentStackAddendum,
} = require('ReactComponentTreeHook');
}
@@ -70,8 +70,9 @@ function getCurrentComponentErrorInfo(parentType) {
var info = getDeclarationErrorAddendum();
if (!info) {
var parentName = typeof parentType === 'string' ?
parentType : parentType.displayName || parentType.name;
var parentName = typeof parentType === 'string'
? parentType
: parentType.displayName || parentType.name;
if (parentName) {
info = `\n\nCheck the top-level render call using <${parentName}>.`;
}
@@ -96,9 +97,8 @@ function validateExplicitKey(element, parentType) {
}
element._store.validated = true;
var memoizer = ownerHasKeyUseWarning.uniqueKey || (
ownerHasKeyUseWarning.uniqueKey = {}
);
var memoizer = ownerHasKeyUseWarning.uniqueKey ||
(ownerHasKeyUseWarning.uniqueKey = {});
var currentComponentErrorInfo = getCurrentComponentErrorInfo(parentType);
if (memoizer[currentComponentErrorInfo]) {
@@ -110,21 +110,20 @@ function validateExplicitKey(element, parentType) {
// property, it may be the creator of the child that's responsible for
// assigning it a key.
var childOwner = '';
if (element &&
element._owner &&
element._owner !== ReactCurrentOwner.current) {
if (
element && element._owner && element._owner !== ReactCurrentOwner.current
) {
// Give the component that originally created this child.
childOwner =
` It was passed a child from ${getComponentName(element._owner)}.`;
childOwner = ` It was passed a child from ${getComponentName(element._owner)}.`;
}
warning(
false,
'Each child in an array or iterator should have a unique "key" prop.' +
'%s%s See https://fb.me/react-warning-keys for more information.%s',
'%s%s See https://fb.me/react-warning-keys for more information.%s',
currentComponentErrorInfo,
childOwner,
getCurrentStackAddendum(element)
getCurrentStackAddendum(element),
);
}
@@ -183,41 +182,32 @@ function validatePropTypes(element) {
}
var name = componentClass.displayName || componentClass.name;
if (componentClass.propTypes) {
checkReactTypeSpec(
componentClass.propTypes,
element.props,
'prop',
name
);
checkReactTypeSpec(componentClass.propTypes, element.props, 'prop', name);
}
if (typeof componentClass.getDefaultProps === 'function') {
warning(
componentClass.getDefaultProps.isReactClassApproved,
'getDefaultProps is only used on classic React.createClass ' +
'definitions. Use a static property named `defaultProps` instead.'
'definitions. Use a static property named `defaultProps` instead.',
);
}
}
var ReactElementValidator = {
createElement: function(type, props, children) {
var validType =
typeof type === 'string' ||
typeof type === 'function';
var validType = typeof type === 'string' || typeof type === 'function';
// We warn in this case but don't throw. We expect the element creation to
// succeed and there will likely be errors in render.
if (!validType) {
var info = '';
if (
type === undefined ||
typeof type === 'object' &&
type !== null &&
Object.keys(type).length === 0
(typeof type === 'object' &&
type !== null &&
Object.keys(type).length === 0)
) {
info +=
' You likely forgot to export your component from the file ' +
'it\'s defined in.';
info += ' You likely forgot to export your component from the file ' +
"it's defined in.";
}
var sourceInfo = getSourceInfoErrorAddendum(props);
@@ -232,8 +222,8 @@ var ReactElementValidator = {
warning(
false,
'React.createElement: type is invalid -- expected a string (for ' +
'built-in components) or a class/function (for composite ' +
'components) but got: %s.%s',
'built-in components) or a class/function (for composite ' +
'components) but got: %s.%s',
type == null ? type : typeof type,
info,
);
@@ -272,37 +262,29 @@ var ReactElementValidator = {
},
createFactory: function(type) {
var validatedFactory = ReactElementValidator.createElement.bind(
null,
type
);
var validatedFactory = ReactElementValidator.createElement.bind(null, type);
// Legacy hook TODO: Warn if this is accessed
validatedFactory.type = type;
if (__DEV__) {
if (canDefineProperty) {
Object.defineProperty(
validatedFactory,
'type',
{
enumerable: false,
get: function() {
warning(
false,
'Factory.type is deprecated. Access the class directly ' +
'before passing it to createFactory.'
);
Object.defineProperty(this, 'type', {
value: type,
});
return type;
},
}
);
Object.defineProperty(validatedFactory, 'type', {
enumerable: false,
get: function() {
warning(
false,
'Factory.type is deprecated. Access the class directly ' +
'before passing it to createFactory.',
);
Object.defineProperty(this, 'type', {
value: type,
});
return type;
},
});
}
}
return validatedFactory;
},
@@ -320,7 +302,6 @@ var ReactElementValidator = {
}
return newElement;
},
};
module.exports = ReactElementValidator;
@@ -83,9 +83,9 @@ describe('ReactElement', () => {
expectDev(console.error.calls.count()).toBe(1);
expectDev(console.error.calls.argsFor(0)[0]).toContain(
'Child: `key` is not a prop. Trying to access it will result ' +
'in `undefined` being returned. If you need to access the same ' +
'value within the child component, you should pass it as a different ' +
'prop. (https://fb.me/react-special-props)'
'in `undefined` being returned. If you need to access the same ' +
'value within the child component, you should pass it as a different ' +
'prop. (https://fb.me/react-special-props)',
);
});
@@ -113,9 +113,9 @@ describe('ReactElement', () => {
expectDev(console.error.calls.count()).toBe(1);
expectDev(console.error.calls.argsFor(0)[0]).toContain(
'Child: `key` is not a prop. Trying to access it will result ' +
'in `undefined` being returned. If you need to access the same ' +
'value within the child component, you should pass it as a different ' +
'prop. (https://fb.me/react-special-props)'
'in `undefined` being returned. If you need to access the same ' +
'value within the child component, you should pass it as a different ' +
'prop. (https://fb.me/react-special-props)',
);
});
@@ -127,9 +127,9 @@ describe('ReactElement', () => {
expectDev(console.error.calls.count()).toBe(1);
expectDev(console.error.calls.argsFor(0)[0]).toContain(
'div: `key` is not a prop. Trying to access it will result ' +
'in `undefined` being returned. If you need to access the same ' +
'value within the child component, you should pass it as a different ' +
'prop. (https://fb.me/react-special-props)'
'in `undefined` being returned. If you need to access the same ' +
'value within the child component, you should pass it as a different ' +
'prop. (https://fb.me/react-special-props)',
);
});
@@ -155,9 +155,9 @@ describe('ReactElement', () => {
expectDev(console.error.calls.count()).toBe(1);
expectDev(console.error.calls.argsFor(0)[0]).toContain(
'Child: `ref` is not a prop. Trying to access it will result ' +
'in `undefined` being returned. If you need to access the same ' +
'value within the child component, you should pass it as a different ' +
'prop. (https://fb.me/react-special-props)'
'in `undefined` being returned. If you need to access the same ' +
'value within the child component, you should pass it as a different ' +
'prop. (https://fb.me/react-special-props)',
);
});
@@ -265,7 +265,7 @@ describe('ReactElement', () => {
});
var instance = ReactTestUtils.renderIntoDocument(
React.createElement(Wrapper)
React.createElement(Wrapper),
);
if (ReactDOMFeatureFlags.useFiber) {
@@ -278,9 +278,12 @@ describe('ReactElement', () => {
it('merges an additional argument onto the children prop', () => {
spyOn(console, 'error');
var a = 1;
var element = React.createFactory(ComponentClass)({
children: 'text',
}, a);
var element = React.createFactory(ComponentClass)(
{
children: 'text',
},
a,
);
expect(element.props.children).toBe(a);
expectDev(console.error.calls.count()).toBe(0);
});
@@ -296,9 +299,12 @@ describe('ReactElement', () => {
it('overrides children if null is provided as an argument', () => {
spyOn(console, 'error');
var element = React.createFactory(ComponentClass)({
children: 'text',
}, null);
var element = React.createFactory(ComponentClass)(
{
children: 'text',
},
null,
);
expect(element.props.children).toBe(null);
expectDev(console.error.calls.count()).toBe(0);
});
@@ -346,10 +352,8 @@ describe('ReactElement', () => {
},
});
expect(React.isValidElement(React.createElement('div')))
.toEqual(true);
expect(React.isValidElement(React.createElement(Component)))
.toEqual(true);
expect(React.isValidElement(React.createElement('div'))).toEqual(true);
expect(React.isValidElement(React.createElement(Component))).toEqual(true);
expect(React.isValidElement(null)).toEqual(false);
expect(React.isValidElement(true)).toEqual(false);
@@ -357,7 +361,7 @@ describe('ReactElement', () => {
expect(React.isValidElement('string')).toEqual(false);
expect(React.isValidElement(React.DOM.div)).toEqual(false);
expect(React.isValidElement(Component)).toEqual(false);
expect(React.isValidElement({ type: 'div', props: {} })).toEqual(false);
expect(React.isValidElement({type: 'div', props: {}})).toEqual(false);
var jsonElement = JSON.stringify(React.createElement('div'));
expect(React.isValidElement(JSON.parse(jsonElement))).toBe(true);
@@ -401,7 +405,7 @@ describe('ReactElement', () => {
var container = document.createElement('div');
var instance = ReactDOM.render(
React.createElement(Component, {fruit: 'mango'}),
container
container,
);
expect(instance.props.fruit).toBe('mango');
@@ -422,12 +426,12 @@ describe('ReactElement', () => {
});
var instance = ReactTestUtils.renderIntoDocument(
React.createElement(Component)
React.createElement(Component),
);
expect(instance.props.prop).toBe('testKey');
var inst2 = ReactTestUtils.renderIntoDocument(
React.createElement(Component, {prop: null})
React.createElement(Component, {prop: null}),
);
expect(inst2.props.prop).toBe(null);
});
@@ -510,10 +514,8 @@ describe('ReactElement', () => {
},
});
expect(React.isValidElement(React.createElement('div')))
.toEqual(true);
expect(React.isValidElement(React.createElement(Component)))
.toEqual(true);
expect(React.isValidElement(React.createElement('div'))).toEqual(true);
expect(React.isValidElement(React.createElement(Component))).toEqual(true);
expect(React.isValidElement(null)).toEqual(false);
expect(React.isValidElement(true)).toEqual(false);
@@ -521,12 +523,11 @@ describe('ReactElement', () => {
expect(React.isValidElement('string')).toEqual(false);
expect(React.isValidElement(React.DOM.div)).toEqual(false);
expect(React.isValidElement(Component)).toEqual(false);
expect(React.isValidElement({ type: 'div', props: {} })).toEqual(false);
expect(React.isValidElement({type: 'div', props: {}})).toEqual(false);
var jsonElement = JSON.stringify(React.createElement('div'));
expect(React.isValidElement(JSON.parse(jsonElement))).toBe(false);
});
});
describe('comparing jsx vs .createFactory() vs .createElement()', () => {
@@ -540,7 +541,6 @@ describe('comparing jsx vs .createFactory() vs .createElement()', () => {
Child = jest.genMockFromModule('ReactElementTestChild');
});
describe('when using jsx only', () => {
var Parent, instance;
beforeEach(() => {
@@ -557,7 +557,10 @@ describe('comparing jsx vs .createFactory() vs .createElement()', () => {
});
it('should scry children but cannot', () => {
var children = ReactTestUtils.scryRenderedComponentsWithType(instance, Child);
var children = ReactTestUtils.scryRenderedComponentsWithType(
instance,
Child,
);
expect(children.length).toBe(1);
});
@@ -566,7 +569,10 @@ describe('comparing jsx vs .createFactory() vs .createElement()', () => {
});
it('can capture Child instantiation calls', () => {
expect(Child.mock.calls[0][0]).toEqual({ foo: 'foo value', children: 'children value' });
expect(Child.mock.calls[0][0]).toEqual({
foo: 'foo value',
children: 'children value',
});
});
});
@@ -576,7 +582,10 @@ describe('comparing jsx vs .createFactory() vs .createElement()', () => {
var childFactory = React.createFactory(Child);
var Parent = React.createClass({
render: function() {
return React.DOM.div({}, childFactory({ ref: 'child', foo: 'foo value' }, 'children value'));
return React.DOM.div(
{},
childFactory({ref: 'child', foo: 'foo value'}, 'children value'),
);
},
});
factory = React.createFactory(Parent);
@@ -584,7 +593,10 @@ describe('comparing jsx vs .createFactory() vs .createElement()', () => {
});
it('can properly scry children', () => {
var children = ReactTestUtils.scryRenderedComponentsWithType(instance, Child);
var children = ReactTestUtils.scryRenderedComponentsWithType(
instance,
Child,
);
expect(children.length).toBe(1);
});
@@ -593,7 +605,10 @@ describe('comparing jsx vs .createFactory() vs .createElement()', () => {
});
it('can capture Child instantiation calls', () => {
expect(Child.mock.calls[0][0]).toEqual({ foo: 'foo value', children: 'children value' });
expect(Child.mock.calls[0][0]).toEqual({
foo: 'foo value',
children: 'children value',
});
});
});
@@ -602,7 +617,14 @@ describe('comparing jsx vs .createFactory() vs .createElement()', () => {
beforeEach(() => {
var Parent = React.createClass({
render: function() {
return React.DOM.div({}, React.createElement(Child, { ref: 'child', foo: 'foo value' }, 'children value'));
return React.DOM.div(
{},
React.createElement(
Child,
{ref: 'child', foo: 'foo value'},
'children value',
),
);
},
});
factory = React.createFactory(Parent);
@@ -610,7 +632,10 @@ describe('comparing jsx vs .createFactory() vs .createElement()', () => {
});
it('should scry children but cannot', () => {
var children = ReactTestUtils.scryRenderedComponentsWithType(instance, Child);
var children = ReactTestUtils.scryRenderedComponentsWithType(
instance,
Child,
);
expect(children.length).toBe(1);
});
@@ -619,8 +644,10 @@ describe('comparing jsx vs .createFactory() vs .createElement()', () => {
});
it('can capture Child instantiation calls', () => {
expect(Child.mock.calls[0][0]).toEqual({ foo: 'foo value', children: 'children value' });
expect(Child.mock.calls[0][0]).toEqual({
foo: 'foo value',
children: 'children value',
});
});
});
});
@@ -42,7 +42,7 @@ describe('ReactElementClone', () => {
render: function() {
return (
<div className="parent">
{React.cloneElement(this.props.child, { className: 'xyz' })}
{React.cloneElement(this.props.child, {className: 'xyz'})}
</div>
);
},
@@ -66,7 +66,7 @@ describe('ReactElementClone', () => {
render: function() {
return (
<div className="parent">
{React.cloneElement(this.props.child, { className: 'xyz' })}
{React.cloneElement(this.props.child, {className: 'xyz'})}
</div>
);
},
@@ -91,7 +91,7 @@ describe('ReactElementClone', () => {
render: function() {
return (
<div>
{React.cloneElement(this.props.child, { className: 'xyz' })}
{React.cloneElement(this.props.child, {className: 'xyz'})}
</div>
);
},
@@ -120,7 +120,7 @@ describe('ReactElementClone', () => {
});
ReactTestUtils.renderIntoDocument(
React.cloneElement(<Component />, {children: 'xyz'})
React.cloneElement(<Component />, {children: 'xyz'}),
);
});
@@ -133,7 +133,7 @@ describe('ReactElementClone', () => {
});
ReactTestUtils.renderIntoDocument(
React.cloneElement(<Component>xyz</Component>, {})
React.cloneElement(<Component>xyz</Component>, {}),
);
});
@@ -146,34 +146,41 @@ describe('ReactElementClone', () => {
var clone = React.cloneElement(
<Component>xyz</Component>,
{ children: <Component /> },
<div />,
<span />
);
expect(clone.props.children).toEqual([
{children: <Component />},
<div />,
<span />,
]);
);
expect(clone.props.children).toEqual([<div />, <span />]);
});
it('should override children if undefined is provided as an argument', () => {
var element = React.createElement(ComponentClass, {
children: 'text',
}, undefined);
var element = React.createElement(
ComponentClass,
{
children: 'text',
},
undefined,
);
expect(element.props.children).toBe(undefined);
var element2 = React.cloneElement(React.createElement(ComponentClass, {
children: 'text',
}), {}, undefined);
var element2 = React.cloneElement(
React.createElement(ComponentClass, {
children: 'text',
}),
{},
undefined,
);
expect(element2.props.children).toBe(undefined);
});
it('should support keys and refs', () => {
var Parent = React.createClass({
render: function() {
var clone =
React.cloneElement(this.props.children, {key: 'xyz', ref: 'xyz'});
var clone = React.cloneElement(this.props.children, {
key: 'xyz',
ref: 'xyz',
});
expect(clone.key).toBe('xyz');
expect(clone.ref).toBe('xyz');
return <div>{clone}</div>;
@@ -218,7 +225,7 @@ describe('ReactElementClone', () => {
});
ReactTestUtils.renderIntoDocument(
React.cloneElement(<Component myprop="abc" />, {myprop: 'xyz'})
React.cloneElement(<Component myprop="abc" />, {myprop: 'xyz'}),
);
});
@@ -252,7 +259,7 @@ describe('ReactElementClone', () => {
expectDev(console.error.calls.count()).toBe(1);
expectDev(console.error.calls.argsFor(0)[0]).toContain(
'Each child in an array or iterator should have a unique "key" prop.'
'Each child in an array or iterator should have a unique "key" prop.',
);
});
@@ -297,21 +304,20 @@ describe('ReactElementClone', () => {
});
var GrandParent = React.createClass({
render: function() {
return React.createElement(
Parent,
{ child: React.createElement(Component, {color: 'red'}) }
);
return React.createElement(Parent, {
child: React.createElement(Component, {color: 'red'}),
});
},
});
ReactTestUtils.renderIntoDocument(React.createElement(GrandParent));
expectDev(console.error.calls.count()).toBe(1);
expectDev(console.error.calls.argsFor(0)[0]).toBe(
'Warning: Failed prop type: ' +
'Invalid prop `color` of type `number` supplied to `Component`, ' +
'expected `string`.\n' +
' in Component (created by GrandParent)\n' +
' in Parent (created by GrandParent)\n' +
' in GrandParent'
'Invalid prop `color` of type `number` supplied to `Component`, ' +
'expected `string`.\n' +
' in Component (created by GrandParent)\n' +
' in Parent (created by GrandParent)\n' +
' in GrandParent',
);
});
@@ -361,5 +367,4 @@ describe('ReactElementClone', () => {
expect(Object.isFrozen(element.props)).toBe(true);
expect(clone.props).toEqual({foo: 'ef'});
});
});
@@ -46,7 +46,7 @@ describe('ReactElementValidator', () => {
expectDev(console.error.calls.count()).toBe(1);
expectDev(console.error.calls.argsFor(0)[0]).toContain(
'Each child in an array or iterator should have a unique "key" prop.'
'Each child in an array or iterator should have a unique "key" prop.',
);
});
@@ -66,19 +66,17 @@ describe('ReactElementValidator', () => {
var ComponentWrapper = React.createClass({
displayName: 'ComponentWrapper',
render: function() {
return InnerComponent({childSet: [Component(), Component()] });
return InnerComponent({childSet: [Component(), Component()]});
},
});
ReactTestUtils.renderIntoDocument(
React.createElement(ComponentWrapper)
);
ReactTestUtils.renderIntoDocument(React.createElement(ComponentWrapper));
expectDev(console.error.calls.count()).toBe(1);
expectDev(console.error.calls.argsFor(0)[0]).toContain(
'Each child in an array or iterator should have a unique "key" prop.' +
'\n\nCheck the render method of `InnerClass`. ' +
'It was passed a child from ComponentWrapper. '
'\n\nCheck the render method of `InnerClass`. ' +
'It was passed a child from ComponentWrapper. ',
);
});
@@ -92,35 +90,29 @@ describe('ReactElementValidator', () => {
},
});
var divs = [
<div />,
<div />,
];
var divs = [<div />, <div />];
ReactTestUtils.renderIntoDocument(<Anonymous>{divs}</Anonymous>);
expectDev(console.error.calls.count()).toBe(1);
expectDev(normalizeCodeLocInfo(console.error.calls.argsFor(0)[0])).toBe(
'Warning: Each child in an array or iterator should have a unique ' +
'"key" prop. See https://fb.me/react-warning-keys for more information.\n' +
' in div (at **)'
'"key" prop. See https://fb.me/react-warning-keys for more information.\n' +
' in div (at **)',
);
});
it('warns for keys for arrays of elements with no owner info', () => {
spyOn(console, 'error');
var divs = [
<div />,
<div />,
];
var divs = [<div />, <div />];
ReactTestUtils.renderIntoDocument(<div>{divs}</div>);
expectDev(console.error.calls.count()).toBe(1);
expectDev(normalizeCodeLocInfo(console.error.calls.argsFor(0)[0])).toBe(
'Warning: Each child in an array or iterator should have a unique ' +
'"key" prop.\n\nCheck the top-level render call using <div>. See ' +
'https://fb.me/react-warning-keys for more information.\n' +
' in div (at **)'
'"key" prop.\n\nCheck the top-level render call using <div>. See ' +
'https://fb.me/react-warning-keys for more information.\n' +
' in div (at **)',
);
});
@@ -150,12 +142,12 @@ describe('ReactElementValidator', () => {
expectDev(console.error.calls.count()).toBe(1);
expectDev(normalizeCodeLocInfo(console.error.calls.argsFor(0)[0])).toBe(
'Warning: Each child in an array or iterator should have a unique ' +
'"key" prop.\n\nCheck the render method of `Component`. See ' +
'https://fb.me/react-warning-keys for more information.\n' +
' in div (at **)\n' +
' in Component (at **)\n' +
' in Parent (at **)\n' +
' in GrandParent (at **)'
'"key" prop.\n\nCheck the render method of `Component`. See ' +
'https://fb.me/react-warning-keys for more information.\n' +
' in div (at **)\n' +
' in Component (at **)\n' +
' in Parent (at **)\n' +
' in GrandParent (at **)',
);
});
@@ -177,7 +169,7 @@ describe('ReactElementValidator', () => {
<Wrapper>
<span />
<span />
</Wrapper>
</Wrapper>,
);
expectDev(console.error.calls.count()).toBe(0);
@@ -203,7 +195,7 @@ describe('ReactElementValidator', () => {
expectDev(console.error.calls.count()).toBe(1);
expectDev(console.error.calls.argsFor(0)[0]).toContain(
'Each child in an array or iterator should have a unique "key" prop.'
'Each child in an array or iterator should have a unique "key" prop.',
);
});
@@ -279,10 +271,10 @@ describe('ReactElementValidator', () => {
ReactTestUtils.renderIntoDocument(React.createElement(ParentComp));
expectDev(console.error.calls.argsFor(0)[0]).toBe(
'Warning: Failed prop type: ' +
'Invalid prop `color` of type `number` supplied to `MyComp`, ' +
'expected `string`.\n' +
' in MyComp (created by ParentComp)\n' +
' in ParentComp'
'Invalid prop `color` of type `number` supplied to `MyComp`, ' +
'expected `string`.\n' +
' in MyComp (created by ParentComp)\n' +
' in ParentComp',
);
});
@@ -297,35 +289,35 @@ describe('ReactElementValidator', () => {
expectDev(console.error.calls.count()).toBe(6);
expectDev(console.error.calls.argsFor(0)[0]).toBe(
'Warning: React.createElement: type is invalid -- expected a string ' +
'(for built-in components) or a class/function (for composite ' +
'components) but got: undefined. You likely forgot to export your ' +
'component from the file it\'s defined in.'
'(for built-in components) or a class/function (for composite ' +
'components) but got: undefined. You likely forgot to export your ' +
"component from the file it's defined in.",
);
expectDev(console.error.calls.argsFor(1)[0]).toBe(
'Warning: React.createElement: type is invalid -- expected a string ' +
'(for built-in components) or a class/function (for composite ' +
'components) but got: null.'
'(for built-in components) or a class/function (for composite ' +
'components) but got: null.',
);
expectDev(console.error.calls.argsFor(2)[0]).toBe(
'Warning: React.createElement: type is invalid -- expected a string ' +
'(for built-in components) or a class/function (for composite ' +
'components) but got: boolean.'
'(for built-in components) or a class/function (for composite ' +
'components) but got: boolean.',
);
expectDev(console.error.calls.argsFor(3)[0]).toBe(
'Warning: React.createElement: type is invalid -- expected a string ' +
'(for built-in components) or a class/function (for composite ' +
'components) but got: number.'
'(for built-in components) or a class/function (for composite ' +
'components) but got: number.',
);
expectDev(console.error.calls.argsFor(4)[0]).toBe(
'Warning: React.createElement: type is invalid -- expected a string ' +
'(for built-in components) or a class/function (for composite ' +
'components) but got: object.'
'(for built-in components) or a class/function (for composite ' +
'components) but got: object.',
);
expectDev(console.error.calls.argsFor(5)[0]).toBe(
'Warning: React.createElement: type is invalid -- expected a string ' +
'(for built-in components) or a class/function (for composite ' +
'components) but got: object. You likely forgot to export your ' +
'component from the file it\'s defined in.'
'(for built-in components) or a class/function (for composite ' +
'components) but got: object. You likely forgot to export your ' +
"component from the file it's defined in.",
);
React.createElement('div');
expectDev(console.error.calls.count()).toBe(6);
@@ -342,15 +334,15 @@ describe('ReactElementValidator', () => {
ReactTestUtils.renderIntoDocument(React.createElement(ParentComp));
}).toThrowError(
'Element type is invalid: expected a string (for built-in components) ' +
'or a class/function (for composite components) but got: null.\n\nCheck ' +
'the render method of `ParentComp`.'
'or a class/function (for composite components) but got: null.\n\nCheck ' +
'the render method of `ParentComp`.',
);
expectDev(console.error.calls.count()).toBe(1);
expectDev(console.error.calls.argsFor(0)[0]).toBe(
'Warning: React.createElement: type is invalid -- expected a string ' +
'(for built-in components) or a class/function (for composite ' +
'components) but got: null.\n\nCheck the render method of `ParentComp`.' +
'\n in ParentComp'
'(for built-in components) or a class/function (for composite ' +
'components) but got: null.\n\nCheck the render method of `ParentComp`.' +
'\n in ParentComp',
);
});
@@ -372,8 +364,8 @@ describe('ReactElementValidator', () => {
expectDev(console.error.calls.count()).toBe(1);
expectDev(console.error.calls.argsFor(0)[0]).toBe(
'Warning: Failed prop type: The prop `prop` is marked as required in ' +
'`Component`, but its value is `null`.\n' +
' in Component'
'`Component`, but its value is `null`.\n' +
' in Component',
);
});
@@ -391,14 +383,14 @@ describe('ReactElementValidator', () => {
});
ReactTestUtils.renderIntoDocument(
React.createElement(Component, {prop:null})
React.createElement(Component, {prop: null}),
);
expectDev(console.error.calls.count()).toBe(1);
expectDev(console.error.calls.argsFor(0)[0]).toBe(
'Warning: Failed prop type: The prop `prop` is marked as required in ' +
'`Component`, but its value is `null`.\n' +
' in Component'
'`Component`, but its value is `null`.\n' +
' in Component',
);
});
@@ -414,30 +406,28 @@ describe('ReactElementValidator', () => {
},
});
ReactTestUtils.renderIntoDocument(React.createElement(Component));
ReactTestUtils.renderIntoDocument(
React.createElement(Component)
);
ReactTestUtils.renderIntoDocument(
React.createElement(Component, {prop: 42})
React.createElement(Component, {prop: 42}),
);
expectDev(console.error.calls.count()).toBe(2);
expectDev(console.error.calls.argsFor(0)[0]).toBe(
'Warning: Failed prop type: ' +
'The prop `prop` is marked as required in `Component`, but its value ' +
'is `undefined`.\n' +
' in Component'
'The prop `prop` is marked as required in `Component`, but its value ' +
'is `undefined`.\n' +
' in Component',
);
expectDev(console.error.calls.argsFor(1)[0]).toBe(
'Warning: Failed prop type: ' +
'Invalid prop `prop` of type `number` supplied to ' +
'`Component`, expected `string`.\n' +
' in Component'
'Invalid prop `prop` of type `number` supplied to ' +
'`Component`, expected `string`.\n' +
' in Component',
);
ReactTestUtils.renderIntoDocument(
React.createElement(Component, {prop: 'string'})
React.createElement(Component, {prop: 'string'}),
);
// Should not error for strings
@@ -457,16 +447,16 @@ describe('ReactElementValidator', () => {
});
ReactTestUtils.renderIntoDocument(
React.createElement(Component, {myProp: {value: 'hi'}})
React.createElement(Component, {myProp: {value: 'hi'}}),
);
expectDev(console.error.calls.count()).toBe(1);
expectDev(console.error.calls.argsFor(0)[0]).toBe(
'Warning: Component: type specification of prop `myProp` is invalid; ' +
'the type checker function must return `null` or an `Error` but ' +
'returned a function. You may have forgotten to pass an argument to ' +
'the type checker creator (arrayOf, instanceOf, objectOf, oneOf, ' +
'oneOfType, and shape all require an argument).'
'the type checker function must return `null` or an `Error` but ' +
'returned a function. You may have forgotten to pass an argument to ' +
'the type checker creator (arrayOf, instanceOf, objectOf, oneOf, ' +
'oneOfType, and shape all require an argument).',
);
});
@@ -482,7 +472,7 @@ describe('ReactElementValidator', () => {
expectDev(console.error.calls.count()).toBe(1);
expectDev(console.error.calls.argsFor(0)[0]).toBe(
'Warning: Factory.type is deprecated. Access the class directly before ' +
'passing it to createFactory.'
'passing it to createFactory.',
);
// Warn once, not again
expect(TestFactory.type).toBe(TestComponent);
@@ -531,7 +521,7 @@ describe('ReactElementValidator', () => {
// shouldn't blow up either.
var child = {
$$typeof: (<div />).$$typeof,
$$typeof: <div />.$$typeof,
type: 'span',
key: null,
ref: null,
@@ -549,10 +539,9 @@ describe('ReactElementValidator', () => {
expectDev(console.error.calls.count()).toBe(1);
expectDev(normalizeCodeLocInfo(console.error.calls.argsFor(0)[0])).toBe(
'Warning: React.createElement: type is invalid -- expected a string ' +
'(for built-in components) or a class/function (for composite ' +
'components) but got: undefined. You likely forgot to export your ' +
'component from the file it\'s defined in.\n\nCheck your code at **.'
'(for built-in components) or a class/function (for composite ' +
'components) but got: undefined. You likely forgot to export your ' +
"component from the file it's defined in.\n\nCheck your code at **.",
);
});
});
+40 -43
View File
@@ -95,7 +95,7 @@ if (__DEV__) {
var productionTypeChecker = function() {
invariant(
false,
'React.PropTypes type checking code is stripped in production.'
'React.PropTypes type checking code is stripped in production.',
);
};
productionTypeChecker.isRequired = productionTypeChecker;
@@ -122,7 +122,6 @@ if (__DEV__) {
};
}
/**
* inlined Object.is polyfill to avoid requiring consumers ship their own
* https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is
@@ -130,7 +129,8 @@ if (__DEV__) {
/*eslint-disable no-self-compare*/
function is(x, y) {
// SameValue algorithm
if (x === y) { // Steps 1-5, 7-10
if (x === y) {
// Steps 1-5, 7-10
// Steps 6.b-6.e: +0 != -0
return x !== 0 || 1 / x === 1 / y;
} else {
@@ -165,27 +165,24 @@ function createChainableTypeChecker(validate) {
componentName,
location,
propFullName,
secret
secret,
) {
componentName = componentName || ANONYMOUS;
propFullName = propFullName || propName;
if (__DEV__) {
if (
secret !== ReactPropTypesSecret &&
typeof console !== 'undefined'
) {
if (secret !== ReactPropTypesSecret && typeof console !== 'undefined') {
var cacheKey = `${componentName}:${propName}`;
if (!manualPropTypeCallCache[cacheKey]) {
warning(
false,
'You are manually calling a React.PropTypes validation ' +
'function for the `%s` prop on `%s`. This is deprecated ' +
'and will not work in production with the next major version. ' +
'You may be seeing this warning due to a third-party PropTypes ' +
'library. See https://fb.me/react-warning-dont-call-proptypes ' +
'for details.',
'function for the `%s` prop on `%s`. This is deprecated ' +
'and will not work in production with the next major version. ' +
'You may be seeing this warning due to a third-party PropTypes ' +
'library. See https://fb.me/react-warning-dont-call-proptypes ' +
'for details.',
propFullName,
componentName
componentName,
);
manualPropTypeCallCache[cacheKey] = true;
}
@@ -196,23 +193,17 @@ function createChainableTypeChecker(validate) {
if (props[propName] === null) {
return new PropTypeError(
`The ${location} \`${propFullName}\` is marked as required ` +
`in \`${componentName}\`, but its value is \`null\`.`
`in \`${componentName}\`, but its value is \`null\`.`,
);
}
return new PropTypeError(
`The ${location} \`${propFullName}\` is marked as required in ` +
`\`${componentName}\`, but its value is \`undefined\`.`
`\`${componentName}\`, but its value is \`undefined\`.`,
);
}
return null;
} else {
return validate(
props,
propName,
componentName,
location,
propFullName,
);
return validate(props, propName, componentName, location, propFullName);
}
}
@@ -229,7 +220,7 @@ function createPrimitiveTypeChecker(expectedType) {
componentName,
location,
propFullName,
secret
secret,
) {
var propValue = props[propName];
var propType = getPropType(propValue);
@@ -241,8 +232,8 @@ function createPrimitiveTypeChecker(expectedType) {
return new PropTypeError(
`Invalid ${location} \`${propFullName}\` of type ` +
`\`${preciseType}\` supplied to \`${componentName}\`, expected ` +
`\`${expectedType}\`.`
`\`${preciseType}\` supplied to \`${componentName}\`, expected ` +
`\`${expectedType}\`.`,
);
}
return null;
@@ -258,7 +249,7 @@ function createArrayOfTypeChecker(typeChecker) {
function validate(props, propName, componentName, location, propFullName) {
if (typeof typeChecker !== 'function') {
return new PropTypeError(
`Property \`${propFullName}\` of component \`${componentName}\` has invalid PropType notation inside arrayOf.`
`Property \`${propFullName}\` of component \`${componentName}\` has invalid PropType notation inside arrayOf.`,
);
}
var propValue = props[propName];
@@ -266,7 +257,7 @@ function createArrayOfTypeChecker(typeChecker) {
var propType = getPropType(propValue);
return new PropTypeError(
`Invalid ${location} \`${propFullName}\` of type ` +
`\`${propType}\` supplied to \`${componentName}\`, expected an array.`
`\`${propType}\` supplied to \`${componentName}\`, expected an array.`,
);
}
for (var i = 0; i < propValue.length; i++) {
@@ -276,7 +267,7 @@ function createArrayOfTypeChecker(typeChecker) {
componentName,
location,
`${propFullName}[${i}]`,
ReactPropTypesSecret
ReactPropTypesSecret,
);
if (error instanceof Error) {
return error;
@@ -294,7 +285,7 @@ function createElementTypeChecker() {
var propType = getPropType(propValue);
return new PropTypeError(
`Invalid ${location} \`${propFullName}\` of type ` +
`\`${propType}\` supplied to \`${componentName}\`, expected a single ReactElement.`
`\`${propType}\` supplied to \`${componentName}\`, expected a single ReactElement.`,
);
}
return null;
@@ -309,8 +300,8 @@ function createInstanceTypeChecker(expectedClass) {
var actualClassName = getClassName(props[propName]);
return new PropTypeError(
`Invalid ${location} \`${propFullName}\` of type ` +
`\`${actualClassName}\` supplied to \`${componentName}\`, expected ` +
`instance of \`${expectedClassName}\`.`
`\`${actualClassName}\` supplied to \`${componentName}\`, expected ` +
`instance of \`${expectedClassName}\`.`,
);
}
return null;
@@ -320,7 +311,10 @@ function createInstanceTypeChecker(expectedClass) {
function createEnumTypeChecker(expectedValues) {
if (!Array.isArray(expectedValues)) {
warning(false, 'Invalid argument supplied to oneOf, expected an instance of array.');
warning(
false,
'Invalid argument supplied to oneOf, expected an instance of array.',
);
return emptyFunction.thatReturnsNull;
}
@@ -335,7 +329,7 @@ function createEnumTypeChecker(expectedValues) {
var valuesString = JSON.stringify(expectedValues);
return new PropTypeError(
`Invalid ${location} \`${propFullName}\` of value \`${propValue}\` ` +
`supplied to \`${componentName}\`, expected one of ${valuesString}.`
`supplied to \`${componentName}\`, expected one of ${valuesString}.`,
);
}
return createChainableTypeChecker(validate);
@@ -345,7 +339,7 @@ function createObjectOfTypeChecker(typeChecker) {
function validate(props, propName, componentName, location, propFullName) {
if (typeof typeChecker !== 'function') {
return new PropTypeError(
`Property \`${propFullName}\` of component \`${componentName}\` has invalid PropType notation inside objectOf.`
`Property \`${propFullName}\` of component \`${componentName}\` has invalid PropType notation inside objectOf.`,
);
}
var propValue = props[propName];
@@ -353,7 +347,7 @@ function createObjectOfTypeChecker(typeChecker) {
if (propType !== 'object') {
return new PropTypeError(
`Invalid ${location} \`${propFullName}\` of type ` +
`\`${propType}\` supplied to \`${componentName}\`, expected an object.`
`\`${propType}\` supplied to \`${componentName}\`, expected an object.`,
);
}
for (var key in propValue) {
@@ -364,7 +358,7 @@ function createObjectOfTypeChecker(typeChecker) {
componentName,
location,
`${propFullName}.${key}`,
ReactPropTypesSecret
ReactPropTypesSecret,
);
if (error instanceof Error) {
return error;
@@ -378,7 +372,10 @@ function createObjectOfTypeChecker(typeChecker) {
function createUnionTypeChecker(arrayOfTypeCheckers) {
if (!Array.isArray(arrayOfTypeCheckers)) {
warning(false, 'Invalid argument supplied to oneOfType, expected an instance of array.');
warning(
false,
'Invalid argument supplied to oneOfType, expected an instance of array.',
);
return emptyFunction.thatReturnsNull;
}
@@ -392,7 +389,7 @@ function createUnionTypeChecker(arrayOfTypeCheckers) {
componentName,
location,
propFullName,
ReactPropTypesSecret
ReactPropTypesSecret,
) == null
) {
return null;
@@ -401,7 +398,7 @@ function createUnionTypeChecker(arrayOfTypeCheckers) {
return new PropTypeError(
`Invalid ${location} \`${propFullName}\` supplied to ` +
`\`${componentName}\`.`
`\`${componentName}\`.`,
);
}
return createChainableTypeChecker(validate);
@@ -412,7 +409,7 @@ function createNodeChecker() {
if (!isNode(props[propName])) {
return new PropTypeError(
`Invalid ${location} \`${propFullName}\` supplied to ` +
`\`${componentName}\`, expected a ReactNode.`
`\`${componentName}\`, expected a ReactNode.`,
);
}
return null;
@@ -427,7 +424,7 @@ function createShapeTypeChecker(shapeTypes) {
if (propType !== 'object') {
return new PropTypeError(
`Invalid ${location} \`${propFullName}\` of type \`${propType}\` ` +
`supplied to \`${componentName}\`, expected \`object\`.`
`supplied to \`${componentName}\`, expected \`object\`.`,
);
}
for (var key in shapeTypes) {
@@ -441,7 +438,7 @@ function createShapeTypeChecker(shapeTypes) {
componentName,
location,
`${propFullName}.${key}`,
ReactPropTypesSecret
ReactPropTypesSecret,
);
if (error) {
return error;
@@ -62,14 +62,22 @@ function typeCheckFailRequiredValues(declaration) {
var unspecifiedMsg = 'The prop `testProp` is marked as required in ' +
'`testComponent`, but its value is \`undefined\`.';
var propTypes = { testProp: declaration };
var propTypes = {testProp: declaration};
// Required prop is null
var message1 = getPropTypeWarningMessage(propTypes, { testProp: null }, 'testComponent');
var message1 = getPropTypeWarningMessage(
propTypes,
{testProp: null},
'testComponent',
);
expect(message1).toContain(specifiedButIsNullMsg);
// Required prop is undefined
var message2 = getPropTypeWarningMessage(propTypes, { testProp: undefined }, 'testComponent');
var message2 = getPropTypeWarningMessage(
propTypes,
{testProp: undefined},
'testComponent',
);
expect(message2).toContain(unspecifiedMsg);
// Required prop is not a member of props object
@@ -93,16 +101,11 @@ function expectWarningInDevelopment(declaration, value) {
var propName = 'testProp' + Math.random().toString();
var componentName = 'testComponent' + Math.random().toString();
for (var i = 0; i < 3; i++) {
declaration(
props,
propName,
componentName,
'prop'
);
declaration(props, propName, componentName, 'prop');
}
expect(console.error.calls.count()).toBe(1);
expect(console.error.calls.argsFor(0)[0]).toContain(
'You are manually calling a React.PropTypes validation '
'You are manually calling a React.PropTypes validation ',
);
console.error.calls.reset();
}
@@ -124,8 +127,14 @@ describe('ReactPropTypes', () => {
return new Error('some error');
},
};
const props = { foo: 'foo' };
const returnValue = checkPropTypes(propTypes, props, 'prop', 'testComponent', null);
const props = {foo: 'foo'};
const returnValue = checkPropTypes(
propTypes,
props,
'prop',
'testComponent',
null,
);
expect(console.error.calls.argsFor(0)[0]).toContain('some error');
expect(returnValue).toBe(undefined);
});
@@ -137,8 +146,14 @@ describe('ReactPropTypes', () => {
throw new Error('some error');
},
};
const props = { foo: 'foo' };
const returnValue = checkPropTypes(propTypes, props, 'prop', 'testComponent', null);
const props = {foo: 'foo'};
const returnValue = checkPropTypes(
propTypes,
props,
'prop',
'testComponent',
null,
);
expect(console.error.calls.argsFor(0)[0]).toContain('some error');
expect(returnValue).toBe(undefined);
});
@@ -150,31 +165,31 @@ describe('ReactPropTypes', () => {
PropTypes.string,
[],
'Invalid prop `testProp` of type `array` supplied to ' +
'`testComponent`, expected `string`.'
'`testComponent`, expected `string`.',
);
typeCheckFail(
PropTypes.string,
false,
'Invalid prop `testProp` of type `boolean` supplied to ' +
'`testComponent`, expected `string`.'
'`testComponent`, expected `string`.',
);
typeCheckFail(
PropTypes.string,
0,
'Invalid prop `testProp` of type `number` supplied to ' +
'`testComponent`, expected `string`.'
'`testComponent`, expected `string`.',
);
typeCheckFail(
PropTypes.string,
{},
'Invalid prop `testProp` of type `object` supplied to ' +
'`testComponent`, expected `string`.'
'`testComponent`, expected `string`.',
);
typeCheckFail(
PropTypes.string,
Symbol(),
'Invalid prop `testProp` of type `symbol` supplied to ' +
'`testComponent`, expected `string`.'
'`testComponent`, expected `string`.',
);
});
@@ -183,13 +198,13 @@ describe('ReactPropTypes', () => {
PropTypes.string,
new Date(),
'Invalid prop `testProp` of type `date` supplied to ' +
'`testComponent`, expected `string`.'
'`testComponent`, expected `string`.',
);
typeCheckFail(
PropTypes.string,
/please/,
'Invalid prop `testProp` of type `regexp` supplied to ' +
'`testComponent`, expected `string`.'
'`testComponent`, expected `string`.',
);
});
@@ -289,9 +304,9 @@ describe('ReactPropTypes', () => {
describe('ArrayOf Type', () => {
it('should fail for invalid argument', () => {
typeCheckFail(
PropTypes.arrayOf({ foo: PropTypes.string }),
{ foo: 'bar' },
'Property `testProp` of component `testComponent` has invalid PropType notation inside arrayOf.'
PropTypes.arrayOf({foo: PropTypes.string}),
{foo: 'bar'},
'Property `testProp` of component `testComponent` has invalid PropType notation inside arrayOf.',
);
});
@@ -305,14 +320,14 @@ describe('ReactPropTypes', () => {
it('should support arrayOf with complex types', () => {
typeCheckPass(
PropTypes.arrayOf(PropTypes.shape({a: PropTypes.number.isRequired})),
[{a: 1}, {a: 2}]
[{a: 1}, {a: 2}],
);
function Thing() {}
typeCheckPass(
PropTypes.arrayOf(PropTypes.instanceOf(Thing)),
[new Thing(), new Thing()]
);
typeCheckPass(PropTypes.arrayOf(PropTypes.instanceOf(Thing)), [
new Thing(),
new Thing(),
]);
});
it('should warn with invalid items in the array', () => {
@@ -320,7 +335,7 @@ describe('ReactPropTypes', () => {
PropTypes.arrayOf(PropTypes.number),
[1, 2, 'b'],
'Invalid prop `testProp[2]` of type `string` supplied to ' +
'`testComponent`, expected `number`.'
'`testComponent`, expected `number`.',
);
});
@@ -332,7 +347,9 @@ describe('ReactPropTypes', () => {
PropTypes.arrayOf(PropTypes.instanceOf(Thing)),
[new Thing(), 'xyz'],
'Invalid prop `testProp[1]` of type `String` supplied to ' +
'`testComponent`, expected instance of `' + name + '`.'
'`testComponent`, expected instance of `' +
name +
'`.',
);
});
@@ -341,19 +358,19 @@ describe('ReactPropTypes', () => {
PropTypes.arrayOf(PropTypes.number),
{'0': 'maybe-array', length: 1},
'Invalid prop `testProp` of type `object` supplied to ' +
'`testComponent`, expected an array.'
'`testComponent`, expected an array.',
);
typeCheckFail(
PropTypes.arrayOf(PropTypes.number),
123,
'Invalid prop `testProp` of type `number` supplied to ' +
'`testComponent`, expected an array.'
'`testComponent`, expected an array.',
);
typeCheckFail(
PropTypes.arrayOf(PropTypes.number),
'string',
'Invalid prop `testProp` of type `string` supplied to ' +
'`testComponent`, expected an array.'
'`testComponent`, expected an array.',
);
});
@@ -368,26 +385,32 @@ describe('ReactPropTypes', () => {
it('should warn for missing required values', () => {
typeCheckFailRequiredValues(
PropTypes.arrayOf(PropTypes.number).isRequired
PropTypes.arrayOf(PropTypes.number).isRequired,
);
});
it('should warn if called manually in development', () => {
spyOn(console, 'error');
expectWarningInDevelopment(PropTypes.arrayOf({foo: PropTypes.string}), {
foo: 'bar',
});
expectWarningInDevelopment(PropTypes.arrayOf(PropTypes.number), [
1,
2,
'b',
]);
expectWarningInDevelopment(PropTypes.arrayOf(PropTypes.number), {
'0': 'maybe-array',
length: 1,
});
expectWarningInDevelopment(
PropTypes.arrayOf({ foo: PropTypes.string }),
{ foo: 'bar' }
PropTypes.arrayOf(PropTypes.number).isRequired,
null,
);
expectWarningInDevelopment(
PropTypes.arrayOf(PropTypes.number),
[1, 2, 'b']
PropTypes.arrayOf(PropTypes.number).isRequired,
undefined,
);
expectWarningInDevelopment(
PropTypes.arrayOf(PropTypes.number),
{'0': 'maybe-array', length: 1}
);
expectWarningInDevelopment(PropTypes.arrayOf(PropTypes.number).isRequired, null);
expectWarningInDevelopment(PropTypes.arrayOf(PropTypes.number).isRequired, undefined);
});
});
@@ -413,25 +436,25 @@ describe('ReactPropTypes', () => {
PropTypes.element,
[<div />, <div />],
'Invalid prop `testProp` of type `array` supplied to `testComponent`, ' +
'expected a single ReactElement.'
'expected a single ReactElement.',
);
typeCheckFail(
PropTypes.element,
123,
'Invalid prop `testProp` of type `number` supplied to `testComponent`, ' +
'expected a single ReactElement.'
'expected a single ReactElement.',
);
typeCheckFail(
PropTypes.element,
'foo',
'Invalid prop `testProp` of type `string` supplied to `testComponent`, ' +
'expected a single ReactElement.'
'expected a single ReactElement.',
);
typeCheckFail(
PropTypes.element,
false,
'Invalid prop `testProp` of type `boolean` supplied to `testComponent`, ' +
'expected a single ReactElement.'
'expected a single ReactElement.',
);
});
@@ -472,7 +495,6 @@ describe('ReactPropTypes', () => {
expectWarningInDevelopment(PropTypes.element.isRequired, null);
expectWarningInDevelopment(PropTypes.element.isRequired, undefined);
});
});
describe('Instance Types', () => {
@@ -487,43 +509,57 @@ describe('ReactPropTypes', () => {
PropTypes.instanceOf(Person),
false,
'Invalid prop `testProp` of type `Boolean` supplied to ' +
'`testComponent`, expected instance of `' + personName + '`.'
'`testComponent`, expected instance of `' +
personName +
'`.',
);
typeCheckFail(
PropTypes.instanceOf(Person),
{},
'Invalid prop `testProp` of type `Object` supplied to ' +
'`testComponent`, expected instance of `' + personName + '`.'
'`testComponent`, expected instance of `' +
personName +
'`.',
);
typeCheckFail(
PropTypes.instanceOf(Person),
'',
'Invalid prop `testProp` of type `String` supplied to ' +
'`testComponent`, expected instance of `' + personName + '`.'
'`testComponent`, expected instance of `' +
personName +
'`.',
);
typeCheckFail(
PropTypes.instanceOf(Date),
{},
'Invalid prop `testProp` of type `Object` supplied to ' +
'`testComponent`, expected instance of `' + dateName + '`.'
'`testComponent`, expected instance of `' +
dateName +
'`.',
);
typeCheckFail(
PropTypes.instanceOf(RegExp),
{},
'Invalid prop `testProp` of type `Object` supplied to ' +
'`testComponent`, expected instance of `' + regExpName + '`.'
'`testComponent`, expected instance of `' +
regExpName +
'`.',
);
typeCheckFail(
PropTypes.instanceOf(Person),
new Cat(),
'Invalid prop `testProp` of type `Cat` supplied to ' +
'`testComponent`, expected instance of `' + personName + '`.'
'`testComponent`, expected instance of `' +
personName +
'`.',
);
typeCheckFail(
PropTypes.instanceOf(Person),
Object.create(null),
'Invalid prop `testProp` of type `<<anonymous>>` supplied to ' +
'`testComponent`, expected instance of `' + personName + '`.'
'`testComponent`, expected instance of `' +
personName +
'`.',
);
});
@@ -553,9 +589,11 @@ describe('ReactPropTypes', () => {
expectWarningInDevelopment(PropTypes.instanceOf(Date), {});
expectWarningInDevelopment(PropTypes.instanceOf(Date), new Date());
expectWarningInDevelopment(PropTypes.instanceOf(Date).isRequired, {});
expectWarningInDevelopment(PropTypes.instanceOf(Date).isRequired, new Date());
expectWarningInDevelopment(
PropTypes.instanceOf(Date).isRequired,
new Date(),
);
});
});
describe('React Component Types', () => {
@@ -594,18 +632,21 @@ describe('ReactPropTypes', () => {
// Object of renderable things
var frag = ReactFragment.create;
typeCheckPass(PropTypes.node, frag({
k0: 123,
k1: 'Some string',
k2: <div />,
k3: frag({
k30: <MyComponent />,
k31: frag({k310: <a />}),
k32: 'Another string',
typeCheckPass(
PropTypes.node,
frag({
k0: 123,
k1: 'Some string',
k2: <div />,
k3: frag({
k30: <MyComponent />,
k31: frag({k310: <a />}),
k32: 'Another string',
}),
k4: null,
k5: undefined,
}),
k4: null,
k5: undefined,
}));
);
expectDev(console.error.calls.count()).toBe(0);
});
@@ -632,7 +673,10 @@ describe('ReactPropTypes', () => {
return {
next: function() {
var done = ++i > 2;
return {value: done ? undefined : ['#' + i, <MyComponent />], done: done};
return {
value: done ? undefined : ['#' + i, <MyComponent />],
done: done,
};
},
};
},
@@ -663,45 +707,46 @@ describe('ReactPropTypes', () => {
expectWarningInDevelopment(PropTypes.node.isRequired, undefined);
expectWarningInDevelopment(PropTypes.node.isRequired, undefined);
});
});
describe('ObjectOf Type', () => {
it('should fail for invalid argument', () => {
typeCheckFail(
PropTypes.objectOf({ foo: PropTypes.string }),
{ foo: 'bar' },
'Property `testProp` of component `testComponent` has invalid PropType notation inside objectOf.'
PropTypes.objectOf({foo: PropTypes.string}),
{foo: 'bar'},
'Property `testProp` of component `testComponent` has invalid PropType notation inside objectOf.',
);
});
it('should support the objectOf propTypes', () => {
typeCheckPass(PropTypes.objectOf(PropTypes.number), {a: 1, b: 2, c: 3});
typeCheckPass(
PropTypes.objectOf(PropTypes.string),
{a: 'a', b: 'b', c: 'c'}
);
typeCheckPass(
PropTypes.objectOf(PropTypes.oneOf(['a', 'b'])),
{a: 'a', b: 'b'}
);
typeCheckPass(
PropTypes.objectOf(PropTypes.symbol),
{a: Symbol(), b: Symbol(), c: Symbol()}
);
typeCheckPass(PropTypes.objectOf(PropTypes.string), {
a: 'a',
b: 'b',
c: 'c',
});
typeCheckPass(PropTypes.objectOf(PropTypes.oneOf(['a', 'b'])), {
a: 'a',
b: 'b',
});
typeCheckPass(PropTypes.objectOf(PropTypes.symbol), {
a: Symbol(),
b: Symbol(),
c: Symbol(),
});
});
it('should support objectOf with complex types', () => {
typeCheckPass(
PropTypes.objectOf(PropTypes.shape({a: PropTypes.number.isRequired})),
{a: {a: 1}, b: {a: 2}}
{a: {a: 1}, b: {a: 2}},
);
function Thing() {}
typeCheckPass(
PropTypes.objectOf(PropTypes.instanceOf(Thing)),
{a: new Thing(), b: new Thing()}
);
typeCheckPass(PropTypes.objectOf(PropTypes.instanceOf(Thing)), {
a: new Thing(),
b: new Thing(),
});
});
it('should warn with invalid items in the object', () => {
@@ -709,7 +754,7 @@ describe('ReactPropTypes', () => {
PropTypes.objectOf(PropTypes.number),
{a: 1, b: 2, c: 'b'},
'Invalid prop `testProp.c` of type `string` supplied to `testComponent`, ' +
'expected `number`.'
'expected `number`.',
);
});
@@ -721,7 +766,9 @@ describe('ReactPropTypes', () => {
PropTypes.objectOf(PropTypes.instanceOf(Thing)),
{a: new Thing(), b: 'xyz'},
'Invalid prop `testProp.b` of type `String` supplied to ' +
'`testComponent`, expected instance of `' + name + '`.'
'`testComponent`, expected instance of `' +
name +
'`.',
);
});
@@ -730,25 +777,25 @@ describe('ReactPropTypes', () => {
PropTypes.objectOf(PropTypes.number),
[1, 2],
'Invalid prop `testProp` of type `array` supplied to ' +
'`testComponent`, expected an object.'
'`testComponent`, expected an object.',
);
typeCheckFail(
PropTypes.objectOf(PropTypes.number),
123,
'Invalid prop `testProp` of type `number` supplied to ' +
'`testComponent`, expected an object.'
'`testComponent`, expected an object.',
);
typeCheckFail(
PropTypes.objectOf(PropTypes.number),
'string',
'Invalid prop `testProp` of type `string` supplied to ' +
'`testComponent`, expected an object.'
'`testComponent`, expected an object.',
);
typeCheckFail(
PropTypes.objectOf(PropTypes.symbol),
Symbol(),
'Invalid prop `testProp` of type `symbol` supplied to ' +
'`testComponent`, expected an object.'
'`testComponent`, expected an object.',
);
});
@@ -763,23 +810,26 @@ describe('ReactPropTypes', () => {
it('should warn for missing required values', () => {
typeCheckFailRequiredValues(
PropTypes.objectOf(PropTypes.number).isRequired
PropTypes.objectOf(PropTypes.number).isRequired,
);
});
it('should warn if called manually in development', () => {
spyOn(console, 'error');
expectWarningInDevelopment(
PropTypes.objectOf({ foo: PropTypes.string }),
{ foo: 'bar' }
);
expectWarningInDevelopment(
PropTypes.objectOf(PropTypes.number),
{a: 1, b: 2, c: 'b'}
);
expectWarningInDevelopment(PropTypes.objectOf({foo: PropTypes.string}), {
foo: 'bar',
});
expectWarningInDevelopment(PropTypes.objectOf(PropTypes.number), {
a: 1,
b: 2,
c: 'b',
});
expectWarningInDevelopment(PropTypes.objectOf(PropTypes.number), [1, 2]);
expectWarningInDevelopment(PropTypes.objectOf(PropTypes.number), null);
expectWarningInDevelopment(PropTypes.objectOf(PropTypes.number), undefined);
expectWarningInDevelopment(
PropTypes.objectOf(PropTypes.number),
undefined,
);
});
});
@@ -790,8 +840,9 @@ describe('ReactPropTypes', () => {
PropTypes.oneOf('red', 'blue');
expectDev(console.error).toHaveBeenCalled();
expectDev(console.error.calls.argsFor(0)[0])
.toContain('Invalid argument supplied to oneOf, expected an instance of array.');
expectDev(console.error.calls.argsFor(0)[0]).toContain(
'Invalid argument supplied to oneOf, expected an instance of array.',
);
typeCheckPass(PropTypes.oneOf('red', 'blue'), 'red');
});
@@ -801,25 +852,25 @@ describe('ReactPropTypes', () => {
PropTypes.oneOf(['red', 'blue']),
true,
'Invalid prop `testProp` of value `true` supplied to ' +
'`testComponent`, expected one of ["red","blue"].'
'`testComponent`, expected one of ["red","blue"].',
);
typeCheckFail(
PropTypes.oneOf(['red', 'blue']),
[],
'Invalid prop `testProp` of value `` supplied to `testComponent`, ' +
'expected one of ["red","blue"].'
'expected one of ["red","blue"].',
);
typeCheckFail(
PropTypes.oneOf(['red', 'blue']),
'',
'Invalid prop `testProp` of value `` supplied to `testComponent`, ' +
'expected one of ["red","blue"].'
'expected one of ["red","blue"].',
);
typeCheckFail(
PropTypes.oneOf([0, 'false']),
false,
'Invalid prop `testProp` of value `false` supplied to ' +
'`testComponent`, expected one of [0,"false"].'
'`testComponent`, expected one of [0,"false"].',
);
});
@@ -853,8 +904,9 @@ describe('ReactPropTypes', () => {
PropTypes.oneOfType(PropTypes.string, PropTypes.number);
expectDev(console.error).toHaveBeenCalled();
expectDev(console.error.calls.argsFor(0)[0])
.toContain('Invalid argument supplied to oneOfType, expected an instance of array.');
expectDev(console.error.calls.argsFor(0)[0]).toContain(
'Invalid argument supplied to oneOfType, expected an instance of array.',
);
typeCheckPass(PropTypes.oneOf(PropTypes.string, PropTypes.number), []);
});
@@ -863,7 +915,7 @@ describe('ReactPropTypes', () => {
typeCheckFail(
PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
[],
'Invalid prop `testProp` supplied to `testComponent`.'
'Invalid prop `testProp` supplied to `testComponent`.',
);
var checker = PropTypes.oneOfType([
@@ -873,15 +925,12 @@ describe('ReactPropTypes', () => {
typeCheckFail(
checker,
{c: 1},
'Invalid prop `testProp` supplied to `testComponent`.'
'Invalid prop `testProp` supplied to `testComponent`.',
);
});
it('should not warn if one of the types are valid', () => {
var checker = PropTypes.oneOfType([
PropTypes.string,
PropTypes.number,
]);
var checker = PropTypes.oneOfType([PropTypes.string, PropTypes.number]);
typeCheckPass(checker, null);
typeCheckPass(checker, 'foo');
typeCheckPass(checker, 123);
@@ -896,16 +945,18 @@ describe('ReactPropTypes', () => {
it('should be implicitly optional and not warn without values', () => {
typeCheckPass(
PropTypes.oneOfType([PropTypes.string, PropTypes.number]), null
PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
null,
);
typeCheckPass(
PropTypes.oneOfType([PropTypes.string, PropTypes.number]), undefined
PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
undefined,
);
});
it('should warn for missing required values', () => {
typeCheckFailRequiredValues(
PropTypes.oneOfType([PropTypes.string, PropTypes.number]).isRequired
PropTypes.oneOfType([PropTypes.string, PropTypes.number]).isRequired,
);
});
@@ -913,18 +964,17 @@ describe('ReactPropTypes', () => {
spyOn(console, 'error');
expectWarningInDevelopment(
PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
[]
[],
);
expectWarningInDevelopment(
PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
null
null,
);
expectWarningInDevelopment(
PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
undefined
undefined,
);
});
});
describe('Shape Types', () => {
@@ -933,13 +983,13 @@ describe('ReactPropTypes', () => {
PropTypes.shape({}),
'some string',
'Invalid prop `testProp` of type `string` supplied to ' +
'`testComponent`, expected `object`.'
'`testComponent`, expected `object`.',
);
typeCheckFail(
PropTypes.shape({}),
['array'],
'Invalid prop `testProp` of type `array` supplied to ' +
'`testComponent`, expected `object`.'
'`testComponent`, expected `object`.',
);
});
@@ -966,7 +1016,7 @@ describe('ReactPropTypes', () => {
PropTypes.shape({key: PropTypes.number.isRequired}),
{},
'The prop `testProp.key` is marked as required in `testComponent`, ' +
'but its value is `undefined`.'
'but its value is `undefined`.',
);
});
@@ -978,44 +1028,49 @@ describe('ReactPropTypes', () => {
}),
{},
'The prop `testProp.key` is marked as required in `testComponent`, ' +
'but its value is `undefined`.'
'but its value is `undefined`.',
);
});
it('should warn for invalid key types', () => {
typeCheckFail(PropTypes.shape({key: PropTypes.number}),
typeCheckFail(
PropTypes.shape({key: PropTypes.number}),
{key: 'abc'},
'Invalid prop `testProp.key` of type `string` supplied to `testComponent`, ' +
'expected `number`.'
'expected `number`.',
);
});
it('should be implicitly optional and not warn without values', () => {
typeCheckPass(
PropTypes.shape(PropTypes.shape({key: PropTypes.number})), null
PropTypes.shape(PropTypes.shape({key: PropTypes.number})),
null,
);
typeCheckPass(
PropTypes.shape(PropTypes.shape({key: PropTypes.number})), undefined
PropTypes.shape(PropTypes.shape({key: PropTypes.number})),
undefined,
);
});
it('should warn for missing required values', () => {
typeCheckFailRequiredValues(
PropTypes.shape({key: PropTypes.number}).isRequired
PropTypes.shape({key: PropTypes.number}).isRequired,
);
});
it('should warn if called manually in development', () => {
spyOn(console, 'error');
expectWarningInDevelopment(PropTypes.shape({}), 'some string');
expectWarningInDevelopment(PropTypes.shape({ foo: PropTypes.number }), { foo: 42 });
expectWarningInDevelopment(PropTypes.shape({foo: PropTypes.number}), {
foo: 42,
});
expectWarningInDevelopment(
PropTypes.shape({key: PropTypes.number}).isRequired,
null
null,
);
expectWarningInDevelopment(
PropTypes.shape({key: PropTypes.number}).isRequired,
undefined
undefined,
);
expectWarningInDevelopment(PropTypes.element, <div />);
});
@@ -1027,13 +1082,13 @@ describe('ReactPropTypes', () => {
PropTypes.symbol,
'hello',
'Invalid prop `testProp` of type `string` supplied to ' +
'`testComponent`, expected `symbol`.'
'`testComponent`, expected `symbol`.',
);
typeCheckFail(
PropTypes.symbol,
function() { },
function() {},
'Invalid prop `testProp` of type `function` supplied to ' +
'`testComponent`, expected `symbol`.'
'`testComponent`, expected `symbol`.',
);
typeCheckFail(
PropTypes.symbol,
@@ -1041,7 +1096,7 @@ describe('ReactPropTypes', () => {
'@@toStringTag': 'Katana',
},
'Invalid prop `testProp` of type `object` supplied to ' +
'`testComponent`, expected `symbol`.'
'`testComponent`, expected `symbol`.',
);
});
@@ -1090,15 +1145,15 @@ describe('ReactPropTypes', () => {
expect(spy.calls.argsFor(0)[1]).toBe('num');
});
it('should have received the validator\'s return value', () => {
it("should have received the validator's return value", () => {
spyOn(console, 'error');
var spy = jasmine.createSpy().and.callFake(
function(props, propName, componentName) {
var spy = jasmine
.createSpy()
.and.callFake(function(props, propName, componentName) {
if (props[propName] !== 5) {
return new Error('num must be 5!');
}
}
);
});
Component = class extends React.Component {
static propTypes = {num: spy};
@@ -1111,33 +1166,31 @@ describe('ReactPropTypes', () => {
ReactDOM.render(<Component num={6} />, container);
expectDev(console.error.calls.count()).toBe(1);
expect(
console.error.calls.argsFor(0)[0].replace(/\(at .+?:\d+\)/g, '(at **)')
console.error.calls.argsFor(0)[0].replace(/\(at .+?:\d+\)/g, '(at **)'),
).toBe(
'Warning: Failed prop type: num must be 5!\n' +
' in Component (at **)'
' in Component (at **)',
);
});
it('should not warn if the validator returned null',
() => {
spyOn(console, 'error');
var spy = jasmine.createSpy().and.callFake(
function(props, propName, componentName) {
return null;
}
);
Component = class extends React.Component {
static propTypes = {num: spy};
it('should not warn if the validator returned null', () => {
spyOn(console, 'error');
var spy = jasmine
.createSpy()
.and.callFake(function(props, propName, componentName) {
return null;
});
Component = class extends React.Component {
static propTypes = {num: spy};
render() {
return <div />;
}
};
render() {
return <div />;
}
};
var container = document.createElement('div');
ReactDOM.render(<Component num={5} />, container);
expectDev(console.error.calls.count()).toBe(0);
}
);
var container = document.createElement('div');
ReactDOM.render(<Component num={5} />, container);
expectDev(console.error.calls.count()).toBe(0);
});
});
});
@@ -42,15 +42,8 @@ describe('ReactPropTypesProduction', function() {
function expectThrowsInProduction(declaration, value) {
var props = {testProp: value};
expect(() => {
declaration(
props,
'testProp',
'testComponent',
'prop'
);
}).toThrowError(
'Minified React error #144'
);
declaration(props, 'testProp', 'testComponent', 'prop');
}).toThrowError('Minified React error #144');
}
describe('Primitive Types', function() {
@@ -96,20 +89,26 @@ describe('ReactPropTypesProduction', function() {
describe('ArrayOf Type', function() {
it('should be a no-op', function() {
expectThrowsInProduction(PropTypes.arrayOf({foo: PropTypes.string}), {
foo: 'bar',
});
expectThrowsInProduction(PropTypes.arrayOf(PropTypes.number), [
1,
2,
'b',
]);
expectThrowsInProduction(PropTypes.arrayOf(PropTypes.number), {
'0': 'maybe-array',
length: 1,
});
expectThrowsInProduction(
PropTypes.arrayOf({ foo: PropTypes.string }),
{ foo: 'bar' }
PropTypes.arrayOf(PropTypes.number).isRequired,
null,
);
expectThrowsInProduction(
PropTypes.arrayOf(PropTypes.number),
[1, 2, 'b']
PropTypes.arrayOf(PropTypes.number).isRequired,
undefined,
);
expectThrowsInProduction(
PropTypes.arrayOf(PropTypes.number),
{'0': 'maybe-array', length: 1}
);
expectThrowsInProduction(PropTypes.arrayOf(PropTypes.number).isRequired, null);
expectThrowsInProduction(PropTypes.arrayOf(PropTypes.number).isRequired, undefined);
});
});
@@ -141,14 +140,14 @@ describe('ReactPropTypesProduction', function() {
describe('ObjectOf Type', function() {
it('should be a no-op', function() {
expectThrowsInProduction(
PropTypes.objectOf({ foo: PropTypes.string }),
{ foo: 'bar' }
);
expectThrowsInProduction(
PropTypes.objectOf(PropTypes.number),
{a: 1, b: 2, c: 'b'}
);
expectThrowsInProduction(PropTypes.objectOf({foo: PropTypes.string}), {
foo: 'bar',
});
expectThrowsInProduction(PropTypes.objectOf(PropTypes.number), {
a: 1,
b: 2,
c: 'b',
});
expectThrowsInProduction(PropTypes.objectOf(PropTypes.number), [1, 2]);
expectThrowsInProduction(PropTypes.objectOf(PropTypes.number), null);
expectThrowsInProduction(PropTypes.objectOf(PropTypes.number), undefined);
@@ -168,19 +167,19 @@ describe('ReactPropTypesProduction', function() {
it('should be a no-op', function() {
expectThrowsInProduction(
PropTypes.oneOfType(PropTypes.string, PropTypes.number),
'red'
'red',
);
expectThrowsInProduction(
PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
[]
[],
);
expectThrowsInProduction(
PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
null
null,
);
expectThrowsInProduction(
PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
undefined
undefined,
);
});
});
@@ -190,11 +189,11 @@ describe('ReactPropTypesProduction', function() {
expectThrowsInProduction(PropTypes.shape({}), 'some string');
expectThrowsInProduction(
PropTypes.shape({key: PropTypes.number}).isRequired,
null
null,
);
expectThrowsInProduction(
PropTypes.shape({key: PropTypes.number}).isRequired,
undefined
undefined,
);
});
});
+15 -8
View File
@@ -43,26 +43,33 @@ function checkPropTypes(typeSpecs, values, location, componentName, getStack) {
invariant(
typeof typeSpecs[typeSpecName] === 'function',
'%s: %s type `%s` is invalid; it must be a function, usually from ' +
'React.PropTypes.',
'React.PropTypes.',
componentName || 'React class',
location,
typeSpecName
typeSpecName,
);
error = typeSpecs[typeSpecName](
values,
typeSpecName,
componentName,
location,
null,
ReactPropTypesSecret,
);
error = typeSpecs[typeSpecName](values, typeSpecName, componentName, location, null, ReactPropTypesSecret);
} catch (ex) {
error = ex;
}
warning(
!error || error instanceof Error,
'%s: type specification of %s `%s` is invalid; the type checker ' +
'function must return `null` or an `Error` but returned a %s. ' +
'You may have forgotten to pass an argument to the type checker ' +
'creator (arrayOf, instanceOf, objectOf, oneOf, oneOfType, and ' +
'shape all require an argument).',
'function must return `null` or an `Error` but returned a %s. ' +
'You may have forgotten to pass an argument to the type checker ' +
'creator (arrayOf, instanceOf, objectOf, oneOf, oneOfType, and ' +
'shape all require an argument).',
componentName || 'React class',
location,
typeSpecName,
typeof error
typeof error,
);
if (error instanceof Error && !(error.message in loggedTypeFailures)) {
// Only monitor this failure once because there tends to be a lot of the
+42 -31
View File
@@ -21,24 +21,27 @@ var invariant = require('fbjs/lib/invariant');
var warning = require('fbjs/lib/warning');
var getComponentName = require('getComponentName');
import type { ReactElement, Source } from 'ReactElementType';
import type { DebugID } from 'ReactInstanceType';
import type { Fiber } from 'ReactFiber';
import type {ReactElement, Source} from 'ReactElementType';
import type {DebugID} from 'ReactInstanceType';
import type {Fiber} from 'ReactFiber';
function isNative(fn) {
// Based on isNative() from Lodash
var funcToString = Function.prototype.toString;
var hasOwnProperty = Object.prototype.hasOwnProperty;
var reIsNative = RegExp('^' + funcToString
// Take an example native function source for comparison
.call(hasOwnProperty)
// Strip regex characters so we can use it for regex
.replace(/[\\^$.*+?()[\]{}|]/g, '\\$&')
// Remove hasOwnProperty from the template to make it generic
.replace(
/hasOwnProperty|(function).*?(?=\\\()| for .+?(?=\\\])/g,
'$1.*?'
) + '$'
var reIsNative = RegExp(
'^' +
funcToString
// Take an example native function source for comparison
.call(hasOwnProperty)
// Strip regex characters so we can use it for regex
.replace(/[\\^$.*+?()[\]{}|]/g, '\\$&')
// Remove hasOwnProperty from the template to make it generic
.replace(
/hasOwnProperty|(function).*?(?=\\\()| for .+?(?=\\\])/g,
'$1.*?',
) +
'$',
);
try {
var source = funcToString.call(fn);
@@ -48,7 +51,7 @@ function isNative(fn) {
}
}
var canUseCollections = (
var canUseCollections =
// Array.from
typeof Array.from === 'function' &&
// Map
@@ -64,8 +67,7 @@ var canUseCollections = (
// Set.prototype.keys
Set.prototype != null &&
typeof Set.prototype.keys === 'function' &&
isNative(Set.prototype.keys)
);
isNative(Set.prototype.keys);
var setItem;
var getItem;
@@ -101,7 +103,6 @@ if (canUseCollections) {
getRootIDs = function() {
return Array.from(rootIDSet.keys());
};
} else {
var itemByKey = {};
var rootByKey = {};
@@ -179,10 +180,14 @@ function describeID(id: DebugID): string {
warning(
element,
'ReactComponentTreeHook: Missing React element for debugID %s when ' +
'building stack',
id
'building stack',
id,
);
return describeComponentFrame(
name || '',
element && element._source,
ownerName || '',
);
return describeComponentFrame(name || '', element && element._source, ownerName || '');
}
var ReactComponentTreeHook = {
@@ -197,19 +202,19 @@ var ReactComponentTreeHook = {
invariant(
nextChild,
'Expected hook events to fire for the child ' +
'before its parent includes it in onSetChildren().'
'before its parent includes it in onSetChildren().',
);
invariant(
nextChild.childIDs != null ||
typeof nextChild.element !== 'object' ||
nextChild.element == null,
typeof nextChild.element !== 'object' ||
nextChild.element == null,
'Expected onSetChildren() to fire for a container child ' +
'before its parent includes it in onSetChildren().'
'before its parent includes it in onSetChildren().',
);
invariant(
nextChild.isMounted,
'Expected onMountComponent() to fire for the child ' +
'before its parent includes it in onSetChildren().'
'before its parent includes it in onSetChildren().',
);
if (nextChild.parentID == null) {
nextChild.parentID = id;
@@ -220,15 +225,19 @@ var ReactComponentTreeHook = {
invariant(
nextChild.parentID === id,
'Expected onBeforeMountComponent() parent and onSetChildren() to ' +
'be consistent (%s has parents %s and %s).',
'be consistent (%s has parents %s and %s).',
nextChildID,
nextChild.parentID,
id
id,
);
}
},
onBeforeMountComponent(id: DebugID, element: ReactElement, parentID: DebugID): void {
onBeforeMountComponent(
id: DebugID,
element: ReactElement,
parentID: DebugID,
): void {
var item = {
element,
parentID,
@@ -313,19 +322,21 @@ var ReactComponentTreeHook = {
info += describeComponentFrame(
name,
topElement._source,
owner && getComponentName(owner)
owner && getComponentName(owner),
);
}
var currentOwner = ReactCurrentOwner.current;
if (currentOwner) {
if (typeof currentOwner.tag === 'number') {
const workInProgress = ((currentOwner : any) : Fiber);
const workInProgress = ((currentOwner: any): Fiber);
// Safe because if current owner exists, we are reconciling,
// and it is guaranteed to be the work-in-progress version.
info += getStackAddendumByWorkInProgressFiber(workInProgress);
} else if (typeof currentOwner._debugID === 'number') {
info += ReactComponentTreeHook.getStackAddendumByID(currentOwner._debugID);
info += ReactComponentTreeHook.getStackAddendumByID(
currentOwner._debugID,
);
}
}
return info;
@@ -60,10 +60,10 @@ ReactComponent.prototype.isReactComponent = {};
ReactComponent.prototype.setState = function(partialState, callback) {
invariant(
typeof partialState === 'object' ||
typeof partialState === 'function' ||
partialState == null,
typeof partialState === 'function' ||
partialState == null,
'setState(...): takes an object of state variables to update or a ' +
'function which returns an object of state variables.'
'function which returns an object of state variables.',
);
this.updater.enqueueSetState(this, partialState, callback, 'setState');
};
@@ -96,12 +96,12 @@ if (__DEV__) {
isMounted: [
'isMounted',
'Instead, make sure to clean up subscriptions and pending requests in ' +
'componentWillUnmount to prevent memory leaks.',
'componentWillUnmount to prevent memory leaks.',
],
replaceState: [
'replaceState',
'Refactor your code to use setState instead (see ' +
'https://github.com/facebook/react/issues/3236).',
'https://github.com/facebook/react/issues/3236).',
],
};
var defineDeprecationWarning = function(methodName, info) {
@@ -112,7 +112,7 @@ if (__DEV__) {
false,
'%s(...) is deprecated in plain JavaScript React classes. %s',
info[0],
info[1]
info[1],
);
return undefined;
},
@@ -19,11 +19,12 @@ function warnNoop(publicInstance, callerName) {
warning(
false,
'%s(...): Can only update a mounted or mounting component. ' +
'This usually means you called %s() on an unmounted component. ' +
'This is a no-op.\n\nPlease check the code for the %s component.',
'This usually means you called %s() on an unmounted component. ' +
'This is a no-op.\n\nPlease check the code for the %s component.',
callerName,
callerName,
constructor && (constructor.displayName || constructor.name) || 'ReactClass'
(constructor && (constructor.displayName || constructor.name)) ||
'ReactClass',
);
}
}
@@ -32,7 +33,6 @@ function warnNoop(publicInstance, callerName) {
* This is the abstract API for an update queue.
*/
var ReactNoopUpdateQueue = {
/**
* Checks whether or not this composite component is mounted.
* @param {ReactClass} publicInstance The instance we want to test.
@@ -76,7 +76,12 @@ var ReactNoopUpdateQueue = {
* @param {?string} Name of the calling function in the public API.
* @internal
*/
enqueueReplaceState: function(publicInstance, completeState, callback, callerName) {
enqueueReplaceState: function(
publicInstance,
completeState,
callback,
callerName,
) {
warnNoop(publicInstance, 'replaceState');
},
@@ -92,7 +97,12 @@ var ReactNoopUpdateQueue = {
* @param {?string} Name of the calling function in the public API.
* @internal
*/
enqueueSetState: function(publicInstance, partialState, callback, callerName) {
enqueueSetState: function(
publicInstance,
partialState,
callback,
callerName,
) {
warnNoop(publicInstance, 'setState');
},
};
@@ -26,7 +26,6 @@ describe('ReactClassEquivalence', () => {
var result2 = runJest('ReactES6Class-test.js');
compareResults(result1, result2);
});
});
function runJest(testFile) {
@@ -36,13 +35,13 @@ function runJest(testFile) {
var setupFile = path.resolve(
'scripts',
'jest',
'setupSpecEquivalenceReporter.js'
'setupSpecEquivalenceReporter.js',
);
var result = spawnSync(
jestBin,
[testFile, '--setupTestFrameworkScriptFile', setupFile],
{cwd},
);
var result = spawnSync(jestBin, [
testFile,
'--setupTestFrameworkScriptFile',
setupFile,
], {cwd});
if (result.error) {
throw result.error;
@@ -51,12 +50,12 @@ function runJest(testFile) {
if (result.status !== 0) {
throw new Error(
'jest process exited with: ' +
result.status +
'\n' +
'stdout: ' +
result.stdout.toString() +
'stderr: ' +
result.stderr.toString()
result.status +
'\n' +
'stdout: ' +
result.stdout.toString() +
'stderr: ' +
result.stderr.toString(),
);
}
@@ -15,7 +15,6 @@ var React;
var ReactDOM;
describe('ReactES6Class', () => {
var container;
var freeze = function(expectation) {
Object.freeze(expectation);
@@ -52,19 +51,19 @@ describe('ReactES6Class', () => {
}
it('preserves the name of the class for use in error messages', () => {
class Foo extends React.Component { }
class Foo extends React.Component {}
expect(Foo.name).toBe('Foo');
});
it('throws if no render function is defined', () => {
spyOn(console, 'error');
class Foo extends React.Component { }
class Foo extends React.Component {}
expect(() => ReactDOM.render(<Foo />, container)).toThrow();
expect(console.error.calls.count()).toBe(1);
expect(console.error.calls.argsFor(0)[0]).toBe(
'Warning: Foo(...): No `render` method found on the returned component ' +
'instance: you may have forgotten to define `render`.'
'instance: you may have forgotten to define `render`.',
);
});
@@ -174,7 +173,7 @@ describe('ReactES6Class', () => {
}
}
expect(() => test(<Foo />, 'span', '')).toThrowError(
'Foo.state: must be set to an object or null'
'Foo.state: must be set to an object or null',
);
});
});
@@ -203,10 +202,7 @@ describe('ReactES6Class', () => {
}
render() {
return (
<Inner
name={this.state.bar}
onClick={this.handleClick.bind(this)}
/>
<Inner name={this.state.bar} onClick={this.handleClick.bind(this)} />
);
}
}
@@ -225,12 +221,7 @@ describe('ReactES6Class', () => {
this.setState({bar: 'bar'});
}
render() {
return (
<Inner
name={this.state.bar}
onClick={this.handleClick}
/>
);
return <Inner name={this.state.bar} onClick={this.handleClick} />;
}
}
test(<Foo initialValue="foo" />, 'DIV', 'foo');
@@ -295,12 +286,10 @@ describe('ReactES6Class', () => {
}
}
test(<Foo value="foo" />, 'SPAN', 'foo');
expect(lifeCycles).toEqual([
'will-mount',
'did-mount',
]);
expect(lifeCycles).toEqual(['will-mount', 'did-mount']);
lifeCycles = []; // reset
test(<Foo value="bar" />, 'SPAN', 'bar');
// prettier-ignore
expect(lifeCycles).toEqual([
'receive-props', freeze({value: 'bar'}),
'should-update', freeze({value: 'bar'}), {},
@@ -309,9 +298,7 @@ describe('ReactES6Class', () => {
]);
lifeCycles = []; // reset
ReactDOM.unmountComponentAtNode(container);
expect(lifeCycles).toEqual([
'will-unmount',
]);
expect(lifeCycles).toEqual(['will-unmount']);
});
it('warns when classic properties are defined on the instance, but does not invoke them.', () => {
@@ -341,16 +328,16 @@ describe('ReactES6Class', () => {
expect(getDefaultPropsWasCalled).toBe(false);
expect(console.error.calls.count()).toBe(4);
expect(console.error.calls.argsFor(0)[0]).toContain(
'getInitialState was defined on Foo, a plain JavaScript class.'
'getInitialState was defined on Foo, a plain JavaScript class.',
);
expect(console.error.calls.argsFor(1)[0]).toContain(
'getDefaultProps was defined on Foo, a plain JavaScript class.'
'getDefaultProps was defined on Foo, a plain JavaScript class.',
);
expect(console.error.calls.argsFor(2)[0]).toContain(
'propTypes was defined as an instance property on Foo.'
'propTypes was defined as an instance property on Foo.',
);
expect(console.error.calls.argsFor(3)[0]).toContain(
'contextTypes was defined as an instance property on Foo.'
'contextTypes was defined as an instance property on Foo.',
);
});
@@ -385,9 +372,9 @@ describe('ReactES6Class', () => {
expect(console.error.calls.count()).toBe(1);
expect(console.error.calls.argsFor(0)[0]).toBe(
'Warning: ' +
'NamedComponent has a method called componentShouldUpdate(). Did you ' +
'mean shouldComponentUpdate()? The name is phrased as a question ' +
'because the function is expected to return a value.'
'NamedComponent has a method called componentShouldUpdate(). Did you ' +
'mean shouldComponentUpdate()? The name is phrased as a question ' +
'because the function is expected to return a value.',
);
});
@@ -407,8 +394,8 @@ describe('ReactES6Class', () => {
expect(console.error.calls.count()).toBe(1);
expect(console.error.calls.argsFor(0)[0]).toBe(
'Warning: ' +
'NamedComponent has a method called componentWillRecieveProps(). Did ' +
'you mean componentWillReceiveProps()?'
'NamedComponent has a method called componentWillRecieveProps(). Did ' +
'you mean componentWillReceiveProps()?',
);
});
@@ -419,10 +406,10 @@ describe('ReactES6Class', () => {
expect(() => instance.isMounted()).toThrow();
expect(console.error.calls.count()).toBe(2);
expect(console.error.calls.argsFor(0)[0]).toContain(
'replaceState(...) is deprecated in plain JavaScript React classes'
'replaceState(...) is deprecated in plain JavaScript React classes',
);
expect(console.error.calls.argsFor(1)[0]).toContain(
'isMounted(...) is deprecated in plain JavaScript React classes'
'isMounted(...) is deprecated in plain JavaScript React classes',
);
});
@@ -460,5 +447,4 @@ describe('ReactES6Class', () => {
var node = ReactDOM.findDOMNode(instance);
expect(node).toBe(container.firstChild);
});
});
@@ -93,5 +93,4 @@ describe('ReactPureComponent', () => {
ReactDOM.render(<Component />, document.createElement('div'));
expect(renders).toBe(1);
});
});
@@ -80,7 +80,7 @@ describe('ReactJSXElement', () => {
expect(element.type).toBe(Component);
expect(element.key).toBe('12');
expect(element.ref).toBe('34');
var expectation = {foo:'56'};
var expectation = {foo: '56'};
Object.freeze(expectation);
expect(element.props).toEqual(expectation);
});
@@ -90,7 +90,7 @@ describe('ReactJSXElement', () => {
expect(element.type).toBe(Component);
expect(element.key).toBe('12');
expect(element.ref).toBe(null);
var expectation = {foo:'56'};
var expectation = {foo: '56'};
Object.freeze(expectation);
expect(element.props).toEqual(expectation);
});
@@ -124,7 +124,7 @@ describe('ReactJSXElement', () => {
var element2 = React.cloneElement(
<Component children="text" />,
{},
undefined
undefined,
);
expect(element2.props.children).toBe(undefined);
});
@@ -165,7 +165,7 @@ describe('ReactJSXElement', () => {
expect(React.isValidElement({})).toEqual(false);
expect(React.isValidElement('string')).toEqual(false);
expect(React.isValidElement(Component)).toEqual(false);
expect(React.isValidElement({ type: 'div', props: {} })).toEqual(false);
expect(React.isValidElement({type: 'div', props: {}})).toEqual(false);
});
it('is indistinguishable from a plain object', () => {
@@ -178,10 +178,7 @@ describe('ReactJSXElement', () => {
Component.defaultProps = {fruit: 'persimmon'};
var container = document.createElement('div');
var instance = ReactDOM.render(
<Component fruit="mango" />,
container
);
var instance = ReactDOM.render(<Component fruit="mango" />, container);
expect(instance.props.fruit).toBe('mango');
ReactDOM.render(<Component />, container);
@@ -199,9 +196,9 @@ describe('ReactJSXElement', () => {
var instance = ReactTestUtils.renderIntoDocument(<NormalizingComponent />);
expect(instance.props.prop).toBe('testKey');
var inst2 =
ReactTestUtils.renderIntoDocument(<NormalizingComponent prop={null} />);
var inst2 = ReactTestUtils.renderIntoDocument(
<NormalizingComponent prop={null} />,
);
expect(inst2.props.prop).toBe(null);
});
});
@@ -55,7 +55,7 @@ describe('ReactJSXElementValidator', () => {
expectDev(console.error.calls.count()).toBe(1);
expectDev(console.error.calls.argsFor(0)[0]).toContain(
'Each child in an array or iterator should have a unique "key" prop.'
'Each child in an array or iterator should have a unique "key" prop.',
);
});
@@ -70,11 +70,7 @@ describe('ReactJSXElementValidator', () => {
class ComponentWrapper extends React.Component {
render() {
return (
<InnerComponent
childSet={[<Component />, <Component />]}
/>
);
return <InnerComponent childSet={[<Component />, <Component />]} />;
}
}
@@ -83,8 +79,8 @@ describe('ReactJSXElementValidator', () => {
expectDev(console.error.calls.count()).toBe(1);
expectDev(console.error.calls.argsFor(0)[0]).toContain(
'Each child in an array or iterator should have a unique "key" prop.' +
'\n\nCheck the render method of `InnerComponent`. ' +
'It was passed a child from ComponentWrapper. '
'\n\nCheck the render method of `InnerComponent`. ' +
'It was passed a child from ComponentWrapper. ',
);
});
@@ -107,14 +103,16 @@ describe('ReactJSXElementValidator', () => {
expectDev(console.error.calls.count()).toBe(1);
expectDev(console.error.calls.argsFor(0)[0]).toContain(
'Each child in an array or iterator should have a unique "key" prop.'
'Each child in an array or iterator should have a unique "key" prop.',
);
});
it('does not warns for arrays of elements with keys', () => {
spyOn(console, 'error');
void <Component>{[<Component key="#1" />, <Component key="#2" />]}</Component>;
void (
<Component>{[<Component key="#1" />, <Component key="#2" />]}</Component>
);
expectDev(console.error.calls.count()).toBe(0);
});
@@ -200,10 +198,10 @@ describe('ReactJSXElementValidator', () => {
ReactTestUtils.renderIntoDocument(<ParentComp />);
expect(normalizeCodeLocInfo(console.error.calls.argsFor(0)[0])).toBe(
'Warning: Failed prop type: ' +
'Invalid prop `color` of type `number` supplied to `MyComp`, ' +
'expected `string`.\n' +
' in MyComp (at **)\n' +
' in ParentComp (at **)'
'Invalid prop `color` of type `number` supplied to `MyComp`, ' +
'expected `string`.\n' +
' in MyComp (at **)\n' +
' in ParentComp (at **)',
);
});
@@ -236,11 +234,11 @@ describe('ReactJSXElementValidator', () => {
// If it doesn't, it means we're using information from the old element.
expect(normalizeCodeLocInfo(console.error.calls.argsFor(0)[0])).toBe(
'Warning: Failed prop type: ' +
'Invalid prop `color` of type `number` supplied to `MyComp`, ' +
'expected `string`.\n' +
' in MyComp (at **)\n' +
' in MiddleComp (at **)\n' +
' in ParentComp (at **)'
'Invalid prop `color` of type `number` supplied to `MyComp`, ' +
'expected `string`.\n' +
' in MyComp (at **)\n' +
' in MiddleComp (at **)\n' +
' in ParentComp (at **)',
);
});
@@ -258,28 +256,28 @@ describe('ReactJSXElementValidator', () => {
expectDev(console.error.calls.count()).toBe(4);
expectDev(normalizeCodeLocInfo(console.error.calls.argsFor(0)[0])).toBe(
'Warning: React.createElement: type is invalid -- expected a string ' +
'(for built-in components) or a class/function (for composite ' +
'components) but got: undefined. You likely forgot to export your ' +
'component from the file it\'s defined in.' +
'\n\nCheck your code at **.'
'(for built-in components) or a class/function (for composite ' +
'components) but got: undefined. You likely forgot to export your ' +
"component from the file it's defined in." +
'\n\nCheck your code at **.',
);
expectDev(normalizeCodeLocInfo(console.error.calls.argsFor(1)[0])).toBe(
'Warning: React.createElement: type is invalid -- expected a string ' +
'(for built-in components) or a class/function (for composite ' +
'components) but got: null.' +
'\n\nCheck your code at **.'
'(for built-in components) or a class/function (for composite ' +
'components) but got: null.' +
'\n\nCheck your code at **.',
);
expectDev(normalizeCodeLocInfo(console.error.calls.argsFor(2)[0])).toBe(
'Warning: React.createElement: type is invalid -- expected a string ' +
'(for built-in components) or a class/function (for composite ' +
'components) but got: boolean.' +
'\n\nCheck your code at **.'
'(for built-in components) or a class/function (for composite ' +
'components) but got: boolean.' +
'\n\nCheck your code at **.',
);
expectDev(normalizeCodeLocInfo(console.error.calls.argsFor(3)[0])).toBe(
'Warning: React.createElement: type is invalid -- expected a string ' +
'(for built-in components) or a class/function (for composite ' +
'components) but got: number.' +
'\n\nCheck your code at **.'
'(for built-in components) or a class/function (for composite ' +
'components) but got: number.' +
'\n\nCheck your code at **.',
);
void <Div />;
expectDev(console.error.calls.count()).toBe(4);
@@ -295,8 +293,8 @@ describe('ReactJSXElementValidator', () => {
expectDev(console.error.calls.count()).toBe(1);
expect(normalizeCodeLocInfo(console.error.calls.argsFor(0)[0])).toBe(
'Warning: Failed prop type: The prop `prop` is marked as required in ' +
'`RequiredPropComponent`, but its value is `null`.\n' +
' in RequiredPropComponent (at **)'
'`RequiredPropComponent`, but its value is `null`.\n' +
' in RequiredPropComponent (at **)',
);
});
@@ -308,8 +306,8 @@ describe('ReactJSXElementValidator', () => {
expectDev(console.error.calls.count()).toBe(1);
expect(normalizeCodeLocInfo(console.error.calls.argsFor(0)[0])).toBe(
'Warning: Failed prop type: The prop `prop` is marked as required in ' +
'`RequiredPropComponent`, but its value is `null`.\n' +
' in RequiredPropComponent (at **)'
'`RequiredPropComponent`, but its value is `null`.\n' +
' in RequiredPropComponent (at **)',
);
});
@@ -322,16 +320,16 @@ describe('ReactJSXElementValidator', () => {
expectDev(console.error.calls.count()).toBe(2);
expect(normalizeCodeLocInfo(console.error.calls.argsFor(0)[0])).toBe(
'Warning: Failed prop type: ' +
'The prop `prop` is marked as required in `RequiredPropComponent`, but ' +
'its value is `undefined`.\n' +
' in RequiredPropComponent (at **)'
'The prop `prop` is marked as required in `RequiredPropComponent`, but ' +
'its value is `undefined`.\n' +
' in RequiredPropComponent (at **)',
);
expect(normalizeCodeLocInfo(console.error.calls.argsFor(1)[0])).toBe(
'Warning: Failed prop type: ' +
'Invalid prop `prop` of type `number` supplied to ' +
'`RequiredPropComponent`, expected `string`.\n' +
' in RequiredPropComponent (at **)'
'Invalid prop `prop` of type `number` supplied to ' +
'`RequiredPropComponent`, expected `string`.\n' +
' in RequiredPropComponent (at **)',
);
ReactTestUtils.renderIntoDocument(<RequiredPropComponent prop="string" />);
@@ -358,7 +356,7 @@ describe('ReactJSXElementValidator', () => {
expectDev(console.error.calls.count()).toBe(1);
expectDev(console.error.calls.argsFor(0)[0]).toContain(
'NullPropTypeComponent: prop type `prop` is invalid; it must be a ' +
'function, usually from React.PropTypes.'
'function, usually from React.PropTypes.',
);
});
@@ -376,7 +374,7 @@ describe('ReactJSXElementValidator', () => {
expectDev(console.error.calls.count()).toBe(1);
expectDev(console.error.calls.argsFor(0)[0]).toContain(
'NullContextTypeComponent: context type `prop` is invalid; it must ' +
'be a function, usually from React.PropTypes.'
'be a function, usually from React.PropTypes.',
);
});
@@ -394,8 +392,7 @@ describe('ReactJSXElementValidator', () => {
expectDev(console.error.calls.count()).toBe(1);
expectDev(console.error.calls.argsFor(0)[0]).toContain(
'getDefaultProps is only used on classic React.createClass definitions.' +
' Use a static property named `defaultProps` instead.'
' Use a static property named `defaultProps` instead.',
);
});
});
@@ -25,22 +25,19 @@ describe('EventPluginHub', () => {
it('should prevent non-function listeners, at dispatch', () => {
var node = ReactTestUtils.renderIntoDocument(
<div onClick="not a function" />
<div onClick="not a function" />,
);
expect(function() {
ReactTestUtils.SimulateNative.click(node);
}).toThrowError(
'Expected onClick listener to be a function, instead got type string'
'Expected onClick listener to be a function, instead got type string',
);
});
it('should not prevent null listeners, at dispatch', () => {
var node = ReactTestUtils.renderIntoDocument(
<div onClick={null} />
);
var node = ReactTestUtils.renderIntoDocument(<div onClick={null} />);
expect(function() {
ReactTestUtils.SimulateNative.click(node);
}).not.toThrow();
});
});
@@ -60,7 +60,7 @@ describe('ReactChildReconciler', () => {
expectDev(console.error.calls.count()).toBe(1);
expectDev(console.error.calls.argsFor(0)[0]).toContain(
'Child keys must be unique; when two children share a key, only the first child will be used.'
'Child keys must be unique; when two children share a key, only the first child will be used.',
);
});
@@ -88,14 +88,16 @@ describe('ReactChildReconciler', () => {
ReactTestUtils.renderIntoDocument(<GrandParent />);
expectDev(console.error.calls.count()).toBe(1);
expectDev(normalizeCodeLocInfo(console.error.calls.argsFor(0)[0])).toContain(
expectDev(
normalizeCodeLocInfo(console.error.calls.argsFor(0)[0]),
).toContain(
'Encountered two children with the same key, `1`. ' +
'Child keys must be unique; when two children share a key, ' +
'only the first child will be used.\n' +
' in div (at **)\n' +
' in Component (at **)\n' +
' in Parent (at **)\n' +
' in GrandParent (at **)'
'Child keys must be unique; when two children share a key, ' +
'only the first child will be used.\n' +
' in div (at **)\n' +
' in Component (at **)\n' +
' in Parent (at **)\n' +
' in GrandParent (at **)',
);
});
@@ -112,7 +114,7 @@ describe('ReactChildReconciler', () => {
expectDev(console.error.calls.count()).toBe(1);
expectDev(console.error.calls.argsFor(0)[0]).toContain(
'Child keys must be unique; when two children share a key, only the first child will be used.'
'Child keys must be unique; when two children share a key, only the first child will be used.',
);
});
@@ -140,14 +142,16 @@ describe('ReactChildReconciler', () => {
ReactTestUtils.renderIntoDocument(<GrandParent />);
expectDev(console.error.calls.count()).toBe(1);
expectDev(normalizeCodeLocInfo(console.error.calls.argsFor(0)[0])).toContain(
expectDev(
normalizeCodeLocInfo(console.error.calls.argsFor(0)[0]),
).toContain(
'Encountered two children with the same key, `1`. ' +
'Child keys must be unique; when two children share a key, ' +
'only the first child will be used.\n' +
' in div (at **)\n' +
' in Component (at **)\n' +
' in Parent (at **)\n' +
' in GrandParent (at **)'
'Child keys must be unique; when two children share a key, ' +
'only the first child will be used.\n' +
' in div (at **)\n' +
' in Component (at **)\n' +
' in Parent (at **)\n' +
' in GrandParent (at **)',
);
});
});
+61 -58
View File
@@ -29,15 +29,11 @@ describe('ReactComponent', () => {
// jQuery objects are basically arrays; people often pass them in by mistake
expect(function() {
ReactDOM.render(<div />, [container]);
}).toThrowError(
/Target container is not a DOM element./
);
}).toThrowError(/Target container is not a DOM element./);
expect(function() {
ReactDOM.render(<div />, null);
}).toThrowError(
/Target container is not a DOM element./
);
}).toThrowError(/Target container is not a DOM element./);
});
it('should throw when supplying a ref outside of render method', () => {
@@ -59,7 +55,7 @@ describe('ReactComponent', () => {
<span key={0} />
<span key={1} />
<span key={2} />
</Wrapper>
</Wrapper>,
);
}).toThrowError(/Cannot assign to read only property.*/);
});
@@ -84,7 +80,7 @@ describe('ReactComponent', () => {
<span key={0} />
<span key={1} />
<span key={2} />
</Wrapper>
</Wrapper>,
);
}).toThrowError(/Cannot assign to read only property.*/);
});
@@ -157,9 +153,9 @@ describe('ReactComponent', () => {
class Component extends React.Component {
render() {
var inner = <Wrapper object={innerObj} ref={(c) => this.innerRef = c} />;
var inner = <Wrapper object={innerObj} ref={c => this.innerRef = c} />;
var outer = (
<Wrapper object={outerObj} ref={(c) => this.outerRef = c}>
<Wrapper object={outerObj} ref={c => this.outerRef = c}>
{inner}
</Wrapper>
);
@@ -194,16 +190,16 @@ describe('ReactComponent', () => {
getInner = () => {
// (With old-style refs, it's impossible to get a ref to this div
// because Wrapper is the current owner when this function is called.)
return <div className="inner" ref={(c) => this.innerRef = c} />;
return <div className="inner" ref={c => this.innerRef = c} />;
};
render() {
return (
<Wrapper
title="wrapper"
ref={(c) => this.wrapperRef = c}
ref={c => this.wrapperRef = c}
getContent={this.getInner}
/>
/>
);
}
@@ -245,12 +241,18 @@ describe('ReactComponent', () => {
render() {
return (
<div>
<Inner id={1} ref={(c) => {
log.push(`ref 1 got ${c ? `instance ${c.props.id}` : 'null'}`);
}} />
<Inner id={2} ref={(c) => {
log.push(`ref 2 got ${c ? `instance ${c.props.id}` : 'null'}`);
}} />
<Inner
id={1}
ref={c => {
log.push(`ref 1 got ${c ? `instance ${c.props.id}` : 'null'}`);
}}
/>
<Inner
id={2}
ref={c => {
log.push(`ref 2 got ${c ? `instance ${c.props.id}` : 'null'}`);
}}
/>
</div>
);
}
@@ -280,39 +282,41 @@ describe('ReactComponent', () => {
/* eslint-disable indent */
expect(log).toEqual([
'start mount',
'inner 1 render',
'inner 2 render',
'inner 1 componentDidMount',
'ref 1 got instance 1',
'inner 2 componentDidMount',
'ref 2 got instance 2',
'outer componentDidMount',
'inner 1 render',
'inner 2 render',
'inner 1 componentDidMount',
'ref 1 got instance 1',
'inner 2 componentDidMount',
'ref 2 got instance 2',
'outer componentDidMount',
'start update',
// Previous (equivalent) refs get cleared
...(ReactDOMFeatureFlags.useFiber ? [
// Fiber renders first, resets refs later
'inner 1 render',
'inner 2 render',
'ref 1 got null',
'ref 2 got null',
] : [
// Stack resets refs before rendering
'ref 1 got null',
'inner 1 render',
'ref 2 got null',
'inner 2 render',
]),
'inner 1 componentDidUpdate',
'ref 1 got instance 1',
'inner 2 componentDidUpdate',
'ref 2 got instance 2',
'outer componentDidUpdate',
// Previous (equivalent) refs get cleared
...(ReactDOMFeatureFlags.useFiber
? [
// Fiber renders first, resets refs later
'inner 1 render',
'inner 2 render',
'ref 1 got null',
'ref 2 got null',
]
: [
// Stack resets refs before rendering
'ref 1 got null',
'inner 1 render',
'ref 2 got null',
'inner 2 render',
]),
'inner 1 componentDidUpdate',
'ref 1 got instance 1',
'inner 2 componentDidUpdate',
'ref 2 got instance 2',
'outer componentDidUpdate',
'start unmount',
'outer componentWillUnmount',
'ref 1 got null',
'inner 1 componentWillUnmount',
'ref 2 got null',
'inner 2 componentWillUnmount',
'outer componentWillUnmount',
'ref 1 got null',
'inner 1 componentWillUnmount',
'ref 2 got null',
'inner 2 componentWillUnmount',
]);
/* eslint-enable indent */
});
@@ -334,15 +338,15 @@ describe('ReactComponent', () => {
var X = undefined;
expect(() => ReactTestUtils.renderIntoDocument(<X />)).toThrowError(
'Element type is invalid: expected a string (for built-in components) ' +
'or a class/function (for composite components) but got: undefined. ' +
'You likely forgot to export your component from the file it\'s ' +
'defined in.'
'or a class/function (for composite components) but got: undefined. ' +
"You likely forgot to export your component from the file it's " +
'defined in.',
);
var Y = null;
expect(() => ReactTestUtils.renderIntoDocument(<Y />)).toThrowError(
'Element type is invalid: expected a string (for built-in components) ' +
'or a class/function (for composite components) but got: null.'
'or a class/function (for composite components) but got: null.',
);
// One warning for each element creation
@@ -368,13 +372,12 @@ describe('ReactComponent', () => {
expect(() => ReactTestUtils.renderIntoDocument(<Foo />)).toThrowError(
'Element type is invalid: expected a string (for built-in components) ' +
'or a class/function (for composite components) but got: undefined. ' +
'You likely forgot to export your component from the file it\'s ' +
'defined in.\n\nCheck the render method of `Bar`.'
'or a class/function (for composite components) but got: undefined. ' +
"You likely forgot to export your component from the file it's " +
'defined in.\n\nCheck the render method of `Bar`.',
);
// One warning for each element creation
expectDev(console.error.calls.count()).toBe(1);
});
});
@@ -19,7 +19,6 @@ var clone = function(o) {
return JSON.parse(JSON.stringify(o));
};
var GET_INIT_STATE_RETURN_VAL = {
hasWillMountCompleted: false,
hasRenderCompleted: false,
@@ -70,16 +69,13 @@ type ComponentLifeCycle =
* Mounted components have a DOM node representation and are capable of
* receiving new props.
*/
'MOUNTED' |
/**
| 'MOUNTED' /**
* Unmounted components are inactive and cannot receive new props.
*/
'UNMOUNTED';
| 'UNMOUNTED';
function getLifeCycleState(instance): ComponentLifeCycle {
return instance.updater.isMounted(instance) ?
'MOUNTED' :
'UNMOUNTED';
return instance.updater.isMounted(instance) ? 'MOUNTED' : 'UNMOUNTED';
}
/**
@@ -104,9 +100,7 @@ describe('ReactComponentLifeCycle', () => {
state = {};
render() {
return (
<div />
);
return <div />;
}
}
@@ -152,11 +146,9 @@ describe('ReactComponentLifeCycle', () => {
render() {
return (
<div>{
this.state.showHasOnDOMReadyComponent ?
<Child /> :
<div />
}</div>
<div>
{this.state.showHasOnDOMReadyComponent ? <Child /> : <div />}
</div>
);
}
}
@@ -178,9 +170,7 @@ describe('ReactComponentLifeCycle', () => {
}
render() {
return (
<div />
);
return <div />;
}
}
@@ -197,9 +187,7 @@ describe('ReactComponentLifeCycle', () => {
}
render() {
return (
<div />
);
return <div />;
}
}
@@ -221,9 +209,7 @@ describe('ReactComponentLifeCycle', () => {
}
render() {
return (
<div />
);
return <div />;
}
}
@@ -231,9 +217,9 @@ describe('ReactComponentLifeCycle', () => {
expectDev(console.error.calls.count()).toBe(1);
expectDev(console.error.calls.argsFor(0)[0]).toBe(
'Warning: setState(...): Can only update a mounted or ' +
'mounting component. This usually means you called setState() on an ' +
'unmounted component. This is a no-op.\n\nPlease check the code for the ' +
'StatefulComponent component.'
'mounting component. This usually means you called setState() on an ' +
'unmounted component. This is a no-op.\n\nPlease check the code for the ' +
'StatefulComponent component.',
);
});
@@ -259,7 +245,7 @@ describe('ReactComponentLifeCycle', () => {
expectDev(console.error.calls.count()).toBe(1);
expectDev(console.error.calls.argsFor(0)[0]).toContain(
'Component is accessing isMounted inside its render()'
'Component is accessing isMounted inside its render()',
);
});
@@ -285,7 +271,7 @@ describe('ReactComponentLifeCycle', () => {
expectDev(console.error.calls.count()).toBe(1);
expectDev(console.error.calls.argsFor(0)[0]).toContain(
'Component is accessing isMounted inside its render()'
'Component is accessing isMounted inside its render()',
);
});
@@ -326,14 +312,13 @@ describe('ReactComponentLifeCycle', () => {
ReactTestUtils.renderIntoDocument(<Component />);
expectDev(console.error.calls.count()).toBe(1);
expectDev(console.error.calls.argsFor(0)[0]).toContain(
'Component is accessing findDOMNode inside its render()'
'Component is accessing findDOMNode inside its render()',
);
});
it('should carry through each of the phases of setup', () => {
spyOn(console, 'error');
class LifeCycleComponent extends React.Component {
constructor(props, context) {
super(props, context);
@@ -345,22 +330,21 @@ describe('ReactComponentLifeCycle', () => {
hasWillUnmountCompleted: false,
};
this._testJournal.returnedFromGetInitialState = clone(initState);
this._testJournal.lifeCycleAtStartOfGetInitialState =
getLifeCycleState(this);
this._testJournal.lifeCycleAtStartOfGetInitialState = getLifeCycleState(
this,
);
this.state = initState;
}
componentWillMount() {
this._testJournal.stateAtStartOfWillMount = clone(this.state);
this._testJournal.lifeCycleAtStartOfWillMount =
getLifeCycleState(this);
this._testJournal.lifeCycleAtStartOfWillMount = getLifeCycleState(this);
this.state.hasWillMountCompleted = true;
}
componentDidMount() {
this._testJournal.stateAtStartOfDidMount = clone(this.state);
this._testJournal.lifeCycleAtStartOfDidMount =
getLifeCycleState(this);
this._testJournal.lifeCycleAtStartOfDidMount = getLifeCycleState(this);
this.setState({hasDidMountCompleted: true});
}
@@ -384,8 +368,9 @@ describe('ReactComponentLifeCycle', () => {
componentWillUnmount() {
this._testJournal.stateAtStartOfWillUnmount = clone(this.state);
this._testJournal.lifeCycleAtStartOfWillUnmount =
getLifeCycleState(this);
this._testJournal.lifeCycleAtStartOfWillUnmount = getLifeCycleState(
this,
);
this.state.hasWillUnmountCompleted = true;
}
}
@@ -398,31 +383,29 @@ describe('ReactComponentLifeCycle', () => {
// getInitialState
expect(instance._testJournal.returnedFromGetInitialState).toEqual(
GET_INIT_STATE_RETURN_VAL
GET_INIT_STATE_RETURN_VAL,
);
expect(instance._testJournal.lifeCycleAtStartOfGetInitialState).toBe(
'UNMOUNTED',
);
expect(instance._testJournal.lifeCycleAtStartOfGetInitialState)
.toBe('UNMOUNTED');
// componentWillMount
expect(instance._testJournal.stateAtStartOfWillMount).toEqual(
instance._testJournal.returnedFromGetInitialState
instance._testJournal.returnedFromGetInitialState,
);
expect(instance._testJournal.lifeCycleAtStartOfWillMount)
.toBe('UNMOUNTED');
expect(instance._testJournal.lifeCycleAtStartOfWillMount).toBe('UNMOUNTED');
// componentDidMount
expect(instance._testJournal.stateAtStartOfDidMount)
.toEqual(DID_MOUNT_STATE);
expect(instance._testJournal.lifeCycleAtStartOfDidMount).toBe(
'MOUNTED'
expect(instance._testJournal.stateAtStartOfDidMount).toEqual(
DID_MOUNT_STATE,
);
expect(instance._testJournal.lifeCycleAtStartOfDidMount).toBe('MOUNTED');
// initial render
expect(instance._testJournal.stateInInitialRender)
.toEqual(INIT_RENDER_STATE);
expect(instance._testJournal.lifeCycleInInitialRender).toBe(
'UNMOUNTED'
expect(instance._testJournal.stateInInitialRender).toEqual(
INIT_RENDER_STATE,
);
expect(instance._testJournal.lifeCycleInInitialRender).toBe('UNMOUNTED');
expect(getLifeCycleState(instance)).toBe('MOUNTED');
@@ -430,22 +413,18 @@ describe('ReactComponentLifeCycle', () => {
instance.forceUpdate();
// render 2nd time
expect(instance._testJournal.stateInLaterRender)
.toEqual(NEXT_RENDER_STATE);
expect(instance._testJournal.lifeCycleInLaterRender).toBe(
'MOUNTED'
);
expect(instance._testJournal.stateInLaterRender).toEqual(NEXT_RENDER_STATE);
expect(instance._testJournal.lifeCycleInLaterRender).toBe('MOUNTED');
expect(getLifeCycleState(instance)).toBe('MOUNTED');
ReactDOM.unmountComponentAtNode(container);
expect(instance._testJournal.stateAtStartOfWillUnmount)
.toEqual(WILL_UNMOUNT_STATE);
// componentWillUnmount called right before unmount.
expect(instance._testJournal.lifeCycleAtStartOfWillUnmount).toBe(
'MOUNTED'
expect(instance._testJournal.stateAtStartOfWillUnmount).toEqual(
WILL_UNMOUNT_STATE,
);
// componentWillUnmount called right before unmount.
expect(instance._testJournal.lifeCycleAtStartOfWillUnmount).toBe('MOUNTED');
// But the current lifecycle of the component is unmounted.
expect(getLifeCycleState(instance)).toBe('UNMOUNTED');
@@ -453,7 +432,7 @@ describe('ReactComponentLifeCycle', () => {
expectDev(console.error.calls.count()).toBe(1);
expectDev(console.error.calls.argsFor(0)[0]).toContain(
'LifeCycleComponent is accessing isMounted inside its render() function'
'LifeCycleComponent is accessing isMounted inside its render() function',
);
});
@@ -482,9 +461,7 @@ describe('ReactComponentLifeCycle', () => {
class Component extends React.Component {
render() {
return (
<Tooltip
ref="tooltip"
tooltip={<div>{this.props.tooltipText}</div>}>
<Tooltip ref="tooltip" tooltip={<div>{this.props.tooltipText}</div>}>
{this.props.text}
</Tooltip>
);
@@ -492,17 +469,11 @@ describe('ReactComponentLifeCycle', () => {
}
var container = document.createElement('div');
ReactDOM.render(
<Component text="uno" tooltipText="one" />,
container
);
ReactDOM.render(<Component text="uno" tooltipText="one" />, container);
// Since `instance` is a root component, we can set its props. This also
// makes Tooltip rerender the tooltip component, which shouldn't throw.
ReactDOM.render(
<Component text="dos" tooltipText="two" />,
container
);
ReactDOM.render(<Component text="dos" tooltipText="two" />, container);
});
it('should allow state updates in componentDidMount', () => {
@@ -519,15 +490,16 @@ describe('ReactComponentLifeCycle', () => {
}
render() {
return (<div />);
return <div />;
}
}
var instance =
var instance = (
<SetStateInComponentDidMount
valueToUseInitially="hello"
valueToUseInOnDOMReady="goodbye"
/>;
/>
);
instance = ReactTestUtils.renderIntoDocument(instance);
expect(instance.state.stateField).toBe('goodbye');
});
@@ -566,7 +538,6 @@ describe('ReactComponentLifeCycle', () => {
componentWillUnmount: logger('inner componentWillUnmount'),
});
var container = document.createElement('div');
log = [];
ReactDOM.render(<Outer x={17} />, container);
@@ -634,8 +605,8 @@ describe('ReactComponentLifeCycle', () => {
};
const div = document.createElement('div');
ReactDOM.render(<Parent ref={(c) => c && log.push('ref')} />, div);
ReactDOM.render(<Parent ref={(c) => c && log.push('ref')} />, div);
ReactDOM.render(<Parent ref={c => c && log.push('ref')} />, div);
ReactDOM.render(<Parent ref={c => c && log.push('ref')} />, div);
expect(log).toEqual([
'will mount',
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -22,7 +22,6 @@ var ReactPropTypes;
var ReactTestUtils;
describe('ReactCompositeComponent', () => {
beforeEach(() => {
jest.resetModules();
React = require('react');
@@ -42,9 +41,9 @@ describe('ReactCompositeComponent', () => {
render() {
var toggleActivatedState = this._toggleActivatedState;
return !this.state.activated ?
<a ref="x" onClick={toggleActivatedState} /> :
<b ref="x" onClick={toggleActivatedState} />;
return !this.state.activated
? <a ref="x" onClick={toggleActivatedState} />
: <b ref="x" onClick={toggleActivatedState} />;
}
};
@@ -59,9 +58,9 @@ describe('ReactCompositeComponent', () => {
render() {
var className = this.props.anchorClassOn ? 'anchorClass' : '';
return this.props.renderAnchor ?
<a ref="anch" className={className} /> :
<b />;
return this.props.renderAnchor
? <a ref="anch" className={className} />
: <b />;
}
};
});
@@ -139,19 +138,22 @@ describe('ReactCompositeComponent', () => {
var container = document.createElement('div');
var instance = ReactDOM.render(
<ChildUpdates renderAnchor={true} anchorClassOn={false} />,
container
container,
);
ReactDOM.render( // Warm any cache
ReactDOM.render(
// Warm any cache
<ChildUpdates renderAnchor={true} anchorClassOn={true} />,
container
container,
);
ReactDOM.render( // Clear out the anchor
ReactDOM.render(
// Clear out the anchor
<ChildUpdates renderAnchor={false} anchorClassOn={true} />,
container
container,
);
ReactDOM.render( // rerender
ReactDOM.render(
// rerender
<ChildUpdates renderAnchor={true} anchorClassOn={false} />,
container
container,
);
expect(instance.getAnchor().className).toBe('');
});
@@ -188,7 +190,7 @@ describe('ReactCompositeComponent', () => {
expectDev(console.error.calls.count()).toBe(1);
var explicitlyBound = mountedInstance.methodToBeExplicitlyBound.bind(
mountedInstance
mountedInstance,
);
expectDev(console.error.calls.count()).toBe(2);
var autoBound = mountedInstance.methodAutoBound;
@@ -199,7 +201,6 @@ describe('ReactCompositeComponent', () => {
expect(explicitlyBound.call(mountedInstance)).toBe(mountedInstance);
expect(autoBound.call(mountedInstance)).toBe(mountedInstance);
});
it('should not pass this to getDefaultProps', () => {
@@ -227,10 +228,14 @@ describe('ReactCompositeComponent', () => {
var instance1 = ReactTestUtils.renderIntoDocument(<Component />);
expect(instance1.props).toEqual({prop: 'testKey'});
var instance2 = ReactTestUtils.renderIntoDocument(<Component prop={undefined} />);
var instance2 = ReactTestUtils.renderIntoDocument(
<Component prop={undefined} />,
);
expect(instance2.props).toEqual({prop: 'testKey'});
var instance3 = ReactTestUtils.renderIntoDocument(<Component prop={null} />);
var instance3 = ReactTestUtils.renderIntoDocument(
<Component prop={null} />,
);
expect(instance3.props).toEqual({prop: null});
});
@@ -279,9 +284,9 @@ describe('ReactCompositeComponent', () => {
expectDev(console.error.calls.count()).toBe(1);
expectDev(console.error.calls.argsFor(0)[0]).toContain(
'Can only update a mounted or mounting component. This usually means ' +
'you called setState, replaceState, or forceUpdate on an unmounted ' +
'component. This is a no-op.\n\nPlease check the code for the ' +
'Component component.'
'you called setState, replaceState, or forceUpdate on an unmounted ' +
'component. This is a no-op.\n\nPlease check the code for the ' +
'Component component.',
);
});
@@ -323,9 +328,9 @@ describe('ReactCompositeComponent', () => {
expectDev(console.error.calls.count()).toBe(1);
expectDev(console.error.calls.argsFor(0)[0]).toContain(
'Can only update a mounted or mounting component. This usually means ' +
'you called setState, replaceState, or forceUpdate on an unmounted ' +
'component. This is a no-op.\n\nPlease check the code for the ' +
'Component component.'
'you called setState, replaceState, or forceUpdate on an unmounted ' +
'component. This is a no-op.\n\nPlease check the code for the ' +
'Component component.',
);
});
@@ -357,7 +362,6 @@ describe('ReactCompositeComponent', () => {
expect(cbCalled).toBe(false);
});
it('should warn about `setState` in render', () => {
spyOn(console, 'error');
@@ -373,7 +377,7 @@ describe('ReactCompositeComponent', () => {
renderPasses++;
renderedState = this.state.value;
if (this.state.value === 0) {
this.setState({ value: 1 });
this.setState({value: 1});
}
return <div />;
}
@@ -386,9 +390,9 @@ describe('ReactCompositeComponent', () => {
expectDev(console.error.calls.count()).toBe(1);
expectDev(console.error.calls.argsFor(0)[0]).toContain(
'Cannot update during an existing state transition (such as within ' +
'`render` or another component\'s constructor). Render methods should ' +
'be a pure function of props and state; constructor side-effects are ' +
'an anti-pattern, but can be moved to `componentWillMount`.'
"`render` or another component's constructor). Render methods should " +
'be a pure function of props and state; constructor side-effects are ' +
'an anti-pattern, but can be moved to `componentWillMount`.',
);
// The setState call is queued and then executed as a second pass. This
@@ -417,7 +421,7 @@ describe('ReactCompositeComponent', () => {
getChildContext() {
if (this.state.value === 0) {
this.setState({ value: 1 });
this.setState({value: 1});
}
}
@@ -434,7 +438,7 @@ describe('ReactCompositeComponent', () => {
expect(instance.state.value).toBe(1);
expectDev(console.error.calls.count()).toBe(1);
expectDev(console.error.calls.argsFor(0)[0]).toBe(
'Warning: setState(...): Cannot call setState() inside getChildContext()'
'Warning: setState(...): Cannot call setState() inside getChildContext()',
);
});
@@ -507,7 +511,7 @@ describe('ReactCompositeComponent', () => {
expectDev(console.error.calls.count()).toBe(1);
expectDev(console.error.calls.argsFor(0)[0]).toBe(
'Warning: Component.shouldComponentUpdate(): Returned undefined instead of a ' +
'boolean value. Make sure to return true or false.'
'boolean value. Make sure to return true or false.',
);
});
@@ -515,8 +519,7 @@ describe('ReactCompositeComponent', () => {
spyOn(console, 'error');
class Component extends React.Component {
componentDidUnmount = () => {
};
componentDidUnmount = () => {};
render() {
return <div />;
@@ -528,8 +531,8 @@ describe('ReactCompositeComponent', () => {
expectDev(console.error.calls.count()).toBe(1);
expectDev(console.error.calls.argsFor(0)[0]).toBe(
'Warning: Component has a method called ' +
'componentDidUnmount(). But there is no such lifecycle method. ' +
'Did you mean componentWillUnmount()?'
'componentDidUnmount(). But there is no such lifecycle method. ' +
'Did you mean componentWillUnmount()?',
);
});
@@ -639,7 +642,7 @@ describe('ReactCompositeComponent', () => {
}
parentInstance = ReactTestUtils.renderIntoDocument(
<Parent><Middle><Child /></Middle></Parent>
<Parent><Middle><Child /></Middle></Parent>,
);
expect(parentInstance.state.flag).toBe(false);
@@ -691,10 +694,7 @@ describe('ReactCompositeComponent', () => {
}
}
var wrapper = ReactTestUtils.renderIntoDocument(
<Wrapper />
);
var wrapper = ReactTestUtils.renderIntoDocument(<Wrapper />);
expect(wrapper.refs.parent.state.flag).toEqual(true);
expect(wrapper.refs.child.context).toEqual({flag: true});
@@ -999,7 +999,7 @@ describe('ReactCompositeComponent', () => {
<GrandChild>B2</GrandChild>
</ChildWithContext>
</Parent>,
div
div,
);
parentInstance.setState({
@@ -1030,9 +1030,9 @@ describe('ReactCompositeComponent', () => {
expectDev(console.error.calls.count()).toBe(1);
expectDev(console.error.calls.argsFor(0)[0]).toMatch(
'Render methods should be a pure function of props and state; ' +
'triggering nested component updates from render is not allowed. If ' +
'necessary, trigger nested updates in componentDidUpdate.\n\nCheck the ' +
'render method of Outer.'
'triggering nested component updates from render is not allowed. If ' +
'necessary, trigger nested updates in componentDidUpdate.\n\nCheck the ' +
'render method of Outer.',
);
});
@@ -1295,7 +1295,7 @@ describe('ReactCompositeComponent', () => {
class Foo extends React.Component {
constructor(props) {
var _props = { idx: props.idx + '!' };
var _props = {idx: props.idx + '!'};
super(_props);
}
@@ -1311,9 +1311,8 @@ describe('ReactCompositeComponent', () => {
expectDev(console.error.calls.count()).toBe(1);
expectDev(console.error.calls.argsFor(0)[0]).toContain(
'Foo(...): When calling super() in `Foo`, make sure to pass ' +
'up the same props that your component\'s constructor was passed.'
"up the same props that your component's constructor was passed.",
);
});
it('should only call componentWillUnmount once', () => {
@@ -1344,7 +1343,7 @@ describe('ReactCompositeComponent', () => {
var container = document.createElement('div');
var setRef = (ref) => {
var setRef = ref => {
if (ref) {
app = ref;
}
@@ -1397,5 +1396,4 @@ describe('ReactCompositeComponent', () => {
'B componentDidMount',
]);
});
});
@@ -28,7 +28,6 @@ var expectSingleChildlessDiv;
* nodes.
*/
describe('ReactCompositeComponentDOMMinimalism', () => {
beforeEach(() => {
React = require('react');
ReactDOM = require('react-dom');
@@ -96,5 +95,4 @@ describe('ReactCompositeComponentDOMMinimalism', () => {
expect(el.children[0].tagName).toBe('UL');
expect(el.children[0].children.length).toBe(0);
});
});
@@ -16,7 +16,6 @@ var ReactDOM;
var ReactTestUtils;
describe('ReactCompositeComponentNestedState-state', () => {
beforeEach(() => {
React = require('react');
ReactDOM = require('react-dom');
@@ -27,7 +26,7 @@ describe('ReactCompositeComponentNestedState-state', () => {
class ParentComponent extends React.Component {
state = {color: 'blue'};
handleColor = (color) => {
handleColor = color => {
this.props.logger('parent-handleColor', this.state.color);
this.setState({color: color}, function() {
this.props.logger('parent-after-setState', this.state.color);
@@ -56,13 +55,24 @@ describe('ReactCompositeComponentNestedState-state', () => {
handleHue = (shade, color) => {
this.props.logger('handleHue', this.state.hue, this.props.color);
this.props.onSelectColor(color);
this.setState(function(state, props) {
this.props.logger('setState-this', this.state.hue, this.props.color);
this.props.logger('setState-args', state.hue, props.color);
return {hue: shade + ' ' + props.color};
}, function() {
this.props.logger('after-setState', this.state.hue, this.props.color);
});
this.setState(
function(state, props) {
this.props.logger(
'setState-this',
this.state.hue,
this.props.color,
);
this.props.logger('setState-args', state.hue, props.color);
return {hue: shade + ' ' + props.color};
},
function() {
this.props.logger(
'after-setState',
this.state.hue,
this.props.color,
);
},
);
};
render() {
@@ -91,15 +101,10 @@ describe('ReactCompositeComponentNestedState-state', () => {
var logger = jest.fn();
void ReactDOM.render(
<ParentComponent logger={logger} />,
container
);
void ReactDOM.render(<ParentComponent logger={logger} />, container);
// click "light green"
ReactTestUtils.Simulate.click(
container.childNodes[0].childNodes[3]
);
ReactTestUtils.Simulate.click(container.childNodes[0].childNodes[3]);
expect(logger.mock.calls).toEqual([
['parent-render', 'blue'],
@@ -18,7 +18,6 @@ var ReactDOMFeatureFlags;
var TestComponent;
describe('ReactCompositeComponent-state', () => {
beforeEach(() => {
React = require('react');
@@ -38,7 +37,7 @@ describe('ReactCompositeComponent-state', () => {
setFavoriteColor: function(nextColor) {
this.setState(
{color: nextColor},
this.peekAtCallback('setFavoriteColor')
this.peekAtCallback('setFavoriteColor'),
);
},
@@ -59,7 +58,7 @@ describe('ReactCompositeComponent-state', () => {
});
this.setState(
{color: 'sunrise'},
this.peekAtCallback('setState-sunrise')
this.peekAtCallback('setState-sunrise'),
);
this.setState(function(state) {
this.peekAtState('after-setState-sunrise', state);
@@ -67,7 +66,7 @@ describe('ReactCompositeComponent-state', () => {
this.peekAtState('componentWillMount-after-sunrise');
this.setState(
{color: 'orange'},
this.peekAtCallback('setState-orange')
this.peekAtCallback('setState-orange'),
);
this.setState(function(state) {
this.peekAtState('after-setState-orange', state);
@@ -79,7 +78,7 @@ describe('ReactCompositeComponent-state', () => {
this.peekAtState('componentDidMount-start');
this.setState(
{color: 'yellow'},
this.peekAtCallback('setState-yellow')
this.peekAtCallback('setState-yellow'),
);
this.peekAtState('componentDidMount-end');
},
@@ -97,7 +96,7 @@ describe('ReactCompositeComponent-state', () => {
this.peekAtState('before-setState-again-receiveProps', state);
return {color: newProps.nextColor};
},
this.peekAtCallback('setState-receiveProps')
this.peekAtCallback('setState-receiveProps'),
);
this.setState(function(state) {
this.peekAtState('after-setState-receiveProps', state);
@@ -138,12 +137,12 @@ describe('ReactCompositeComponent-state', () => {
container,
function peekAtInitialCallback() {
this.peekAtState('initial-callback');
}
},
);
ReactDOM.render(
<TestComponent stateListener={stateListener} nextColor="green" />,
container,
instance.peekAtCallback('setProps')
instance.peekAtCallback('setProps'),
);
instance.setFavoriteColor('blue');
instance.forceUpdate(instance.peekAtCallback('forceUpdate'));
@@ -191,9 +190,7 @@ describe('ReactCompositeComponent-state', () => {
// from the queue. In Fiber, we keep updates in the queue to support
// replaceState(prevState => newState).
// TODO: Fix Stack to match Fiber.
expected.push(
['before-setState-receiveProps', 'yellow'],
);
expected.push(['before-setState-receiveProps', 'yellow']);
}
expected.push(
@@ -232,7 +229,6 @@ describe('ReactCompositeComponent-state', () => {
expect(stateListener.mock.calls.join('\n')).toEqual(expected.join('\n'));
});
it('should call componentDidUpdate of children first', () => {
var container = document.createElement('div');
@@ -242,7 +238,7 @@ describe('ReactCompositeComponent-state', () => {
var parent = null;
class Child extends React.Component {
state = {bar:false};
state = {bar: false};
componentDidMount() {
child = this;
}
@@ -266,7 +262,7 @@ describe('ReactCompositeComponent-state', () => {
}
class Parent extends React.Component {
state = {foo:false};
state = {foo: false};
componentDidMount() {
parent = this;
}
@@ -281,40 +277,36 @@ describe('ReactCompositeComponent-state', () => {
ReactDOM.render(<Parent />, container);
ReactDOM.unstable_batchedUpdates(() => {
parent.setState({ foo: true });
child.setState({ bar: true });
parent.setState({foo: true});
child.setState({bar: true});
});
// When we render changes top-down in a batch, children's componentDidUpdate
// happens before the parent.
expect(ops).toEqual([
'child did update',
'parent did update',
]);
expect(ops).toEqual(['child did update', 'parent did update']);
shouldUpdate = false;
ops = [];
ReactDOM.unstable_batchedUpdates(() => {
parent.setState({ foo: false });
child.setState({ bar: false });
parent.setState({foo: false});
child.setState({bar: false});
});
// We expect the same thing to happen if we bail out in the middle.
expect(ops).toEqual(
ReactDOMFeatureFlags.useFiber
? [
// Fiber works as expected
'child did update',
'parent did update',
]
// Fiber works as expected
'child did update',
'parent did update',
]
: [
// Stack treats these as two separate updates and therefore the order
// is inverse.
'parent did update',
'child did update',
]
// Stack treats these as two separate updates and therefore the order
// is inverse.
'parent did update',
'child did update',
],
);
});
it('should batch unmounts', () => {
@@ -396,8 +388,10 @@ describe('ReactCompositeComponent-state', () => {
}
shouldComponentUpdate(nextProps, nextState) {
log.push(
'scu from ' + Object.keys(this.state) +
' to ' + Object.keys(nextState)
'scu from ' +
Object.keys(this.state) +
' to ' +
Object.keys(nextState),
);
return false;
}
@@ -409,10 +403,7 @@ describe('ReactCompositeComponent-state', () => {
expect(log.length).toBe(1);
test.setState({c: 0});
expect(log.length).toBe(2);
expect(log).toEqual([
'scu from a to a,b',
'scu from a,b to a,b,c',
]);
expect(log).toEqual(['scu from a to a,b', 'scu from a,b to a,b,c']);
});
it('should treat assigning to this.state inside cWRP as a replaceState, with a warning', () => {
@@ -420,17 +411,21 @@ describe('ReactCompositeComponent-state', () => {
let ops = [];
class Test extends React.Component {
state = { step: 1, extra: true };
state = {step: 1, extra: true};
componentWillReceiveProps() {
this.setState({ step: 2 }, () => {
this.setState({step: 2}, () => {
// Tests that earlier setState callbacks are not dropped
ops.push(`callback -- step: ${this.state.step}, extra: ${!!this.state.extra}`);
ops.push(
`callback -- step: ${this.state.step}, extra: ${!!this.state.extra}`,
);
});
// Treat like replaceState
this.state = { step: 3 };
this.state = {step: 3};
}
render() {
ops.push(`render -- step: ${this.state.step}, extra: ${!!this.state.extra}`);
ops.push(
`render -- step: ${this.state.step}, extra: ${!!this.state.extra}`,
);
return null;
}
}
@@ -449,8 +444,8 @@ describe('ReactCompositeComponent-state', () => {
expect(console.error.calls.count()).toEqual(1);
expect(console.error.calls.argsFor(0)[0]).toEqual(
'Warning: Test.componentWillReceiveProps(): Assigning directly to ' +
'this.state is deprecated (except inside a component\'s constructor). ' +
'Use setState instead.'
"this.state is deprecated (except inside a component's constructor). " +
'Use setState instead.',
);
});
});
@@ -80,21 +80,17 @@ describe('ReactEmptyComponent', () => {
ReactTestUtils.renderIntoDocument(<Component />);
}).toThrowError(
'Component.render(): A valid React element (or null) must be returned. You may ' +
'have returned undefined, an array or some other invalid object.'
'have returned undefined, an array or some other invalid object.',
);
});
it('should be able to switch between rendering null and a normal tag', () => {
var instance1 =
<TogglingComponent
firstComponent={null}
secondComponent={'div'}
/>;
var instance2 =
<TogglingComponent
firstComponent={'div'}
secondComponent={null}
/>;
var instance1 = (
<TogglingComponent firstComponent={null} secondComponent={'div'} />
);
var instance2 = (
<TogglingComponent firstComponent={'div'} secondComponent={null} />
);
ReactTestUtils.renderIntoDocument(instance1);
ReactTestUtils.renderIntoDocument(instance2);
@@ -107,18 +103,16 @@ describe('ReactEmptyComponent', () => {
});
it('should be able to switch in a list of children', () => {
var instance1 =
<TogglingComponent
firstComponent={null}
secondComponent={'div'}
/>;
var instance1 = (
<TogglingComponent firstComponent={null} secondComponent={'div'} />
);
ReactTestUtils.renderIntoDocument(
<div>
{instance1}
{instance1}
{instance1}
</div>
</div>,
);
expect(log.calls.count()).toBe(6);
@@ -130,36 +124,31 @@ describe('ReactEmptyComponent', () => {
expect(log.calls.argsFor(5)[0].tagName).toBe('DIV');
});
it('should distinguish between a script placeholder and an actual script tag',
() => {
var instance1 =
<TogglingComponent
firstComponent={null}
secondComponent={'script'}
/>;
var instance2 =
<TogglingComponent
firstComponent={'script'}
secondComponent={null}
/>;
it('should distinguish between a script placeholder and an actual script tag', () => {
var instance1 = (
<TogglingComponent firstComponent={null} secondComponent={'script'} />
);
var instance2 = (
<TogglingComponent firstComponent={'script'} secondComponent={null} />
);
expect(function() {
ReactTestUtils.renderIntoDocument(instance1);
}).not.toThrow();
expect(function() {
ReactTestUtils.renderIntoDocument(instance2);
}).not.toThrow();
expect(function() {
ReactTestUtils.renderIntoDocument(instance1);
}).not.toThrow();
expect(function() {
ReactTestUtils.renderIntoDocument(instance2);
}).not.toThrow();
expect(log.calls.count()).toBe(4);
expect(log.calls.argsFor(0)[0]).toBe(null);
expect(log.calls.argsFor(1)[0].tagName).toBe('SCRIPT');
expect(log.calls.argsFor(2)[0].tagName).toBe('SCRIPT');
expect(log.calls.argsFor(3)[0]).toBe(null);
}
);
expect(log.calls.count()).toBe(4);
expect(log.calls.argsFor(0)[0]).toBe(null);
expect(log.calls.argsFor(1)[0].tagName).toBe('SCRIPT');
expect(log.calls.argsFor(2)[0].tagName).toBe('SCRIPT');
expect(log.calls.argsFor(3)[0]).toBe(null);
});
it('should have findDOMNode return null when multiple layers of composite ' +
'components render to the same null placeholder',
it(
'should have findDOMNode return null when multiple layers of composite ' +
'components render to the same null placeholder',
() => {
class GrandChild extends React.Component {
render() {
@@ -173,16 +162,12 @@ describe('ReactEmptyComponent', () => {
}
}
var instance1 =
<TogglingComponent
firstComponent={'div'}
secondComponent={Child}
/>;
var instance2 =
<TogglingComponent
firstComponent={Child}
secondComponent={'div'}
/>;
var instance1 = (
<TogglingComponent firstComponent={'div'} secondComponent={Child} />
);
var instance2 = (
<TogglingComponent firstComponent={Child} secondComponent={'div'} />
);
expect(function() {
ReactTestUtils.renderIntoDocument(instance1);
@@ -196,7 +181,7 @@ describe('ReactEmptyComponent', () => {
expect(log.calls.argsFor(1)[0]).toBe(null);
expect(log.calls.argsFor(2)[0]).toBe(null);
expect(log.calls.argsFor(3)[0].tagName).toBe('DIV');
}
},
);
it('works when switching components', () => {
@@ -259,9 +244,7 @@ describe('ReactEmptyComponent', () => {
// Stack does not implement this.
expect(function() {
ReactDOM.render(null, div);
}).toThrowError(
'ReactDOM.render(): Invalid component element.'
);
}).toThrowError('ReactDOM.render(): Invalid component element.');
}
} finally {
ReactFeatureFlags.disableNewFiberFeatures = true;
File diff suppressed because it is too large Load Diff
@@ -51,13 +51,15 @@ describeStack('ReactHostOperationHistoryHook', () => {
ReactDOM.render(<div><p>Hi.</p></div>, node);
var inst = ReactDOMComponentTree.getInstanceFromNode(node.firstChild);
assertHistoryMatches([{
instanceID: inst._debugID,
type: 'mount',
payload: ReactDOMFeatureFlags.useCreateElement ?
'DIV' :
'<div data-reactroot="" data-reactid="1"><p data-reactid="2">Hi.</p></div>',
}]);
assertHistoryMatches([
{
instanceID: inst._debugID,
type: 'mount',
payload: ReactDOMFeatureFlags.useCreateElement
? 'DIV'
: '<div data-reactroot="" data-reactid="1"><p data-reactid="2">Hi.</p></div>',
},
]);
});
it('gets recorded for composite roots', () => {
@@ -70,14 +72,16 @@ describeStack('ReactHostOperationHistoryHook', () => {
ReactDOM.render(<Foo />, node);
var inst = ReactDOMComponentTree.getInstanceFromNode(node.firstChild);
assertHistoryMatches([{
instanceID: inst._debugID,
type: 'mount',
payload: ReactDOMFeatureFlags.useCreateElement ?
'DIV' :
'<div data-reactroot="" data-reactid="1">' +
'<p data-reactid="2">Hi.</p></div>',
}]);
assertHistoryMatches([
{
instanceID: inst._debugID,
type: 'mount',
payload: ReactDOMFeatureFlags.useCreateElement
? 'DIV'
: '<div data-reactroot="" data-reactid="1">' +
'<p data-reactid="2">Hi.</p></div>',
},
]);
});
it('gets ignored for composite roots that return null', () => {
@@ -111,11 +115,13 @@ describeStack('ReactHostOperationHistoryHook', () => {
// Since empty components should be invisible to hooks,
// we record a "mount" event rather than a "replace with".
assertHistoryMatches([{
instanceID: inst._debugID,
type: 'mount',
payload: 'SPAN',
}]);
assertHistoryMatches([
{
instanceID: inst._debugID,
type: 'mount',
payload: 'SPAN',
},
]);
});
});
@@ -124,32 +130,42 @@ describeStack('ReactHostOperationHistoryHook', () => {
var node = document.createElement('div');
ReactHostOperationHistoryHook._preventClearing = true;
ReactDOM.render(<div style={{
color: 'red',
backgroundColor: 'yellow',
}} />, node);
ReactDOM.render(
<div
style={{
color: 'red',
backgroundColor: 'yellow',
}}
/>,
node,
);
var inst = ReactDOMComponentTree.getInstanceFromNode(node.firstChild);
if (ReactDOMFeatureFlags.useCreateElement) {
assertHistoryMatches([{
instanceID: inst._debugID,
type: 'update styles',
payload: {
color: 'red',
backgroundColor: 'yellow',
assertHistoryMatches([
{
instanceID: inst._debugID,
type: 'update styles',
payload: {
color: 'red',
backgroundColor: 'yellow',
},
},
}, {
instanceID: inst._debugID,
type: 'mount',
payload: 'DIV',
}]);
{
instanceID: inst._debugID,
type: 'mount',
payload: 'DIV',
},
]);
} else {
assertHistoryMatches([{
instanceID: inst._debugID,
type: 'mount',
payload: '<div style="color:red;background-color:yellow;" ' +
'data-reactroot="" data-reactid="1"></div>',
}]);
assertHistoryMatches([
{
instanceID: inst._debugID,
type: 'mount',
payload: '<div style="color:red;background-color:yellow;" ' +
'data-reactroot="" data-reactid="1"></div>',
},
]);
}
});
@@ -159,31 +175,41 @@ describeStack('ReactHostOperationHistoryHook', () => {
var inst = ReactDOMComponentTree.getInstanceFromNode(node.firstChild);
ReactHostOperationHistoryHook._preventClearing = true;
ReactDOM.render(<div style={{ color: 'red' }} />, node);
ReactDOM.render(<div style={{
color: 'blue',
backgroundColor: 'yellow',
}} />, node);
ReactDOM.render(<div style={{ backgroundColor: 'green' }} />, node);
ReactDOM.render(<div style={{color: 'red'}} />, node);
ReactDOM.render(
<div
style={{
color: 'blue',
backgroundColor: 'yellow',
}}
/>,
node,
);
ReactDOM.render(<div style={{backgroundColor: 'green'}} />, node);
ReactDOM.render(<div />, node);
assertHistoryMatches([{
instanceID: inst._debugID,
type: 'update styles',
payload: { color: 'red' },
}, {
instanceID: inst._debugID,
type: 'update styles',
payload: { color: 'blue', backgroundColor: 'yellow' },
}, {
instanceID: inst._debugID,
type: 'update styles',
payload: { color: '', backgroundColor: 'green' },
}, {
instanceID: inst._debugID,
type: 'update styles',
payload: { backgroundColor: '' },
}]);
assertHistoryMatches([
{
instanceID: inst._debugID,
type: 'update styles',
payload: {color: 'red'},
},
{
instanceID: inst._debugID,
type: 'update styles',
payload: {color: 'blue', backgroundColor: 'yellow'},
},
{
instanceID: inst._debugID,
type: 'update styles',
payload: {color: '', backgroundColor: 'green'},
},
{
instanceID: inst._debugID,
type: 'update styles',
payload: {backgroundColor: ''},
},
]);
});
it('gets ignored if the styles are shallowly equal', () => {
@@ -192,23 +218,35 @@ describeStack('ReactHostOperationHistoryHook', () => {
var inst = ReactDOMComponentTree.getInstanceFromNode(node.firstChild);
ReactHostOperationHistoryHook._preventClearing = true;
ReactDOM.render(<div style={{
color: 'red',
backgroundColor: 'yellow',
}} />, node);
ReactDOM.render(<div style={{
color: 'red',
backgroundColor: 'yellow',
}} />, node);
ReactDOM.render(
<div
style={{
color: 'red',
backgroundColor: 'yellow',
}}
/>,
node,
);
ReactDOM.render(
<div
style={{
color: 'red',
backgroundColor: 'yellow',
}}
/>,
node,
);
assertHistoryMatches([{
instanceID: inst._debugID,
type: 'update styles',
payload: {
color: 'red',
backgroundColor: 'yellow',
assertHistoryMatches([
{
instanceID: inst._debugID,
type: 'update styles',
payload: {
color: 'red',
backgroundColor: 'yellow',
},
},
}]);
]);
});
});
@@ -222,26 +260,32 @@ describeStack('ReactHostOperationHistoryHook', () => {
var inst = ReactDOMComponentTree.getInstanceFromNode(node.firstChild);
if (ReactDOMFeatureFlags.useCreateElement) {
assertHistoryMatches([{
instanceID: inst._debugID,
type: 'update attribute',
payload: { className: 'rad' },
}, {
instanceID: inst._debugID,
type: 'update attribute',
payload: { tabIndex: 42 },
}, {
instanceID: inst._debugID,
type: 'mount',
payload: 'DIV',
}]);
assertHistoryMatches([
{
instanceID: inst._debugID,
type: 'update attribute',
payload: {className: 'rad'},
},
{
instanceID: inst._debugID,
type: 'update attribute',
payload: {tabIndex: 42},
},
{
instanceID: inst._debugID,
type: 'mount',
payload: 'DIV',
},
]);
} else {
assertHistoryMatches([{
instanceID: inst._debugID,
type: 'mount',
payload: '<div class="rad" tabindex="42" data-reactroot="" ' +
'data-reactid="1"></div>',
}]);
assertHistoryMatches([
{
instanceID: inst._debugID,
type: 'mount',
payload: '<div class="rad" tabindex="42" data-reactroot="" ' +
'data-reactid="1"></div>',
},
]);
}
});
@@ -255,27 +299,33 @@ describeStack('ReactHostOperationHistoryHook', () => {
ReactDOM.render(<div className="mad" tabIndex={42} />, node);
ReactDOM.render(<div tabIndex={43} />, node);
assertHistoryMatches([{
instanceID: inst._debugID,
type: 'update attribute',
payload: { className: 'rad' },
}, {
instanceID: inst._debugID,
type: 'update attribute',
payload: { className: 'mad' },
}, {
instanceID: inst._debugID,
type: 'update attribute',
payload: { tabIndex: 42 },
}, {
instanceID: inst._debugID,
type: 'remove attribute',
payload: 'className',
}, {
instanceID: inst._debugID,
type: 'update attribute',
payload: { tabIndex: 43 },
}]);
assertHistoryMatches([
{
instanceID: inst._debugID,
type: 'update attribute',
payload: {className: 'rad'},
},
{
instanceID: inst._debugID,
type: 'update attribute',
payload: {className: 'mad'},
},
{
instanceID: inst._debugID,
type: 'update attribute',
payload: {tabIndex: 42},
},
{
instanceID: inst._debugID,
type: 'remove attribute',
payload: 'className',
},
{
instanceID: inst._debugID,
type: 'update attribute',
payload: {tabIndex: 43},
},
]);
});
});
@@ -289,15 +339,18 @@ describeStack('ReactHostOperationHistoryHook', () => {
ReactDOM.render(<div disabled={true} />, node);
ReactDOM.render(<div disabled={false} />, node);
assertHistoryMatches([{
instanceID: inst._debugID,
type: 'update attribute',
payload: { disabled: true },
}, {
instanceID: inst._debugID,
type: 'remove attribute',
payload: 'disabled',
}]);
assertHistoryMatches([
{
instanceID: inst._debugID,
type: 'update attribute',
payload: {disabled: true},
},
{
instanceID: inst._debugID,
type: 'remove attribute',
payload: 'disabled',
},
]);
});
});
@@ -310,26 +363,32 @@ describeStack('ReactHostOperationHistoryHook', () => {
var inst = ReactDOMComponentTree.getInstanceFromNode(node.firstChild);
if (ReactDOMFeatureFlags.useCreateElement) {
assertHistoryMatches([{
instanceID: inst._debugID,
type: 'update attribute',
payload: { 'data-x': 'rad' },
}, {
instanceID: inst._debugID,
type: 'update attribute',
payload: { 'data-y': 42 },
}, {
instanceID: inst._debugID,
type: 'mount',
payload: 'DIV',
}]);
assertHistoryMatches([
{
instanceID: inst._debugID,
type: 'update attribute',
payload: {'data-x': 'rad'},
},
{
instanceID: inst._debugID,
type: 'update attribute',
payload: {'data-y': 42},
},
{
instanceID: inst._debugID,
type: 'mount',
payload: 'DIV',
},
]);
} else {
assertHistoryMatches([{
instanceID: inst._debugID,
type: 'mount',
payload: '<div data-x="rad" data-y="42" data-reactroot="" ' +
'data-reactid="1"></div>',
}]);
assertHistoryMatches([
{
instanceID: inst._debugID,
type: 'mount',
payload: '<div data-x="rad" data-y="42" data-reactroot="" ' +
'data-reactid="1"></div>',
},
]);
}
});
@@ -343,27 +402,33 @@ describeStack('ReactHostOperationHistoryHook', () => {
ReactDOM.render(<div data-x="mad" data-y={42} />, node);
ReactDOM.render(<div data-y={43} />, node);
assertHistoryMatches([{
instanceID: inst._debugID,
type: 'update attribute',
payload: { 'data-x': 'rad' },
}, {
instanceID: inst._debugID,
type: 'update attribute',
payload: { 'data-x': 'mad' },
}, {
instanceID: inst._debugID,
type: 'update attribute',
payload: { 'data-y': 42 },
}, {
instanceID: inst._debugID,
type: 'remove attribute',
payload: 'data-x',
}, {
instanceID: inst._debugID,
type: 'update attribute',
payload: { 'data-y': 43 },
}]);
assertHistoryMatches([
{
instanceID: inst._debugID,
type: 'update attribute',
payload: {'data-x': 'rad'},
},
{
instanceID: inst._debugID,
type: 'update attribute',
payload: {'data-x': 'mad'},
},
{
instanceID: inst._debugID,
type: 'update attribute',
payload: {'data-y': 42},
},
{
instanceID: inst._debugID,
type: 'remove attribute',
payload: 'data-x',
},
{
instanceID: inst._debugID,
type: 'update attribute',
payload: {'data-y': 43},
},
]);
});
});
@@ -376,26 +441,32 @@ describeStack('ReactHostOperationHistoryHook', () => {
var inst = ReactDOMComponentTree.getInstanceFromNode(node.firstChild);
if (ReactDOMFeatureFlags.useCreateElement) {
assertHistoryMatches([{
instanceID: inst._debugID,
type: 'update attribute',
payload: { className: 'rad' },
}, {
instanceID: inst._debugID,
type: 'update attribute',
payload: { tabIndex: 42 },
}, {
instanceID: inst._debugID,
type: 'mount',
payload: 'MY-COMPONENT',
}]);
assertHistoryMatches([
{
instanceID: inst._debugID,
type: 'update attribute',
payload: {className: 'rad'},
},
{
instanceID: inst._debugID,
type: 'update attribute',
payload: {tabIndex: 42},
},
{
instanceID: inst._debugID,
type: 'mount',
payload: 'MY-COMPONENT',
},
]);
} else {
assertHistoryMatches([{
instanceID: inst._debugID,
type: 'mount',
payload: '<my-component className="rad" tabIndex="42" ' +
'data-reactroot="" data-reactid="1"></my-component>',
}]);
assertHistoryMatches([
{
instanceID: inst._debugID,
type: 'mount',
payload: '<my-component className="rad" tabIndex="42" ' +
'data-reactroot="" data-reactid="1"></my-component>',
},
]);
}
});
@@ -409,27 +480,33 @@ describeStack('ReactHostOperationHistoryHook', () => {
ReactDOM.render(<my-component className="mad" tabIndex={42} />, node);
ReactDOM.render(<my-component tabIndex={43} />, node);
assertHistoryMatches([{
instanceID: inst._debugID,
type: 'update attribute',
payload: { className: 'rad' },
}, {
instanceID: inst._debugID,
type: 'update attribute',
payload: { className: 'mad' },
}, {
instanceID: inst._debugID,
type: 'update attribute',
payload: { tabIndex: 42 },
}, {
instanceID: inst._debugID,
type: 'remove attribute',
payload: 'className',
}, {
instanceID: inst._debugID,
type: 'update attribute',
payload: { tabIndex: 43 },
}]);
assertHistoryMatches([
{
instanceID: inst._debugID,
type: 'update attribute',
payload: {className: 'rad'},
},
{
instanceID: inst._debugID,
type: 'update attribute',
payload: {className: 'mad'},
},
{
instanceID: inst._debugID,
type: 'update attribute',
payload: {tabIndex: 42},
},
{
instanceID: inst._debugID,
type: 'remove attribute',
payload: 'className',
},
{
instanceID: inst._debugID,
type: 'update attribute',
payload: {tabIndex: 43},
},
]);
});
});
});
@@ -444,26 +521,33 @@ describeStack('ReactHostOperationHistoryHook', () => {
ReactHostOperationHistoryHook._preventClearing = true;
ReactDOM.render(<div>Bye.</div>, node);
assertHistoryMatches([{
instanceID: inst._debugID,
type: 'replace text',
payload: 'Bye.',
}]);
assertHistoryMatches([
{
instanceID: inst._debugID,
type: 'replace text',
payload: 'Bye.',
},
]);
});
it('gets recorded during an update from html', () => {
var node = document.createElement('div');
ReactDOM.render(<div dangerouslySetInnerHTML={{__html: 'Hi.'}} />, node);
ReactDOM.render(
<div dangerouslySetInnerHTML={{__html: 'Hi.'}} />,
node,
);
var inst = ReactDOMComponentTree.getInstanceFromNode(node.firstChild);
ReactHostOperationHistoryHook._preventClearing = true;
ReactDOM.render(<div>Bye.</div>, node);
assertHistoryMatches([{
instanceID: inst._debugID,
type: 'replace text',
payload: 'Bye.',
}]);
assertHistoryMatches([
{
instanceID: inst._debugID,
type: 'replace text',
payload: 'Bye.',
},
]);
});
it('gets recorded during an update from children', () => {
@@ -474,19 +558,23 @@ describeStack('ReactHostOperationHistoryHook', () => {
ReactHostOperationHistoryHook._preventClearing = true;
ReactDOM.render(<div>Bye.</div>, node);
assertHistoryMatches([{
instanceID: inst._debugID,
type: 'remove child',
payload: {fromIndex: 0},
}, {
instanceID: inst._debugID,
type: 'remove child',
payload: {fromIndex: 1},
}, {
instanceID: inst._debugID,
type: 'replace text',
payload: 'Bye.',
}]);
assertHistoryMatches([
{
instanceID: inst._debugID,
type: 'remove child',
payload: {fromIndex: 0},
},
{
instanceID: inst._debugID,
type: 'remove child',
payload: {fromIndex: 1},
},
{
instanceID: inst._debugID,
type: 'replace text',
payload: 'Bye.',
},
]);
});
it('gets ignored if new text is equal', () => {
@@ -504,21 +592,28 @@ describeStack('ReactHostOperationHistoryHook', () => {
it('gets recorded during an update', () => {
var node = document.createElement('div');
ReactDOM.render(<div>{'Hi.'}{42}</div>, node);
var inst1 = ReactDOMComponentTree.getInstanceFromNode(node.firstChild.childNodes[0]);
var inst2 = ReactDOMComponentTree.getInstanceFromNode(node.firstChild.childNodes[3]);
var inst1 = ReactDOMComponentTree.getInstanceFromNode(
node.firstChild.childNodes[0],
);
var inst2 = ReactDOMComponentTree.getInstanceFromNode(
node.firstChild.childNodes[3],
);
ReactHostOperationHistoryHook._preventClearing = true;
ReactDOM.render(<div>{'Bye.'}{43}</div>, node);
assertHistoryMatches([{
instanceID: inst1._debugID,
type: 'replace text',
payload: 'Bye.',
}, {
instanceID: inst2._debugID,
type: 'replace text',
payload: '43',
}]);
assertHistoryMatches([
{
instanceID: inst1._debugID,
type: 'replace text',
payload: 'Bye.',
},
{
instanceID: inst2._debugID,
type: 'replace text',
payload: '43',
},
]);
});
it('gets ignored if new text is equal', () => {
@@ -550,11 +645,13 @@ describeStack('ReactHostOperationHistoryHook', () => {
ReactHostOperationHistoryHook._preventClearing = true;
ReactDOM.render(<Foo />, node);
assertHistoryMatches([{
instanceID: inst._debugID,
type: 'replace with',
payload: 'SPAN',
}]);
assertHistoryMatches([
{
instanceID: inst._debugID,
type: 'replace with',
payload: 'SPAN',
},
]);
});
it('gets recorded when composite renders to null after a native', () => {
@@ -573,11 +670,13 @@ describeStack('ReactHostOperationHistoryHook', () => {
ReactHostOperationHistoryHook._preventClearing = true;
ReactDOM.render(<Foo />, node);
assertHistoryMatches([{
instanceID: inst._debugID,
type: 'replace with',
payload: '#comment',
}]);
assertHistoryMatches([
{
instanceID: inst._debugID,
type: 'replace with',
payload: '#comment',
},
]);
});
it('gets ignored if the type has not changed', () => {
@@ -606,37 +705,32 @@ describeStack('ReactHostOperationHistoryHook', () => {
var inst = ReactDOMComponentTree.getInstanceFromNode(node.firstChild);
ReactHostOperationHistoryHook._preventClearing = true;
ReactDOM.render(
<div dangerouslySetInnerHTML={{__html: 'Bye.'}} />,
node
);
ReactDOM.render(<div dangerouslySetInnerHTML={{__html: 'Bye.'}} />, node);
assertHistoryMatches([{
instanceID: inst._debugID,
type: 'replace children',
payload: 'Bye.',
}]);
assertHistoryMatches([
{
instanceID: inst._debugID,
type: 'replace children',
payload: 'Bye.',
},
]);
});
it('gets recorded during an update from html', () => {
var node = document.createElement('div');
ReactDOM.render(
<div dangerouslySetInnerHTML={{__html: 'Hi.'}} />,
node
);
ReactDOM.render(<div dangerouslySetInnerHTML={{__html: 'Hi.'}} />, node);
var inst = ReactDOMComponentTree.getInstanceFromNode(node.firstChild);
ReactHostOperationHistoryHook._preventClearing = true;
ReactDOM.render(
<div dangerouslySetInnerHTML={{__html: 'Bye.'}} />,
node
);
ReactDOM.render(<div dangerouslySetInnerHTML={{__html: 'Bye.'}} />, node);
assertHistoryMatches([{
instanceID: inst._debugID,
type: 'replace children',
payload: 'Bye.',
}]);
assertHistoryMatches([
{
instanceID: inst._debugID,
type: 'replace children',
payload: 'Bye.',
},
]);
});
it('gets recorded during an update from children', () => {
@@ -645,38 +739,33 @@ describeStack('ReactHostOperationHistoryHook', () => {
var inst = ReactDOMComponentTree.getInstanceFromNode(node.firstChild);
ReactHostOperationHistoryHook._preventClearing = true;
ReactDOM.render(
<div dangerouslySetInnerHTML={{__html: 'Hi.'}} />,
node
);
ReactDOM.render(<div dangerouslySetInnerHTML={{__html: 'Hi.'}} />, node);
assertHistoryMatches([{
instanceID: inst._debugID,
type: 'remove child',
payload: {fromIndex: 0},
}, {
instanceID: inst._debugID,
type: 'remove child',
payload: {fromIndex: 1},
}, {
instanceID: inst._debugID,
type: 'replace children',
payload: 'Hi.',
}]);
assertHistoryMatches([
{
instanceID: inst._debugID,
type: 'remove child',
payload: {fromIndex: 0},
},
{
instanceID: inst._debugID,
type: 'remove child',
payload: {fromIndex: 1},
},
{
instanceID: inst._debugID,
type: 'replace children',
payload: 'Hi.',
},
]);
});
it('gets ignored if new html is equal', () => {
var node = document.createElement('div');
ReactDOM.render(
<div dangerouslySetInnerHTML={{__html: 'Hi.'}} />,
node
);
ReactDOM.render(<div dangerouslySetInnerHTML={{__html: 'Hi.'}} />, node);
ReactHostOperationHistoryHook._preventClearing = true;
ReactDOM.render(
<div dangerouslySetInnerHTML={{__html: 'Hi.'}} />,
node
);
ReactDOM.render(<div dangerouslySetInnerHTML={{__html: 'Hi.'}} />, node);
assertHistoryMatches([]);
});
@@ -691,11 +780,13 @@ describeStack('ReactHostOperationHistoryHook', () => {
ReactHostOperationHistoryHook._preventClearing = true;
ReactDOM.render(<div><span /><p /></div>, node);
assertHistoryMatches([{
instanceID: inst._debugID,
type: 'insert child',
payload: {toIndex: 1, content: 'P'},
}]);
assertHistoryMatches([
{
instanceID: inst._debugID,
type: 'insert child',
payload: {toIndex: 1, content: 'P'},
},
]);
});
});
@@ -708,11 +799,13 @@ describeStack('ReactHostOperationHistoryHook', () => {
ReactHostOperationHistoryHook._preventClearing = true;
ReactDOM.render(<div><p key="b" /><span key="a" /></div>, node);
assertHistoryMatches([{
instanceID: inst._debugID,
type: 'move child',
payload: {fromIndex: 0, toIndex: 1},
}]);
assertHistoryMatches([
{
instanceID: inst._debugID,
type: 'move child',
payload: {fromIndex: 0, toIndex: 1},
},
]);
});
});
@@ -725,11 +818,13 @@ describeStack('ReactHostOperationHistoryHook', () => {
ReactHostOperationHistoryHook._preventClearing = true;
ReactDOM.render(<div><span key="a" /></div>, node);
assertHistoryMatches([{
instanceID: inst._debugID,
type: 'remove child',
payload: {fromIndex: 1},
}]);
assertHistoryMatches([
{
instanceID: inst._debugID,
type: 'remove child',
payload: {fromIndex: 1},
},
]);
});
});
});
+14 -28
View File
@@ -17,7 +17,6 @@ var ReactFragment;
var ReactTestUtils;
describe('ReactIdentity', () => {
beforeEach(() => {
jest.resetModules();
React = require('react');
@@ -32,11 +31,12 @@ describe('ReactIdentity', () => {
it('should allow key property to express identity', () => {
var node;
var Component = (props) =>
<div ref={(c) => node = c}>
var Component = props => (
<div ref={c => node = c}>
<div key={props.swap ? 'banana' : 'apple'} />
<div key={props.swap ? 'apple' : 'banana'} />
</div>;
</div>
);
var container = document.createElement('div');
ReactDOM.render(<Component />, container);
@@ -58,12 +58,12 @@ describe('ReactIdentity', () => {
var node1;
var node2;
ReactDOM.render(
<Wrapper key="wrap1"><span ref={(c) => node1 = c} /></Wrapper>,
container
<Wrapper key="wrap1"><span ref={c => node1 = c} /></Wrapper>,
container,
);
ReactDOM.render(
<Wrapper key="wrap2"><span ref={(c) => node2 = c} /></Wrapper>,
container
<Wrapper key="wrap2"><span ref={c => node2 = c} /></Wrapper>,
container,
);
expect(node1).not.toBe(node2);
@@ -91,10 +91,7 @@ describe('ReactIdentity', () => {
it('should allow any character as a key, in a detached parent', () => {
var detachedContainer = document.createElement('div');
renderAComponentWithKeyIntoContainer(
"<'WEIRD/&\\key'>",
detachedContainer
);
renderAComponentWithKeyIntoContainer("<'WEIRD/&\\key'>", detachedContainer);
});
it('should allow any character as a key, in an attached parent', () => {
@@ -103,17 +100,13 @@ describe('ReactIdentity', () => {
var attachedContainer = document.createElement('div');
document.body.appendChild(attachedContainer);
renderAComponentWithKeyIntoContainer(
"<'WEIRD/&\\key'>",
attachedContainer
);
renderAComponentWithKeyIntoContainer("<'WEIRD/&\\key'>", attachedContainer);
document.body.removeChild(attachedContainer);
});
it('should not allow scripts in keys to execute', () => {
var h4x0rKey =
'"><script>window[\'YOUVEBEENH4X0RED\']=true;</script><div id="';
var h4x0rKey = '"><script>window[\'YOUVEBEENH4X0RED\']=true;</script><div id="';
var attachedContainer = document.createElement('div');
document.body.appendChild(attachedContainer);
@@ -150,9 +143,7 @@ describe('ReactIdentity', () => {
}
expect(function() {
ReactTestUtils.renderIntoDocument(<TestContainer />);
}).not.toThrow();
});
@@ -184,9 +175,7 @@ describe('ReactIdentity', () => {
}
expect(function() {
ReactTestUtils.renderIntoDocument(<TestContainer />);
}).not.toThrow();
});
@@ -209,9 +198,7 @@ describe('ReactIdentity', () => {
}
expect(function() {
ReactTestUtils.renderIntoDocument(<TestContainer />);
}).not.toThrow();
});
@@ -258,16 +245,15 @@ describe('ReactIdentity', () => {
});
it('should not allow implicit and explicit keys to collide', () => {
var component =
var component = (
<div>
<span />
<span key="0" />
</div>;
</div>
);
expect(function() {
ReactTestUtils.renderIntoDocument(component);
}).not.toThrow();
});
});
@@ -18,13 +18,16 @@ var AutoMockedComponent;
var MockedComponent;
describe('ReactMockedComponent', () => {
beforeEach(() => {
React = require('react');
ReactTestUtils = require('ReactTestUtils');
AutoMockedComponent = jest.genMockFromModule('ReactMockedComponentTestComponent');
MockedComponent = jest.genMockFromModule('ReactMockedComponentTestComponent');
AutoMockedComponent = jest.genMockFromModule(
'ReactMockedComponentTestComponent',
);
MockedComponent = jest.genMockFromModule(
'ReactMockedComponentTestComponent',
);
ReactTestUtils.mockComponent(MockedComponent);
});
@@ -52,7 +55,7 @@ describe('ReactMockedComponent', () => {
var found = ReactTestUtils.findRenderedComponentWithType(
instance,
AutoMockedComponent
AutoMockedComponent,
);
expect(typeof found).toBe('object');
@@ -85,7 +88,7 @@ describe('ReactMockedComponent', () => {
var found = ReactTestUtils.findRenderedComponentWithType(
instance,
MockedComponent
MockedComponent,
);
expect(typeof found).toBe('object');
@@ -96,5 +99,4 @@ describe('ReactMockedComponent', () => {
var instance = ReactTestUtils.renderIntoDocument(<MockedComponent />);
expect(typeof instance.hasCustomMethod).toBe('function');
});
});
+35 -39
View File
@@ -119,7 +119,7 @@ describe('ReactMultiChild', () => {
ReactDOM.render(
<WrapperComponent><MockComponent /></WrapperComponent>,
container
container,
);
expect(mockMount.mock.calls.length).toBe(1);
@@ -177,25 +177,24 @@ describe('ReactMultiChild', () => {
}
}
ReactDOM.render(
<Parent>{[<div key="1" />]}</Parent>,
container
);
ReactDOM.render(<Parent>{[<div key="1" />]}</Parent>, container);
ReactDOM.render(
<Parent>{[<div key="1" />, <div key="1" />]}</Parent>,
container
container,
);
expectDev(console.error.calls.count()).toBe(1);
expectDev(normalizeCodeLocInfo(console.error.calls.argsFor(0)[0])).toContain(
expectDev(
normalizeCodeLocInfo(console.error.calls.argsFor(0)[0]),
).toContain(
'Encountered two children with the same key, `1`. ' +
'Child keys must be unique; when two children share a key, ' +
'only the first child will be used.\n' +
' in div (at **)\n' +
' in WrapperComponent (at **)\n' +
' in div (at **)\n' +
' in Parent (at **)'
'Child keys must be unique; when two children share a key, ' +
'only the first child will be used.\n' +
' in div (at **)\n' +
' in WrapperComponent (at **)\n' +
' in div (at **)\n' +
' in Parent (at **)',
);
});
@@ -242,23 +241,25 @@ describe('ReactMultiChild', () => {
ReactDOM.render(
<Parent>{createIterable([<div key="1" />])}</Parent>,
container
container,
);
ReactDOM.render(
<Parent>{createIterable([<div key="1" />, <div key="1" />])}</Parent>,
container
container,
);
expectDev(console.error.calls.count()).toBe(1);
expectDev(normalizeCodeLocInfo(console.error.calls.argsFor(0)[0])).toContain(
expectDev(
normalizeCodeLocInfo(console.error.calls.argsFor(0)[0]),
).toContain(
'Encountered two children with the same key, `1`. ' +
'Child keys must be unique; when two children share a key, ' +
'only the first child will be used.\n' +
' in div (at **)\n' +
' in WrapperComponent (at **)\n' +
' in div (at **)\n' +
' in Parent (at **)'
'Child keys must be unique; when two children share a key, ' +
'only the first child will be used.\n' +
' in div (at **)\n' +
' in WrapperComponent (at **)\n' +
' in div (at **)\n' +
' in Parent (at **)',
);
});
});
@@ -267,9 +268,7 @@ describe('ReactMultiChild', () => {
spyOn(console, 'error');
class Parent extends React.Component {
render() {
return (
<div>{new Map([['foo', 0], ['bar', 1]])}</div>
);
return <div>{new Map([['foo', 0], ['bar', 1]])}</div>;
}
}
var container = document.createElement('div');
@@ -277,8 +276,8 @@ describe('ReactMultiChild', () => {
expectDev(console.error.calls.count()).toBe(1);
expectDev(console.error.calls.argsFor(0)[0]).toBe(
'Warning: Using Maps as children is unsupported and will likely yield ' +
'unexpected results. Convert it to a sequence/iterable of keyed ' +
'ReactElements instead.\n\nCheck the render method of `Parent`.'
'unexpected results. Convert it to a sequence/iterable of keyed ' +
'ReactElements instead.\n\nCheck the render method of `Parent`.',
);
});
@@ -303,7 +302,7 @@ describe('ReactMultiChild', () => {
class Letters extends React.Component {
render() {
const letters = this.props.letters.split('');
return <div>{letters.map((c) => <Letter key={c} char={c} />)}</div>;
return <div>{letters.map(c => <Letter key={c} char={c} />)}</div>;
}
}
@@ -337,8 +336,8 @@ describe('ReactMultiChild', () => {
// These are reference-unequal so they will be swapped even if they have
// matching keys
var SpyA = (props) => <Spy {...props} />;
var SpyB = (props) => <Spy {...props} />;
var SpyA = props => <Spy {...props} />;
var SpyB = props => <Spy {...props} />;
var container = document.createElement('div');
ReactDOM.render(
@@ -346,14 +345,14 @@ describe('ReactMultiChild', () => {
<SpyA key="one" name="oneA" />
<SpyA key="two" name="twoA" />
</div>,
container
container,
);
ReactDOM.render(
<div>
<SpyB key="one" name="oneB" />
<SpyB key="two" name="twoB" />
</div>,
container
container,
);
expect(log).toEqual([
@@ -364,9 +363,8 @@ describe('ReactMultiChild', () => {
'oneA componentDidMount',
'twoA componentDidMount',
...(
ReactDOMFeatureFlags.useFiber
? [
...(ReactDOMFeatureFlags.useFiber
? [
'oneB componentWillMount',
'oneB render',
'twoB componentWillMount',
@@ -374,19 +372,17 @@ describe('ReactMultiChild', () => {
'oneA componentWillUnmount',
'twoA componentWillUnmount',
]
: [
: [
'oneB componentWillMount',
'oneB render',
'oneA componentWillUnmount',
'twoB componentWillMount',
'twoB render',
'twoA componentWillUnmount',
]
),
]),
'oneB componentDidMount',
'twoB componentDidMount',
]);
});
});
@@ -119,14 +119,15 @@ class FriendsStatusDisplay extends React.Component {
for (var key in this.props.usernameToStatus) {
var status = this.props.usernameToStatus[key];
children.push(
!status ? null :
<StatusDisplay
key={key}
ref={key}
contentKey={key}
onFlush={this.verifyPreviousRefsResolved.bind(this, key)}
status={status}
/>
!status
? null
: <StatusDisplay
key={key}
ref={key}
contentKey={key}
onFlush={this.verifyPreviousRefsResolved.bind(this, key)}
status={status}
/>,
);
}
var childrenToRender = this.props.prepareChildren(children);
@@ -138,12 +139,14 @@ class FriendsStatusDisplay extends React.Component {
}
}
function getInternalStateByUserName(statusDisplays) {
return Object.keys(statusDisplays).reduce((acc, key) => {
acc[key] = statusDisplays[key].getInternalState();
return acc;
}, {});
return Object.keys(statusDisplays).reduce(
(acc, key) => {
acc[key] = statusDisplays[key].getInternalState();
return acc;
},
{},
);
}
/**
@@ -155,14 +158,16 @@ function verifyStatuses(statusDisplays, props) {
var nonEmptyStatusDisplays = stripEmptyValues(statusDisplays);
var nonEmptyStatusProps = stripEmptyValues(props.usernameToStatus);
var username;
expect(Object.keys(nonEmptyStatusDisplays).length)
.toEqual(Object.keys(nonEmptyStatusProps).length);
expect(Object.keys(nonEmptyStatusDisplays).length).toEqual(
Object.keys(nonEmptyStatusProps).length,
);
for (username in nonEmptyStatusDisplays) {
if (!nonEmptyStatusDisplays.hasOwnProperty(username)) {
continue;
}
expect(nonEmptyStatusDisplays[username].getStatus())
.toEqual(nonEmptyStatusProps[username]);
expect(nonEmptyStatusDisplays[username].getStatus()).toEqual(
nonEmptyStatusProps[username],
);
}
// now go the other way to make sure we got them all.
@@ -170,12 +175,14 @@ function verifyStatuses(statusDisplays, props) {
if (!nonEmptyStatusProps.hasOwnProperty(username)) {
continue;
}
expect(nonEmptyStatusDisplays[username].getStatus())
.toEqual(nonEmptyStatusProps[username]);
expect(nonEmptyStatusDisplays[username].getStatus()).toEqual(
nonEmptyStatusProps[username],
);
}
expect(Object.keys(nonEmptyStatusDisplays))
.toEqual(Object.keys(nonEmptyStatusProps));
expect(Object.keys(nonEmptyStatusDisplays)).toEqual(
Object.keys(nonEmptyStatusProps),
);
}
/**
@@ -191,13 +198,13 @@ function verifyStatesPreserved(lastInternalStates, statusDisplays) {
continue;
}
if (lastInternalStates[key]) {
expect(lastInternalStates[key])
.toEqual(statusDisplays[key].getInternalState());
expect(lastInternalStates[key]).toEqual(
statusDisplays[key].getInternalState(),
);
}
}
}
/**
* Verifies that the internal representation of a set of `renderedChildren`
* accurately reflects what is in the DOM.
@@ -218,9 +225,7 @@ function verifyDomOrderingAccurate(outerContainer, statusDisplays) {
continue;
}
var statusDisplay = statusDisplays[username];
orderedLogicalKeys.push(
statusDisplay.props.contentKey
);
orderedLogicalKeys.push(statusDisplay.props.contentKey);
}
expect(orderedDomKeys).toEqual(orderedLogicalKeys);
}
@@ -228,11 +233,8 @@ function verifyDomOrderingAccurate(outerContainer, statusDisplays) {
function testPropsSequenceWithPreparedChildren(sequence, prepareChildren) {
var container = document.createElement('div');
var parentInstance = ReactDOM.render(
<FriendsStatusDisplay
{...sequence[0]}
prepareChildren={prepareChildren}
/>,
container
<FriendsStatusDisplay {...sequence[0]} prepareChildren={prepareChildren} />,
container,
);
var statusDisplays = parentInstance.getStatusDisplays();
var lastInternalStates = getInternalStateByUserName(statusDisplays);
@@ -244,7 +246,7 @@ function testPropsSequenceWithPreparedChildren(sequence, prepareChildren) {
{...sequence[i]}
prepareChildren={prepareChildren}
/>,
container
container,
);
statusDisplays = parentInstance.getStatusDisplays();
verifyStatuses(statusDisplays, sequence[i]);
@@ -289,8 +291,11 @@ describe('ReactMultiChildReconcile', () => {
var container = document.createElement('div');
var parentInstance = ReactDOM.render(
<FriendsStatusDisplay {...props} prepareChildren={prepareChildrenArray} />,
container
<FriendsStatusDisplay
{...props}
prepareChildren={prepareChildrenArray}
/>,
container,
);
var statusDisplays = parentInstance.getStatusDisplays();
var startingInternalState = statusDisplays.jcw.getInternalState();
@@ -298,20 +303,24 @@ describe('ReactMultiChildReconcile', () => {
// Now remove the child.
ReactDOM.render(
<FriendsStatusDisplay prepareChildren={prepareChildrenArray} />,
container
container,
);
statusDisplays = parentInstance.getStatusDisplays();
expect(statusDisplays.jcw).toBeFalsy();
// Now reset the props that cause there to be a child
ReactDOM.render(
<FriendsStatusDisplay {...props} prepareChildren={prepareChildrenArray} />,
container
<FriendsStatusDisplay
{...props}
prepareChildren={prepareChildrenArray}
/>,
container,
);
statusDisplays = parentInstance.getStatusDisplays();
expect(statusDisplays.jcw).toBeTruthy();
expect(statusDisplays.jcw.getInternalState())
.not.toBe(startingInternalState);
expect(statusDisplays.jcw.getInternalState()).not.toBe(
startingInternalState,
);
});
it('should reset internal state if removed then readded in an iterable', () => {
@@ -324,8 +333,11 @@ describe('ReactMultiChildReconcile', () => {
var container = document.createElement('div');
var parentInstance = ReactDOM.render(
<FriendsStatusDisplay {...props} prepareChildren={prepareChildrenIterable} />,
container
<FriendsStatusDisplay
{...props}
prepareChildren={prepareChildrenIterable}
/>,
container,
);
var statusDisplays = parentInstance.getStatusDisplays();
var startingInternalState = statusDisplays.jcw.getInternalState();
@@ -333,20 +345,24 @@ describe('ReactMultiChildReconcile', () => {
// Now remove the child.
ReactDOM.render(
<FriendsStatusDisplay prepareChildren={prepareChildrenIterable} />,
container
container,
);
statusDisplays = parentInstance.getStatusDisplays();
expect(statusDisplays.jcw).toBeFalsy();
// Now reset the props that cause there to be a child
ReactDOM.render(
<FriendsStatusDisplay {...props} prepareChildren={prepareChildrenIterable} />,
container
<FriendsStatusDisplay
{...props}
prepareChildren={prepareChildrenIterable}
/>,
container,
);
statusDisplays = parentInstance.getStatusDisplays();
expect(statusDisplays.jcw).toBeTruthy();
expect(statusDisplays.jcw.getInternalState())
.not.toBe(startingInternalState);
expect(statusDisplays.jcw.getInternalState()).not.toBe(
startingInternalState,
);
});
it('should create unique identity', () => {
@@ -380,7 +396,7 @@ describe('ReactMultiChildReconcile', () => {
it('should transition from zero to one children correctly', () => {
var PROPS_SEQUENCE = [
{usernameToStatus: {} },
{usernameToStatus: {}},
{
usernameToStatus: {
first: 'firstStatus',
@@ -397,7 +413,7 @@ describe('ReactMultiChildReconcile', () => {
first: 'firstStatus',
},
},
{usernameToStatus: {} },
{usernameToStatus: {}},
];
testPropsSequence(PROPS_SEQUENCE);
});
@@ -442,8 +458,6 @@ describe('ReactMultiChildReconcile', () => {
]);
});
/**
* `FriendsStatusDisplay` renders nulls as empty children (it's a convention
* of `FriendsStatusDisplay`, nothing related to React or these test cases.
@@ -557,7 +571,8 @@ describe('ReactMultiChildReconcile', () => {
},
},
{
usernameToStatus: { // Full circle!
usernameToStatus: {
// Full circle!
userOne: 'userOneStatus',
userTwo: 'userTwoStatus',
userThree: 'userThreeStatus',
@@ -603,7 +618,8 @@ describe('ReactMultiChildReconcile', () => {
},
},
{
usernameToStatus: { // Full circle!
usernameToStatus: {
// Full circle!
userOne: 'userOneStatus',
userTwo: 'userTwoStatus',
userThree: 'userThreeStatus',
@@ -614,7 +630,6 @@ describe('ReactMultiChildReconcile', () => {
testPropsSequence(PROPS_SEQUENCE);
});
it('should remove nulled out children and ignore new null children', () => {
var PROPS_SEQUENCE = [
{
@@ -640,7 +655,7 @@ describe('ReactMultiChildReconcile', () => {
usernameToStatus: {
jcw: 'jcwStatus',
jordanjcw: 'jordanjcwStatus',
john: 'johnStatus', // john will go away
john: 'johnStatus', // john will go away
joe: 'joeStatus',
},
},
@@ -96,7 +96,6 @@ var expectChildren = function(container, children) {
}
};
/**
* ReactMultiChild DOM integration test. In ReactDOM components, we make sure
* that single children that are strings are treated as "content" which is much
@@ -105,6 +104,7 @@ var expectChildren = function(container, children) {
describe('ReactMultiChildText', () => {
it('should correctly handle all possible children for render and update', () => {
spyOn(console, 'error');
// prettier-ignore
testAllPermutations([
// basic values
undefined, [],
@@ -193,14 +193,14 @@ describe('ReactMultiChildText', () => {
]);
expectDev(console.error.calls.count()).toBe(1);
expectDev(console.error.calls.argsFor(0)[0]).toContain(
'Warning: Each child in an array or iterator should have a unique "key" prop.'
'Warning: Each child in an array or iterator should have a unique "key" prop.',
);
});
it('should throw if rendering both HTML and children', () => {
expect(function() {
ReactTestUtils.renderIntoDocument(
<div dangerouslySetInnerHTML={{__html: 'abcdef'}}>ghjkl</div>
<div dangerouslySetInnerHTML={{__html: 'abcdef'}}>ghjkl</div>,
);
}).toThrow();
});
+136 -118
View File
@@ -104,17 +104,20 @@ describeStack('ReactPerf', () => {
});
var summary = ReactPerf.getWasted(measurements);
expect(summary).toEqual([{
key: 'App',
instanceCount: 1,
inclusiveRenderDuration: 3,
renderCount: 1,
}, {
key: 'App > Box',
instanceCount: 2,
inclusiveRenderDuration: 2,
renderCount: 2,
}]);
expect(summary).toEqual([
{
key: 'App',
instanceCount: 1,
inclusiveRenderDuration: 3,
renderCount: 1,
},
{
key: 'App > Box',
instanceCount: 2,
inclusiveRenderDuration: 2,
renderCount: 2,
},
]);
});
it('should count no-op update in child as waste', () => {
@@ -128,12 +131,14 @@ describeStack('ReactPerf', () => {
});
var summary = ReactPerf.getWasted(measurements);
expect(summary).toEqual([{
key: 'App > Box',
instanceCount: 1,
inclusiveRenderDuration: 1,
renderCount: 1,
}]);
expect(summary).toEqual([
{
key: 'App > Box',
instanceCount: 1,
inclusiveRenderDuration: 1,
renderCount: 1,
},
]);
});
function expectNoWaste(fn) {
@@ -208,12 +213,12 @@ describeStack('ReactPerf', () => {
var container = document.createElement('div');
ReactDOM.render(
<Div dangerouslySetInnerHTML={{__html: 'me'}} />,
container
container,
);
expectNoWaste(() => {
ReactDOM.render(
<Div dangerouslySetInnerHTML={{__html: 'you'}} />,
container
container,
);
});
});
@@ -266,13 +271,15 @@ describeStack('ReactPerf', () => {
ReactDOM.render(<Div><Div key="a" /></Div>, container);
ReactDOM.render(<Div><Div key="b" /></Div>, container);
});
expect(ReactPerf.getExclusive(measurements)).toEqual([{
key: 'Div',
instanceCount: 3,
counts: { ctor: 3, render: 4 },
durations: { ctor: 3, render: 4 },
totalDuration: 7,
}]);
expect(ReactPerf.getExclusive(measurements)).toEqual([
{
key: 'Div',
instanceCount: 3,
counts: {ctor: 3, render: 4},
durations: {ctor: 3, render: 4},
totalDuration: 7,
},
]);
});
it('should include lifecycle methods in measurements', () => {
@@ -283,33 +290,35 @@ describeStack('ReactPerf', () => {
instance.setState({});
ReactDOM.unmountComponentAtNode(container);
});
expect(ReactPerf.getExclusive(measurements)).toEqual([{
key: 'LifeCycle',
instanceCount: 1,
totalDuration: 14,
counts: {
ctor: 1,
shouldComponentUpdate: 2,
componentWillMount: 1,
componentDidMount: 1,
componentWillReceiveProps: 1,
componentWillUpdate: 2,
componentDidUpdate: 2,
componentWillUnmount: 1,
render: 3,
expect(ReactPerf.getExclusive(measurements)).toEqual([
{
key: 'LifeCycle',
instanceCount: 1,
totalDuration: 14,
counts: {
ctor: 1,
shouldComponentUpdate: 2,
componentWillMount: 1,
componentDidMount: 1,
componentWillReceiveProps: 1,
componentWillUpdate: 2,
componentDidUpdate: 2,
componentWillUnmount: 1,
render: 3,
},
durations: {
ctor: 1,
shouldComponentUpdate: 2,
componentWillMount: 1,
componentDidMount: 1,
componentWillReceiveProps: 1,
componentWillUpdate: 2,
componentDidUpdate: 2,
componentWillUnmount: 1,
render: 3,
},
},
durations: {
ctor: 1,
shouldComponentUpdate: 2,
componentWillMount: 1,
componentDidMount: 1,
componentWillReceiveProps: 1,
componentWillUpdate: 2,
componentDidUpdate: 2,
componentWillUnmount: 1,
render: 3,
},
}]);
]);
});
it('should include render time of functional components', () => {
@@ -321,17 +330,19 @@ describeStack('ReactPerf', () => {
var measurements = measure(() => {
ReactDOM.render(<Foo />, container);
});
expect(ReactPerf.getExclusive(measurements)).toEqual([{
key: 'Foo',
instanceCount: 1,
totalDuration: 1,
counts: {
render: 1,
expect(ReactPerf.getExclusive(measurements)).toEqual([
{
key: 'Foo',
instanceCount: 1,
totalDuration: 1,
counts: {
render: 1,
},
durations: {
render: 1,
},
},
durations: {
render: 1,
},
}]);
]);
});
it('should not count time in a portal towards lifecycle method', () => {
@@ -354,40 +365,43 @@ describeStack('ReactPerf', () => {
ReactDOM.render(<Portal />, container);
});
expect(ReactPerf.getExclusive(measurements)).toEqual([{
key: 'Portal',
instanceCount: 1,
totalDuration: 6,
counts: {
ctor: 1,
componentDidMount: 1,
render: 1,
expect(ReactPerf.getExclusive(measurements)).toEqual([
{
key: 'Portal',
instanceCount: 1,
totalDuration: 6,
counts: {
ctor: 1,
componentDidMount: 1,
render: 1,
},
durations: {
ctor: 1,
// We want to exclude nested imperative ReactDOM.render() from lifecycle hook's own time.
// Otherwise it would artificially float to the top even though its exclusive time is small.
// This is how we get 4 as a number with the performanceNow() mock:
// - we capture the time we enter componentDidMount (n = 0)
// - we capture the time when we enter a nested flush (n = 1)
// - in the nested flush, we call it twice: before and after <Foo /> rendering. (n = 3)
// - we capture the time when we exit a nested flush (n = 4)
// - we capture the time we exit componentDidMount (n = 5)
// Time spent in componentDidMount = (5 - 0 - (4 - 3)) = 4.
componentDidMount: 4,
render: 1,
},
},
durations: {
ctor: 1,
// We want to exclude nested imperative ReactDOM.render() from lifecycle hook's own time.
// Otherwise it would artificially float to the top even though its exclusive time is small.
// This is how we get 4 as a number with the performanceNow() mock:
// - we capture the time we enter componentDidMount (n = 0)
// - we capture the time when we enter a nested flush (n = 1)
// - in the nested flush, we call it twice: before and after <Foo /> rendering. (n = 3)
// - we capture the time when we exit a nested flush (n = 4)
// - we capture the time we exit componentDidMount (n = 5)
// Time spent in componentDidMount = (5 - 0 - (4 - 3)) = 4.
componentDidMount: 4,
render: 1,
{
key: 'Foo',
instanceCount: 1,
totalDuration: 1,
counts: {
render: 1,
},
durations: {
render: 1,
},
},
}, {
key: 'Foo',
instanceCount: 1,
totalDuration: 1,
counts: {
render: 1,
},
durations: {
render: 1,
},
}]);
]);
});
it('warns once when using getMeasurementsSummaryMap', () => {
@@ -397,7 +411,7 @@ describeStack('ReactPerf', () => {
expectDev(console.error.calls.count()).toBe(1);
expectDev(console.error.calls.argsFor(0)[0]).toContain(
'`ReactPerf.getMeasurementsSummaryMap(...)` is deprecated. Use ' +
'`ReactPerf.getWasted(...)` instead.'
'`ReactPerf.getWasted(...)` instead.',
);
ReactPerf.getMeasurementsSummaryMap(measurements);
@@ -411,7 +425,7 @@ describeStack('ReactPerf', () => {
expectDev(console.error.calls.count()).toBe(1);
expectDev(console.error.calls.argsFor(0)[0]).toContain(
'`ReactPerf.printDOM(...)` is deprecated. Use ' +
'`ReactPerf.printOperations(...)` instead.'
'`ReactPerf.printOperations(...)` instead.',
);
ReactPerf.printDOM(measurements);
@@ -504,22 +518,26 @@ describeStack('ReactPerf', () => {
expect(ReactPerf.getWasted()).toEqual([]);
ReactDOM.render(<Measurer><App /></Measurer>, container);
expect(ReactPerf.getWasted()).toEqual([{
key: 'Measurer',
instanceCount: 1,
inclusiveRenderDuration: 4,
renderCount: 1,
}, {
key: 'App',
instanceCount: 1,
inclusiveRenderDuration: 3,
renderCount: 1,
}, {
key: 'App > Box',
instanceCount: 2,
inclusiveRenderDuration: 2,
renderCount: 2,
}]);
expect(ReactPerf.getWasted()).toEqual([
{
key: 'Measurer',
instanceCount: 1,
inclusiveRenderDuration: 4,
renderCount: 1,
},
{
key: 'App',
instanceCount: 1,
inclusiveRenderDuration: 3,
renderCount: 1,
},
{
key: 'App > Box',
instanceCount: 2,
inclusiveRenderDuration: 2,
renderCount: 2,
},
]);
});
it('should not print errant warnings if render() throws', () => {
@@ -539,7 +557,7 @@ describeStack('ReactPerf', () => {
<LifeCycle />
<Evil />
</div>,
container
container,
);
} catch (err) {
if (err !== thrownErr) {
@@ -569,7 +587,7 @@ describeStack('ReactPerf', () => {
<LifeCycle />
<Evil />
</div>,
container
container,
);
} catch (err) {
if (err !== thrownErr) {
@@ -599,7 +617,7 @@ describeStack('ReactPerf', () => {
<LifeCycle />
<Evil />
</div>,
container
container,
);
} catch (err) {
if (err !== thrownErr) {
@@ -635,7 +653,7 @@ describeStack('ReactPerf', () => {
<LifeCycle />
<EvilPortal />
</div>,
container
container,
);
} catch (err) {
if (err !== thrownErr) {
@@ -675,7 +693,7 @@ describeStack('ReactPerf', () => {
<LifeCycle />
<EvilPortal />
</div>,
container
container,
);
} catch (err) {
if (err !== thrownErr) {
@@ -715,7 +733,7 @@ describeStack('ReactPerf', () => {
<LifeCycle />
<EvilPortal />
</div>,
container
container,
);
} catch (err) {
if (err !== thrownErr) {
@@ -123,19 +123,19 @@ describe('ReactStatelessComponent', () => {
expectDev(console.error.calls.count()).toBe(1);
expectDev(console.error.calls.argsFor(0)[0]).toContain(
'StatelessComponentWithChildContext(...): childContextTypes cannot ' +
'be defined on a functional component.'
'be defined on a functional component.',
);
} else {
expectDev(console.error.calls.count()).toBe(2);
expectDev(console.error.calls.argsFor(0)[0]).toContain(
'StatelessComponentWithChildContext(...): childContextTypes cannot ' +
'be defined on a functional component.'
'be defined on a functional component.',
);
expectDev(normalizeCodeLocInfo(console.error.calls.argsFor(1)[0])).toBe(
'Warning: StatelessComponentWithChildContext.childContextTypes is specified ' +
'but there is no getChildContext() method on the instance. You can either ' +
'define getChildContext() on StatelessComponentWithChildContext or remove ' +
'childContextTypes from it.'
'but there is no getChildContext() method on the instance. You can either ' +
'define getChildContext() on StatelessComponentWithChildContext or remove ' +
'childContextTypes from it.',
);
}
});
@@ -150,19 +150,18 @@ describe('ReactStatelessComponent', () => {
ReactTestUtils.renderIntoDocument(<div><NotAComponent /></div>);
}).toThrowError(
'NotAComponent(...): A valid React element (or null) must be returned. ' +
'You may have returned undefined, an array or some other invalid object.'
'You may have returned undefined, an array or some other invalid object.',
);
});
}
it('should throw when stateless component returns undefined', () => {
function NotAComponent() {
}
function NotAComponent() {}
expect(function() {
ReactTestUtils.renderIntoDocument(<div><NotAComponent /></div>);
}).toThrowError(
'NotAComponent(...): A valid React element (or null) must be returned. ' +
'You may have returned undefined, an array or some other invalid object.'
'You may have returned undefined, an array or some other invalid object.',
);
});
@@ -173,9 +172,7 @@ describe('ReactStatelessComponent', () => {
expect(function() {
ReactTestUtils.renderIntoDocument(<Child test="test" />);
}).toThrowError(
'Stateless function components cannot have refs.'
);
}).toThrowError('Stateless function components cannot have refs.');
});
it('should warn when given a string ref', () => {
@@ -199,12 +196,12 @@ describe('ReactStatelessComponent', () => {
expectDev(console.error.calls.count()).toBe(1);
expectDev(normalizeCodeLocInfo(console.error.calls.argsFor(0)[0])).toBe(
'Warning: Stateless function components cannot be given refs. ' +
'Attempts to access this ref will fail.\n\nCheck the render method ' +
'of `ParentUsingStringRef`.\n' +
' in StatelessComponent (at **)\n' +
' in div (at **)\n' +
' in Indirection (at **)\n' +
' in ParentUsingStringRef (at **)'
'Attempts to access this ref will fail.\n\nCheck the render method ' +
'of `ParentUsingStringRef`.\n' +
' in StatelessComponent (at **)\n' +
' in div (at **)\n' +
' in Indirection (at **)\n' +
' in ParentUsingStringRef (at **)',
);
ReactTestUtils.renderIntoDocument(<ParentUsingStringRef />);
@@ -222,9 +219,12 @@ describe('ReactStatelessComponent', () => {
render() {
return (
<Indirection>
<StatelessComponent name="A" ref={(arg) => {
expect(arg).toBe(null);
}} />
<StatelessComponent
name="A"
ref={arg => {
expect(arg).toBe(null);
}}
/>
</Indirection>
);
}
@@ -234,12 +234,12 @@ describe('ReactStatelessComponent', () => {
expectDev(console.error.calls.count()).toBe(1);
expectDev(normalizeCodeLocInfo(console.error.calls.argsFor(0)[0])).toBe(
'Warning: Stateless function components cannot be given refs. ' +
'Attempts to access this ref will fail.\n\nCheck the render method ' +
'of `ParentUsingFunctionRef`.\n' +
' in StatelessComponent (at **)\n' +
' in div (at **)\n' +
' in Indirection (at **)\n' +
' in ParentUsingFunctionRef (at **)'
'Attempts to access this ref will fail.\n\nCheck the render method ' +
'of `ParentUsingFunctionRef`.\n' +
' in StatelessComponent (at **)\n' +
' in div (at **)\n' +
' in Indirection (at **)\n' +
' in ParentUsingFunctionRef (at **)',
);
ReactTestUtils.renderIntoDocument(<ParentUsingFunctionRef />);
@@ -258,10 +258,12 @@ describe('ReactStatelessComponent', () => {
return <StatelessComponent name="A" ref={() => {}} />;
},
});
const instance1 = ReactTestUtils.renderIntoDocument(<AnonymousParentUsingJSX />);
const instance1 = ReactTestUtils.renderIntoDocument(
<AnonymousParentUsingJSX />,
);
expectDev(console.error.calls.count()).toBe(1);
expectDev(console.error.calls.argsFor(0)[0]).toContain(
'Warning: Stateless function components cannot be given refs.'
'Warning: Stateless function components cannot be given refs.',
);
// Should be deduped (offending element is on the same line):
instance1.forceUpdate();
@@ -273,13 +275,18 @@ describe('ReactStatelessComponent', () => {
// When owner doesn't use JSX, and is anonymous, we warn once per internal instance.
var AnonymousParentNotUsingJSX = createClassWithoutDisplayName({
render() {
return React.createElement(StatelessComponent, {name: 'A', 'ref': () => {}});
return React.createElement(StatelessComponent, {
name: 'A',
ref: () => {},
});
},
});
const instance2 = ReactTestUtils.renderIntoDocument(<AnonymousParentNotUsingJSX />);
const instance2 = ReactTestUtils.renderIntoDocument(
<AnonymousParentNotUsingJSX />,
);
expectDev(console.error.calls.count()).toBe(1);
expectDev(console.error.calls.argsFor(0)[0]).toContain(
'Warning: Stateless function components cannot be given refs.'
'Warning: Stateless function components cannot be given refs.',
);
// Should be deduped (same internal instance):
instance2.forceUpdate();
@@ -288,20 +295,25 @@ describe('ReactStatelessComponent', () => {
ReactTestUtils.renderIntoDocument(<AnonymousParentNotUsingJSX />);
expectDev(console.error.calls.count()).toBe(2);
expectDev(console.error.calls.argsFor(1)[0]).toContain(
'Warning: Stateless function components cannot be given refs.'
'Warning: Stateless function components cannot be given refs.',
);
console.error.calls.reset();
// When owner doesn't use JSX, but is named, we warn once per owner name
class NamedParentNotUsingJSX extends React.Component {
render() {
return React.createElement(StatelessComponent, {name: 'A', 'ref': () => {}});
return React.createElement(StatelessComponent, {
name: 'A',
ref: () => {},
});
}
}
const instance3 = ReactTestUtils.renderIntoDocument(<NamedParentNotUsingJSX />);
const instance3 = ReactTestUtils.renderIntoDocument(
<NamedParentNotUsingJSX />,
);
expectDev(console.error.calls.count()).toBe(1);
expectDev(console.error.calls.argsFor(0)[0]).toContain(
'Warning: Stateless function components cannot be given refs.'
'Warning: Stateless function components cannot be given refs.',
);
// Should be deduped (same owner name):
instance3.forceUpdate();
@@ -329,7 +341,9 @@ describe('ReactStatelessComponent', () => {
spyOn(console, 'error');
ReactTestUtils.renderIntoDocument(<Child />);
expectDev(console.error.calls.count()).toBe(1);
expectDev(console.error.calls.argsFor(0)[0]).toContain('a unique "key" prop');
expectDev(console.error.calls.argsFor(0)[0]).toContain(
'a unique "key" prop',
);
expectDev(console.error.calls.argsFor(0)[0]).toContain('Child');
});
@@ -344,11 +358,11 @@ describe('ReactStatelessComponent', () => {
ReactTestUtils.renderIntoDocument(<Child />);
expectDev(console.error.calls.count()).toBe(1);
expect(
console.error.calls.argsFor(0)[0].replace(/\(at .+?:\d+\)/g, '(at **)')
console.error.calls.argsFor(0)[0].replace(/\(at .+?:\d+\)/g, '(at **)'),
).toBe(
'Warning: Failed prop type: Invalid prop `test` of type `number` ' +
'supplied to `Child`, expected `string`.\n' +
' in Child (at **)'
'supplied to `Child`, expected `string`.\n' +
' in Child (at **)',
);
});
@@ -401,5 +415,4 @@ describe('ReactStatelessComponent', () => {
}
expect(() => ReactTestUtils.renderIntoDocument(<Child />)).not.toThrow();
});
});
@@ -94,10 +94,7 @@ describe('ReactTreeTraversal', () => {
it('should traverse two phase at shallowest node', () => {
var parent = renderParentIntoDocument();
var target = getInst(parent.refs.P);
var expectedCalls = [
['P', 'captured', ARG],
['P', 'bubbled', ARG],
];
var expectedCalls = [['P', 'captured', ARG], ['P', 'bubbled', ARG]];
ReactTreeTraversal.traverseTwoPhase(target, callback, ARG);
expect(mockFn.mock.calls).toEqual(expectedCalls);
});
@@ -105,9 +102,7 @@ describe('ReactTreeTraversal', () => {
describe('traverseEnterLeave', () => {
it('should not traverse when enter/leaving outside DOM', () => {
ReactTreeTraversal.traverseEnterLeave(
null, null, callback, ARG, ARG2
);
ReactTreeTraversal.traverseEnterLeave(null, null, callback, ARG, ARG2);
expect(mockFn).not.toHaveBeenCalled();
});
@@ -115,9 +110,7 @@ describe('ReactTreeTraversal', () => {
var parent = renderParentIntoDocument();
var leave = getInst(parent.refs.P_P1_C1.refs.DIV_1);
var enter = getInst(parent.refs.P_P1_C1.refs.DIV_1);
ReactTreeTraversal.traverseEnterLeave(
leave, enter, callback, ARG, ARG2
);
ReactTreeTraversal.traverseEnterLeave(leave, enter, callback, ARG, ARG2);
expect(mockFn).not.toHaveBeenCalled();
});
@@ -130,9 +123,7 @@ describe('ReactTreeTraversal', () => {
// enter/leave shouldn't fire anything on the parent
['P_P1_C1__DIV_2', 'captured', ARG2],
];
ReactTreeTraversal.traverseEnterLeave(
leave, enter, callback, ARG, ARG2
);
ReactTreeTraversal.traverseEnterLeave(leave, enter, callback, ARG, ARG2);
expect(mockFn.mock.calls).toEqual(expectedCalls);
});
@@ -140,12 +131,8 @@ describe('ReactTreeTraversal', () => {
var parent = renderParentIntoDocument();
var leave = getInst(parent.refs.P_P1_C1.refs.DIV_1);
var enter = getInst(parent.refs.P_P1_C1.refs.DIV);
var expectedCalls = [
['P_P1_C1__DIV_1', 'bubbled', ARG],
];
ReactTreeTraversal.traverseEnterLeave(
leave, enter, callback, ARG, ARG2
);
var expectedCalls = [['P_P1_C1__DIV_1', 'bubbled', ARG]];
ReactTreeTraversal.traverseEnterLeave(leave, enter, callback, ARG, ARG2);
expect(mockFn.mock.calls).toEqual(expectedCalls);
});
@@ -158,9 +145,7 @@ describe('ReactTreeTraversal', () => {
['P_P1', 'captured', ARG2],
['P_P1_C1__DIV', 'captured', ARG2],
];
ReactTreeTraversal.traverseEnterLeave(
leave, enter, callback, ARG, ARG2
);
ReactTreeTraversal.traverseEnterLeave(leave, enter, callback, ARG, ARG2);
expect(mockFn.mock.calls).toEqual(expectedCalls);
});
@@ -168,12 +153,8 @@ describe('ReactTreeTraversal', () => {
var parent = renderParentIntoDocument();
var leave = null; // From the window or outside of the React sandbox.
var enter = getInst(parent.refs.P);
var expectedCalls = [
['P', 'captured', ARG2],
];
ReactTreeTraversal.traverseEnterLeave(
leave, enter, callback, ARG, ARG2
);
var expectedCalls = [['P', 'captured', ARG2]];
ReactTreeTraversal.traverseEnterLeave(leave, enter, callback, ARG, ARG2);
expect(mockFn.mock.calls).toEqual(expectedCalls);
});
@@ -186,9 +167,7 @@ describe('ReactTreeTraversal', () => {
['P_P1', 'bubbled', ARG],
['P', 'bubbled', ARG],
];
ReactTreeTraversal.traverseEnterLeave(
leave, enter, callback, ARG, ARG2
);
ReactTreeTraversal.traverseEnterLeave(leave, enter, callback, ARG, ARG2);
expect(mockFn.mock.calls).toEqual(expectedCalls);
});
@@ -201,9 +180,7 @@ describe('ReactTreeTraversal', () => {
['P_P1', 'bubbled', ARG],
['P', 'bubbled', ARG],
];
ReactTreeTraversal.traverseEnterLeave(
leave, enter, callback, ARG, ARG2
);
ReactTreeTraversal.traverseEnterLeave(leave, enter, callback, ARG, ARG2);
expect(mockFn.mock.calls).toEqual(expectedCalls);
});
});
@@ -213,7 +190,8 @@ describe('ReactTreeTraversal', () => {
var parent = renderParentIntoDocument();
var ancestors = [
// Common ancestor with self is self.
{one: parent.refs.P_P1_C1.refs.DIV_1,
{
one: parent.refs.P_P1_C1.refs.DIV_1,
two: parent.refs.P_P1_C1.refs.DIV_1,
com: parent.refs.P_P1_C1.refs.DIV_1,
},
@@ -255,11 +233,10 @@ describe('ReactTreeTraversal', () => {
var plan = ancestors[i];
var firstCommon = ReactTreeTraversal.getLowestCommonAncestor(
getInst(plan.one),
getInst(plan.two)
getInst(plan.two),
);
expect(firstCommon).toBe(getInst(plan.com));
}
});
});
});
+50 -50
View File
@@ -487,21 +487,21 @@ describe('ReactUpdates', () => {
[root.refs.switcher.refs.box, root.refs.switcher],
// Owner-child relationships have inverse will and did
['Switcher', 'Box'],
['Box', 'Switcher']
['Box', 'Switcher'],
);
testUpdates(
[root.refs.child, root.refs.switcher.refs.box],
// Not owner-child so reconcile independently
['Box', 'Child'],
['Box', 'Child']
['Box', 'Child'],
);
testUpdates(
[root.refs.child, root.refs.switcher],
// Switcher owns Box and Child, Box does not own Child
['Switcher', 'Box', 'Child'],
['Box', 'Switcher', 'Child']
['Box', 'Switcher', 'Child'],
);
});
@@ -531,7 +531,7 @@ describe('ReactUpdates', () => {
if (ReactDOMFeatureFlags.useFiber) {
portal = ReactDOM.unstable_createPortal(
<B ref={n => b = n} />,
bContainer
bContainer,
);
}
return <div>A{this.state.x}{portal}</div>;
@@ -607,31 +607,31 @@ describe('ReactUpdates', () => {
/* eslint-disable indent */
expect(updates).toEqual([
'Outer-render-0',
'Inner-render-0-0',
'Inner-render-0-0',
'Outer-setState-1',
'Outer-render-1',
'Inner-render-1-0',
'Inner-didUpdate-1-0',
'Outer-didUpdate-1',
// Happens in a batch, so don't re-render yet
'Inner-setState-1',
'Outer-callback-1',
'Outer-render-1',
'Inner-render-1-0',
'Inner-didUpdate-1-0',
'Outer-didUpdate-1',
// Happens in a batch, so don't re-render yet
'Inner-setState-1',
'Outer-callback-1',
// Happens in a batch
'Outer-setState-2',
// Happens in a batch
'Outer-setState-2',
// Flush batched updates all at once
'Outer-render-2',
'Inner-render-2-1',
'Inner-didUpdate-2-1',
'Inner-callback-1',
'Outer-didUpdate-2',
'Inner-setState-2',
'Outer-callback-2',
'Inner-render-2-2',
'Inner-didUpdate-2-2',
'Inner-callback-2',
// Flush batched updates all at once
'Outer-render-2',
'Inner-render-2-1',
'Inner-didUpdate-2-1',
'Inner-callback-1',
'Outer-didUpdate-2',
'Inner-setState-2',
'Outer-callback-2',
'Inner-render-2-2',
'Inner-didUpdate-2-2',
'Inner-callback-2',
]);
/* eslint-enable indent */
});
@@ -654,7 +654,7 @@ describe('ReactUpdates', () => {
depth={this.props.depth + 1}
count={this.props.count}
/>,
ReactDOM.findDOMNode(this)
ReactDOM.findDOMNode(this),
);
}
}
@@ -761,7 +761,7 @@ describe('ReactUpdates', () => {
<div>
<A />
<B />
</div>
</div>,
);
});
@@ -886,29 +886,29 @@ describe('ReactUpdates', () => {
expect(() => component.setState({}, 'no')).toThrowError(
'Invalid argument passed as callback. Expected a function. Instead ' +
'received: no',
'received: no',
);
expectDev(console.error.calls.argsFor(0)[0]).toContain(
'setState(...): Expected the last optional `callback` argument to be ' +
'a function. Instead received: no.'
'a function. Instead received: no.',
);
component = ReactTestUtils.renderIntoDocument(<A />);
expect(() => component.setState({}, {foo: 'bar'})).toThrowError(
'Invalid argument passed as callback. Expected a function. Instead ' +
'received: [object Object]',
'received: [object Object]',
);
expectDev(console.error.calls.argsFor(1)[0]).toContain(
'setState(...): Expected the last optional `callback` argument to be ' +
'a function. Instead received: [object Object].'
'a function. Instead received: [object Object].',
);
component = ReactTestUtils.renderIntoDocument(<A />);
expect(() => component.setState({}, new Foo())).toThrowError(
'Invalid argument passed as callback. Expected a function. Instead ' +
'received: [object Object]',
'received: [object Object]',
);
expectDev(console.error.calls.argsFor(2)[0]).toContain(
'setState(...): Expected the last optional `callback` argument to be ' +
'a function. Instead received: [object Object].'
'a function. Instead received: [object Object].',
);
expect(console.error.calls.count()).toBe(3);
});
@@ -932,29 +932,29 @@ describe('ReactUpdates', () => {
expect(() => component.replaceState({}, 'no')).toThrowError(
'Invalid argument passed as callback. Expected a function. Instead ' +
'received: no',
'received: no',
);
expectDev(console.error.calls.argsFor(0)[0]).toContain(
'replaceState(...): Expected the last optional `callback` argument to be ' +
'a function. Instead received: no.'
'a function. Instead received: no.',
);
component = ReactTestUtils.renderIntoDocument(<A />);
expect(() => component.replaceState({}, {foo: 'bar'})).toThrowError(
'Invalid argument passed as callback. Expected a function. Instead ' +
'received: [object Object]',
'received: [object Object]',
);
expectDev(console.error.calls.argsFor(1)[0]).toContain(
'replaceState(...): Expected the last optional `callback` argument to be ' +
'a function. Instead received: [object Object].'
'a function. Instead received: [object Object].',
);
component = ReactTestUtils.renderIntoDocument(<A />);
expect(() => component.replaceState({}, new Foo())).toThrowError(
'Invalid argument passed as callback. Expected a function. Instead ' +
'received: [object Object]',
'received: [object Object]',
);
expectDev(console.error.calls.argsFor(2)[0]).toContain(
'replaceState(...): Expected the last optional `callback` argument to be ' +
'a function. Instead received: [object Object].'
'a function. Instead received: [object Object].',
);
expect(console.error.calls.count()).toBe(3);
});
@@ -979,29 +979,29 @@ describe('ReactUpdates', () => {
expect(() => component.forceUpdate('no')).toThrowError(
'Invalid argument passed as callback. Expected a function. Instead ' +
'received: no',
'received: no',
);
expectDev(console.error.calls.argsFor(0)[0]).toContain(
'forceUpdate(...): Expected the last optional `callback` argument to be ' +
'a function. Instead received: no.'
'a function. Instead received: no.',
);
component = ReactTestUtils.renderIntoDocument(<A />);
expect(() => component.forceUpdate({foo: 'bar'})).toThrowError(
'Invalid argument passed as callback. Expected a function. Instead ' +
'received: [object Object]',
'received: [object Object]',
);
expectDev(console.error.calls.argsFor(1)[0]).toContain(
'forceUpdate(...): Expected the last optional `callback` argument to be ' +
'a function. Instead received: [object Object].'
'a function. Instead received: [object Object].',
);
component = ReactTestUtils.renderIntoDocument(<A />);
expect(() => component.forceUpdate(new Foo())).toThrowError(
'Invalid argument passed as callback. Expected a function. Instead ' +
'received: [object Object]',
'received: [object Object]',
);
expectDev(console.error.calls.argsFor(2)[0]).toContain(
'forceUpdate(...): Expected the last optional `callback` argument to be ' +
'a function. Instead received: [object Object].'
'a function. Instead received: [object Object].',
);
expect(console.error.calls.count()).toBe(3);
});
@@ -1065,10 +1065,10 @@ describe('ReactUpdates', () => {
class App extends React.Component {
constructor(props) {
super(props);
this.state = { showChild: true };
this.state = {showChild: true};
}
componentDidMount() {
this.setState({ showChild: false });
this.setState({showChild: false});
}
render() {
return (
@@ -1096,7 +1096,7 @@ describe('ReactUpdates', () => {
callbacks.push(this.onChange);
}
componentWillUnmount() {
callbacks = callbacks.filter((c) => c !== this.onChange);
callbacks = callbacks.filter(c => c !== this.onChange);
}
render() {
return <div key={Math.random()} onClick={function() {}} />;
@@ -1142,13 +1142,13 @@ describe('ReactUpdates', () => {
function render() {
ReactDOM.render(
<Editor
onChange={(newProps) => {
onChange={newProps => {
props = {...props, ...newProps};
render();
}}
{...props}
/>,
container
container,
);
}
@@ -29,11 +29,11 @@ describe('refs-destruction', () => {
render() {
return (
<div>
{this.props.destroy ? null :
<div ref="theInnerDiv">
Lets try to destroy this.
</div>
}
{this.props.destroy
? null
: <div ref="theInnerDiv">
Lets try to destroy this.
</div>}
</div>
);
}
@@ -43,36 +43,38 @@ describe('refs-destruction', () => {
it('should remove refs when destroying the parent', () => {
var container = document.createElement('div');
var testInstance = ReactDOM.render(<TestComponent />, container);
expect(ReactTestUtils.isDOMComponent(testInstance.refs.theInnerDiv))
.toBe(true);
expect(ReactTestUtils.isDOMComponent(testInstance.refs.theInnerDiv)).toBe(
true,
);
expect(
Object.keys(testInstance.refs || {})
.filter(key => testInstance.refs[key])
.length
Object.keys(testInstance.refs || {}).filter(
key => testInstance.refs[key],
).length,
).toEqual(1);
ReactDOM.unmountComponentAtNode(container);
expect(
Object.keys(testInstance.refs || {})
.filter(key => testInstance.refs[key])
.length
Object.keys(testInstance.refs || {}).filter(
key => testInstance.refs[key],
).length,
).toEqual(0);
});
it('should remove refs when destroying the child', () => {
var container = document.createElement('div');
var testInstance = ReactDOM.render(<TestComponent />, container);
expect(ReactTestUtils.isDOMComponent(testInstance.refs.theInnerDiv))
.toBe(true);
expect(ReactTestUtils.isDOMComponent(testInstance.refs.theInnerDiv)).toBe(
true,
);
expect(
Object.keys(testInstance.refs || {})
.filter(key => testInstance.refs[key])
.length
Object.keys(testInstance.refs || {}).filter(
key => testInstance.refs[key],
).length,
).toEqual(1);
ReactDOM.render(<TestComponent destroy={true} />, container);
expect(
Object.keys(testInstance.refs || {})
.filter(key => testInstance.refs[key])
.length
Object.keys(testInstance.refs || {}).filter(
key => testInstance.refs[key],
).length,
).toEqual(0);
});
@@ -91,12 +93,15 @@ describe('refs-destruction', () => {
componentWillUnmount() {
var self = this;
// some async animation
setTimeout(function() {
expect(function() {
ReactDOM.unmountComponentAtNode(self.div);
}).not.toThrow();
document.body.removeChild(self.div);
}, 0);
setTimeout(
function() {
expect(function() {
ReactDOM.unmountComponentAtNode(self.div);
}).not.toThrow();
document.body.removeChild(self.div);
},
0,
);
}
render() {
@@ -106,9 +111,11 @@ describe('refs-destruction', () => {
class AppModal extends React.Component {
render() {
return (<Modal>
<a ref="ref" />
</Modal>);
return (
<Modal>
<a ref="ref" />
</Modal>
);
}
}
+32 -26
View File
@@ -39,7 +39,7 @@ class ClickCounter extends React.Component {
className="clickLogDiv"
key={'clickLog' + i}
ref={'clickLog' + i}
/>
/>,
);
}
return (
@@ -88,8 +88,9 @@ class TestRefsComponent extends React.Component {
* Render a TestRefsComponent and ensure that the main refs are wired up.
*/
var renderTestRefsComponent = function() {
var testRefsComponent =
ReactTestUtils.renderIntoDocument(<TestRefsComponent />);
var testRefsComponent = ReactTestUtils.renderIntoDocument(
<TestRefsComponent />,
);
expect(testRefsComponent instanceof TestRefsComponent).toBe(true);
var generalContainer = testRefsComponent.refs.myContainer;
@@ -101,10 +102,11 @@ var renderTestRefsComponent = function() {
return testRefsComponent;
};
var expectClickLogsLengthToBe = function(instance, length) {
var clickLogs =
ReactTestUtils.scryRenderedDOMComponentsWithClass(instance, 'clickLogDiv');
var clickLogs = ReactTestUtils.scryRenderedDOMComponentsWithClass(
instance,
'clickLogDiv',
);
expect(clickLogs.length).toBe(length);
expect(Object.keys(instance.refs.myCounter.refs).length).toBe(length);
};
@@ -122,11 +124,10 @@ describe('reactiverefs', () => {
*/
it('Should increase refs with an increase in divs', () => {
var testRefsComponent = renderTestRefsComponent();
var clickIncrementer =
ReactTestUtils.findRenderedDOMComponentWithClass(
testRefsComponent,
'clickIncrementer'
);
var clickIncrementer = ReactTestUtils.findRenderedDOMComponentWithClass(
testRefsComponent,
'clickIncrementer',
);
expectClickLogsLengthToBe(testRefsComponent, 1);
@@ -210,12 +211,18 @@ describe('ref swapping', () => {
it('Allow refs to hop around children correctly', () => {
var refHopsAround = ReactTestUtils.renderIntoDocument(<RefHopsAround />);
var firstDiv =
ReactTestUtils.findRenderedDOMComponentWithClass(refHopsAround, 'first');
var secondDiv =
ReactTestUtils.findRenderedDOMComponentWithClass(refHopsAround, 'second');
var thirdDiv =
ReactTestUtils.findRenderedDOMComponentWithClass(refHopsAround, 'third');
var firstDiv = ReactTestUtils.findRenderedDOMComponentWithClass(
refHopsAround,
'first',
);
var secondDiv = ReactTestUtils.findRenderedDOMComponentWithClass(
refHopsAround,
'second',
);
var thirdDiv = ReactTestUtils.findRenderedDOMComponentWithClass(
refHopsAround,
'third',
);
expect(refHopsAround.refs.hopRef).toEqual(firstDiv);
expect(refHopsAround.refs.divTwoRef).toEqual(secondDiv);
@@ -241,7 +248,6 @@ describe('ref swapping', () => {
expect(refHopsAround.refs.divThreeRef).toEqual(thirdDiv);
});
it('always has a value for this.refs', () => {
class Component extends React.Component {
render() {
@@ -329,11 +335,11 @@ describe('string refs between fiber and stack', () => {
ReactDOM.unstable_renderSubtreeIntoContainer(
this,
span,
this._container = document.createElement('div'),
(this._container = document.createElement('div')),
() => {
expect(this.refs.span.nodeName).toBe('SPAN');
layerMounted = true;
}
},
);
}
componentWillUnmount() {
@@ -350,8 +356,8 @@ describe('string refs between fiber and stack', () => {
expectDev(console.error.calls.count()).toBe(1);
expectDev(console.error.calls.argsFor(0)[0]).toBe(
'Warning: You are using React DOM Fiber which is an experimental ' +
'renderer. It is likely to have bugs, breaking changes and is ' +
'unsupported.'
'renderer. It is likely to have bugs, breaking changes and is ' +
'unsupported.',
);
}
});
@@ -376,11 +382,11 @@ describe('string refs between fiber and stack', () => {
ReactDOMFiber.unstable_renderSubtreeIntoContainer(
this,
span,
this._container = document.createElement('div'),
(this._container = document.createElement('div')),
() => {
expect(this.refs.span.nodeName).toBe('SPAN');
layerMounted = true;
}
},
);
}
componentWillUnmount() {
@@ -397,8 +403,8 @@ describe('string refs between fiber and stack', () => {
expectDev(console.error.calls.count()).toBe(1);
expectDev(console.error.calls.argsFor(0)[0]).toBe(
'Warning: You are using React DOM Fiber which is an experimental ' +
'renderer. It is likely to have bugs, breaking changes and is ' +
'unsupported.'
'renderer. It is likely to have bugs, breaking changes and is ' +
'unsupported.',
);
}
});
+22 -56
View File
@@ -23,7 +23,7 @@ const React = require('react');
const ReactFiberReconciler = require('ReactFiberReconciler');
const ReactDOMFrameScheduling = require('ReactDOMFrameScheduling');
const { Component } = React;
const {Component} = React;
const pooledTransform = new Transform();
@@ -133,19 +133,14 @@ function getScaleY(props) {
function isSameFont(oldFont, newFont) {
if (oldFont === newFont) {
return true;
} else if (
typeof newFont === 'string' ||
typeof oldFont === 'string'
) {
} else if (typeof newFont === 'string' || typeof oldFont === 'string') {
return false;
} else {
return (
newFont.fontSize === oldFont.fontSize &&
return newFont.fontSize === oldFont.fontSize &&
newFont.fontStyle === oldFont.fontStyle &&
newFont.fontVariant === oldFont.fontVariant &&
newFont.fontWeight === oldFont.fontWeight &&
newFont.fontFamily === oldFont.fontFamily
);
newFont.fontFamily === oldFont.fontFamily;
}
}
@@ -180,24 +175,21 @@ function applyNodeProps(instance, props, prevProps = {}) {
}
if (
instance.xx !== pooledTransform.xx || instance.yx !== pooledTransform.yx ||
instance.xy !== pooledTransform.xy || instance.yy !== pooledTransform.yy ||
instance.x !== pooledTransform.x || instance.y !== pooledTransform.y
instance.xx !== pooledTransform.xx ||
instance.yx !== pooledTransform.yx ||
instance.xy !== pooledTransform.xy ||
instance.yy !== pooledTransform.yy ||
instance.x !== pooledTransform.x ||
instance.y !== pooledTransform.y
) {
instance.transformTo(pooledTransform);
}
if (
props.cursor !== prevProps.cursor ||
props.title !== prevProps.title
) {
if (props.cursor !== prevProps.cursor || props.title !== prevProps.title) {
instance.indicate(props.cursor, props.title);
}
if (
instance.blend &&
props.opacity !== prevProps.opacity
) {
if (instance.blend && props.opacity !== prevProps.opacity) {
instance.blend(props.opacity == null ? 1 : props.opacity);
}
@@ -256,11 +248,7 @@ function applyShapeProps(instance, props, prevProps = {}) {
prevProps.height !== props.height ||
prevProps.width !== props.width
) {
instance.draw(
path,
props.width,
props.height,
);
instance.draw(path, props.width, props.height);
instance._prevDelta = path.delta;
instance._prevPath = path;
@@ -278,12 +266,7 @@ function applyTextProps(instance, props, prevProps = {}) {
props.alignment !== prevProps.alignment ||
props.path !== prevProps.path
) {
instance.draw(
string,
props.font,
props.alignment,
props.path,
);
instance.draw(string, props.font, props.alignment, props.path);
instance._currentString = string;
}
@@ -327,33 +310,22 @@ class Pattern {
class Surface extends Component {
componentDidMount() {
const { height, width } = this.props;
const {height, width} = this.props;
this._surface = Mode.Surface(+width, +height, this._tagRef);
this._mountNode = ARTRenderer.createContainer(this._surface);
ARTRenderer.updateContainer(
this.props.children,
this._mountNode,
this,
);
ARTRenderer.updateContainer(this.props.children, this._mountNode, this);
}
componentDidUpdate(prevProps, prevState) {
const props = this.props;
if (
props.height !== prevProps.height ||
props.width !== prevProps.width
) {
if (props.height !== prevProps.height || props.width !== prevProps.width) {
this._surface.resize(+props.width, +props.height);
}
ARTRenderer.updateContainer(
this.props.children,
this._mountNode,
this,
);
ARTRenderer.updateContainer(this.props.children, this._mountNode, this);
if (this._surface.render) {
this._surface.render();
@@ -361,11 +333,7 @@ class Surface extends Component {
}
componentWillUnmount() {
ARTRenderer.updateContainer(
null,
this._mountNode,
this,
);
ARTRenderer.updateContainer(null, this._mountNode, this);
}
render() {
@@ -475,7 +443,7 @@ const ARTRenderer = ReactFiberReconciler({
insertBefore(parentInstance, child, beforeChild) {
invariant(
child !== beforeChild,
'ReactART: Can not insert node before itself'
'ReactART: Can not insert node before itself',
);
child.injectBefore(beforeChild);
@@ -520,10 +488,8 @@ const ARTRenderer = ReactFiberReconciler({
scheduleDeferredCallback: ReactDOMFrameScheduling.rIC,
shouldSetTextContent(props) {
return (
typeof props.children === 'string' ||
typeof props.children === 'number'
);
return typeof props.children === 'string' ||
typeof props.children === 'number';
},
useSyncScheduling: true,
+91 -107
View File
@@ -12,7 +12,7 @@
'use strict';
require('art/modes/current').setCurrent(
require('art/modes/fast-noSideEffects') // Flip this to DOM mode for debugging
require('art/modes/fast-noSideEffects'), // Flip this to DOM mode for debugging
);
const Transform = require('art/core/transform');
@@ -67,8 +67,9 @@ function createComponent(name) {
*/
function injectAfter(parentNode, referenceNode, node) {
let beforeNode;
if (node.parentNode === parentNode &&
node.previousSibling === referenceNode) {
if (
node.parentNode === parentNode && node.previousSibling === referenceNode
) {
return;
}
if (referenceNode == null) {
@@ -83,7 +84,7 @@ function injectAfter(parentNode, referenceNode, node) {
// checks and the behavior isn't well-defined.
invariant(
node !== beforeNode,
'ReactART: Can not insert node before itself'
'ReactART: Can not insert node before itself',
);
node.injectBefore(beforeNode);
} else if (node.parentNode !== parentNode) {
@@ -94,7 +95,6 @@ function injectAfter(parentNode, referenceNode, node) {
// ContainerMixin for components that can hold ART nodes
const ContainerMixin = assign({}, ReactMultiChild, {
/**
* Moves a child component to the supplied index.
*
@@ -153,11 +153,7 @@ const ContainerMixin = assign({}, ReactMultiChild, {
// Shorthands
mountAndInjectChildren: function(children, transaction, context) {
const mountedImages = this.mountChildren(
children,
transaction,
context
);
const mountedImages = this.mountChildren(children, transaction, context);
// Each mount image corresponds to one of the flattened children
let i = 0;
for (let key in this._renderedChildren) {
@@ -168,15 +164,13 @@ const ContainerMixin = assign({}, ReactMultiChild, {
i++;
}
}
}
},
});
// Surface is a React DOM Component, not an ART component. It serves as the
// entry point into the ART reconciler.
const Surface = React.createClass({
displayName: 'Surface',
mixins: [ContainerMixin],
@@ -192,15 +186,16 @@ const Surface = React.createClass({
this,
this.props.children,
transaction,
ReactInstanceMap.get(this)._context
ReactInstanceMap.get(this)._context,
);
ReactUpdates.ReactReconcileTransaction.release(transaction);
},
componentDidUpdate: function(oldProps) {
const node = this.node;
if (this.props.width != oldProps.width ||
this.props.height != oldProps.height) {
if (
this.props.width != oldProps.width || this.props.height != oldProps.height
) {
node.resize(+this.props.width, +this.props.height);
}
@@ -210,7 +205,7 @@ const Surface = React.createClass({
this,
this.props.children,
transaction,
ReactInstanceMap.get(this)._context
ReactInstanceMap.get(this)._context,
);
ReactUpdates.ReactReconcileTransaction.release(transaction);
@@ -243,8 +238,7 @@ const Surface = React.createClass({
title={props.title}
/>
);
}
},
});
// Various nodes that can go into a surface
@@ -255,11 +249,10 @@ const EventTypes = {
onMouseOut: 'mouseout',
onMouseUp: 'mouseup',
onMouseDown: 'mousedown',
onClick: 'click'
onClick: 'click',
};
const NodeMixin = {
construct: function(element) {
this._currentElement = element;
},
@@ -314,10 +307,12 @@ const NodeMixin = {
applyNodeProps: function(oldProps, props) {
const node = this.node;
const scaleX = props.scaleX != null ? props.scaleX :
props.scale != null ? props.scale : 1;
const scaleY = props.scaleY != null ? props.scaleY :
props.scale != null ? props.scale : 1;
const scaleX = props.scaleX != null
? props.scaleX
: props.scale != null ? props.scale : 1;
const scaleY = props.scaleY != null
? props.scaleY
: props.scale != null ? props.scale : 1;
pooledTransform
.transformTo(1, 0, 0, 1, 0, 0)
@@ -329,9 +324,14 @@ const NodeMixin = {
pooledTransform.transform(props.transform);
}
if (node.xx !== pooledTransform.xx || node.yx !== pooledTransform.yx ||
node.xy !== pooledTransform.xy || node.yy !== pooledTransform.yy ||
node.x !== pooledTransform.x || node.y !== pooledTransform.y) {
if (
node.xx !== pooledTransform.xx ||
node.yx !== pooledTransform.yx ||
node.xy !== pooledTransform.xy ||
node.yy !== pooledTransform.yy ||
node.x !== pooledTransform.x ||
node.y !== pooledTransform.y
) {
node.transformTo(pooledTransform);
}
@@ -359,21 +359,19 @@ const NodeMixin = {
mountComponentIntoNode: function(rootID, container) {
throw new Error(
'You cannot render an ART component standalone. ' +
'You need to wrap it in a Surface.'
'You need to wrap it in a Surface.',
);
}
},
};
// Group
const Group = createComponent('Group', NodeMixin, ContainerMixin, {
mountComponent: function(
transaction,
nativeParent,
nativeContainerInfo,
context
context,
) {
this.node = Mode.Group();
const props = this._currentElement.props;
@@ -399,55 +397,54 @@ const Group = createComponent('Group', NodeMixin, ContainerMixin, {
unmountComponent: function() {
this.destroyEventListeners();
this.unmountChildren();
}
},
});
// ClippingRectangle
const ClippingRectangle = createComponent(
'ClippingRectangle', NodeMixin, ContainerMixin, {
'ClippingRectangle',
NodeMixin,
ContainerMixin,
{
mountComponent: function(
transaction,
nativeParent,
nativeContainerInfo,
context,
) {
this.node = Mode.ClippingRectangle();
const props = this._currentElement.props;
this.applyClippingProps(emptyObject, props);
this.mountAndInjectChildren(props.children, transaction, context);
return this.node;
},
mountComponent: function(
transaction,
nativeParent,
nativeContainerInfo,
context
) {
this.node = Mode.ClippingRectangle();
const props = this._currentElement.props;
this.applyClippingProps(emptyObject, props);
this.mountAndInjectChildren(props.children, transaction, context);
return this.node;
receiveComponent: function(nextComponent, transaction, context) {
const props = nextComponent.props;
const oldProps = this._currentElement.props;
this.applyClippingProps(oldProps, props);
this.updateChildren(props.children, transaction, context);
this._currentElement = nextComponent;
},
applyClippingProps: function(oldProps, props) {
this.node.width = props.width;
this.node.height = props.height;
this.node.x = props.x;
this.node.y = props.y;
this.applyNodeProps(oldProps, props);
},
unmountComponent: function() {
this.destroyEventListeners();
this.unmountChildren();
},
},
receiveComponent: function(nextComponent, transaction, context) {
const props = nextComponent.props;
const oldProps = this._currentElement.props;
this.applyClippingProps(oldProps, props);
this.updateChildren(props.children, transaction, context);
this._currentElement = nextComponent;
},
applyClippingProps: function(oldProps, props) {
this.node.width = props.width;
this.node.height = props.height;
this.node.x = props.x;
this.node.y = props.y;
this.applyNodeProps(oldProps, props);
},
unmountComponent: function() {
this.destroyEventListeners();
this.unmountChildren();
}
});
);
// Renderables
const RenderableMixin = assign({}, NodeMixin, {
applyRenderableProps: function(oldProps, props) {
if (oldProps.fill !== props.fill) {
if (props.fill && props.fill.applyFill) {
@@ -470,7 +467,7 @@ const RenderableMixin = assign({}, NodeMixin, {
props.strokeWidth,
props.strokeCap,
props.strokeJoin,
props.strokeDash
props.strokeDash,
);
}
this.applyNodeProps(oldProps, props);
@@ -478,14 +475,12 @@ const RenderableMixin = assign({}, NodeMixin, {
unmountComponent: function() {
this.destroyEventListeners();
}
},
});
// Shape
const Shape = createComponent('Shape', RenderableMixin, {
construct: function(element) {
this._currentElement = element;
this._oldDelta = null;
@@ -496,7 +491,7 @@ const Shape = createComponent('Shape', RenderableMixin, {
transaction,
nativeParent,
nativeContainerInfo,
context
context,
) {
this.node = Mode.Shape();
const props = this._currentElement.props;
@@ -516,30 +511,25 @@ const Shape = createComponent('Shape', RenderableMixin, {
const oldPath = this._oldPath;
const path = props.d || childrenAsString(props.children);
if (path.delta !== oldDelta ||
path !== oldPath ||
oldProps.width !== props.width ||
oldProps.height !== props.height) {
this.node.draw(
path,
props.width,
props.height
);
if (
path.delta !== oldDelta ||
path !== oldPath ||
oldProps.width !== props.width ||
oldProps.height !== props.height
) {
this.node.draw(path, props.width, props.height);
this._oldPath = path;
this._oldDelta = path.delta;
}
this.applyRenderableProps(oldProps, props);
}
},
});
// Text
const Text = createComponent('Text', RenderableMixin, {
construct: function(element) {
this._currentElement = element;
this._oldString = null;
@@ -549,7 +539,7 @@ const Text = createComponent('Text', RenderableMixin, {
transaction,
nativeParent,
nativeContainerInfo,
context
context,
) {
const props = this._currentElement.props;
const newString = childrenAsString(props.children);
@@ -566,13 +556,11 @@ const Text = createComponent('Text', RenderableMixin, {
if (typeof newFont === 'string' || typeof oldFont === 'string') {
return false;
}
return (
newFont.fontSize === oldFont.fontSize &&
return newFont.fontSize === oldFont.fontSize &&
newFont.fontStyle === oldFont.fontStyle &&
newFont.fontVariant === oldFont.fontVariant &&
newFont.fontWeight === oldFont.fontWeight &&
newFont.fontFamily === oldFont.fontFamily
);
newFont.fontFamily === oldFont.fontFamily;
},
receiveComponent: function(nextComponent, transaction, context) {
@@ -582,23 +570,19 @@ const Text = createComponent('Text', RenderableMixin, {
const oldString = this._oldString;
const newString = childrenAsString(props.children);
if (oldString !== newString ||
!this.isSameFont(oldProps.font, props.font) ||
oldProps.alignment !== props.alignment ||
oldProps.path !== props.path) {
this.node.draw(
newString,
props.font,
props.alignment,
props.path
);
if (
oldString !== newString ||
!this.isSameFont(oldProps.font, props.font) ||
oldProps.alignment !== props.alignment ||
oldProps.path !== props.path
) {
this.node.draw(newString, props.font, props.alignment, props.path);
this._oldString = newString;
}
this.applyRenderableProps(oldProps, props);
this._currentElement = nextComponent;
}
},
});
// Declarative fill type objects - API design not finalized
+43 -39
View File
@@ -49,7 +49,6 @@ function testDOMNodeStructure(domNode, expectedStructure) {
}
describe('ReactART', () => {
beforeEach(() => {
ARTCurrentMode.setCurrent(ARTSVGMode);
@@ -59,29 +58,33 @@ describe('ReactART', () => {
TestComponent = class extends React.Component {
render() {
var a =
var a = (
<Shape
d="M0,0l50,0l0,50l-50,0z"
fill={new ReactART.LinearGradient(["black", "white"])}
fill={new ReactART.LinearGradient(['black', 'white'])}
key="a"
width={50} height={50}
x={50} y={50}
width={50}
height={50}
x={50}
y={50}
opacity={0.1}
/>;
/>
);
var b =
var b = (
<Shape
fill="#3C5A99"
key="b"
scale={0.5}
x={50} y={50}
x={50}
y={50}
title="This is an F"
cursor="pointer">
M64.564,38.583H54l0.008-5.834c0-3.035,0.293-4.666,4.657-4.666
h5.833V16.429h-9.33c-11.213,0-15.159,5.654-15.159,15.16v6.994
h-6.99v11.652h6.99v33.815H54V50.235h9.331L64.564,38.583z
</Shape>;
</Shape>
);
var c = <Group key="c" />;
@@ -113,22 +116,20 @@ describe('ReactART', () => {
width: '150',
height: '200',
children: [
{ nodeName: 'defs' },
{nodeName: 'defs'},
{
nodeName: 'g',
children: [
{
nodeName: 'defs',
children: [
{ nodeName: 'linearGradient' }
]
children: [{nodeName: 'linearGradient'}],
},
{ nodeName: 'path' },
{ nodeName: 'path' },
{ nodeName: 'g' }
]
}
]
{nodeName: 'path'},
{nodeName: 'path'},
{nodeName: 'g'},
],
},
],
};
var realNode = ReactDOM.findDOMNode(instance);
@@ -137,22 +138,25 @@ describe('ReactART', () => {
it('should be able to reorder components', () => {
var container = document.createElement('div');
var instance = ReactDOM.render(<TestComponent flipped={false} />, container);
var instance = ReactDOM.render(
<TestComponent flipped={false} />,
container,
);
var expectedStructure = {
nodeName: 'svg',
children: [
{ nodeName: 'defs' },
{nodeName: 'defs'},
{
nodeName: 'g',
children: [
{ nodeName: 'defs' },
{ nodeName: 'path', opacity: '0.1' },
{ nodeName: 'path', opacity: Missing },
{ nodeName: 'g' }
]
}
]
{nodeName: 'defs'},
{nodeName: 'path', opacity: '0.1'},
{nodeName: 'path', opacity: Missing},
{nodeName: 'g'},
],
},
],
};
var realNode = ReactDOM.findDOMNode(instance);
@@ -163,17 +167,17 @@ describe('ReactART', () => {
var expectedNewStructure = {
nodeName: 'svg',
children: [
{ nodeName: 'defs' },
{nodeName: 'defs'},
{
nodeName: 'g',
children: [
{ nodeName: 'defs' },
{ nodeName: 'path', opacity: Missing },
{ nodeName: 'path', opacity: '0.1' },
{ nodeName: 'g' }
]
}
]
{nodeName: 'defs'},
{nodeName: 'path', opacity: Missing},
{nodeName: 'path', opacity: '0.1'},
{nodeName: 'g'},
],
},
],
};
testDOMNodeStructure(realNode, expectedNewStructure);
@@ -187,7 +191,7 @@ describe('ReactART', () => {
var chars = this.props.chars.split('');
return (
<Surface>
{chars.map((text) => <Shape key={text} title={text} />)}
{chars.map(text => <Shape key={text} title={text} />)}
</Surface>
);
}
@@ -225,7 +229,7 @@ describe('ReactART', () => {
<Group>
<CustomShape />
</Group>
</Surface>
</Surface>,
);
expect(mounted).toBe(true);
});
+23 -20
View File
@@ -44,11 +44,11 @@ var ReactDOM = {
// Allows for debugging when the hook is injected on the page.
if (
typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ !== 'undefined' &&
typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.inject === 'function') {
typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.inject === 'function'
) {
__REACT_DEVTOOLS_GLOBAL_HOOK__.inject({
ComponentTree: {
getClosestInstanceFromNode:
ReactDOMComponentTree.getClosestInstanceFromNode,
getClosestInstanceFromNode: ReactDOMComponentTree.getClosestInstanceFromNode,
getNodeFromInstance: function(inst) {
// inst is an internal instance (but could be a composite)
if (inst._renderedComponent) {
@@ -69,21 +69,24 @@ if (
if (__DEV__) {
var ExecutionEnvironment = require('fbjs/lib/ExecutionEnvironment');
if (ExecutionEnvironment.canUseDOM && window.top === window.self) {
// First check if devtools is not installed
if (typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ === 'undefined') {
// If we're in Chrome or Firefox, provide a download link if not installed.
if ((navigator.userAgent.indexOf('Chrome') > -1 &&
if (
(navigator.userAgent.indexOf('Chrome') > -1 &&
navigator.userAgent.indexOf('Edge') === -1) ||
navigator.userAgent.indexOf('Firefox') > -1) {
navigator.userAgent.indexOf('Firefox') > -1
) {
// Firefox does not have the issue with devtools loaded over file://
var showFileUrlMessage = window.location.protocol.indexOf('http') === -1 &&
navigator.userAgent.indexOf('Firefox') === -1;
var showFileUrlMessage = window.location.protocol.indexOf('http') ===
-1 && navigator.userAgent.indexOf('Firefox') === -1;
console.debug(
'Download the React DevTools ' +
(showFileUrlMessage ? 'and use an HTTP server (instead of a file: URL) ' : '') +
'for a better development experience: ' +
'https://fb.me/react-devtools'
(showFileUrlMessage
? 'and use an HTTP server (instead of a file: URL) '
: '') +
'for a better development experience: ' +
'https://fb.me/react-devtools',
);
}
}
@@ -91,22 +94,22 @@ if (__DEV__) {
var testFunc = function testFn() {};
warning(
(testFunc.name || testFunc.toString()).indexOf('testFn') !== -1,
'It looks like you\'re using a minified copy of the development build ' +
'of React. When deploying React apps to production, make sure to use ' +
'the production build which skips development warnings and is faster. ' +
'See https://fb.me/react-minification for more details.'
"It looks like you're using a minified copy of the development build " +
'of React. When deploying React apps to production, make sure to use ' +
'the production build which skips development warnings and is faster. ' +
'See https://fb.me/react-minification for more details.',
);
// If we're in IE8, check to see if we are in compatibility mode and provide
// information on preventing compatibility mode
var ieCompatibilityMode =
document.documentMode && document.documentMode < 8;
var ieCompatibilityMode = document.documentMode &&
document.documentMode < 8;
warning(
!ieCompatibilityMode,
'Internet Explorer is running in compatibility mode; please add the ' +
'following tag to your HTML to prevent this from happening: ' +
'<meta http-equiv="X-UA-Compatible" content="IE=edge" />'
'following tag to your HTML to prevent this from happening: ' +
'<meta http-equiv="X-UA-Compatible" content="IE=edge" />',
);
var expectedFeatures = [
@@ -127,7 +130,7 @@ if (__DEV__) {
warning(
false,
'One or more ES5 shims expected by React are not available: ' +
'https://fb.me/react-warning-polyfills'
'https://fb.me/react-warning-polyfills',
);
break;
}
+3 -2
View File
@@ -13,5 +13,6 @@ var ReactDOMFeatureFlags = require('ReactDOMFeatureFlags');
var useFiber = ReactDOMFeatureFlags.useFiber;
module.exports =
useFiber ? require('ReactDOMFiber') : require.requireActual('ReactDOM');
module.exports = useFiber
? require('ReactDOMFiber')
: require.requireActual('ReactDOM');
@@ -69,7 +69,7 @@ describe('ReactDOMProduction', () => {
<Component key={2}>B</Component>
<Component key={3}>C</Component>
</div>,
container
container,
);
expect(container.firstChild).toBe(inst);
@@ -82,7 +82,7 @@ describe('ReactDOMProduction', () => {
<Component key={1}>A</Component>
<Component key={3}>C</Component>
</div>,
container
container,
);
expect(inst.className).toBe('red');
@@ -126,10 +126,7 @@ describe('ReactDOMProduction', () => {
}
var container = document.createElement('div');
var inst = ReactDOM.render(
<Component x={1} />,
container
);
var inst = ReactDOM.render(<Component x={1} />, container);
expect(log).toEqual([
['componentWillMount'],
['render'],
@@ -147,15 +144,10 @@ describe('ReactDOMProduction', () => {
log = [];
inst.setState({y: 2});
expect(log).toEqual([
['shouldComponentUpdate', {x: 1}, {y: 2}],
]);
expect(log).toEqual([['shouldComponentUpdate', {x: 1}, {y: 2}]]);
log = [];
ReactDOM.render(
<Component x={2} />,
container
);
ReactDOM.render(<Component x={2} />, container);
expect(log).toEqual([
['componentWillReceiveProps', {x: 2}],
['shouldComponentUpdate', {x: 2}, {y: 2}],
@@ -165,10 +157,7 @@ describe('ReactDOMProduction', () => {
]);
log = [];
ReactDOM.render(
<Component x={2} />,
container
);
ReactDOM.render(<Component x={2} />, container);
expect(log).toEqual([
['componentWillReceiveProps', {x: 2}],
['shouldComponentUpdate', {x: 2}, {y: 2}],
@@ -176,9 +165,7 @@ describe('ReactDOMProduction', () => {
log = [];
ReactDOM.unmountComponentAtNode(container);
expect(log).toEqual([
['componentWillUnmount'],
]);
expect(log).toEqual([['componentWillUnmount']]);
});
it('should throw with an error code in production', () => {
@@ -193,9 +180,9 @@ describe('ReactDOMProduction', () => {
ReactDOM.render(<Component />, container);
}).toThrowError(
'Minified React error #109; visit ' +
'http://facebook.github.io/react/docs/error-decoder.html?invariant=109&args[]=Component' +
' for the full message or use the non-minified dev environment' +
' for full errors and additional helpful warnings.'
'http://facebook.github.io/react/docs/error-decoder.html?invariant=109&args[]=Component' +
' for the full message or use the non-minified dev environment' +
' for full errors and additional helpful warnings.',
);
});
@@ -232,7 +219,7 @@ describe('ReactDOMProduction', () => {
var usePortal = function(tree) {
return ReactDOM.unstable_createPortal(
tree,
document.createElement('div')
document.createElement('div'),
);
};
var assertNamespacesMatch = function(tree) {
@@ -266,14 +253,14 @@ describe('ReactDOMProduction', () => {
{usePortal(<p {...expectHTML} />)}
</svg>
<image {...expectSVG} />
</svg>
</svg>,
)}
<p {...expectHTML} />
</foreignObject>
<image {...expectSVG} />
</svg>
<p {...expectHTML} />
</div>
</div>,
);
});
}
+196 -152
View File
@@ -12,8 +12,8 @@
'use strict';
import type { Fiber } from 'ReactFiber';
import type { ReactNodeList } from 'ReactTypes';
import type {Fiber} from 'ReactFiber';
import type {ReactNodeList} from 'ReactTypes';
var ReactBrowserEventEmitter = require('ReactBrowserEventEmitter');
var ReactControlledComponent = require('ReactControlledComponent');
@@ -28,8 +28,8 @@ var ReactFiberReconciler = require('ReactFiberReconciler');
var ReactInputSelection = require('ReactInputSelection');
var ReactInstanceMap = require('ReactInstanceMap');
var ReactPortal = require('ReactPortal');
var { isValidElement } = require('react');
var { injectInternals } = require('ReactFiberDevToolsHook');
var {isValidElement} = require('react');
var {injectInternals} = require('ReactFiberDevToolsHook');
var findDOMNode = require('findDOMNode');
var invariant = require('fbjs/lib/invariant');
@@ -49,40 +49,39 @@ var {
if (__DEV__) {
var validateDOMNesting = require('validateDOMNesting');
var { updatedAncestorInfo } = validateDOMNesting;
var {updatedAncestorInfo} = validateDOMNesting;
}
const DOCUMENT_NODE = 9;
ReactDOMInjection.inject();
ReactControlledComponent.injection.injectFiberControlledHostComponent(
ReactDOMFiberComponent
ReactDOMFiberComponent,
);
findDOMNode._injectFiber(function(fiber: Fiber) {
return DOMRenderer.findHostInstance(fiber);
});
type DOMContainerElement = Element & { _reactRootContainer: ?Object };
type DOMContainerElement = Element & {_reactRootContainer: ?Object};
type Container = Element;
type Props = {
autoFocus ?: boolean,
children ?: mixed,
hidden ?: boolean,
autoFocus?: boolean,
children?: mixed,
hidden?: boolean,
};
type Instance = Element;
type TextInstance = Text;
type HostContextDev = {
namespace : string,
ancestorInfo : mixed,
namespace: string,
ancestorInfo: mixed,
};
type HostContextProd = string;
type HostContext = HostContextDev | HostContextProd;
let eventsEnabled : ?boolean = null;
let selectionInformation : ?mixed = null;
let eventsEnabled: ?boolean = null;
let selectionInformation: ?mixed = null;
var ELEMENT_NODE_TYPE = 1;
var DOC_NODE_TYPE = 9;
@@ -96,11 +95,10 @@ var DOCUMENT_FRAGMENT_NODE_TYPE = 11;
* @internal
*/
function isValidContainer(node) {
return !!(node && (
node.nodeType === ELEMENT_NODE_TYPE ||
node.nodeType === DOC_NODE_TYPE ||
node.nodeType === DOCUMENT_FRAGMENT_NODE_TYPE
));
return !!(node &&
(node.nodeType === ELEMENT_NODE_TYPE ||
node.nodeType === DOC_NODE_TYPE ||
node.nodeType === DOCUMENT_FRAGMENT_NODE_TYPE));
}
function validateContainer(container) {
@@ -109,7 +107,7 @@ function validateContainer(container) {
}
}
function getReactRootElementInContainer(container : any) {
function getReactRootElementInContainer(container: any) {
if (!container) {
return null;
}
@@ -121,10 +119,7 @@ function getReactRootElementInContainer(container : any) {
}
}
function shouldAutoFocusHostComponent(
type : string,
props : Props,
) : boolean {
function shouldAutoFocusHostComponent(type: string, props: Props): boolean {
switch (type) {
case 'button':
case 'input':
@@ -136,14 +131,16 @@ function shouldAutoFocusHostComponent(
}
var DOMRenderer = ReactFiberReconciler({
getRootHostContext(rootContainerInstance : Container) : HostContext {
getRootHostContext(rootContainerInstance: Container): HostContext {
const ownNamespace = rootContainerInstance.namespaceURI || null;
const type = rootContainerInstance.tagName;
const namespace = getChildNamespace(ownNamespace, type);
if (__DEV__) {
const isMountingIntoDocument = rootContainerInstance.ownerDocument.documentElement === rootContainerInstance;
const validatedTag = isMountingIntoDocument ? '#document' : type.toLowerCase();
const isMountingIntoDocument = rootContainerInstance.ownerDocument.documentElement ===
rootContainerInstance;
const validatedTag = isMountingIntoDocument
? '#document'
: type.toLowerCase();
const ancestorInfo = updatedAncestorInfo(null, validatedTag, null);
return {namespace, ancestorInfo};
}
@@ -151,16 +148,20 @@ var DOMRenderer = ReactFiberReconciler({
},
getChildHostContext(
parentHostContext : HostContext,
type : string,
) : HostContext {
parentHostContext: HostContext,
type: string,
): HostContext {
if (__DEV__) {
const parentHostContextDev = ((parentHostContext : any) : HostContextDev);
const parentHostContextDev = ((parentHostContext: any): HostContextDev);
const namespace = getChildNamespace(parentHostContextDev.namespace, type);
const ancestorInfo = updatedAncestorInfo(parentHostContextDev.ancestorInfo, type, null);
const ancestorInfo = updatedAncestorInfo(
parentHostContextDev.ancestorInfo,
type,
null,
);
return {namespace, ancestorInfo};
}
const parentNamespace = ((parentHostContext : any) : HostContextProd);
const parentNamespace = ((parentHostContext: any): HostContextProd);
return getChildNamespace(parentNamespace, type);
},
@@ -168,13 +169,13 @@ var DOMRenderer = ReactFiberReconciler({
return instance;
},
prepareForCommit() : void {
prepareForCommit(): void {
eventsEnabled = ReactBrowserEventEmitter.isEnabled();
selectionInformation = ReactInputSelection.getSelectionInformation();
ReactBrowserEventEmitter.setEnabled(false);
},
resetAfterCommit() : void {
resetAfterCommit(): void {
ReactInputSelection.restoreSelection(selectionInformation);
selectionInformation = null;
ReactBrowserEventEmitter.setEnabled(eventsEnabled);
@@ -182,88 +183,114 @@ var DOMRenderer = ReactFiberReconciler({
},
createInstance(
type : string,
props : Props,
rootContainerInstance : Container,
hostContext : HostContext,
internalInstanceHandle : Object,
) : Instance {
let parentNamespace : string;
type: string,
props: Props,
rootContainerInstance: Container,
hostContext: HostContext,
internalInstanceHandle: Object,
): Instance {
let parentNamespace: string;
if (__DEV__) {
// TODO: take namespace into account when validating.
const hostContextDev = ((hostContext : any) : HostContextDev);
const hostContextDev = ((hostContext: any): HostContextDev);
validateDOMNesting(type, null, null, hostContextDev.ancestorInfo);
if (
typeof props.children === 'string' ||
typeof props.children === 'number'
typeof props.children === 'string' || typeof props.children === 'number'
) {
const string = '' + props.children;
const ownAncestorInfo = updatedAncestorInfo(hostContextDev.ancestorInfo, type, null);
const ownAncestorInfo = updatedAncestorInfo(
hostContextDev.ancestorInfo,
type,
null,
);
validateDOMNesting(null, string, null, ownAncestorInfo);
}
parentNamespace = hostContextDev.namespace;
} else {
parentNamespace = ((hostContext : any) : HostContextProd);
parentNamespace = ((hostContext: any): HostContextProd);
}
const domElement : Instance = createElement(type, props, rootContainerInstance, parentNamespace);
const domElement: Instance = createElement(
type,
props,
rootContainerInstance,
parentNamespace,
);
precacheFiberNode(internalInstanceHandle, domElement);
updateFiberProps(domElement, props);
return domElement;
},
appendInitialChild(parentInstance : Instance, child : Instance | TextInstance) : void {
appendInitialChild(
parentInstance: Instance,
child: Instance | TextInstance,
): void {
parentInstance.appendChild(child);
},
finalizeInitialChildren(
domElement : Instance,
type : string,
props : Props,
rootContainerInstance : Container,
) : boolean {
domElement: Instance,
type: string,
props: Props,
rootContainerInstance: Container,
): boolean {
setInitialProperties(domElement, type, props, rootContainerInstance);
return shouldAutoFocusHostComponent(type, props);
},
prepareUpdate(
domElement : Instance,
type : string,
oldProps : Props,
newProps : Props,
rootContainerInstance : Container,
hostContext : HostContext,
) : null | Array<mixed> {
domElement: Instance,
type: string,
oldProps: Props,
newProps: Props,
rootContainerInstance: Container,
hostContext: HostContext,
): null | Array<mixed> {
if (__DEV__) {
const hostContextDev = ((hostContext : any) : HostContextDev);
if (typeof newProps.children !== typeof oldProps.children && (
typeof newProps.children === 'string' ||
typeof newProps.children === 'number'
)) {
const hostContextDev = ((hostContext: any): HostContextDev);
if (
typeof newProps.children !== typeof oldProps.children &&
(typeof newProps.children === 'string' ||
typeof newProps.children === 'number')
) {
const string = '' + newProps.children;
const ownAncestorInfo = updatedAncestorInfo(hostContextDev.ancestorInfo, type, null);
const ownAncestorInfo = updatedAncestorInfo(
hostContextDev.ancestorInfo,
type,
null,
);
validateDOMNesting(null, string, null, ownAncestorInfo);
}
}
return diffProperties(domElement, type, oldProps, newProps, rootContainerInstance);
return diffProperties(
domElement,
type,
oldProps,
newProps,
rootContainerInstance,
);
},
commitMount(
domElement : Instance,
type : string,
newProps : Props,
internalInstanceHandle : Object,
) : void {
((domElement : any) : HTMLButtonElement | HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement).focus();
domElement: Instance,
type: string,
newProps: Props,
internalInstanceHandle: Object,
): void {
((domElement: any):
| HTMLButtonElement
| HTMLInputElement
| HTMLSelectElement
| HTMLTextAreaElement).focus();
},
commitUpdate(
domElement : Instance,
updatePayload : Array<mixed>,
type : string,
oldProps : Props,
newProps : Props,
internalInstanceHandle : Object,
) : void {
domElement: Instance,
updatePayload: Array<mixed>,
type: string,
oldProps: Props,
newProps: Props,
internalInstanceHandle: Object,
): void {
// Update the props handle so that we know which props are the ones with
// with current event handlers.
updateFiberProps(domElement, newProps);
@@ -271,58 +298,64 @@ var DOMRenderer = ReactFiberReconciler({
updateProperties(domElement, updatePayload, type, oldProps, newProps);
},
shouldSetTextContent(props : Props) : boolean {
return (
typeof props.children === 'string' ||
shouldSetTextContent(props: Props): boolean {
return typeof props.children === 'string' ||
typeof props.children === 'number' ||
(
typeof props.dangerouslySetInnerHTML === 'object' &&
(typeof props.dangerouslySetInnerHTML === 'object' &&
props.dangerouslySetInnerHTML !== null &&
typeof props.dangerouslySetInnerHTML.__html === 'string'
)
);
typeof props.dangerouslySetInnerHTML.__html === 'string');
},
resetTextContent(domElement : Instance) : void {
resetTextContent(domElement: Instance): void {
domElement.textContent = '';
},
shouldDeprioritizeSubtree(type : string, props : Props) : boolean {
shouldDeprioritizeSubtree(type: string, props: Props): boolean {
return !!props.hidden;
},
createTextInstance(
text : string,
rootContainerInstance : Container,
hostContext : HostContext,
internalInstanceHandle : Object
) : TextInstance {
text: string,
rootContainerInstance: Container,
hostContext: HostContext,
internalInstanceHandle: Object,
): TextInstance {
if (__DEV__) {
const hostContextDev = ((hostContext : any) : HostContextDev);
const hostContextDev = ((hostContext: any): HostContextDev);
validateDOMNesting(null, text, null, hostContextDev.ancestorInfo);
}
var textNode : TextInstance = document.createTextNode(text);
var textNode: TextInstance = document.createTextNode(text);
precacheFiberNode(internalInstanceHandle, textNode);
return textNode;
},
commitTextUpdate(textInstance : TextInstance, oldText : string, newText : string) : void {
commitTextUpdate(
textInstance: TextInstance,
oldText: string,
newText: string,
): void {
textInstance.nodeValue = newText;
},
appendChild(parentInstance : Instance | Container, child : Instance | TextInstance) : void {
appendChild(
parentInstance: Instance | Container,
child: Instance | TextInstance,
): void {
parentInstance.appendChild(child);
},
insertBefore(
parentInstance : Instance | Container,
child : Instance | TextInstance,
beforeChild : Instance | TextInstance
) : void {
parentInstance: Instance | Container,
child: Instance | TextInstance,
beforeChild: Instance | TextInstance,
): void {
parentInstance.insertBefore(child, beforeChild);
},
removeChild(parentInstance : Instance | Container, child : Instance | TextInstance) : void {
removeChild(
parentInstance: Instance | Container,
child: Instance | TextInstance,
): void {
parentInstance.removeChild(child);
},
@@ -331,10 +364,11 @@ var DOMRenderer = ReactFiberReconciler({
scheduleDeferredCallback: ReactDOMFrameScheduling.rIC,
useSyncScheduling: !ReactDOMFeatureFlags.fiberAsyncScheduling,
});
ReactGenericBatching.injection.injectFiberBatchedUpdates(DOMRenderer.batchedUpdates);
ReactGenericBatching.injection.injectFiberBatchedUpdates(
DOMRenderer.batchedUpdates,
);
var warned = false;
@@ -343,21 +377,22 @@ function warnAboutUnstableUse() {
warning(
warned || ReactDOMFeatureFlags.useFiber,
'You are using React DOM Fiber which is an experimental renderer. ' +
'It is likely to have bugs, breaking changes and is unsupported.'
'It is likely to have bugs, breaking changes and is unsupported.',
);
warned = true;
}
function renderSubtreeIntoContainer(
parentComponent : ?ReactComponent<any, any, any>,
children : ReactNodeList,
containerNode : DOMContainerElement | Document,
callback: ?Function
parentComponent: ?ReactComponent<any, any, any>,
children: ReactNodeList,
containerNode: DOMContainerElement | Document,
callback: ?Function,
) {
validateContainer(containerNode);
let container : DOMContainerElement =
containerNode.nodeType === DOCUMENT_NODE ? (containerNode : any).documentElement : (containerNode : any);
let container: DOMContainerElement = containerNode.nodeType === DOCUMENT_NODE
? (containerNode: any).documentElement
: (containerNode: any);
let root = container._reactRootContainer;
if (!root) {
// First clear any existing content.
@@ -365,7 +400,7 @@ function renderSubtreeIntoContainer(
container.removeChild(container.lastChild);
}
const newRoot = DOMRenderer.createContainer(container);
root = container._reactRootContainer = newRoot;
root = (container._reactRootContainer = newRoot);
// Initial mount should not be batched.
DOMRenderer.unbatchedUpdates(() => {
DOMRenderer.updateContainer(children, newRoot, parentComponent, callback);
@@ -377,8 +412,11 @@ function renderSubtreeIntoContainer(
}
var ReactDOM = {
render(element : ReactElement<any>, container : DOMContainerElement, callback: ?Function) {
render(
element: ReactElement<any>,
container: DOMContainerElement,
callback: ?Function,
) {
validateContainer(container);
if (ReactFeatureFlags.disableNewFiberFeatures) {
@@ -390,29 +428,26 @@ var ReactDOM = {
invariant(
false,
'ReactDOM.render(): Invalid component element. Instead of ' +
'passing a string like \'div\', pass ' +
'React.createElement(\'div\') or <div />.'
"passing a string like 'div', pass " +
"React.createElement('div') or <div />.",
);
} else if (typeof element === 'function') {
invariant(
false,
'ReactDOM.render(): Invalid component element. Instead of ' +
'passing a class like Foo, pass React.createElement(Foo) ' +
'or <Foo />.'
'passing a class like Foo, pass React.createElement(Foo) ' +
'or <Foo />.',
);
} else if (element != null && typeof element.props !== 'undefined') {
// Check if it quacks like an element
invariant(
false,
'ReactDOM.render(): Invalid component element. This may be ' +
'caused by unintentionally loading two independent copies ' +
'of React.'
'caused by unintentionally loading two independent copies ' +
'of React.',
);
} else {
invariant(
false,
'ReactDOM.render(): Invalid component element.'
);
invariant(false, 'ReactDOM.render(): Invalid component element.');
}
}
}
@@ -420,24 +455,24 @@ var ReactDOM = {
if (__DEV__) {
const isRootRenderedBySomeReact = !!container._reactRootContainer;
const rootEl = getReactRootElementInContainer(container);
const hasNonRootReactChild = !!(rootEl && ReactDOMComponentTree.getInstanceFromNode(rootEl));
const hasNonRootReactChild = !!(rootEl &&
ReactDOMComponentTree.getInstanceFromNode(rootEl));
warning(
!hasNonRootReactChild ||
isRootRenderedBySomeReact,
!hasNonRootReactChild || isRootRenderedBySomeReact,
'render(...): Replacing React-rendered children with a new root ' +
'component. If you intended to update the children of this node, ' +
'you should instead have the existing children update their state ' +
'and render the new components instead of calling ReactDOM.render.'
'component. If you intended to update the children of this node, ' +
'you should instead have the existing children update their state ' +
'and render the new components instead of calling ReactDOM.render.',
);
warning(
!container.tagName || container.tagName.toUpperCase() !== 'BODY',
'render(): Rendering components directly into document.body is ' +
'discouraged, since its children are often manipulated by third-party ' +
'scripts and browser extensions. This may lead to subtle ' +
'reconciliation issues. Try rendering into a container element created ' +
'for your app.'
'discouraged, since its children are often manipulated by third-party ' +
'scripts and browser extensions. This may lead to subtle ' +
'reconciliation issues. Try rendering into a container element created ' +
'for your app.',
);
}
@@ -445,33 +480,39 @@ var ReactDOM = {
},
unstable_renderSubtreeIntoContainer(
parentComponent : ReactComponent<any, any, any>,
element : ReactElement<any>,
containerNode : DOMContainerElement | Document,
callback: ?Function
parentComponent: ReactComponent<any, any, any>,
element: ReactElement<any>,
containerNode: DOMContainerElement | Document,
callback: ?Function,
) {
invariant(
parentComponent != null && ReactInstanceMap.has(parentComponent),
'parentComponent must be a valid React Component'
'parentComponent must be a valid React Component',
);
return renderSubtreeIntoContainer(
parentComponent,
element,
containerNode,
callback,
);
return renderSubtreeIntoContainer(parentComponent, element, containerNode, callback);
},
unmountComponentAtNode(container : DOMContainerElement) {
unmountComponentAtNode(container: DOMContainerElement) {
invariant(
isValidContainer(container),
'unmountComponentAtNode(...): Target container is not a DOM element.'
'unmountComponentAtNode(...): Target container is not a DOM element.',
);
warnAboutUnstableUse();
if (container._reactRootContainer) {
if (__DEV__) {
const rootEl = getReactRootElementInContainer(container);
const renderedByDifferentReact = rootEl && !ReactDOMComponentTree.getInstanceFromNode(rootEl);
const renderedByDifferentReact = rootEl &&
!ReactDOMComponentTree.getInstanceFromNode(rootEl);
warning(
!renderedByDifferentReact,
'unmountComponentAtNode(): The node you\'re attempting to unmount ' +
'was rendered by another copy of React.'
"unmountComponentAtNode(): The node you're attempting to unmount " +
'was rendered by another copy of React.',
);
}
@@ -486,7 +527,11 @@ var ReactDOM = {
findDOMNode: findDOMNode,
unstable_createPortal(children: ReactNodeList, container : DOMContainerElement, key : ?string = null) {
unstable_createPortal(
children: ReactNodeList,
container: DOMContainerElement,
key: ?string = null,
) {
// TODO: pass ReactDOM portal implementation as third argument
return ReactPortal.createPortal(children, container, null, key);
},
@@ -494,7 +539,6 @@ var ReactDOM = {
unstable_batchedUpdates: ReactGenericBatching.batchedUpdates,
unstable_deferredUpdates: DOMRenderer.deferredUpdates,
};
if (typeof injectInternals === 'function') {
+173 -191
View File
@@ -24,7 +24,7 @@ var ReactDOMFiberInput = require('ReactDOMFiberInput');
var ReactDOMFiberOption = require('ReactDOMFiberOption');
var ReactDOMFiberSelect = require('ReactDOMFiberSelect');
var ReactDOMFiberTextarea = require('ReactDOMFiberTextarea');
var { getCurrentFiberOwnerName } = require('ReactDebugCurrentFiber');
var {getCurrentFiberOwnerName} = require('ReactDebugCurrentFiber');
var emptyFunction = require('fbjs/lib/emptyFunction');
var invariant = require('fbjs/lib/invariant');
@@ -38,9 +38,13 @@ if (__DEV__) {
var ReactDOMInvalidARIAHook = require('ReactDOMInvalidARIAHook');
var ReactDOMNullInputValuePropHook = require('ReactDOMNullInputValuePropHook');
var ReactDOMUnknownPropertyHook = require('ReactDOMUnknownPropertyHook');
var { validateProperties: validateARIAProperties } = ReactDOMInvalidARIAHook;
var { validateProperties: validateInputPropertes } = ReactDOMNullInputValuePropHook;
var { validateProperties: validateUnknownPropertes } = ReactDOMUnknownPropertyHook;
var {validateProperties: validateARIAProperties} = ReactDOMInvalidARIAHook;
var {
validateProperties: validateInputPropertes,
} = ReactDOMNullInputValuePropHook;
var {
validateProperties: validateUnknownPropertes,
} = ReactDOMUnknownPropertyHook;
}
var didWarnShadyDOM = false;
@@ -63,7 +67,6 @@ var {
// Node type for document fragments (Node.DOCUMENT_FRAGMENT_NODE).
var DOC_FRAGMENT_TYPE = 11;
function getDeclarationErrorAddendum() {
var ownerName = getCurrentFiberOwnerName();
if (ownerName) {
@@ -73,7 +76,7 @@ function getDeclarationErrorAddendum() {
return '';
}
function assertValidProps(tag : string, props : ?Object) {
function assertValidProps(tag: string, props: ?Object) {
if (!props) {
return;
}
@@ -82,53 +85,52 @@ function assertValidProps(tag : string, props : ?Object) {
invariant(
props.children == null && props.dangerouslySetInnerHTML == null,
'%s is a void element tag and must neither have `children` nor ' +
'use `dangerouslySetInnerHTML`.%s',
'use `dangerouslySetInnerHTML`.%s',
tag,
getDeclarationErrorAddendum()
getDeclarationErrorAddendum(),
);
}
if (props.dangerouslySetInnerHTML != null) {
invariant(
props.children == null,
'Can only set one of `children` or `props.dangerouslySetInnerHTML`.'
'Can only set one of `children` or `props.dangerouslySetInnerHTML`.',
);
invariant(
typeof props.dangerouslySetInnerHTML === 'object' &&
HTML in props.dangerouslySetInnerHTML,
HTML in props.dangerouslySetInnerHTML,
'`props.dangerouslySetInnerHTML` must be in the form `{__html: ...}`. ' +
'Please visit https://fb.me/react-invariant-dangerously-set-inner-html ' +
'for more information.'
'Please visit https://fb.me/react-invariant-dangerously-set-inner-html ' +
'for more information.',
);
}
if (__DEV__) {
warning(
props.innerHTML == null,
'Directly setting property `innerHTML` is not permitted. ' +
'For more information, lookup documentation on `dangerouslySetInnerHTML`.'
'For more information, lookup documentation on `dangerouslySetInnerHTML`.',
);
warning(
props.suppressContentEditableWarning ||
!props.contentEditable ||
props.children == null,
!props.contentEditable ||
props.children == null,
'A component is `contentEditable` and contains `children` managed by ' +
'React. It is now your responsibility to guarantee that none of ' +
'those nodes are unexpectedly modified or duplicated. This is ' +
'probably not intentional.'
'React. It is now your responsibility to guarantee that none of ' +
'those nodes are unexpectedly modified or duplicated. This is ' +
'probably not intentional.',
);
warning(
props.onFocusIn == null &&
props.onFocusOut == null,
props.onFocusIn == null && props.onFocusOut == null,
'React uses onFocus and onBlur instead of onFocusIn and onFocusOut. ' +
'All React events are normalized to bubble, so onFocusIn and onFocusOut ' +
'are not needed/supported by React.'
'All React events are normalized to bubble, so onFocusIn and onFocusOut ' +
'are not needed/supported by React.',
);
}
invariant(
props.style == null || typeof props.style === 'object',
'The `style` prop expects a mapping from style properties to values, ' +
'not a string. For example, style={{marginRight: spacing + \'em\'}} when ' +
'using JSX.%s',
getDeclarationErrorAddendum()
"not a string. For example, style={{marginRight: spacing + 'em'}} when " +
'using JSX.%s',
getDeclarationErrorAddendum(),
);
}
@@ -146,11 +148,13 @@ function ensureListeningTo(rootContainerElement, registrationName) {
// bubble.
warning(
registrationName !== 'onScroll' || isEventSupported('scroll', true),
'This browser doesn\'t support the `onScroll` event'
"This browser doesn't support the `onScroll` event",
);
}
var isDocumentFragment = rootContainerElement.nodeType === DOC_FRAGMENT_TYPE;
var doc = isDocumentFragment ? rootContainerElement : rootContainerElement.ownerDocument;
var doc = isDocumentFragment
? rootContainerElement
: rootContainerElement.ownerDocument;
listenTo(registrationName, doc);
}
@@ -182,7 +186,7 @@ var mediaEvents = {
topWaiting: 'waiting',
};
function trapClickOnNonInteractiveElement(node : HTMLElement) {
function trapClickOnNonInteractiveElement(node: HTMLElement) {
// Mobile Safari does not fire properly bubble click events on
// non-interactive elements, which means delegated click listeners do not
// fire. The workaround for this bug involves attaching an empty click
@@ -195,7 +199,7 @@ function trapClickOnNonInteractiveElement(node : HTMLElement) {
node.onclick = emptyFunction;
}
function trapBubbledEventsLocal(node : Element, tag : string) {
function trapBubbledEventsLocal(node: Element, tag: string) {
// If a component renders to null or if another component fatals and causes
// the state of the tree to be corrupted, `node` here can be null.
@@ -205,11 +209,7 @@ function trapBubbledEventsLocal(node : Element, tag : string) {
switch (tag) {
case 'iframe':
case 'object':
ReactBrowserEventEmitter.trapBubbledEvent(
'topLoad',
'load',
node
);
ReactBrowserEventEmitter.trapBubbledEvent('topLoad', 'load', node);
break;
case 'video':
case 'audio':
@@ -219,58 +219,30 @@ function trapBubbledEventsLocal(node : Element, tag : string) {
ReactBrowserEventEmitter.trapBubbledEvent(
event,
mediaEvents[event],
node
node,
);
}
}
break;
case 'source':
ReactBrowserEventEmitter.trapBubbledEvent(
'topError',
'error',
node
);
ReactBrowserEventEmitter.trapBubbledEvent('topError', 'error', node);
break;
case 'img':
case 'image':
ReactBrowserEventEmitter.trapBubbledEvent(
'topError',
'error',
node
);
ReactBrowserEventEmitter.trapBubbledEvent(
'topLoad',
'load',
node
);
ReactBrowserEventEmitter.trapBubbledEvent('topError', 'error', node);
ReactBrowserEventEmitter.trapBubbledEvent('topLoad', 'load', node);
break;
case 'form':
ReactBrowserEventEmitter.trapBubbledEvent(
'topReset',
'reset',
node
);
ReactBrowserEventEmitter.trapBubbledEvent(
'topSubmit',
'submit',
node
);
ReactBrowserEventEmitter.trapBubbledEvent('topReset', 'reset', node);
ReactBrowserEventEmitter.trapBubbledEvent('topSubmit', 'submit', node);
break;
case 'input':
case 'select':
case 'textarea':
ReactBrowserEventEmitter.trapBubbledEvent(
'topInvalid',
'invalid',
node
);
ReactBrowserEventEmitter.trapBubbledEvent('topInvalid', 'invalid', node);
break;
case 'details':
ReactBrowserEventEmitter.trapBubbledEvent(
'topToggle',
'toggle',
node
);
ReactBrowserEventEmitter.trapBubbledEvent('topToggle', 'toggle', node);
break;
}
}
@@ -279,21 +251,21 @@ function trapBubbledEventsLocal(node : Element, tag : string) {
// those special-case tags.
var omittedCloseTags = {
'area': true,
'base': true,
'br': true,
'col': true,
'embed': true,
'hr': true,
'img': true,
'input': true,
'keygen': true,
'link': true,
'meta': true,
'param': true,
'source': true,
'track': true,
'wbr': true,
area: true,
base: true,
br: true,
col: true,
embed: true,
hr: true,
img: true,
input: true,
keygen: true,
link: true,
meta: true,
param: true,
source: true,
track: true,
wbr: true,
// NOTE: menuitem's close tag should be omitted, but that causes problems.
};
@@ -301,7 +273,7 @@ var omittedCloseTags = {
// `omittedCloseTags` except that `menuitem` should still have its closing tag.
var voidElementTags = {
'menuitem': true,
menuitem: true,
...omittedCloseTags,
};
@@ -310,11 +282,11 @@ function isCustomComponent(tagName, props) {
}
function setInitialDOMProperties(
domElement : Element,
rootContainerElement : Element,
nextProps : Object,
isCustomComponentTag : boolean,
) : void {
domElement: Element,
rootContainerElement: Element,
nextProps: Object,
isCustomComponentTag: boolean,
): void {
for (var propKey in nextProps) {
var nextProp = nextProps[propKey];
if (!nextProps.hasOwnProperty(propKey)) {
@@ -330,10 +302,7 @@ function setInitialDOMProperties(
}
// Relies on `updateStylesByID` not mutating `styleUpdates`.
// TODO: call ReactInstrumentation.debugTool.onHostOperation in DEV.
CSSPropertyOperations.setValueForStyles(
domElement,
nextProp,
);
CSSPropertyOperations.setValueForStyles(domElement, nextProp);
} else if (propKey === DANGEROUSLY_SET_INNER_HTML) {
var nextHtml = nextProp ? nextProp[HTML] : undefined;
if (nextHtml != null) {
@@ -352,40 +321,37 @@ function setInitialDOMProperties(
ensureListeningTo(rootContainerElement, propKey);
}
} else if (isCustomComponentTag) {
DOMPropertyOperations.setValueForAttribute(
domElement,
propKey,
nextProp
);
DOMPropertyOperations.setValueForAttribute(domElement, propKey, nextProp);
} else if (
DOMProperty.properties[propKey] ||
DOMProperty.isCustomAttribute(propKey)) {
DOMProperty.properties[propKey] || DOMProperty.isCustomAttribute(propKey)
) {
// If we're updating to null or undefined, we should remove the property
// from the DOM node instead of inadvertently setting to a string. This
// brings us in line with the same behavior we have on initial render.
if (nextProp != null) {
DOMPropertyOperations.setValueForProperty(domElement, propKey, nextProp);
DOMPropertyOperations.setValueForProperty(
domElement,
propKey,
nextProp,
);
}
}
}
}
function updateDOMProperties(
domElement : Element,
updatePayload : Array<any>,
wasCustomComponentTag : boolean,
isCustomComponentTag : boolean,
) : void {
domElement: Element,
updatePayload: Array<any>,
wasCustomComponentTag: boolean,
isCustomComponentTag: boolean,
): void {
// TODO: Handle wasCustomComponentTag
for (var i = 0; i < updatePayload.length; i += 2) {
var propKey = updatePayload[i];
var propValue = updatePayload[i + 1];
if (propKey === STYLE) {
// TODO: call ReactInstrumentation.debugTool.onHostOperation in DEV.
CSSPropertyOperations.setValueForStyles(
domElement,
propValue,
);
CSSPropertyOperations.setValueForStyles(domElement, propValue);
} else if (propKey === DANGEROUSLY_SET_INNER_HTML) {
setInnerHTML(domElement, propValue);
} else if (propKey === CHILDREN) {
@@ -395,22 +361,23 @@ function updateDOMProperties(
DOMPropertyOperations.setValueForAttribute(
domElement,
propKey,
propValue
propValue,
);
} else {
DOMPropertyOperations.deleteValueForAttribute(
domElement,
propKey
);
DOMPropertyOperations.deleteValueForAttribute(domElement, propKey);
}
} else if (
DOMProperty.properties[propKey] ||
DOMProperty.isCustomAttribute(propKey)) {
DOMProperty.properties[propKey] || DOMProperty.isCustomAttribute(propKey)
) {
// If we're updating to null or undefined, we should remove the property
// from the DOM node instead of inadvertently setting to a string. This
// brings us in line with the same behavior we have on initial render.
if (propValue != null) {
DOMPropertyOperations.setValueForProperty(domElement, propKey, propValue);
DOMPropertyOperations.setValueForProperty(
domElement,
propKey,
propValue,
);
} else {
DOMPropertyOperations.deleteValueForProperty(domElement, propKey);
}
@@ -419,7 +386,7 @@ function updateDOMProperties(
}
// Assumes there is no parent namespace.
function getIntrinsicNamespace(type : string) : string {
function getIntrinsicNamespace(type: string): string {
switch (type) {
case 'svg':
return SVG_NAMESPACE;
@@ -431,7 +398,7 @@ function getIntrinsicNamespace(type : string) : string {
}
var ReactDOMFiberComponent = {
getChildNamespace(parentNamespace : string | null, type : string) : string {
getChildNamespace(parentNamespace: string | null, type: string): string {
if (parentNamespace == null || parentNamespace === HTML_NAMESPACE) {
// No (or default) parent namespace: potential entry point.
return getIntrinsicNamespace(type);
@@ -445,15 +412,15 @@ var ReactDOMFiberComponent = {
},
createElement(
type : string,
props : Object,
rootContainerElement : Element,
parentNamespace : string
) : Element {
type: string,
props: Object,
rootContainerElement: Element,
parentNamespace: string,
): Element {
// We create tags in the namespace of their parent container, except HTML
// tags get no namespace.
var ownerDocument = rootContainerElement.ownerDocument;
var domElement : Element;
var domElement: Element;
var namespaceURI = parentNamespace;
if (namespaceURI === HTML_NAMESPACE) {
namespaceURI = getIntrinsicNamespace(type);
@@ -461,11 +428,10 @@ var ReactDOMFiberComponent = {
if (namespaceURI === HTML_NAMESPACE) {
if (__DEV__) {
warning(
type === type.toLowerCase() ||
isCustomComponent(type, props),
type === type.toLowerCase() || isCustomComponent(type, props),
'<%s /> is using uppercase HTML. Always use lowercase HTML tags ' +
'in React.',
type
'in React.',
type,
);
}
@@ -473,9 +439,9 @@ var ReactDOMFiberComponent = {
// Create the script via .innerHTML so its "parser-inserted" flag is
// set to true and it does not execute
var div = ownerDocument.createElement('div');
div.innerHTML = '<script><' + '/script>'; // eslint-disable-line
div.innerHTML = '<script><' + '/script>'; // eslint-disable-line
// This is guaranteed to yield a script element.
var firstChild = ((div.firstChild : any) : HTMLScriptElement);
var firstChild = ((div.firstChild: any): HTMLScriptElement);
domElement = div.removeChild(firstChild);
} else if (props.is) {
domElement = ownerDocument.createElement(type, props.is);
@@ -486,22 +452,18 @@ var ReactDOMFiberComponent = {
domElement = ownerDocument.createElement(type);
}
} else {
domElement = ownerDocument.createElementNS(
namespaceURI,
type
);
domElement = ownerDocument.createElementNS(namespaceURI, type);
}
return domElement;
},
setInitialProperties(
domElement : Element,
tag : string,
rawProps : Object,
rootContainerElement : Element
) : void {
domElement: Element,
tag: string,
rawProps: Object,
rootContainerElement: Element,
): void {
var isCustomComponentTag = isCustomComponent(tag, rawProps);
if (__DEV__) {
validatePropertiesInDevelopment(tag, rawProps);
@@ -509,14 +471,14 @@ var ReactDOMFiberComponent = {
warning(
false,
'%s is using shady DOM. Using shady DOM with React can ' +
'cause things to break subtly.',
getCurrentFiberOwnerName() || 'A component'
'cause things to break subtly.',
getCurrentFiberOwnerName() || 'A component',
);
didWarnShadyDOM = true;
}
}
var props : Object;
var props: Object;
switch (tag) {
case 'audio':
case 'form':
@@ -569,20 +531,20 @@ var ReactDOMFiberComponent = {
domElement,
rootContainerElement,
props,
isCustomComponentTag
isCustomComponentTag,
);
switch (tag) {
case 'input':
// TODO: Make sure we check if this is still unmounted or do any clean
// up necessary since we never stop tracking anymore.
inputValueTracking.trackNode((domElement : any));
inputValueTracking.trackNode((domElement: any));
ReactDOMFiberInput.postMountWrapper(domElement, rawProps);
break;
case 'textarea':
// TODO: Make sure we check if this is still unmounted or do any clean
// up necessary since we never stop tracking anymore.
inputValueTracking.trackNode((domElement : any));
inputValueTracking.trackNode((domElement: any));
ReactDOMFiberTextarea.postMountWrapper(domElement, rawProps);
break;
case 'option':
@@ -591,7 +553,7 @@ var ReactDOMFiberComponent = {
default:
if (typeof props.onClick === 'function') {
// TODO: This cast may not be sound for SVG, MathML or custom elements.
trapClickOnNonInteractiveElement(((domElement : any) : HTMLElement));
trapClickOnNonInteractiveElement(((domElement: any): HTMLElement));
}
break;
}
@@ -599,20 +561,20 @@ var ReactDOMFiberComponent = {
// Calculate the diff between the two objects.
diffProperties(
domElement : Element,
tag : string,
lastRawProps : Object,
nextRawProps : Object,
rootContainerElement : Element,
) : null | Array<mixed> {
domElement: Element,
tag: string,
lastRawProps: Object,
nextRawProps: Object,
rootContainerElement: Element,
): null | Array<mixed> {
if (__DEV__) {
validatePropertiesInDevelopment(tag, nextRawProps);
}
var updatePayload : null | Array<any> = null;
var updatePayload: null | Array<any> = null;
var lastProps : Object;
var nextProps : Object;
var lastProps: Object;
var nextProps: Object;
switch (tag) {
case 'input':
lastProps = ReactDOMFiberInput.getHostProps(domElement, lastRawProps);
@@ -630,17 +592,25 @@ var ReactDOMFiberComponent = {
updatePayload = [];
break;
case 'textarea':
lastProps = ReactDOMFiberTextarea.getHostProps(domElement, lastRawProps);
nextProps = ReactDOMFiberTextarea.getHostProps(domElement, nextRawProps);
lastProps = ReactDOMFiberTextarea.getHostProps(
domElement,
lastRawProps,
);
nextProps = ReactDOMFiberTextarea.getHostProps(
domElement,
nextRawProps,
);
updatePayload = [];
break;
default:
lastProps = lastRawProps;
nextProps = nextRawProps;
if (typeof lastProps.onClick !== 'function' &&
typeof nextProps.onClick === 'function') {
if (
typeof lastProps.onClick !== 'function' &&
typeof nextProps.onClick === 'function'
) {
// TODO: This cast may not be sound for SVG, MathML or custom elements.
trapClickOnNonInteractiveElement(((domElement : any) : HTMLElement));
trapClickOnNonInteractiveElement(((domElement: any): HTMLElement));
}
break;
}
@@ -651,9 +621,11 @@ var ReactDOMFiberComponent = {
var styleName;
var styleUpdates = null;
for (propKey in lastProps) {
if (nextProps.hasOwnProperty(propKey) ||
!lastProps.hasOwnProperty(propKey) ||
lastProps[propKey] == null) {
if (
nextProps.hasOwnProperty(propKey) ||
!lastProps.hasOwnProperty(propKey) ||
lastProps[propKey] == null
) {
continue;
}
if (propKey === STYLE) {
@@ -666,8 +638,9 @@ var ReactDOMFiberComponent = {
styleUpdates[styleName] = '';
}
}
} else if (propKey === DANGEROUSLY_SET_INNER_HTML ||
propKey === CHILDREN) {
} else if (
propKey === DANGEROUSLY_SET_INNER_HTML || propKey === CHILDREN
) {
// Noop. This is handled by the clear text mechanism.
} else if (propKey === SUPPRESS_CONTENT_EDITABLE_WARNING) {
// Noop
@@ -686,11 +659,12 @@ var ReactDOMFiberComponent = {
}
for (propKey in nextProps) {
var nextProp = nextProps[propKey];
var lastProp =
lastProps != null ? lastProps[propKey] : undefined;
if (!nextProps.hasOwnProperty(propKey) ||
nextProp === lastProp ||
nextProp == null && lastProp == null) {
var lastProp = lastProps != null ? lastProps[propKey] : undefined;
if (
!nextProps.hasOwnProperty(propKey) ||
nextProp === lastProp ||
(nextProp == null && lastProp == null)
) {
continue;
}
if (propKey === STYLE) {
@@ -704,8 +678,10 @@ var ReactDOMFiberComponent = {
if (lastProp) {
// Unset styles on `lastProp` but not on `nextProp`.
for (styleName in lastProp) {
if (lastProp.hasOwnProperty(styleName) &&
(!nextProp || !nextProp.hasOwnProperty(styleName))) {
if (
lastProp.hasOwnProperty(styleName) &&
(!nextProp || !nextProp.hasOwnProperty(styleName))
) {
if (!styleUpdates) {
styleUpdates = {};
}
@@ -714,8 +690,10 @@ var ReactDOMFiberComponent = {
}
// Update styles that changed since `lastProp`.
for (styleName in nextProp) {
if (nextProp.hasOwnProperty(styleName) &&
lastProp[styleName] !== nextProp[styleName]) {
if (
nextProp.hasOwnProperty(styleName) &&
lastProp[styleName] !== nextProp[styleName]
) {
if (!styleUpdates) {
styleUpdates = {};
}
@@ -744,9 +722,10 @@ var ReactDOMFiberComponent = {
// inserted already.
}
} else if (propKey === CHILDREN) {
if (lastProp !== nextProp && (
typeof nextProp === 'string' || typeof nextProp === 'number'
)) {
if (
lastProp !== nextProp &&
(typeof nextProp === 'string' || typeof nextProp === 'number')
) {
(updatePayload = updatePayload || []).push(propKey, '' + nextProp);
}
} else if (propKey === SUPPRESS_CONTENT_EDITABLE_WARNING) {
@@ -776,12 +755,12 @@ var ReactDOMFiberComponent = {
// Apply the diff.
updateProperties(
domElement : Element,
updatePayload : Array<any>,
tag : string,
lastRawProps : Object,
nextRawProps : Object
) : void {
domElement: Element,
updatePayload: Array<any>,
tag: string,
lastRawProps: Object,
nextRawProps: Object,
): void {
var wasCustomComponentTag = isCustomComponent(tag, lastRawProps);
var isCustomComponentTag = isCustomComponent(tag, nextRawProps);
// Apply the diff.
@@ -789,7 +768,7 @@ var ReactDOMFiberComponent = {
domElement,
updatePayload,
wasCustomComponentTag,
isCustomComponentTag
isCustomComponentTag,
);
// TODO: Ensure that an update gets scheduled if any of the special props
@@ -812,7 +791,11 @@ var ReactDOMFiberComponent = {
}
},
restoreControlledState(domElement : Element, tag : string, props : Object) : void {
restoreControlledState(
domElement: Element,
tag: string,
props: Object,
): void {
switch (tag) {
case 'input':
ReactDOMFiberInput.restoreControlledState(domElement, props);
@@ -825,7 +808,6 @@ var ReactDOMFiberComponent = {
return;
}
},
};
module.exports = ReactDOMFiberComponent;
@@ -20,18 +20,18 @@
// layout, paint and other browser work is counted against the available time.
// The frame rate is dynamically adjusted.
import type { Deadline } from 'ReactFiberReconciler';
import type {Deadline} from 'ReactFiberReconciler';
var invariant = require('fbjs/lib/invariant');
// TODO: There's no way to cancel these, because Fiber doesn't atm.
let rAF : (callback : (time : number) => void) => number;
let rIC : (callback : (deadline : Deadline) => void) => number;
let rAF: (callback: (time: number) => void) => number;
let rIC: (callback: (deadline: Deadline) => void) => number;
if (typeof requestAnimationFrame !== 'function') {
invariant(
false,
'React depends on requestAnimationFrame. Make sure that you load a ' +
'polyfill in older browsers.'
'polyfill in older browsers.',
);
} else if (typeof requestIdleCallback !== 'function') {
// Wrap requestAnimationFrame and polyfill requestIdleCallback.
@@ -50,22 +50,21 @@ if (typeof requestAnimationFrame !== 'function') {
var activeFrameTime = 33;
var frameDeadlineObject = {
timeRemaining: (
typeof performance === 'object' &&
typeof performance.now === 'function' ? function() {
// We assume that if we have a performance timer that the rAF callback
// gets a performance timer value. Not sure if this is always true.
return frameDeadline - performance.now();
} : function() {
// As a fallback we use Date.now.
return frameDeadline - Date.now();
}
),
timeRemaining: typeof performance === 'object' &&
typeof performance.now === 'function'
? function() {
// We assume that if we have a performance timer that the rAF callback
// gets a performance timer value. Not sure if this is always true.
return frameDeadline - performance.now();
}
: function() {
// As a fallback we use Date.now.
return frameDeadline - Date.now();
},
};
// We use the postMessage trick to defer idle work until after the repaint.
var messageKey =
'__reactIdleCallback$' + Math.random().toString(36).slice(2);
var messageKey = '__reactIdleCallback$' + Math.random().toString(36).slice(2);
var idleTick = function(event) {
if (event.source !== window || event.data !== messageKey) {
return;
@@ -84,7 +83,9 @@ if (typeof requestAnimationFrame !== 'function') {
var animationTick = function(rafTime) {
isAnimationFrameScheduled = false;
var nextFrameTime = rafTime - frameDeadline + activeFrameTime;
if (nextFrameTime < activeFrameTime && previousFrameTime < activeFrameTime) {
if (
nextFrameTime < activeFrameTime && previousFrameTime < activeFrameTime
) {
if (nextFrameTime < 8) {
// Defensive coding. We don't support higher frame rates than 120hz.
// If we get lower than that, it is probably a bug.
@@ -97,8 +98,9 @@ if (typeof requestAnimationFrame !== 'function') {
// running on 120hz display or 90hz VR display.
// Take the max of the two in case one of them was an anomaly due to
// missed frame deadlines.
activeFrameTime = nextFrameTime < previousFrameTime ?
previousFrameTime : nextFrameTime;
activeFrameTime = nextFrameTime < previousFrameTime
? previousFrameTime
: nextFrameTime;
} else {
previousFrameTime = nextFrameTime;
}
@@ -114,7 +116,7 @@ if (typeof requestAnimationFrame !== 'function') {
}
};
rAF = function(callback : (time : number) => void) : number {
rAF = function(callback: (time: number) => void): number {
// This assumes that we only schedule one callback at a time because that's
// how Fiber uses it.
scheduledRAFCallback = callback;
@@ -126,7 +128,7 @@ if (typeof requestAnimationFrame !== 'function') {
return 0;
};
rIC = function(callback : (deadline : Deadline) => void) : number {
rIC = function(callback: (deadline: Deadline) => void): number {
// This assumes that we only schedule one callback at a time because that's
// how Fiber uses it.
scheduledRICCallback = callback;
@@ -34,20 +34,14 @@ describe('ReactDOMFiber', () => {
it('should render strings as children', () => {
const Box = ({value}) => <div>{value}</div>;
ReactDOM.render(
<Box value="foo" />,
container
);
ReactDOM.render(<Box value="foo" />, container);
expect(container.textContent).toEqual('foo');
});
it('should render numbers as children', () => {
const Box = ({value}) => <div>{value}</div>;
ReactDOM.render(
<Box value={10} />,
container
);
ReactDOM.render(<Box value={10} />, container);
expect(container.textContent).toEqual('10');
});
@@ -55,20 +49,12 @@ describe('ReactDOMFiber', () => {
it('should be called a callback argument', () => {
// mounting phase
let called = false;
ReactDOM.render(
<div>Foo</div>,
container,
() => called = true
);
ReactDOM.render(<div>Foo</div>, container, () => called = true);
expect(called).toEqual(true);
// updating phase
called = false;
ReactDOM.render(
<div>Foo</div>,
container,
() => called = true
);
ReactDOM.render(<div>Foo</div>, container, () => called = true);
expect(called).toEqual(true);
});
@@ -82,21 +68,13 @@ describe('ReactDOMFiber', () => {
// mounting phase
let called = false;
ReactDOM.render(
element,
container,
() => called = true
);
ReactDOM.render(element, container, () => called = true);
expect(called).toEqual(true);
// updating phase
called = false;
ReactDOM.unstable_batchedUpdates(() => {
ReactDOM.render(
element,
container,
() => called = true
);
ReactDOM.render(element, container, () => called = true);
});
expect(called).toEqual(true);
});
@@ -105,20 +83,14 @@ describe('ReactDOMFiber', () => {
it('should render a component returning strings directly from render', () => {
const Text = ({value}) => value;
ReactDOM.render(
<Text value="foo" />,
container
);
ReactDOM.render(<Text value="foo" />, container);
expect(container.textContent).toEqual('foo');
});
it('should render a component returning numbers directly from render', () => {
const Text = ({value}) => value;
ReactDOM.render(
<Text value={10} />,
container
);
ReactDOM.render(<Text value={10} />, container);
expect(container.textContent).toEqual('10');
});
@@ -133,7 +105,7 @@ describe('ReactDOMFiber', () => {
let instance = null;
ReactDOM.render(
<Text value="foo" ref={ref => instance = ref} />,
container
container,
);
const textNode = ReactDOM.findDOMNode(instance);
@@ -145,18 +117,12 @@ describe('ReactDOMFiber', () => {
it('finds the first child when a component returns a fragment', () => {
class Fragment extends React.Component {
render() {
return [
<div />,
<span />,
];
return [<div />, <span />];
}
}
let instance = null;
ReactDOM.render(
<Fragment ref={ref => instance = ref} />,
container
);
ReactDOM.render(<Fragment ref={ref => instance = ref} />, container);
expect(container.childNodes.length).toBe(2);
@@ -174,18 +140,12 @@ describe('ReactDOMFiber', () => {
class Fragment extends React.Component {
render() {
return [
<Wrapper><div /></Wrapper>,
<span />,
];
return [<Wrapper><div /></Wrapper>, <span />];
}
}
let instance = null;
ReactDOM.render(
<Fragment ref={ref => instance = ref} />,
container
);
ReactDOM.render(<Fragment ref={ref => instance = ref} />, container);
expect(container.childNodes.length).toBe(2);
@@ -203,19 +163,12 @@ describe('ReactDOMFiber', () => {
class Fragment extends React.Component {
render() {
return [
<NullComponent />,
<div />,
<span />,
];
return [<NullComponent />, <div />, <span />];
}
}
let instance = null;
ReactDOM.render(
<Fragment ref={ref => instance = ref} />,
container
);
ReactDOM.render(<Fragment ref={ref => instance = ref} />, container);
expect(container.childNodes.length).toBe(2);
@@ -234,7 +187,7 @@ describe('ReactDOMFiber', () => {
var usePortal = function(tree) {
return ReactDOM.unstable_createPortal(
tree,
document.createElement('div')
document.createElement('div'),
);
};
@@ -264,12 +217,9 @@ describe('ReactDOMFiber', () => {
ReactDOM.render(
<div>
{ReactDOM.unstable_createPortal(
<div>portal</div>,
portalContainer
)}
{ReactDOM.unstable_createPortal(<div>portal</div>, portalContainer)}
</div>,
container
container,
);
expect(portalContainer.innerHTML).toBe('<div>portal</div>');
expect(container.innerHTML).toBe('<div></div>');
@@ -315,7 +265,7 @@ describe('ReactDOMFiber', () => {
<Child name={`normal[0]:${step}`} />,
ReactDOM.unstable_createPortal(
<Child name={`portal1[0]:${step}`} />,
portalContainer1
portalContainer1,
),
<Child name={`normal[1]:${step}`} />,
ReactDOM.unstable_createPortal(
@@ -323,7 +273,7 @@ describe('ReactDOMFiber', () => {
<Child name={`portal2[0]:${step}`} />,
<Child name={`portal2[1]:${step}`} />,
],
portalContainer2
portalContainer2,
),
];
}
@@ -331,8 +281,12 @@ describe('ReactDOMFiber', () => {
ReactDOM.render(<Parent step="a" />, container);
expect(portalContainer1.innerHTML).toBe('<div>portal1[0]:a</div>');
expect(portalContainer2.innerHTML).toBe('<div>portal2[0]:a</div><div>portal2[1]:a</div>');
expect(container.innerHTML).toBe('<div>normal[0]:a</div><div>normal[1]:a</div>');
expect(portalContainer2.innerHTML).toBe(
'<div>portal2[0]:a</div><div>portal2[1]:a</div>',
);
expect(container.innerHTML).toBe(
'<div>normal[0]:a</div><div>normal[1]:a</div>',
);
expect(ops).toEqual([
'normal[0]:a componentDidMount',
'portal1[0]:a componentDidMount',
@@ -345,8 +299,12 @@ describe('ReactDOMFiber', () => {
ops.length = 0;
ReactDOM.render(<Parent step="b" />, container);
expect(portalContainer1.innerHTML).toBe('<div>portal1[0]:b</div>');
expect(portalContainer2.innerHTML).toBe('<div>portal2[0]:b</div><div>portal2[1]:b</div>');
expect(container.innerHTML).toBe('<div>normal[0]:b</div><div>normal[1]:b</div>');
expect(portalContainer2.innerHTML).toBe(
'<div>portal2[0]:b</div><div>portal2[1]:b</div>',
);
expect(container.innerHTML).toBe(
'<div>normal[0]:b</div><div>normal[1]:b</div>',
);
expect(ops).toEqual([
'normal[0]:b componentDidUpdate',
'portal1[0]:b componentDidUpdate',
@@ -376,26 +334,36 @@ describe('ReactDOMFiber', () => {
var portalContainer2 = document.createElement('div');
var portalContainer3 = document.createElement('div');
ReactDOM.render([
<div>normal[0]</div>,
ReactDOM.unstable_createPortal([
<div>portal1[0]</div>,
ReactDOM.render(
[
<div>normal[0]</div>,
ReactDOM.unstable_createPortal(
<div>portal2[0]</div>,
portalContainer2
[
<div>portal1[0]</div>,
ReactDOM.unstable_createPortal(
<div>portal2[0]</div>,
portalContainer2,
),
ReactDOM.unstable_createPortal(
<div>portal3[0]</div>,
portalContainer3,
),
<div>portal1[1]</div>,
],
portalContainer1,
),
ReactDOM.unstable_createPortal(
<div>portal3[0]</div>,
portalContainer3
),
<div>portal1[1]</div>,
], portalContainer1),
<div>normal[1]</div>,
], container);
expect(portalContainer1.innerHTML).toBe('<div>portal1[0]</div><div>portal1[1]</div>');
<div>normal[1]</div>,
],
container,
);
expect(portalContainer1.innerHTML).toBe(
'<div>portal1[0]</div><div>portal1[1]</div>',
);
expect(portalContainer2.innerHTML).toBe('<div>portal2[0]</div>');
expect(portalContainer3.innerHTML).toBe('<div>portal3[0]</div>');
expect(container.innerHTML).toBe('<div>normal[0]</div><div>normal[1]</div>');
expect(container.innerHTML).toBe(
'<div>normal[0]</div><div>normal[1]</div>',
);
ReactDOM.unmountComponentAtNode(container);
expect(portalContainer1.innerHTML).toBe('');
@@ -409,72 +377,54 @@ describe('ReactDOMFiber', () => {
ReactDOM.render(
<div>
{ReactDOM.unstable_createPortal(
<div>portal:1</div>,
portalContainer
)}
{ReactDOM.unstable_createPortal(<div>portal:1</div>, portalContainer)}
</div>,
container
container,
);
expect(portalContainer.innerHTML).toBe('<div>portal:1</div>');
expect(container.innerHTML).toBe('<div></div>');
ReactDOM.render(
<div>
{ReactDOM.unstable_createPortal(
<div>portal:2</div>,
portalContainer
)}
{ReactDOM.unstable_createPortal(<div>portal:2</div>, portalContainer)}
</div>,
container
container,
);
expect(portalContainer.innerHTML).toBe('<div>portal:2</div>');
expect(container.innerHTML).toBe('<div></div>');
ReactDOM.render(
<div>
{ReactDOM.unstable_createPortal(
<p>portal:3</p>,
portalContainer
)}
{ReactDOM.unstable_createPortal(<p>portal:3</p>, portalContainer)}
</div>,
container
container,
);
expect(portalContainer.innerHTML).toBe('<p>portal:3</p>');
expect(container.innerHTML).toBe('<div></div>');
ReactDOM.render(
<div>
{ReactDOM.unstable_createPortal(
['Hi', 'Bye'],
portalContainer
)}
{ReactDOM.unstable_createPortal(['Hi', 'Bye'], portalContainer)}
</div>,
container
container,
);
expect(portalContainer.innerHTML).toBe('HiBye');
expect(container.innerHTML).toBe('<div></div>');
ReactDOM.render(
<div>
{ReactDOM.unstable_createPortal(
['Bye', 'Hi'],
portalContainer
)}
{ReactDOM.unstable_createPortal(['Bye', 'Hi'], portalContainer)}
</div>,
container
container,
);
expect(portalContainer.innerHTML).toBe('ByeHi');
expect(container.innerHTML).toBe('<div></div>');
ReactDOM.render(
<div>
{ReactDOM.unstable_createPortal(
null,
portalContainer
)}
{ReactDOM.unstable_createPortal(null, portalContainer)}
</div>,
container
container,
);
expect(portalContainer.innerHTML).toBe('');
expect(container.innerHTML).toBe('<div></div>');
@@ -484,20 +434,16 @@ describe('ReactDOMFiber', () => {
assertNamespacesMatch(
<svg {...expectSVG}>
<image {...expectSVG} />
{usePortal(
<div {...expectHTML} />
)}
{usePortal(<div {...expectHTML} />)}
<image {...expectSVG} />
</svg>
</svg>,
);
assertNamespacesMatch(
<math {...expectMath}>
<mi {...expectMath} />
{usePortal(
<div {...expectHTML} />
)}
{usePortal(<div {...expectHTML} />)}
<mi {...expectMath} />
</math>
</math>,
);
assertNamespacesMatch(
<div {...expectHTML}>
@@ -505,10 +451,10 @@ describe('ReactDOMFiber', () => {
{usePortal(
<svg {...expectSVG}>
<image {...expectSVG} />
</svg>
</svg>,
)}
<p {...expectHTML} />
</div>
</div>,
);
});
@@ -516,15 +462,11 @@ describe('ReactDOMFiber', () => {
assertNamespacesMatch(
<svg {...expectSVG}>
<image {...expectSVG} />
{usePortal(
<div {...expectHTML} />
)}
{usePortal(<div {...expectHTML} />)}
<image {...expectSVG} />
{usePortal(
<div {...expectHTML} />
)}
{usePortal(<div {...expectHTML} />)}
<image {...expectSVG} />
</svg>
</svg>,
);
assertNamespacesMatch(
<div {...expectHTML}>
@@ -533,11 +475,11 @@ describe('ReactDOMFiber', () => {
{usePortal(
<svg {...expectSVG}>
<image {...expectSVG} />
</svg>
</svg>,
)}
</math>
<p {...expectHTML} />
</div>
</div>,
);
assertNamespacesMatch(
<math {...expectMath}>
@@ -553,34 +495,30 @@ describe('ReactDOMFiber', () => {
<p {...expectHTML} />
</foreignObject>
<image {...expectSVG} />
</svg>
</svg>,
)}
<mi {...expectMath} />
</math>
</math>,
);
assertNamespacesMatch(
<div {...expectHTML}>
{usePortal(
<svg {...expectSVG}>
{usePortal(
<div {...expectHTML} />
)}
{usePortal(<div {...expectHTML} />)}
<image {...expectSVG} />
</svg>
</svg>,
)}
<p {...expectHTML} />
</div>
</div>,
);
assertNamespacesMatch(
<svg {...expectSVG}>
<svg {...expectSVG}>
{usePortal(
<div {...expectHTML} />
)}
{usePortal(<div {...expectHTML} />)}
<image {...expectSVG} />
</svg>
<image {...expectSVG} />
</svg>
</svg>,
);
});
@@ -590,7 +528,7 @@ describe('ReactDOMFiber', () => {
{usePortal(
<svg {...expectSVG}>
<image {...expectSVG} />
</svg>
</svg>,
)}
<p {...expectHTML} />
<svg {...expectSVG}>
@@ -603,7 +541,7 @@ describe('ReactDOMFiber', () => {
<image {...expectSVG} />
</svg>
<p {...expectHTML} />
</div>
</div>,
);
assertNamespacesMatch(
<div {...expectHTML}>
@@ -617,7 +555,7 @@ describe('ReactDOMFiber', () => {
<image {...expectSVG} />
</svg>
<image {...expectSVG} />
</svg>
</svg>,
)}
<image {...expectSVG} />
<foreignObject {...expectSVG}>
@@ -629,7 +567,7 @@ describe('ReactDOMFiber', () => {
<image {...expectSVG} />
</svg>
<p {...expectHTML} />
</div>
</div>,
);
assertNamespacesMatch(
<div {...expectHTML}>
@@ -647,14 +585,14 @@ describe('ReactDOMFiber', () => {
{usePortal(<p {...expectHTML} />)}
</svg>
<image {...expectSVG} />
</svg>
</svg>,
)}
<p {...expectHTML} />
</foreignObject>
<image {...expectSVG} />
</svg>
<p {...expectHTML} />
</div>
</div>,
);
});
@@ -667,12 +605,10 @@ describe('ReactDOMFiber', () => {
assertNamespacesMatch(
<svg {...expectSVG}>
<BrokenRender />
</svg>
</svg>,
);
}).toThrow('Hello');
assertNamespacesMatch(
<div {...expectHTML} />
);
assertNamespacesMatch(<div {...expectHTML} />);
});
it('should unwind namespaces on caught errors', () => {
@@ -703,11 +639,9 @@ describe('ReactDOMFiber', () => {
</ErrorBoundary>
</foreignObject>
<image {...expectSVG} />
</svg>
);
assertNamespacesMatch(
<div {...expectHTML} />
</svg>,
);
assertNamespacesMatch(<div {...expectHTML} />);
});
it('should unwind namespaces on caught errors in a portal', () => {
@@ -736,13 +670,11 @@ describe('ReactDOMFiber', () => {
<math {...expectMath}>
<BrokenRender />)
</math>
</div>
</div>,
)}
</ErrorBoundary>
{usePortal(
<div {...expectHTML} />
)}
</svg>
{usePortal(<div {...expectHTML} />)}
</svg>,
);
});
@@ -771,10 +703,7 @@ describe('ReactDOMFiber', () => {
}
render() {
return ReactDOM.unstable_createPortal(
<Component />,
portalContainer
);
return ReactDOM.unstable_createPortal(<Component />, portalContainer);
}
}
@@ -815,10 +744,7 @@ describe('ReactDOMFiber', () => {
}
render() {
return ReactDOM.unstable_createPortal(
<Component />,
portalContainer
);
return ReactDOM.unstable_createPortal(<Component />, portalContainer);
}
}
@@ -858,10 +784,7 @@ describe('ReactDOMFiber', () => {
}
render() {
return ReactDOM.unstable_createPortal(
<Component />,
portalContainer
);
return ReactDOM.unstable_createPortal(<Component />, portalContainer);
}
}
@@ -876,11 +799,9 @@ describe('ReactDOMFiber', () => {
it('findDOMNode should find dom element after expanding a fragment', () => {
class MyNode extends React.Component {
render() {
return (
!this.props.flag ?
[<div key="a" />] :
[<span key="b" />, <div key="a" />]
);
return !this.props.flag
? [<div key="a" />]
: [<span key="b" />, <div key="a" />];
}
}
@@ -904,13 +825,15 @@ describe('ReactDOMFiber', () => {
ReactDOM.render(
<div onClick={() => ops.push('parent clicked')}>
{ReactDOM.unstable_createPortal(
<div onClick={() => ops.push('portal clicked')} ref={n => portal = n}>
<div
onClick={() => ops.push('portal clicked')}
ref={n => portal = n}>
portal
</div>,
portalContainer
portalContainer,
)}
</div>,
container
container,
);
expect(portal.tagName).toBe('DIV');
@@ -919,13 +842,10 @@ describe('ReactDOMFiber', () => {
ReactTestUtils.simulateNativeEventOnNode(
'topClick',
portal,
fakeNativeEvent
fakeNativeEvent,
);
expect(ops).toEqual([
'portal clicked',
'parent clicked',
]);
expect(ops).toEqual(['portal clicked', 'parent clicked']);
});
it('should not onMouseLeave when staying in the portal', () => {
@@ -938,24 +858,16 @@ describe('ReactDOMFiber', () => {
function simulateMouseMove(from, to) {
if (from) {
ReactTestUtils.simulateNativeEventOnNode(
'topMouseOut',
from,
{
target: from,
relatedTarget: to,
}
);
ReactTestUtils.simulateNativeEventOnNode('topMouseOut', from, {
target: from,
relatedTarget: to,
});
}
if (to) {
ReactTestUtils.simulateNativeEventOnNode(
'topMouseOver',
to,
{
target: to,
relatedTarget: from,
}
);
ReactTestUtils.simulateNativeEventOnNode('topMouseOver', to, {
target: to,
relatedTarget: from,
});
}
}
@@ -972,18 +884,16 @@ describe('ReactDOMFiber', () => {
ref={n => secondTarget = n}>
portal
</div>,
portalContainer
portalContainer,
)}
</div>
<div ref={n => thirdTarget = n} />
</div>,
container
container,
);
simulateMouseMove(null, firstTarget);
expect(ops).toEqual([
'enter parent',
]);
expect(ops).toEqual(['enter parent']);
ops = [];
@@ -1008,18 +918,16 @@ describe('ReactDOMFiber', () => {
const handlerB = () => ops.push('B');
class Example extends React.Component {
state = { flip: false, count: 0 };
state = {flip: false, count: 0};
flip() {
this.setState({ flip: true, count: this.state.count + 1 });
this.setState({flip: true, count: this.state.count + 1});
}
tick() {
this.setState({ count: this.state.count + 1 });
this.setState({count: this.state.count + 1});
}
render() {
const useB = !this.props.forceA && this.state.flip;
return (
<div onClick={useB ? handlerB : handlerA} />
);
return <div onClick={useB ? handlerB : handlerA} />;
}
}
@@ -1043,7 +951,7 @@ describe('ReactDOMFiber', () => {
ReactTestUtils.simulateNativeEventOnNode(
'topClick',
target,
fakeNativeEvent
fakeNativeEvent,
);
}
@@ -1082,7 +990,6 @@ describe('ReactDOMFiber', () => {
// Any click that happens after commit, should invoke A.
click(node);
expect(ops).toEqual(['A']);
});
it('should not crash encountering low-priority tree', () => {
@@ -1090,7 +997,7 @@ describe('ReactDOMFiber', () => {
<div hidden={true}>
<div />
</div>,
container
container,
);
});
}
@@ -1115,11 +1022,17 @@ describe('disableNewFiberFeatures', () => {
it('throws if non-element passed to top-level render', () => {
const message = 'render(): Invalid component element.';
expect(() => ReactDOM.render(null, container)).toThrow(message, container);
expect(() => ReactDOM.render(undefined, container)).toThrow(message, container);
expect(() => ReactDOM.render(undefined, container)).toThrow(
message,
container,
);
expect(() => ReactDOM.render(false, container)).toThrow(message, container);
expect(() => ReactDOM.render('Hi', container)).toThrow(message, container);
expect(() => ReactDOM.render(999, container)).toThrow(message, container);
expect(() => ReactDOM.render([<div />], container)).toThrow(message, container);
expect(() => ReactDOM.render([<div />], container)).toThrow(
message,
container,
);
});
it('throws if something other than false, null, or an element is returned from render', () => {
@@ -1127,9 +1040,16 @@ describe('disableNewFiberFeatures', () => {
return props.children;
}
expect(() => ReactDOM.render(<Render>Hi</Render>, container)).toThrow(/You may have returned undefined/);
expect(() => ReactDOM.render(<Render>{999}</Render>, container)).toThrow(/You may have returned undefined/);
expect(() => ReactDOM.render(<Render>[<div />]</Render>, container)).toThrow(/You may have returned undefined/);
expect(() => ReactDOM.render(<Render>Hi</Render>, container)).toThrow(
/You may have returned undefined/,
);
expect(() => ReactDOM.render(<Render>{999}</Render>, container)).toThrow(
/You may have returned undefined/,
);
expect(() =>
ReactDOM.render(<Render>[<div />]</Render>, container)).toThrow(
/You may have returned undefined/,
);
});
it('treats mocked render functions as if they return null', () => {
@@ -16,14 +16,14 @@ type InputWithWrapperState = HTMLInputElement & {
_wrapperState: {
initialValue: ?string,
initialChecked: ?boolean,
controlled?: boolean
}
controlled?: boolean,
},
};
var DOMPropertyOperations = require('DOMPropertyOperations');
var ReactControlledValuePropTypes = require('ReactControlledValuePropTypes');
var ReactDOMComponentTree = require('ReactDOMComponentTree');
var { getCurrentFiberOwnerName } = require('ReactDebugCurrentFiber');
var {getCurrentFiberOwnerName} = require('ReactDebugCurrentFiber');
var invariant = require('fbjs/lib/invariant');
var warning = require('fbjs/lib/warning');
@@ -55,38 +55,42 @@ function isControlled(props) {
* See http://www.w3.org/TR/2012/WD-html5-20121025/the-input-element.html
*/
var ReactDOMInput = {
getHostProps: function(element : Element, props : Object) {
var node = ((element : any) : InputWithWrapperState);
getHostProps: function(element: Element, props: Object) {
var node = ((element: any): InputWithWrapperState);
var value = props.value;
var checked = props.checked;
var hostProps = Object.assign({
// Make sure we set .type before any other properties (setting .value
// before .type means .value is lost in IE11 and below)
type: undefined,
// Make sure we set .step before .value (setting .value before .step
// means .value is rounded on mount, based upon step precision)
step: undefined,
// Make sure we set .min & .max before .value (to ensure proper order
// in corner cases such as min or max deriving from value, e.g. Issue #7170)
min: undefined,
max: undefined,
}, props, {
defaultChecked: undefined,
defaultValue: undefined,
value: value != null ? value : node._wrapperState.initialValue,
checked: checked != null ? checked : node._wrapperState.initialChecked,
});
var hostProps = Object.assign(
{
// Make sure we set .type before any other properties (setting .value
// before .type means .value is lost in IE11 and below)
type: undefined,
// Make sure we set .step before .value (setting .value before .step
// means .value is rounded on mount, based upon step precision)
step: undefined,
// Make sure we set .min & .max before .value (to ensure proper order
// in corner cases such as min or max deriving from value, e.g. Issue #7170)
min: undefined,
max: undefined,
},
props,
{
defaultChecked: undefined,
defaultValue: undefined,
value: value != null ? value : node._wrapperState.initialValue,
checked: checked != null ? checked : node._wrapperState.initialChecked,
},
);
return hostProps;
},
mountWrapper: function(element : Element, props : Object) {
mountWrapper: function(element: Element, props: Object) {
if (__DEV__) {
ReactControlledValuePropTypes.checkPropTypes(
'input',
props,
getCurrentFiberOwnerName()
getCurrentFiberOwnerName(),
);
if (
@@ -97,13 +101,13 @@ var ReactDOMInput = {
warning(
false,
'%s contains an input of type %s with both checked and defaultChecked props. ' +
'Input elements must be either controlled or uncontrolled ' +
'(specify either the checked prop, or the defaultChecked prop, but not ' +
'both). Decide between using a controlled or uncontrolled input ' +
'element and remove one of these props. More info: ' +
'https://fb.me/react-controlled-components',
'Input elements must be either controlled or uncontrolled ' +
'(specify either the checked prop, or the defaultChecked prop, but not ' +
'both). Decide between using a controlled or uncontrolled input ' +
'element and remove one of these props. More info: ' +
'https://fb.me/react-controlled-components',
getCurrentFiberOwnerName() || 'A component',
props.type
props.type,
);
didWarnCheckedDefaultChecked = true;
}
@@ -115,22 +119,24 @@ var ReactDOMInput = {
warning(
false,
'%s contains an input of type %s with both value and defaultValue props. ' +
'Input elements must be either controlled or uncontrolled ' +
'(specify either the value prop, or the defaultValue prop, but not ' +
'both). Decide between using a controlled or uncontrolled input ' +
'element and remove one of these props. More info: ' +
'https://fb.me/react-controlled-components',
'Input elements must be either controlled or uncontrolled ' +
'(specify either the value prop, or the defaultValue prop, but not ' +
'both). Decide between using a controlled or uncontrolled input ' +
'element and remove one of these props. More info: ' +
'https://fb.me/react-controlled-components',
getCurrentFiberOwnerName() || 'A component',
props.type
props.type,
);
didWarnValueDefaultValue = true;
}
}
var defaultValue = props.defaultValue;
var node = ((element : any) : InputWithWrapperState);
var node = ((element: any): InputWithWrapperState);
node._wrapperState = {
initialChecked: props.checked != null ? props.checked : props.defaultChecked,
initialChecked: props.checked != null
? props.checked
: props.defaultChecked,
initialValue: props.value != null ? props.value : defaultValue,
};
@@ -139,32 +145,40 @@ var ReactDOMInput = {
}
},
updateWrapper: function(element : Element, props : Object) {
var node = ((element : any) : InputWithWrapperState);
updateWrapper: function(element: Element, props: Object) {
var node = ((element: any): InputWithWrapperState);
if (__DEV__) {
var controlled = isControlled(props);
if (!node._wrapperState.controlled && controlled && !didWarnUncontrolledToControlled) {
if (
!node._wrapperState.controlled &&
controlled &&
!didWarnUncontrolledToControlled
) {
warning(
false,
'%s is changing an uncontrolled input of type %s to be controlled. ' +
'Input elements should not switch from uncontrolled to controlled (or vice versa). ' +
'Decide between using a controlled or uncontrolled input ' +
'element for the lifetime of the component. More info: https://fb.me/react-controlled-components',
'Input elements should not switch from uncontrolled to controlled (or vice versa). ' +
'Decide between using a controlled or uncontrolled input ' +
'element for the lifetime of the component. More info: https://fb.me/react-controlled-components',
getCurrentFiberOwnerName() || 'A component',
props.type
props.type,
);
didWarnUncontrolledToControlled = true;
}
if (node._wrapperState.controlled && !controlled && !didWarnControlledToUncontrolled) {
if (
node._wrapperState.controlled &&
!controlled &&
!didWarnControlledToUncontrolled
) {
warning(
false,
'%s is changing a controlled input of type %s to be uncontrolled. ' +
'Input elements should not switch from controlled to uncontrolled (or vice versa). ' +
'Decide between using a controlled or uncontrolled input ' +
'element for the lifetime of the component. More info: https://fb.me/react-controlled-components',
'Input elements should not switch from controlled to uncontrolled (or vice versa). ' +
'Decide between using a controlled or uncontrolled input ' +
'element for the lifetime of the component. More info: https://fb.me/react-controlled-components',
getCurrentFiberOwnerName() || 'A component',
props.type
props.type,
);
didWarnControlledToUncontrolled = true;
}
@@ -175,13 +189,12 @@ var ReactDOMInput = {
DOMPropertyOperations.setValueForProperty(
node,
'checked',
checked || false
checked || false,
);
}
var value = props.value;
if (value != null) {
// Cast `value` to a string to ensure the value is set correctly. While
// browsers typically do this as necessary, jsdom doesn't.
var newValue = '' + value;
@@ -210,8 +223,8 @@ var ReactDOMInput = {
}
},
postMountWrapper: function(element : Element, props : Object) {
var node = ((element : any) : InputWithWrapperState);
postMountWrapper: function(element: Element, props: Object) {
var node = ((element: any): InputWithWrapperState);
// Detach value from defaultValue. We won't do anything if we're working on
// submit or reset inputs as those values & defaultValues are linked. They
@@ -256,8 +269,8 @@ var ReactDOMInput = {
}
},
restoreControlledState: function(element : Element, props : Object) {
var node = ((element : any) : InputWithWrapperState);
restoreControlledState: function(element: Element, props: Object) {
var node = ((element: any): InputWithWrapperState);
ReactDOMInput.updateWrapper(node, props);
updateNamedCousins(node, props);
},
@@ -266,10 +279,10 @@ var ReactDOMInput = {
function updateNamedCousins(rootNode, props) {
var name = props.name;
if (props.type === 'radio' && name != null) {
var queryRoot : Element = rootNode;
var queryRoot: Element = rootNode;
while (queryRoot.parentNode) {
queryRoot = ((queryRoot.parentNode : any) : Element);
queryRoot = ((queryRoot.parentNode: any): Element);
}
// If `rootNode.form` was non-null, then we could try `form.elements`,
@@ -280,23 +293,25 @@ function updateNamedCousins(rootNode, props) {
// document. Let's just use the local `querySelectorAll` to ensure we don't
// miss anything.
var group = queryRoot.querySelectorAll(
'input[name=' + JSON.stringify('' + name) + '][type="radio"]');
'input[name=' + JSON.stringify('' + name) + '][type="radio"]',
);
for (var i = 0; i < group.length; i++) {
var otherNode = ((group[i] : any) : HTMLInputElement);
if (otherNode === rootNode ||
otherNode.form !== rootNode.form) {
var otherNode = ((group[i]: any): HTMLInputElement);
if (otherNode === rootNode || otherNode.form !== rootNode.form) {
continue;
}
// This will throw if radio buttons rendered by different copies of React
// and the same name are rendered into the same form (same as #1939).
// That's probably okay; we don't support it just as we don't support
// mixing React radio buttons with non-React ones.
var otherProps = ReactDOMComponentTree.getFiberCurrentPropsFromNode(otherNode);
var otherProps = ReactDOMComponentTree.getFiberCurrentPropsFromNode(
otherNode,
);
invariant(
otherProps,
'ReactDOMInput: Mixing React and non-React radio inputs with the ' +
'same `name` is not supported.'
'same `name` is not supported.',
);
// If this is a controlled radio button group, forcing the input that
// was previously checked to update will cause it to be come re-checked
@@ -39,25 +39,25 @@ function flattenChildren(children) {
* Implements an <option> host component that warns when `selected` is set.
*/
var ReactDOMOption = {
mountWrapper: function(element : Element, props : Object) {
mountWrapper: function(element: Element, props: Object) {
// TODO (yungsters): Remove support for `selected` in <option>.
if (__DEV__) {
warning(
props.selected == null,
'Use the `defaultValue` or `value` props on <select> instead of ' +
'setting `selected` on <option>.'
'setting `selected` on <option>.',
);
}
},
postMountWrapper: function(element : Element, props : Object) {
postMountWrapper: function(element: Element, props: Object) {
// value="" should make a value attribute (#6219)
if (props.value != null) {
element.setAttribute('value', props.value);
}
},
getHostProps: function(element : Element, props : Object) {
getHostProps: function(element: Element, props: Object) {
var hostProps = Object.assign({children: undefined}, props);
var content = flattenChildren(props.children);
@@ -68,7 +68,6 @@ var ReactDOMOption = {
return hostProps;
},
};
module.exports = ReactDOMOption;
@@ -15,12 +15,12 @@
type SelectWithWrapperState = HTMLSelectElement & {
_wrapperState: {
initialValue: ?string,
wasMultiple: boolean
}
wasMultiple: boolean,
},
};
var ReactControlledValuePropTypes = require('ReactControlledValuePropTypes');
var { getCurrentFiberOwnerName } = require('ReactDebugCurrentFiber');
var {getCurrentFiberOwnerName} = require('ReactDebugCurrentFiber');
var warning = require('fbjs/lib/warning');
var didWarnValueDefaultValue = false;
@@ -42,7 +42,7 @@ function checkSelectPropTypes(props) {
ReactControlledValuePropTypes.checkPropTypes(
'select',
props,
getCurrentFiberOwnerName()
getCurrentFiberOwnerName(),
);
for (var i = 0; i < valuePropNames.length; i++) {
@@ -55,28 +55,34 @@ function checkSelectPropTypes(props) {
warning(
false,
'The `%s` prop supplied to <select> must be an array if ' +
'`multiple` is true.%s',
'`multiple` is true.%s',
propName,
getDeclarationErrorAddendum()
getDeclarationErrorAddendum(),
);
} else if (!props.multiple && isArray) {
warning(
false,
'The `%s` prop supplied to <select> must be a scalar ' +
'value if `multiple` is false.%s',
'value if `multiple` is false.%s',
propName,
getDeclarationErrorAddendum()
getDeclarationErrorAddendum(),
);
}
}
}
function updateOptions(node : HTMLSelectElement, multiple : boolean, propValue : any) {
type IndexableHTMLOptionsCollection = HTMLOptionsCollection & { [key:number]: HTMLOptionElement };
var options : IndexableHTMLOptionsCollection = node.options;
function updateOptions(
node: HTMLSelectElement,
multiple: boolean,
propValue: any,
) {
type IndexableHTMLOptionsCollection = HTMLOptionsCollection & {
[key: number]: HTMLOptionElement,
};
var options: IndexableHTMLOptionsCollection = node.options;
if (multiple) {
let selectedValues = (propValue : Array<string>);
let selectedValues = (propValue: Array<string>);
let selectedValue = {};
for (let i = 0; i < selectedValues.length; i++) {
selectedValue['' + selectedValues[i]] = true;
@@ -90,7 +96,7 @@ function updateOptions(node : HTMLSelectElement, multiple : boolean, propValue :
} else {
// Do not set `select.value` as exact behavior isn't consistent across all
// browsers for all cases.
let selectedValue = '' + (propValue : string);
let selectedValue = '' + (propValue: string);
for (let i = 0; i < options.length; i++) {
if (options[i].value === selectedValue) {
options[i].selected = true;
@@ -119,14 +125,14 @@ function updateOptions(node : HTMLSelectElement, multiple : boolean, propValue :
* selected.
*/
var ReactDOMSelect = {
getHostProps: function(element : Element, props : Object) {
getHostProps: function(element: Element, props: Object) {
return Object.assign({}, props, {
value: undefined,
});
},
mountWrapper: function(element : Element, props : Object) {
var node = ((element : any) : SelectWithWrapperState);
mountWrapper: function(element: Element, props: Object) {
var node = ((element: any): SelectWithWrapperState);
if (__DEV__) {
checkSelectPropTypes(props);
}
@@ -145,10 +151,10 @@ var ReactDOMSelect = {
warning(
false,
'Select elements must be either controlled or uncontrolled ' +
'(specify either the value prop, or the defaultValue prop, but not ' +
'both). Decide between using a controlled or uncontrolled select ' +
'element and remove one of these props. More info: ' +
'https://fb.me/react-controlled-components'
'(specify either the value prop, or the defaultValue prop, but not ' +
'both). Decide between using a controlled or uncontrolled select ' +
'element and remove one of these props. More info: ' +
'https://fb.me/react-controlled-components',
);
didWarnValueDefaultValue = true;
}
@@ -161,8 +167,8 @@ var ReactDOMSelect = {
}
},
postUpdateWrapper: function(element : Element, props : Object) {
var node = ((element : any) : SelectWithWrapperState);
postUpdateWrapper: function(element: Element, props: Object) {
var node = ((element: any): SelectWithWrapperState);
// After the initial mount, we control selected-ness manually so don't pass
// this value down
node._wrapperState.initialValue = undefined;
@@ -184,8 +190,8 @@ var ReactDOMSelect = {
}
},
restoreControlledState: function(element : Element, props : Object) {
var node = ((element : any) : SelectWithWrapperState);
restoreControlledState: function(element: Element, props: Object) {
var node = ((element: any): SelectWithWrapperState);
var value = props.value;
if (value != null) {
@@ -15,11 +15,11 @@
type TextAreaWithWrapperState = HTMLTextAreaElement & {
_wrapperState: {
initialValue: string,
}
},
};
var ReactControlledValuePropTypes = require('ReactControlledValuePropTypes');
var { getCurrentFiberOwnerName } = require('ReactDebugCurrentFiber');
var {getCurrentFiberOwnerName} = require('ReactDebugCurrentFiber');
var invariant = require('fbjs/lib/invariant');
var warning = require('fbjs/lib/warning');
@@ -42,11 +42,11 @@ var didWarnValDefaultVal = false;
* `defaultValue` if specified, or the children content (deprecated).
*/
var ReactDOMTextarea = {
getHostProps: function(element : Element, props : Object) {
var node = ((element : any) : TextAreaWithWrapperState);
getHostProps: function(element: Element, props: Object) {
var node = ((element: any): TextAreaWithWrapperState);
invariant(
props.dangerouslySetInnerHTML == null,
'`dangerouslySetInnerHTML` does not make sense on <textarea>.'
'`dangerouslySetInnerHTML` does not make sense on <textarea>.',
);
// Always set children to the same thing. In IE9, the selection range will
@@ -63,13 +63,13 @@ var ReactDOMTextarea = {
return hostProps;
},
mountWrapper: function(element : Element, props : Object) {
var node = ((element : any) : TextAreaWithWrapperState);
mountWrapper: function(element: Element, props: Object) {
var node = ((element: any): TextAreaWithWrapperState);
if (__DEV__) {
ReactControlledValuePropTypes.checkPropTypes(
'textarea',
props,
getCurrentFiberOwnerName()
getCurrentFiberOwnerName(),
);
if (
props.value !== undefined &&
@@ -79,16 +79,15 @@ var ReactDOMTextarea = {
warning(
false,
'Textarea elements must be either controlled or uncontrolled ' +
'(specify either the value prop, or the defaultValue prop, but not ' +
'both). Decide between using a controlled or uncontrolled textarea ' +
'and remove one of these props. More info: ' +
'https://fb.me/react-controlled-components'
'(specify either the value prop, or the defaultValue prop, but not ' +
'both). Decide between using a controlled or uncontrolled textarea ' +
'and remove one of these props. More info: ' +
'https://fb.me/react-controlled-components',
);
didWarnValDefaultVal = true;
}
}
var value = props.value;
var initialValue = value;
@@ -102,17 +101,17 @@ var ReactDOMTextarea = {
warning(
false,
'Use the `defaultValue` or `value` props instead of setting ' +
'children on <textarea>.'
'children on <textarea>.',
);
}
invariant(
defaultValue == null,
'If you supply `defaultValue` on a <textarea>, do not pass children.'
'If you supply `defaultValue` on a <textarea>, do not pass children.',
);
if (Array.isArray(children)) {
invariant(
children.length <= 1,
'<textarea> can only have at most one child.'
'<textarea> can only have at most one child.',
);
children = children[0];
}
@@ -130,8 +129,8 @@ var ReactDOMTextarea = {
};
},
updateWrapper: function(element : Element, props : Object) {
var node = ((element : any) : TextAreaWithWrapperState);
updateWrapper: function(element: Element, props: Object) {
var node = ((element: any): TextAreaWithWrapperState);
var value = props.value;
if (value != null) {
// Cast `value` to a string to ensure the value is set correctly. While
@@ -151,8 +150,8 @@ var ReactDOMTextarea = {
}
},
postMountWrapper: function(element : Element, props : Object) {
var node = ((element : any) : TextAreaWithWrapperState);
postMountWrapper: function(element: Element, props: Object) {
var node = ((element: any): TextAreaWithWrapperState);
// This is in postMount because we need access to the DOM node, which is not
// available until after the component has mounted.
var textContent = node.textContent;
@@ -166,11 +165,10 @@ var ReactDOMTextarea = {
}
},
restoreControlledState: function(element : Element, props : Object) {
restoreControlledState: function(element: Element, props: Object) {
// DOM component is still mounted; update
ReactDOMTextarea.updateWrapper(element, props);
},
};
module.exports = ReactDOMTextarea;
@@ -22,7 +22,7 @@ var memoizeStringOnly = require('fbjs/lib/memoizeStringOnly');
var warning = require('fbjs/lib/warning');
if (__DEV__) {
var { getCurrentFiberOwnerName } = require('ReactDebugCurrentFiber');
var {getCurrentFiberOwnerName} = require('ReactDebugCurrentFiber');
}
var processStyleName = memoizeStringOnly(function(styleName) {
@@ -67,7 +67,7 @@ if (__DEV__) {
'Unsupported style property %s. Did you mean %s?%s',
name,
camelizeStyleName(name),
checkRenderMessage(owner)
checkRenderMessage(owner),
);
};
@@ -82,7 +82,7 @@ if (__DEV__) {
'Unsupported vendor-prefixed style property %s. Did you mean %s?%s',
name,
name.charAt(0).toUpperCase() + name.slice(1),
checkRenderMessage(owner)
checkRenderMessage(owner),
);
};
@@ -94,11 +94,11 @@ if (__DEV__) {
warnedStyleValues[value] = true;
warning(
false,
'Style property values shouldn\'t contain a semicolon.%s ' +
'Try "%s: %s" instead.',
"Style property values shouldn't contain a semicolon.%s " +
'Try "%s: %s" instead.',
checkRenderMessage(owner),
name,
value.replace(badStyleValueWithSemicolonPattern, '')
value.replace(badStyleValueWithSemicolonPattern, ''),
);
};
@@ -112,7 +112,7 @@ if (__DEV__) {
false,
'`NaN` is an invalid value for the `%s` css style property.%s',
name,
checkRenderMessage(owner)
checkRenderMessage(owner),
);
};
@@ -161,7 +161,6 @@ if (__DEV__) {
* Operations for dealing with CSS properties.
*/
var CSSPropertyOperations = {
/**
* Serializes a mapping of style properties for use as inline styles:
*
@@ -187,8 +186,8 @@ var CSSPropertyOperations = {
}
if (styleValue != null) {
serialized += processStyleName(styleName) + ':';
serialized +=
dangerousStyleValue(styleName, styleValue, component) + ';';
serialized += dangerousStyleValue(styleName, styleValue, component) +
';';
}
}
return serialized || null;
@@ -214,7 +213,7 @@ var CSSPropertyOperations = {
var styleValue = dangerousStyleValue(
styleName,
styles[styleName],
component
component,
);
if (styleName === 'float' || styleName === 'cssFloat') {
styleName = styleFloatAccessor;
@@ -222,8 +221,7 @@ var CSSPropertyOperations = {
if (styleValue) {
style[styleName] = styleValue;
} else {
var expansion =
hasShorthandPropertyBug &&
var expansion = hasShorthandPropertyBug &&
CSSProperty.shorthandPropertyExpansions[styleName];
if (expansion) {
// Shorthand property that IE8 won't like unsetting, so unset each
@@ -237,7 +235,6 @@ var CSSPropertyOperations = {
}
}
},
};
module.exports = CSSPropertyOperations;
+22 -17
View File
@@ -66,18 +66,18 @@ var DOMPropertyInjection = {
if (domPropertyConfig.isCustomAttribute) {
DOMProperty._isCustomAttributeFunctions.push(
domPropertyConfig.isCustomAttribute
domPropertyConfig.isCustomAttribute,
);
}
for (var propName in Properties) {
invariant(
!DOMProperty.properties.hasOwnProperty(propName),
'injectDOMPropertyConfig(...): You\'re trying to inject DOM property ' +
'\'%s\' which has already been injected. You may be accidentally ' +
'injecting the same DOM property config twice, or you may be ' +
'injecting two configs that have conflicting property names.',
propName
"injectDOMPropertyConfig(...): You're trying to inject DOM property " +
"'%s' which has already been injected. You may be accidentally " +
'injecting the same DOM property config twice, or you may be ' +
'injecting two configs that have conflicting property names.',
propName,
);
var lowerCased = propName.toLowerCase();
@@ -92,17 +92,23 @@ var DOMPropertyInjection = {
mustUseProperty: checkMask(propConfig, Injection.MUST_USE_PROPERTY),
hasBooleanValue: checkMask(propConfig, Injection.HAS_BOOLEAN_VALUE),
hasNumericValue: checkMask(propConfig, Injection.HAS_NUMERIC_VALUE),
hasPositiveNumericValue:
checkMask(propConfig, Injection.HAS_POSITIVE_NUMERIC_VALUE),
hasOverloadedBooleanValue:
checkMask(propConfig, Injection.HAS_OVERLOADED_BOOLEAN_VALUE),
hasPositiveNumericValue: checkMask(
propConfig,
Injection.HAS_POSITIVE_NUMERIC_VALUE,
),
hasOverloadedBooleanValue: checkMask(
propConfig,
Injection.HAS_OVERLOADED_BOOLEAN_VALUE,
),
};
invariant(
propertyInfo.hasBooleanValue + propertyInfo.hasNumericValue +
propertyInfo.hasOverloadedBooleanValue <= 1,
propertyInfo.hasBooleanValue +
propertyInfo.hasNumericValue +
propertyInfo.hasOverloadedBooleanValue <=
1,
'DOMProperty: Value can be one of boolean, overloaded boolean, or ' +
'numeric value, but not a combination: %s',
propName
'numeric value, but not a combination: %s',
propName,
);
if (__DEV__) {
@@ -138,7 +144,6 @@ var DOMPropertyInjection = {
var ATTRIBUTE_NAME_START_CHAR = ':A-Z_a-z\\u00C0-\\u00D6\\u00D8-\\u00F6\\u00F8-\\u02FF\\u0370-\\u037D\\u037F-\\u1FFF\\u200C-\\u200D\\u2070-\\u218F\\u2C00-\\u2FEF\\u3001-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFFD';
/* eslint-enable max-len */
/**
* DOMProperty exports lookup objects that can be used like functions:
*
@@ -153,12 +158,12 @@ var ATTRIBUTE_NAME_START_CHAR = ':A-Z_a-z\\u00C0-\\u00D6\\u00D8-\\u00F6\\u00F8-\
* @see http://jsperf.com/key-missing
*/
var DOMProperty = {
ID_ATTRIBUTE_NAME: 'data-reactid',
ROOT_ATTRIBUTE_NAME: 'data-reactroot',
ATTRIBUTE_NAME_START_CHAR: ATTRIBUTE_NAME_START_CHAR,
ATTRIBUTE_NAME_CHAR: ATTRIBUTE_NAME_START_CHAR + '\\-.0-9\\u00B7\\u0300-\\u036F\\u203F-\\u2040',
ATTRIBUTE_NAME_CHAR: ATTRIBUTE_NAME_START_CHAR +
'\\-.0-9\\u00B7\\u0300-\\u036F\\u203F-\\u2040',
/**
* Map from property "standard name" to an object with info about how to set
@@ -19,7 +19,11 @@ var quoteAttributeValueForBrowser = require('quoteAttributeValueForBrowser');
var warning = require('fbjs/lib/warning');
var VALID_ATTRIBUTE_NAME_REGEX = new RegExp(
'^[' + DOMProperty.ATTRIBUTE_NAME_START_CHAR + '][' + DOMProperty.ATTRIBUTE_NAME_CHAR + ']*$'
'^[' +
DOMProperty.ATTRIBUTE_NAME_START_CHAR +
'][' +
DOMProperty.ATTRIBUTE_NAME_CHAR +
']*$',
);
var illegalAttributeNameCache = {};
var validatedAttributeNameCache = {};
@@ -36,11 +40,7 @@ function isAttributeNameSafe(attributeName) {
return true;
}
illegalAttributeNameCache[attributeName] = true;
warning(
false,
'Invalid attribute name: `%s`',
attributeName
);
warning(false, 'Invalid attribute name: `%s`', attributeName);
return false;
}
@@ -48,7 +48,7 @@ function shouldIgnoreValue(propertyInfo, value) {
return value == null ||
(propertyInfo.hasBooleanValue && !value) ||
(propertyInfo.hasNumericValue && isNaN(value)) ||
(propertyInfo.hasPositiveNumericValue && (value < 1)) ||
(propertyInfo.hasPositiveNumericValue && value < 1) ||
(propertyInfo.hasOverloadedBooleanValue && value === false);
}
@@ -56,7 +56,6 @@ function shouldIgnoreValue(propertyInfo, value) {
* Operations for dealing with DOM properties.
*/
var DOMPropertyOperations = {
/**
* Creates markup for the ID property.
*
@@ -64,7 +63,8 @@ var DOMPropertyOperations = {
* @return {string} Markup string.
*/
createMarkupForID: function(id) {
return DOMProperty.ID_ATTRIBUTE_NAME + '=' +
return DOMProperty.ID_ATTRIBUTE_NAME +
'=' +
quoteAttributeValueForBrowser(id);
},
@@ -88,15 +88,18 @@ var DOMPropertyOperations = {
* @return {?string} Markup string, or null if the property was invalid.
*/
createMarkupForProperty: function(name, value) {
var propertyInfo = DOMProperty.properties.hasOwnProperty(name) ?
DOMProperty.properties[name] : null;
var propertyInfo = DOMProperty.properties.hasOwnProperty(name)
? DOMProperty.properties[name]
: null;
if (propertyInfo) {
if (shouldIgnoreValue(propertyInfo, value)) {
return '';
}
var attributeName = propertyInfo.attributeName;
if (propertyInfo.hasBooleanValue ||
(propertyInfo.hasOverloadedBooleanValue && value === true)) {
if (
propertyInfo.hasBooleanValue ||
(propertyInfo.hasOverloadedBooleanValue && value === true)
) {
return attributeName + '=""';
}
return attributeName + '=' + quoteAttributeValueForBrowser(value);
@@ -131,8 +134,9 @@ var DOMPropertyOperations = {
* @param {*} value
*/
setValueForProperty: function(node, name, value) {
var propertyInfo = DOMProperty.properties.hasOwnProperty(name) ?
DOMProperty.properties[name] : null;
var propertyInfo = DOMProperty.properties.hasOwnProperty(name)
? DOMProperty.properties[name]
: null;
if (propertyInfo) {
var mutationMethod = propertyInfo.mutationMethod;
if (mutationMethod) {
@@ -151,8 +155,10 @@ var DOMPropertyOperations = {
// ('' + value) makes it output the correct toString()-value.
if (namespace) {
node.setAttributeNS(namespace, attributeName, '' + value);
} else if (propertyInfo.hasBooleanValue ||
(propertyInfo.hasOverloadedBooleanValue && value === true)) {
} else if (
propertyInfo.hasBooleanValue ||
(propertyInfo.hasOverloadedBooleanValue && value === true)
) {
node.setAttribute(attributeName, '');
} else {
node.setAttribute(attributeName, '' + value);
@@ -219,8 +225,9 @@ var DOMPropertyOperations = {
* @param {string} name
*/
deleteValueForProperty: function(node, name) {
var propertyInfo = DOMProperty.properties.hasOwnProperty(name) ?
DOMProperty.properties[name] : null;
var propertyInfo = DOMProperty.properties.hasOwnProperty(name)
? DOMProperty.properties[name]
: null;
if (propertyInfo) {
var mutationMethod = propertyInfo.mutationMethod;
if (mutationMethod) {
@@ -247,7 +254,6 @@ var DOMPropertyOperations = {
});
}
},
};
module.exports = DOMPropertyOperations;
@@ -16,14 +16,12 @@ var DOMProperty = require('DOMProperty');
var MUST_USE_PROPERTY = DOMProperty.injection.MUST_USE_PROPERTY;
var HAS_BOOLEAN_VALUE = DOMProperty.injection.HAS_BOOLEAN_VALUE;
var HAS_NUMERIC_VALUE = DOMProperty.injection.HAS_NUMERIC_VALUE;
var HAS_POSITIVE_NUMERIC_VALUE =
DOMProperty.injection.HAS_POSITIVE_NUMERIC_VALUE;
var HAS_OVERLOADED_BOOLEAN_VALUE =
DOMProperty.injection.HAS_OVERLOADED_BOOLEAN_VALUE;
var HAS_POSITIVE_NUMERIC_VALUE = DOMProperty.injection.HAS_POSITIVE_NUMERIC_VALUE;
var HAS_OVERLOADED_BOOLEAN_VALUE = DOMProperty.injection.HAS_OVERLOADED_BOOLEAN_VALUE;
var HTMLDOMPropertyConfig = {
isCustomAttribute: RegExp.prototype.test.bind(
new RegExp('^(data|aria)-[' + DOMProperty.ATTRIBUTE_NAME_CHAR + ']*$')
new RegExp('^(data|aria)-[' + DOMProperty.ATTRIBUTE_NAME_CHAR + ']*$'),
),
Properties: {
/**
@@ -211,8 +209,7 @@ var HTMLDOMPropertyConfig = {
htmlFor: 'for',
httpEquiv: 'http-equiv',
},
DOMPropertyNames: {
},
DOMPropertyNames: {},
};
module.exports = HTMLDOMPropertyConfig;
@@ -84,8 +84,10 @@ var reactTopListenersCounter = 0;
var topEventMapping = {
topAbort: 'abort',
topAnimationEnd: getVendorPrefixedEventName('animationend') || 'animationend',
topAnimationIteration: getVendorPrefixedEventName('animationiteration') || 'animationiteration',
topAnimationStart: getVendorPrefixedEventName('animationstart') || 'animationstart',
topAnimationIteration: getVendorPrefixedEventName('animationiteration') ||
'animationiteration',
topAnimationStart: getVendorPrefixedEventName('animationstart') ||
'animationstart',
topBlur: 'blur',
topCancel: 'cancel',
topCanPlay: 'canplay',
@@ -145,7 +147,8 @@ var topEventMapping = {
topTouchEnd: 'touchend',
topTouchMove: 'touchmove',
topTouchStart: 'touchstart',
topTransitionEnd: getVendorPrefixedEventName('transitionend') || 'transitionend',
topTransitionEnd: getVendorPrefixedEventName('transitionend') ||
'transitionend',
topVolumeChange: 'volumechange',
topWaiting: 'waiting',
topWheel: 'wheel',
@@ -167,7 +170,6 @@ function getListeningForDocument(mountAt) {
}
var ReactBrowserEventEmitter = Object.assign({}, ReactEventEmitterMixin, {
/**
* Injectable event backend
*/
@@ -179,7 +181,7 @@ var ReactBrowserEventEmitter = Object.assign({}, ReactEventEmitterMixin, {
*/
injectReactEventListener: function(ReactEventListener) {
ReactEventListener.setHandleTopLevel(
ReactBrowserEventEmitter.handleTopLevel
ReactBrowserEventEmitter.handleTopLevel,
);
ReactBrowserEventEmitter.ReactEventListener = ReactEventListener;
},
@@ -200,10 +202,8 @@ var ReactBrowserEventEmitter = Object.assign({}, ReactEventEmitterMixin, {
* @return {boolean} True if callbacks are enabled.
*/
isEnabled: function() {
return !!(
ReactBrowserEventEmitter.ReactEventListener &&
ReactBrowserEventEmitter.ReactEventListener.isEnabled()
);
return !!(ReactBrowserEventEmitter.ReactEventListener &&
ReactBrowserEventEmitter.ReactEventListener.isEnabled());
},
/**
@@ -230,27 +230,27 @@ var ReactBrowserEventEmitter = Object.assign({}, ReactEventEmitterMixin, {
listenTo: function(registrationName, contentDocumentHandle) {
var mountAt = contentDocumentHandle;
var isListening = getListeningForDocument(mountAt);
var dependencies =
EventPluginRegistry.registrationNameDependencies[registrationName];
var dependencies = EventPluginRegistry.registrationNameDependencies[
registrationName
];
for (var i = 0; i < dependencies.length; i++) {
var dependency = dependencies[i];
if (!(
isListening.hasOwnProperty(dependency) &&
isListening[dependency]
)) {
if (
!(isListening.hasOwnProperty(dependency) && isListening[dependency])
) {
if (dependency === 'topWheel') {
if (isEventSupported('wheel')) {
ReactBrowserEventEmitter.ReactEventListener.trapBubbledEvent(
'topWheel',
'wheel',
mountAt
mountAt,
);
} else if (isEventSupported('mousewheel')) {
ReactBrowserEventEmitter.ReactEventListener.trapBubbledEvent(
'topWheel',
'mousewheel',
mountAt
mountAt,
);
} else {
// Firefox needs to capture a different mouse scroll event.
@@ -258,37 +258,34 @@ var ReactBrowserEventEmitter = Object.assign({}, ReactEventEmitterMixin, {
ReactBrowserEventEmitter.ReactEventListener.trapBubbledEvent(
'topWheel',
'DOMMouseScroll',
mountAt
mountAt,
);
}
} else if (dependency === 'topScroll') {
if (isEventSupported('scroll', true)) {
ReactBrowserEventEmitter.ReactEventListener.trapCapturedEvent(
'topScroll',
'scroll',
mountAt
mountAt,
);
} else {
ReactBrowserEventEmitter.ReactEventListener.trapBubbledEvent(
'topScroll',
'scroll',
ReactBrowserEventEmitter.ReactEventListener.WINDOW_HANDLE
ReactBrowserEventEmitter.ReactEventListener.WINDOW_HANDLE,
);
}
} else if (dependency === 'topFocus' ||
dependency === 'topBlur') {
} else if (dependency === 'topFocus' || dependency === 'topBlur') {
if (isEventSupported('focus', true)) {
ReactBrowserEventEmitter.ReactEventListener.trapCapturedEvent(
'topFocus',
'focus',
mountAt
mountAt,
);
ReactBrowserEventEmitter.ReactEventListener.trapCapturedEvent(
'topBlur',
'blur',
mountAt
mountAt,
);
} else if (isEventSupported('focusin')) {
// IE has `focusin` and `focusout` events which bubble.
@@ -296,12 +293,12 @@ var ReactBrowserEventEmitter = Object.assign({}, ReactEventEmitterMixin, {
ReactBrowserEventEmitter.ReactEventListener.trapBubbledEvent(
'topFocus',
'focusin',
mountAt
mountAt,
);
ReactBrowserEventEmitter.ReactEventListener.trapBubbledEvent(
'topBlur',
'focusout',
mountAt
mountAt,
);
}
@@ -313,7 +310,7 @@ var ReactBrowserEventEmitter = Object.assign({}, ReactEventEmitterMixin, {
ReactBrowserEventEmitter.ReactEventListener.trapCapturedEvent(
'topCancel',
'cancel',
mountAt
mountAt,
);
}
isListening.topCancel = true;
@@ -322,7 +319,7 @@ var ReactBrowserEventEmitter = Object.assign({}, ReactEventEmitterMixin, {
ReactBrowserEventEmitter.ReactEventListener.trapCapturedEvent(
'topClose',
'close',
mountAt
mountAt,
);
}
isListening.topClose = true;
@@ -330,7 +327,7 @@ var ReactBrowserEventEmitter = Object.assign({}, ReactEventEmitterMixin, {
ReactBrowserEventEmitter.ReactEventListener.trapBubbledEvent(
dependency,
topEventMapping[dependency],
mountAt
mountAt,
);
}
@@ -341,14 +338,14 @@ var ReactBrowserEventEmitter = Object.assign({}, ReactEventEmitterMixin, {
isListeningToAllDependencies: function(registrationName, mountAt) {
var isListening = getListeningForDocument(mountAt);
var dependencies =
EventPluginRegistry.registrationNameDependencies[registrationName];
var dependencies = EventPluginRegistry.registrationNameDependencies[
registrationName
];
for (var i = 0; i < dependencies.length; i++) {
var dependency = dependencies[i];
if (!(
isListening.hasOwnProperty(dependency) &&
isListening[dependency]
)) {
if (
!(isListening.hasOwnProperty(dependency) && isListening[dependency])
) {
return false;
}
}
@@ -359,7 +356,7 @@ var ReactBrowserEventEmitter = Object.assign({}, ReactEventEmitterMixin, {
return ReactBrowserEventEmitter.ReactEventListener.trapBubbledEvent(
topLevelType,
handlerBaseName,
handle
handle,
);
},
@@ -367,7 +364,7 @@ var ReactBrowserEventEmitter = Object.assign({}, ReactEventEmitterMixin, {
return ReactBrowserEventEmitter.ReactEventListener.trapCapturedEvent(
topLevelType,
handlerBaseName,
handle
handle,
);
},
@@ -405,7 +402,6 @@ var ReactBrowserEventEmitter = Object.assign({}, ReactEventEmitterMixin, {
isMonitoringScrollValue = true;
}
},
});
module.exports = ReactBrowserEventEmitter;
@@ -13,7 +13,7 @@
var DOMProperty = require('DOMProperty');
var ReactDOMComponentFlags = require('ReactDOMComponentFlags');
var { HostComponent, HostText } = require('ReactTypeOfWork');
var {HostComponent, HostText} = require('ReactTypeOfWork');
var invariant = require('fbjs/lib/invariant');
@@ -31,11 +31,10 @@ var internalEventHandlersKey = '__reactEventHandlers$' + randomKey;
*/
function shouldPrecacheNode(node, nodeID) {
return (node.nodeType === 1 &&
node.getAttribute(ATTR_NAME) === ('' + nodeID)) ||
(node.nodeType === 8 &&
node.nodeValue === ' react-text: ' + nodeID + ' ') ||
(node.nodeType === 8 &&
node.nodeValue === ' react-empty: ' + nodeID + ' ');
node.getAttribute(ATTR_NAME) === '' + nodeID) ||
(node.nodeType === 8 &&
node.nodeValue === ' react-text: ' + nodeID + ' ') ||
(node.nodeType === 8 && node.nodeValue === ' react-empty: ' + nodeID + ' ');
}
/**
@@ -194,7 +193,7 @@ function getNodeFromInstance(inst) {
// invariant for a missing parent, which is super confusing.
invariant(
inst._hostNode !== undefined,
'getNodeFromInstance: Invalid argument.'
'getNodeFromInstance: Invalid argument.',
);
if (inst._hostNode) {
@@ -207,7 +206,7 @@ function getNodeFromInstance(inst) {
parents.push(inst);
invariant(
inst._hostParent,
'React DOM tree root should always have a node reference.'
'React DOM tree root should always have a node reference.',
);
inst = inst._hostParent;
}
@@ -39,7 +39,7 @@ function inject() {
alreadyInjected = true;
ReactBrowserEventEmitter.injection.injectReactEventListener(
ReactEventListener
ReactEventListener,
);
/**
@@ -99,7 +99,7 @@ function getModernOffsets(node) {
selection.anchorNode,
selection.anchorOffset,
selection.focusNode,
selection.focusOffset
selection.focusOffset,
);
var rangeLength = isSelectionCollapsed ? 0 : currentRange.toString().length;
@@ -112,7 +112,7 @@ function getModernOffsets(node) {
tempRange.startContainer,
tempRange.startOffset,
tempRange.endContainer,
tempRange.endOffset
tempRange.endOffset,
);
var start = isTempRangeCollapsed ? 0 : tempRange.toString().length;
@@ -176,8 +176,7 @@ function setModernOffsets(node, offsets) {
var selection = window.getSelection();
var length = node[getTextContentAccessor()].length;
var start = Math.min(offsets.start, length);
var end = offsets.end === undefined ?
start : Math.min(offsets.end, length);
var end = offsets.end === undefined ? start : Math.min(offsets.end, length);
// IE 11 uses modern selection, but doesn't support the extend method.
// Flip backward selections, so we can set with a single range.
@@ -205,11 +204,9 @@ function setModernOffsets(node, offsets) {
}
}
var useIEOffsets = (
ExecutionEnvironment.canUseDOM &&
var useIEOffsets = ExecutionEnvironment.canUseDOM &&
'selection' in document &&
!('getSelection' in window)
);
!('getSelection' in window);
var ReactDOMSelection = {
/**
+8 -11
View File
@@ -21,7 +21,7 @@ var ReactTypeOfWork = require('ReactTypeOfWork');
var getEventTarget = require('getEventTarget');
var getUnboundedScrollPosition = require('fbjs/lib/getUnboundedScrollPosition');
var { HostRoot } = ReactTypeOfWork;
var {HostRoot} = ReactTypeOfWork;
/**
* Find the deepest React component completely containing the root of the
@@ -67,7 +67,7 @@ Object.assign(TopLevelCallbackBookKeeping.prototype, {
});
PooledClass.addPoolingTo(
TopLevelCallbackBookKeeping,
PooledClass.threeArgumentPooler
PooledClass.threeArgumentPooler,
);
function handleTopLevelImpl(bookKeeping) {
@@ -88,9 +88,7 @@ function handleTopLevelImpl(bookKeeping) {
break;
}
bookKeeping.ancestors.push(ancestor);
ancestor = ReactDOMComponentTree.getClosestInstanceFromNode(
root
);
ancestor = ReactDOMComponentTree.getClosestInstanceFromNode(root);
} while (ancestor);
for (var i = 0; i < bookKeeping.ancestors.length; i++) {
@@ -99,7 +97,7 @@ function handleTopLevelImpl(bookKeeping) {
bookKeeping.topLevelType,
targetInst,
bookKeeping.nativeEvent,
getEventTarget(bookKeeping.nativeEvent)
getEventTarget(bookKeeping.nativeEvent),
);
}
}
@@ -127,7 +125,6 @@ var ReactEventListener = {
return ReactEventListener._enabled;
},
/**
* Traps top-level events by using event bubbling.
*
@@ -145,7 +142,7 @@ var ReactEventListener = {
return EventListener.listen(
element,
handlerBaseName,
ReactEventListener.dispatchEvent.bind(null, topLevelType)
ReactEventListener.dispatchEvent.bind(null, topLevelType),
);
},
@@ -166,7 +163,7 @@ var ReactEventListener = {
return EventListener.capture(
element,
handlerBaseName,
ReactEventListener.dispatchEvent.bind(null, topLevelType)
ReactEventListener.dispatchEvent.bind(null, topLevelType),
);
},
@@ -182,13 +179,13 @@ var ReactEventListener = {
var nativeEventTarget = getEventTarget(nativeEvent);
var targetInst = ReactDOMComponentTree.getClosestInstanceFromNode(
nativeEventTarget
nativeEventTarget,
);
var bookKeeping = TopLevelCallbackBookKeeping.getPooled(
topLevelType,
nativeEvent,
targetInst
targetInst,
);
try {

Some files were not shown because too many files have changed in this diff Show More