# Basic Testing

## Configure Libraries

Let's start by configuring enzyme (because jest is built into create-react-app):

```js
import Enzyme from 'enzyme'
import EnzymeAdapter from 'enzyme-adapter-react-16'

Enzyme.configure({ adapter: new EnzymeAdapter() })
```

**Pro tip**: To save time, you can move this configuration into its own file and tell jest to run it *before* every jest test. In create-react-app, a designated `src/setupTests.js` is already set up for this.

## Writing Tests

### Empty Critical Tests

Start by writing out **empty** tests for all the **critical** parts of your app: features that, if they were changed, you'd want to be **warned**.

```js
// This app shows a counter and a button that, when clicked, increments the counter
test('renders without error', () => {}) // <= PRO TIP: this is an excellent basic first test
test('renders increment button', () => {})
test('renders counter display', () => {})
test('counter starts at 0', () => {})
test('pressing button increments counter display', () => {})
// ^ This last test focuses on *BEHAVIOUR* by looking at output on page, not state
```

### data-test attribute

**Pro tip**: One effective method to test whether a component renders is to (1) add a `data-test` attribute to the component, (2) `find` the component using that attribute, and then (3) check that only 1 component is found.

```js
test('renders increment button', () => {
  const wrapper = shallow(<App />)
  const button = wrapper.find('[data-test="incrementButton]')
  expect(button.length).toBe(1)
})
```

### Useful helper functions

This function finds nodes in a wrapper with a given `data-test` attribute:

```js
const findByTestAttr = (wrapper, val) => {
  return wrapper.find(`[data-test='${val}']`)
}
```

This function sets up and returns a `ShallowWrapper` component by encapsulating all configuration in a function:

```js
// Use this to easily instantiate your component in order to test it!
// NOTE 1: The component is passed defaultProps that you can override
// (especially useful when component has required propTypes)
// NOTE 2: If state is provided, state is also set
const defaultProps = { myProp: undefined }

const setup = (props={}, state=null) => {
  const setupProps = { ...defaultProps, ...props }

  const wrapper = shallow(<MyComponent {...setupProps} />)
  if (state) wrapper.setState(state)

  return wrapper
}
```

### Finding child nodes, managing state, and simulating events

Let's test that a button click increments a counter display. This will use:

* `state` and `setState` for state management
* `find` for finding child nodes
* `simulate` for simulating events
* `text` to get inner text of node

```js
test('pressing button increments counter display', () => {
  const wrapper = shallow(<App />)
  wrapper.setState({ counter: 7 }) // <= don't have to do this if component has initial state

  const button = wrapper.find('[data-set="incrementButton"]')
  button.simulate('click')

  const counterDisplay = wrapper.find('[data-set="counterDisplay"]')
  expect(counterDisplay.text()).toContain(8)
})
```

**Note**: We use `toContain` because that allows you to change the text content inside `counterDisplay` without causing test failure.

### propTypes testing

If your component has `propTypes` set up, you can run tests using `check-prop-types` to check that your `propTypes` are doing their job by only accepting the correct props.

```js
import checkPropTypes from 'check-prop-types'

// Helper function
const checkProps = (component, props) => {
  const propsError = checkPropTypes(
    component.propTypes,
    props,
    'prop',
    component.name
  )

  expect(propsError).toBeUndefined()
}

test('expected props don\'t throw error message', () => {
  const expectedProps = { myProp: 'hello' }
  checkProps(MyComponent, expectedProps)
})
```

Using `checkPropTypes` inside `checkProps`, a `propsError` message is returned *if* the provided props don't adhere to `propTypes`. We then check to see if there is in fact an error message using `expect`.

### Contexts, describe, and forEach

We can wrap a set of `test` functions inside a `describe` function, creating a **context** in which all those tests fall under.

For example, a counter may have a set of tests for testing the increment portion of the counter:

```js
describe('if increment button clicked', () => {
  test('does not increment if counter is at 10', () => {
    const wrapper = setup()
    // Expects here
  })
  test('does increment if counter is below 10', () => {
    const wrapper = setup()
    // Expects here
  })
})
```

Notice how we write `const wrapper = setup()` before each test? For code that you're repeating, you can move this to a `beforeEach`. `beforeEach` will run the code *before* each test.

```js
// Refactor
describe('if increment button clicked', () => {
  let wrapper // <= accessible scope
  beforeEach(() => {
    wrapper = setup()
  })

  test('does not increment if counter is at 10', () => {
    // Expects here
  })
  test('does increment if counter is below 10', () => {
    // Expects here
  })
})
```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://notes.danfitz.com/javascript/react-testing/2-basic-testing.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
