Skip to content
This repository has been archived by the owner on Sep 1, 2024. It is now read-only.

Commit

Permalink
[New] Add type check for validator for 'shape' and 'exact'
Browse files Browse the repository at this point in the history
Fixes #220.
  • Loading branch information
Asbjørn Hegdahl authored and ljharb committed Oct 26, 2018
1 parent 75ddcb8 commit 9e7afa3
Show file tree
Hide file tree
Showing 3 changed files with 62 additions and 2 deletions.
25 changes: 25 additions & 0 deletions __tests__/PropTypesDevelopmentReact15.js
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,15 @@ function expectWarningInDevelopment(declaration, value) {
console.error.calls.reset();
}

function expectInvalidValidatorWarning(declaration, type) {
PropTypes.checkPropTypes({ foo: declaration }, { foo: {} }, 'prop', 'testComponent', null);
expect(console.error.calls.argsFor(0)[0]).toEqual(
'Warning: Failed prop type: testComponent: prop type `foo.bar` is invalid; '
+ 'it must be a function, usually from the `prop-types` package, but received `' + type + '`.'
);
console.error.calls.reset();
}

describe('PropTypesDevelopmentReact15', () => {
beforeEach(() => {
resetWarningCache();
Expand Down Expand Up @@ -224,6 +233,22 @@ describe('PropTypesDevelopmentReact15', () => {
);
expect(returnValue).toBe(undefined);
});

it('should warn for invalid validators inside shape', () => {
spyOn(console, 'error');
expectInvalidValidatorWarning(PropTypes.shape({ bar: PropTypes.invalid_type }), 'undefined');
expectInvalidValidatorWarning(PropTypes.shape({ bar: true }), 'boolean');
expectInvalidValidatorWarning(PropTypes.shape({ bar: 'true' }), 'string');
expectInvalidValidatorWarning(PropTypes.shape({ bar: null }), 'null');
});

it('should warn for invalid validators inside exact', () => {
spyOn(console, 'error');
expectInvalidValidatorWarning(PropTypes.exact({ bar: PropTypes.invalid_type }), 'undefined');
expectInvalidValidatorWarning(PropTypes.exact({ bar: true }), 'boolean');
expectInvalidValidatorWarning(PropTypes.exact({ bar: 'true' }), 'string');
expectInvalidValidatorWarning(PropTypes.exact({ bar: null }), 'null');
});
});

describe('resetWarningCache', () => {
Expand Down
25 changes: 25 additions & 0 deletions __tests__/PropTypesDevelopmentStandalone-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,15 @@ function expectThrowsInDevelopment(declaration, value) {
);
}

function expectInvalidValidatorWarning(declaration, type) {
PropTypes.checkPropTypes({ foo: declaration }, { foo: {} }, 'prop', 'testComponent', null);
expect(console.error.calls.argsFor(0)[0]).toEqual(
'Warning: Failed prop type: testComponent: prop type `foo.bar` is invalid; '
+ 'it must be a function, usually from the `prop-types` package, but received `' + type + '`.'
);
console.error.calls.reset();
}

describe('PropTypesDevelopmentStandalone', () => {
beforeEach(() => {
resetWarningCache();
Expand Down Expand Up @@ -221,6 +230,22 @@ describe('PropTypesDevelopmentStandalone', () => {
);
expect(returnValue).toBe(undefined);
});

it('should warn for invalid validators inside shape', () => {
spyOn(console, 'error');
expectInvalidValidatorWarning(PropTypes.shape({ bar: PropTypes.invalid_type }), 'undefined');
expectInvalidValidatorWarning(PropTypes.shape({ bar: true }), 'boolean');
expectInvalidValidatorWarning(PropTypes.shape({ bar: 'true' }), 'string');
expectInvalidValidatorWarning(PropTypes.shape({ bar: null }), 'null');
});

it('should warn for invalid validators inside exact', () => {
spyOn(console, 'error');
expectInvalidValidatorWarning(PropTypes.exact({ bar: PropTypes.invalid_type }), 'undefined');
expectInvalidValidatorWarning(PropTypes.exact({ bar: true }), 'boolean');
expectInvalidValidatorWarning(PropTypes.exact({ bar: 'true' }), 'string');
expectInvalidValidatorWarning(PropTypes.exact({ bar: null }), 'null');
});
});

describe('resetWarningCache', () => {
Expand Down
14 changes: 12 additions & 2 deletions factoryWithTypeCheckers.js
Original file line number Diff line number Diff line change
Expand Up @@ -400,6 +400,13 @@ module.exports = function(isValidElement, throwOnDirectAccess) {
return createChainableTypeChecker(validate);
}

function invalidValidatorError(componentName, location, propFullName, key, type) {
return new PropTypeError(
(componentName || 'React class') + ': ' + location + ' type `' + propFullName + '.' + key + '` is invalid; ' +
'it must be a function, usually from the `prop-types` package, but received `' + type + '`.'
);
}

function createShapeTypeChecker(shapeTypes) {
function validate(props, propName, componentName, location, propFullName) {
var propValue = props[propName];
Expand All @@ -409,8 +416,8 @@ module.exports = function(isValidElement, throwOnDirectAccess) {
}
for (var key in shapeTypes) {
var checker = shapeTypes[key];
if (!checker) {
continue;
if (typeof checker !== 'function') {
return invalidValidatorError(componentName, location, propFullName, key, getPreciseType(checker));
}
var error = checker(propValue, key, componentName, location, propFullName + '.' + key, ReactPropTypesSecret);
if (error) {
Expand All @@ -434,6 +441,9 @@ module.exports = function(isValidElement, throwOnDirectAccess) {
var allKeys = assign({}, props[propName], shapeTypes);
for (var key in allKeys) {
var checker = shapeTypes[key];
if (has(shapeTypes, key) && typeof checker !== 'function') {
return invalidValidatorError(componentName, location, propFullName, key, getPreciseType(checker));
}
if (!checker) {
return new PropTypeError(
'Invalid ' + location + ' `' + propFullName + '` key `' + key + '` supplied to `' + componentName + '`.' +
Expand Down

0 comments on commit 9e7afa3

Please sign in to comment.