> For the complete documentation index, see [llms.txt](https://sandeepamaranath.gitbook.io/notes/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://sandeepamaranath.gitbook.io/notes/languages-and-frameworks/react-testing.md).

# React Testing

{% embed url="<https://www.udemy.com/course/react-testing-library/learn/lecture/24418712#overview>" %}
Udemy Course
{% endembed %}

## What is Jest?

Jest is a delightful **JavaScript Testing Framework** with a focus on simplicity.

It works with projects using: [Babel](https://babeljs.io/), [TypeScript](https://www.typescriptlang.org/), [Node](https://nodejs.org/), [React](https://reactjs.org/), [Angular](https://angular.io/), [Vue](https://vuejs.org/) and more!

### What is Jest-DOM?

* Jest Dom comes with create-react-app
* It uses src/setup.test.js and the Jest DOM is available on all these files ending with .test.js
* The above point means that the Jest DOM matchers are available in .test.js files where Jest DOM provides some of the methods that will test the screen elements -> "Tests if element is present on DOM or not" and many more methods related to screen/UI which is DOM.&#x20;
* The normal Jest doesn't do the testing of screen elements. It might do test of Javascript related stuff, for example, jest can test how many elements are present in an array. On the other hand, Jest DOM can test if UI shows "Learn React" or not.
* Simply put, because of Jest DOM, the DOM matchers for Jest is available on .test.js files

{% embed url="<https://jestjs.io/docs/getting-started>" %}
Jest docs
{% endembed %}

## What is React Testing Library?

* Provides virtual DOMs for tests - Any time we are running tests without a browser, we need to have a virtual DOM so we can do things like click elements and we can see if virtual DOM behaves like it should do.

### How Jest is related to React Testing Library?

* Jest is a test runner. Jest is responsible for&#x20;
  * Finding Tests
  * Running the tests
  * Determining whether the tests pass or fail
* Both React Testing Library and Jest works together.&#x20;

## Relationship between React-Testing-Library and Jest

![What is React-Testing-Library and JEST](/files/ztEU3eUpFlkNwf90GmwX)

![React-Testing-Library + Jest](/files/WEpP5OWYW0bxoeqYBbyD)

{% embed url="<https://stackoverflow.com/questions/66341449/testing-library-react-vs-jest>" %}
I've commented on the answer which I like
{% endembed %}

## What is Enzyme and Mocha?

**Enzyme** is replacement for React Testing Library like it's said in the stackoverflow link above. It's not the replacement for Jest.&#x20;

Mocha is replacement for Jest.

Below combination are possible

* React Testing Library  + Jest  **-> Our Udemy Course and popular option**
* Enzyme + Jest
* React Testing Library + Mocha
* Enzyme + Mocha

## How to run tests?

* To run the create-react-app we use `npm start`
* To run the tests, we use `npm test`&#x20;
* Type 'a' to run our tests. This is our watch mode (More on this later)

![Basic test details](/files/Qx6vTxuuyaQ3asR56rWB)

## Assertions

Assertions are the statements that **test our expectations** against **actual results**.

![Simple assert statement](/files/eJQDz60PsCLwPHhax5cu)

![Jest Vs Jest DOM](/files/5ZRf3o0EXXoxo9cBOFSn)

## How Jest Works?

![How Jest Works](/files/CZuMuovcCV4ScKOfdQd7)

![Empty test passes](/files/2QEAOmLKVCzg6sDvL6bl)

## What is Test Driven Development (TDD)?

Writing the tests even before writing the code.&#x20;

![What is TDD](/files/C6bzMXiwr2J7o47fBOuF)

![Why TDD](/files/jXARzO8UZOShj9KTa9mw)

## What are the types of Tests?

* **Unit Testing**&#x20;
  * Tests one unit of code at a time. May be a single function or a component without depending on other units
* **Integration Testing**
  * Tests how multiple units work together. Testing interaction between different functions/units/components
* **Functional / Behavioural Testing**
  * Functional testing means testing the behaviour of a function/software. We might be testing if the software does the right thing with the particular set of data. That might be an integration test as it might have to interact with different units. So the functional test can be an integration test as well
  * The functional test can also be a simple unit test. Let's say on a button click, the div turns red. This might be a simple unit test but still it can be considered as functional test as well as it tests for a particular behaviour of CLICK TURNS RED OR NOT
  * So, the functional test means, not testing the code but testing the behaviour
  * React-Testing-Library encourages functional tests
* **Acceptance/End-to-End(E2E) test**
  * This is an End-to-End testing where we need a browser and might also need the server&#x20;
  * Popular tools for E2E testing are Cypress and Selenium
  * React-Testing-Library doesn't support E2E testing

![Unit Testing Vs Functional Testing](/files/bfdm1gtlpNNfIxMhI6K5)

## TDD (Test-Driven-Development) Vs BDD (Behavioural Driven Development)

If only developer is testing the code while writing the code then its TDD even though we write functional tests for testing behaviour

BDD is when different teams are involved like developer, QA, business and so on to test the software&#x20;

![TDD Vs BDD](/files/0XAuwzUvHy7Q6FlGCXs6)

## Accessibility and Finding Elements with Testing Library

* Testing library recommends **finding elements by accessibility** handles like screen readers would be able to find them

{% embed url="<https://testing-library.com/docs/queries/about#priority>" %}
What priority to use&#x20;
{% endembed %}

#### Priorities to access the elements (For more details refer the above docs)

1. Queries Accessible to everyone. Examples:

* getByRole - All the role definitions can be found here <https://www.w3.org/TR/wai-aria-1.1/#role_definitions>
  * Most of the HTML / JSX elements has the role by default. For Example, the link is the default role of anchor tag \<a> and we don't need to explicitly define it.&#x20;
  * To define the role explicitly we say `role = ""`. Example, `<a role="link"/>`

![getByRole](/files/0XoQwRL1nFENY1pyIYwP)

* getByLabelText

2\. Semantic Queries

* getByAltText
* getByTitle

3\. Test IDs

* getByTestId

Read more about this in the document given below.&#x20;

{% hint style="warning" %}
If our test can't find an element like the screen reader would then our app is not friendly to the screen readers which is a bad thing 😢
{% endhint %}

## Course Plan to learn React-Testing

![Course plan](/files/vEu7jRYLxuLTgDDUjNej)

### First App - Color Button

![Change colour of buttons tests](/files/6IDWRaYvfNKpyGcYkbd0)

**In the first app, we just test the change of the colour of the button on click. If we click on red button, it will change to blue and vice versa.**

#### **Task 1 - Test the background color of button if it's red**

**Step 1**

* In TDD style, we first write the test before we test the functionality and make it fail
* First clear the content in `App.js` and make sure it just returns a simple `div`
* Write the test for this first and see it fail and then in step 2, write enough to make the test pass

![First test that fails (TDD)](/files/Sv2h8ATMH0Fo0VKNCdXJ)

```javascript
import { render, screen } from '@testing-library/react';
import App from './App';

test('button has correct initial color', () => {
  // first, render the app
  render(<App />)

  // second, find the element. That will be done by global object - screen that has access to virtual dom
  const colorButton = screen.getByRole('button', { name: 'Change To blue' })  // find element with a role of button and text 'Change to blue'

  // third, expect the bgcolor  to red
  expect(colorButton).toHaveStyle({ backgroundColor: 'red' })

})
```

**Step 2**

* Once the test fails, then write enough to make the test pass in `App.js` file

![TDD - make the step pass](/files/HXhDh4BjlbqjWkLXY1ZH)

#### **Task 2 - Test the button when clicked changes the colour to blue**

**Steps**

* First write the test and let it fail
* Now write the function to make the button colour to blue and then see the test pass

**Test Before Code**

```javascript
test('button turns blue on click', () => {
  render(<App />)
  const colorButton = screen.getByRole('button', { name: 'Change To Blue' })
  fireEvent.click(colorButton)
  // expect the change of color to blue on click
  expect(colorButton).toHaveStyle({ backgroundColor: 'Blue' })

  //expect the change of text to Change To Red as well after click
  expect(colorButton.textContent).toBe('Change To Red')
  // OR
  // expect(colorButton).toHaveTextContent('Change To Red')
})

// Note : We can write two assert statements sometimes as this is a 
// functional/behavioural testing
```

**Code after Test fails**

```javascript
function App() {
  const [buttonColor, setButtonColor] = React.useState('Red')
  const newButtonColor = buttonColor === 'Red' ? 'Blue' : 'Red'

  return (
    <div>
      <button onClick={() => setButtonColor(newButtonColor)} style={{ backgroundColor: buttonColor }}>Change To {newButtonColor}</button>
    </div>
  );
}

export default App;
```

#### **Task 3 - Let's add Checkbox to the page. When checkbox is checked, the button should be disabled and when unchecked, the button gets enabled**

**Steps**

* Write the test for initial condition - to check if the colorButton is enabled and the checkbox is disabled
* The below test fails as it can't find checkbox

```javascript
test('initial conditions', () => {
  // the button starts out enabled
  render(<App />)

  const colorButton = screen.getByRole('button', { name: 'Change To Blue' })

  expect(colorButton).toBeEnabled() // checks the button if enabled

  // check that the checkbox is unchecked
  const checkbox = screen.getByRole('checkbox')

  expect(checkbox).not.toBeChecked()
})
```

* Let's make the test pass by adding a checkbox into App.js

```javascript
function App() {
  const [buttonColor, setButtonColor] = React.useState('Red')
  const newButtonColor = buttonColor === 'Red' ? 'Blue' : 'Red'

  return (
    <div>
      <button onClick={() => setButtonColor(newButtonColor)} style={{ backgroundColor: buttonColor }}>Change To {newButtonColor}</button>

      <input type="checkbox" /> // added to make the above test pass 

    </div>
  );
}
```

* Let's test for button being disabled after checkbox being checked&#x20;

```javascript
test('test for button being disabled after checkbox being checked', () => {

  render(<App />)

  // get the checkbox
  const checkbox = screen.getByRole('checkbox')

  // first check the checkbox through fire-even
  fireEvent.click(checkbox)

  // get the button
  const colorButton = screen.getByRole('button', { name: 'Change To Blue' })

  // then check if button is disabled
  expect(colorButton).toBeDisabled()

})

test('when checkbox is unchecked, the button should be enabled', () => {
  render(<App />)
  const checkbox = screen.getByRole('checkbox')
  const colorButton = screen.getByRole('button', { name: 'Change To Blue' })
  fireEvent.click(checkbox)
  fireEvent.click(checkbox)
  expect(colorButton).toBeEnabled()
})
```

* To make the test passed

```javascript
import logo from './logo.svg';
import React from 'react'
import './App.css';

function App() {
  const [buttonColor, setButtonColor] = React.useState('Red')
  const [buttonEnabled, setButtonEnabled] = React.useState(false)
  const newButtonColor = buttonColor === 'Red' ? 'Blue' : 'Red'

  return (
    <div>
      <button disabled={buttonEnabled} onClick={() => setButtonColor(newButtonColor)} style={{ backgroundColor: buttonColor }}>Change To {newButtonColor}</button>

      <input aria-checked={buttonEnabled}
        type="checkbox" onClick={() => setButtonEnabled(prevState => !prevState)} />

    </div>
  );
}

export default App;
```

#### &#x20;How to give a name to the checkbox?&#x20;

Name of the checkbox comes from the label assigned to it

![Name of the checkbox comes from label](/files/GfeIekclIa7jXCsdMrJe)

#### **Task 4 - Now let's add functionality where the button colour turns grey**

**Steps**

* Disable checkbox
* Check if button is grey
* Enable checkbox
* Check if button is red
* Click the button to change colour to blue
* Disable checkbox
* Check if button is grey
* Enable checkbox
* Check if button is blue&#x20;

```javascript
test('turn the button to gray on disabling it', () => {
  render(<App />)
  const colorButton = screen.getByRole('button', { name: 'Change To Blue' })
  const checkbox = screen.getByRole('checkbox', { name: 'Disable Button' })

  // disable checkbox
  fireEvent.click(checkbox)

  // check if btn is gray
  expect(colorButton).toBeDisabled()
  expect(colorButton).toHaveStyle({ backgroundColor: 'grey' })

  // enable checkbox 
  fireEvent.click(checkbox)

  // check if btn is red
  expect(colorButton).toHaveStyle({ backgroundColor: 'Red' })

  // click btn to change color to blue
  fireEvent.click(colorButton)

  // disable checkbox
  fireEvent.click(checkbox)

  // check if button is gray
  expect(colorButton).toHaveStyle({ backgroundColor: 'grey' })

  // enable checkbox
  fireEvent.click(checkbox)

  // check if btn is blue
  expect(colorButton).toHaveStyle({ backgroundColor: 'Blue' })

})
```

* Now after the test fails, implement the passing code and re-test to check if functionality is passed

```javascript
<button disabled={buttonEnabled} 
  onClick={() => setButtonColor(newButtonColor)} 
  style={{ backgroundColor: buttonEnabled ? 'grey' : buttonColor }}>
  Change To {newButtonColor}
</button>
```

## Unit Tests

Till now we were doing a functional/functionality/behavioural testing on components. Then what is a unit test? Let's say we have a function that is used by one or more components. We might want to test that function with different inputs (different edge cases) and this is called unit test.

Let's take an example here. Let's say our users are bored of red and blue colours and they want Mid night blue and Medium Violet Red.&#x20;

Here, our function might take different type of inputs like camel case, single word and so on. But at the end, we need a camel case output.&#x20;

**Edge cases**

* Test for - Single word colour like 'red', 'blue' (with no inner capital letters)
* Test for - Works for one inner capital letter like 'midnightBlue'
* Test for - Works for multiple inner capital letters like 'mediumVioletRed'

Here's you can see that we need to test a single function with different edge  case inputs. In this case we can group these test cases (as it is related to same test with different inputs). **For grouping the test cases, we can use describe.**&#x20;

#### **Grouping tests**

describe statement is used to group the tests

```javascript
describe('Spaces before camel-case capital letters', () => {
  test('Works for no inner capital letters', () => {
    expect(replaceCamelWithSpace('red')).toBe('red')
  })

  test('Works for word having one capital letter', () => {
    expect(replaceCamelWithSpace('MidnightBlue')).toBe('Midnight Blue')
  })

  test('Works for word having multiple capital letters', () => {
    expect(replaceCamelWithSpace('MediumVioletRed')).toBe('Medium Violet Red')
  })
})
```

Function to make this pass

```javascript
export function replaceCamelWithSpace(colorName) {
  // replacing capitals with spaces if the capital letter appears in the middle
  return colorName.replace(/\B([A-Z])\B/g, ' $1')
}
```

## What all you learned?

| Task                                                                                                                                                                                                                         | How to do |
| ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------- |
| <ul><li><p><strong>FIRST APP - COLOUR BUTTON</strong></p><p>How to test text content on screen</p></li><li>How to check if button is enabled and disabled</li><li>How to check if checkbox is enabled and disabled</li></ul> |           |
| <p><strong>SECOND APP</strong></p><ul><li></li></ul>                                                                                                                                                                         |           |
|                                                                                                                                                                                                                              |           |
|                                                                                                                                                                                                                              |           |
|                                                                                                                                                                                                                              |           |
