From 3c9ea7279513cd6e009e15b4b6ed9eac6b9ad02a Mon Sep 17 00:00:00 2001 From: Grant Timmerman Date: Thu, 26 Mar 2015 01:21:54 -0700 Subject: [PATCH 1/2] Display error when trying to create an element of type boolean. Fixes #3478 --- src/classic/element/ReactElementValidator.js | 11 ++++--- .../__tests__/ReactElementValidator-test.js | 32 +++++++++++-------- .../ReactJSXElementValidator-test.js | 16 ++++++---- 3 files changed, 34 insertions(+), 25 deletions(-) diff --git a/src/classic/element/ReactElementValidator.js b/src/classic/element/ReactElementValidator.js index bd961d4d62..2f95b10176 100644 --- a/src/classic/element/ReactElementValidator.js +++ b/src/classic/element/ReactElementValidator.js @@ -362,7 +362,8 @@ function checkAndWarnForMutatedProps(element) { * @param {ReactElement} element */ function validatePropTypes(element) { - if (element.type == null) { + if (element.type == null || !(typeof element.type === 'string' || + typeof element.type === 'function')) { // This has already warned. Don't throw. return; } @@ -399,10 +400,10 @@ var ReactElementValidator = { // We warn in this case but don't throw. We expect the element creation to // succeed and there will likely be errors in render. warning( - type != null, - 'React.createElement: type should not be null or undefined. It should ' + - 'be a string (for DOM elements) or a ReactClass (for composite ' + - 'components).%s', + type != null && (typeof type === 'string' || typeof type === 'function'), + 'React.createElement: type should not be null, undefined, or boolean. ' + + 'It should be a string (for DOM elements) or a ReactClass ' + + '(for composite components).%s', getDeclarationErrorAddendum() ); diff --git a/src/classic/element/__tests__/ReactElementValidator-test.js b/src/classic/element/__tests__/ReactElementValidator-test.js index bd908c4bf4..ccfa3eb917 100644 --- a/src/classic/element/__tests__/ReactElementValidator-test.js +++ b/src/classic/element/__tests__/ReactElementValidator-test.js @@ -258,26 +258,32 @@ describe('ReactElementValidator', function() { ); }); - it('gives a helpful error when passing null or undefined', function() { + it('gives a helpful error when passing null, undefined, or boolean', () => { spyOn(console, 'error'); React.createElement(undefined); React.createElement(null); - expect(console.error.calls.length).toBe(2); + React.createElement(true); + expect(console.error.calls.length).toBe(3); expect(console.error.calls[0].args[0]).toBe( - 'Warning: React.createElement: type should not be null or undefined. ' + - 'It should be a string (for DOM elements) or a ReactClass (for ' + - 'composite components).' + 'Warning: React.createElement: type should not be null, undefined, ' + + 'or boolean. It should be a string (for DOM elements) or a ReactClass ' + + '(for composite components).' ); expect(console.error.calls[1].args[0]).toBe( - 'Warning: React.createElement: type should not be null or undefined. ' + - 'It should be a string (for DOM elements) or a ReactClass (for ' + - 'composite components).' + 'Warning: React.createElement: type should not be null, undefined, ' + + 'or boolean. It should be a string (for DOM elements) or a ReactClass ' + + '(for composite components).' + ); + expect(console.error.calls[2].args[0]).toBe( + 'Warning: React.createElement: type should not be null, undefined, ' + + 'or boolean. It should be a string (for DOM elements) or a ReactClass ' + + '(for composite components).' ); React.createElement('div'); - expect(console.error.calls.length).toBe(2); + expect(console.error.calls.length).toBe(3); }); - it('includes the owner name when passing null or undefined', function() { + it('includes the owner name when passing null, undefined, or boolean', () => { spyOn(console, 'error'); var ParentComp = React.createClass({ render: function() { @@ -289,9 +295,9 @@ describe('ReactElementValidator', function() { }).toThrow(); expect(console.error.calls.length).toBe(2); expect(console.error.calls[0].args[0]).toBe( - 'Warning: React.createElement: type should not be null or undefined. ' + - 'It should be a string (for DOM elements) or a ReactClass (for ' + - 'composite components). Check the render method of `ParentComp`.' + 'Warning: React.createElement: type should not be null, undefined, ' + + 'or boolean. It should be a string (for DOM elements) or a ReactClass ' + + '(for composite components). Check the render method of `ParentComp`.' ); expect(console.error.calls[1].args[0]).toBe( 'Warning: Only functions or strings can be mounted as React components.' diff --git a/src/modern/element/__tests__/ReactJSXElementValidator-test.js b/src/modern/element/__tests__/ReactJSXElementValidator-test.js index b3cf895158..abf1f96e4f 100644 --- a/src/modern/element/__tests__/ReactJSXElementValidator-test.js +++ b/src/modern/element/__tests__/ReactJSXElementValidator-test.js @@ -208,24 +208,26 @@ describe('ReactJSXElementValidator', function() { ); }); - it('gives a helpful error when passing null or undefined', function() { + it('gives a helpful error when passing null, undefined, or boolean', () => { var Undefined = undefined; var Null = null; var Div = 'div'; + var True = true; spyOn(console, 'error'); ; ; - expect(console.error.calls.length).toBe(2); + ; + expect(console.error.calls.length).toBe(3); expect(console.error.calls[0].args[0]).toContain( - 'type should not be null or undefined. It should be a string (for ' + - 'DOM elements) or a ReactClass (for composite components).' + 'type should not be null, undefined, or boolean. It should be a ' + + 'string (for DOM elements) or a ReactClass (for composite components).' ); expect(console.error.calls[1].args[0]).toContain( - 'type should not be null or undefined. It should be a string (for ' + - 'DOM elements) or a ReactClass (for composite components).' + 'type should not be null, undefined, or boolean. It should be a ' + + 'string (for DOM elements) or a ReactClass (for composite components).' );
; - expect(console.error.calls.length).toBe(2); + expect(console.error.calls.length).toBe(3); }); it('should check default prop values', function() { From 59a914aac0b96c68c7218343e0c994f59ec73ddb Mon Sep 17 00:00:00 2001 From: Grant Timmerman Date: Thu, 26 Mar 2015 10:07:56 -0700 Subject: [PATCH 2/2] Disable numeric element types --- src/classic/element/ReactElementValidator.js | 9 +++-- .../__tests__/ReactElementValidator-test.js | 33 ++++++++++++------- .../ReactJSXElementValidator-test.js | 24 ++++++++++---- 3 files changed, 42 insertions(+), 24 deletions(-) diff --git a/src/classic/element/ReactElementValidator.js b/src/classic/element/ReactElementValidator.js index 2f95b10176..bb1f21066a 100644 --- a/src/classic/element/ReactElementValidator.js +++ b/src/classic/element/ReactElementValidator.js @@ -362,7 +362,7 @@ function checkAndWarnForMutatedProps(element) { * @param {ReactElement} element */ function validatePropTypes(element) { - if (element.type == null || !(typeof element.type === 'string' || + if (!(typeof element.type === 'string' || typeof element.type === 'function')) { // This has already warned. Don't throw. return; @@ -399,10 +399,9 @@ var ReactElementValidator = { createElement: function(type, props, children) { // We warn in this case but don't throw. We expect the element creation to // succeed and there will likely be errors in render. - warning( - type != null && (typeof type === 'string' || typeof type === 'function'), - 'React.createElement: type should not be null, undefined, or boolean. ' + - 'It should be a string (for DOM elements) or a ReactClass ' + + warning(typeof type === 'string' || typeof type === 'function', + 'React.createElement: type should not be null, undefined, boolean, or ' + + 'number. It should be a string (for DOM elements) or a ReactClass ' + '(for composite components).%s', getDeclarationErrorAddendum() ); diff --git a/src/classic/element/__tests__/ReactElementValidator-test.js b/src/classic/element/__tests__/ReactElementValidator-test.js index ccfa3eb917..ef550c0ea4 100644 --- a/src/classic/element/__tests__/ReactElementValidator-test.js +++ b/src/classic/element/__tests__/ReactElementValidator-test.js @@ -258,32 +258,40 @@ describe('ReactElementValidator', function() { ); }); - it('gives a helpful error when passing null, undefined, or boolean', () => { + it('gives a helpful error when passing null, undefined, boolean, or number', + () => { spyOn(console, 'error'); React.createElement(undefined); React.createElement(null); React.createElement(true); - expect(console.error.calls.length).toBe(3); + React.createElement(123); + expect(console.error.calls.length).toBe(4); expect(console.error.calls[0].args[0]).toBe( 'Warning: React.createElement: type should not be null, undefined, ' + - 'or boolean. It should be a string (for DOM elements) or a ReactClass ' + - '(for composite components).' + 'boolean, or number. It should be a string (for DOM elements) or a ' + + 'ReactClass (for composite components).' ); expect(console.error.calls[1].args[0]).toBe( 'Warning: React.createElement: type should not be null, undefined, ' + - 'or boolean. It should be a string (for DOM elements) or a ReactClass ' + - '(for composite components).' + 'boolean, or number. It should be a string (for DOM elements) or a ' + + 'ReactClass (for composite components).' ); expect(console.error.calls[2].args[0]).toBe( 'Warning: React.createElement: type should not be null, undefined, ' + - 'or boolean. It should be a string (for DOM elements) or a ReactClass ' + - '(for composite components).' + 'boolean, or number. It should be a string (for DOM elements) or a ' + + 'ReactClass (for composite components).' + ); + expect(console.error.calls[3].args[0]).toBe( + 'Warning: React.createElement: type should not be null, undefined, ' + + 'boolean, or number. It should be a string (for DOM elements) or a ' + + 'ReactClass (for composite components).' ); React.createElement('div'); - expect(console.error.calls.length).toBe(3); + expect(console.error.calls.length).toBe(4); }); - it('includes the owner name when passing null, undefined, or boolean', () => { + it('includes the owner name when passing null, undefined, boolean, or number', + () => { spyOn(console, 'error'); var ParentComp = React.createClass({ render: function() { @@ -296,8 +304,9 @@ describe('ReactElementValidator', function() { expect(console.error.calls.length).toBe(2); expect(console.error.calls[0].args[0]).toBe( 'Warning: React.createElement: type should not be null, undefined, ' + - 'or boolean. It should be a string (for DOM elements) or a ReactClass ' + - '(for composite components). Check the render method of `ParentComp`.' + 'boolean, or number. It should be a string (for DOM elements) or a ' + + 'ReactClass (for composite components). Check the render method of ' + + '`ParentComp`.' ); expect(console.error.calls[1].args[0]).toBe( 'Warning: Only functions or strings can be mounted as React components.' diff --git a/src/modern/element/__tests__/ReactJSXElementValidator-test.js b/src/modern/element/__tests__/ReactJSXElementValidator-test.js index abf1f96e4f..1e15d2d3b9 100644 --- a/src/modern/element/__tests__/ReactJSXElementValidator-test.js +++ b/src/modern/element/__tests__/ReactJSXElementValidator-test.js @@ -211,23 +211,33 @@ describe('ReactJSXElementValidator', function() { it('gives a helpful error when passing null, undefined, or boolean', () => { var Undefined = undefined; var Null = null; - var Div = 'div'; var True = true; + var Num = 123; + var Div = 'div'; spyOn(console, 'error'); ; ; ; - expect(console.error.calls.length).toBe(3); + ; + expect(console.error.calls.length).toBe(4); expect(console.error.calls[0].args[0]).toContain( - 'type should not be null, undefined, or boolean. It should be a ' + - 'string (for DOM elements) or a ReactClass (for composite components).' + 'type should not be null, undefined, boolean, or number. It should be ' + + 'a string (for DOM elements) or a ReactClass (for composite components).' ); expect(console.error.calls[1].args[0]).toContain( - 'type should not be null, undefined, or boolean. It should be a ' + - 'string (for DOM elements) or a ReactClass (for composite components).' + 'type should not be null, undefined, boolean, or number. It should be ' + + 'a string (for DOM elements) or a ReactClass (for composite components).' + ); + expect(console.error.calls[2].args[0]).toContain( + 'type should not be null, undefined, boolean, or number. It should be ' + + 'a string (for DOM elements) or a ReactClass (for composite components).' + ); + expect(console.error.calls[3].args[0]).toContain( + 'type should not be null, undefined, boolean, or number. It should be ' + + 'a string (for DOM elements) or a ReactClass (for composite components).' );
; - expect(console.error.calls.length).toBe(3); + expect(console.error.calls.length).toBe(4); }); it('should check default prop values', function() {