Setting up tests for React-Native-Expo-Typescript
Tags: reactnative, jest, typescript, expo
Published: 2021-02-09 08:33:41

Recently I decided to write tests for my expo react native app written in typescript. Having done this in Reactjs, I didn't expect its native counterpart to be such a pain. I did the usual reading of documentations, checking StackOverflow and there was nothing. I couldn't find any working test or a proper documentation for setting up tests for expo react native apps written in typescript. I must add that I initialised my expo app using a blank template. Using either the tabs or the minimal template automatically sets up test for you (I learnt this much matter).

Luckily after about 2 weeks, I came across an npm package **expo-template-typescript-jest** [https://www.npmjs.com/package/expo-template-typescript-jest] created by [https://github.com/elgsantos]
 
It seemed like it was recently put there as an answer to my prayer. I had to take it for a spin. Ah!! yes it worked. Also, seeing that I didn't want to use its template, I had to study the repo and replicate the configurations used in my already existing expo app. 

let me walk you through how I added **jest** and **react-test-renderer** to my already existing expo app in 4 simple steps. 

**LIST OF DEPENDENCIES USED**
1) React-test-renderer
2) jest
3) jest-expo
4) ts-jest
5) jest-coverage-badges
6) @types/jest
7) @types/react-test-renderer

**STEPS:**

1) Install all the listed dependencies above best with **--save-dev** flag to see these in your devDependencies.

2) Add a jest configuration file.

``` javascript 
//jest.config.js
module.exports = {
 testEnvironment: "jsdom",
  preset: "jest-expo",
  globals: {
    "ts-jest": {
      tsconfig: {
        jsx: "react",
      },
    },
  },
  transform: {
    "^.+\\.js$": "<rootDir>/node_modules/react-native/jest/preprocessor.js",
    "^.+\\.tsx?$": "ts-jest",
  },
  testMatch: ["**/?(*.)+(spec|test).ts?(x)"],
  collectCoverageFrom: [
    "**/*.{ts,tsx}",
    "!**/coverage/**",
    "!**/node_modules/**",
    "!**/babel.config.js",
    "!**/jest.setup.js",
  ],
  moduleFileExtensions: ["js", "ts", "tsx"],
  transformIgnorePatterns: [
    "node_modules/(?!(jest-)?react-native|react-clone-referenced-element|@react-native-community|expo(nent)?|@expo(nent)?/.*|react-navigation|@react-navigation/.*|@unimodules/.*|sentry-expo|native-base)",
  ],
  coverageReporters: ["json-summary", "text", "lcov"],
})
```


3) Add  **"esModuleInterop": true** to your tsconfig.json file. Your final configuration file should look like the one below.
   ``` javascript
//tsconfig.json
  {
  "compilerOptions": {
    "allowSyntheticDefaultImports": true,
    "jsx": "react-native",
    "lib": ["dom", "esnext"],
    "moduleResolution": "node",
    "noEmit": true,
    "skipLibCheck": true,
    "resolveJsonModule": true,
    "strict": true,
    "esModuleInterop": true
  }
}
```
 
 
4) Add scripts for running your tests in different modes in your package.json.

 ``` javascript
//package.json
"test": "jest",
"test:watch": "npm run test --watch",
"test:ci": "npm run test --coverage",
"test:badges": "npm run test:ci  && jest-coverage-badges --input coverage/coverage-summary.json --output __badges__"
```

Now we can go ahead to check if this works
I will have two files here: *App.tsx* and *App.test.tsx*

1) **App.tsx**
``` javascript
//App.tsx
import { StatusBar } from "expo-status-bar"
import React from "react"
import { StyleSheet, Text, View, Image } from "react-native"

export default function App() {
  return (
    <View style={styles.container}>
      <Image
        source={require("./assets/adaptive-icon.png")}
        style={styles.logo}
      />
      <Text>Open up App.tsx to start working on your app!</Text>
      <StatusBar style="auto" />
    </View>
  )
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: "#fff",
    alignItems: "center",
    justifyContent: "center",
  },
  logo: {
    width: 120,
    height: 120,
    margin: 10,
  },
})
```

2) **App.spec.tsx**

``` javascript
//App.spec.tsx
import React from "react"
import renderer from "react-test-renderer"

import App from "./App"

describe("<App />", () => {
  it("has 2 child", () => {
    const tree: any = renderer.create(<App />).toJSON()
    expect(tree?.children?.length).toBe(2)
  })
})
```
You can go ahead and test with *npm run test*. 

To have a better overview of the code and template used here, you can check out the repo below.

{% github elgsantos/expo-template-typescript-jest %}