How to start practicing TDD while creating a reusable component with React
Published: 2020-10-18 22:58:22

*This article will try to teach how to practice test-driven development while at the same time teaching how to test a reusable react component.*

*Requirements before starting*
* *You have installed node.js on your computer*
* *Ensure that `npx create-react-app app-name` works in your terminal since we are going to use this to create the basic setup of the app*
* *Install enzyme `npm i -D enzyme`*
* *Install enzyme adapter `npm i - D enzyme-adapter-react-16` since we are using version 16 of React*
* *Create or edit* **src/setupTests.js** *to match the following code* 

```
import '@testing-library/jest-dom/extend-expect';
import { configure } from 'enzyme'
import Adapter from 'enzyme-adapter-react-16'
 
configure({
  adapter: new Adapter()
})

```

Now that you have done this ensure that you can run the single test that comes with the setup when we created the app.

Run **npm test** in your terminal and press a to run all the tests, you will see a similar screen like the following:
![running first test](https://dev-to-uploads.s3.amazonaws.com/i/4vv9nwp7n6nw5uuj5bu3.PNG)

Once you have done this, let’s delete the test case in file **src/App.test.js** to start creating our tests.

What do we want to achieve? For this exercise we want to create a Button component that we can reuse multiple times inside our app, specifically we want to be able to set a different text every time we call the Button component.

### Let’s Go!

Ok, first, following the TDD principles, we need to create a failing test before creating any code for the Button component and App component.

Before creating our tests, we are going to create a describe block and inside we are going to add beforeAll() function to create appWrapper before every test run that will keep our code DRY.

```
let appWrapper
  beforeAll(() => {
    appWrapper = shallow(<App />)
  })

```

appWrapper contains our App component.

Now go to **src/App.test.js** and the first test case will ensure that App component renders a Button component that will be our submit button.

```
it('renders a button component', () => {
    const submitButton = appWrapper.find(SubmitButton)
})

```

After writing this line we need to run the tests again and we can see that we have a failing test.
![first failing test](https://dev-to-uploads.s3.amazonaws.com/i/dta16a8teoknoedy66cd.PNG)

Let’s move on to make the test green. Following the other step of TDD, we need to write only enough code to make the test green.

Let’s create Button.js in the src folder with the following code
```
export default() => {}

```

And create the following jsx on App.js to return the Button component.

```
import React from 'react';
import SubmitButton from './Button'
 
function App() {
  return <SubmitButton />
}
export default App;
```

Also, we need to import the Button component in **src/App.test.js**

```
import React from 'react';
import App from './App';
import { shallow } from 'enzyme';
import SubmitButton from './Button'
 
describe('App', () => {
  let appWrapper
  beforeAll(() => {
    appWrapper = shallow(<App />)
  })
 
  it('renders a button component', () => {
    const submitButton = appWrapper.find(SubmitButton)
  })
})

```
 
Now we have our test in green.
![first test green](https://dev-to-uploads.s3.amazonaws.com/i/2w93j6u66j92jmz5xwnz.PNG)

Let’s finish this test by doing an assertion. We are going to inspect if the App contains one Button component by adding the following code to the first test:

```
expect(submitButton).toHaveLength(1)

```

Full test looks like this:

```
it('renders a button component', () => {
    const submitButton = appWrapper.find(SubmitButton)
    
    expect(submitButton).toHaveLength(1)
})

```
Ensure that the test is still green.

So far we’ve made a little bit of TDD by creating a Button component and render it in App component.

### Let’s keep practicing!

Our second test is going to inspect if we are passing a prop called value to the Button component

Let’s create a failing test

```
it('pass value as prop', () => {
    const submitButton = appWrapper.find(SubmitButton)
    
    expect(submitButton.props().value).toBeDefined()
  })

```
We are expecting a prop called value to be defined in the Button component but we received an undefined value.

![second failing test](https://dev-to-uploads.s3.amazonaws.com/i/bkk75qfyhhc27qw5gsmd.PNG)

Let’s make this test green!
To make the test pass, we need to pass a prop called value in the Button component inside the App component

```

function App() {
  return <SubmitButton value="" />
}

```

Now our test is green again, congrats!

![second test green](https://dev-to-uploads.s3.amazonaws.com/i/1bv2r8h2p4fxht0nlyxp.PNG)

Let’s do another test to keep practicing TDD, remember practice makes perfect!
For this test, we want to inspect if the value prop is equal to the string “Submit” so we are going to create another failing test.

```
it("has a value prop equal to 'Submit'", () => {
    const submitButton = appWrapper.find(SubmitButton)
 
    expect(submitButton.props().value).toEqual('Submit')
  })

```

As you can imagine this test is going to fail
![third failing test](https://dev-to-uploads.s3.amazonaws.com/i/n50v9ngol9bfz8je9neb.PNG)

We need to refactor the Button component inside the App component to make the test green.

```

import React from 'react';
import SubmitButton from './Button'
 
function App() {
  return <SubmitButton value="Submit" />
}
export default App;

```
**YES!**, all the three tests are passing now 

![third test green](https://dev-to-uploads.s3.amazonaws.com/i/xek6g72e0ockzfga5yhh.PNG)
 
If you get here, Well done! you now have a clear idea of what Test-driven development is.
Just to recap:
* write a failing test, just enough code to make the test fails
* refactor only the necessary code to make the test green
* Then again, write a failing test and then refactor to make the test green and so on

And for final touches, as you can see we are repeating `const submitButton = appWrapper.find(SubmitButton)` across all our test cases, so let’s refactor this to make our code DRY

```
let appWrapper, submitButton
  beforeAll(() => {
    appWrapper = shallow(<App />)
    submitButton = appWrapper.find(SubmitButton)
  })

```

Now we can safely delete `const submitButton = appWrapper.find(SubmitButton)` in every test and our test will still be green.

Full code: 
```
import React from 'react';
import App from './App';
import { shallow } from 'enzyme';
import SubmitButton from './Button'
 
describe('App', () => {
  let appWrapper, submitButton
  beforeAll(() => {
    appWrapper = shallow(<App />)
    submitButton = appWrapper.find(SubmitButton)
  })
 
  it('renders a button component', () => {
 
    expect(submitButton).toHaveLength(1)
  })
 
  it('pass value as prop', () => {
    
    expect(submitButton.props().value).toBeDefined()
  })
 
  it("has a value prop equal to 'Submit'", () => {
    
    expect(submitButton.props().value).toEqual('Submit')
  })
})

```

#### Additional Resources
A great resource that explains in a very clear way how to do TDD:
[TDD Live Coding - Test Driven Development Tutorial with React, Jest, and Enzyme](https://www.youtube.com/watch?v=tX-gu6FWcsE)


Find me at [github.com/Viricruz](github.com/ViriCruz)

## Happy Testing!!