diff --git a/README.md b/README.md index 7be7810..5069e51 100755 --- a/README.md +++ b/README.md @@ -25,8 +25,6 @@ Use the mixin function which returns a class with PropTypes and defaultProps log const ValidatingModel = propTypesMixin(Model); ``` -If `process.env.NODE_ENV === 'production'`, PropTypes checking will be disabled. - Define your concrete model, and add `propTypes` and `defaultProps` static class attributes. ```javascript @@ -44,7 +42,7 @@ Person.defaultProps = { Person.modelName = 'Person'; ``` -The mixin adds a layer of logic on top of the Model static method `create` and the instance method `update`. When calling `create`, if you have defined `defaultProps`, it'll merge the defaults with the props you passed in. Then, if you've defined `Model.propTypes`, it'll validate the props. An error will be thrown if a prop is found to be invalid. The final props (that may have been merged with defaults) will be passed to the `create` method on the superclass you passed the mixin function. +The mixin adds a layer of logic on top of the Model static method `create` and the instance method `update`. When calling `create`, if you have defined `defaultProps`, it'll merge the defaults with the props you passed in. Then, if you've defined `Model.propTypes`, it'll validate the props. The final props (that may have been merged with defaults) will be passed to the `create` method on the superclass you passed the mixin function. When you call the `modelInstance.update(attrObj)` instance method, the keys in `attrObj` will be checked against the corresponding `propTypes`, if they exist. diff --git a/package.json b/package.json index 6e89e59..3afff3d 100644 --- a/package.json +++ b/package.json @@ -31,6 +31,9 @@ "eslint-config-airbnb-base": "^11.2.0", "eslint-plugin-import": "^2.2.0", "jest": "^21.2.1", - "react": "^0.14.7" + "react": "^0.14.9" + }, + "dependencies": { + "prop-types": "^15.6.0" } } diff --git a/src/index.js b/src/index.js index 47ca3e1..07a6f56 100755 --- a/src/index.js +++ b/src/index.js @@ -1,9 +1,4 @@ -function validateProp(validator, props, key, modelName) { - const result = validator(props, key, modelName, 'prop'); - if (result instanceof Error) { - throw result; - } -} +import { PropTypes } from 'prop-types'; function hasPropTypes(obj) { return typeof obj.propTypes === 'object'; @@ -14,9 +9,7 @@ function hasDefaultProps(obj) { } function validateProps(props, propTypes, modelName) { - Object.keys(propTypes).forEach((key) => { - validateProp(propTypes[key], props, key, modelName); - }); + PropTypes.checkPropTypes(propTypes, props, 'prop', modelName); } export function getPropTypesMixin(userOpts) { diff --git a/src/index.test.js b/src/index.test.js index 89a8944..9849aab 100644 --- a/src/index.test.js +++ b/src/index.test.js @@ -1,5 +1,4 @@ -/* eslint-disable import/no-extraneous-dependencies */ -import { PropTypes } from 'react'; +import { PropTypes } from 'prop-types'; import propTypesMixin, { getPropTypesMixin } from './index'; @@ -9,6 +8,7 @@ describe('PropTypesMixin', () => { let modelInstance; let createSpy; let updateSpy; + let consoleErrorSpy; beforeEach(() => { Model = class { @@ -27,6 +27,8 @@ describe('PropTypesMixin', () => { modelInstance = new ModelWithMixin(); updateSpy = jest.spyOn(modelInstance, 'update'); + consoleErrorSpy = jest.spyOn(global.console, 'error'); + consoleErrorSpy.mockReset(); }); it('getPropTypesMixin works correctly', () => { @@ -65,10 +67,11 @@ describe('PropTypesMixin', () => { }; ModelWithMixin.create({ name: 'shouldnt raise error' }); + expect(consoleErrorSpy.mock.calls.length).toBe(0); - const funcShouldThrow = () => ModelWithMixin.create({ notName: 'asd' }); - - expect(funcShouldThrow).toThrow('ModelWithMixin', 'name'); + ModelWithMixin.create({ notName: 'asd' }); + expect(consoleErrorSpy.mock.calls.length).toBe(1); + expect(consoleErrorSpy).toBeCalledWith('Warning: Failed prop type: The prop `name` is marked as required in `ModelWithMixin.create`, but its value is `undefined`.'); }); it('raises validation error on update correctly', () => { @@ -76,12 +79,14 @@ describe('PropTypesMixin', () => { name: PropTypes.string.isRequired, age: PropTypes.number.isRequired, }; + expect(consoleErrorSpy.mock.calls.length).toBe(0); + const instance = new ModelWithMixin({ name: 'asd', age: 123 }); + expect(consoleErrorSpy.mock.calls.length).toBe(0); - const instance = new ModelWithMixin(); - - const funcShouldThrow = () => instance.update({ name: 123 }); + instance.update({ name: 123 }); - expect(funcShouldThrow).toThrow('ModelWithMixin', 'name'); + expect(consoleErrorSpy.mock.calls.length).toBe(1); + expect(consoleErrorSpy).toBeCalledWith('Warning: Failed prop type: Invalid prop `name` of type `number` supplied to `ModelWithMixin.update`, expected `string`.'); }); it('correctly uses defaultProps', () => {