Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/kpfromer/react-component-setup

A simple npm package to help test react components
https://github.com/kpfromer/react-component-setup

chai enzyme javascript jest mocha react reactjs testing testing-tools

Last synced: 26 days ago
JSON representation

A simple npm package to help test react components

Awesome Lists containing this project

README

        

# react-component-setup

[![Build Status](https://travis-ci.org/kpfromer/react-component-setup.svg?branch=master)](https://travis-ci.org/kpfromer/react-component-setup)
[![Coveralls github](https://img.shields.io/coveralls/github/kpfromer/react-component-setup.svg)](https://coveralls.io/github/kpfromer/react-component-setup?branch=master)

## Description

This package reduces component testing boilerplate code by providing a handy `mount` and `shallow` functions using enzyme.

## Installation

Run the following command:

`npm install --save-dev react-component-setup`

## Why?

I read an [article by Tomasz Bak](https://medium.com/selleo/testing-react-components-best-practices-2f77ac302d12)
describing some best react practices. One practice described that you should use a setup() instead
of a beforeEach (in jest) for your code to be more readable. I liked this practice and incorporated into one of my projects.
However, immediately, it became tedious to write a setup() for every component; thus I created `react-component-setup`.

## Usage

First, install the [required packages](#requirements)!

Import the package:

```javascript
import { SetupComponent } from 'react-component-setup';
```

Then run the `SetupComponent` initially in your Reactjs test file to generate
default properties and automatic element fetching.

`SetupComponent` will return an object with `mount` and `shallow` functions.
Each of which corresponds with their respective enzyme call. Example return:

```javascript
{
mount: [mount Function],
shalllow: [shallow Function]
}
```

```javascript
import React, { Component } from 'react';
import { SetupComponent } from 'react-component-setup';

class CoolReactComponent extends Component {
render() {
return (


Hello, world!


I am a cool react component



);
}
}

const { shallow: setup } = SetupComponent({ component: CoolReactComponent }); // Component to construct
// I could have used mount instead of shallow if needed
```

Note that the `{ shallow: setup } = ...` is just a [javascript object deconstructor](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment).

Then add a simple test using whatever testing framework you want, in this case, I used jest.

```javascript
describe('CoolReactComponent', () => {
it('should render a cool component', () => {
const { wrapper } = setup();
expect(wrapper.exists()).toBe(true);
});
});
```

Both `mount` and `shallow` return an object of `wrapper` which is the enzyme shallow container of the constructed component.

#### Defining properties for the component

Most components have properties. In order to supply your properties to the component provide an object with
the properties value. Example:

```javascript
import React, { Component } from 'react';
import { SetupComponent } from 'react-component-setup';

class NameDisplayer extends Component {
render() {
return (

First name: {this.props.firstName}. Last name: {this.props.lastName}.


);
}
}

const { shallow: setup } = SetupComponent({ component: NameDisplayer });

setup({
firstName: 'Mark'
lastName: 'Johnson'
}); // returns component like

First name: Mark. Last name: Johnson.


```

#### Find an element automatically

If you want to find an element automatically (you test that element quite often)
You can add it to the `SetupComponent`'s elementsToFind list.
All elementsToFind does is it returns the `wrapper.find()` of the `query` using the `name`.
Example:

```javascript
import React, { Component } from 'react';
import { SetupComponent } from 'react-component-setup';

class CoolReactComponent extends Component {
render() {
return (


Hello, world!


I am a cool react component



);
}
}

const { shallow: setup } = SetupComponent({
component: CoolReactComponent,
elementsToFind: [ // the elements that should be found automatically
{
name: 'coolParagraph',
query: '.cool-paragraph'
}
]
});

describe('CoolReactComponent', () => {
it('should render a chill paragraph', () => {
const { coolParagraph } = setup(); // coolParagraph is from the name in the list
expect(coolParagraph.html()).toMatchSnapshot();
});
});
```

#### Refreshing elements in `elementsToFind`

I have had trouble using elementsToFind with inputs when simulating a change.
Simulating a change on input causes any variable reference to the element to become stale, thus the variable is useless since you will need to reuse the `wrapper.find` method.
See more [here](https://github.com/airbnb/enzyme/issues/76#issuecomment-388112899).
To fix this issue a newly created `refresh` method has been added to automatically refind the element for you.

Basic Example:

```javascript
const { wrapper, coolCustomElementToFind, refresh } = setup(); // setup is the the shallow or mount function created from SetupComponent

const refreshedCustomElement = refresh(coolCustomElementToFind); // refresh does not change coolCustomElementToFind

```

Full Example:

```javascript
import React, { Component } from 'react';
import { SetupComponent } from 'react-component-setup';

class InputComponent extends Component {

state = {
val: 'unchanged'
};

changeVal = event => this.setState({ val: event.target.value });

render() {
return (


title




);
}
}

const { shallow: setup } = setupComponent({
component: InputComponent,
elementsToFind: [
{
name: 'input',
query: 'input'
}
]
})

describe('Component', () => {
it('updates values', () => {
const { input, refresh } = setup();

input.simulate('change', { target: { value: 'A new input value!' } });
// By now the input variable is outdated and it's `props('value')` don't actual match the new value
// It needs to be refreshed

expect(refresh(input).props().value).toBe('A new input value!');
});
});
```

#### Default Properties

If you want to add default properties to your component add an object to the `SetupComponent` function. Example:

```javascript
import React, { Component } from 'react';
import { SetupComponent } from 'react-component-setup';

class DisplayName extends Component {
render() {
return (

Hello {this.props.name}!


);
}
}

const { shallow: setup } = SetupComponent(
component: DisplayName,
defaultProps: { // the default props for the component
name: 'Kyle'
}
);

setup(); // returns element that is

Hello, Kyle!


```

Note: default props will be overridden by props provided in the setup function call.

#### Enzyme shallow and mount options

To add TODO!
If you want to add [enzyme options](https://github.com/airbnb/enzyme/blob/master/docs/api/shallow.md#arguments)
to the shallow or mount command they can be provided similarly to default properties via the `defaultEnzymeOptions`.

Example:

```javascript
import { SetupComponent } from 'react-component-setup';

const { shallow: setup } = SetupComponent(
component: ComponentName,
defaultEnzymeOptions: {
context: {
themecolor: '#fff'
}
}
);
```

To change the options on the fly provide a second argument to shallow/mount function.

```javascript
import { SetupComponent } from 'react-component-setup';

const { shallow: setup } = SetupComponent(
component: ComponentName,
defaultEnzymeOptions: {
context: {
themecolor: '#fff'
}
}
);

setup({}, { context: { themecolor: '#different theme color' } )
```

## Requirements:

1. `react` version ^0.14.9 || ^15.0.0 || ^16.0.0
2. `react-dom` version ^0.14.9 || ^15.0.0 || ^16.0.0
3. `enzyme` version ~3.3.0

## License

react-component-setup is [MIT licensed](LICENSE).