├── .envrc ├── test ├── utils │ └── test-helper.js ├── mocha.opts └── main.js ├── .babelrc ├── .travis.yml ├── src ├── prop-types.js └── main.js ├── .gitignore ├── LICENSE ├── CHANGELOG.md ├── package.json └── README.md /.envrc: -------------------------------------------------------------------------------- 1 | export PATH=./node_modules/.bin:$PATH 2 | -------------------------------------------------------------------------------- /test/utils/test-helper.js: -------------------------------------------------------------------------------- 1 | require('chai').should() 2 | -------------------------------------------------------------------------------- /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["@babel/preset-env"] 3 | } 4 | -------------------------------------------------------------------------------- /test/mocha.opts: -------------------------------------------------------------------------------- 1 | --recursive 2 | --require test/utils/test-helper 3 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - "6" 4 | after_success: 5 | - npm run coveralls 6 | -------------------------------------------------------------------------------- /src/prop-types.js: -------------------------------------------------------------------------------- 1 | let PropTypes 2 | 3 | try { PropTypes = require('prop-types') } 4 | catch (e) { PropTypes = require('react').PropTypes } 5 | 6 | module.exports = PropTypes 7 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | 6 | # Runtime data 7 | pids 8 | *.pid 9 | *.seed 10 | 11 | # Directory for instrumented libs generated by jscoverage/JSCover 12 | lib-cov 13 | 14 | # Coverage directory used by tools like istanbul 15 | coverage 16 | 17 | # nyc test coverage 18 | .nyc_output 19 | 20 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 21 | .grunt 22 | 23 | # node-waf configuration 24 | .lock-wscript 25 | 26 | # Compiled binary addons (http://nodejs.org/api/addons.html) 27 | build/Release 28 | 29 | # Dependency directories 30 | node_modules 31 | jspm_packages 32 | 33 | # Optional npm cache directory 34 | .npm 35 | 36 | # Optional REPL history 37 | .node_repl_history 38 | 39 | .env 40 | dist 41 | .DS_Store 42 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Mark Battersby 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## [Unreleased] 2 |
3 | 4 | Changes that have landed in master but are not yet released. 5 | 6 |
7 | 8 | ## 0.5.0 (August 17, 2018) 9 | * #18 - Generator can now accept a single type and will generate it. 10 | ```js 11 | generate(PropType.bool.isRequired) 12 | // => true 13 | ``` 14 | 15 | * #27 - Generator now generates Symbols. 16 | 17 | ## 0.4.0 (August 10, 2018) 18 | Breaking Changes: 19 | 20 | * #21 - Default generators now produce values that match their `propName`. 21 | ```js 22 | generate({ foo: PropType.string, bar: PropTypes.object }) 23 | // Old: => { foo: 'string', bar: {} } 24 | // New: => { foo: 'foo', bar: { bar: 'bar' } } 25 | ``` 26 | 27 | * #21 - Generator callbacks now receive `propName` as their first argument, and their definitions' argument as the second. 28 | 29 | * #19 - `generateProps.init()` *must* be called prior to components being imported or `generateProps()` being called. 30 | 31 | Non-breaking Changes: 32 | 33 | * #17 - Fixed: Deeply nested props wouldn't respect opts argument. 34 | ```js 35 | generate({ 36 | foo: PropType.shape({ 37 | bar: PropType.shape({ 38 | baz: PropType.string 39 | }) 40 | }) 41 | }, { optional: true }) 42 | // Old: => { foo: {} } 43 | // New: => { foo: { bar: { baz: 'baz' } } } 44 | ``` 45 | 46 | ## 0.3.0 (October 5, 2017) 47 | * Generators are now deterministic by default. Previously, snapshot tests might break if `oneOf` or `oneOfType` were used. 48 | * `opts` can now be passed as the second arg to `generateProps` to generate or omit required or optional types. Default: `{ required: true, optional: false }` 49 | * Generators can be overridden via the `opts` argument. Syntax: `generateProps(Component, { generators: { bool: () => false } })` 50 | * `string`, `any`, and `node` generators now return exactly those strings. (`'string'`, `'any'`, or `'node'`) 51 | * React 16 and the `prop-types` package are now supported. 52 | 53 | ### A Note On React v15.3 - v16.0 54 | If you are using React v15.3 or higher, you should port your PropTypes to the 55 | new `prop-type` lib. https://github.com/facebook/prop-types 56 | 57 | ## 0.2.0 (October 18, 2016) 58 | ## 0.1.0 (October 18, 2016) 59 | ## 0.0.1 (July 14, 2016) 60 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-generate-props", 3 | "version": "0.6.1", 4 | "description": "Generate default props based on your React component's PropTypes", 5 | "main": "dist/main.js", 6 | "engines": { 7 | "node": ">=6.0.0" 8 | }, 9 | "files": [ 10 | "dist/*", 11 | "src/*" 12 | ], 13 | "dependencies": { 14 | "lodash": "^4.13.1" 15 | }, 16 | "devDependencies": { 17 | "@babel/cli": "^7.5.5", 18 | "@babel/core": "^7.5.5", 19 | "@babel/preset-env": "^7.5.5", 20 | "chai": "^4.2.0", 21 | "coveralls": "^3.0.5", 22 | "istanbul": "^0.4.4", 23 | "mocha": "^6.2.0", 24 | "mocha-lcov-reporter": "^1.2.0", 25 | "prop-types": "^15.6.0", 26 | "react": "^16.0.0" 27 | }, 28 | "peerDependencies": { 29 | "react": "0.13.x || 0.14.x || ^15.0.0-0 || 15.x || 16.x" 30 | }, 31 | "scripts": { 32 | "build": "babel src -d dist", 33 | "preversion": "npm run build", 34 | "coverage": "istanbul cover _mocha", 35 | "precoveralls": "npm run coverage -- --report lcovonly", 36 | "coveralls": "cat ./coverage/lcov.info | coveralls", 37 | "postcoveralls": "rm -rf ./coverage", 38 | "test": "npm run react:no-prop-types && npm run react:with-prop-types", 39 | "react:clean": "rm -rf node_modules/react node_modules/react-dom node_modules/react-addons-test-utils node_modules/prop-types", 40 | "react:no-prop-types": "npm run react:13 && mocha && npm run react:14.8 && mocha && npm run react:15.2 && mocha", 41 | "react:13": "npm run react:clean && npm i --no-save --no-progress react@0.13 && rm -rf node_modules/prop-types", 42 | "react:14.8": "npm run react:clean && npm i --no-save --no-progress react@0.14.8 react-dom@0.14.8 react-addons-test-utils@0.14.8 && rm -rf node_modules/prop-types", 43 | "react:15.2": "npm run react:clean && npm i --no-save --no-progress react@15.2 react-dom@15 react-addons-test-utils@15.2 && rm -rf node_modules/prop-types", 44 | "react:with-prop-types": "npm run react:14 && mocha && npm run react:15 && mocha && npm run react:16 && mocha", 45 | "react:14": "npm run react:clean && npm i --no-save --no-progress react@0.14 react-dom@0.14 react-addons-test-utils@0.14", 46 | "react:15": "npm run react:clean && npm i --no-save --no-progress react@15 react-dom@15 react-addons-test-utils@15", 47 | "react:16": "npm run react:clean && npm i --no-save --no-progress react@16 prop-types" 48 | }, 49 | "repository": { 50 | "type": "git", 51 | "url": "git+https://github.com/markalfred/react-generate-props.git" 52 | }, 53 | "keywords": [ 54 | "react", 55 | "prop", 56 | "props", 57 | "proptypes", 58 | "generate", 59 | "generator" 60 | ], 61 | "author": "Mark Battersby", 62 | "license": "MIT", 63 | "bugs": { 64 | "url": "https://github.com/markalfred/react-generate-props/issues" 65 | }, 66 | "homepage": "https://github.com/markalfred/react-generate-props#readme" 67 | } 68 | -------------------------------------------------------------------------------- /src/main.js: -------------------------------------------------------------------------------- 1 | const _ = require('lodash') 2 | const React = require('react') 3 | const PropTypes = require('./prop-types') 4 | 5 | let options 6 | let initialized = false 7 | 8 | const addHiddenProperties = (obj, prop, value) => { 9 | addHiddenProperty(obj, prop, value) 10 | addHiddenProperty(obj.isRequired, prop, value) 11 | return obj 12 | } 13 | 14 | const addHiddenProperty = (obj, prop, value) => 15 | Object.defineProperty(obj, prop, { enumerable: false, value }) 16 | 17 | const wrapPropTypes = () => { 18 | initialized = true 19 | // Adds a .type key which allows the type to be derived during the 20 | // evaluation process. This is necessary for complex types which 21 | // return the result of a generator function, leaving no way to 22 | // determine which type instantiated it. 23 | 24 | const original = _.cloneDeep(PropTypes) 25 | 26 | _.each(_.keys(GENERATORS), (k) => { 27 | if (PropTypes[k] === undefined) return 28 | if (PropTypes[k].isRequired !== undefined) { 29 | // Simple type. Just extend the object 30 | PropTypes[k] = addHiddenProperties(PropTypes[k], 'type', k) 31 | } else { 32 | // Complex type. Must extend the creator's return value 33 | PropTypes[k] = (arg) => { 34 | let res = original[k](arg) 35 | res = addHiddenProperties(res, 'type', k) 36 | res = addHiddenProperties(res, 'arg', arg) 37 | return res 38 | } 39 | } 40 | }) 41 | } 42 | 43 | const GENERATORS = { 44 | // Simple types 45 | array: (propName) => propName ? [propName] : [], 46 | bool: () => true, 47 | func: () => () => {}, 48 | number: () => 1, 49 | object: (propName) => propName ? ({ [propName]: propName }): {}, 50 | string: (propName) => propName || 'string', 51 | any: (propName) => propName || 'any', 52 | element: (propName) => React.createElement('div', propName), 53 | node: (propName) => propName || 'node', 54 | symbol: (propName) => Symbol(propName), 55 | 56 | // Complex types 57 | arrayOf: (propName, type) => { 58 | const res = generateOneProp(type, propName, false) 59 | return res ? [res] : [] 60 | }, 61 | instanceOf: (propName, klass) => new klass(), 62 | objectOf: (propName, type) => ({ key: generateOneProp(type, propName, false) }), 63 | oneOf: (propName, values) => _.first(values), 64 | oneOfType: (propName, types) => forceGenerateOneProp(_.first(types), propName), 65 | shape: (propName, shape) => generateProps(shape, options), 66 | exact: (propName, shape) => generateProps(shape, options) 67 | } 68 | 69 | const shouldGenerate = (propType) => { 70 | return ( 71 | // Generate required props, and this is the required version 72 | (options.required && !propType.isRequired) || 73 | // Generate optional props, and this is the optional version 74 | (options.optional && !!propType.isRequired) 75 | ) 76 | } 77 | 78 | const initError = new Error( 79 | 'generateProps.init() must be called at the beginning of your test suite' 80 | ) 81 | 82 | const generateOneProp = (propType, propName, wrapInArray = true) => { 83 | if (propType.type === undefined && initialized === false) { 84 | throw initError 85 | } 86 | 87 | const generate = options.generators[propType.type].bind(this, propName) 88 | const arg = propType.arg 89 | if (generate) { 90 | if (shouldGenerate(propType)) { 91 | if (wrapInArray) { 92 | return [propName, generate(arg)] 93 | } else { 94 | return generate(arg) 95 | } 96 | } 97 | } 98 | } 99 | 100 | const forceGenerateOneProp = (propType, propName) => { 101 | const generate = GENERATORS[propType.type].bind(this, propName) 102 | const arg = propType.arg 103 | if (generate) { 104 | return generate(arg) 105 | } 106 | } 107 | 108 | const generateProps = (arg, opts) => { 109 | if (initialized === false) { 110 | throw initError 111 | } 112 | 113 | options = _.defaults({}, opts, { required: true, optional: false }) 114 | if (opts && opts.generators) { 115 | options.generators = _.defaults({}, opts.generators, GENERATORS) 116 | } else { 117 | options.generators = GENERATORS 118 | } 119 | 120 | let propTypes 121 | 122 | if (!arg) { 123 | throw new TypeError('generateProps expected a propType object or a React Component') 124 | } 125 | 126 | if (arg.type && GENERATORS[arg.type]) { 127 | return generateOneProp(arg, undefined, false) 128 | } else if (arg.propTypes && arg.propTypes.type && GENERATORS[arg.propTypes.type]) { 129 | return generateOneProp(arg.propTypes, undefined, false) 130 | } 131 | 132 | if (_.isPlainObject(arg.propTypes)) { 133 | propTypes = arg.propTypes 134 | } else if (_.isPlainObject(arg)) { 135 | propTypes = arg 136 | } else { 137 | throw new TypeError('generateProps expected a propType object or a React Component') 138 | } 139 | 140 | return _(propTypes) 141 | .map(generateOneProp) 142 | .compact() 143 | .fromPairs() 144 | .value() 145 | } 146 | 147 | Object.assign(generateProps, { init: wrapPropTypes }) 148 | 149 | module.exports = generateProps 150 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # react-generate-props 2 | Generate default props based on your React component's PropTypes 3 | 4 | [![Build Status](https://travis-ci.org/markalfred/react-generate-props.svg?branch=master)](https://travis-ci.org/markalfred/react-generate-props) 5 | [![Coverage Status](https://coveralls.io/repos/github/markalfred/react-generate-props/badge.svg?branch=master)](https://coveralls.io/github/markalfred/react-generate-props?branch=master) 6 | 7 | ```js 8 | generateProps({ name: PropTypes.string, number: PropTypes.number }) 9 | // => { name: 'name', number: 1 } 10 | ``` 11 | 12 | ## Installation 13 | ```bash 14 | $ npm install --save-dev react-generate-props 15 | ``` 16 | 17 | ## Usage 18 | 19 | **Important:** 20 | Initialize the library *before* importing any components into your test suite. 21 | 22 | ```js 23 | // test-helper.js 24 | 25 | import { init } from 'react-generate-props' 26 | init() 27 | ``` 28 | 29 | Define your component's propTypes. 30 | 31 | ```jsx 32 | const Counter = ({ count }) =>
{count}
33 | Counter.propTypes = { count: PropTypes.number.isRequired } 34 | export default Counter 35 | ``` 36 | 37 | Pass the component to this library. It will generate reasonable props based on the defined types. 38 | 39 | ```js 40 | import generateProps from 'react-generate-props' 41 | import Counter from './counter' 42 | generateProps(Counter) 43 | // => { count: 1 } 44 | ``` 45 | 46 | Use these default props to reduce boilerplate and prop type validation errors in your tests! :tada: 47 | 48 | ## Example 49 | 50 | A more in-depth example. 51 | 52 | ```jsx 53 | // component.jsx 54 | 55 | class Component extends React.Component { 56 | static propTypes = { 57 | title: PropTypes.string.isRequired, 58 | followers: PropTypes.number.isRequired, 59 | user: PropTypes.shape({ 60 | loggedIn: PropTypes.bool.isRequired, 61 | name: PropTypes.string.isRequired 62 | }).isRequired 63 | } 64 | 65 | render() { 66 |
67 |

