diff --git a/packages/react-dom/src/ReactDOMFiberComponent.js b/packages/react-dom/src/ReactDOMFiberComponent.js index ed2f96703527a..4828633315952 100644 --- a/packages/react-dom/src/ReactDOMFiberComponent.js +++ b/packages/react-dom/src/ReactDOMFiberComponent.js @@ -61,7 +61,7 @@ var HTML = '__html'; var {Namespaces: {html: HTML_NAMESPACE}, getIntrinsicNamespace} = DOMNamespaces; -var getStack = emptyFunction; +var getStack = emptyFunction.thatReturnsArgument(''); if (__DEV__) { getStack = getCurrentFiberStackAddendum; @@ -562,7 +562,7 @@ var ReactDOMFiberComponent = { props = rawProps; } - assertValidProps(tag, props, getCurrentFiberOwnerName); + assertValidProps(tag, props, getStack); setInitialDOMProperties( tag, @@ -656,7 +656,7 @@ var ReactDOMFiberComponent = { break; } - assertValidProps(tag, nextProps, getCurrentFiberOwnerName); + assertValidProps(tag, nextProps, getStack); var propKey; var styleName; @@ -971,7 +971,7 @@ var ReactDOMFiberComponent = { break; } - assertValidProps(tag, rawProps, getCurrentFiberOwnerName); + assertValidProps(tag, rawProps, getStack); if (__DEV__) { var extraAttributeNames: Set = new Set(); diff --git a/packages/react-dom/src/server/ReactPartialRenderer.js b/packages/react-dom/src/server/ReactPartialRenderer.js index 51e8bbdd833f1..9d2aea37a47dc 100644 --- a/packages/react-dom/src/server/ReactPartialRenderer.js +++ b/packages/react-dom/src/server/ReactPartialRenderer.js @@ -30,7 +30,7 @@ var omittedCloseTags = require('omittedCloseTags'); var isCustomComponent = require('isCustomComponent'); var toArray = React.Children.toArray; -var emptyFunctionThatReturnsNull = emptyFunction.thatReturnsNull; +var getStackAddendum = emptyFunction.thatReturnsArgument(''); if (__DEV__) { var warning = require('fbjs/lib/warning'); @@ -80,9 +80,9 @@ if (__DEV__) { currentDebugStack = null; ReactDebugCurrentFrame.getCurrentStack = null; }; - var getStackAddendum = function(): null | string { + getStackAddendum = function(): null | string { if (currentDebugStack === null) { - return null; + return ''; } let stack = ''; let debugStack = currentDebugStack; @@ -141,11 +141,7 @@ function createMarkupForStyles(styles) { var styleValue = styles[styleName]; if (__DEV__) { if (!isCustomProperty) { - warnValidStyle( - styleName, - styleValue, - () => '', // getCurrentFiberStackAddendum, - ); + warnValidStyle(styleName, styleValue, getStackAddendum); } } if (styleValue != null) { @@ -574,7 +570,7 @@ class ReactDOMServerRenderer { ReactControlledValuePropTypes.checkPropTypes( 'input', props, - () => '', //getCurrentFiberStackAddendum + getStackAddendum, ); if ( @@ -632,7 +628,7 @@ class ReactDOMServerRenderer { ReactControlledValuePropTypes.checkPropTypes( 'textarea', props, - () => '', //getCurrentFiberStackAddendum + getStackAddendum, ); if ( props.value !== undefined && @@ -693,7 +689,7 @@ class ReactDOMServerRenderer { ReactControlledValuePropTypes.checkPropTypes( 'select', props, - () => '', // getCurrentFiberStackAddendum, + getStackAddendum, ); for (var i = 0; i < valuePropNames.length; i++) { @@ -785,7 +781,7 @@ class ReactDOMServerRenderer { validatePropertiesInDevelopment(tag, props); } - assertValidProps(tag, props, emptyFunctionThatReturnsNull); + assertValidProps(tag, props, getStackAddendum); var out = createOpenTagMarkup( element.type, diff --git a/packages/react-dom/src/shared/__tests__/ReactDOMComponent-test.js b/packages/react-dom/src/shared/__tests__/ReactDOMComponent-test.js index f19303701f60a..abf0fd7cec6b2 100644 --- a/packages/react-dom/src/shared/__tests__/ReactDOMComponent-test.js +++ b/packages/react-dom/src/shared/__tests__/ReactDOMComponent-test.js @@ -954,50 +954,38 @@ describe('ReactDOMComponent', () => { }); it('should warn against children for void elements', () => { - var container = document.createElement('div'); - - expect(function() { + const container = document.createElement('div'); + let caughtErr; + try { ReactDOM.render(children, container); - }).toThrowError( + } catch (err) { + caughtErr = err; + } + expect(caughtErr).not.toBe(undefined); + expect(normalizeCodeLocInfo(caughtErr.message)).toContain( 'input is a void element tag and must neither have `children` nor ' + 'use `dangerouslySetInnerHTML`.', + '\n in input (at **)', ); }); it('should warn against dangerouslySetInnerHTML for void elements', () => { - var container = document.createElement('div'); - - expect(function() { + const container = document.createElement('div'); + let caughtErr; + try { ReactDOM.render( , container, ); - }).toThrowError( - 'input is a void element tag and must neither have `children` nor use ' + - '`dangerouslySetInnerHTML`.', - ); - }); - - it('should include owner rather than parent in warnings', () => { - var container = document.createElement('div'); - - function Parent(props) { - return props.children; - } - function Owner() { - // We're using the input dangerouslySetInnerHTML invariant but the - // exact error doesn't matter as long as we have a way to verify - // that warnings and invariants contain owner rather than parent name. - return ( - - - - ); + } catch (err) { + caughtErr = err; } - - expect(function() { - ReactDOM.render(, container); - }).toThrowError('\n\nThis DOM node was rendered by `Owner`.'); + expect(caughtErr).not.toBe(undefined); + expect(normalizeCodeLocInfo(caughtErr.message)).toContain( + 'input is a void element tag and must neither have `children` nor ' + + 'use `dangerouslySetInnerHTML`.', + '\n in input (at **)', + ); }); it('should emit a warning once for a named custom component using shady DOM', () => { @@ -1178,19 +1166,27 @@ describe('ReactDOMComponent', () => { expect(tracker.getValue()).toEqual('foo'); }); - it('should warn for children on void elements', () => { + it('should throw for children on void elements', () => { class X extends React.Component { render() { return moo; } } - var container = document.createElement('div'); - expect(function() { + const container = document.createElement('div'); + let caughtErr; + try { ReactDOM.render(, container); - }).toThrowError( + } catch (err) { + caughtErr = err; + } + + expect(caughtErr).not.toBe(undefined); + expect(normalizeCodeLocInfo(caughtErr.message)).toContain( 'input is a void element tag and must neither have `children` ' + - 'nor use `dangerouslySetInnerHTML`.\n\nThis DOM node was rendered by `X`.', + 'nor use `dangerouslySetInnerHTML`.' + + '\n in input (at **)' + + '\n in X (at **)', ); }); @@ -1303,12 +1299,20 @@ describe('ReactDOMComponent', () => { } } - expect(function() { + let caughtErr; + try { ReactDOM.render(, container); - }).toThrowError( + } catch (err) { + caughtErr = err; + } + + expect(caughtErr).not.toBe(undefined); + expect(normalizeCodeLocInfo(caughtErr.message)).toContain( 'The `style` prop expects a mapping from style properties to values, ' + "not a string. For example, style={{marginRight: spacing + 'em'}} " + - 'when using JSX.\n\nThis DOM node was rendered by `Animal`.', + 'when using JSX.' + + '\n in div (at **)' + + '\n in Animal (at **)', ); }); diff --git a/packages/react-dom/src/shared/__tests__/ReactServerRendering-test.js b/packages/react-dom/src/shared/__tests__/ReactServerRendering-test.js index 766265b7181a3..3e82973ace230 100644 --- a/packages/react-dom/src/shared/__tests__/ReactServerRendering-test.js +++ b/packages/react-dom/src/shared/__tests__/ReactServerRendering-test.js @@ -18,6 +18,10 @@ var PropTypes; var ROOT_ATTRIBUTE_NAME; +function normalizeCodeLocInfo(str) { + return str && str.replace(/\(at .+?:\d+\)/g, '(at **)'); +} + describe('ReactDOMServer', () => { beforeEach(() => { jest.resetModules(); @@ -380,11 +384,17 @@ describe('ReactDOMServer', () => { }); it('should throw prop mapping error for an