From 90c8c4783ca26aea2fad4769b143cf7055ab1c9b Mon Sep 17 00:00:00 2001 From: Jordan Harband Date: Tue, 4 Jan 2022 16:02:05 -0800 Subject: [PATCH] [Fix] fix crash when a custom propType return lacks `.data`; call `hasOwnProperty` properly Fixes #369 --- __tests__/PropTypesDevelopmentReact15.js | 31 +++++++++++++++++++ .../PropTypesDevelopmentStandalone-test.js | 31 +++++++++++++++++++ __tests__/PropTypesProductionReact15-test.js | 22 +++++++++++++ .../PropTypesProductionStandalone-test.js | 31 +++++++++++++++++++ factoryWithTypeCheckers.js | 2 +- 5 files changed, 116 insertions(+), 1 deletion(-) diff --git a/__tests__/PropTypesDevelopmentReact15.js b/__tests__/PropTypesDevelopmentReact15.js index a617234..49fe3ac 100644 --- a/__tests__/PropTypesDevelopmentReact15.js +++ b/__tests__/PropTypesDevelopmentReact15.js @@ -1385,6 +1385,37 @@ describe('PropTypesDevelopmentReact15', () => { ); expectWarningInDevelopment(PropTypes.element,
); }); + + it('works with oneOfType', () => { + typeCheckPass( + PropTypes.exact({ foo: PropTypes.oneOfType([PropTypes.number, PropTypes.string]) }), + { foo: 42 } + ); + typeCheckPass( + PropTypes.exact({ foo: PropTypes.oneOfType([PropTypes.number, PropTypes.string]) }), + { foo: '42' } + ); + typeCheckFail( + PropTypes.exact({ foo: PropTypes.oneOfType([PropTypes.number, PropTypes.string]) }), + { foo: 42, bar: 'what is 6 * 7' }, + `Warning: Failed prop type: Invalid prop \`testProp\` key \`bar\` supplied to \`testComponent\`. +Bad object: { + "foo": 42, + "bar": "what is 6 * 7" +} +Valid keys: [ + "foo" +]` + ); + }); + + it('works with a custom propType', () => { + typeCheckFail( + PropTypes.oneOfType([() => new Error('hi')]), + {}, + 'Warning: Failed prop type: Invalid prop `testProp` supplied to `testComponent`.' + ) + }); }); describe('Symbol Type', () => { diff --git a/__tests__/PropTypesDevelopmentStandalone-test.js b/__tests__/PropTypesDevelopmentStandalone-test.js index 066c03a..04310c1 100644 --- a/__tests__/PropTypesDevelopmentStandalone-test.js +++ b/__tests__/PropTypesDevelopmentStandalone-test.js @@ -1456,6 +1456,37 @@ describe('PropTypesDevelopmentStandalone', () => { ); expectThrowsInDevelopment(PropTypes.element,
); }); + + it('works with oneOfType', () => { + typeCheckPass( + PropTypes.exact({ foo: PropTypes.oneOfType([PropTypes.number, PropTypes.string]) }), + { foo: 42 } + ); + typeCheckPass( + PropTypes.exact({ foo: PropTypes.oneOfType([PropTypes.number, PropTypes.string]) }), + { foo: '42' } + ); + typeCheckFail( + PropTypes.exact({ foo: PropTypes.oneOfType([PropTypes.number, PropTypes.string]) }), + { foo: 42, bar: 'what is 6 * 7' }, + `Warning: Failed prop type: Invalid prop \`testProp\` key \`bar\` supplied to \`testComponent\`. +Bad object: { + "foo": 42, + "bar": "what is 6 * 7" +} +Valid keys: [ + "foo" +]` + ); + }); + + it('works with a custom propType', () => { + typeCheckFail( + PropTypes.oneOfType([() => new Error('hi')]), + {}, + 'Warning: Failed prop type: Invalid prop `testProp` supplied to `testComponent`.' + ) + }); }); describe('Symbol Type', () => { diff --git a/__tests__/PropTypesProductionReact15-test.js b/__tests__/PropTypesProductionReact15-test.js index 1a47724..2703916 100644 --- a/__tests__/PropTypesProductionReact15-test.js +++ b/__tests__/PropTypesProductionReact15-test.js @@ -1112,6 +1112,28 @@ describe('PropTypesProductionReact15', () => { ); expectNoop(PropTypes.element,
); }); + + it('works with oneOfType', () => { + expectNoop( + PropTypes.exact({ foo: PropTypes.oneOfType([PropTypes.number, PropTypes.string]) }), + { foo: 42 } + ); + expectNoop( + PropTypes.exact({ foo: PropTypes.oneOfType([PropTypes.number, PropTypes.string]) }), + { foo: '42' } + ); + expectNoop( + PropTypes.exact({ foo: PropTypes.oneOfType([PropTypes.number, PropTypes.string]) }), + { foo: 42, bar: 'what is 6 * 7' } + ); + }); + + it('works with a custom propType', () => { + expectNoop( + PropTypes.oneOfType([() => new Error('hi')]), + {} + ) + }); }); describe('Symbol Type', () => { diff --git a/__tests__/PropTypesProductionStandalone-test.js b/__tests__/PropTypesProductionStandalone-test.js index 24a5965..1aab48f 100644 --- a/__tests__/PropTypesProductionStandalone-test.js +++ b/__tests__/PropTypesProductionStandalone-test.js @@ -326,6 +326,37 @@ describe('PropTypesProductionStandalone', () => { PropTypes.exact({key: PropTypes.number}).isRequired, ); }); + + it('works with oneOfType', () => { + typeCheckPass( + PropTypes.exact({ foo: PropTypes.oneOfType([PropTypes.number, PropTypes.string]) }), + { foo: 42 } + ); + typeCheckPass( + PropTypes.exact({ foo: PropTypes.oneOfType([PropTypes.number, PropTypes.string]) }), + { foo: '42' } + ); + expectThrowsInProduction( + PropTypes.exact({ foo: PropTypes.oneOfType([PropTypes.number, PropTypes.string]) }), + { foo: 42, bar: 'what is 6 * 7' }, + `Warning: Failed prop type: Invalid prop \`testProp\` key \`bar\` supplied to \`testComponent\`. +Bad object: { + "foo": 42, + "bar": "what is 6 * 7" +} +Valid keys: [ + "foo" +]` + ); + }); + + it('works with a custom propType', () => { + expectThrowsInProduction( + PropTypes.oneOfType([() => new Error('hi')]), + {}, + 'Warning: Failed prop type: Invalid prop `testProp` supplied to `testComponent`.' + ) + }); }); describe('Symbol Type', () => { diff --git a/factoryWithTypeCheckers.js b/factoryWithTypeCheckers.js index 6108567..a88068e 100644 --- a/factoryWithTypeCheckers.js +++ b/factoryWithTypeCheckers.js @@ -390,7 +390,7 @@ module.exports = function(isValidElement, throwOnDirectAccess) { if (checkerResult == null) { return null; } - if (checkerResult.data.hasOwnProperty('expectedType')) { + if (checkerResult.data && has(checkerResult.data, 'expectedType')) { expectedTypes.push(checkerResult.data.expectedType); } }