GithubHelp home page GithubHelp logo

markalfred / react-generate-props Goto Github PK

View Code? Open in Web Editor NEW
23.0 2.0 4.0 561 KB

Generate default props based on your React component's PropTypes

License: MIT License

JavaScript 100.00%
react jest enzyme test props proptypes

react-generate-props's Introduction

react-generate-props

Generate default props based on your React component's PropTypes

Build Status Coverage Status

generateProps({ name: PropTypes.string, number: PropTypes.number })
// => { name: 'name', number: 1 }

Installation

$ npm install --save-dev react-generate-props

Usage

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

// test-helper.js

import { init } from 'react-generate-props'
init()

Define your component's propTypes.

const Counter = ({ count }) => <div>{count}</div>
Counter.propTypes = { count: PropTypes.number.isRequired }
export default Counter

Pass the component to this library. It will generate reasonable props based on the defined types.

import generateProps from 'react-generate-props'
import Counter from './counter'
generateProps(Counter)
// => { count: 1 }

Use these default props to reduce boilerplate and prop type validation errors in your tests! ๐ŸŽ‰

Example

A more in-depth example.

// component.jsx

class Component extends React.Component {
  static propTypes = {
    title: PropTypes.string.isRequired,
    followers: PropTypes.number.isRequired,
    user: PropTypes.shape({
      loggedIn: PropTypes.bool.isRequired,
      name: PropTypes.string.isRequired
    }).isRequired
  }

  render() {
    <div>
      <h1>{this.props.title}</h1>
      <small>{this.props.followers}</small>
      {this.props.user.loggedIn && <p>Hello, {this.props.user.name}.</p>}
    </div>
  }
}

export default Component
// component-test.js

import generateProps from 'react-generate-props'
import Component from './component.jsx'

const props = generateProps(Component)
// => { title: 'title', followers: 1, user: { loggedIn: true, name: 'name' } }

render(<Component {...props} />)
/* =>
<div>
  <h1>title</h1>
  <small>1</small>
  <p>Hello, name.</p>
</div>
*/

API

The library takes two arguments.

generateProps(schema, opts)

schema: An Object, Function, or Class containing a PropTypes definition, or a single PropType. All of the following are valid:

Plain Object

const Counter = { count: PropTypes.number.isRequired }

Plain Object with a propTypes key

const Counter = { propTypes: { count: PropTypes.number.isRequired } }

Functional Component

const Counter = ({ counter }) => {/* ... */}
Counter.propTypes = { count: PropTypes.number.isRequired }

React.Component Class

class Counter extends React.Component {
  static propTypes = { count: PropTypes.number.isRequired }
}

Single PropType

const Counter = PropTypes.shape({ count: PropTypes.number.isRequired }).isRequired

In each of these cases, the effect would be the same

generateProps(Counter)
// => { count: 1 }

opts: An Object which may contain the following:

{
  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 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

const propTypes = {
  name: PropTypes.string.isRequired,
  loggedIn: PropTypes.bool,
  userType: PropTypes.oneOf(['admin', 'user']).isRequired
}

generateProps(propTypes)
// => { name: 'string', userType: 'admin' }

generateProps(propTypes, { optional: true })
// => { name: 'string', loggedIn: true, userType: 'admin' }

generateProps(propTypes, {
  optional: true,
  generators: {
    string: (propName) => 'Alice',
    bool: (propName) => propName === 'loggedIn',
    oneOf: (propName, values) => values[values.length - 1]
  }
})
// => { name: 'Alice', loggedIn: true, userType: 'user' }

react-generate-props's People

Contributors

dependabot-preview[bot] avatar dependabot[bot] avatar markalfred avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar

react-generate-props's Issues

Allow for Generation of Custom Prop Types

Airbnb created a number of custom prop types (https://github.com/airbnb/prop-types), and we should allow for the generation of these (and any other) custom types. For instance, using their empty validator:

const customGenerators =  { empty: () => null }

generateProps.init({ generators: customGenerators })
// Note: init doesn't currently take any options

import { empty } from 'airbnb-prop-types'
Component.propTypes = { alwaysEmpty: empty.isRequired }

generateProps(Component)
// => Current: {}
// => Proposed: { alwaysEmpty: null }

A real world example that I'd like right now:

generateProps.init({ generators: { dateString: () => moment().format() } })

import { dateString } from 'lib/custom-prop-types'
Component.propTypes = { insertedAt: dateString.isRequired }

generateProps(Component)
// => Current: {}
// => Proposed: { insertedAt: '2019-06-12T17:23:27-04:00' }

Generators could receive prop name as argument

When providing custom generators, there is no way to distinguish which propType in particular it is being generated in each execution, and so if there are multiple properties of the same kind that need to be generated differently (for example two numbers where one of them is an ID while the other is a decimal value) it is not possible to do it.
Could it be possible to provide the propType name to the generator function as a second argument?

Return more information in generator callbacks

I would love to request just a bit more information when a generator is called so that the function can have some context around the property being generated.

For instance, one of the use cases I have is that I want to generate function props for our storybook callbacks using the action method supplied by Storybook. I would love to have the value of this action represent the property name. E.g., if I have a prop called onBlur, I would like to generate a function prop that would look like: action('onBlur').

To be more clear, ultimately it would be great to do this:

generateProps(..., {
  generators: {
    func: (propName) => { action.bind(this, propName); },
  },
});

I think this would open up a lot of functionality for the other generators, too :)

{ optional: true } doesn't generate deeply-nested optional props in shapes

shape = {
  shapeProp: PropTypes.shape({
    optionalProp: PropTypes.any,
    requiredProp: PropTypes.any.isRequired
  })
}

generateProps(shape, { optional: true })

// Expected:
{ shapeProp: { optionalProp: 'any', requiredProp: 'any' } }

// Actual: 
{ shapeProp: { requiredProp: 'any' } }

Note to self: likely that shape generator isn't forwarding opts to recursive generateProps calls.

Use reducer initialState to generate props

We're using react-redux and would like to use our reducer's initialState for generated props.

I'm thinking if the shape generator took the prop name or ideally a path, we could decide whether to return initialState from the reducer or to recursively call generateProps as the library normally would.

Interested in hearing if this would be a welcomed PR. Or maybe it's possible today and I just didn't catch it.

High order component

When I have a high order component that wraps the Component I want to test, I get an error when generating the props.

 generateProps expected a propType object or a React Component

const Dropdown = WithToggle({ toggledOn, show, hide }) => 
<div>whatever</div>

const props = generateProps(Dropdown);

Wrapping of complex types seem to be broken

I cannot seem to get any oneOfType, oneOf, etc complex propTypes to be correctly wrapped. The wrapped function always seems to be returning undefined for its type, and therefore never gets a generated value.

Currently using prop-types ^15.5.8.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.