Javascript Unit Testing – Jest - Course Notes
Tags: googlecloud, javascript, localdevelopment, notes
Published: 2021-12-13 14:45:02

---
title: Javascript Unit Testing – Jest - Course Notes
published: true
date: 2020-08-17 23:04:28 UTC
tags: GoogleCloud,Javascript,LocalDevelopment,notes
canonical_url: http://181.126.83.235/2020/08/17/javascript-unit-testing-jest/
---

## Jest Traversy Tutorial

Local folder:
`E:\NMS\CURSOS\SMALL-TUTORIALS\jest-tutorial-traversy`

Youtube tutorial link:
<a href="https://www.youtube.com/watch?v=7r4xVDI2vho">https://www.youtube.com/watch?v=7r4xVDI2vho</a>

Github link of tutorial:
<a href="https://github.com/bradtraversy/jest_testing_basics">https://github.com/bradtraversy/jest_testing_basics</a>


### Installation

```bash
npm init -y
npm i -D jest
# for systax highlighting in vscode (type adquisition)
# https://stackoverflow.com/questions/42024526/vscode-automatic-type-acquisition-for-jest
npm install -D @types/jest
```

In `package.json`
```json
  "scripts": {
    "test": "jest"
  },
```

### How to run tests

```bash
npm test
```

Example `functions.test.js`
```js
const functions = require('./functions');

// to run functions before of after
// beforeEach(() => initDatabase());
// afterEach(() => closeDatabase());
// beforeAll(() => initDatabase());
// afterAll(() => closeDatabase());

//toBe
test('Adds 2 + 2 = 4', ()=> {
    expect(functions.add(2,2)).toBe(4);
});

//to not.toBe
test('Adds 2 + 2 not equal to 5', ()=> {
    expect(functions.add(2,2)).not.toBe(5);
});

// toBeFalsy
test('is 0 falsy?', ()=> {
    expect(0).toBeFalsy();
}); //Answer is yes

// toEqual
test('User should be Brad Traversy object', () => {
    expect(functions.createUser()).toEqual({
      firstName: 'Brad',
      lastName: 'Traversy'
    });
  });

// Async Await
test('User fetched name should be Leanne Graham', async () => {
    // expect.assertions(1);
    const data = await functions.fetchUser();
    expect(data.name).toEqual('Leanne Graham');
  });

// CHECK FOR TRUTHY & FALSY VALUES
// toBeEqual
// toBeNull matches only null
// toBeUndefined matches only undefined
// toBeDefined is the opposite of toBeUndefined
// toBeTruthy matches anything that an if statement treats as true
// toBeFalsy matches anything that an if statement treats as false
```

Example `functions.js`
```js
const axios = require('axios');

const functions = {
  add: (num1, num2) => num1 + num2,
  isNull: () => null,
  checkValue: x => x,
  createUser: () => {
    const user = { firstName: 'Brad' };
    user['lastName'] = 'Traversy';
    return user;
  },
  fetchUser: () =>
    axios
      .get('https://jsonplaceholder.typicode.com/users/1')
      .then(res => res.data)
      .catch(err => 'error')
};

module.exports = functions;
```

## Mocks and async functions

In order of getting testing results that are independent of the API's we use, we can use mocks. 

For that, we can create a `__mocks__` folder that we can call using `jest.mock('./mymodule')`. 

An entire module is substituted. When using global package such as `axios`. You dont need to call `jest.mock('axios')`, it is done automatically if you place the `axios.js` file in the `__mocks__` folder.

`__mocks__/async.js`:
```js
const fetchUser = () => {
  console.log("Using mock function for fetchData")
    return Promise.resolve({name:"Leanne Graham"});
  }
exports.fetchUser = fetchUser;
```

`async.js`
```js
const axios = require('axios');

const fetchUser = () =>{
  console.log('Fetching data with axios...')
    return axios
      .get('https://jsonplaceholder.typicode.com/users/1')
      .then(res => res.data)
      .catch(err => 'error')
    }
exports.fetchUser = fetchUser;
```

