React Testing with Airbnb's Enzyme, Jest and Babel
Tags: javascript, react, testing, webdev
Published: 2019-08-28 05:58:09


##Hi Guys Good Day!


ok, guys first We gonna configure Jest, Enzyme from the ground up. So you can know what modules or packages we're gonna use.


Do this in the command line on your desktop.
```cmd
  md testing-with-enzyme && cd testing-with-enzyme
```
__md testing-with-enzyme__ - Makes a directory with a name of testing-with-enzyme
__&&__ - runs the second command if the first command does not throw an error
__cd testing-with-enzyme__ - Changes the current directory to testing-with-enzyme


```cmd
  npm init --y && npm i -D @babel/preset-env @babel/preset-react 
  @babel/plugin-proposal-class-properties @types/jest jest
  enzyme enzyme-adapter-react-16 && npm i -P react react-dom
```

ok, I'm not gonna explain all these packages but we're gonna all of these packages to work with __enzyme__ and __jest__.


```cmd
 type nul > babel.config.js && type nul > jest.config.js && md Tests && md components
```
__type nul__ for __Windows OS__. __touch__ for __UNIX Systems__.


Our __babel.config.js__ file.
```js
module.exports = {
  presets: ['@babel/preset-env', '@babel/preset-react'],
  plugins: ['@babel/plugin-proposal-class-properties']
}
```

Our __jest.config.js__ file.
```js
module.exports = {
  rootDir: '.',
  displayName: {
    name: 'enzyme-setup',
    color: 'blue'
  },
  runner: 'jest-runner',
  verbose: true,
  errorOnDeprecated: true,
  roots: ['./Tests'],
  moduleFileExtensions: ['js', 'jsx'],
  setupFilesAfterEnv: ['<rootDir>Tests/setupTest.js']
}
```


Inside our __Tests__ folder make a __setupTest.js__ file.
```js
import { configure } from 'enzyme'
import Adapter from 'enzyme-adapter-react-16'

configure({
  adapter: new Adapter()
})
```

