JavaScript Testing (JEST)

We learn about Jest and mocks here

What is Mocking?

Mocking video

Let's say in our app, we need to call an API. loadTitle is a function that calls fetchData function. fetchData function is placed in http.js file. fetchData function then calls axios package and this axios has .get method that calls API and returns the data.

fetchData function gets back that data and extracts the title in it and sends it back to it's caller who is loadTitle. loadTitle function converts this title into upper case (transformed text is sent back) and sends it back.

Nothing mocked yet

Now let's say we are writing a test to test if loadTitle() returns properly transformed upper case text. But when we test this, we need to call loadTitle which in turn calls fetchData which then calls axios.get() and makes an API request.

For testing our loadTitle function we need to avoid somehow calling API. Let's step back and think what can be done. Let's answer this question, what if loadTitle gets the data from fetchData is not the data coming from the API! That's still Ok right as we don't care from where the data is coming back into loadTitle function. All we care about in the test is whether or not the loadTitle test is passing or not, meaning if loadTitle function is able to convert the data coming from fetchData to upper case or not.

So we have two options here.

  • We can either make fetchData function return a mocked data back to loadTitle instead of fetchData reaching axios

  • The second option is to make axios.get() return the mocked data instead of axios.get() calling an API

How to Mock

Mocking fetchData function

Mocking the fetchData function call

So in option 1, we mock the fetchData function placed inside http.js file. How to do that?

  • Create a __mocks __ folder and add http.js file inside it. This is the file where the original fetchData function is exported.

  • Write a mocked function to return what you want

  • Inside the test, place this code jest.mock('./http.js')

  • Now the mocked fetchData is called

Mocking axios package (basically mocking axios.get() function to be specific)

Mocking axios(package's) get function

In option 2, we mock the axios.get function. How to do that?

  • Inside the __mocks__ folder create the file with the package name you need to mock, axios.js in this case. So the file will be axios.js

  • Write a function here called get() and export it. Make sure it returns a promise like below

get() returns promise mock data - 1st way with Promise.resolve, no async keyword

You can also make this function async so that it returns a promise by default so that you don't have to use Promise.resolve but straight away return the object.

get() returns a promise mock data - 2nd way with async keyword, no promise.resolve
  • Now the test runs without jest.mock as, when it hits the axios package, it looks at mocks folder and automatically picks that up

Code

index.html
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <link rel="stylesheet" href="styles.css">
    <title>JS Testing</title>
</head>

 <body>
    <section class="control-panel">
        <button id="btnAddUser" class="button">Add User</button>
    </section>
    <script src="dist/main.js"></script>
</body>

</html>
app.js
const {printTitle} = require('./util')
const button = document.querySelector('button')

button.addEventListener('click',printTitle)

exports.printTitle = printTitles
http.js
const axios = require('axios')
const fetchData = () => {
    console.log('This is coming from main fetched data')
    return axios.get('https://jsonplaceholder.typicode.com/todos/1')
            .then(response => {
                console.log('This is coming from main axios data')
                return response.data
            })
}

exports.fetchData = fetchData
__mocks__/http.js
const fetchData = () => {
    // return axios.get('https://jsonplaceholder.typicode.com/todos/1')
    //         .then(response => response.data)

    // above is mocked
    console.log('This is coming from mocked fetched data')

    return Promise.resolve({
        title :'delectus aut autem'
    })
}

exports.fetchData = fetchData_httjs
__mocks__/axios.js
const get = async(url) => {
    console.log('This is coming from mocked axios data')
    //  return Promise.resolve({data:{
    //      title:'delectus aut autem'
    //  }})
     return {data:{
        title:'delectus aut autem'
    }}
}

exports.get = get
package.json
{
  "name": "js-testing-introduction",
  "version": "1.0.0",
  "description": "An introduction to JS testing",
  "main": "app.js",
  "scripts": {
    "start": "webpack app.js --mode development --watch",
    "test": "jest"
  },
  "keywords": [
    "js",
    "javascript",
    "testing",
    "jest",
    "unit",
    "tests",
    "integration",
    "tests",
    "e2e",
    "tests"
  ],
  "author": "Maximilian Schwarzmรผller/ Academind GmbH",
  "license": "ISC",
  "devDependencies": {
    "jest": "^23.6.0",
    "webpack": "^4.20.2",
    "webpack-cli": "^3.1.2"
  },
  "dependencies": {
    "axios": "^0.18.0 "
  }

Last updated

Was this helpful?