React testing & formatting made easy
Tags: testing, react
Published: 2021-02-17 19:14:39

> It doesn't matter how beautiful your site is, if a push with some faulty code can crumble it all

Testing fixes this.

And luckily for us, react has already thought of it.

Open up your favorite code editor and create a file named after one of your components, but add a .test. as a file extension.
Example:
`Category.test.js`
In here we're gonna be testing a mocked axios response.

In here you wanna import everything you need, including but not limited to: 
- your component
- mockedAxios from "axios"
- { act, cleanup, render, screen, waitFor } from "@testing-library/react"

we're gonna be using Jest, which is what facebook uses to test react apps - this means it's already included if we started our project with the create-react-app template.

```javascript
afterEach(cleanup)
jest.mock("axios")
```

The first function makes sure that the virtually rendered test is unmounted after each run, and the second tells the document that we're mocking an axios response.
The whole point is to simulate what kind of response our component wants to use. This means that we're **not** testing the actual API response, but our own mocked version.

```javascript
describe("shows our component", function() {
   // This is where our test will be set up
})
```
We wanna create an almost exact copy of what the real API response looks like, the reason it's not an exact copy is that the values don't matter - only the properties.

So this could be our mocked response, but remember *it needs to have the exact same properties and nesting as the real thing*
```javascript
    var response = {
        data: {
            playlists: {
                items: [
                    {
                        id: 1,
                        images: [
                            {
                                url: "https://via.placeholder.com/600"
                            }
                        ],
                        name: "rock on",
                        type: "playlist"
                    },
                    {
                        id: 2,
                        images: [
                            {
                                url: "https://via.placeholder.com/600"
                            }
                        ],
                        name: "dance moves",
                        type: "playlist"
                    },
                ]
            }
        }
    }
```

Now to actually test this we will use an 'it' function, which takes a name parameter and callback function.
```javascript
it("shows a functional component", async function() {
   // Our test will run here
});
```
Inside we need:
- `mockedAxios.get.mockResolvedValue(response)`
Which uses our fake response and simulates it as real.
- an `act` function which closely simulates a browser environment by executing useEffects, and reduces amount of re-renders done. It takes a callback function as parameter.
- an `await waitFor` function which also takes a callback function as parameter. We use await because of the outer `it` function being asynchronous.

This is what we're left with:

```javascript
it("this is a description of what the function does", async function() {
  mockedAxios.get.mockResolvedValue(response);

  act(function() {
      
  });

  await waitFor(function() {
        
  });
});
```

Inside of the callback for the `act` function, we need to render our component in the simulated browser.
```javascript
render (
   <Component /> 
)
```

Inside of the callback for the asynchronous `waitFor` function, we need to declare a variable that looks for a specific piece of text on the screen in this simulated environment. For the test to pass, this piece of text obviously needs to be provided by the mocked axios response declared further above.

```javascript
var text = screen.getByText(/party/i)
expect(text).toBeInTheDocument()
```
Run the premade script called "test", and it will get a pass!

**To summarize**,
we are not testing the actual finished product, or the real API response. We are simply making sure that the component is ready and able to **use** the information it will eventually be provided and is designed for.

```javascript
afterEach(cleanup);
jest.mock("axios");

describe("shows our component", function() {
    var response = {
        data: {
            categories: {
                items: [
                    {
                        id: 1,
                        images: [
                            {
                                url: "https://via.placeholder.com/600"
                            }
                        ],
                        name: "party",
                        type: "playlist"
                    },
                    {
                        id: 2,
                        images: [
                            {
                                url: "https://via.placeholder.com/600"
                            }
                        ],
                        name: "dance moves",
                        type: "playlist"
                    },
                ]
            } 
        }
    }

    it("shows a functional component", async function() {
        mockedAxios.get.mockResolvedValue(response);

        act(function() {
            render (
	          <Component />
            );
        });

        await waitFor(function() {
            var text = screen.getByText(/party/i);
            expect(text).toBeInTheDocument();
        });
    });
});
```


##Formatting

The package `Prettier` makes sure our code is formatted in a uniform way. Useful for examples like sharing code and working together, it creates a consistent style by making sure the files follow a specific set of rules.

`npm install prettier -D`
This needs to be a dev-dependency for later!

Now these files need to created in your root folder:
- prettierrc.json, to let your code editor know that you're using prettier. This is your config file.
- .prettierignore file so your code editor knows which files shouldnt be formatted

There's a bunch of different options that can be input in the json config, so instead of writing them all out i'll link you to the official documentation
[prettier options](https://prettier.io/docs/en/options.html)

An easy example could look like this
```javascript
{
   "printWidth": 120,
   "useTabs": true,
   "semi: true,
   "singleQuote": false,
   "quoteProps: "consistent",
   "bracketSpacing": true,
   "arrowParents": "avoid"
}
```

This makes sure that even though Bob from your office loves to use 31 tabs between variable declarations and not use a single line break, you won't have to deal with it when he sends you the file for review. 
And there's potential options to deal with ALL of your co-workers "personal formatting preferences", and you don't even have to confront them about it - great right?

**Now for the ignore file**
Most importantly, add your node_modules folder to the .prettierignore file.
some other good ideas are 'build', 'coverage' and '.vscode', but like the official documentation recommends, you can mostly just copy everything from your .gitignore file.

To format all files with prettier:
- Create a new script in package.json called "prettier", with a value of `"prettier --write ."`
- Go to the console and `npm run prettier`, this uses the default options and ones written in your config file.

If you so desire, theres the possibility of changing the script value to `"prettier --write src/"` to only format files in the src folder etc.

##A bit of a warning!
We automatically use eslint because of react, so we need to install a package that lets Prettier work nicely with it. This simply disables some eslint options that might interfere.
`npm install eslint-config-prettier -D`

##Pre-commit hooks:

Quick to set up, but incredibly useful.

To make sure Prettier always formats your files before committing,
go to the console and write as so:
`npx mrm lint-staged`
This is a package that simply runs Prettier before every commit.

If you also wanna make sure you don't commit something that has failed one of your tests, go to the console once again:
`npm i husky`
`npx husky install`
`npx husky add .husky/pre-commit "npm test"`
Add cross-env CI=true to your test script like so:
`npm i cross-env`
`"test": "cross-env CI=true react-scripts test"`
Now the "npm test" script will always be ran before a commit, and if it fails, the script will end itself.

Now there's no way around formatting the code, take that -31 tabs Bob-