{this.props.title}

68 | {this.props.followers} 69 | {this.props.user.loggedIn &&

Hello, {this.props.user.name}.

} 70 |
71 | } 72 | } 73 | 74 | export default Component 75 | ``` 76 | 77 | ```jsx 78 | // component-test.js 79 | 80 | import generateProps from 'react-generate-props' 81 | import Component from './component.jsx' 82 | 83 | const props = generateProps(Component) 84 | // => { title: 'title', followers: 1, user: { loggedIn: true, name: 'name' } } 85 | 86 | render() 87 | /* => 88 |
89 |

title

90 | 1 91 |

Hello, name.

92 |
93 | */ 94 | 95 | ``` 96 | 97 | ## API 98 | 99 | The library takes two arguments. 100 | 101 | ```js 102 | generateProps(schema, opts) 103 | ``` 104 | 105 | #### `schema`: An Object, Function, or Class containing a PropTypes definition, or a single PropType. All of the following are valid: 106 | 107 | Plain Object 108 | ```js 109 | const Counter = { count: PropTypes.number.isRequired } 110 | ``` 111 | 112 | Plain Object with a `propTypes` key 113 | ```js 114 | const Counter = { propTypes: { count: PropTypes.number.isRequired } } 115 | ``` 116 | 117 | Functional Component 118 | ```js 119 | const Counter = ({ counter }) => {/* ... */} 120 | Counter.propTypes = { count: PropTypes.number.isRequired } 121 | ``` 122 | 123 | `React.Component` Class 124 | ```js 125 | class Counter extends React.Component { 126 | static propTypes = { count: PropTypes.number.isRequired } 127 | } 128 | ``` 129 | 130 | Single PropType 131 | ```js 132 | const Counter = PropTypes.shape({ count: PropTypes.number.isRequired }).isRequired 133 | ``` 134 | 135 | In each of these cases, the effect would be the same 136 | ```js 137 | generateProps(Counter) 138 | // => { count: 1 } 139 | ``` 140 | 141 | #### `opts`: An Object which may contain the following: 142 | 143 | ```js 144 | { 145 | required: true, 146 | // default: true. When true, props marked as .isRequired will be generated. 147 | 148 | optional: false, 149 | // default: false. When true, props *not* marked as .isRequired will be generated. 150 | 151 | generators: { 152 | // Can be used to override this lib's default generators. 153 | // Each key is a prop type, each value is a function. 154 | // Each function receives the propName as its first argument, 155 | // followed by that prop type's argument, if it takes one. 156 | 157 | bool: (propName) => false, 158 | function: (propName) => spy(), 159 | number: (propName) => propName.length, 160 | instanceOf: (propName, klass) => new klass(), 161 | oneOf: (propName, values) => values[values.length - 1] 162 | } 163 | } 164 | ``` 165 | 166 | ## One More Example 167 | 168 | ```js 169 | const propTypes = { 170 | name: PropTypes.string.isRequired, 171 | loggedIn: PropTypes.bool, 172 | userType: PropTypes.oneOf(['admin', 'user']).isRequired 173 | } 174 | 175 | generateProps(propTypes) 176 | // => { name: 'string', userType: 'admin' } 177 | 178 | generateProps(propTypes, { optional: true }) 179 | // => { name: 'string', loggedIn: true, userType: 'admin' } 180 | 181 | generateProps(propTypes, { 182 | optional: true, 183 | generators: { 184 | string: (propName) => 'Alice', 185 | bool: (propName) => propName === 'loggedIn', 186 | oneOf: (propName, values) => values[values.length - 1] 187 | } 188 | }) 189 | // => { name: 'Alice', loggedIn: true, userType: 'user' } 190 | ``` 191 | -------------------------------------------------------------------------------- /test/main.js: -------------------------------------------------------------------------------- 1 | const React = require('react') 2 | const PropTypes = require('../src/prop-types') 3 | 4 | const ComponentAsClass = class extends React.Component { render() { 'component' } } 5 | const ComponentAsFunction = () => 'component' 6 | 7 | const generateProps = require('../src/main') 8 | 9 | describe('generateProps (incorrect)', () => { 10 | describe('when called before generateProps.init() was called', () => { 11 | it('throws an error', () => { 12 | const fnCall = () => generateProps({}) 13 | fnCall.should.throw(Error, 'generateProps.init() must be called at the beginning of your test suite') 14 | }) 15 | }) 16 | 17 | describe('given the bad argument', () => { 18 | // TODO: Add plain objects, or things like "React" to this. 19 | const badArgs = [null, undefined, 0, 1, -1, false, true, [], NaN, '', 'string'] 20 | 21 | for (let arg of badArgs) { 22 | describe('(' + arg + ')', () => { 23 | it('throws an error', () => { 24 | generateProps.init() 25 | let fnCall = () => generateProps(arg) 26 | fnCall.should.throw(TypeError, 'generateProps expected a propType object or a React Component') 27 | }) 28 | }) 29 | } 30 | }) 31 | }) 32 | 33 | describe('generateProps (correct)', () => { 34 | before(() => { generateProps.init() }) 35 | describe('given a required array', () => { 36 | it('generates an array', () => { 37 | const propTypes = { myArray: PropTypes.array.isRequired } 38 | ComponentAsClass.propTypes = propTypes 39 | ComponentAsFunction.propTypes = propTypes 40 | 41 | const expected = { myArray: ['myArray'] } 42 | 43 | generateProps(propTypes).should.deep.equal(expected) 44 | generateProps({ propTypes }).should.deep.equal(expected) 45 | generateProps(ComponentAsClass).should.deep.equal(expected) 46 | generateProps(ComponentAsFunction).should.deep.equal(expected) 47 | generateProps(propTypes.myArray).should.deep.equal([]) 48 | }) 49 | }) 50 | 51 | describe('given a required bool', () => { 52 | it('generates a bool', () => { 53 | const propTypes = { myBool: PropTypes.bool.isRequired } 54 | ComponentAsClass.propTypes = propTypes 55 | ComponentAsFunction.propTypes = propTypes 56 | 57 | const expected = { myBool: true } 58 | 59 | generateProps(propTypes).should.deep.equal(expected) 60 | generateProps({ propTypes }).should.deep.equal(expected) 61 | generateProps(ComponentAsClass).should.deep.equal(expected) 62 | generateProps(ComponentAsFunction).should.deep.equal(expected) 63 | generateProps(propTypes.myBool).should.equal(true) 64 | }) 65 | }) 66 | 67 | describe('given a required func', () => { 68 | it('generates a func', () => { 69 | const propTypes = { myFunc: PropTypes.func.isRequired } 70 | ComponentAsClass.propTypes = propTypes 71 | ComponentAsFunction.propTypes = propTypes 72 | 73 | generateProps(propTypes).myFunc.should.be.a('function') 74 | generateProps({ propTypes }).myFunc.should.be.a('function') 75 | generateProps(ComponentAsClass).myFunc.should.be.a('function') 76 | generateProps(ComponentAsFunction).myFunc.should.be.a('function') 77 | generateProps(propTypes.myFunc).should.be.a('function') 78 | }) 79 | }) 80 | 81 | describe('given a required number', () => { 82 | it('generates a number', () => { 83 | const propTypes = { myNumber: PropTypes.number.isRequired } 84 | ComponentAsClass.propTypes = propTypes 85 | ComponentAsFunction.propTypes = propTypes 86 | 87 | const expected = { myNumber: 1 } 88 | 89 | generateProps(propTypes).should.deep.equal(expected) 90 | generateProps({ propTypes }).should.deep.equal(expected) 91 | generateProps(ComponentAsClass).should.deep.equal(expected) 92 | generateProps(ComponentAsFunction).should.deep.equal(expected) 93 | generateProps(propTypes.myNumber).should.equal(1) 94 | }) 95 | }) 96 | 97 | describe('given a required object', () => { 98 | it('generates an object', () => { 99 | const propTypes = { myObject: PropTypes.object.isRequired } 100 | ComponentAsClass.propTypes = propTypes 101 | ComponentAsFunction.propTypes = propTypes 102 | 103 | const expected = { myObject: { myObject: 'myObject' } } 104 | 105 | generateProps(propTypes).should.deep.equal(expected) 106 | generateProps({ propTypes }).should.deep.equal(expected) 107 | generateProps(ComponentAsClass).should.deep.equal(expected) 108 | generateProps(ComponentAsFunction).should.deep.equal(expected) 109 | generateProps(propTypes.myObject).should.deep.equal({}) 110 | }) 111 | }) 112 | 113 | describe('given a required string', () => { 114 | it('generates a string', () => { 115 | const propTypes = { myString: PropTypes.string.isRequired } 116 | ComponentAsClass.propTypes = propTypes 117 | ComponentAsFunction.propTypes = propTypes 118 | 119 | const expected = { myString: 'myString' } 120 | 121 | generateProps(propTypes).should.deep.equal(expected) 122 | generateProps({ propTypes }).should.deep.equal(expected) 123 | generateProps(ComponentAsClass).should.deep.equal(expected) 124 | generateProps(ComponentAsFunction).should.deep.equal(expected) 125 | generateProps(propTypes.myString).should.deep.equal('string') 126 | }) 127 | }) 128 | 129 | describe('given a required any', () => { 130 | it('generates an any', () => { 131 | const propTypes = { myAny: PropTypes.any.isRequired } 132 | ComponentAsClass.propTypes = propTypes 133 | ComponentAsFunction.propTypes = propTypes 134 | 135 | const expected = { myAny: 'myAny' } 136 | 137 | generateProps(propTypes).should.deep.equal(expected) 138 | generateProps({ propTypes }).should.deep.equal(expected) 139 | generateProps(ComponentAsClass).should.deep.equal(expected) 140 | generateProps(ComponentAsFunction).should.deep.equal(expected) 141 | generateProps(propTypes.myAny).should.deep.equal('any') 142 | }) 143 | }) 144 | 145 | describe('given a required element', () => { 146 | it('generates a react element', () => { 147 | const propTypes = { myElement: PropTypes.element.isRequired } 148 | ComponentAsClass.propTypes = propTypes 149 | ComponentAsFunction.propTypes = propTypes 150 | 151 | const expected = { myElement: React.createElement('div', 'myElement') } 152 | 153 | generateProps(propTypes).should.deep.equal(expected) 154 | generateProps({ propTypes }).should.deep.equal(expected) 155 | generateProps(ComponentAsClass).should.deep.equal(expected) 156 | generateProps(ComponentAsFunction).should.deep.equal(expected) 157 | generateProps(propTypes.myElement).should.deep.equal(React.createElement('div')) 158 | }) 159 | }) 160 | 161 | describe('given a required node', () => { 162 | it('generates a node', () => { 163 | const propTypes = { myNode: PropTypes.node.isRequired } 164 | ComponentAsClass.propTypes = propTypes 165 | ComponentAsFunction.propTypes = propTypes 166 | 167 | const expected = { myNode: 'myNode' } 168 | 169 | generateProps(propTypes).should.deep.equal(expected) 170 | generateProps({ propTypes }).should.deep.equal(expected) 171 | generateProps(ComponentAsClass).should.deep.equal(expected) 172 | generateProps(ComponentAsFunction).should.deep.equal(expected) 173 | generateProps(propTypes.myNode).should.deep.equal('node') 174 | }) 175 | }) 176 | 177 | describe('given a required symbol', () => { 178 | it('generates a symbol', () => { 179 | if (PropTypes.symbol === undefined) return 180 | 181 | const propTypes = { mySymbol: PropTypes.symbol.isRequired } 182 | ComponentAsClass.propTypes = propTypes 183 | ComponentAsFunction.propTypes = propTypes 184 | 185 | const expected = 'Symbol(mySymbol)' 186 | 187 | generateProps(propTypes).mySymbol.toString().should.equal(expected) 188 | generateProps({ propTypes }).mySymbol.toString().should.equal(expected) 189 | generateProps(ComponentAsClass).mySymbol.toString().should.equal(expected) 190 | generateProps(ComponentAsFunction).mySymbol.toString().should.equal(expected) 191 | generateProps(propTypes.mySymbol).toString().should.equal('Symbol()') 192 | }) 193 | }) 194 | 195 | describe('given a required arrayOf', () => { 196 | describe('required arrays', () => { 197 | it('generates an array of arrays', () => { 198 | const propTypes = { myArrayOfArrays: PropTypes.arrayOf(PropTypes.array.isRequired).isRequired } 199 | ComponentAsClass.propTypes = propTypes 200 | ComponentAsFunction.propTypes = propTypes 201 | 202 | const expected = { myArrayOfArrays: [['myArrayOfArrays']] } 203 | 204 | generateProps(propTypes).should.deep.equal(expected) 205 | generateProps({ propTypes }).should.deep.equal(expected) 206 | generateProps(ComponentAsClass).should.deep.equal(expected) 207 | generateProps(ComponentAsFunction).should.deep.equal(expected) 208 | generateProps(propTypes.myArrayOfArrays).should.deep.equal([[]]) 209 | }) 210 | }) 211 | 212 | describe('required bools', () => { 213 | it('generates an array of bools', () => { 214 | const propTypes = { myArrayOfBools: PropTypes.arrayOf(PropTypes.bool.isRequired).isRequired } 215 | ComponentAsClass.propTypes = propTypes 216 | ComponentAsFunction.propTypes = propTypes 217 | 218 | const expected = { myArrayOfBools: [true] } 219 | 220 | generateProps(propTypes).should.deep.equal(expected) 221 | generateProps({ propTypes }).should.deep.equal(expected) 222 | generateProps(ComponentAsClass).should.deep.equal(expected) 223 | generateProps(ComponentAsFunction).should.deep.equal(expected) 224 | generateProps(propTypes.myArrayOfBools).should.deep.equal([true]) 225 | }) 226 | }) 227 | 228 | describe('required funcs', () => { 229 | it('generates an array of funcs', () => { 230 | const propTypes = { myArrayOfFuncs: PropTypes.arrayOf(PropTypes.func.isRequired).isRequired } 231 | ComponentAsClass.propTypes = propTypes 232 | ComponentAsFunction.propTypes = propTypes 233 | 234 | generateProps(propTypes).myArrayOfFuncs[0].should.be.a('function') 235 | generateProps({ propTypes }).myArrayOfFuncs[0].should.be.a('function') 236 | generateProps(ComponentAsClass).myArrayOfFuncs[0].should.be.a('function') 237 | generateProps(ComponentAsFunction).myArrayOfFuncs[0].should.be.a('function') 238 | generateProps(propTypes.myArrayOfFuncs)[0].should.be.a('function') 239 | }) 240 | }) 241 | 242 | describe('required numbers', () => { 243 | it('generates an array of numbers', () => { 244 | const propTypes = { myArrayOfNumbers: PropTypes.arrayOf(PropTypes.number.isRequired).isRequired } 245 | ComponentAsClass.propTypes = propTypes 246 | ComponentAsFunction.propTypes = propTypes 247 | 248 | const expected = { myArrayOfNumbers: [1] } 249 | 250 | generateProps(propTypes).should.deep.equal(expected) 251 | generateProps({ propTypes }).should.deep.equal(expected) 252 | generateProps(ComponentAsClass).should.deep.equal(expected) 253 | generateProps(ComponentAsFunction).should.deep.equal(expected) 254 | generateProps(propTypes.myArrayOfNumbers).should.deep.equal([1]) 255 | }) 256 | }) 257 | 258 | describe('required objects', () => { 259 | it('generates an array of objects', () => { 260 | const propTypes = { myArrayOfObjects: PropTypes.arrayOf(PropTypes.object.isRequired).isRequired } 261 | ComponentAsClass.propTypes = propTypes 262 | ComponentAsFunction.propTypes = propTypes 263 | 264 | const expected = { myArrayOfObjects: [{ myArrayOfObjects: 'myArrayOfObjects' }] } 265 | 266 | generateProps(propTypes).should.deep.equal(expected) 267 | generateProps({ propTypes }).should.deep.equal(expected) 268 | generateProps(ComponentAsClass).should.deep.equal(expected) 269 | generateProps(ComponentAsFunction).should.deep.equal(expected) 270 | generateProps(propTypes.myArrayOfObjects).should.deep.equal([{}]) 271 | }) 272 | }) 273 | 274 | describe('required strings', () => { 275 | it('generates an array of strings', () => { 276 | const propTypes = { myArrayOfStrings: PropTypes.arrayOf(PropTypes.string.isRequired).isRequired } 277 | ComponentAsClass.propTypes = propTypes 278 | ComponentAsFunction.propTypes = propTypes 279 | 280 | const expected = { myArrayOfStrings: ['myArrayOfStrings'] } 281 | 282 | generateProps(propTypes).should.deep.equal(expected) 283 | generateProps({ propTypes }).should.deep.equal(expected) 284 | generateProps(ComponentAsClass).should.deep.equal(expected) 285 | generateProps(ComponentAsFunction).should.deep.equal(expected) 286 | generateProps(propTypes.myArrayOfStrings).should.deep.equal(['string']) 287 | }) 288 | }) 289 | 290 | describe('required anys', () => { 291 | it('generates an array of anys', () => { 292 | const propTypes = { myArrayOfAnys: PropTypes.arrayOf(PropTypes.any.isRequired).isRequired } 293 | ComponentAsClass.propTypes = propTypes 294 | ComponentAsFunction.propTypes = propTypes 295 | 296 | const expected = { myArrayOfAnys: ['myArrayOfAnys'] } 297 | 298 | generateProps(propTypes).should.deep.equal(expected) 299 | generateProps({ propTypes }).should.deep.equal(expected) 300 | generateProps(ComponentAsClass).should.deep.equal(expected) 301 | generateProps(ComponentAsFunction).should.deep.equal(expected) 302 | generateProps(propTypes.myArrayOfAnys).should.deep.equal(['any']) 303 | }) 304 | }) 305 | }) 306 | 307 | describe('given a required instanceOf(MyClass)', () => { 308 | it('generates a an instance of MyClass', () => { 309 | class MyClass {} 310 | 311 | const propTypes = { myInstance: PropTypes.instanceOf(MyClass).isRequired } 312 | ComponentAsClass.propTypes = propTypes 313 | ComponentAsFunction.propTypes = propTypes 314 | 315 | const expected = { myInstance: new MyClass() } 316 | 317 | generateProps(propTypes).should.deep.equal(expected) 318 | generateProps({ propTypes }).should.deep.equal(expected) 319 | generateProps(ComponentAsClass).should.deep.equal(expected) 320 | generateProps(ComponentAsFunction).should.deep.equal(expected) 321 | generateProps(propTypes.myInstance).should.deep.equal(new MyClass()) 322 | }) 323 | }) 324 | 325 | describe('given a required objectOf', () => { 326 | describe('required arrays', () => { 327 | it('generates an array of arrays', () => { 328 | const propTypes = { myObjectOfArrays: PropTypes.objectOf(PropTypes.array.isRequired).isRequired } 329 | ComponentAsClass.propTypes = propTypes 330 | ComponentAsFunction.propTypes = propTypes 331 | 332 | const expected = { myObjectOfArrays: { key: ['myObjectOfArrays'] } } 333 | 334 | generateProps(propTypes).should.deep.equal(expected) 335 | generateProps({ propTypes }).should.deep.equal(expected) 336 | generateProps(ComponentAsClass).should.deep.equal(expected) 337 | generateProps(ComponentAsFunction).should.deep.equal(expected) 338 | generateProps(propTypes.myObjectOfArrays).should.deep.equal({ key: [] }) 339 | }) 340 | }) 341 | 342 | describe('required bools', () => { 343 | it('generates an array of bools', () => { 344 | const propTypes = { myObjectOfBools: PropTypes.objectOf(PropTypes.bool.isRequired).isRequired } 345 | ComponentAsClass.propTypes = propTypes 346 | ComponentAsFunction.propTypes = propTypes 347 | 348 | const expected = { myObjectOfBools: { key: true } } 349 | 350 | generateProps(propTypes).should.deep.equal(expected) 351 | generateProps({ propTypes }).should.deep.equal(expected) 352 | generateProps(ComponentAsClass).should.deep.equal(expected) 353 | generateProps(ComponentAsFunction).should.deep.equal(expected) 354 | generateProps(propTypes.myObjectOfBools).should.deep.equal({ key: true }) 355 | }) 356 | }) 357 | 358 | describe('required funcs', () => { 359 | it('generates an array of funcs', () => { 360 | const propTypes = { myObjectOfFuncs: PropTypes.objectOf(PropTypes.func.isRequired).isRequired } 361 | ComponentAsClass.propTypes = propTypes 362 | ComponentAsFunction.propTypes = propTypes 363 | 364 | generateProps(propTypes).myObjectOfFuncs.key.should.be.a('function') 365 | generateProps({ propTypes }).myObjectOfFuncs.key.should.be.a('function') 366 | generateProps(ComponentAsClass).myObjectOfFuncs.key.should.be.a('function') 367 | generateProps(ComponentAsFunction).myObjectOfFuncs.key.should.be.a('function') 368 | generateProps(propTypes.myObjectOfFuncs).key.should.be.a('function') 369 | }) 370 | }) 371 | 372 | describe('required numbers', () => { 373 | it('generates an array of numbers', () => { 374 | const propTypes = { myObjectOfNumbers: PropTypes.objectOf(PropTypes.number.isRequired).isRequired } 375 | ComponentAsClass.propTypes = propTypes 376 | ComponentAsFunction.propTypes = propTypes 377 | 378 | const expected = { myObjectOfNumbers: { key: 1 } } 379 | 380 | generateProps(propTypes).should.deep.equal(expected) 381 | generateProps({ propTypes }).should.deep.equal(expected) 382 | generateProps(ComponentAsClass).should.deep.equal(expected) 383 | generateProps(ComponentAsFunction).should.deep.equal(expected) 384 | generateProps(propTypes.myObjectOfNumbers).should.deep.equal({ key: 1 }) 385 | }) 386 | }) 387 | 388 | describe('required objects', () => { 389 | it('generates an array of objects', () => { 390 | const propTypes = { myObjectOfObjects: PropTypes.objectOf(PropTypes.object.isRequired).isRequired } 391 | ComponentAsClass.propTypes = propTypes 392 | ComponentAsFunction.propTypes = propTypes 393 | 394 | const expected = { myObjectOfObjects: { key: { myObjectOfObjects: 'myObjectOfObjects' } } } 395 | 396 | generateProps(propTypes).should.deep.equal(expected) 397 | generateProps({ propTypes }).should.deep.equal(expected) 398 | generateProps(ComponentAsClass).should.deep.equal(expected) 399 | generateProps(ComponentAsFunction).should.deep.equal(expected) 400 | generateProps(propTypes.myObjectOfObjects).should.deep.equal({ key: {} }) 401 | }) 402 | }) 403 | 404 | describe('required strings', () => { 405 | it('generates an array of strings', () => { 406 | const propTypes = { myObjectOfStrings: PropTypes.objectOf(PropTypes.string.isRequired).isRequired } 407 | ComponentAsClass.propTypes = propTypes 408 | ComponentAsFunction.propTypes = propTypes 409 | 410 | const expected = { myObjectOfStrings: { key: 'myObjectOfStrings' } } 411 | 412 | generateProps(propTypes).should.deep.equal(expected) 413 | generateProps({ propTypes }).should.deep.equal(expected) 414 | generateProps(ComponentAsClass).should.deep.equal(expected) 415 | generateProps(ComponentAsFunction).should.deep.equal(expected) 416 | generateProps(propTypes.myObjectOfStrings).should.deep.equal({ key: 'string' }) 417 | }) 418 | }) 419 | 420 | describe('required anys', () => { 421 | it('generates an array of anys', () => { 422 | const propTypes = { myObjectOfAnys: PropTypes.objectOf(PropTypes.any.isRequired).isRequired } 423 | ComponentAsClass.propTypes = propTypes 424 | ComponentAsFunction.propTypes = propTypes 425 | 426 | const expected = { myObjectOfAnys: { key: 'myObjectOfAnys' } } 427 | 428 | generateProps(propTypes).should.deep.equal(expected) 429 | generateProps({ propTypes }).should.deep.equal(expected) 430 | generateProps(ComponentAsClass).should.deep.equal(expected) 431 | generateProps(ComponentAsFunction).should.deep.equal(expected) 432 | generateProps(propTypes.myObjectOfAnys).should.deep.equal({ key: 'any' }) 433 | }) 434 | }) 435 | }) 436 | 437 | describe('given a required oneOf', () => { 438 | describe('foo or bar', () => { 439 | it('generates the first option, foo', () => { 440 | const propTypes = { myFooOrBar: PropTypes.oneOf(['foo', 'bar']).isRequired } 441 | ComponentAsClass.propTypes = propTypes 442 | ComponentAsFunction.propTypes = propTypes 443 | 444 | const expected = 'foo' 445 | 446 | generateProps(propTypes).myFooOrBar.should.equal(expected) 447 | generateProps({ propTypes }).myFooOrBar.should.equal(expected) 448 | generateProps(ComponentAsClass).myFooOrBar.should.equal(expected) 449 | generateProps(ComponentAsFunction).myFooOrBar.should.equal(expected) 450 | generateProps(propTypes.myFooOrBar).should.equal(expected) 451 | }) 452 | }) 453 | }) 454 | 455 | describe('given a required oneOfType', () => { 456 | describe('bool or', () => { 457 | describe('number', () => { 458 | it('generates the first option, a bool', () => { 459 | const propTypes = { myBoolOrNumber: PropTypes.oneOfType([PropTypes.bool, PropTypes.number]).isRequired } 460 | ComponentAsClass.propTypes = propTypes 461 | ComponentAsFunction.propTypes = propTypes 462 | 463 | const expected = true 464 | 465 | generateProps(propTypes).myBoolOrNumber.should.equal(expected) 466 | generateProps({ propTypes }).myBoolOrNumber.should.equal(expected) 467 | generateProps(ComponentAsClass).myBoolOrNumber.should.equal(expected) 468 | generateProps(ComponentAsFunction).myBoolOrNumber.should.equal(expected) 469 | }) 470 | }) 471 | }) 472 | }) 473 | 474 | describe('given a required shape', () => { 475 | describe('with a required array value', () => { 476 | it('generates an object with an array value', () => { 477 | const propTypes = { myShape: PropTypes.shape({ myArray: PropTypes.array.isRequired }).isRequired } 478 | ComponentAsClass.propTypes = propTypes 479 | ComponentAsFunction.propTypes = propTypes 480 | 481 | const expected = { myShape: { myArray: ['myArray'] } } 482 | 483 | generateProps(propTypes).should.deep.equal(expected) 484 | generateProps({ propTypes }).should.deep.equal(expected) 485 | generateProps(ComponentAsClass).should.deep.equal(expected) 486 | generateProps(ComponentAsFunction).should.deep.equal(expected) 487 | generateProps(propTypes.myShape).should.deep.equal(expected.myShape) 488 | }) 489 | 490 | describe('and a required bool', () => { 491 | it('generates an object with an array value and a bool value', () => { 492 | const propTypes = { 493 | myShape: PropTypes.shape({ 494 | myArray: PropTypes.array.isRequired, 495 | myBool: PropTypes.bool.isRequired 496 | }).isRequired 497 | } 498 | ComponentAsClass.propTypes = propTypes 499 | ComponentAsFunction.propTypes = propTypes 500 | 501 | const expected = { myShape: { myArray: ['myArray'], myBool: true } } 502 | 503 | generateProps(propTypes).should.deep.equal(expected) 504 | generateProps({ propTypes }).should.deep.equal(expected) 505 | generateProps(ComponentAsClass).should.deep.equal(expected) 506 | generateProps(ComponentAsFunction).should.deep.equal(expected) 507 | generateProps(propTypes.myShape).should.deep.equal(expected.myShape) 508 | }) 509 | }) 510 | 511 | describe('and a required shape', () => { 512 | describe('with a required number', () => { 513 | it('generates an object with an array value and a sub-object with bool value', () => { 514 | const propTypes = { 515 | myShape: PropTypes.shape({ 516 | myArray: PropTypes.array.isRequired, 517 | mySubShape: PropTypes.shape({ 518 | myNumber: PropTypes.number.isRequired 519 | }).isRequired 520 | }).isRequired 521 | } 522 | ComponentAsClass.propTypes = propTypes 523 | ComponentAsFunction.propTypes = propTypes 524 | 525 | const expected = { myShape: { myArray: ['myArray'], mySubShape: { myNumber: 1 } } } 526 | 527 | generateProps(propTypes).should.deep.equal(expected) 528 | generateProps({ propTypes }).should.deep.equal(expected) 529 | generateProps(ComponentAsClass).should.deep.equal(expected) 530 | generateProps(ComponentAsFunction).should.deep.equal(expected) 531 | generateProps(propTypes.myShape).should.deep.equal(expected.myShape) 532 | }) 533 | }) 534 | }) 535 | }) 536 | }) 537 | 538 | describe('given a required exact', () => { 539 | describe('with a required array value', () => { 540 | it('generates an object with an array value', () => { 541 | if (!PropTypes.exact) return 542 | 543 | const propTypes = { myExact: PropTypes.exact({ myArray: PropTypes.array.isRequired }).isRequired } 544 | ComponentAsClass.propTypes = propTypes 545 | ComponentAsFunction.propTypes = propTypes 546 | 547 | const expected = { myExact: { myArray: ['myArray'] } } 548 | 549 | generateProps(propTypes).should.deep.equal(expected) 550 | generateProps({ propTypes }).should.deep.equal(expected) 551 | generateProps(ComponentAsClass).should.deep.equal(expected) 552 | generateProps(ComponentAsFunction).should.deep.equal(expected) 553 | generateProps(propTypes.myExact).should.deep.equal(expected.myExact) 554 | }) 555 | 556 | describe('and a required bool', () => { 557 | it('generates an object with an array value and a bool value', () => { 558 | if (!PropTypes.exact) return 559 | 560 | const propTypes = { 561 | myExact: PropTypes.exact({ 562 | myArray: PropTypes.array.isRequired, 563 | myBool: PropTypes.bool.isRequired 564 | }).isRequired 565 | } 566 | ComponentAsClass.propTypes = propTypes 567 | ComponentAsFunction.propTypes = propTypes 568 | 569 | const expected = { myExact: { myArray: ['myArray'], myBool: true } } 570 | 571 | generateProps(propTypes).should.deep.equal(expected) 572 | generateProps({ propTypes }).should.deep.equal(expected) 573 | generateProps(ComponentAsClass).should.deep.equal(expected) 574 | generateProps(ComponentAsFunction).should.deep.equal(expected) 575 | generateProps(propTypes.myExact).should.deep.equal(expected.myExact) 576 | }) 577 | }) 578 | 579 | describe('and a required shape', () => { 580 | describe('with a required number', () => { 581 | it('generates an object with an array value and a sub-object with bool value', () => { 582 | if (!PropTypes.exact) return 583 | 584 | const propTypes = { 585 | myExact: PropTypes.exact({ 586 | myArray: PropTypes.array.isRequired, 587 | mySubShape: PropTypes.shape({ 588 | myNumber: PropTypes.number.isRequired 589 | }).isRequired 590 | }).isRequired 591 | } 592 | ComponentAsClass.propTypes = propTypes 593 | ComponentAsFunction.propTypes = propTypes 594 | 595 | const expected = { myExact: { myArray: ['myArray'], mySubShape: { myNumber: 1 } } } 596 | 597 | generateProps(propTypes).should.deep.equal(expected) 598 | generateProps({ propTypes }).should.deep.equal(expected) 599 | generateProps(ComponentAsClass).should.deep.equal(expected) 600 | generateProps(ComponentAsFunction).should.deep.equal(expected) 601 | generateProps(propTypes.myExact).should.deep.equal(expected.myExact) 602 | }) 603 | }) 604 | }) 605 | }) 606 | }) 607 | }) 608 | 609 | describe('generateProps(opts)', () => { 610 | const propTypes = { 611 | optionalArray: PropTypes.array, 612 | requiredArray: PropTypes.array.isRequired, 613 | optionalBool: PropTypes.bool, 614 | requiredBool: PropTypes.bool.isRequired, 615 | optionalNumber: PropTypes.number, 616 | requiredNumber: PropTypes.number.isRequired, 617 | optionalObject: PropTypes.object, 618 | requiredObject: PropTypes.object.isRequired, 619 | optionalString: PropTypes.string, 620 | requiredString: PropTypes.string.isRequired, 621 | optionalAny: PropTypes.any, 622 | requiredAny: PropTypes.any.isRequired, 623 | optionalElement: PropTypes.element, 624 | requiredElement: PropTypes.element.isRequired, 625 | optionalNode: PropTypes.node, 626 | requiredNode: PropTypes.node.isRequired 627 | } 628 | 629 | const required = { 630 | requiredArray: ['requiredArray'], 631 | requiredBool: true, 632 | requiredNumber: 1, 633 | requiredObject: { requiredObject: 'requiredObject' }, 634 | requiredString: 'requiredString', 635 | requiredAny: 'requiredAny', 636 | requiredElement: React.createElement('div', 'requiredElement'), 637 | requiredNode: 'requiredNode' 638 | } 639 | 640 | const optional = { 641 | optionalArray: ['optionalArray'], 642 | optionalBool: true, 643 | optionalNumber: 1, 644 | optionalObject: { optionalObject: 'optionalObject' }, 645 | optionalString: 'optionalString', 646 | optionalAny: 'optionalAny', 647 | optionalElement: React.createElement('div', 'optionalElement'), 648 | optionalNode: 'optionalNode' 649 | } 650 | 651 | describe('given opts = ', () => { 652 | describe('undefined', () => { 653 | it('generates required props only by default', () => { 654 | const expected = required 655 | generateProps(propTypes).should.deep.equal(expected) 656 | }) 657 | }) 658 | 659 | describe('{ required: true }', () => { 660 | it('generates required props', () => { 661 | const expected = required 662 | generateProps(propTypes, { required: true }).should.deep.equal(expected) 663 | }) 664 | }) 665 | 666 | describe('{ required: false }', () => { 667 | it('does not generate required props', () => { 668 | const expected = {} 669 | generateProps(propTypes, { required: false }).should.deep.equal(expected) 670 | }) 671 | }) 672 | 673 | describe('{ optional: true }', () => { 674 | it('generates optional props', () => { 675 | const expected = Object.assign({}, required, optional) 676 | generateProps(propTypes, { optional: true }).should.deep.equal(expected) 677 | }) 678 | 679 | it('generates optional props in nested objects', () => { 680 | const expected = Object.assign({}, required, optional) 681 | generateProps({ wrappingShape: PropTypes.shape(propTypes) }, { optional: true }) 682 | .should.deep.equal({ wrappingShape: expected }) 683 | }) 684 | }) 685 | 686 | describe('{ optional: false }', () => { 687 | it('does not generate optional props', () => { 688 | const expected = required 689 | generateProps(propTypes, { optional: false }).should.deep.equal(expected) 690 | }) 691 | }) 692 | }) 693 | 694 | describe('given opts.generators = ', () => { 695 | describe('with bool override', () => { 696 | it('generates a custom bool', () => { 697 | const opts = { generators: { bool: () => false } } 698 | generateProps(propTypes, opts).requiredBool.should.be.false 699 | }) 700 | }) 701 | }) 702 | }) 703 | 704 | describe('PropTypes.checkPropTypes', () => { 705 | before(() => { 706 | generateProps.init() 707 | global._errorBackup = global.console.error 708 | global.console.error = err => { throw err } 709 | }) 710 | after(() => { 711 | global.console.error = global._errorBackup 712 | }) 713 | 714 | it('handles a generated shape', () => { 715 | const shape = PropTypes.shape({ myAny: PropTypes.any.isRequired }).isRequired 716 | const props = generateProps(shape) 717 | const fn = () => PropTypes.checkPropTypes 718 | ? PropTypes.checkPropTypes(shape, props) 719 | : shape(props) 720 | fn.should.not.throw() 721 | }) 722 | }) 723 | --------------------------------------------------------------------------------