From 094d29425ca099698cfc6317272973c4569b8104 Mon Sep 17 00:00:00 2001 From: Brandon Dail Date: Mon, 27 Jun 2016 14:41:09 -0500 Subject: [PATCH 01/14] Warn if PropType function is called in production --- .../classic/types/ReactPropTypes.js | 49 ++- .../classic/types/ReactPropTypesSecret.js | 17 ++ .../ReactPropTypesProduction-test.js | 286 ++++++++++++++++++ .../classic/types/checkReactTypeSpec.js | 3 +- 4 files changed, 347 insertions(+), 8 deletions(-) create mode 100644 src/isomorphic/classic/types/ReactPropTypesSecret.js create mode 100644 src/isomorphic/classic/types/__tests__/ReactPropTypesProduction-test.js diff --git a/src/isomorphic/classic/types/ReactPropTypes.js b/src/isomorphic/classic/types/ReactPropTypes.js index 9b419cc7695..22ba338768a 100644 --- a/src/isomorphic/classic/types/ReactPropTypes.js +++ b/src/isomorphic/classic/types/ReactPropTypes.js @@ -13,6 +13,7 @@ var ReactElement = require('ReactElement'); var ReactPropTypeLocationNames = require('ReactPropTypeLocationNames'); +var ReactPropTypesSecret = require('ReactPropTypesSecret'); var emptyFunction = require('emptyFunction'); var getIteratorFn = require('getIteratorFn'); @@ -111,10 +112,21 @@ function createChainableTypeChecker(validate) { propName, componentName, location, - propFullName + propFullName, + secret ) { componentName = componentName || ANONYMOUS; propFullName = propFullName || propName; + if (!__DEV__) { + if (secret !== ReactPropTypesSecret) { + console.error( + `You are manually calling a React.PropTypes validation function ` + + `for the prop ${propFullName} on ${componentName} in a production ` + + `build. This is deprecated and will not work in the next ` + + `major version.` + ); + } + } if (props[propName] == null) { var locationName = ReactPropTypeLocationNames[location]; if (isRequired) { @@ -125,7 +137,13 @@ function createChainableTypeChecker(validate) { } return null; } else { - return validate(props, propName, componentName, location, propFullName); + return validate( + props, + propName, + componentName, + location, + propFullName, + ); } } @@ -136,7 +154,14 @@ function createChainableTypeChecker(validate) { } function createPrimitiveTypeChecker(expectedType) { - function validate(props, propName, componentName, location, propFullName) { + function validate( + props, + propName, + componentName, + location, + propFullName, + secret + ) { var propValue = props[propName]; var propType = getPropType(propValue); if (propType !== expectedType) { @@ -183,7 +208,8 @@ function createArrayOfTypeChecker(typeChecker) { i, componentName, location, - `${propFullName}[${i}]` + `${propFullName}[${i}]`, + ReactPropTypesSecret ); if (error instanceof Error) { return error; @@ -272,7 +298,8 @@ function createObjectOfTypeChecker(typeChecker) { key, componentName, location, - `${propFullName}.${key}` + `${propFullName}.${key}`, + ReactPropTypesSecret ); if (error instanceof Error) { return error; @@ -294,7 +321,14 @@ function createUnionTypeChecker(arrayOfTypeCheckers) { for (var i = 0; i < arrayOfTypeCheckers.length; i++) { var checker = arrayOfTypeCheckers[i]; if ( - checker(props, propName, componentName, location, propFullName) == null + checker( + props, + propName, + componentName, + location, + propFullName, + ReactPropTypesSecret + ) == null ) { return null; } @@ -344,7 +378,8 @@ function createShapeTypeChecker(shapeTypes) { key, componentName, location, - `${propFullName}.${key}` + `${propFullName}.${key}`, + ReactPropTypesSecret ); if (error) { return error; diff --git a/src/isomorphic/classic/types/ReactPropTypesSecret.js b/src/isomorphic/classic/types/ReactPropTypesSecret.js new file mode 100644 index 00000000000..b61a1400ba5 --- /dev/null +++ b/src/isomorphic/classic/types/ReactPropTypesSecret.js @@ -0,0 +1,17 @@ +/** + * Copyright 2013-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @providesModule ReactPropTypesSecret + */ + + +'use strict'; + +const ReactPropTypesSecret = '__REACT_PROP_TYPES_SECRET__'; + +module.exports = ReactPropTypesSecret; diff --git a/src/isomorphic/classic/types/__tests__/ReactPropTypesProduction-test.js b/src/isomorphic/classic/types/__tests__/ReactPropTypesProduction-test.js new file mode 100644 index 00000000000..28cee9d9368 --- /dev/null +++ b/src/isomorphic/classic/types/__tests__/ReactPropTypesProduction-test.js @@ -0,0 +1,286 @@ +/** + * Copyright 2013-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @emails react-core + */ + +'use strict'; + + +describe('ReactPropTypesProduction', function() { + var oldProcess; + var PropTypes; + var React; + var ReactTestUtils; + + beforeEach(function() { + __DEV__ = false; + oldProcess = process; + global.process = {env: {NODE_ENV: 'production'}}; + + jest.resetModuleRegistry(); + PropTypes = require('ReactPropTypes'); + React = require('React'); + ReactTestUtils = require('ReactTestUtils'); + }); + + afterEach(function() { + __DEV__ = true; + global.process = oldProcess; + }); + + function typeCheckPass(declaration, value) { + var props = {testProp: value}; + declaration( + props, + 'testProp', + 'testComponent', + 'prop' + ); + const expectedCount = __DEV__ ? 0 : 1; + expect(console.error.calls.count()).toBe(expectedCount); + if (!__DEV__) { + expect(console.error.calls.argsFor(0)[0]).toContain( + 'You are manually calling a React.PropTypes validation ' + ); + } + console.error.calls.reset(); + } + + + describe('Primitive Types', function() { + it('should warn if called manually in production', function() { + spyOn(console, 'error'); + typeCheckPass(PropTypes.array, /please/); + typeCheckPass(PropTypes.array, []); + typeCheckPass(PropTypes.array.isRequired, /please/); + typeCheckPass(PropTypes.array.isRequired, []); + typeCheckPass(PropTypes.array.isRequired, null); + typeCheckPass(PropTypes.array.isRequired, undefined); + typeCheckPass(PropTypes.bool, []); + typeCheckPass(PropTypes.bool, true); + typeCheckPass(PropTypes.bool.isRequired, []); + typeCheckPass(PropTypes.bool.isRequired, true); + typeCheckPass(PropTypes.bool.isRequired, null); + typeCheckPass(PropTypes.bool.isRequired, undefined); + typeCheckPass(PropTypes.func, false); + typeCheckPass(PropTypes.func, function() {}); + typeCheckPass(PropTypes.func.isRequired, false); + typeCheckPass(PropTypes.func.isRequired, function() {}); + typeCheckPass(PropTypes.func.isRequired, null); + typeCheckPass(PropTypes.func.isRequired, undefined); + typeCheckPass(PropTypes.number, function() {}); + typeCheckPass(PropTypes.number, 42); + typeCheckPass(PropTypes.number.isRequired, function() {}); + typeCheckPass(PropTypes.number.isRequired, 42); + typeCheckPass(PropTypes.number.isRequired, null); + typeCheckPass(PropTypes.number.isRequired, undefined); + typeCheckPass(PropTypes.string, 0); + typeCheckPass(PropTypes.string, 'foo'); + typeCheckPass(PropTypes.string.isRequired, 0); + typeCheckPass(PropTypes.string.isRequired, 'foo'); + typeCheckPass(PropTypes.string.isRequired, null); + typeCheckPass(PropTypes.string.isRequired, undefined); + typeCheckPass(PropTypes.symbol, 0); + typeCheckPass(PropTypes.symbol, Symbol('Foo')); + typeCheckPass(PropTypes.symbol.isRequired, 0); + typeCheckPass(PropTypes.symbol.isRequired, Symbol('Foo')); + typeCheckPass(PropTypes.symbol.isRequired, null); + typeCheckPass(PropTypes.symbol.isRequired, undefined); + typeCheckPass(PropTypes.object, ''); + typeCheckPass(PropTypes.object, {foo: 'bar'}); + typeCheckPass(PropTypes.object.isRequired, ''); + typeCheckPass(PropTypes.object.isRequired, {foo: 'bar'}); + typeCheckPass(PropTypes.object.isRequired, null); + typeCheckPass(PropTypes.object.isRequired, undefined); + }); + }); + + + describe('Any Type', function() { + it('should warn if called manually in production', function() { + spyOn(console, 'error'); + typeCheckPass(PropTypes.any, null); + typeCheckPass(PropTypes.any.isRequired, null); + typeCheckPass(PropTypes.any.isRequired, undefined); + }); + }); + + describe('ArrayOf Type', function() { + it('should warn if called manually in production', function() { + spyOn(console, 'error'); + typeCheckPass( + PropTypes.arrayOf({ foo: PropTypes.string }), + { foo: 'bar' } + ); + typeCheckPass( + PropTypes.arrayOf(PropTypes.number), + [1, 2, 'b'] + ); + typeCheckPass( + PropTypes.arrayOf(PropTypes.number), + {'0': 'maybe-array', length: 1} + ); + typeCheckPass(PropTypes.arrayOf(PropTypes.number).isRequired, null); + typeCheckPass(PropTypes.arrayOf(PropTypes.number).isRequired, undefined); + }); + }); + + + describe('Component Type', function() { + it('should warn if called manually in production', function() { + spyOn(console, 'error'); + typeCheckPass(PropTypes.element, [
,
]); + typeCheckPass(PropTypes.element,
); + typeCheckPass(PropTypes.element, 123); + typeCheckPass(PropTypes.element, 'foo'); + typeCheckPass(PropTypes.element, false); + typeCheckPass(PropTypes.element.isRequired, null); + typeCheckPass(PropTypes.element.isRequired, undefined); + }); + }); + + describe('Instance Types', function() { + it('should warn if called manually in production', function() { + spyOn(console, 'error'); + typeCheckPass(PropTypes.instanceOf(Date), {}); + typeCheckPass(PropTypes.instanceOf(Date), new Date()); + typeCheckPass(PropTypes.instanceOf(Date).isRequired, {}); + typeCheckPass(PropTypes.instanceOf(Date).isRequired, new Date()); + }); + }); + + describe('React Component Types', function() { + it('should warn if called manually in production', function() { + spyOn(console, 'error'); + typeCheckPass(PropTypes.node, 'node'); + typeCheckPass(PropTypes.node, {}); + typeCheckPass(PropTypes.node.isRequired, 'node'); + typeCheckPass(PropTypes.node.isRequired, undefined); + typeCheckPass(PropTypes.node.isRequired, undefined); + }); + }); + + describe('ObjectOf Type', function() { + it('should warn if called manually in production', function() { + spyOn(console, 'error'); + typeCheckPass( + PropTypes.objectOf({ foo: PropTypes.string }), + { foo: 'bar' } + ); + typeCheckPass( + PropTypes.objectOf(PropTypes.number), + {a: 1, b: 2, c: 'b'} + ); + typeCheckPass(PropTypes.objectOf(PropTypes.number), [1, 2]); + typeCheckPass(PropTypes.objectOf(PropTypes.number), null); + typeCheckPass(PropTypes.objectOf(PropTypes.number), undefined); + }); + }); + + describe('OneOf Types', function() { + it('should warn if called manually in production', function() { + spyOn(console, 'error'); + typeCheckPass(PropTypes.oneOf('red', 'blue'), 'red'); + typeCheckPass(PropTypes.oneOf(['red', 'blue']), true); + typeCheckPass(PropTypes.oneOf(['red', 'blue']), null); + typeCheckPass(PropTypes.oneOf(['red', 'blue']), undefined); + }); + }); + + describe('Union Types', function() { + it('should warn if called manually in production', function() { + spyOn(console, 'error'); + typeCheckPass( + PropTypes.oneOfType(PropTypes.string, PropTypes.number), + 'red' + ); + typeCheckPass( + PropTypes.oneOfType([PropTypes.string, PropTypes.number]), + [] + ); + typeCheckPass( + PropTypes.oneOfType([PropTypes.string, PropTypes.number]), + null + ); + typeCheckPass( + PropTypes.oneOfType([PropTypes.string, PropTypes.number]), + undefined + ); + }); + }); + + describe('Shape Types', function() { + it('should warn if called manually in production', function() { + spyOn(console, 'error'); + typeCheckPass(PropTypes.shape({}), 'some string'); + typeCheckPass(PropTypes.shape({ foo: PropTypes.number }), { foo: 42 }); + typeCheckPass( + PropTypes.shape({key: PropTypes.number}).isRequired, + null + ); + typeCheckPass( + PropTypes.shape({key: PropTypes.number}).isRequired, + undefined + ); + typeCheckPass(PropTypes.element,
); + }); + }); + + it('should not warn in the development environment', () => { + __DEV__ = true; + oldProcess = process; + global.process = {env: {NODE_ENV: 'development'}}; + jest.resetModuleRegistry(); + PropTypes = require('ReactPropTypes'); + React = require('React'); + + spyOn(console, 'error'); + typeCheckPass(PropTypes.bool, true); + typeCheckPass(PropTypes.array, []); + typeCheckPass(PropTypes.string, 'foo'); + typeCheckPass(PropTypes.any, 'foo'); + typeCheckPass( + PropTypes.arrayOf(PropTypes.number), + [1, 2, 3] + ); + typeCheckPass(PropTypes.instanceOf(Date), new Date()); + typeCheckPass( + PropTypes.objectOf({ foo: PropTypes.string }), + { foo: 'bar' } + ); + typeCheckPass(PropTypes.oneOf('red', 'blue'), 'red'); + typeCheckPass( + PropTypes.oneOfType(PropTypes.string, PropTypes.number), + 'red' + ); + typeCheckPass(PropTypes.shape({ foo: PropTypes.number }), { foo: 42 }); + }); + + it('should not warn when doing type checks internally', function() { + spyOn(console, 'error'); + var Component = React.createClass({ + propTypes: { + foo: PropTypes.string, + bar: PropTypes.number, + baz: PropTypes.shape({ + qux: PropTypes.array, + }), + }, + render: function() { + return
; + }, + }); + var instance = ( + + ); + instance = ReactTestUtils.renderIntoDocument(instance); + expect(console.error.calls.count()).toBe(0); + }); + +}); diff --git a/src/isomorphic/classic/types/checkReactTypeSpec.js b/src/isomorphic/classic/types/checkReactTypeSpec.js index 3b119b395fe..6914d1d1d62 100644 --- a/src/isomorphic/classic/types/checkReactTypeSpec.js +++ b/src/isomorphic/classic/types/checkReactTypeSpec.js @@ -13,6 +13,7 @@ var ReactComponentTreeDevtool = require('ReactComponentTreeDevtool'); var ReactPropTypeLocationNames = require('ReactPropTypeLocationNames'); +var ReactPropTypesSecret = require('ReactPropTypesSecret'); var invariant = require('invariant'); var warning = require('warning'); @@ -49,7 +50,7 @@ function checkReactTypeSpec(typeSpecs, values, location, componentName, element, ReactPropTypeLocationNames[location], typeSpecName ); - error = typeSpecs[typeSpecName](values, typeSpecName, componentName, location); + error = typeSpecs[typeSpecName](values, typeSpecName, componentName, location, null, ReactPropTypesSecret); } catch (ex) { error = ex; } From be21348794d9abcf0aba1f4783271ff84205db72 Mon Sep 17 00:00:00 2001 From: Brandon Dail Date: Mon, 27 Jun 2016 14:54:01 -0500 Subject: [PATCH 02/14] Check if console is undefined before warning --- src/isomorphic/classic/types/ReactPropTypes.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/isomorphic/classic/types/ReactPropTypes.js b/src/isomorphic/classic/types/ReactPropTypes.js index 22ba338768a..458e0f0c296 100644 --- a/src/isomorphic/classic/types/ReactPropTypes.js +++ b/src/isomorphic/classic/types/ReactPropTypes.js @@ -118,7 +118,7 @@ function createChainableTypeChecker(validate) { componentName = componentName || ANONYMOUS; propFullName = propFullName || propName; if (!__DEV__) { - if (secret !== ReactPropTypesSecret) { + if (secret !== ReactPropTypesSecret && typeof console !== 'undefined') { console.error( `You are manually calling a React.PropTypes validation function ` + `for the prop ${propFullName} on ${componentName} in a production ` + From 88f745de4b3b7ad966a7339a96b63c3b24419872 Mon Sep 17 00:00:00 2001 From: Brandon Dail Date: Mon, 27 Jun 2016 14:55:35 -0500 Subject: [PATCH 03/14] Randomize value of ReactPropTypesSecret --- src/isomorphic/classic/types/ReactPropTypesSecret.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/isomorphic/classic/types/ReactPropTypesSecret.js b/src/isomorphic/classic/types/ReactPropTypesSecret.js index b61a1400ba5..3ecf61687c5 100644 --- a/src/isomorphic/classic/types/ReactPropTypesSecret.js +++ b/src/isomorphic/classic/types/ReactPropTypesSecret.js @@ -12,6 +12,6 @@ 'use strict'; -const ReactPropTypesSecret = '__REACT_PROP_TYPES_SECRET__'; +const ReactPropTypesSecret = '__REACT_PROP_TYPES_SECRET__' + Math.random(); module.exports = ReactPropTypesSecret; From dd5e97855033324a5c7d2d8d92c61db0d802e042 Mon Sep 17 00:00:00 2001 From: Brandon Dail Date: Mon, 27 Jun 2016 15:14:00 -0500 Subject: [PATCH 04/14] Remove dev environment tests --- .../ReactPropTypesProduction-test.js | 41 ++----------------- 1 file changed, 4 insertions(+), 37 deletions(-) diff --git a/src/isomorphic/classic/types/__tests__/ReactPropTypesProduction-test.js b/src/isomorphic/classic/types/__tests__/ReactPropTypesProduction-test.js index 28cee9d9368..134352d3d68 100644 --- a/src/isomorphic/classic/types/__tests__/ReactPropTypesProduction-test.js +++ b/src/isomorphic/classic/types/__tests__/ReactPropTypesProduction-test.js @@ -42,13 +42,10 @@ describe('ReactPropTypesProduction', function() { 'testComponent', 'prop' ); - const expectedCount = __DEV__ ? 0 : 1; - expect(console.error.calls.count()).toBe(expectedCount); - if (!__DEV__) { - expect(console.error.calls.argsFor(0)[0]).toContain( - 'You are manually calling a React.PropTypes validation ' - ); - } + expect(console.error.calls.count()).toBe(1); + expect(console.error.calls.argsFor(0)[0]).toContain( + 'You are manually calling a React.PropTypes validation ' + ); console.error.calls.reset(); } @@ -232,36 +229,6 @@ describe('ReactPropTypesProduction', function() { }); }); - it('should not warn in the development environment', () => { - __DEV__ = true; - oldProcess = process; - global.process = {env: {NODE_ENV: 'development'}}; - jest.resetModuleRegistry(); - PropTypes = require('ReactPropTypes'); - React = require('React'); - - spyOn(console, 'error'); - typeCheckPass(PropTypes.bool, true); - typeCheckPass(PropTypes.array, []); - typeCheckPass(PropTypes.string, 'foo'); - typeCheckPass(PropTypes.any, 'foo'); - typeCheckPass( - PropTypes.arrayOf(PropTypes.number), - [1, 2, 3] - ); - typeCheckPass(PropTypes.instanceOf(Date), new Date()); - typeCheckPass( - PropTypes.objectOf({ foo: PropTypes.string }), - { foo: 'bar' } - ); - typeCheckPass(PropTypes.oneOf('red', 'blue'), 'red'); - typeCheckPass( - PropTypes.oneOfType(PropTypes.string, PropTypes.number), - 'red' - ); - typeCheckPass(PropTypes.shape({ foo: PropTypes.number }), { foo: 42 }); - }); - it('should not warn when doing type checks internally', function() { spyOn(console, 'error'); var Component = React.createClass({ From ee0701bb235c79c2b225daab346843d1eed55b7b Mon Sep 17 00:00:00 2001 From: Brandon Dail Date: Mon, 27 Jun 2016 15:15:36 -0500 Subject: [PATCH 05/14] Rename typeCheckPass to productionWarningCheck --- .../ReactPropTypesProduction-test.js | 170 +++++++++--------- 1 file changed, 85 insertions(+), 85 deletions(-) diff --git a/src/isomorphic/classic/types/__tests__/ReactPropTypesProduction-test.js b/src/isomorphic/classic/types/__tests__/ReactPropTypesProduction-test.js index 134352d3d68..9bd16e623f0 100644 --- a/src/isomorphic/classic/types/__tests__/ReactPropTypesProduction-test.js +++ b/src/isomorphic/classic/types/__tests__/ReactPropTypesProduction-test.js @@ -34,7 +34,7 @@ describe('ReactPropTypesProduction', function() { global.process = oldProcess; }); - function typeCheckPass(declaration, value) { + function productionWarningCheck(declaration, value) { var props = {testProp: value}; declaration( props, @@ -53,48 +53,48 @@ describe('ReactPropTypesProduction', function() { describe('Primitive Types', function() { it('should warn if called manually in production', function() { spyOn(console, 'error'); - typeCheckPass(PropTypes.array, /please/); - typeCheckPass(PropTypes.array, []); - typeCheckPass(PropTypes.array.isRequired, /please/); - typeCheckPass(PropTypes.array.isRequired, []); - typeCheckPass(PropTypes.array.isRequired, null); - typeCheckPass(PropTypes.array.isRequired, undefined); - typeCheckPass(PropTypes.bool, []); - typeCheckPass(PropTypes.bool, true); - typeCheckPass(PropTypes.bool.isRequired, []); - typeCheckPass(PropTypes.bool.isRequired, true); - typeCheckPass(PropTypes.bool.isRequired, null); - typeCheckPass(PropTypes.bool.isRequired, undefined); - typeCheckPass(PropTypes.func, false); - typeCheckPass(PropTypes.func, function() {}); - typeCheckPass(PropTypes.func.isRequired, false); - typeCheckPass(PropTypes.func.isRequired, function() {}); - typeCheckPass(PropTypes.func.isRequired, null); - typeCheckPass(PropTypes.func.isRequired, undefined); - typeCheckPass(PropTypes.number, function() {}); - typeCheckPass(PropTypes.number, 42); - typeCheckPass(PropTypes.number.isRequired, function() {}); - typeCheckPass(PropTypes.number.isRequired, 42); - typeCheckPass(PropTypes.number.isRequired, null); - typeCheckPass(PropTypes.number.isRequired, undefined); - typeCheckPass(PropTypes.string, 0); - typeCheckPass(PropTypes.string, 'foo'); - typeCheckPass(PropTypes.string.isRequired, 0); - typeCheckPass(PropTypes.string.isRequired, 'foo'); - typeCheckPass(PropTypes.string.isRequired, null); - typeCheckPass(PropTypes.string.isRequired, undefined); - typeCheckPass(PropTypes.symbol, 0); - typeCheckPass(PropTypes.symbol, Symbol('Foo')); - typeCheckPass(PropTypes.symbol.isRequired, 0); - typeCheckPass(PropTypes.symbol.isRequired, Symbol('Foo')); - typeCheckPass(PropTypes.symbol.isRequired, null); - typeCheckPass(PropTypes.symbol.isRequired, undefined); - typeCheckPass(PropTypes.object, ''); - typeCheckPass(PropTypes.object, {foo: 'bar'}); - typeCheckPass(PropTypes.object.isRequired, ''); - typeCheckPass(PropTypes.object.isRequired, {foo: 'bar'}); - typeCheckPass(PropTypes.object.isRequired, null); - typeCheckPass(PropTypes.object.isRequired, undefined); + productionWarningCheck(PropTypes.array, /please/); + productionWarningCheck(PropTypes.array, []); + productionWarningCheck(PropTypes.array.isRequired, /please/); + productionWarningCheck(PropTypes.array.isRequired, []); + productionWarningCheck(PropTypes.array.isRequired, null); + productionWarningCheck(PropTypes.array.isRequired, undefined); + productionWarningCheck(PropTypes.bool, []); + productionWarningCheck(PropTypes.bool, true); + productionWarningCheck(PropTypes.bool.isRequired, []); + productionWarningCheck(PropTypes.bool.isRequired, true); + productionWarningCheck(PropTypes.bool.isRequired, null); + productionWarningCheck(PropTypes.bool.isRequired, undefined); + productionWarningCheck(PropTypes.func, false); + productionWarningCheck(PropTypes.func, function() {}); + productionWarningCheck(PropTypes.func.isRequired, false); + productionWarningCheck(PropTypes.func.isRequired, function() {}); + productionWarningCheck(PropTypes.func.isRequired, null); + productionWarningCheck(PropTypes.func.isRequired, undefined); + productionWarningCheck(PropTypes.number, function() {}); + productionWarningCheck(PropTypes.number, 42); + productionWarningCheck(PropTypes.number.isRequired, function() {}); + productionWarningCheck(PropTypes.number.isRequired, 42); + productionWarningCheck(PropTypes.number.isRequired, null); + productionWarningCheck(PropTypes.number.isRequired, undefined); + productionWarningCheck(PropTypes.string, 0); + productionWarningCheck(PropTypes.string, 'foo'); + productionWarningCheck(PropTypes.string.isRequired, 0); + productionWarningCheck(PropTypes.string.isRequired, 'foo'); + productionWarningCheck(PropTypes.string.isRequired, null); + productionWarningCheck(PropTypes.string.isRequired, undefined); + productionWarningCheck(PropTypes.symbol, 0); + productionWarningCheck(PropTypes.symbol, Symbol('Foo')); + productionWarningCheck(PropTypes.symbol.isRequired, 0); + productionWarningCheck(PropTypes.symbol.isRequired, Symbol('Foo')); + productionWarningCheck(PropTypes.symbol.isRequired, null); + productionWarningCheck(PropTypes.symbol.isRequired, undefined); + productionWarningCheck(PropTypes.object, ''); + productionWarningCheck(PropTypes.object, {foo: 'bar'}); + productionWarningCheck(PropTypes.object.isRequired, ''); + productionWarningCheck(PropTypes.object.isRequired, {foo: 'bar'}); + productionWarningCheck(PropTypes.object.isRequired, null); + productionWarningCheck(PropTypes.object.isRequired, undefined); }); }); @@ -102,29 +102,29 @@ describe('ReactPropTypesProduction', function() { describe('Any Type', function() { it('should warn if called manually in production', function() { spyOn(console, 'error'); - typeCheckPass(PropTypes.any, null); - typeCheckPass(PropTypes.any.isRequired, null); - typeCheckPass(PropTypes.any.isRequired, undefined); + productionWarningCheck(PropTypes.any, null); + productionWarningCheck(PropTypes.any.isRequired, null); + productionWarningCheck(PropTypes.any.isRequired, undefined); }); }); describe('ArrayOf Type', function() { it('should warn if called manually in production', function() { spyOn(console, 'error'); - typeCheckPass( + productionWarningCheck( PropTypes.arrayOf({ foo: PropTypes.string }), { foo: 'bar' } ); - typeCheckPass( + productionWarningCheck( PropTypes.arrayOf(PropTypes.number), [1, 2, 'b'] ); - typeCheckPass( + productionWarningCheck( PropTypes.arrayOf(PropTypes.number), {'0': 'maybe-array', length: 1} ); - typeCheckPass(PropTypes.arrayOf(PropTypes.number).isRequired, null); - typeCheckPass(PropTypes.arrayOf(PropTypes.number).isRequired, undefined); + productionWarningCheck(PropTypes.arrayOf(PropTypes.number).isRequired, null); + productionWarningCheck(PropTypes.arrayOf(PropTypes.number).isRequired, undefined); }); }); @@ -132,80 +132,80 @@ describe('ReactPropTypesProduction', function() { describe('Component Type', function() { it('should warn if called manually in production', function() { spyOn(console, 'error'); - typeCheckPass(PropTypes.element, [
,
]); - typeCheckPass(PropTypes.element,
); - typeCheckPass(PropTypes.element, 123); - typeCheckPass(PropTypes.element, 'foo'); - typeCheckPass(PropTypes.element, false); - typeCheckPass(PropTypes.element.isRequired, null); - typeCheckPass(PropTypes.element.isRequired, undefined); + productionWarningCheck(PropTypes.element, [
,
]); + productionWarningCheck(PropTypes.element,
); + productionWarningCheck(PropTypes.element, 123); + productionWarningCheck(PropTypes.element, 'foo'); + productionWarningCheck(PropTypes.element, false); + productionWarningCheck(PropTypes.element.isRequired, null); + productionWarningCheck(PropTypes.element.isRequired, undefined); }); }); describe('Instance Types', function() { it('should warn if called manually in production', function() { spyOn(console, 'error'); - typeCheckPass(PropTypes.instanceOf(Date), {}); - typeCheckPass(PropTypes.instanceOf(Date), new Date()); - typeCheckPass(PropTypes.instanceOf(Date).isRequired, {}); - typeCheckPass(PropTypes.instanceOf(Date).isRequired, new Date()); + productionWarningCheck(PropTypes.instanceOf(Date), {}); + productionWarningCheck(PropTypes.instanceOf(Date), new Date()); + productionWarningCheck(PropTypes.instanceOf(Date).isRequired, {}); + productionWarningCheck(PropTypes.instanceOf(Date).isRequired, new Date()); }); }); describe('React Component Types', function() { it('should warn if called manually in production', function() { spyOn(console, 'error'); - typeCheckPass(PropTypes.node, 'node'); - typeCheckPass(PropTypes.node, {}); - typeCheckPass(PropTypes.node.isRequired, 'node'); - typeCheckPass(PropTypes.node.isRequired, undefined); - typeCheckPass(PropTypes.node.isRequired, undefined); + productionWarningCheck(PropTypes.node, 'node'); + productionWarningCheck(PropTypes.node, {}); + productionWarningCheck(PropTypes.node.isRequired, 'node'); + productionWarningCheck(PropTypes.node.isRequired, undefined); + productionWarningCheck(PropTypes.node.isRequired, undefined); }); }); describe('ObjectOf Type', function() { it('should warn if called manually in production', function() { spyOn(console, 'error'); - typeCheckPass( + productionWarningCheck( PropTypes.objectOf({ foo: PropTypes.string }), { foo: 'bar' } ); - typeCheckPass( + productionWarningCheck( PropTypes.objectOf(PropTypes.number), {a: 1, b: 2, c: 'b'} ); - typeCheckPass(PropTypes.objectOf(PropTypes.number), [1, 2]); - typeCheckPass(PropTypes.objectOf(PropTypes.number), null); - typeCheckPass(PropTypes.objectOf(PropTypes.number), undefined); + productionWarningCheck(PropTypes.objectOf(PropTypes.number), [1, 2]); + productionWarningCheck(PropTypes.objectOf(PropTypes.number), null); + productionWarningCheck(PropTypes.objectOf(PropTypes.number), undefined); }); }); describe('OneOf Types', function() { it('should warn if called manually in production', function() { spyOn(console, 'error'); - typeCheckPass(PropTypes.oneOf('red', 'blue'), 'red'); - typeCheckPass(PropTypes.oneOf(['red', 'blue']), true); - typeCheckPass(PropTypes.oneOf(['red', 'blue']), null); - typeCheckPass(PropTypes.oneOf(['red', 'blue']), undefined); + productionWarningCheck(PropTypes.oneOf('red', 'blue'), 'red'); + productionWarningCheck(PropTypes.oneOf(['red', 'blue']), true); + productionWarningCheck(PropTypes.oneOf(['red', 'blue']), null); + productionWarningCheck(PropTypes.oneOf(['red', 'blue']), undefined); }); }); describe('Union Types', function() { it('should warn if called manually in production', function() { spyOn(console, 'error'); - typeCheckPass( + productionWarningCheck( PropTypes.oneOfType(PropTypes.string, PropTypes.number), 'red' ); - typeCheckPass( + productionWarningCheck( PropTypes.oneOfType([PropTypes.string, PropTypes.number]), [] ); - typeCheckPass( + productionWarningCheck( PropTypes.oneOfType([PropTypes.string, PropTypes.number]), null ); - typeCheckPass( + productionWarningCheck( PropTypes.oneOfType([PropTypes.string, PropTypes.number]), undefined ); @@ -215,17 +215,17 @@ describe('ReactPropTypesProduction', function() { describe('Shape Types', function() { it('should warn if called manually in production', function() { spyOn(console, 'error'); - typeCheckPass(PropTypes.shape({}), 'some string'); - typeCheckPass(PropTypes.shape({ foo: PropTypes.number }), { foo: 42 }); - typeCheckPass( + productionWarningCheck(PropTypes.shape({}), 'some string'); + productionWarningCheck(PropTypes.shape({ foo: PropTypes.number }), { foo: 42 }); + productionWarningCheck( PropTypes.shape({key: PropTypes.number}).isRequired, null ); - typeCheckPass( + productionWarningCheck( PropTypes.shape({key: PropTypes.number}).isRequired, undefined ); - typeCheckPass(PropTypes.element,
); + productionWarningCheck(PropTypes.element,
); }); }); From 88141f2c88dfb6ae43745b166b48ac67eb8f1967 Mon Sep 17 00:00:00 2001 From: Brandon Dail Date: Mon, 27 Jun 2016 15:47:08 -0500 Subject: [PATCH 06/14] Rename productionWarningCheck to expectWarningInProduction --- .../ReactPropTypesProduction-test.js | 170 +++++++++--------- 1 file changed, 85 insertions(+), 85 deletions(-) diff --git a/src/isomorphic/classic/types/__tests__/ReactPropTypesProduction-test.js b/src/isomorphic/classic/types/__tests__/ReactPropTypesProduction-test.js index 9bd16e623f0..a456fdb2bce 100644 --- a/src/isomorphic/classic/types/__tests__/ReactPropTypesProduction-test.js +++ b/src/isomorphic/classic/types/__tests__/ReactPropTypesProduction-test.js @@ -34,7 +34,7 @@ describe('ReactPropTypesProduction', function() { global.process = oldProcess; }); - function productionWarningCheck(declaration, value) { + function expectWarningInProduction(declaration, value) { var props = {testProp: value}; declaration( props, @@ -53,48 +53,48 @@ describe('ReactPropTypesProduction', function() { describe('Primitive Types', function() { it('should warn if called manually in production', function() { spyOn(console, 'error'); - productionWarningCheck(PropTypes.array, /please/); - productionWarningCheck(PropTypes.array, []); - productionWarningCheck(PropTypes.array.isRequired, /please/); - productionWarningCheck(PropTypes.array.isRequired, []); - productionWarningCheck(PropTypes.array.isRequired, null); - productionWarningCheck(PropTypes.array.isRequired, undefined); - productionWarningCheck(PropTypes.bool, []); - productionWarningCheck(PropTypes.bool, true); - productionWarningCheck(PropTypes.bool.isRequired, []); - productionWarningCheck(PropTypes.bool.isRequired, true); - productionWarningCheck(PropTypes.bool.isRequired, null); - productionWarningCheck(PropTypes.bool.isRequired, undefined); - productionWarningCheck(PropTypes.func, false); - productionWarningCheck(PropTypes.func, function() {}); - productionWarningCheck(PropTypes.func.isRequired, false); - productionWarningCheck(PropTypes.func.isRequired, function() {}); - productionWarningCheck(PropTypes.func.isRequired, null); - productionWarningCheck(PropTypes.func.isRequired, undefined); - productionWarningCheck(PropTypes.number, function() {}); - productionWarningCheck(PropTypes.number, 42); - productionWarningCheck(PropTypes.number.isRequired, function() {}); - productionWarningCheck(PropTypes.number.isRequired, 42); - productionWarningCheck(PropTypes.number.isRequired, null); - productionWarningCheck(PropTypes.number.isRequired, undefined); - productionWarningCheck(PropTypes.string, 0); - productionWarningCheck(PropTypes.string, 'foo'); - productionWarningCheck(PropTypes.string.isRequired, 0); - productionWarningCheck(PropTypes.string.isRequired, 'foo'); - productionWarningCheck(PropTypes.string.isRequired, null); - productionWarningCheck(PropTypes.string.isRequired, undefined); - productionWarningCheck(PropTypes.symbol, 0); - productionWarningCheck(PropTypes.symbol, Symbol('Foo')); - productionWarningCheck(PropTypes.symbol.isRequired, 0); - productionWarningCheck(PropTypes.symbol.isRequired, Symbol('Foo')); - productionWarningCheck(PropTypes.symbol.isRequired, null); - productionWarningCheck(PropTypes.symbol.isRequired, undefined); - productionWarningCheck(PropTypes.object, ''); - productionWarningCheck(PropTypes.object, {foo: 'bar'}); - productionWarningCheck(PropTypes.object.isRequired, ''); - productionWarningCheck(PropTypes.object.isRequired, {foo: 'bar'}); - productionWarningCheck(PropTypes.object.isRequired, null); - productionWarningCheck(PropTypes.object.isRequired, undefined); + expectWarningInProduction(PropTypes.array, /please/); + expectWarningInProduction(PropTypes.array, []); + expectWarningInProduction(PropTypes.array.isRequired, /please/); + expectWarningInProduction(PropTypes.array.isRequired, []); + expectWarningInProduction(PropTypes.array.isRequired, null); + expectWarningInProduction(PropTypes.array.isRequired, undefined); + expectWarningInProduction(PropTypes.bool, []); + expectWarningInProduction(PropTypes.bool, true); + expectWarningInProduction(PropTypes.bool.isRequired, []); + expectWarningInProduction(PropTypes.bool.isRequired, true); + expectWarningInProduction(PropTypes.bool.isRequired, null); + expectWarningInProduction(PropTypes.bool.isRequired, undefined); + expectWarningInProduction(PropTypes.func, false); + expectWarningInProduction(PropTypes.func, function() {}); + expectWarningInProduction(PropTypes.func.isRequired, false); + expectWarningInProduction(PropTypes.func.isRequired, function() {}); + expectWarningInProduction(PropTypes.func.isRequired, null); + expectWarningInProduction(PropTypes.func.isRequired, undefined); + expectWarningInProduction(PropTypes.number, function() {}); + expectWarningInProduction(PropTypes.number, 42); + expectWarningInProduction(PropTypes.number.isRequired, function() {}); + expectWarningInProduction(PropTypes.number.isRequired, 42); + expectWarningInProduction(PropTypes.number.isRequired, null); + expectWarningInProduction(PropTypes.number.isRequired, undefined); + expectWarningInProduction(PropTypes.string, 0); + expectWarningInProduction(PropTypes.string, 'foo'); + expectWarningInProduction(PropTypes.string.isRequired, 0); + expectWarningInProduction(PropTypes.string.isRequired, 'foo'); + expectWarningInProduction(PropTypes.string.isRequired, null); + expectWarningInProduction(PropTypes.string.isRequired, undefined); + expectWarningInProduction(PropTypes.symbol, 0); + expectWarningInProduction(PropTypes.symbol, Symbol('Foo')); + expectWarningInProduction(PropTypes.symbol.isRequired, 0); + expectWarningInProduction(PropTypes.symbol.isRequired, Symbol('Foo')); + expectWarningInProduction(PropTypes.symbol.isRequired, null); + expectWarningInProduction(PropTypes.symbol.isRequired, undefined); + expectWarningInProduction(PropTypes.object, ''); + expectWarningInProduction(PropTypes.object, {foo: 'bar'}); + expectWarningInProduction(PropTypes.object.isRequired, ''); + expectWarningInProduction(PropTypes.object.isRequired, {foo: 'bar'}); + expectWarningInProduction(PropTypes.object.isRequired, null); + expectWarningInProduction(PropTypes.object.isRequired, undefined); }); }); @@ -102,29 +102,29 @@ describe('ReactPropTypesProduction', function() { describe('Any Type', function() { it('should warn if called manually in production', function() { spyOn(console, 'error'); - productionWarningCheck(PropTypes.any, null); - productionWarningCheck(PropTypes.any.isRequired, null); - productionWarningCheck(PropTypes.any.isRequired, undefined); + expectWarningInProduction(PropTypes.any, null); + expectWarningInProduction(PropTypes.any.isRequired, null); + expectWarningInProduction(PropTypes.any.isRequired, undefined); }); }); describe('ArrayOf Type', function() { it('should warn if called manually in production', function() { spyOn(console, 'error'); - productionWarningCheck( + expectWarningInProduction( PropTypes.arrayOf({ foo: PropTypes.string }), { foo: 'bar' } ); - productionWarningCheck( + expectWarningInProduction( PropTypes.arrayOf(PropTypes.number), [1, 2, 'b'] ); - productionWarningCheck( + expectWarningInProduction( PropTypes.arrayOf(PropTypes.number), {'0': 'maybe-array', length: 1} ); - productionWarningCheck(PropTypes.arrayOf(PropTypes.number).isRequired, null); - productionWarningCheck(PropTypes.arrayOf(PropTypes.number).isRequired, undefined); + expectWarningInProduction(PropTypes.arrayOf(PropTypes.number).isRequired, null); + expectWarningInProduction(PropTypes.arrayOf(PropTypes.number).isRequired, undefined); }); }); @@ -132,80 +132,80 @@ describe('ReactPropTypesProduction', function() { describe('Component Type', function() { it('should warn if called manually in production', function() { spyOn(console, 'error'); - productionWarningCheck(PropTypes.element, [
,
]); - productionWarningCheck(PropTypes.element,
); - productionWarningCheck(PropTypes.element, 123); - productionWarningCheck(PropTypes.element, 'foo'); - productionWarningCheck(PropTypes.element, false); - productionWarningCheck(PropTypes.element.isRequired, null); - productionWarningCheck(PropTypes.element.isRequired, undefined); + expectWarningInProduction(PropTypes.element, [
,
]); + expectWarningInProduction(PropTypes.element,
); + expectWarningInProduction(PropTypes.element, 123); + expectWarningInProduction(PropTypes.element, 'foo'); + expectWarningInProduction(PropTypes.element, false); + expectWarningInProduction(PropTypes.element.isRequired, null); + expectWarningInProduction(PropTypes.element.isRequired, undefined); }); }); describe('Instance Types', function() { it('should warn if called manually in production', function() { spyOn(console, 'error'); - productionWarningCheck(PropTypes.instanceOf(Date), {}); - productionWarningCheck(PropTypes.instanceOf(Date), new Date()); - productionWarningCheck(PropTypes.instanceOf(Date).isRequired, {}); - productionWarningCheck(PropTypes.instanceOf(Date).isRequired, new Date()); + expectWarningInProduction(PropTypes.instanceOf(Date), {}); + expectWarningInProduction(PropTypes.instanceOf(Date), new Date()); + expectWarningInProduction(PropTypes.instanceOf(Date).isRequired, {}); + expectWarningInProduction(PropTypes.instanceOf(Date).isRequired, new Date()); }); }); describe('React Component Types', function() { it('should warn if called manually in production', function() { spyOn(console, 'error'); - productionWarningCheck(PropTypes.node, 'node'); - productionWarningCheck(PropTypes.node, {}); - productionWarningCheck(PropTypes.node.isRequired, 'node'); - productionWarningCheck(PropTypes.node.isRequired, undefined); - productionWarningCheck(PropTypes.node.isRequired, undefined); + expectWarningInProduction(PropTypes.node, 'node'); + expectWarningInProduction(PropTypes.node, {}); + expectWarningInProduction(PropTypes.node.isRequired, 'node'); + expectWarningInProduction(PropTypes.node.isRequired, undefined); + expectWarningInProduction(PropTypes.node.isRequired, undefined); }); }); describe('ObjectOf Type', function() { it('should warn if called manually in production', function() { spyOn(console, 'error'); - productionWarningCheck( + expectWarningInProduction( PropTypes.objectOf({ foo: PropTypes.string }), { foo: 'bar' } ); - productionWarningCheck( + expectWarningInProduction( PropTypes.objectOf(PropTypes.number), {a: 1, b: 2, c: 'b'} ); - productionWarningCheck(PropTypes.objectOf(PropTypes.number), [1, 2]); - productionWarningCheck(PropTypes.objectOf(PropTypes.number), null); - productionWarningCheck(PropTypes.objectOf(PropTypes.number), undefined); + expectWarningInProduction(PropTypes.objectOf(PropTypes.number), [1, 2]); + expectWarningInProduction(PropTypes.objectOf(PropTypes.number), null); + expectWarningInProduction(PropTypes.objectOf(PropTypes.number), undefined); }); }); describe('OneOf Types', function() { it('should warn if called manually in production', function() { spyOn(console, 'error'); - productionWarningCheck(PropTypes.oneOf('red', 'blue'), 'red'); - productionWarningCheck(PropTypes.oneOf(['red', 'blue']), true); - productionWarningCheck(PropTypes.oneOf(['red', 'blue']), null); - productionWarningCheck(PropTypes.oneOf(['red', 'blue']), undefined); + expectWarningInProduction(PropTypes.oneOf('red', 'blue'), 'red'); + expectWarningInProduction(PropTypes.oneOf(['red', 'blue']), true); + expectWarningInProduction(PropTypes.oneOf(['red', 'blue']), null); + expectWarningInProduction(PropTypes.oneOf(['red', 'blue']), undefined); }); }); describe('Union Types', function() { it('should warn if called manually in production', function() { spyOn(console, 'error'); - productionWarningCheck( + expectWarningInProduction( PropTypes.oneOfType(PropTypes.string, PropTypes.number), 'red' ); - productionWarningCheck( + expectWarningInProduction( PropTypes.oneOfType([PropTypes.string, PropTypes.number]), [] ); - productionWarningCheck( + expectWarningInProduction( PropTypes.oneOfType([PropTypes.string, PropTypes.number]), null ); - productionWarningCheck( + expectWarningInProduction( PropTypes.oneOfType([PropTypes.string, PropTypes.number]), undefined ); @@ -215,17 +215,17 @@ describe('ReactPropTypesProduction', function() { describe('Shape Types', function() { it('should warn if called manually in production', function() { spyOn(console, 'error'); - productionWarningCheck(PropTypes.shape({}), 'some string'); - productionWarningCheck(PropTypes.shape({ foo: PropTypes.number }), { foo: 42 }); - productionWarningCheck( + expectWarningInProduction(PropTypes.shape({}), 'some string'); + expectWarningInProduction(PropTypes.shape({ foo: PropTypes.number }), { foo: 42 }); + expectWarningInProduction( PropTypes.shape({key: PropTypes.number}).isRequired, null ); - productionWarningCheck( + expectWarningInProduction( PropTypes.shape({key: PropTypes.number}).isRequired, undefined ); - productionWarningCheck(PropTypes.element,
); + expectWarningInProduction(PropTypes.element,
); }); }); From 0fc728fd96802678f9aaff0ba4eace6c19c8afe3 Mon Sep 17 00:00:00 2001 From: Brandon Dail Date: Mon, 27 Jun 2016 15:48:43 -0500 Subject: [PATCH 07/14] Call toString on Math.random() --- src/isomorphic/classic/types/ReactPropTypesSecret.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/isomorphic/classic/types/ReactPropTypesSecret.js b/src/isomorphic/classic/types/ReactPropTypesSecret.js index 3ecf61687c5..1b9b06195e8 100644 --- a/src/isomorphic/classic/types/ReactPropTypesSecret.js +++ b/src/isomorphic/classic/types/ReactPropTypesSecret.js @@ -12,6 +12,7 @@ 'use strict'; -const ReactPropTypesSecret = '__REACT_PROP_TYPES_SECRET__' + Math.random(); + +const ReactPropTypesSecret = '__REACT_PROP_TYPES_SECRET__' + Math.random().toString(); module.exports = ReactPropTypesSecret; From 0bcd6665f79324f335f1bef52b807091a96b9754 Mon Sep 17 00:00:00 2001 From: Brandon Dail Date: Mon, 27 Jun 2016 15:49:35 -0500 Subject: [PATCH 08/14] Rename test block for React type checks --- .../classic/types/__tests__/ReactPropTypesProduction-test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/isomorphic/classic/types/__tests__/ReactPropTypesProduction-test.js b/src/isomorphic/classic/types/__tests__/ReactPropTypesProduction-test.js index a456fdb2bce..9f508f8fae7 100644 --- a/src/isomorphic/classic/types/__tests__/ReactPropTypesProduction-test.js +++ b/src/isomorphic/classic/types/__tests__/ReactPropTypesProduction-test.js @@ -229,7 +229,7 @@ describe('ReactPropTypesProduction', function() { }); }); - it('should not warn when doing type checks internally', function() { + it('should not warn for type checks performed by React', function() { spyOn(console, 'error'); var Component = React.createClass({ propTypes: { From 43193e2c1efcd6c2ed26f8ca6b5667ca386370ef Mon Sep 17 00:00:00 2001 From: Brandon Dail Date: Mon, 27 Jun 2016 15:51:04 -0500 Subject: [PATCH 09/14] Make sure warning isnt emitted for failing props --- .../classic/types/__tests__/ReactPropTypesProduction-test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/isomorphic/classic/types/__tests__/ReactPropTypesProduction-test.js b/src/isomorphic/classic/types/__tests__/ReactPropTypesProduction-test.js index 9f508f8fae7..67639246329 100644 --- a/src/isomorphic/classic/types/__tests__/ReactPropTypesProduction-test.js +++ b/src/isomorphic/classic/types/__tests__/ReactPropTypesProduction-test.js @@ -244,7 +244,7 @@ describe('ReactPropTypesProduction', function() { }, }); var instance = ( - + ); instance = ReactTestUtils.renderIntoDocument(instance); expect(console.error.calls.count()).toBe(0); From 35b0ac7571063e379de655db7162f437a376ab4a Mon Sep 17 00:00:00 2001 From: Brandon Dail Date: Wed, 29 Jun 2016 10:15:48 -0500 Subject: [PATCH 10/14] Cache warning by component and prop, warn in dev --- .../classic/types/ReactPropTypes.js | 26 +- .../ReactPropTypesProduction-test.js | 229 +++++++++--------- 2 files changed, 137 insertions(+), 118 deletions(-) diff --git a/src/isomorphic/classic/types/ReactPropTypes.js b/src/isomorphic/classic/types/ReactPropTypes.js index 458e0f0c296..b0027722d86 100644 --- a/src/isomorphic/classic/types/ReactPropTypes.js +++ b/src/isomorphic/classic/types/ReactPropTypes.js @@ -106,6 +106,9 @@ function is(x, y) { /*eslint-enable no-self-compare*/ function createChainableTypeChecker(validate) { + if (__DEV__) { + var manualPropTypeCallCache = {}; + } function checkType( isRequired, props, @@ -117,14 +120,21 @@ function createChainableTypeChecker(validate) { ) { componentName = componentName || ANONYMOUS; propFullName = propFullName || propName; - if (!__DEV__) { - if (secret !== ReactPropTypesSecret && typeof console !== 'undefined') { - console.error( - `You are manually calling a React.PropTypes validation function ` + - `for the prop ${propFullName} on ${componentName} in a production ` + - `build. This is deprecated and will not work in the next ` + - `major version.` - ); + if (__DEV__) { + if ( + secret !== ReactPropTypesSecret && + typeof console !== 'undefined' + ) { + var cacheKey = `${componentName}:${propName}`; + if (!manualPropTypeCallCache[cacheKey]) { + console.error( + `You are manually calling a React.PropTypes validation ` + + `function for the prop ${propFullName} on ${componentName} ` + + `in a production build. This is deprecated and will ` + + `not work in the next major version.` + ); + manualPropTypeCallCache[cacheKey] = true; + } } } if (props[propName] == null) { diff --git a/src/isomorphic/classic/types/__tests__/ReactPropTypesProduction-test.js b/src/isomorphic/classic/types/__tests__/ReactPropTypesProduction-test.js index 67639246329..20ae53ae3d4 100644 --- a/src/isomorphic/classic/types/__tests__/ReactPropTypesProduction-test.js +++ b/src/isomorphic/classic/types/__tests__/ReactPropTypesProduction-test.js @@ -13,35 +13,41 @@ describe('ReactPropTypesProduction', function() { - var oldProcess; + // var oldProcess; var PropTypes; var React; var ReactTestUtils; beforeEach(function() { - __DEV__ = false; - oldProcess = process; - global.process = {env: {NODE_ENV: 'production'}}; - - jest.resetModuleRegistry(); + // __DEV__ = false; + // oldProcess = process; + // global.process = {env: {NODE_ENV: 'production'}}; + // + // jest.resetModuleRegistry(); PropTypes = require('ReactPropTypes'); React = require('React'); ReactTestUtils = require('ReactTestUtils'); }); afterEach(function() { - __DEV__ = true; - global.process = oldProcess; + // __DEV__ = true; + // global.process = oldProcess; }); - function expectWarningInProduction(declaration, value) { + function expectWarningInDevelopment(declaration, value) { var props = {testProp: value}; - declaration( - props, - 'testProp', - 'testComponent', - 'prop' - ); + // Call the function three times in all cases to make + // sure the warning is only output once. + var propName = 'testProp' + Math.random().toString(); + var componentName = 'testComponent' + Math.random().toString(); + for (var i = 0; i < 3; i ++) { + 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 ' @@ -51,161 +57,161 @@ describe('ReactPropTypesProduction', function() { describe('Primitive Types', function() { - it('should warn if called manually in production', function() { + it('should warn if called manually in development', function() { spyOn(console, 'error'); - expectWarningInProduction(PropTypes.array, /please/); - expectWarningInProduction(PropTypes.array, []); - expectWarningInProduction(PropTypes.array.isRequired, /please/); - expectWarningInProduction(PropTypes.array.isRequired, []); - expectWarningInProduction(PropTypes.array.isRequired, null); - expectWarningInProduction(PropTypes.array.isRequired, undefined); - expectWarningInProduction(PropTypes.bool, []); - expectWarningInProduction(PropTypes.bool, true); - expectWarningInProduction(PropTypes.bool.isRequired, []); - expectWarningInProduction(PropTypes.bool.isRequired, true); - expectWarningInProduction(PropTypes.bool.isRequired, null); - expectWarningInProduction(PropTypes.bool.isRequired, undefined); - expectWarningInProduction(PropTypes.func, false); - expectWarningInProduction(PropTypes.func, function() {}); - expectWarningInProduction(PropTypes.func.isRequired, false); - expectWarningInProduction(PropTypes.func.isRequired, function() {}); - expectWarningInProduction(PropTypes.func.isRequired, null); - expectWarningInProduction(PropTypes.func.isRequired, undefined); - expectWarningInProduction(PropTypes.number, function() {}); - expectWarningInProduction(PropTypes.number, 42); - expectWarningInProduction(PropTypes.number.isRequired, function() {}); - expectWarningInProduction(PropTypes.number.isRequired, 42); - expectWarningInProduction(PropTypes.number.isRequired, null); - expectWarningInProduction(PropTypes.number.isRequired, undefined); - expectWarningInProduction(PropTypes.string, 0); - expectWarningInProduction(PropTypes.string, 'foo'); - expectWarningInProduction(PropTypes.string.isRequired, 0); - expectWarningInProduction(PropTypes.string.isRequired, 'foo'); - expectWarningInProduction(PropTypes.string.isRequired, null); - expectWarningInProduction(PropTypes.string.isRequired, undefined); - expectWarningInProduction(PropTypes.symbol, 0); - expectWarningInProduction(PropTypes.symbol, Symbol('Foo')); - expectWarningInProduction(PropTypes.symbol.isRequired, 0); - expectWarningInProduction(PropTypes.symbol.isRequired, Symbol('Foo')); - expectWarningInProduction(PropTypes.symbol.isRequired, null); - expectWarningInProduction(PropTypes.symbol.isRequired, undefined); - expectWarningInProduction(PropTypes.object, ''); - expectWarningInProduction(PropTypes.object, {foo: 'bar'}); - expectWarningInProduction(PropTypes.object.isRequired, ''); - expectWarningInProduction(PropTypes.object.isRequired, {foo: 'bar'}); - expectWarningInProduction(PropTypes.object.isRequired, null); - expectWarningInProduction(PropTypes.object.isRequired, undefined); + expectWarningInDevelopment(PropTypes.array, /please/); + expectWarningInDevelopment(PropTypes.array, []); + expectWarningInDevelopment(PropTypes.array.isRequired, /please/); + expectWarningInDevelopment(PropTypes.array.isRequired, []); + expectWarningInDevelopment(PropTypes.array.isRequired, null); + expectWarningInDevelopment(PropTypes.array.isRequired, undefined); + expectWarningInDevelopment(PropTypes.bool, []); + expectWarningInDevelopment(PropTypes.bool, true); + expectWarningInDevelopment(PropTypes.bool.isRequired, []); + expectWarningInDevelopment(PropTypes.bool.isRequired, true); + expectWarningInDevelopment(PropTypes.bool.isRequired, null); + expectWarningInDevelopment(PropTypes.bool.isRequired, undefined); + expectWarningInDevelopment(PropTypes.func, false); + expectWarningInDevelopment(PropTypes.func, function() {}); + expectWarningInDevelopment(PropTypes.func.isRequired, false); + expectWarningInDevelopment(PropTypes.func.isRequired, function() {}); + expectWarningInDevelopment(PropTypes.func.isRequired, null); + expectWarningInDevelopment(PropTypes.func.isRequired, undefined); + expectWarningInDevelopment(PropTypes.number, function() {}); + expectWarningInDevelopment(PropTypes.number, 42); + expectWarningInDevelopment(PropTypes.number.isRequired, function() {}); + expectWarningInDevelopment(PropTypes.number.isRequired, 42); + expectWarningInDevelopment(PropTypes.number.isRequired, null); + expectWarningInDevelopment(PropTypes.number.isRequired, undefined); + expectWarningInDevelopment(PropTypes.string, 0); + expectWarningInDevelopment(PropTypes.string, 'foo'); + expectWarningInDevelopment(PropTypes.string.isRequired, 0); + expectWarningInDevelopment(PropTypes.string.isRequired, 'foo'); + expectWarningInDevelopment(PropTypes.string.isRequired, null); + expectWarningInDevelopment(PropTypes.string.isRequired, undefined); + expectWarningInDevelopment(PropTypes.symbol, 0); + expectWarningInDevelopment(PropTypes.symbol, Symbol('Foo')); + expectWarningInDevelopment(PropTypes.symbol.isRequired, 0); + expectWarningInDevelopment(PropTypes.symbol.isRequired, Symbol('Foo')); + expectWarningInDevelopment(PropTypes.symbol.isRequired, null); + expectWarningInDevelopment(PropTypes.symbol.isRequired, undefined); + expectWarningInDevelopment(PropTypes.object, ''); + expectWarningInDevelopment(PropTypes.object, {foo: 'bar'}); + expectWarningInDevelopment(PropTypes.object.isRequired, ''); + expectWarningInDevelopment(PropTypes.object.isRequired, {foo: 'bar'}); + expectWarningInDevelopment(PropTypes.object.isRequired, null); + expectWarningInDevelopment(PropTypes.object.isRequired, undefined); }); }); describe('Any Type', function() { - it('should warn if called manually in production', function() { + it('should warn if called manually in development', function() { spyOn(console, 'error'); - expectWarningInProduction(PropTypes.any, null); - expectWarningInProduction(PropTypes.any.isRequired, null); - expectWarningInProduction(PropTypes.any.isRequired, undefined); + expectWarningInDevelopment(PropTypes.any, null); + expectWarningInDevelopment(PropTypes.any.isRequired, null); + expectWarningInDevelopment(PropTypes.any.isRequired, undefined); }); }); describe('ArrayOf Type', function() { - it('should warn if called manually in production', function() { + it('should warn if called manually in development', function() { spyOn(console, 'error'); - expectWarningInProduction( + expectWarningInDevelopment( PropTypes.arrayOf({ foo: PropTypes.string }), { foo: 'bar' } ); - expectWarningInProduction( + expectWarningInDevelopment( PropTypes.arrayOf(PropTypes.number), [1, 2, 'b'] ); - expectWarningInProduction( + expectWarningInDevelopment( PropTypes.arrayOf(PropTypes.number), {'0': 'maybe-array', length: 1} ); - expectWarningInProduction(PropTypes.arrayOf(PropTypes.number).isRequired, null); - expectWarningInProduction(PropTypes.arrayOf(PropTypes.number).isRequired, undefined); + expectWarningInDevelopment(PropTypes.arrayOf(PropTypes.number).isRequired, null); + expectWarningInDevelopment(PropTypes.arrayOf(PropTypes.number).isRequired, undefined); }); }); describe('Component Type', function() { - it('should warn if called manually in production', function() { + it('should warn if called manually in development', function() { spyOn(console, 'error'); - expectWarningInProduction(PropTypes.element, [
,
]); - expectWarningInProduction(PropTypes.element,
); - expectWarningInProduction(PropTypes.element, 123); - expectWarningInProduction(PropTypes.element, 'foo'); - expectWarningInProduction(PropTypes.element, false); - expectWarningInProduction(PropTypes.element.isRequired, null); - expectWarningInProduction(PropTypes.element.isRequired, undefined); + expectWarningInDevelopment(PropTypes.element, [
,
]); + expectWarningInDevelopment(PropTypes.element,
); + expectWarningInDevelopment(PropTypes.element, 123); + expectWarningInDevelopment(PropTypes.element, 'foo'); + expectWarningInDevelopment(PropTypes.element, false); + expectWarningInDevelopment(PropTypes.element.isRequired, null); + expectWarningInDevelopment(PropTypes.element.isRequired, undefined); }); }); describe('Instance Types', function() { - it('should warn if called manually in production', function() { + it('should warn if called manually in development', function() { spyOn(console, 'error'); - expectWarningInProduction(PropTypes.instanceOf(Date), {}); - expectWarningInProduction(PropTypes.instanceOf(Date), new Date()); - expectWarningInProduction(PropTypes.instanceOf(Date).isRequired, {}); - expectWarningInProduction(PropTypes.instanceOf(Date).isRequired, new Date()); + expectWarningInDevelopment(PropTypes.instanceOf(Date), {}); + expectWarningInDevelopment(PropTypes.instanceOf(Date), new Date()); + expectWarningInDevelopment(PropTypes.instanceOf(Date).isRequired, {}); + expectWarningInDevelopment(PropTypes.instanceOf(Date).isRequired, new Date()); }); }); describe('React Component Types', function() { - it('should warn if called manually in production', function() { + it('should warn if called manually in development', function() { spyOn(console, 'error'); - expectWarningInProduction(PropTypes.node, 'node'); - expectWarningInProduction(PropTypes.node, {}); - expectWarningInProduction(PropTypes.node.isRequired, 'node'); - expectWarningInProduction(PropTypes.node.isRequired, undefined); - expectWarningInProduction(PropTypes.node.isRequired, undefined); + expectWarningInDevelopment(PropTypes.node, 'node'); + expectWarningInDevelopment(PropTypes.node, {}); + expectWarningInDevelopment(PropTypes.node.isRequired, 'node'); + expectWarningInDevelopment(PropTypes.node.isRequired, undefined); + expectWarningInDevelopment(PropTypes.node.isRequired, undefined); }); }); describe('ObjectOf Type', function() { - it('should warn if called manually in production', function() { + it('should warn if called manually in development', function() { spyOn(console, 'error'); - expectWarningInProduction( + expectWarningInDevelopment( PropTypes.objectOf({ foo: PropTypes.string }), { foo: 'bar' } ); - expectWarningInProduction( + expectWarningInDevelopment( PropTypes.objectOf(PropTypes.number), {a: 1, b: 2, c: 'b'} ); - expectWarningInProduction(PropTypes.objectOf(PropTypes.number), [1, 2]); - expectWarningInProduction(PropTypes.objectOf(PropTypes.number), null); - expectWarningInProduction(PropTypes.objectOf(PropTypes.number), undefined); + expectWarningInDevelopment(PropTypes.objectOf(PropTypes.number), [1, 2]); + expectWarningInDevelopment(PropTypes.objectOf(PropTypes.number), null); + expectWarningInDevelopment(PropTypes.objectOf(PropTypes.number), undefined); }); }); describe('OneOf Types', function() { - it('should warn if called manually in production', function() { + it('should warn if called manually in development', function() { spyOn(console, 'error'); - expectWarningInProduction(PropTypes.oneOf('red', 'blue'), 'red'); - expectWarningInProduction(PropTypes.oneOf(['red', 'blue']), true); - expectWarningInProduction(PropTypes.oneOf(['red', 'blue']), null); - expectWarningInProduction(PropTypes.oneOf(['red', 'blue']), undefined); + expectWarningInDevelopment(PropTypes.oneOf('red', 'blue'), 'red'); + expectWarningInDevelopment(PropTypes.oneOf(['red', 'blue']), true); + expectWarningInDevelopment(PropTypes.oneOf(['red', 'blue']), null); + expectWarningInDevelopment(PropTypes.oneOf(['red', 'blue']), undefined); }); }); describe('Union Types', function() { - it('should warn if called manually in production', function() { + it('should warn if called manually in development', function() { spyOn(console, 'error'); - expectWarningInProduction( + expectWarningInDevelopment( PropTypes.oneOfType(PropTypes.string, PropTypes.number), 'red' ); - expectWarningInProduction( + expectWarningInDevelopment( PropTypes.oneOfType([PropTypes.string, PropTypes.number]), [] ); - expectWarningInProduction( + expectWarningInDevelopment( PropTypes.oneOfType([PropTypes.string, PropTypes.number]), null ); - expectWarningInProduction( + expectWarningInDevelopment( PropTypes.oneOfType([PropTypes.string, PropTypes.number]), undefined ); @@ -213,19 +219,19 @@ describe('ReactPropTypesProduction', function() { }); describe('Shape Types', function() { - it('should warn if called manually in production', function() { + it('should warn if called manually in development', function() { spyOn(console, 'error'); - expectWarningInProduction(PropTypes.shape({}), 'some string'); - expectWarningInProduction(PropTypes.shape({ foo: PropTypes.number }), { foo: 42 }); - expectWarningInProduction( + expectWarningInDevelopment(PropTypes.shape({}), 'some string'); + expectWarningInDevelopment(PropTypes.shape({ foo: PropTypes.number }), { foo: 42 }); + expectWarningInDevelopment( PropTypes.shape({key: PropTypes.number}).isRequired, null ); - expectWarningInProduction( + expectWarningInDevelopment( PropTypes.shape({key: PropTypes.number}).isRequired, undefined ); - expectWarningInProduction(PropTypes.element,
); + expectWarningInDevelopment(PropTypes.element,
); }); }); @@ -247,7 +253,10 @@ describe('ReactPropTypesProduction', function() { ); instance = ReactTestUtils.renderIntoDocument(instance); - expect(console.error.calls.count()).toBe(0); + expect(console.error.calls.count()).toBe(1); + expect(console.error.calls.argsFor(0)[0]).not.toContain( + 'You are manually calling a React.PropTypes validation ' + ); }); }); From b550f5ba4b0af172ef860f7bd55a090726e89cb1 Mon Sep 17 00:00:00 2001 From: Brandon Dail Date: Wed, 29 Jun 2016 10:35:54 -0500 Subject: [PATCH 11/14] Pass ReactPropTypesSecret to internal checks --- src/addons/link/__tests__/ReactLinkPropTypes-test.js | 9 +++++++-- src/isomorphic/classic/types/ReactPropTypes.js | 12 +++++++----- .../classic/types/__tests__/ReactPropTypes-test.js | 10 ++++++++-- .../dom/client/wrappers/LinkedValueUtils.js | 5 ++++- 4 files changed, 26 insertions(+), 10 deletions(-) diff --git a/src/addons/link/__tests__/ReactLinkPropTypes-test.js b/src/addons/link/__tests__/ReactLinkPropTypes-test.js index 6ade1377703..7171c7f5532 100644 --- a/src/addons/link/__tests__/ReactLinkPropTypes-test.js +++ b/src/addons/link/__tests__/ReactLinkPropTypes-test.js @@ -15,6 +15,7 @@ var emptyFunction = require('emptyFunction'); var LinkPropTypes = require('ReactLink').PropTypes; var React = require('React'); var ReactPropTypeLocations = require('ReactPropTypeLocations'); +var ReactPropTypesSecret = require('ReactPropTypesSecret'); var invalidMessage = 'Invalid prop `testProp` supplied to `testComponent`.'; var requiredMessage = @@ -26,7 +27,9 @@ function typeCheckFail(declaration, value, message) { props, 'testProp', 'testComponent', - ReactPropTypeLocations.prop + ReactPropTypeLocations.prop, + null, + ReactPropTypesSecret ); expect(error instanceof Error).toBe(true); expect(error.message).toBe(message); @@ -38,7 +41,9 @@ function typeCheckPass(declaration, value) { props, 'testProp', 'testComponent', - ReactPropTypeLocations.prop + ReactPropTypeLocations.prop, + null, + ReactPropTypesSecret ); expect(error).toBe(null); } diff --git a/src/isomorphic/classic/types/ReactPropTypes.js b/src/isomorphic/classic/types/ReactPropTypes.js index b0027722d86..ba34830524c 100644 --- a/src/isomorphic/classic/types/ReactPropTypes.js +++ b/src/isomorphic/classic/types/ReactPropTypes.js @@ -127,11 +127,13 @@ function createChainableTypeChecker(validate) { ) { var cacheKey = `${componentName}:${propName}`; if (!manualPropTypeCallCache[cacheKey]) { - console.error( - `You are manually calling a React.PropTypes validation ` + - `function for the prop ${propFullName} on ${componentName} ` + - `in a production build. This is deprecated and will ` + - `not work in the next major version.` + warning( + false, + 'You are manually calling a React.PropTypes validation ' + + 'function for the prop %s on %s. This is deprecated ' + + 'and will not work in the next major version.', + propFullName, + componentName ); manualPropTypeCallCache[cacheKey] = true; } diff --git a/src/isomorphic/classic/types/__tests__/ReactPropTypes-test.js b/src/isomorphic/classic/types/__tests__/ReactPropTypes-test.js index 4e787857c76..8016dc4cbc4 100644 --- a/src/isomorphic/classic/types/__tests__/ReactPropTypes-test.js +++ b/src/isomorphic/classic/types/__tests__/ReactPropTypes-test.js @@ -16,6 +16,7 @@ var React; var ReactFragment; var ReactPropTypeLocations; var ReactTestUtils; +var ReactPropTypesSecret; var Component; var MyComponent; @@ -28,7 +29,9 @@ function typeCheckFail(declaration, value, message) { props, 'testProp', 'testComponent', - ReactPropTypeLocations.prop + ReactPropTypeLocations.prop, + null, + ReactPropTypesSecret ); expect(error instanceof Error).toBe(true); expect(error.message).toBe(message); @@ -40,7 +43,9 @@ function typeCheckPass(declaration, value) { props, 'testProp', 'testComponent', - ReactPropTypeLocations.prop + ReactPropTypeLocations.prop, + null, + ReactPropTypesSecret ); expect(error).toBe(null); } @@ -52,6 +57,7 @@ describe('ReactPropTypes', function() { ReactFragment = require('ReactFragment'); ReactPropTypeLocations = require('ReactPropTypeLocations'); ReactTestUtils = require('ReactTestUtils'); + ReactPropTypesSecret = require('ReactPropTypesSecret'); }); describe('Primitive Types', function() { diff --git a/src/renderers/dom/client/wrappers/LinkedValueUtils.js b/src/renderers/dom/client/wrappers/LinkedValueUtils.js index ae3afb98d23..d13630d6f56 100644 --- a/src/renderers/dom/client/wrappers/LinkedValueUtils.js +++ b/src/renderers/dom/client/wrappers/LinkedValueUtils.js @@ -13,6 +13,7 @@ var ReactPropTypes = require('ReactPropTypes'); var ReactPropTypeLocations = require('ReactPropTypeLocations'); +var ReactPropTypesSecret = require('ReactPropTypesSecret'); var invariant = require('invariant'); var warning = require('warning'); @@ -109,7 +110,9 @@ var LinkedValueUtils = { props, propName, tagName, - ReactPropTypeLocations.prop + ReactPropTypeLocations.prop, + null, + ReactPropTypesSecret ); } if (error instanceof Error && !(error.message in loggedTypeFailures)) { From 48f796f46f3ea1c6ed77059e1bc5936457928b20 Mon Sep 17 00:00:00 2001 From: Brandon Dail Date: Wed, 29 Jun 2016 16:21:14 -0500 Subject: [PATCH 12/14] Move tests to ReactPropTypes-test.js --- .../types/__tests__/ReactPropTypes-test.js | 183 ++++++++++++ .../ReactPropTypesProduction-test.js | 262 ------------------ 2 files changed, 183 insertions(+), 262 deletions(-) delete mode 100644 src/isomorphic/classic/types/__tests__/ReactPropTypesProduction-test.js diff --git a/src/isomorphic/classic/types/__tests__/ReactPropTypes-test.js b/src/isomorphic/classic/types/__tests__/ReactPropTypes-test.js index 8016dc4cbc4..82cfcccddab 100644 --- a/src/isomorphic/classic/types/__tests__/ReactPropTypes-test.js +++ b/src/isomorphic/classic/types/__tests__/ReactPropTypes-test.js @@ -50,6 +50,25 @@ function typeCheckPass(declaration, value) { expect(error).toBe(null); } +function expectWarningInDevelopment(declaration, value) { + var props = {testProp: 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' + ); + } + expect(console.error.calls.count()).toBe(1); + expect(console.error.calls.argsFor(0)[0]).toContain( + 'You are manually calling a React.PropTypes validation ' + ); + console.error.calls.reset(); +} + describe('ReactPropTypes', function() { beforeEach(function() { PropTypes = require('ReactPropTypes'); @@ -130,6 +149,54 @@ describe('ReactPropTypes', function() { typeCheckFail(PropTypes.string.isRequired, null, requiredMessage); typeCheckFail(PropTypes.string.isRequired, undefined, requiredMessage); }); + + it('should warn if called manually in development', function() { + spyOn(console, 'error'); + expectWarningInDevelopment(PropTypes.array, /please/); + expectWarningInDevelopment(PropTypes.array, []); + expectWarningInDevelopment(PropTypes.array.isRequired, /please/); + expectWarningInDevelopment(PropTypes.array.isRequired, []); + expectWarningInDevelopment(PropTypes.array.isRequired, null); + expectWarningInDevelopment(PropTypes.array.isRequired, undefined); + expectWarningInDevelopment(PropTypes.bool, []); + expectWarningInDevelopment(PropTypes.bool, true); + expectWarningInDevelopment(PropTypes.bool.isRequired, []); + expectWarningInDevelopment(PropTypes.bool.isRequired, true); + expectWarningInDevelopment(PropTypes.bool.isRequired, null); + expectWarningInDevelopment(PropTypes.bool.isRequired, undefined); + expectWarningInDevelopment(PropTypes.func, false); + expectWarningInDevelopment(PropTypes.func, function() {}); + expectWarningInDevelopment(PropTypes.func.isRequired, false); + expectWarningInDevelopment(PropTypes.func.isRequired, function() {}); + expectWarningInDevelopment(PropTypes.func.isRequired, null); + expectWarningInDevelopment(PropTypes.func.isRequired, undefined); + expectWarningInDevelopment(PropTypes.number, function() {}); + expectWarningInDevelopment(PropTypes.number, 42); + expectWarningInDevelopment(PropTypes.number.isRequired, function() {}); + expectWarningInDevelopment(PropTypes.number.isRequired, 42); + expectWarningInDevelopment(PropTypes.number.isRequired, null); + expectWarningInDevelopment(PropTypes.number.isRequired, undefined); + expectWarningInDevelopment(PropTypes.string, 0); + expectWarningInDevelopment(PropTypes.string, 'foo'); + expectWarningInDevelopment(PropTypes.string.isRequired, 0); + expectWarningInDevelopment(PropTypes.string.isRequired, 'foo'); + expectWarningInDevelopment(PropTypes.string.isRequired, null); + expectWarningInDevelopment(PropTypes.string.isRequired, undefined); + expectWarningInDevelopment(PropTypes.symbol, 0); + expectWarningInDevelopment(PropTypes.symbol, Symbol('Foo')); + expectWarningInDevelopment(PropTypes.symbol.isRequired, 0); + expectWarningInDevelopment(PropTypes.symbol.isRequired, Symbol('Foo')); + expectWarningInDevelopment(PropTypes.symbol.isRequired, null); + expectWarningInDevelopment(PropTypes.symbol.isRequired, undefined); + expectWarningInDevelopment(PropTypes.object, ''); + expectWarningInDevelopment(PropTypes.object, {foo: 'bar'}); + expectWarningInDevelopment(PropTypes.object.isRequired, ''); + expectWarningInDevelopment(PropTypes.object.isRequired, {foo: 'bar'}); + expectWarningInDevelopment(PropTypes.object.isRequired, null); + expectWarningInDevelopment(PropTypes.object.isRequired, undefined); + }); + + }); describe('Any type', function() { @@ -149,6 +216,14 @@ describe('ReactPropTypes', function() { typeCheckFail(PropTypes.any.isRequired, null, requiredMessage); typeCheckFail(PropTypes.any.isRequired, undefined, requiredMessage); }); + + it('should warn if called manually in development', function() { + spyOn(console, 'error'); + expectWarningInDevelopment(PropTypes.any, null); + expectWarningInDevelopment(PropTypes.any.isRequired, null); + expectWarningInDevelopment(PropTypes.any.isRequired, undefined); + }); + }); describe('ArrayOf Type', function() { @@ -243,6 +318,24 @@ describe('ReactPropTypes', function() { requiredMessage ); }); + + it('should warn if called manually in development', function() { + 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(PropTypes.number).isRequired, null); + expectWarningInDevelopment(PropTypes.arrayOf(PropTypes.number).isRequired, undefined); + }); }); describe('Component Type', function() { @@ -298,6 +391,18 @@ describe('ReactPropTypes', function() { typeCheckFail(PropTypes.element.isRequired, null, requiredMessage); typeCheckFail(PropTypes.element.isRequired, undefined, requiredMessage); }); + + it('should warn if called manually in development', function() { + spyOn(console, 'error'); + expectWarningInDevelopment(PropTypes.element, [
,
]); + expectWarningInDevelopment(PropTypes.element,
); + expectWarningInDevelopment(PropTypes.element, 123); + expectWarningInDevelopment(PropTypes.element, 'foo'); + expectWarningInDevelopment(PropTypes.element, false); + expectWarningInDevelopment(PropTypes.element.isRequired, null); + expectWarningInDevelopment(PropTypes.element.isRequired, undefined); + }); + }); describe('Instance Types', function() { @@ -377,6 +482,15 @@ describe('ReactPropTypes', function() { PropTypes.instanceOf(String).isRequired, undefined, requiredMessage ); }); + + it('should warn if called manually in development', function() { + spyOn(console, 'error'); + expectWarningInDevelopment(PropTypes.instanceOf(Date), {}); + expectWarningInDevelopment(PropTypes.instanceOf(Date), new Date()); + expectWarningInDevelopment(PropTypes.instanceOf(Date).isRequired, {}); + expectWarningInDevelopment(PropTypes.instanceOf(Date).isRequired, new Date()); + }); + }); describe('React Component Types', function() { @@ -484,6 +598,16 @@ describe('ReactPropTypes', function() { it('should accept empty array for required props', function() { typeCheckPass(PropTypes.node.isRequired, []); }); + + it('should warn if called manually in development', function() { + spyOn(console, 'error'); + expectWarningInDevelopment(PropTypes.node, 'node'); + expectWarningInDevelopment(PropTypes.node, {}); + expectWarningInDevelopment(PropTypes.node.isRequired, 'node'); + expectWarningInDevelopment(PropTypes.node.isRequired, undefined); + expectWarningInDevelopment(PropTypes.node.isRequired, undefined); + }); + }); describe('ObjectOf Type', function() { @@ -593,6 +717,21 @@ describe('ReactPropTypes', function() { requiredMessage ); }); + + it('should warn if called manually in development', function() { + 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(PropTypes.number), [1, 2]); + expectWarningInDevelopment(PropTypes.objectOf(PropTypes.number), null); + expectWarningInDevelopment(PropTypes.objectOf(PropTypes.number), undefined); + }); }); describe('OneOf Types', function() { @@ -658,6 +797,14 @@ describe('ReactPropTypes', function() { requiredMessage ); }); + + it('should warn if called manually in development', function() { + spyOn(console, 'error'); + expectWarningInDevelopment(PropTypes.oneOf('red', 'blue'), 'red'); + expectWarningInDevelopment(PropTypes.oneOf(['red', 'blue']), true); + expectWarningInDevelopment(PropTypes.oneOf(['red', 'blue']), null); + expectWarningInDevelopment(PropTypes.oneOf(['red', 'blue']), undefined); + }); }); describe('Union Types', function() { @@ -729,6 +876,27 @@ describe('ReactPropTypes', function() { requiredMessage ); }); + + it('should warn if called manually in development', function() { + spyOn(console, 'error'); + expectWarningInDevelopment( + PropTypes.oneOfType(PropTypes.string, PropTypes.number), + 'red' + ); + expectWarningInDevelopment( + PropTypes.oneOfType([PropTypes.string, PropTypes.number]), + [] + ); + expectWarningInDevelopment( + PropTypes.oneOfType([PropTypes.string, PropTypes.number]), + null + ); + expectWarningInDevelopment( + PropTypes.oneOfType([PropTypes.string, PropTypes.number]), + undefined + ); + }); + }); describe('Shape Types', function() { @@ -813,6 +981,21 @@ describe('ReactPropTypes', function() { requiredMessage ); }); + + it('should warn if called manually in development', function() { + spyOn(console, 'error'); + expectWarningInDevelopment(PropTypes.shape({}), 'some string'); + expectWarningInDevelopment(PropTypes.shape({ foo: PropTypes.number }), { foo: 42 }); + expectWarningInDevelopment( + PropTypes.shape({key: PropTypes.number}).isRequired, + null + ); + expectWarningInDevelopment( + PropTypes.shape({key: PropTypes.number}).isRequired, + undefined + ); + expectWarningInDevelopment(PropTypes.element,
); + }); }); describe('Symbol Type', function() { diff --git a/src/isomorphic/classic/types/__tests__/ReactPropTypesProduction-test.js b/src/isomorphic/classic/types/__tests__/ReactPropTypesProduction-test.js deleted file mode 100644 index 20ae53ae3d4..00000000000 --- a/src/isomorphic/classic/types/__tests__/ReactPropTypesProduction-test.js +++ /dev/null @@ -1,262 +0,0 @@ -/** - * Copyright 2013-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * @emails react-core - */ - -'use strict'; - - -describe('ReactPropTypesProduction', function() { - // var oldProcess; - var PropTypes; - var React; - var ReactTestUtils; - - beforeEach(function() { - // __DEV__ = false; - // oldProcess = process; - // global.process = {env: {NODE_ENV: 'production'}}; - // - // jest.resetModuleRegistry(); - PropTypes = require('ReactPropTypes'); - React = require('React'); - ReactTestUtils = require('ReactTestUtils'); - }); - - afterEach(function() { - // __DEV__ = true; - // global.process = oldProcess; - }); - - function expectWarningInDevelopment(declaration, value) { - var props = {testProp: value}; - // Call the function three times in all cases to make - // sure the warning is only output once. - var propName = 'testProp' + Math.random().toString(); - var componentName = 'testComponent' + Math.random().toString(); - for (var i = 0; i < 3; i ++) { - 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 ' - ); - console.error.calls.reset(); - } - - - describe('Primitive Types', function() { - it('should warn if called manually in development', function() { - spyOn(console, 'error'); - expectWarningInDevelopment(PropTypes.array, /please/); - expectWarningInDevelopment(PropTypes.array, []); - expectWarningInDevelopment(PropTypes.array.isRequired, /please/); - expectWarningInDevelopment(PropTypes.array.isRequired, []); - expectWarningInDevelopment(PropTypes.array.isRequired, null); - expectWarningInDevelopment(PropTypes.array.isRequired, undefined); - expectWarningInDevelopment(PropTypes.bool, []); - expectWarningInDevelopment(PropTypes.bool, true); - expectWarningInDevelopment(PropTypes.bool.isRequired, []); - expectWarningInDevelopment(PropTypes.bool.isRequired, true); - expectWarningInDevelopment(PropTypes.bool.isRequired, null); - expectWarningInDevelopment(PropTypes.bool.isRequired, undefined); - expectWarningInDevelopment(PropTypes.func, false); - expectWarningInDevelopment(PropTypes.func, function() {}); - expectWarningInDevelopment(PropTypes.func.isRequired, false); - expectWarningInDevelopment(PropTypes.func.isRequired, function() {}); - expectWarningInDevelopment(PropTypes.func.isRequired, null); - expectWarningInDevelopment(PropTypes.func.isRequired, undefined); - expectWarningInDevelopment(PropTypes.number, function() {}); - expectWarningInDevelopment(PropTypes.number, 42); - expectWarningInDevelopment(PropTypes.number.isRequired, function() {}); - expectWarningInDevelopment(PropTypes.number.isRequired, 42); - expectWarningInDevelopment(PropTypes.number.isRequired, null); - expectWarningInDevelopment(PropTypes.number.isRequired, undefined); - expectWarningInDevelopment(PropTypes.string, 0); - expectWarningInDevelopment(PropTypes.string, 'foo'); - expectWarningInDevelopment(PropTypes.string.isRequired, 0); - expectWarningInDevelopment(PropTypes.string.isRequired, 'foo'); - expectWarningInDevelopment(PropTypes.string.isRequired, null); - expectWarningInDevelopment(PropTypes.string.isRequired, undefined); - expectWarningInDevelopment(PropTypes.symbol, 0); - expectWarningInDevelopment(PropTypes.symbol, Symbol('Foo')); - expectWarningInDevelopment(PropTypes.symbol.isRequired, 0); - expectWarningInDevelopment(PropTypes.symbol.isRequired, Symbol('Foo')); - expectWarningInDevelopment(PropTypes.symbol.isRequired, null); - expectWarningInDevelopment(PropTypes.symbol.isRequired, undefined); - expectWarningInDevelopment(PropTypes.object, ''); - expectWarningInDevelopment(PropTypes.object, {foo: 'bar'}); - expectWarningInDevelopment(PropTypes.object.isRequired, ''); - expectWarningInDevelopment(PropTypes.object.isRequired, {foo: 'bar'}); - expectWarningInDevelopment(PropTypes.object.isRequired, null); - expectWarningInDevelopment(PropTypes.object.isRequired, undefined); - }); - }); - - - describe('Any Type', function() { - it('should warn if called manually in development', function() { - spyOn(console, 'error'); - expectWarningInDevelopment(PropTypes.any, null); - expectWarningInDevelopment(PropTypes.any.isRequired, null); - expectWarningInDevelopment(PropTypes.any.isRequired, undefined); - }); - }); - - describe('ArrayOf Type', function() { - it('should warn if called manually in development', function() { - 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(PropTypes.number).isRequired, null); - expectWarningInDevelopment(PropTypes.arrayOf(PropTypes.number).isRequired, undefined); - }); - }); - - - describe('Component Type', function() { - it('should warn if called manually in development', function() { - spyOn(console, 'error'); - expectWarningInDevelopment(PropTypes.element, [
,
]); - expectWarningInDevelopment(PropTypes.element,
); - expectWarningInDevelopment(PropTypes.element, 123); - expectWarningInDevelopment(PropTypes.element, 'foo'); - expectWarningInDevelopment(PropTypes.element, false); - expectWarningInDevelopment(PropTypes.element.isRequired, null); - expectWarningInDevelopment(PropTypes.element.isRequired, undefined); - }); - }); - - describe('Instance Types', function() { - it('should warn if called manually in development', function() { - spyOn(console, 'error'); - expectWarningInDevelopment(PropTypes.instanceOf(Date), {}); - expectWarningInDevelopment(PropTypes.instanceOf(Date), new Date()); - expectWarningInDevelopment(PropTypes.instanceOf(Date).isRequired, {}); - expectWarningInDevelopment(PropTypes.instanceOf(Date).isRequired, new Date()); - }); - }); - - describe('React Component Types', function() { - it('should warn if called manually in development', function() { - spyOn(console, 'error'); - expectWarningInDevelopment(PropTypes.node, 'node'); - expectWarningInDevelopment(PropTypes.node, {}); - expectWarningInDevelopment(PropTypes.node.isRequired, 'node'); - expectWarningInDevelopment(PropTypes.node.isRequired, undefined); - expectWarningInDevelopment(PropTypes.node.isRequired, undefined); - }); - }); - - describe('ObjectOf Type', function() { - it('should warn if called manually in development', function() { - 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(PropTypes.number), [1, 2]); - expectWarningInDevelopment(PropTypes.objectOf(PropTypes.number), null); - expectWarningInDevelopment(PropTypes.objectOf(PropTypes.number), undefined); - }); - }); - - describe('OneOf Types', function() { - it('should warn if called manually in development', function() { - spyOn(console, 'error'); - expectWarningInDevelopment(PropTypes.oneOf('red', 'blue'), 'red'); - expectWarningInDevelopment(PropTypes.oneOf(['red', 'blue']), true); - expectWarningInDevelopment(PropTypes.oneOf(['red', 'blue']), null); - expectWarningInDevelopment(PropTypes.oneOf(['red', 'blue']), undefined); - }); - }); - - describe('Union Types', function() { - it('should warn if called manually in development', function() { - spyOn(console, 'error'); - expectWarningInDevelopment( - PropTypes.oneOfType(PropTypes.string, PropTypes.number), - 'red' - ); - expectWarningInDevelopment( - PropTypes.oneOfType([PropTypes.string, PropTypes.number]), - [] - ); - expectWarningInDevelopment( - PropTypes.oneOfType([PropTypes.string, PropTypes.number]), - null - ); - expectWarningInDevelopment( - PropTypes.oneOfType([PropTypes.string, PropTypes.number]), - undefined - ); - }); - }); - - describe('Shape Types', function() { - it('should warn if called manually in development', function() { - spyOn(console, 'error'); - expectWarningInDevelopment(PropTypes.shape({}), 'some string'); - expectWarningInDevelopment(PropTypes.shape({ foo: PropTypes.number }), { foo: 42 }); - expectWarningInDevelopment( - PropTypes.shape({key: PropTypes.number}).isRequired, - null - ); - expectWarningInDevelopment( - PropTypes.shape({key: PropTypes.number}).isRequired, - undefined - ); - expectWarningInDevelopment(PropTypes.element,
); - }); - }); - - it('should not warn for type checks performed by React', function() { - spyOn(console, 'error'); - var Component = React.createClass({ - propTypes: { - foo: PropTypes.string, - bar: PropTypes.number, - baz: PropTypes.shape({ - qux: PropTypes.array, - }), - }, - render: function() { - return
; - }, - }); - var instance = ( - - ); - instance = ReactTestUtils.renderIntoDocument(instance); - expect(console.error.calls.count()).toBe(1); - expect(console.error.calls.argsFor(0)[0]).not.toContain( - 'You are manually calling a React.PropTypes validation ' - ); - }); - -}); From 01d0f8b4a7e1aa337c40dae933f552140923bf29 Mon Sep 17 00:00:00 2001 From: Brandon Dail Date: Thu, 30 Jun 2016 14:19:37 -0500 Subject: [PATCH 13/14] Update the warning message to include link --- src/isomorphic/classic/types/ReactPropTypes.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/isomorphic/classic/types/ReactPropTypes.js b/src/isomorphic/classic/types/ReactPropTypes.js index ba34830524c..ec060fbde79 100644 --- a/src/isomorphic/classic/types/ReactPropTypes.js +++ b/src/isomorphic/classic/types/ReactPropTypes.js @@ -130,8 +130,10 @@ function createChainableTypeChecker(validate) { warning( false, 'You are manually calling a React.PropTypes validation ' + - 'function for the prop %s on %s. This is deprecated ' + - 'and will not work in the next major version.', + 'function for the `%s` prop on `%s`. This is deprecated ' + + 'and will not work in 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 ); From df8f7c213e9eac2411fd4511fd87c551dd97bce3 Mon Sep 17 00:00:00 2001 From: Brandon Dail Date: Tue, 5 Jul 2016 10:02:44 -0500 Subject: [PATCH 14/14] Do not test warning for unions with invalid args --- .../classic/types/__tests__/ReactPropTypes-test.js | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/isomorphic/classic/types/__tests__/ReactPropTypes-test.js b/src/isomorphic/classic/types/__tests__/ReactPropTypes-test.js index 82cfcccddab..b11179a11f5 100644 --- a/src/isomorphic/classic/types/__tests__/ReactPropTypes-test.js +++ b/src/isomorphic/classic/types/__tests__/ReactPropTypes-test.js @@ -800,7 +800,6 @@ describe('ReactPropTypes', function() { it('should warn if called manually in development', function() { spyOn(console, 'error'); - expectWarningInDevelopment(PropTypes.oneOf('red', 'blue'), 'red'); expectWarningInDevelopment(PropTypes.oneOf(['red', 'blue']), true); expectWarningInDevelopment(PropTypes.oneOf(['red', 'blue']), null); expectWarningInDevelopment(PropTypes.oneOf(['red', 'blue']), undefined); @@ -879,10 +878,6 @@ describe('ReactPropTypes', function() { it('should warn if called manually in development', function() { spyOn(console, 'error'); - expectWarningInDevelopment( - PropTypes.oneOfType(PropTypes.string, PropTypes.number), - 'red' - ); expectWarningInDevelopment( PropTypes.oneOfType([PropTypes.string, PropTypes.number]), []