DEV Community

Cover image for React testing & formatting made easy
Thor Würtzner
Thor Würtzner

Posted on • Edited on

React testing & formatting made easy

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.

afterEach(cleanup)
jest.mock("axios")
Enter fullscreen mode Exit fullscreen mode

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.

describe("shows our component", function() {
   // This is where our test will be set up
})
Enter fullscreen mode Exit fullscreen mode

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

    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"
                    },
                ]
            }
        }
    }
Enter fullscreen mode Exit fullscreen mode

Now to actually test this we will use an 'it' function, which takes a name parameter and callback function.

it("shows a functional component", async function() {
   // Our test will run here
});
Enter fullscreen mode Exit fullscreen mode

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:

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

  act(function() {

  });

  await waitFor(function() {

  });
});
Enter fullscreen mode Exit fullscreen mode

Inside of the callback for the act function, we need to render our component in the simulated browser.

render (
   <Component /> 
)
Enter fullscreen mode Exit fullscreen mode

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.

var text = screen.getByText(/party/i)
expect(text).toBeInTheDocument()
Enter fullscreen mode Exit fullscreen mode

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.

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();
        });
    });
});
Enter fullscreen mode Exit fullscreen mode

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

An easy example could look like this

{
   "printWidth": 120,
   "useTabs": true,
   "semi: true,
   "singleQuote": false,
   "quoteProps: "consistent",
   "bracketSpacing": true,
   "arrowParents": "avoid"
}
Enter fullscreen mode Exit fullscreen mode

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-

Top comments (1)

Collapse
 
m1quel profile image
Mikkel Frederiksen

Nice