diff --git a/packages/react-dom/src/__tests__/ReactBrowserEventEmitter-test.internal.js b/packages/react-dom/src/__tests__/ReactBrowserEventEmitter-test.internal.js index e590851146416..d1fde4af6a4d6 100644 --- a/packages/react-dom/src/__tests__/ReactBrowserEventEmitter-test.internal.js +++ b/packages/react-dom/src/__tests__/ReactBrowserEventEmitter-test.internal.js @@ -277,15 +277,11 @@ describe('ReactBrowserEventEmitter', () => { putListener(CHILD, ON_CLICK_KEY, recordIDAndReturnFalse.bind(null, CHILD)); putListener(PARENT, ON_CLICK_KEY, recordID.bind(null, PARENT)); putListener(GRANDPARENT, ON_CLICK_KEY, recordID.bind(null, GRANDPARENT)); - spyOnDev(console, 'error'); ReactTestUtils.Simulate.click(CHILD); expect(idCallOrder.length).toBe(3); expect(idCallOrder[0]).toBe(CHILD); expect(idCallOrder[1]).toBe(PARENT); expect(idCallOrder[2]).toBe(GRANDPARENT); - if (__DEV__) { - expect(console.error.calls.count()).toEqual(0); - } }); /** diff --git a/packages/react-dom/src/__tests__/ReactComponent-test.js b/packages/react-dom/src/__tests__/ReactComponent-test.js index a0a8fde8b8661..94d16543e436b 100644 --- a/packages/react-dom/src/__tests__/ReactComponent-test.js +++ b/packages/react-dom/src/__tests__/ReactComponent-test.js @@ -46,7 +46,6 @@ describe('ReactComponent', () => { }); it('should throw (in dev) when children are mutated during render', () => { - spyOnDev(console, 'error'); function Wrapper(props) { props.children[1] =

; // Mutation is illegal return

{props.children}
; @@ -73,8 +72,6 @@ describe('ReactComponent', () => { }); it('should throw (in dev) when children are mutated during update', () => { - spyOnDev(console, 'error'); - class Wrapper extends React.Component { componentDidMount() { this.props.children[1] =

; // Mutation is illegal @@ -355,10 +352,13 @@ describe('ReactComponent', () => { }); it('throws usefully when rendering badly-typed elements', () => { - spyOnDev(console, 'error'); - const X = undefined; - expect(() => ReactTestUtils.renderIntoDocument()).toThrowError( + expect(() => { + expect(() => ReactTestUtils.renderIntoDocument()).toWarnDev( + 'React.createElement: type is invalid -- expected a string (for built-in components) ' + + 'or a class/function (for composite components) but got: undefined.', + ); + }).toThrowError( 'Element type is invalid: expected a string (for built-in components) ' + 'or a class/function (for composite components) but got: undefined.' + (__DEV__ @@ -368,20 +368,18 @@ describe('ReactComponent', () => { ); const Y = null; - expect(() => ReactTestUtils.renderIntoDocument()).toThrowError( + expect(() => { + expect(() => ReactTestUtils.renderIntoDocument()).toWarnDev( + 'React.createElement: type is invalid -- expected a string (for built-in components) ' + + 'or a class/function (for composite components) but got: null.', + ); + }).toThrowError( 'Element type is invalid: expected a string (for built-in components) ' + 'or a class/function (for composite components) but got: null.', ); - - if (__DEV__) { - // One warning for each element creation - expect(console.error.calls.count()).toBe(2); - } }); it('includes owner name in the error about badly-typed elements', () => { - spyOnDev(console, 'error'); - const X = undefined; function Indirection(props) { @@ -400,7 +398,12 @@ describe('ReactComponent', () => { return ; } - expect(() => ReactTestUtils.renderIntoDocument()).toThrowError( + expect(() => { + expect(() => ReactTestUtils.renderIntoDocument()).toWarnDev( + 'React.createElement: type is invalid -- expected a string (for built-in components) ' + + 'or a class/function (for composite components) but got: undefined.', + ); + }).toThrowError( 'Element type is invalid: expected a string (for built-in components) ' + 'or a class/function (for composite components) but got: undefined.' + (__DEV__ @@ -409,11 +412,6 @@ describe('ReactComponent', () => { '\n\nCheck the render method of `Bar`.' : ''), ); - - if (__DEV__) { - // One warning for each element creation - expect(console.error.calls.count()).toBe(1); - } }); it('throws if a plain object is used as a child', () => { @@ -530,18 +528,13 @@ describe('ReactComponent', () => { function Foo() { return Foo; } - spyOnDev(console, 'error'); const container = document.createElement('div'); - ReactDOM.render(, container); - if (__DEV__) { - expect(console.error.calls.count()).toBe(1); - expect(normalizeCodeLocInfo(console.error.calls.argsFor(0)[0])).toBe( - 'Warning: Functions are not valid as a React child. This may happen if ' + - 'you return a Component instead of from render. ' + - 'Or maybe you meant to call this function rather than return it.\n' + - ' in Foo (at **)', - ); - } + expect(() => ReactDOM.render(, container)).toWarnDev( + 'Warning: Functions are not valid as a React child. This may happen if ' + + 'you return a Component instead of from render. ' + + 'Or maybe you meant to call this function rather than return it.\n' + + ' in Foo (at **)', + ); }); it('warns on function as a return value from a class', () => { @@ -550,18 +543,13 @@ describe('ReactComponent', () => { return Foo; } } - spyOnDev(console, 'error'); const container = document.createElement('div'); - ReactDOM.render(, container); - if (__DEV__) { - expect(console.error.calls.count()).toBe(1); - expect(normalizeCodeLocInfo(console.error.calls.argsFor(0)[0])).toBe( - 'Warning: Functions are not valid as a React child. This may happen if ' + - 'you return a Component instead of from render. ' + - 'Or maybe you meant to call this function rather than return it.\n' + - ' in Foo (at **)', - ); - } + expect(() => ReactDOM.render(, container)).toWarnDev( + 'Warning: Functions are not valid as a React child. This may happen if ' + + 'you return a Component instead of from render. ' + + 'Or maybe you meant to call this function rather than return it.\n' + + ' in Foo (at **)', + ); }); it('warns on function as a child to host component', () => { @@ -572,20 +560,15 @@ describe('ReactComponent', () => { ); } - spyOnDev(console, 'error'); const container = document.createElement('div'); - ReactDOM.render(, container); - if (__DEV__) { - expect(console.error.calls.count()).toBe(1); - expect(normalizeCodeLocInfo(console.error.calls.argsFor(0)[0])).toBe( - 'Warning: Functions are not valid as a React child. This may happen if ' + - 'you return a Component instead of from render. ' + - 'Or maybe you meant to call this function rather than return it.\n' + - ' in span (at **)\n' + - ' in div (at **)\n' + - ' in Foo (at **)', - ); - } + expect(() => ReactDOM.render(, container)).toWarnDev( + 'Warning: Functions are not valid as a React child. This may happen if ' + + 'you return a Component instead of from render. ' + + 'Or maybe you meant to call this function rather than return it.\n' + + ' in span (at **)\n' + + ' in div (at **)\n' + + ' in Foo (at **)', + ); }); it('does not warn for function-as-a-child that gets resolved', () => { @@ -601,7 +584,6 @@ describe('ReactComponent', () => { }); it('deduplicates function type warnings based on component type', () => { - spyOnDev(console, 'error'); class Foo extends React.PureComponent { constructor() { super(); @@ -621,26 +603,23 @@ describe('ReactComponent', () => { } } const container = document.createElement('div'); - const component = ReactDOM.render(, container); + let component; + expect(() => { + component = ReactDOM.render(, container); + }).toWarnDev([ + 'Warning: Functions are not valid as a React child. This may happen if ' + + 'you return a Component instead of from render. ' + + 'Or maybe you meant to call this function rather than return it.\n' + + ' in div (at **)\n' + + ' in Foo (at **)', + 'Warning: Functions are not valid as a React child. This may happen if ' + + 'you return a Component instead of from render. ' + + 'Or maybe you meant to call this function rather than return it.\n' + + ' in span (at **)\n' + + ' in div (at **)\n' + + ' in Foo (at **)', + ]); component.setState({type: 'portobello mushrooms'}); - if (__DEV__) { - expect(console.error.calls.count()).toBe(2); - expect(normalizeCodeLocInfo(console.error.calls.argsFor(0)[0])).toBe( - 'Warning: Functions are not valid as a React child. This may happen if ' + - 'you return a Component instead of from render. ' + - 'Or maybe you meant to call this function rather than return it.\n' + - ' in div (at **)\n' + - ' in Foo (at **)', - ); - expect(normalizeCodeLocInfo(console.error.calls.argsFor(1)[0])).toBe( - 'Warning: Functions are not valid as a React child. This may happen if ' + - 'you return a Component instead of from render. ' + - 'Or maybe you meant to call this function rather than return it.\n' + - ' in span (at **)\n' + - ' in div (at **)\n' + - ' in Foo (at **)', - ); - } }); }); }); diff --git a/packages/react-dom/src/__tests__/ReactComponentLifeCycle-test.js b/packages/react-dom/src/__tests__/ReactComponentLifeCycle-test.js index 33730716ac1e2..51dea221d27ba 100644 --- a/packages/react-dom/src/__tests__/ReactComponentLifeCycle-test.js +++ b/packages/react-dom/src/__tests__/ReactComponentLifeCycle-test.js @@ -198,8 +198,6 @@ describe('ReactComponentLifeCycle', () => { }); it('should not allow update state inside of getInitialState', () => { - spyOnDev(console, 'error'); - class StatefulComponent extends React.Component { constructor(props, context) { super(props, context); @@ -213,26 +211,20 @@ describe('ReactComponentLifeCycle', () => { } } - ReactTestUtils.renderIntoDocument(); - if (__DEV__) { - expect(console.error.calls.count()).toBe(1); - expect(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.', - ); - } + expect(() => { + ReactTestUtils.renderIntoDocument(); + }).toWarnDev( + '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.', + ); - // Check deduplication + // Check deduplication; (no extra warnings should be logged). ReactTestUtils.renderIntoDocument(); - if (__DEV__) { - expect(console.error.calls.count()).toBe(1); - } }); it('should correctly determine if a component is mounted', () => { - spyOnDev(console, 'error'); class Component extends React.Component { _isMounted() { // No longer a public API, but we can test that it works internally by @@ -253,19 +245,13 @@ describe('ReactComponentLifeCycle', () => { const element = ; - const instance = ReactTestUtils.renderIntoDocument(element); - expect(instance._isMounted()).toBeTruthy(); - - if (__DEV__) { - expect(console.error.calls.count()).toBe(1); - expect(console.error.calls.argsFor(0)[0]).toContain( - 'Component is accessing isMounted inside its render()', - ); - } + expect(() => { + const instance = ReactTestUtils.renderIntoDocument(element); + expect(instance._isMounted()).toBeTruthy(); + }).toWarnDev('Component is accessing isMounted inside its render()'); }); it('should correctly determine if a null component is mounted', () => { - spyOnDev(console, 'error'); class Component extends React.Component { _isMounted() { // No longer a public API, but we can test that it works internally by @@ -286,15 +272,10 @@ describe('ReactComponentLifeCycle', () => { const element = ; - const instance = ReactTestUtils.renderIntoDocument(element); - expect(instance._isMounted()).toBeTruthy(); - - if (__DEV__) { - expect(console.error.calls.count()).toBe(1); - expect(console.error.calls.argsFor(0)[0]).toContain( - 'Component is accessing isMounted inside its render()', - ); - } + expect(() => { + const instance = ReactTestUtils.renderIntoDocument(element); + expect(instance._isMounted()).toBeTruthy(); + }).toWarnDev('Component is accessing isMounted inside its render()'); }); it('isMounted should return false when unmounted', () => { @@ -317,7 +298,6 @@ describe('ReactComponentLifeCycle', () => { }); it('warns if findDOMNode is used inside render', () => { - spyOnDev(console, 'error'); class Component extends React.Component { state = {isMounted: false}; componentDidMount() { @@ -331,18 +311,12 @@ describe('ReactComponentLifeCycle', () => { } } - ReactTestUtils.renderIntoDocument(); - if (__DEV__) { - expect(console.error.calls.count()).toBe(1); - expect(console.error.calls.argsFor(0)[0]).toContain( - 'Component is accessing findDOMNode inside its render()', - ); - } + expect(() => { + ReactTestUtils.renderIntoDocument(); + }).toWarnDev('Component is accessing findDOMNode inside its render()'); }); it('should carry through each of the phases of setup', () => { - spyOnDev(console, 'error'); - class LifeCycleComponent extends React.Component { constructor(props, context) { super(props, context); @@ -399,7 +373,13 @@ describe('ReactComponentLifeCycle', () => { // yet initialized, or rendered. // const container = document.createElement('div'); - const instance = ReactDOM.render(, container); + + let instance; + expect(() => { + instance = ReactDOM.render(, container); + }).toWarnDev( + 'LifeCycleComponent is accessing isMounted inside its render() function', + ); // getInitialState expect(instance._testJournal.returnedFromGetInitialState).toEqual( @@ -449,13 +429,6 @@ describe('ReactComponentLifeCycle', () => { // But the current lifecycle of the component is unmounted. expect(getLifeCycleState(instance)).toBe('UNMOUNTED'); expect(instance.state).toEqual(POST_WILL_UNMOUNT_STATE); - - if (__DEV__) { - expect(console.error.calls.count()).toBe(1); - expect(console.error.calls.argsFor(0)[0]).toContain( - 'LifeCycleComponent is accessing isMounted inside its render() function', - ); - } }); it('should not throw when updating an auxiliary component', () => { diff --git a/packages/react-dom/src/__tests__/ReactCompositeComponent-test.js b/packages/react-dom/src/__tests__/ReactCompositeComponent-test.js index 3ae6384dbbcc4..a707a8df6cd1f 100644 --- a/packages/react-dom/src/__tests__/ReactCompositeComponent-test.js +++ b/packages/react-dom/src/__tests__/ReactCompositeComponent-test.js @@ -122,29 +122,21 @@ describe('ReactCompositeComponent', () => { } } - spyOnDev(console, 'warn'); const markup = ReactDOMServer.renderToString(); // Old API based on heuristic let container = document.createElement('div'); container.innerHTML = markup; - ReactDOM.render(, container); - if (__DEV__) { - expect(console.warn.calls.count()).toBe(1); - expect(console.warn.calls.argsFor(0)[0]).toContain( - 'render(): Calling ReactDOM.render() to hydrate server-rendered markup ' + - 'will stop working in React v17. Replace the ReactDOM.render() call ' + - 'with ReactDOM.hydrate() if you want React to attach to the server HTML.', - ); - console.warn.calls.reset(); - } + expect(() => ReactDOM.render(, container)).toLowPriorityWarnDev( + 'render(): Calling ReactDOM.render() to hydrate server-rendered markup ' + + 'will stop working in React v17. Replace the ReactDOM.render() call ' + + 'with ReactDOM.hydrate() if you want React to attach to the server HTML.', + ); + // New explicit API container = document.createElement('div'); container.innerHTML = markup; ReactDOM.hydrate(, container); - if (__DEV__) { - expect(console.warn.calls.count()).toBe(0); - } }); it('should react to state changes from callbacks', () => { @@ -234,8 +226,6 @@ describe('ReactCompositeComponent', () => { }); it('should warn about `forceUpdate` on unmounted components', () => { - spyOnDev(console, 'error'); - const container = document.createElement('div'); document.body.appendChild(container); @@ -251,32 +241,20 @@ describe('ReactCompositeComponent', () => { instance = ReactDOM.render(instance, container); instance.forceUpdate(); - if (__DEV__) { - expect(console.error.calls.count()).toBe(0); - } - ReactDOM.unmountComponentAtNode(container); - instance.forceUpdate(); - if (__DEV__) { - expect(console.error.calls.count()).toBe(1); - expect(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.', - ); - } + expect(() => instance.forceUpdate()).toWarnDev( + '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.', + ); + // No additional warning should be recorded instance.forceUpdate(); - if (__DEV__) { - expect(console.error.calls.count()).toBe(1); - } }); it('should warn about `setState` on unmounted components', () => { - spyOnDev(console, 'error'); - const container = document.createElement('div'); document.body.appendChild(container); @@ -300,26 +278,20 @@ describe('ReactCompositeComponent', () => { instance.setState({value: 1}); - if (__DEV__) { - expect(console.error.calls.count()).toBe(0); - } - expect(renders).toBe(2); ReactDOM.unmountComponentAtNode(container); - instance.setState({value: 2}); - expect(renders).toBe(2); + expect(() => { + instance.setState({value: 2}); + }).toWarnDev( + '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.', + ); - if (__DEV__) { - expect(console.error.calls.count()).toBe(1); - expect(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.', - ); - } + expect(renders).toBe(2); }); it('should silently allow `setState`, not call cb on unmounting components', () => { @@ -351,32 +323,24 @@ describe('ReactCompositeComponent', () => { }); it('should warn when rendering a class with a render method that does not extend React.Component', () => { - spyOnDev(console, 'error'); const container = document.createElement('div'); class ClassWithRenderNotExtended { render() { return

; } } - if (__DEV__) { - expect(console.error.calls.count()).toBe(0); - } expect(() => { - ReactDOM.render(, container); - }).toThrow(TypeError); - if (__DEV__) { - expect(console.error.calls.count()).toBe(1); - expect(console.error.calls.argsFor(0)[0]).toContain( + expect(() => { + ReactDOM.render(, container); + }).toWarnDev( 'Warning: The component appears to have a render method, ' + "but doesn't extend React.Component. This is likely to cause errors. " + 'Change ClassWithRenderNotExtended to extend React.Component instead.', ); - } + }).toThrow(TypeError); }); it('should warn about `setState` in render', () => { - spyOnDev(console, 'error'); - const container = document.createElement('div'); let renderedState = -1; @@ -395,21 +359,16 @@ describe('ReactCompositeComponent', () => { } } - if (__DEV__) { - expect(console.error.calls.count()).toBe(0); - } - - const instance = ReactDOM.render(, container); + let instance; - if (__DEV__) { - expect(console.error.calls.count()).toBe(1); - expect(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`.', - ); - } + expect(() => { + instance = ReactDOM.render(, container); + }).toWarnDev( + '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`.', + ); // The setState call is queued and then executed as a second pass. This // behavior is undefined though so we're free to change it to suit the @@ -424,17 +383,12 @@ describe('ReactCompositeComponent', () => { expect(renderedState).toBe(1); expect(instance2.state.value).toBe(1); - // Test deduplication + // Test deduplication; (no additional warnings are expected). ReactDOM.unmountComponentAtNode(container); ReactDOM.render(, container); - if (__DEV__) { - expect(console.error.calls.count()).toBe(1); - } }); it('should warn about `setState` in getChildContext', () => { - spyOnDev(console, 'error'); - const container = document.createElement('div'); let renderPasses = 0; @@ -455,25 +409,20 @@ describe('ReactCompositeComponent', () => { } Component.childContextTypes = {}; - if (__DEV__) { - expect(console.error.calls.count()).toBe(0); - } - const instance = ReactDOM.render(, container); + let instance; + + expect(() => { + instance = ReactDOM.render(, container); + }).toWarnDev( + 'Warning: setState(...): Cannot call setState() inside getChildContext()', + ); + expect(renderPasses).toBe(2); expect(instance.state.value).toBe(1); - if (__DEV__) { - expect(console.error.calls.count()).toBe(1); - expect(console.error.calls.argsFor(0)[0]).toBe( - 'Warning: setState(...): Cannot call setState() inside getChildContext()', - ); - } - // Test deduplication + // Test deduplication; (no additional warnings are expected). ReactDOM.unmountComponentAtNode(container); ReactDOM.render(, container); - if (__DEV__) { - expect(console.error.calls.count()).toBe(1); - } }); it('should cleanup even if render() fatals', () => { @@ -487,7 +436,7 @@ describe('ReactCompositeComponent', () => { expect(ReactCurrentOwner.current).toBe(null); - expect(function() { + expect(() => { instance = ReactTestUtils.renderIntoDocument(instance); }).toThrow(); @@ -525,8 +474,6 @@ describe('ReactCompositeComponent', () => { }); it('should warn when shouldComponentUpdate() returns undefined', () => { - spyOnDev(console, 'error'); - class Component extends React.Component { state = {bogus: false}; @@ -540,20 +487,14 @@ describe('ReactCompositeComponent', () => { } const instance = ReactTestUtils.renderIntoDocument(); - instance.setState({bogus: true}); - if (__DEV__) { - expect(console.error.calls.count()).toBe(1); - expect(console.error.calls.argsFor(0)[0]).toBe( - 'Warning: Component.shouldComponentUpdate(): Returned undefined instead of a ' + - 'boolean value. Make sure to return true or false.', - ); - } + expect(() => instance.setState({bogus: true})).toWarnDev( + 'Warning: Component.shouldComponentUpdate(): Returned undefined instead of a ' + + 'boolean value. Make sure to return true or false.', + ); }); it('should warn when componentDidUnmount method is defined', () => { - spyOnDev(console, 'error'); - class Component extends React.Component { componentDidUnmount = () => {}; @@ -562,21 +503,14 @@ describe('ReactCompositeComponent', () => { } } - ReactTestUtils.renderIntoDocument(); - - if (__DEV__) { - expect(console.error.calls.count()).toBe(1); - expect(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()?', - ); - } + expect(() => ReactTestUtils.renderIntoDocument()).toWarnDev( + 'Warning: Component has a method called ' + + 'componentDidUnmount(). But there is no such lifecycle method. ' + + 'Did you mean componentWillUnmount()?', + ); }); it('should warn when componentDidReceiveProps method is defined', () => { - spyOnDev(console, 'error'); - class Component extends React.Component { componentDidReceiveProps = () => {}; @@ -585,23 +519,16 @@ describe('ReactCompositeComponent', () => { } } - ReactTestUtils.renderIntoDocument(); - - if (__DEV__) { - expect(console.error.calls.count()).toBe(1); - expect(console.error.calls.argsFor(0)[0]).toBe( - 'Warning: Component has a method called ' + - 'componentDidReceiveProps(). But there is no such lifecycle method. ' + - 'If you meant to update the state in response to changing props, ' + - 'use componentWillReceiveProps(). If you meant to fetch data or ' + - 'run side-effects or mutations after React has updated the UI, use componentDidUpdate().', - ); - } + expect(() => ReactTestUtils.renderIntoDocument()).toWarnDev( + 'Warning: Component has a method called ' + + 'componentDidReceiveProps(). But there is no such lifecycle method. ' + + 'If you meant to update the state in response to changing props, ' + + 'use componentWillReceiveProps(). If you meant to fetch data or ' + + 'run side-effects or mutations after React has updated the UI, use componentDidUpdate().', + ); }); it('should warn when defaultProps was defined as an instance property', () => { - spyOnDev(console, 'error'); - class Component extends React.Component { constructor(props) { super(props); @@ -613,15 +540,10 @@ describe('ReactCompositeComponent', () => { } } - ReactTestUtils.renderIntoDocument(); - - if (__DEV__) { - expect(console.error.calls.count()).toBe(1); - expect(console.error.calls.argsFor(0)[0]).toBe( - 'Warning: Setting defaultProps as an instance property on Component is not supported ' + - 'and will be ignored. Instead, define defaultProps as a static property on Component.', - ); - } + expect(() => ReactTestUtils.renderIntoDocument()).toWarnDev( + 'Warning: Setting defaultProps as an instance property on Component is not supported ' + + 'and will be ignored. Instead, define defaultProps as a static property on Component.', + ); }); it('should pass context to children when not owner', () => { @@ -1093,8 +1015,6 @@ describe('ReactCompositeComponent', () => { }); it('should disallow nested render calls', () => { - spyOnDev(console, 'error'); - class Inner extends React.Component { render() { return
; @@ -1108,16 +1028,12 @@ describe('ReactCompositeComponent', () => { } } - ReactTestUtils.renderIntoDocument(); - if (__DEV__) { - expect(console.error.calls.count()).toBe(1); - expect(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.', - ); - } + expect(() => ReactTestUtils.renderIntoDocument()).toWarnDev( + '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.', + ); }); it('only renders once if updated in componentWillReceiveProps', () => { @@ -1392,8 +1308,6 @@ describe('ReactCompositeComponent', () => { }); it('should warn when mutated props are passed', () => { - spyOnDev(console, 'error'); - const container = document.createElement('div'); class Foo extends React.Component { @@ -1407,19 +1321,10 @@ describe('ReactCompositeComponent', () => { } } - if (__DEV__) { - expect(console.error.calls.count()).toBe(0); - } - - ReactDOM.render(, container); - - if (__DEV__) { - expect(console.error.calls.count()).toBe(1); - expect(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.", - ); - } + expect(() => ReactDOM.render(, container)).toWarnDev( + 'Foo(...): When calling super() in `Foo`, make sure to pass ' + + "up the same props that your component's constructor was passed.", + ); }); it('should only call componentWillUnmount once', () => { @@ -1456,7 +1361,7 @@ describe('ReactCompositeComponent', () => { } }; - expect(function() { + expect(() => { ReactDOM.render(, container); ReactDOM.render(, container); }).toThrow(); @@ -1702,7 +1607,6 @@ describe('ReactCompositeComponent', () => { }); it('should return a meaningful warning when constructor is returned', () => { - spyOnDev(console, 'error'); class RenderTextInvalidConstructor extends React.Component { constructor(props) { super(props); @@ -1714,33 +1618,26 @@ describe('ReactCompositeComponent', () => { } } - expect(function() { - ReactTestUtils.renderIntoDocument(); - }).toThrow(); - - if (__DEV__) { - expect(console.error.calls.count()).toBe(1); - expect(console.error.calls.mostRecent().args[0]).toBe( + expect(() => { + expect(() => { + ReactTestUtils.renderIntoDocument(); + }).toWarnDev( 'Warning: RenderTextInvalidConstructor(...): No `render` method found on the returned component instance: ' + 'did you accidentally return an object from the constructor?', ); - } + }).toThrow(); }); it('should return error if render is not defined', () => { - spyOnDev(console, 'error'); class RenderTestUndefinedRender extends React.Component {} - expect(function() { - ReactTestUtils.renderIntoDocument(); - }).toThrow(); - - if (__DEV__) { - expect(console.error.calls.count()).toBe(1); - expect(console.error.calls.mostRecent().args[0]).toBe( + expect(() => { + expect(() => { + ReactTestUtils.renderIntoDocument(); + }).toWarnDev( 'Warning: RenderTestUndefinedRender(...): No `render` method found on the returned ' + 'component instance: you may have forgotten to define `render`.', ); - } + }).toThrow(); }); }); diff --git a/packages/react-dom/src/__tests__/ReactCompositeComponentState-test.js b/packages/react-dom/src/__tests__/ReactCompositeComponentState-test.js index c69e237c4e93a..c7135984d2760 100644 --- a/packages/react-dom/src/__tests__/ReactCompositeComponentState-test.js +++ b/packages/react-dom/src/__tests__/ReactCompositeComponentState-test.js @@ -17,7 +17,6 @@ let TestComponent; describe('ReactCompositeComponent-state', () => { beforeEach(() => { React = require('react'); - ReactDOM = require('react-dom'); TestComponent = class extends React.Component { @@ -381,8 +380,6 @@ describe('ReactCompositeComponent-state', () => { }); it('should treat assigning to this.state inside cWRP as a replaceState, with a warning', () => { - spyOnDev(console, 'error'); - let ops = []; class Test extends React.Component { state = {step: 1, extra: true}; @@ -409,27 +406,20 @@ describe('ReactCompositeComponent-state', () => { const container = document.createElement('div'); ReactDOM.render(, container); // Update - ReactDOM.render(, container); + expect(() => ReactDOM.render(, container)).toWarnDev( + 'Warning: Test.componentWillReceiveProps(): Assigning directly to ' + + "this.state is deprecated (except inside a component's constructor). " + + 'Use setState instead.', + ); expect(ops).toEqual([ 'render -- step: 1, extra: true', 'render -- step: 3, extra: false', 'callback -- step: 3, extra: false', ]); - if (__DEV__) { - 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.', - ); - } - // Check deduplication + // Check deduplication; (no additional warnings are expected) ReactDOM.render(, container); - if (__DEV__) { - expect(console.error.calls.count()).toEqual(1); - } }); it('should treat assigning to this.state inside cWM as a replaceState, with a warning', () => { @@ -459,19 +449,15 @@ describe('ReactCompositeComponent-state', () => { // Mount const container = document.createElement('div'); - ReactDOM.render(, container); + expect(() => ReactDOM.render(, container)).toWarnDev( + 'Warning: Test.componentWillMount(): Assigning directly to ' + + "this.state is deprecated (except inside a component's constructor). " + + 'Use setState instead.', + ); expect(ops).toEqual([ 'render -- step: 3, extra: false', 'callback -- step: 3, extra: false', ]); - if (__DEV__) { - expect(console.error.calls.count()).toEqual(1); - expect(console.error.calls.argsFor(0)[0]).toEqual( - 'Warning: Test.componentWillMount(): Assigning directly to ' + - "this.state is deprecated (except inside a component's constructor). " + - 'Use setState instead.', - ); - } }); }); diff --git a/packages/react-dom/src/__tests__/ReactDOM-test.js b/packages/react-dom/src/__tests__/ReactDOM-test.js index 15148fed5be61..dd7f97484b6d8 100644 --- a/packages/react-dom/src/__tests__/ReactDOM-test.js +++ b/packages/react-dom/src/__tests__/ReactDOM-test.js @@ -109,8 +109,6 @@ describe('ReactDOM', () => { }); it('throws in render() if the mount callback is not a function', () => { - spyOnDev(console, 'error'); - function Foo() { this.a = 1; this.b = 2; @@ -125,42 +123,44 @@ describe('ReactDOM', () => { } const myDiv = document.createElement('div'); - expect(() => ReactDOM.render(, myDiv, 'no')).toThrowError( - 'Invalid argument passed as callback. Expected a function. Instead ' + - 'received: no', - ); - if (__DEV__) { - expect(console.error.calls.argsFor(0)[0]).toContain( + expect(() => { + expect(() => { + ReactDOM.render(, myDiv, 'no'); + }).toWarnDev( 'render(...): Expected the last optional `callback` argument to be ' + 'a function. Instead received: no.', ); - } - expect(() => ReactDOM.render(, myDiv, {foo: 'bar'})).toThrowError( + }).toThrowError( 'Invalid argument passed as callback. Expected a function. Instead ' + - 'received: [object Object]', + 'received: no', ); - if (__DEV__) { - expect(console.error.calls.argsFor(1)[0]).toContain( + + expect(() => { + expect(() => { + ReactDOM.render(, myDiv, {foo: 'bar'}); + }).toWarnDev( 'render(...): Expected the last optional `callback` argument to be ' + 'a function. Instead received: [object Object].', ); - } - expect(() => ReactDOM.render(, myDiv, new Foo())).toThrowError( + }).toThrowError( 'Invalid argument passed as callback. Expected a function. Instead ' + 'received: [object Object]', ); - if (__DEV__) { - expect(console.error.calls.argsFor(2)[0]).toContain( + + expect(() => { + expect(() => { + ReactDOM.render(, myDiv, new Foo()); + }).toWarnDev( 'render(...): Expected the last optional `callback` argument to be ' + 'a function. Instead received: [object Object].', ); - expect(console.error.calls.count()).toBe(3); - } + }).toThrowError( + 'Invalid argument passed as callback. Expected a function. Instead ' + + 'received: [object Object]', + ); }); it('throws in render() if the update callback is not a function', () => { - spyOnDev(console, 'error'); - function Foo() { this.a = 1; this.b = 2; @@ -176,39 +176,43 @@ describe('ReactDOM', () => { const myDiv = document.createElement('div'); ReactDOM.render(, myDiv); - expect(() => ReactDOM.render(, myDiv, 'no')).toThrowError( - 'Invalid argument passed as callback. Expected a function. Instead ' + - 'received: no', - ); - if (__DEV__) { - expect(console.error.calls.argsFor(0)[0]).toContain( + expect(() => { + expect(() => { + ReactDOM.render(, myDiv, 'no'); + }).toWarnDev( 'render(...): Expected the last optional `callback` argument to be ' + 'a function. Instead received: no.', ); - } - ReactDOM.render(, myDiv); // Re-mount - expect(() => ReactDOM.render(, myDiv, {foo: 'bar'})).toThrowError( + }).toThrowError( 'Invalid argument passed as callback. Expected a function. Instead ' + - 'received: [object Object]', + 'received: no', ); - if (__DEV__) { - expect(console.error.calls.argsFor(1)[0]).toContain( + + ReactDOM.render(, myDiv); // Re-mount + expect(() => { + expect(() => { + ReactDOM.render(, myDiv, {foo: 'bar'}); + }).toWarnDev( 'render(...): Expected the last optional `callback` argument to be ' + 'a function. Instead received: [object Object].', ); - } - ReactDOM.render(, myDiv); // Re-mount - expect(() => ReactDOM.render(, myDiv, new Foo())).toThrowError( + }).toThrowError( 'Invalid argument passed as callback. Expected a function. Instead ' + 'received: [object Object]', ); - if (__DEV__) { - expect(console.error.calls.argsFor(2)[0]).toContain( + + ReactDOM.render(, myDiv); // Re-mount + expect(() => { + expect(() => { + ReactDOM.render(, myDiv, new Foo()); + }).toWarnDev( 'render(...): Expected the last optional `callback` argument to be ' + 'a function. Instead received: [object Object].', ); - expect(console.error.calls.count()).toBe(3); - } + }).toThrowError( + 'Invalid argument passed as callback. Expected a function. Instead ' + + 'received: [object Object]', + ); }); it('preserves focus', () => { @@ -375,28 +379,24 @@ describe('ReactDOM', () => { // https://github.com/facebook/react/issues/11689 it('should warn when attempting to inject an event plugin', () => { - spyOnDev(console, 'warn'); - ReactDOM.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.EventPluginHub.injection.injectEventPluginsByName( - { - TapEventPlugin: { - extractEvents() {}, + expect(() => { + ReactDOM.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.EventPluginHub.injection.injectEventPluginsByName( + { + TapEventPlugin: { + extractEvents() {}, + }, }, - }, - ); - if (__DEV__) { - expect(console.warn.calls.count()).toBe(1); - expect(console.warn.calls.argsFor(0)[0]).toContain( - 'Injecting custom event plugins (TapEventPlugin) is deprecated ' + - 'and will not work in React 17+. Please update your code ' + - 'to not depend on React internals. The stack trace for this ' + - 'warning should reveal the library that is using them. ' + - 'See https://github.com/facebook/react/issues/11689 for a discussion.', ); - } + }).toLowPriorityWarnDev( + 'Injecting custom event plugins (TapEventPlugin) is deprecated ' + + 'and will not work in React 17+. Please update your code ' + + 'to not depend on React internals. The stack trace for this ' + + 'warning should reveal the library that is using them. ' + + 'See https://github.com/facebook/react/issues/11689 for a discussion.', + ); }); it('throws in DEV if jsdom is destroyed by the time setState() is called', () => { - spyOnDev(console, 'error'); class App extends React.Component { state = {x: 1}; render() { diff --git a/packages/react-dom/src/__tests__/ReactDOMAttribute-test.js b/packages/react-dom/src/__tests__/ReactDOMAttribute-test.js index 462f76be9ff08..c952c4b97a4dd 100644 --- a/packages/react-dom/src/__tests__/ReactDOMAttribute-test.js +++ b/packages/react-dom/src/__tests__/ReactDOMAttribute-test.js @@ -19,10 +19,6 @@ describe('ReactDOM unknown attribute', () => { ReactDOM = require('react-dom'); }); - function normalizeCodeLocInfo(str) { - return str && str.replace(/\(at .+?:\d+\)/g, '(at **)'); - } - function testUnknownAttributeRemoval(givenValue) { const el = document.createElement('div'); ReactDOM.render(
, el); @@ -46,20 +42,13 @@ describe('ReactDOM unknown attribute', () => { }); it('changes values true, false to null, and also warns once', () => { - spyOnDev(console, 'error'); - - testUnknownAttributeAssignment(true, null); + expect(() => testUnknownAttributeAssignment(true, null)).toWarnDev( + 'Received `true` for a non-boolean attribute `unknown`.\n\n' + + 'If you want to write it to the DOM, pass a string instead: ' + + 'unknown="true" or unknown={value.toString()}.\n' + + ' in div (at **)', + ); testUnknownAttributeAssignment(false, null); - - if (__DEV__) { - expect(normalizeCodeLocInfo(console.error.calls.argsFor(0)[0])).toMatch( - 'Received `true` for a non-boolean attribute `unknown`.\n\n' + - 'If you want to write it to the DOM, pass a string instead: ' + - 'unknown="true" or unknown={value.toString()}.\n' + - ' in div (at **)', - ); - expect(console.error.calls.count()).toBe(1); - } }); it('removes unknown attributes that were rendered but are now missing', () => { @@ -82,17 +71,11 @@ describe('ReactDOM unknown attribute', () => { }); it('coerces NaN to strings and warns', () => { - spyOnDev(console, 'error'); - - testUnknownAttributeAssignment(NaN, 'NaN'); - if (__DEV__) { - expect(normalizeCodeLocInfo(console.error.calls.argsFor(0)[0])).toMatch( - 'Warning: Received NaN for the `unknown` attribute. ' + - 'If this is expected, cast the value to a string.\n' + - ' in div (at **)', - ); - expect(console.error.calls.count()).toBe(1); - } + expect(() => testUnknownAttributeAssignment(NaN, 'NaN')).toWarnDev( + 'Warning: Received NaN for the `unknown` attribute. ' + + 'If this is expected, cast the value to a string.\n' + + ' in div (at **)', + ); }); it('coerces objects to strings and warns', () => { @@ -107,54 +90,41 @@ describe('ReactDOM unknown attribute', () => { }); it('removes symbols and warns', () => { - spyOnDev(console, 'error'); - - testUnknownAttributeRemoval(Symbol('foo')); - if (__DEV__) { - expect(normalizeCodeLocInfo(console.error.calls.argsFor(0)[0])).toBe( - 'Warning: Invalid value for prop `unknown` on
tag. Either remove it ' + - 'from the element, or pass a string or number value to keep it ' + - 'in the DOM. For details, see https://fb.me/react-attribute-behavior\n' + - ' in div (at **)', - ); - expect(console.error.calls.count()).toBe(1); - } + expect(() => testUnknownAttributeRemoval(Symbol('foo'))).toWarnDev( + 'Warning: Invalid value for prop `unknown` on
tag. Either remove it ' + + 'from the element, or pass a string or number value to keep it ' + + 'in the DOM. For details, see https://fb.me/react-attribute-behavior\n' + + ' in div (at **)', + ); }); it('removes functions and warns', () => { - spyOnDev(console, 'error'); - - testUnknownAttributeRemoval(function someFunction() {}); - if (__DEV__) { - expect(normalizeCodeLocInfo(console.error.calls.argsFor(0)[0])).toBe( - 'Warning: Invalid value for prop `unknown` on
tag. Either remove ' + - 'it from the element, or pass a string or number value to ' + - 'keep it in the DOM. For details, see ' + - 'https://fb.me/react-attribute-behavior\n' + - ' in div (at **)', - ); - expect(console.error.calls.count()).toBe(1); - } + expect(() => + testUnknownAttributeRemoval(function someFunction() {}), + ).toWarnDev( + 'Warning: Invalid value for prop `unknown` on
tag. Either remove ' + + 'it from the element, or pass a string or number value to ' + + 'keep it in the DOM. For details, see ' + + 'https://fb.me/react-attribute-behavior\n' + + ' in div (at **)', + ); }); it('allows camelCase unknown attributes and warns', () => { - spyOnDev(console, 'error'); - const el = document.createElement('div'); - ReactDOM.render(
, el); - expect(el.firstChild.getAttribute('helloworld')).toBe('something'); - if (__DEV__) { - expect(console.error.calls.count()).toBe(1); - expect(normalizeCodeLocInfo(console.error.calls.argsFor(0)[0])).toMatch( - 'React does not recognize the `helloWorld` prop on a DOM element. ' + - 'If you intentionally want it to appear in the DOM as a custom ' + - 'attribute, spell it as lowercase `helloworld` instead. ' + - 'If you accidentally passed it from a parent component, remove ' + - 'it from the DOM element.\n' + - ' in div (at **)', - ); - } + expect(() => + ReactDOM.render(
, el), + ).toWarnDev( + 'React does not recognize the `helloWorld` prop on a DOM element. ' + + 'If you intentionally want it to appear in the DOM as a custom ' + + 'attribute, spell it as lowercase `helloworld` instead. ' + + 'If you accidentally passed it from a parent component, remove ' + + 'it from the DOM element.\n' + + ' in div (at **)', + ); + + expect(el.firstChild.getAttribute('helloworld')).toBe('something'); }); }); }); diff --git a/packages/react-dom/src/__tests__/ReactDOMComponent-test.js b/packages/react-dom/src/__tests__/ReactDOMComponent-test.js index 46961e7f3c347..6a8e488ac6987 100644 --- a/packages/react-dom/src/__tests__/ReactDOMComponent-test.js +++ b/packages/react-dom/src/__tests__/ReactDOMComponent-test.js @@ -147,110 +147,97 @@ describe('ReactDOMComponent', () => { }); it('should warn for unknown prop', () => { - spyOnDev(console, 'error'); const container = document.createElement('div'); - ReactDOM.render(
{}} />, container); - if (__DEV__) { - expect(console.error.calls.count(0)).toBe(1); - expect(normalizeCodeLocInfo(console.error.calls.argsFor(0)[0])).toBe( - 'Warning: Invalid value for prop `foo` on
tag. Either remove it ' + - 'from the element, or pass a string or number value to keep ' + - 'it in the DOM. For details, see https://fb.me/react-attribute-behavior' + - '\n in div (at **)', - ); - } + expect(() => + ReactDOM.render(
{}} />, container), + ).toWarnDev( + 'Warning: Invalid value for prop `foo` on
tag. Either remove it ' + + 'from the element, or pass a string or number value to keep ' + + 'it in the DOM. For details, see https://fb.me/react-attribute-behavior' + + '\n in div (at **)', + ); }); it('should group multiple unknown prop warnings together', () => { - spyOnDev(console, 'error'); const container = document.createElement('div'); - ReactDOM.render(
{}} baz={() => {}} />, container); - if (__DEV__) { - expect(console.error.calls.count(0)).toBe(1); - expect(normalizeCodeLocInfo(console.error.calls.argsFor(0)[0])).toBe( - 'Warning: Invalid values for props `foo`, `baz` on
tag. Either remove ' + - 'them from the element, or pass a string or number value to keep ' + - 'them in the DOM. For details, see https://fb.me/react-attribute-behavior' + - '\n in div (at **)', - ); - } + expect(() => + ReactDOM.render(
{}} baz={() => {}} />, container), + ).toWarnDev( + 'Warning: Invalid values for props `foo`, `baz` on
tag. Either remove ' + + 'them from the element, or pass a string or number value to keep ' + + 'them in the DOM. For details, see https://fb.me/react-attribute-behavior' + + '\n in div (at **)', + ); }); it('should warn for onDblClick prop', () => { - spyOnDev(console, 'error'); const container = document.createElement('div'); - ReactDOM.render(
{}} />, container); - if (__DEV__) { - expect(console.error.calls.count(0)).toBe(1); - expect(normalizeCodeLocInfo(console.error.calls.argsFor(0)[0])).toBe( - 'Warning: Invalid event handler property `onDblClick`. Did you mean `onDoubleClick`?\n in div (at **)', - ); - } + expect(() => + ReactDOM.render(
{}} />, container), + ).toWarnDev( + 'Warning: Invalid event handler property `onDblClick`. Did you mean `onDoubleClick`?\n in div (at **)', + ); }); it('should warn for unknown string event handlers', () => { - spyOnDev(console, 'error'); const container = document.createElement('div'); - ReactDOM.render(
, container); + expect(() => + ReactDOM.render(
, container), + ).toWarnDev( + 'Warning: Unknown event handler property `onUnknown`. It will be ignored.\n in div (at **)', + ); expect(container.firstChild.hasAttribute('onUnknown')).toBe(false); expect(container.firstChild.onUnknown).toBe(undefined); - ReactDOM.render(
, container); + expect(() => + ReactDOM.render(
, container), + ).toWarnDev( + 'Warning: Unknown event handler property `onunknown`. It will be ignored.\n in div (at **)', + ); expect(container.firstChild.hasAttribute('onunknown')).toBe(false); expect(container.firstChild.onunknown).toBe(undefined); - ReactDOM.render(
, container); + expect(() => + ReactDOM.render( +
, + container, + ), + ).toWarnDev( + 'Warning: Unknown event handler property `on-unknown`. It will be ignored.\n in div (at **)', + ); expect(container.firstChild.hasAttribute('on-unknown')).toBe(false); expect(container.firstChild['on-unknown']).toBe(undefined); - if (__DEV__) { - expect(console.error.calls.count(0)).toBe(3); - expect(normalizeCodeLocInfo(console.error.calls.argsFor(0)[0])).toBe( - 'Warning: Unknown event handler property `onUnknown`. It will be ignored.\n in div (at **)', - ); - expect(normalizeCodeLocInfo(console.error.calls.argsFor(1)[0])).toBe( - 'Warning: Unknown event handler property `onunknown`. It will be ignored.\n in div (at **)', - ); - expect(normalizeCodeLocInfo(console.error.calls.argsFor(2)[0])).toBe( - 'Warning: Unknown event handler property `on-unknown`. It will be ignored.\n in div (at **)', - ); - } }); it('should warn for unknown function event handlers', () => { - spyOnDev(console, 'error'); const container = document.createElement('div'); - ReactDOM.render(
, container); + expect(() => + ReactDOM.render(
, container), + ).toWarnDev( + 'Warning: Unknown event handler property `onUnknown`. It will be ignored.\n in div (at **)', + ); expect(container.firstChild.hasAttribute('onUnknown')).toBe(false); expect(container.firstChild.onUnknown).toBe(undefined); - ReactDOM.render(
, container); + expect(() => + ReactDOM.render(
, container), + ).toWarnDev( + 'Warning: Unknown event handler property `onunknown`. It will be ignored.\n in div (at **)', + ); expect(container.firstChild.hasAttribute('onunknown')).toBe(false); expect(container.firstChild.onunknown).toBe(undefined); - ReactDOM.render(
, container); + expect(() => + ReactDOM.render(
, container), + ).toWarnDev( + 'Warning: Unknown event handler property `on-unknown`. It will be ignored.\n in div (at **)', + ); expect(container.firstChild.hasAttribute('on-unknown')).toBe(false); expect(container.firstChild['on-unknown']).toBe(undefined); - if (__DEV__) { - expect(console.error.calls.count(0)).toBe(3); - expect(normalizeCodeLocInfo(console.error.calls.argsFor(0)[0])).toBe( - 'Warning: Unknown event handler property `onUnknown`. It will be ignored.\n in div (at **)', - ); - expect(normalizeCodeLocInfo(console.error.calls.argsFor(1)[0])).toBe( - 'Warning: Unknown event handler property `onunknown`. It will be ignored.\n in div (at **)', - ); - expect(normalizeCodeLocInfo(console.error.calls.argsFor(2)[0])).toBe( - 'Warning: Unknown event handler property `on-unknown`. It will be ignored.\n in div (at **)', - ); - } }); it('should warn for badly cased React attributes', () => { - spyOnDev(console, 'error'); const container = document.createElement('div'); - ReactDOM.render(
, container); + expect(() => ReactDOM.render(
, container)).toWarnDev( + 'Warning: Invalid DOM property `CHILDREN`. Did you mean `children`?\n in div (at **)', + ); expect(container.firstChild.getAttribute('CHILDREN')).toBe('5'); - if (__DEV__) { - expect(console.error.calls.count(0)).toBe(1); - expect(normalizeCodeLocInfo(console.error.calls.argsFor(0)[0])).toBe( - 'Warning: Invalid DOM property `CHILDREN`. Did you mean `children`?\n in div (at **)', - ); - } }); it('should not warn for "0" as a unitless style value', () => { @@ -264,20 +251,13 @@ describe('ReactDOMComponent', () => { }); it('should warn nicely about NaN in style', () => { - spyOnDev(console, 'error'); - const style = {fontSize: NaN}; const div = document.createElement('div'); + expect(() => ReactDOM.render(, div)).toWarnDev( + 'Warning: `NaN` is an invalid value for the `fontSize` css style property.' + + '\n in span (at **)', + ); ReactDOM.render(, div); - ReactDOM.render(, div); - - if (__DEV__) { - expect(console.error.calls.count()).toBe(1); - expect(normalizeCodeLocInfo(console.error.calls.argsFor(0)[0])).toEqual( - 'Warning: `NaN` is an invalid value for the `fontSize` css style property.' + - '\n in span (at **)', - ); - } }); it('should update styles if initially null', () => { @@ -575,44 +555,38 @@ describe('ReactDOMComponent', () => { }); it('should reject attribute key injection attack on markup', () => { - spyOnDev(console, 'error'); - for (let i = 0; i < 3; i++) { - const container = document.createElement('div'); - const element = React.createElement( - 'x-foo-component', - {'blah" onclick="beevil" noise="hi': 'selected'}, - null, - ); - ReactDOM.render(element, container); - } - if (__DEV__) { - expect(console.error.calls.count()).toBe(1); - expect(console.error.calls.argsFor(0)[0]).toEqual( - 'Warning: Invalid attribute name: `blah" onclick="beevil" noise="hi`', - ); - } + expect(() => { + for (let i = 0; i < 3; i++) { + const container = document.createElement('div'); + const element = React.createElement( + 'x-foo-component', + {'blah" onclick="beevil" noise="hi': 'selected'}, + null, + ); + ReactDOM.render(element, container); + } + }).toWarnDev( + 'Warning: Invalid attribute name: `blah" onclick="beevil" noise="hi`', + ); }); it('should reject attribute key injection attack on update', () => { - spyOnDev(console, 'error'); - for (let i = 0; i < 3; i++) { - const container = document.createElement('div'); - const beforeUpdate = React.createElement('x-foo-component', {}, null); - ReactDOM.render(beforeUpdate, container); - - const afterUpdate = React.createElement( - 'x-foo-component', - {'blah" onclick="beevil" noise="hi': 'selected'}, - null, - ); - ReactDOM.render(afterUpdate, container); - } - if (__DEV__) { - expect(console.error.calls.count()).toBe(1); - expect(console.error.calls.argsFor(0)[0]).toEqual( - 'Warning: Invalid attribute name: `blah" onclick="beevil" noise="hi`', - ); - } + expect(() => { + for (let i = 0; i < 3; i++) { + const container = document.createElement('div'); + const beforeUpdate = React.createElement('x-foo-component', {}, null); + ReactDOM.render(beforeUpdate, container); + + const afterUpdate = React.createElement( + 'x-foo-component', + {'blah" onclick="beevil" noise="hi': 'selected'}, + null, + ); + ReactDOM.render(afterUpdate, container); + } + }).toWarnDev( + 'Warning: Invalid attribute name: `blah" onclick="beevil" noise="hi`', + ); }); it('should update arbitrary attributes for tags containing dashes', () => { @@ -857,17 +831,13 @@ describe('ReactDOMComponent', () => { }); it('should warn about non-string "is" attribute', () => { - spyOnDev(console, 'error'); const container = document.createElement('div'); - ReactDOM.render(