Our __package.json__ file.
![package.json](https://thepracticaldev.s3.amazonaws.com/i/4m9td4h2nonebv2wmmga.png)


Inside the __components__ folder make 4 files.
```cmd 
  type nul > App.js && type nul > Form.js && type nul > Header.js && type nul > List.js
```

Our __Header.js__ file.
```js
import React from 'react'

export default function Header({ message, handleToggleTheme, theme }) {
  return (
    <div className="header">
      <h1>{message}</h1>
      <button className="right" onClick={handleToggleTheme}>
        <i className={theme}></i>
      </button>
    </div>
  )
}
```


Our __Form.js__ file.
```js
import React from 'react'

export default function Form({ handleChange, value, handleClick }) {
  return (
    <div className="form">
      <input
        className="form-control"
        type="text"
        onChange={handleChange}
        value={value}
      />
      <button className="btn" onClick={handleClick}>
        Submit
      </button>
    </div>
  )
}
```

Our __List.js__ file.
```js
import React from 'react'

export default function List({ items }) {
  return (
    <ul className="list">
      {items.map(item => (
        <li className="list-item" key={item}>{item}</li>
      ))}
    </ul>
  )
}
```

Our __App.js__ file.
```js
import React, { Component } from 'react'
import Header from './Header'
import List from './List'
import Form from './Form'

export default class App extends Component {

  state = {
    listItem: '',
    items: [],
    isDarkTheme: false
  }



  handleChange = ({ target: { value } }) => {
    this.setState({
      listItem: value
    })
  }

  handleClick = () => {
    this.setState({
      items: [...this.state.items, this.state.listItem],
      listItem: ''
    })
  }


  handleToggleTheme = () => {
    this.setState({
      isDarkTheme: !this.state.isDarkTheme
    })
  }

  render() {
    const theme = this.state.isDarkTheme ? 'dark' : 'light'
    return (
      <div className={theme}>
        <Header
          theme={theme}
          message={this.props.message}
          handleToggleTheme={this.state.handleToggleTheme}
        />
        <Form
          handleChange={this.state.handleChange}
          value={this.state.listItem}
          handleClick={this.state.handleClick}
        />
        <List items={this.state.items} />
      </div>
    )
  }

}

App.defaultProps = {
  message: 'Hello World'
}
```



Inside the __Tests__ folder make an __index.test.js__ file.
```js
import React from 'react'
import App from '../components/App'
import Header from '../components/Header'
import Form from '../components/Form'
import List from '../components/List'
import { shallow, mount } from 'enzyme'

describe('Test App component', () => {
  let wrapper;

  beforeAll(() => {
    wrapper = shallow(<App />)
  })

  it('should not return an error', () => {
    expect(wrapper).toMatchSnapshot()
    console.log(wrapper.debug())
  })
})
```

Then in your terminal run this command
```cmd
 npm t
```
If it does not throw an __error__ and it __passed__ then your good to go.

What's the difference between __shallow__ rendering and __full mount__ rendering?

There's this very useful method __debug__ that both __shallow__ and __mount__ provides us.

Try updating our __index.test.js__ file to look like this.
```js
import React from 'react'
import App from '../components/App'
import Header from '../components/Header'
import Form from '../components/Form'
import List from '../components/List'
import { shallow, mount } from 'enzyme'

describe('Test App component', () => {
  let shallowWrapper, mountWrapper;

  beforeAll(() => {
    shallowWrapper = shallow(<App />)
    mountWrapper = mount(<App />)

    console.log(shallowWrapper)
    console.log(mountWrapper)
  })

})
```
###Structure using the debug method.

The __first__ console.log looks like this.
```javascript
 console.log Tests/index.test.js:12
    <div className="light">
      <Header theme="light" message="Hello World" handleToggleTheme={[Function]} 
        />
      <Form handleChange={[Function]} value="" handleClick={[Function]} />
      <List items={{...}} />
    </div>
```

The __second__ console.log looks like this.
```javascript
  console.log Tests/index.test.js:13
    <App message="Hello World">
      <div className="light">
        <Header theme="light" message="Hello World" handleToggleTheme={[Function]}>
          <div className="header">
            <h1>
              Hello World
            </h1>
            <button className="right" onClick={[Function]}>
              <i className="light" />
            </button>
          </div>
        </Header>
        <Form handleChange={[Function]} value="" handleClick={[Function]}>
          <div className="form">
            <input className="form-control" type="text" onChange={[Function]} value="" />
            <button className="btn" onClick={[Function]} />
          </div>
        </Form>
        <List items={{...}}>
          <ul className="list" />
        </List>
      </div>
    </App>
```

The __debug__ method basically gives us the __structure__ of our component. When we use it on __shallow__ it does not give us the full structure of our component we don't see the __JSX__ structure of our __Header__,__Form__, and __List__ component but when we use it on __mount__ it gives us the full structure of our component down to every __JSX__ element that our child components used.


Useful methods that __Enzyme__ provides us.

####at(index : number)
Returns a wrapper element based on the index is given.

The difference between using __shallow__ and __mount__ on our __App__ component.
```javascript
  it('should have an "App" component "at" index of 0', () => {
    let wrapper = shallow(<App />);
    expect(wrapper.at(0).type()).toBe(App);
  });
   
  it('should return an App', () => {
    let wrapper = mount(<App />);
    expect(wrapper.at(0).type()).toBe(App)
  });

```
The __first__ test failed but the __second__ test passed the reason to this is that the type of element at index __0__ in our __shallowed__ component is __div__, not __App__ but in our __mountend__ component is __App__ refer to the __Structure__ Section changing the __App__ to __div__ in the __shallowed__ test will make the test passed.


####childAt(index : number)
Returns a new wrapper of the child at the specified index.
```javascript
  it('should have a child component of type "Header" at "index" of 0', () => {
    let wrapper = shallow(<App />);
    expect(wrapper.childAt(0).type()).toBe(Header);
  });
   
  it('should have a child element of type "div" at "index" of 0', () => {
    let wrapper = mount(<App />);
    expect(wrapper.childAt(0).type()).toBe('div')
  });
```
Base on the __Structure__ of our __shallowed App__ the first child should be __Header__ and in our __mounted App__ the first child should be div. These two tests should passed.


####find(selector : EnzymeSelector)
Basically finds every node that matches the given selector.

__Selectors__.
  - __find('div')__ =  finds every 'div' element on the current wrapper.
  - __find('div.something')__ = finds every 'div' element with a class of 'something' on the current wrapper.
  - __find('div[title="okinawa"])__  = finds every 'div' element with an attribute of "title" with a value of "okinawa".

  - __find('#okinawa')__ = find every element with an id of "okinawa".
  - __find('.okinawa')__ = finds every element with a class of "okinawa".
  - __find('div#okinawa > span')__ = finds every 'span' element that is the 
    direct child of a "div" with an id of "okinawa"
  - __find('div.okinawa + span')__ = finds every 'span' element that is placed after a "div" element with a class of "okinawa"
  - __find('div.okinawa  span')__ = finds every 'span' element that is inside a "div" element with a class of "okinawa"
  - __find(SomeComponent)__ = finds every element with a contrustor of "SomeComponent"
  ```javascript
   function App({ children }){
     return (
       <div>
           {children}
        </div>
     )
   }   
   
   
   function SomeComponent(){
      return (
        <div>
         <h1>
            Hi!
         </h1>
        </div>
      )
   }
   

   it('should have length of "1" when finding "SomeComponent" comp', () => {
    const wrapper = shallow(<App>
         <SomeComponent />
     </App>
     )
    expect(wrapper.find(SomeComponent)).toHaveLength(1);
   });

  ```
  You can find all the valid selectors [here](https://airbnb.io/enzyme/docs/api/selector.html).
 
####closest(selector : EnzymeSelector)  
finds the closest parent that matches the selector. It traverses every node up starting with itself.

```javascript
  
  it('should have an h1 with a text of "Hello World"', () => {
    let wrapper = shallow(<App />);
    expect(wrapper.find(Header).closest('div.light')).toHaveLength(1);
  });
  

  it('should have a parent element of "div" with a class of "light"', () => {
    let wrapper = mount(<App />);
    expect(wrapper.find(Header).closest('div.light')).toHaveLength(1);
  })

```
These two tests should pass.


####contains(node : node | nodes[])
Tests if the containing wrapper has a matching child or children. 

```javascript
   it('should have a node of <Header /> and the right props', () => {
    let wrapper = shallow(<App />);
    expect(wrapper.contains(
      <Header theme="light" message="Hello World" handleToggleTheme= 
           {wrapper.instance().handleToggleTheme} />
    )).toBeTruthy();
  });

 
 
  it('should contain these two nodes', () => {
    const wrapper = mount(<App />);
    expect(wrapper.contains([
      <h1>Hi</h1>,
      <button className="right" onClick={wrapper.instance().handleToggleTheme}>
        <i className="light" />
      </button>
    ])).toBeTruthy();
  })

```
We're using the __instance()__ method to get the reference of the __handleToggleTheme__ function out of that component instance. More on the __instance__ method later. These tests should pass.



####containsAllMatchingElements(nodes: nodes[])
Must match all the nodes on the current wrapper.
```javascript
 it('should have these two nodes when shallow mounting', () => {
   let wrapper = shallow(<App />);
    wrapper.setState({ listItem: '1' })
    expect(wrapper.containsAllMatchingElements(
      [
        <Form handleChange={wrapper.instance().handleChange} value="1" handleClick={wrapper.instance().handleClick} />,
        <Header theme="light" message="Hello World" handleToggleTheme={wrapper.instance().handleToggleTheme} />
      ]
    )).toBeTruthy();
  });
   
  it('should have these two nodes when mounting', () => {
    let wrapper = mount(<App />);
    expect(wrapper.containsAllMatchingElements([
      <h1>Hi</h1>,
      <button className="right" onClick={wrapper.instance().handleToggleTheme}>
        <i className="light" />
      </button>
    ])).toBeTruthy();
  })


```
We're using __setState__ to update the value of a property in our __state__. It works the same as __React's__ setState. <code>this.setState({property: newValue})</code>. These tests should pass.



####containsAnyMatchingElements(nodes: nodes[])
Must match at least one of the nodes on the current wrapper.
```javascript
  it('should this Form with the right props', () => {
    expect(wrapper.containsAnyMatchingElements(
      [
        <Form handleChange={wrapper.instance().handleChange} value="1" handleClick={wrapper.instance().handleClick} />,
      ]
    )).toBeTruthy();
  });

  it('should return true because the "i" element is right while "div" element is not the right structure', () =>{
    expect(wrapper.containsAnyMatchingElements([
      <div className="form">
      </div>,
      <i className="light" />
    ])).toBeTruthy();
  });

```
You're wondering why we have a __value__ of "1" in the __shallowed__ part that's because we used __setState__ on the previous section and updated our __listItem__ to have a value of __1__. These tests should pass. 

####first()
Behaves like __at(0)__ refer.


####hasClass(class:string)
Tests if the current node has prop of __className__ and checks the value.

```javascript
   
   it('should have a class of "light"', () => {
    let wrapper = shallow(<App />);
    expect(wrapper.hasClass('light')).toBeTruthy();
   });

   it('should have a class of "form-control"', () => 
     wrapper = mount(<App />);  
    {
    expect(wrapper.find(Form).find('#form').childAt(0).hasClass('form-control')).toBeTruthy();
  })

```
These tests should pass.

###html()
returns the raw __html__ string of the current wrapper.
```javascript
   it('should return the correct string', () => {
    let wrapper = shallow(<App >);
    expect(wrapper.childAt(2).html()).toBe('<ul class="list"></ul>')
  });
  
  it('should have an element with an id of "form"', () => {
    let wrapper = mount(<App >);
    wrapper.setProps({ message: 'Hi' });
    expect(wrapper.find('h1').html()).toBe('<h1>Hi</h1>')
  })

```
These tests should pass too.


####instance()
returns the current class instance of the current wrapper it returns null when used on a functional component. the __instance__ method can only be used on the root node.

```javascript

   it('should be an instance of App', () => {
    let wrapper = shallow(<App />);
    expect(wrapper.instance()).toBeInstanceOf(App);
  });


  it('should be an instance of App', () => {
    let wrapper = mount(<App />);
    expect(wrapper.instance()).toBeInstanceOf(App);
  });
```
These tests should pass.


####invoke(functionPropName)(..arguments)

```javascript
  
  it('should have a prop of "value" with a value of "12344"', () => {
    let wrapper = shallow(<App />);
    wrapper.find(Form).invoke('handleChange')({ target: { value: '12344' } });
    expect(wrapper.find(Form).prop('value')).toBe('12344');
  });
  

  it('should truthy value of prop "isDarkTheme"', () => {
    let wrapper = mount(<App />);
    wrapper.find(Header).invoke('handleToggleTheme')()
    expect(wrapper.state('isDarkTheme')).toBeTruthy();
  })

```
These tests should pass too. I think you're wondering I'm passing an object with a __target__ property which has a value of an object with another property of __value__ because my __handleChange__ function looks like this 

```javascript
   handleChange = ({ target: { value } }) => {
    this.setState({
      listItem: value
    })
  }
```

####is(selector: EnzymeSelector)
Checks if the selector matches the current wrapper.
```javascript
   
  it('should return false when checking with ".is"', () => {
    let wrapper = shallow(<App />);
    expect(wrapper.find(List).find('ul').is('.list')).toBeFalsy();
  });

 
  it('should return true when checking with ".is"', () => {
    let wrapper = mount(<App />);
    expect(wrapper.find(List).find('ul').is('.list')).toBeTruthy();
  });
```

The reason that the first test failed and thrown an error because of the reason 
that our element structure when using __shallow__ looks like this
```javascript
    <div className="light">
      <Header theme="light" message="Hello World" handleToggleTheme={[Function]} 
        />
      <Form handleChange={[Function]} value="" handleClick={[Function]} />
      <List items={{...}} />
    </div>
```
It does not render the __ul__ element but when we use it on __mount__ it works.



####isEmptyRender()
returns true if the current wrapper returns <code>null</code> or <code>false</code>.

```javascript
  
  it('should not be falsy because "App" does not return neither null or false', () => {
    let wrapper = shallow(<App />);
    expect(wrapper.isEmptyRender()).toBeFalsy();
  });
  
  it('should return "Nothing" literally', () => {
    class Nothing extends React.Component {
      render() {
        return (
          null
        )
      }
    }
    let wrapper = mount(<Nothing />);
    expect(wrapper.isEmptyRender()).toBeTruthy();
  });

```
These tests should pass. The second test pass due to the reason we returned __null__ on the __render__ method.


####key()
returns the __key value__ of the current wrapper. 

```javascript
  it('should have a prop of items with a length of 2 and a key value of "japan"', () => {
    let wrapper = mount(<Form />);
    let form = wrapper.find(Form);
    form.invoke('handleChange')({ target: { value: 'okinawa' } });
    form.invoke('handleClick')();
    form.invoke('handleChange')({ target: { value: 'japan' } });
    form.invoke('handleClick')();

    expect(wrapper.find(List).prop('items')).toHaveLength(2);
    expect(wrapper.find(List).find('ul').childAt(1).key()).toBe('japan');
  });


```
####last()
returns the last node base on the current selected wrapper.

```javascript
  
  it('should return the last child type which is "List"', () => {
    let wrapper = shallow(<App />);
    expect(wrapper.children().last().type()).toBe(List);
  });
  
  it('should return the last child type which is "div"', () => {
    let wrapper = mount(<App />)
    expect(wrapper.children().last().type()).toBe('div');
  });

```


####name()
returns the "name" of current wrapper.
```javascript
   it('should return a name with a value of "div"', () => {
    let wrapper = shallow(<App />);
    expect(wrapper.name()).toBe('div');
  });

  it('should return a name with a value of "App"', () => {
    let wrapper = mount(<App />);
    expect(wrapper.name()).toBe('App');
  });
```
Again, refer to the __Structure__ Section if your having a little problem understanding.


####filter(selector: EnzymeSelector)
it returns a new wrapper based on the selector given.

```javascript
  it('should have a prop of "item" with length of 3', () => {
    let wrapper = mount(<App />);
    let form = wrapper.find(Form);
    let values = ["ohio", "usa", "amawa"];
    values.forEach((value) => {
      form.invoke('handleChange')({ target: { value } });
      form.invoke('handleClick')();
    })

  expect(wrapper.find(List).find('ul li').filter('.list-item')).toHaveLength(3);

  });

});
```

####props()
returns the prop object of the current wrapper

```javascript
  it('should have a prop "items" with a value of []', () => {
    let wrapper = shallow(<App />);
    expect(wrapper.find(List).props().items).toEqual([]);
  });

  
  it('should have a prop "message" with a value of "Hello World"', () => {
    let wrapper = mount(<App />);

    expect(wrapper.find(Header).props().message).toBe("Hello World");
  });

```


####prop(key:string)
return the value of the property of the current wrapper.

```javascript
  it('should have a prop "items" with a value of []', () => {
    let wrapper = shallow(<App />);
    expect(wrapper.find(List).prop('items')).toEqual([]);
  });

  it('should have a prop "message" with a value of "Hello World"', () => {
    let wrapper = mount(<App />);

    expect(wrapper.find(Header).prop('message')).toBe("Hello World");
  });

```


####setProps(newProps: any)
Sets the new props object of the root node. It can only be used on the root node.

```javascript
   
 it('should have an updated prop "message" with a value of "What the fun"', () => {
    let wrapper = mount(<App />);
    wrapper.setProps({ message: 'What the fun' })
    expect(wrapper.find(Header).prop('message')).toBe("What the fun");
  });

```

####setState(newState : any, callbackFunc: Function)
Sets the new state object of the root node. It can only be used on the root node.

```javascript
  it('should have an updated prop "isDarkTheme" with a value of true', () => {
    let wrapper = mount(<App />);
    wrapper.setState({ isDarkTheme: true });
    expect(wrapper.state('isDarkTheme')).toBeTruthy();
  });

```


####simulate(event:string, ...args)
Invokes an event on the current wrapper.

```javascript
  it('should have an updated value of "1234"', () => {
    let wrapper = mount(<App />);
    wrapper.find('input').simulate('change', { target: { value: '1234' } });
    expect(wrapper.state('listItem')).toBe('1234');
  });

```


####state(key:string)
return the value of a state property.

```javascript
  
  it('should a input with a value of "abc"', () => {
    let wrapper = shallow(<App />);
    wrapper.setState({ listItem: 'abc' });
    expect(wrapper.state('listItem')).toBe('abc');
  });

  it('should have an updated "message" prop with a value of "Hi"', () => {
    let wrapper = mount(<App />);
    wrapper.setProps({ message: 'Hi' });
    expect(wrapper.prop('message')).toBe('Hi');
  })


```
####text()
returns the text of the current wrapper.

```javascript
  it('should a text of "Hello World"', () => {
    let wrapper = mount(<App />);
    expect(wrapper.find('h1').text()).toBe('Hello World');
  });

```

###type()
returns the type of the current wrapper.
```javascript
  
   it('should return the App', () => {
    let wrapper = shallow(<App />);
    expect(wrapper.at(0).type()).toBe('div');
  }); 
 
  it('should return the App', () => {
    let wrapper = mount(<App />);
    expect(wrapper.at(0).type()).toBe(App);
  });

```


Check this [post](https://dev.to/flexdinesh/react-hooks-test-custom-hooks-with-enzyme-40ib
) out to make your own __Cover Image__ for your dev.to Post.

##Thanks guys for reading this post.
# Have a Nice Day :smiley:!.