Skip to content

Commit

Permalink
Require calling .init() at start of test suite
Browse files Browse the repository at this point in the history
  • Loading branch information
markalfred committed Apr 27, 2018
1 parent 66b1493 commit fcf9c8e
Show file tree
Hide file tree
Showing 4 changed files with 71 additions and 29 deletions.
7 changes: 5 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,19 @@
Changes that have landed in master but are not yet released.
</summary>
Breaking Changes:

* Default generators now produce values that match their `propName`.
```js
generate({ foo: PropType.string, bar: PropTypes.object })
// Old: => { foo: 'string', bar: {} }
// New: => { foo: 'foo', bar: { bar: 'bar' } }
```

* Generator callbacks now receive `propName` as their first argument, and their definitions' argument as the second.
* `generateProps.init()` *must* be called prior to components being imported or `generateProps()` being called.

Non-breaking Changes:

* Generator callbacks now receive the `propName` as an argument.
</details>

Expand Down
42 changes: 27 additions & 15 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,15 @@ $ npm install --save-dev react-generate-props

## Usage

**Important:**
Initialize the library *before* importing any components into your test suite.

```js
// test-helper.js

import { init } from 'react-generate-props'
```

Define your component's propTypes.

```jsx
Expand Down Expand Up @@ -114,25 +123,28 @@ generateProps(Counter)
{
required: true,
// default: true. When true, props marked as .isRequired will be generated.

optional: false,
// default: false. When true, props *not* marked as .isRequired will be generated.

generators: {
// Can be used to override this lib's default generators.
// Each key is a prop type, each value is a function,
// each function receives its definition's arguments.
bool: () => false,
function: () => spy(),
instanceOf: (klass) => new klass(),
oneOf: (values) => values[values.length - 1]
// Each key is a prop type, each value is a function.
// Each function receives the propName as its first argument,
// followed by that prop type's argument, if it takes one.

bool: (propName) => false,
function: (propName) => spy(),
number: (propName) => propName.length,
instanceOf: (propName, klass) => new klass(),
oneOf: (propName, values) => values[values.length - 1]
}
}
```

## One More Example

```jsx
```js
const propTypes = {
name: PropTypes.string.isRequired,
loggedIn: PropTypes.bool,
Expand All @@ -145,13 +157,13 @@ generateProps(propTypes)
generateProps(propTypes, { optional: true })
// => { name: 'string', loggedIn: true, userType: 'admin' }

generateProps(propTypes, {
generateProps(propTypes, {
optional: true,
generators: {
string: () => 'Alice',
bool: () => false,
oneOf: (values) => values[values.length - 1]
generators: {
string: (propName) => 'Alice',
bool: (propName) => propName === 'loggedIn',
oneOf: (propName, values) => values[values.length - 1]
}
})
// => { name: 'Alice', loggedIn: false, userType: 'user' }
// => { name: 'Alice', loggedIn: true, userType: 'user' }
```
20 changes: 17 additions & 3 deletions src/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@ const React = require('react')
const PropTypes = require('./prop-types')

let options
let initialized = false;

const wrapPropTypes = () => {
initialized = true;
// Adds a .type key which allows the type to be derived during the
// evaluation process. This is necessary for complex types which
// return the result of a generator function, leaving no way to
Expand All @@ -27,8 +29,6 @@ const wrapPropTypes = () => {
})
}

wrapPropTypes()

const GENERATORS = {
// Simple types
array: (propName) => [propName],
Expand Down Expand Up @@ -59,7 +59,15 @@ const shouldGenerate = (propType) => {
)
}

const generateOneProp = (propType, propName, wrapInArray=true) => {
const initError = new Error(
'generateProps.init() must be called at the beginning of your test suite'
)

const generateOneProp = (propType, propName, wrapInArray = true) => {
if (propType.type === undefined && initialized === false) {
throw initError
}

const generate = options.generators[propType.type].bind(this, propName)
const arg = propType.arg
if (generate) {
Expand All @@ -82,6 +90,10 @@ const forceGenerateOneProp = (propType, propName) => {
}

const generateProps = (arg, opts) => {
if (initialized === false) {
throw initError
}

options = _.defaults({}, opts, { required: true, optional: false })
if (opts && opts.generators) {
options.generators = _.defaults({}, opts.generators, GENERATORS)
Expand All @@ -108,4 +120,6 @@ const generateProps = (arg, opts) => {
.value()
}

Object.assign(generateProps, { init: wrapPropTypes })

module.exports = generateProps
31 changes: 22 additions & 9 deletions test/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,32 @@ const ComponentAsFunction = () => 'component'

const generateProps = require('../src/main')

describe('generateProps', () => {
describe('given a bad argument', () => {
describe('generateProps (incorrect)', () => {
describe('when called before generateProps.init() was called', () => {
it('throws an error', () => {
// TODO: Add plain objects, or things like "React" to this.
const badArgs = [null, undefined, 0, 1, -1, false, true, [], NaN, '', 'string']

for (let arg of badArgs) {
let fnCall = () => generateProps(arg)
fnCall.should.throw(TypeError, 'generateProps expected a propType object or a React Component')
}
const fnCall = () => generateProps({})
fnCall.should.throw(Error, 'generateProps.init() must be called at the beginning of your test suite')
})
})

describe('given the bad argument', () => {
// TODO: Add plain objects, or things like "React" to this.
const badArgs = [null, undefined, 0, 1, -1, false, true, [], NaN, '', 'string']

for (let arg of badArgs) {
describe('(' + arg + ')', () => {
it('throws an error', () => {
generateProps.init()
let fnCall = () => generateProps(arg)
fnCall.should.throw(TypeError, 'generateProps expected a propType object or a React Component')
})
})
}
})
})

describe('generateProps (correct)', () => {
before(() => { generateProps.init() })
describe('given a required array', () => {
it('generates an array', () => {
const propTypes = { myArray: PropTypes.array.isRequired }
Expand Down

0 comments on commit fcf9c8e

Please sign in to comment.