From f4ca2d2d6202783d2d22f8639add8a958e50d328 Mon Sep 17 00:00:00 2001 From: mondaychen Date: Fri, 8 Apr 2016 13:58:23 -0400 Subject: [PATCH] Better warnings for nested propTypes --- src/ImmutablePropTypes.js | 31 +++++++------ src/__tests__/ImmutablePropTypes-test.js | 58 ++++++++++++------------ 2 files changed, 45 insertions(+), 44 deletions(-) diff --git a/src/ImmutablePropTypes.js b/src/ImmutablePropTypes.js index e43a125..1a519bd 100644 --- a/src/ImmutablePropTypes.js +++ b/src/ImmutablePropTypes.js @@ -50,18 +50,19 @@ function getPropType(propValue) { } function createChainableTypeChecker(validate) { - function checkType(isRequired, props, propName, componentName, location) { + function checkType(isRequired, props, propName, componentName, location, propFullName) { + propFullName = propFullName || propName; componentName = componentName || ANONYMOUS; if (props[propName] == null) { var locationName = location; if (isRequired) { return new Error( - `Required ${locationName} \`${propName}\` was not specified in ` + + `Required ${locationName} \`${propFullName}\` was not specified in ` + `\`${componentName}\`.` ); } } else { - return validate(props, propName, componentName, location); + return validate(props, propName, componentName, location, propFullName); } } @@ -72,12 +73,12 @@ function createChainableTypeChecker(validate) { } function createImmutableTypeChecker(immutableClassName, immutableClassTypeValidator) { - function validate(props, propName, componentName, location) { + function validate(props, propName, componentName, location, propFullName) { var propValue = props[propName]; if(!immutableClassTypeValidator(propValue)) { var propType = getPropType(propValue); return new Error( - `Invalid ${location} \`${propName}\` of type \`${propType}\` ` + + `Invalid ${location} \`${propFullName}\` of type \`${propType}\` ` + `supplied to \`${componentName}\`, expected \`${immutableClassName}\`.` ); } @@ -88,13 +89,13 @@ function createImmutableTypeChecker(immutableClassName, immutableClassTypeValida function createIterableTypeChecker(typeChecker, immutableClassName, immutableClassTypeValidator) { - function validate(props, propName, componentName, location) { + function validate(props, propName, componentName, location, propFullName) { var propValue = props[propName]; if (!immutableClassTypeValidator(propValue)) { var locationName = location; var propType = getPropType(propValue); return new Error( - `Invalid ${locationName} \`${propName}\` of type ` + + `Invalid ${locationName} \`${propFullName}\` of type ` + `\`${propType}\` supplied to \`${componentName}\`, expected an Immutable.js ${immutableClassName}.` ); } @@ -102,13 +103,13 @@ function createIterableTypeChecker(typeChecker, immutableClassName, immutableCla if (typeof typeChecker !== 'function') { return new Error( `Invalid typeChecker supplied to \`${componentName}\` ` + - `for propType \`${propName}\`, expected a function.` + `for propType \`${propFullName}\`, expected a function.` ); } var propValues = propValue.toArray(); for (var i = 0, len = propValues.length; i < len; i++) { - var error = typeChecker(propValues, i, componentName, location); + var error = typeChecker(propValues, i, componentName, location, `${propFullName}[${i}]`); if (error instanceof Error) { return error; } @@ -146,13 +147,13 @@ function createIterableOfTypeChecker(typeChecker) { } function createRecordOfTypeChecker(recordKeys) { - function validate(props, propName, componentName, location) { + function validate(props, propName, componentName, location, propFullName) { var propValue = props[propName]; var propType = getPropType(propValue); if (!(propValue instanceof Immutable.Record)) { var locationName = location; return new Error( - `Invalid ${locationName} \`${propName}\` of type \`${propType}\` ` + + `Invalid ${locationName} \`${propFullName}\` of type \`${propType}\` ` + `supplied to \`${componentName}\`, expected an Immutable.js Record.` ); } @@ -162,7 +163,7 @@ function createRecordOfTypeChecker(recordKeys) { continue; } var mutablePropValue = propValue.toObject(); - var error = checker(mutablePropValue, key, componentName, location); + var error = checker(mutablePropValue, key, componentName, location, `${propFullName}.${key}`); if (error) { return error; } @@ -173,13 +174,13 @@ function createRecordOfTypeChecker(recordKeys) { // there is some irony in the fact that shapeTypes is a standard hash and not an immutable collection function createShapeTypeChecker(shapeTypes, immutableClassName = 'Iterable', immutableClassTypeValidator = Immutable.Iterable.isIterable) { - function validate(props, propName, componentName, location) { + function validate(props, propName, componentName, location, propFullName) { var propValue = props[propName]; var propType = getPropType(propValue); if (!immutableClassTypeValidator(propValue)) { var locationName = location; return new Error( - `Invalid ${locationName} \`${propName}\` of type \`${propType}\` ` + + `Invalid ${locationName} \`${propFullName}\` of type \`${propType}\` ` + `supplied to \`${componentName}\`, expected an Immutable.js ${immutableClassName}.` ); } @@ -189,7 +190,7 @@ function createShapeTypeChecker(shapeTypes, immutableClassName = 'Iterable', imm if (!checker) { continue; } - var error = checker(mutablePropValue, key, componentName, location); + var error = checker(mutablePropValue, key, componentName, location, `${propFullName}.${key}`); if (error) { return error; } diff --git a/src/__tests__/ImmutablePropTypes-test.js b/src/__tests__/ImmutablePropTypes-test.js index 0a66996..8dfb38e 100644 --- a/src/__tests__/ImmutablePropTypes-test.js +++ b/src/__tests__/ImmutablePropTypes-test.js @@ -243,7 +243,7 @@ describe('ImmutablePropTypes', function() { typeCheckFail( PropTypes.listOf(React.PropTypes.number), Immutable.List([1, 2, 'b']), - 'Invalid prop `2` of type `string` supplied to `testComponent`, ' + + 'Invalid prop `testProp[2]` of type `string` supplied to `testComponent`, ' + 'expected `number`.' ); }); @@ -255,7 +255,7 @@ describe('ImmutablePropTypes', function() { typeCheckFail( PropTypes.listOf(React.PropTypes.instanceOf(Thing)), Immutable.List([new Thing(), 'xyz']), - 'Invalid prop `1` of type `String` supplied to `testComponent`, expected instance of `' + + 'Invalid prop `testProp[1]` of type `String` supplied to `testComponent`, expected instance of `' + name + '`.' ); }); @@ -335,7 +335,7 @@ describe('ImmutablePropTypes', function() { typeCheckFail( PropTypes.stackOf(React.PropTypes.number), Immutable.Stack([1, 2, 'b']), - 'Invalid prop `2` of type `string` supplied to `testComponent`, ' + + 'Invalid prop `testProp[2]` of type `string` supplied to `testComponent`, ' + 'expected `number`.' ); }); @@ -347,7 +347,7 @@ describe('ImmutablePropTypes', function() { typeCheckFail( PropTypes.stackOf(React.PropTypes.instanceOf(Thing)), Immutable.Stack([new Thing(), 'xyz']), - 'Invalid prop `1` of type `String` supplied to `testComponent`, expected instance of `' + + 'Invalid prop `testProp[1]` of type `String` supplied to `testComponent`, expected instance of `' + name + '`.' ); }); @@ -432,7 +432,7 @@ describe('ImmutablePropTypes', function() { typeCheckFail( PropTypes.mapOf(React.PropTypes.number), Immutable.Map({ 1: 1, 2: 2, 3: 'b' }), - 'Invalid prop `2` of type `string` supplied to `testComponent`, ' + + 'Invalid prop `testProp[2]` of type `string` supplied to `testComponent`, ' + 'expected `number`.' ); }); @@ -444,7 +444,7 @@ describe('ImmutablePropTypes', function() { typeCheckFail( PropTypes.mapOf(React.PropTypes.instanceOf(Thing)), Immutable.Map({ 1: new Thing(), 2: 'xyz' }), - 'Invalid prop `1` of type `String` supplied to `testComponent`, expected instance of `' + + 'Invalid prop `testProp[1]` of type `String` supplied to `testComponent`, expected instance of `' + name + '`.' ); }); @@ -529,7 +529,7 @@ describe('ImmutablePropTypes', function() { typeCheckFail( PropTypes.orderedMapOf(React.PropTypes.number), Immutable.OrderedMap({ 1: 1, 2: 2, 3: 'b' }), - 'Invalid prop `2` of type `string` supplied to `testComponent`, ' + + 'Invalid prop `testProp[2]` of type `string` supplied to `testComponent`, ' + 'expected `number`.' ); }); @@ -541,7 +541,7 @@ describe('ImmutablePropTypes', function() { typeCheckFail( PropTypes.orderedMapOf(React.PropTypes.instanceOf(Thing)), Immutable.OrderedMap({ 1: new Thing(), 2: 'xyz' }), - 'Invalid prop `1` of type `String` supplied to `testComponent`, expected instance of `' + + 'Invalid prop `testProp[1]` of type `String` supplied to `testComponent`, expected instance of `' + name + '`.' ); }); @@ -627,7 +627,7 @@ describe('ImmutablePropTypes', function() { typeCheckFail( PropTypes.setOf(React.PropTypes.number), Immutable.Set([1, 2, 'b']), - 'Invalid prop `2` of type `string` supplied to `testComponent`, ' + + 'Invalid prop `testProp[2]` of type `string` supplied to `testComponent`, ' + 'expected `number`.' ); }); @@ -639,7 +639,7 @@ describe('ImmutablePropTypes', function() { typeCheckFail( PropTypes.setOf(React.PropTypes.instanceOf(Thing)), Immutable.Set([new Thing(), 'xyz' ]), - 'Invalid prop `1` of type `String` supplied to `testComponent`, expected instance of `' + + 'Invalid prop `testProp[1]` of type `String` supplied to `testComponent`, expected instance of `' + name + '`.' ); }); @@ -719,7 +719,7 @@ describe('ImmutablePropTypes', function() { typeCheckFail( PropTypes.orderedSetOf(React.PropTypes.number), Immutable.OrderedSet([1, 2, 'b']), - 'Invalid prop `2` of type `string` supplied to `testComponent`, ' + + 'Invalid prop `testProp[2]` of type `string` supplied to `testComponent`, ' + 'expected `number`.' ); }); @@ -731,7 +731,7 @@ describe('ImmutablePropTypes', function() { typeCheckFail( PropTypes.orderedSetOf(React.PropTypes.instanceOf(Thing)), Immutable.OrderedSet([new Thing(), 'xyz' ]), - 'Invalid prop `1` of type `String` supplied to `testComponent`, expected instance of `' + + 'Invalid prop `testProp[1]` of type `String` supplied to `testComponent`, expected instance of `' + name + '`.' ); }); @@ -848,14 +848,14 @@ describe('ImmutablePropTypes', function() { typeCheckFail( PropTypes.iterableOf(React.PropTypes.number), Immutable.List([1, 2, 'b']), - 'Invalid prop `2` of type `string` supplied to `testComponent`, ' + + 'Invalid prop `testProp[2]` of type `string` supplied to `testComponent`, ' + 'expected `number`.' ); typeCheckFail( PropTypes.iterableOf(React.PropTypes.number), Immutable.Map({ 1: 1, 2: 2, 3: 'b' }), - 'Invalid prop `2` of type `string` supplied to `testComponent`, ' + + 'Invalid prop `testProp[2]` of type `string` supplied to `testComponent`, ' + 'expected `number`.' ); }); @@ -867,14 +867,14 @@ describe('ImmutablePropTypes', function() { typeCheckFail( PropTypes.iterableOf(React.PropTypes.instanceOf(Thing)), Immutable.List([new Thing(), 'xyz']), - 'Invalid prop `1` of type `String` supplied to `testComponent`, expected instance of `' + + 'Invalid prop `testProp[1]` of type `String` supplied to `testComponent`, expected instance of `' + name + '`.' ); typeCheckFail( PropTypes.iterableOf(React.PropTypes.instanceOf(Thing)), Immutable.Map({ 1: new Thing(), 2: 'xyz' }), - 'Invalid prop `1` of type `String` supplied to `testComponent`, expected instance of `' + + 'Invalid prop `testProp[1]` of type `String` supplied to `testComponent`, expected instance of `' + name + '`.' ); }); @@ -984,7 +984,7 @@ describe('ImmutablePropTypes', function() { typeCheckFail( PropTypes.recordOf({key: React.PropTypes.number.isRequired}), new (Immutable.Record({}))(), - 'Required prop `key` was not specified in `testComponent`.' + 'Required prop `testProp.key` was not specified in `testComponent`.' ); }); @@ -995,14 +995,14 @@ describe('ImmutablePropTypes', function() { secondKey: React.PropTypes.number.isRequired }), new (Immutable.Record({}))(), - 'Required prop `key` was not specified in `testComponent`.' + 'Required prop `testProp.key` was not specified in `testComponent`.' ); }); it('should warn for invalid key types', function() { typeCheckFail(PropTypes.recordOf({key: React.PropTypes.number}), new (Immutable.Record({key: 'abc'}))(), - 'Invalid prop `key` of type `string` supplied to `testComponent`, ' + + 'Invalid prop `testProp.key` of type `string` supplied to `testComponent`, ' + 'expected `number`.' ); }); @@ -1078,7 +1078,7 @@ describe('ImmutablePropTypes', function() { typeCheckFail( PropTypes.shape({key: React.PropTypes.number.isRequired}), Immutable.fromJS({}), - 'Required prop `key` was not specified in `testComponent`.' + 'Required prop `testProp.key` was not specified in `testComponent`.' ); }); @@ -1089,14 +1089,14 @@ describe('ImmutablePropTypes', function() { secondKey: React.PropTypes.number.isRequired }), Immutable.fromJS({}), - 'Required prop `key` was not specified in `testComponent`.' + 'Required prop `testProp.key` was not specified in `testComponent`.' ); }); it('should warn for invalid key types', function() { typeCheckFail(PropTypes.shape({key: React.PropTypes.number}), Immutable.fromJS({key: 'abc'}), - 'Invalid prop `key` of type `string` supplied to `testComponent`, ' + + 'Invalid prop `testProp.key` of type `string` supplied to `testComponent`, ' + 'expected `number`.' ); }); @@ -1181,7 +1181,7 @@ describe('ImmutablePropTypes', function() { typeCheckFail( PropTypes.contains({key: React.PropTypes.number.isRequired}), Immutable.fromJS({}), - 'Required prop `key` was not specified in `testComponent`.' + 'Required prop `testProp.key` was not specified in `testComponent`.' ); }); @@ -1192,14 +1192,14 @@ describe('ImmutablePropTypes', function() { secondKey: React.PropTypes.number.isRequired }), Immutable.fromJS({}), - 'Required prop `key` was not specified in `testComponent`.' + 'Required prop `testProp.key` was not specified in `testComponent`.' ); }); it('should warn for invalid key types', function() { typeCheckFail(PropTypes.contains({key: React.PropTypes.number}), Immutable.fromJS({key: 'abc'}), - 'Invalid prop `key` of type `string` supplied to `testComponent`, ' + + 'Invalid prop `testProp.key` of type `string` supplied to `testComponent`, ' + 'expected `number`.' ); }); @@ -1295,7 +1295,7 @@ describe('ImmutablePropTypes', function() { })).isRequired }), Immutable.fromJS({data: [{id: 1}, {}]}), - 'Required prop `id` was not specified in `testComponent`.' + 'Required prop `testProp.data[1].id` was not specified in `testComponent`.' ); }); @@ -1307,7 +1307,7 @@ describe('ImmutablePropTypes', function() { typeCheckFail( PropTypes.mapContains({key: React.PropTypes.number.isRequired}), Immutable.fromJS({}), - 'Required prop `key` was not specified in `testComponent`.' + 'Required prop `testProp.key` was not specified in `testComponent`.' ); }); @@ -1318,14 +1318,14 @@ describe('ImmutablePropTypes', function() { secondKey: React.PropTypes.number.isRequired }), Immutable.fromJS({}), - 'Required prop `key` was not specified in `testComponent`.' + 'Required prop `testProp.key` was not specified in `testComponent`.' ); }); it('should warn for invalid key types', function() { typeCheckFail(PropTypes.mapContains({key: React.PropTypes.number}), Immutable.fromJS({key: 'abc'}), - 'Invalid prop `key` of type `string` supplied to `testComponent`, ' + + 'Invalid prop `testProp.key` of type `string` supplied to `testComponent`, ' + 'expected `number`.' ); });