Jest Traversy Tutorial
Local folder:
E:\NMS\CURSOS\SMALL-TUTORIALS\jest-tutorial-traversy
Youtube tutorial link:
https://www.youtube.com/watch?v=7r4xVDI2vho
Github link of tutorial:
https://github.com/bradtraversy/jest_testing_basics
Installation
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
  "scripts": {
    "test": "jest"
  },
How to run tests
npm test
Example functions.test.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
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:
const fetchUser = () => {
  console.log("Using mock function for fetchData")
    return Promise.resolve({name:"Leanne Graham"});
  }
exports.fetchUser = fetchUser;
async.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
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:
https://www.youtube.com/watch?v=8IoCPZJ-zwA
Github example:
https://github.com/ssagga/firebase-emulators-testing-with-jest/tree/master/functions
Documentation:
https://firebase.google.com/docs/rules/unit-tests
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:
#in one terminal
firebase emulators:start
#in a different terminal
cd functions
jest
functions/jest.config.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
{
    "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
  "scripts": {
    ...
    "test": "jest '\\__tests__\\.*.test.js' --runInBand"
  },
functions/src/__tests__/mymodule.test.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:
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)
})
    
Top comments (0)