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)