`async.test.js`
```js
jest.mock('./async')
const {fetchUser} = require('./async');

// Async Await using mock
test('User fetched name should be Leanne Graham', async () => {
  const data = await fetchUser();
    expect(data.name).toEqual('Leanne Graham');
  });
```

More code in: https://github.com/academind/js-testing-introduction/tree/async-code


# Firebase Functions Unit Testing with Jest

Youtube video:
<a href="https://www.youtube.com/watch?v=8IoCPZJ-zwA">https://www.youtube.com/watch?v=8IoCPZJ-zwA</a>

Github example:
<a href="https://github.com/ssagga/firebase-emulators-testing-with-jest/tree/master/functions">https://github.com/ssagga/firebase-emulators-testing-with-jest/tree/master/functions</a>

Documentation:
<a href="https://firebase.google.com/docs/rules/unit-tests">https://firebase.google.com/docs/rules/unit-tests</a>

Local example:
`E:\NMS\PROGRAMACION_NMS\CENTRALHUB\CH_SCRAPER\APPSEARCH_FIRESTORE_FUNCTIONS\functions`

Example Folder Structure:

myapp
├── node_modules
├── firebase.json
├── firestore.indexes.json
├── firestore.rules
├── functions
│   ├── node_modules
│   ├── index.js
│   ├── jest.config.js
│   ├── jsconfig.json
│   ├── package-lock.json
│   ├── package.json
│   ├── src
│   │   ├── __tests__
│   │   │   └── mymodule.test.js
│   │   ├── change_appsearch.js
│   │   ├── change_firestore.js
│   │   ├── testCollectionTriggers.js
│   │   └── testing.js
│   └── ui-debug.log
├── package-lock.json
├── package.json
└── ui-debug.log

To run:
```bash
#in one terminal
firebase emulators:start
#in a different terminal
cd functions
jest
```

`functions/jest.config.js`
```js
module.exports = {
    testRegex: 'src(/__tests__/.*|(\\.|/)(test|spec))\\.(jsx?|tsx?)$',
    testPathIgnorePatterns: ['lib/', 'node_modules/'],
    moduleFileExtensions: ['js','ts','tsx','jsx','json','node'],
    testEnvironment: 'node',
    rootDir: 'src'
}
```

`functions/jsconfig.json`
```json
{
    "typeAcquisition": {
        "include": [
            "jest"
        ]
    }
}
```

To run tests sequentially instead of in parallel use `jest --runInBand`. It is necessary when running firestore test to prevent one test to influence the other.
`functions/package.json`
```json
  "scripts": {
    ...
    "test": "jest '\\__tests__\\.*.test.js' --runInBand"
  },
```

`functions/src/__tests__/mymodule.test.js`
```js
const firebase = require('@firebase/testing')
const admin = require('firebase-admin')

test('Should be 1', ()=> {
    expect(1).toBe(1);
})

const projectId = "rich-meridian-274818"
process.env.GCLOUD_PROJECT = projectId
process.env.FIRESTORE_EMULATOR_HOST = "localhost:8080";
let app = admin.initializeApp({projectId})
let db = firebase.firestore(app)

beforeAll(async ()=>{
    await firebase.clearFirestoreData({projectId});
})

// When Document written to '/TestCollection/{DocumentId}' , trigger function to copy it to '/Copies/{DocumentId}
test("Expect to find a copy in 'Copies' Collection", async ()=>{
    const testDoc = {
        name: 'Samer',
        age: 21,
        city: 'Riyadh'
    }
    const ref = db.collection('TestCollection').doc()
    await ref.set(testDoc)
    const copyId = ref.id
    const copyRef = db.collection('Copies').doc(copyId)
    await new Promise((r)=>setTimeout(r, 3000))
    const copyDoc = await copyRef.get()
    expect(copyDoc.data()).toStrictEqual(testDoc)
})
```

onCreate function:
```js
const functions = require('firebase-functions');
const admin = require("firebase-admin")

// admin.initializeApp(); //initialized in index.js
const db = admin.firestore()

exports.onCreate = functions.firestore.document('TestCollection/{docId}').onCreate(async (snapshot)=>{
    const data = snapshot.data()
    const docId = snapshot.id
    const copyRef = db.collection('Copies').doc(docId)
    await copyRef.set(data)
})
```