简体   繁体   中英

How to mock Axios inside a custom function?

Question

How can I mock axios.get() when it is inside my own custom function?

I am completely lost at this point. Hope someone can see what I am doing wrong.

Details

I have the below getString() function which downloads the html from a website and returns a value > 0 if the string was found and -1 if string not found.

Since getString() uses axios.get() to download the html, I would like to Jest mock this call.

This article is the closest I can find to my situation, but in his case, he mocks a standalone axios.request() , where mine axios.get() is inside my custom getString() .

My attempt is this:

getString.test.js

const axios = require('axios');
const getString = require('./getString');

jest.mock('./getString', () => {
  return {
    baseURL: 'localhost',
    get: jest.fn().mockResolvedValue({
      data: 'xxx If you are the website administrator xxx'
    }),
  }
});

packages.json

{
  "name": "jest",
  "version": "1.0.0",
  "description": "",
  "main": "getString.js",
  "scripts": {
    "test": "jest"
  },
  "keywords": [],
  "author": "",
  "license": "ISC"
}

I have done npm init -y && npm install --save-dev jest , but npm run test gives me

$ npm run test

> jest@1.0.0 test /home/mje/projects/jest
> jest

sh: jest: command not found
npm ERR! code ELIFECYCLE
npm ERR! syscall spawn
npm ERR! file sh
npm ERR! errno ENOENT
npm ERR! jest@1.0.0 test: `jest`
npm ERR! spawn ENOENT
npm ERR! 
npm ERR! Failed at the jest@1.0.0 test script.
npm ERR! This is probably not a problem with npm. There is likely additional logging output above.
npm WARN Local package.json exists, but node_modules missing, did you mean to install?

The simple PoC works from the docs .

index.js

const getString = require('./getString');

(async function(){
  'use strict'

  const isOk = await getString({
    url:          'http://localhost',
    string:       'If you are the website administrator',
    timeout:      1000,
    maxRedirects: 0
  });

  console.log(isOk);
})();

getString.js

const axios = require('axios');
const qs = require('qs');

module.exports = async (options) => {
  options              = options || {};
  options.url          = options.url || {};
  options.string       = options.string || null;
  options.timeout      = options.timeout || 1000;
  options.maxRedirects = options.maxRedirects || 0;

  try {
    const response = await axios.get(options.url, {
      timeout: options.timeout,
      maxRedirects: options.maxRedirects,
      validateStatus: null,
      transformResponse: [function (data) {
        return data.search(options.string);
  }]
    });
    return await response.data;
  } catch (error) {
    return -1;
  }
};

First verify if jest is within your dependencies, and if it's not - install it

yarn add --dev jest || npm i -D jest

and then test your implementation by mocking axios rather than the implementation that you want to test.

And the rest of the getString could look something like this

const axios = require('axios');
const getString = require('./getString');

jest.mock('axios')

const mockResponseData = {
  hello: "world"
}

describe('getString', () => {
  describe('axios returning resolved promise', () => {
    beforeAll(() => {
      // returning transformed mock
      axios.get.mockResolvedValue({
        data: mockResponseData
      })
    })

    describe('called with arguments', () => {
      let result
      beforeAll(() => {
        result = getString({
          url: 'http://localhost',
          string: 'If you are the website administrator',
          timeout: 1000,
          maxRedirects: 0
        })
      })

      it('should call axios.get', async () => {
        await result
        expect(axios.get).toHaveBeenCalledWith(
          "http://localhost",
          {
            "maxRedirects": 0,
            "timeout": 1000,
            "transformResponse": [
              expect.any(Function)
            ],
            "validateStatus": null
          }
        )
      })

      it('should return the response.data', async () => {
        expect(await result).toEqual(mockResponseData)
      })
    })
  })

  describe('axios returning rejected promise', () => {
    beforeAll(() => {
      // returning transformed mock
      axios.get.mockRejectedValue({
        data: mockResponseData
      })
    })

    describe('called with arguments', () => {
      let result
      beforeAll(() => {
        result = getString({
          url: 'http://localhost',
          string: 'If you are the website administrator',
          timeout: 1000,
          maxRedirects: 0
        })
      })

      it('should return -1', async () => {
        expect(await result).toEqual(-1)
      })
    })
  })
})

Edit: in order to achieve 100% coverage you'll also have to test your implementation's transformResponse and in order to do that you can mock the implementation like this

// this is not tested
import mockResponseBody from './localMock.json';

axios.get.mockImplementation((url, { transformResponse }) =>
    Promise.resolve({
        data: transformResponse.reduce((acc, fn) => fn(acc), mockResponseData)
    })
)


working example

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM