1. Create React Native project

Okie dokie, that’s a surprise, isn’t it? Yep, we need to create a RN project first. Some prefer using create-react-native-app (repo), but in this tutorial I‘ll stick to the good ol’ react-native init command. We open the terminal in the directory where we want our app to sit in and then run:

react-native init RNComponentsTester

2. ESLint setup

Before writing even one line of code, I suggest setting up the linter. It’s a perfect point to start with, as it might save you headache when you start to build your components.

A widely popular choice is eslint-config-airbnb and I’m not so edgy not to follow. Our ESLint configuration will extend this config, but we will need a few plugins. Since we’re using Flow, it’s a good idea to install eslint-plugin-flowtype . To avoid troubles with imports and JSX syntax, we need to add appropriate plugins. Finally, we install it completely by executing:

yarn add --dev eslint babel-eslint eslint-config-airbnb eslint-plugin-flowtype eslint-plugin-import eslint-plugin-jsx-a11y eslint-plugin-react

All we have to do now is add .eslintrc file to our projects root directory. The rules defined in that file are completely up to you - there is a solid documentation on this. My favourite configuration is:

{

"parser": "babel-eslint",

"extends": "airbnb",

"plugins": [

"react",

"flowtype",

"jsx-a11y",

"import"

],

"rules": {

"react/jsx-filename-extension": [

1, { "extensions": [".js", ".jsx"] }

],

"react/prefer-stateless-function": [

2, { "ignorePureComponents": true }

],

"react/forbid-prop-types": [0, { "forbid": [] }],

"import/extensions": [1, "never", { "svg": "always" }],

"import/no-extraneous-dependencies": [

"error",

{

"devDependencies": true,

"optionalDependencies": false,

"peerDependencies": false

}

],

"semi": ["error", "never"]

},

"env": {

"jest": true

}

}

Lastly, create a script in package.json file. This is to be able to quickly run lint through the entire app. Under scripts we simply declare:

"scripts": {

// ...

"lint": "eslint src"

}

src here is a directory, where we keep all the code. From this point on we will be able to check our app simply by calling yarn lint .

Photo by Jeremy Bishop on Unsplash

3. Prettier

Prettier is one of the best things to happened in code management. If you have never heard of it, I assure you you’d love it. You don’t need to think about code styling, and you are 100% guaranteed that the syntax will be consistent across all devs working with the same repo. Just relax and focus on what you’re about to build.

Configuration of prettier is quite straightforward, but to get the most out of it, it’s best to try it with lint-staged and husky packages. Again, we install them together under devDependencies :

yarn add --dev prettier husky lint-staged

All the magic happens in package.json and there is no need to change any other file. First, let’s define the rules we want prettier to follow. We create another script:

"scripts": {

// ...

"pretty": "prettier --semi false --print-width 100 --single-quote

--trailing-comma all --write \"src/**/*.js\""

}

The last argument is regex match indicating which files we’d like to pretty. In this case, they are all Javascript files from our src directory. As we have pretty defined, we can take another step and invite lint-staged to the party. We define, next to scripts :

"scripts": {

// ...

},

"lint-staged": {

"*.js": [

"yarn pretty",

"git add"

]

}

Husky is a tool that allows us to define git hooks, like precommit . To use it, another script goes into our package.json :

"scripts": {

"precommit": "lint-staged && yarn test"

}

When using husky with yarn , you might meet this issue: https://github.com/typicode/husky/issues/84

Simply resolve it with yarn add —-dev husky --force

Now our code is protected from any styling abuse and we can commit our changes being sure, that all of our mistakes will be automatically fixed and forgiven.

We have put a lot of work into our project without writing single line of code yet - let’s change that.

Photo by Kym Ellis on Unsplash

4. Catching the Flow

It’s finally time to create some component. I decided to go with a button, since it will be useful to test other components in the future. You can find sources for my AwesomeButton right here. I won’t spend much time talking on the button itself, but it is given to you in the repo as an example of how you can test your components.

First, let’s focus on enabling Flow for our project. One tip:

It is extremely simple!

Like, really. React Native provides already prepared .flowconfig in its root directory. All that’s needed is:

Open .flowconfig file. Scroll down to the very bottom of this file. Check the version number.

Now, that’s the exact flow-bin package version you need to install. In my case, the number was 0.61.0 , so let’s run the command:

yarn add --dev flow-bin@0.61.0 babel-preset-flow

I tricked you a little. We also need babel-preset-flow , but that’s not a big issue. Just install this package and add a preset in .babelrc file, like so:

{

"presets": ["react-native", "flow"]

}

Let’s create two helper scripts to easily run flow-related commands:

"scripts": {

// ...

"flow": "flow",

"flow-stop": "flow stop"

}

Finally, we’re ready to go. On the flow website you can find information how to use it inside the components, you can also look at my AwesomeButton component. Remember to put the // @flow signature on the top of the file you’re planning to use it in, and you’re good to go.

Photo by Levi Saunders on Unsplash

5. Jest, and the joke’s on you

Forget about all the struggles behind you. Now comes the real deal. The Jest setup.

Jest is something that can turn one of your afternoons into a nightmare, but at the same time save you a lot of trouble in the future. To configure Jest and the awesome Enzyme library from the Airbnb guys, and get them both to work on your brand new React Native project, just do the following:

Install dependencies

yarn add --dev enzyme enzyme-adapter-react-16 enzyme-to-json react-dom

Set Jest configuration in package.json

"scripts": {

// ...

},

"jest": {

"preset": "react-native",

"testMatch": [

"**/?(*.)test.js?(x)"

],

"snapshotSerializers": [

"enzyme-to-json/serializer"

],

"setupFiles": [

"<rootDir>/jest/setup.js"

]

}

A few interesting things happened above. First, we describe the naming convention of test files in our application. ”**/?(*.)test.js?(x)" expression means, that every file with name such as my-component.test.js , my-better-component.test.jsx, /src/components/commons/my-text/test.js etc. will be treated as a test file.

We can also see the snapshotSerializers field, where we make a use of enzyme-to-json package we have previously installed. Thanks to this serializer, our snapshots will take an easily readable form.

And finally, we specify jests setup file location. We need to create the jest folder inside of our root directory and put setup.js file in there. Inside this file, the only thing we need to add is:

import { configure } from 'enzyme'

import Adapter from 'enzyme-adapter-react-16' configure({ adapter: new Adapter() })

This is necessary because of many breaking changes introduced inside React@16 release.

Finally, we add two final scripts in our package.json file:

"scripts": {

// ...

"test:unit": "jest",

"test": "yarn lint && yarn flow && jest"

}

That’s it! You can check this script by running yarn test from projects root terminal, but remember, the tests will only pass if there is at least one .test.js file created and the tests are defined inside.

For the example of how to define tests and maintain test files, you can take a look at my AwesomeButton tests.