How to insert the correct response data into Jest?

Viewed 315

Based on the excellent answers I am attempting to implement JestJS on a similar function.

Question

The problem seams to be how I am inserting the mocked response data in jest.mock(). Below have I described and included all the files I have used.

Can anyone figure out what I am doing wrong?

Here is a live version to try out. https://repl.it/@SandraSchlichti/jest-playground-1#getStatusCode.js

Background

First I dump the correct response data by

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

getStatusCode({
  url: 'https://google.com',
  statusCode: 200,
  timeout: 1000,
  maxRedirects: 0
});

getStatusCode.js

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

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

  try {
    const response = await axios.get(options.url, {
      timeout: options.timeout,
      maxRedirects: options.maxRedirects,
      // make all http status codes a success
      validateStatus: function (status) {
        return true;
      }
  });

    console.log(response); // here just to get the response data for Jest

    return (response.status === options.statusCode) ? 1 : 0;
  } catch (error) {
    return -1;
  }
};

which gives a very large output:

{
  status: 301,
  statusText: 'Moved Permanently',
  headers: {
    location: 'https://www.google.com/',
    'content-type': 'text/html; charset=UTF-8',
    date: 'Thu, 12 Nov 2020 10:48:21 GMT',
    expires: 'Sat, 12 Dec 2020 10:48:21 GMT',
    'cache-control': 'public, max-age=2592000',
    server: 'gws',
    'content-length': '220',
    'x-xss-protection': '0',
    'x-frame-options': 'SAMEORIGIN',
    'alt-svc': 'h3-Q050=":443"; ma=2592000,h3-29=":443"; ma=2592000,h3-T051=":443"; ma=2592000,h3-Q046=":443"; ma=2592000,h3-Q043=":443"; ma=2592000,quic=":443"; ma=2592000; v="46,43"',
    connection: 'close'
  },
  config: {
...

Since I am only interested in the value of status, I just copy/paste the first section into data of my getStatusCode.test.js file.

getStatusCode.test.js

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

// whenever Axios is called from getStatusCode() it won't make a network
// connection, but return the following instead
jest.mock("axios", () => {
  return {
    get: jest.fn().mockResolvedValue({
      data:
      {
        status: 301,
        statusText: 'Moved Permanently',
        headers: {
          location: 'https://www.google.com/',
          'content-type': 'text/html; charset=UTF-8',
          date: 'Thu, 12 Nov 2020 10:09:41 GMT',
          expires: 'Sat, 12 Dec 2020 10:09:41 GMT',
          'cache-control': 'public, max-age=2592000',
          server: 'gws',
          'content-length': '220',
          'x-xss-protection': '0',
          'x-frame-options': 'SAMEORIGIN',
          'alt-svc': 'h3-Q050=":443"; ma=2592000,h3-29=":443"; ma=2592000,h3-T051=":443"; ma=2592000,h3-Q046=":443"; ma=2592000,h3-Q043=":443"; ma=2592000,quic=":443"; ma=2592000; v="46,43"',
          connection: 'close'
        }
      }
    })
  };
});

describe("test getStatusCode ", () => {
  // pretend to get data from the network connection
  let response;
  beforeAll(async () => {
    response = await getStatusCode({
      url: 'https://google.com',
      statusCode: 200,
      timeout: 1000,
      maxRedirects: 0
    });
  });

  // compare returned data with expected
  it("fetches raw response but we are only interested in the statuscode", async () => {
    // ensure the mocked Axios function has been called
    expect(axios.get).toHaveBeenCalled();

    expect(response.status).toBeGreaterThan(0);
  });

});

Running npm run test gives me

 FAIL  ./getStatusCode.test.js
  ● Console

    console.log
      {
        data: {
          status: 301,
          statusText: 'Moved Permanently',
          headers: {
            location: 'https://www.google.com/',
            'content-type': 'text/html; charset=UTF-8',
            date: 'Thu, 12 Nov 2020 10:09:41 GMT',
            expires: 'Sat, 12 Dec 2020 10:09:41 GMT',
            'cache-control': 'public, max-age=2592000',
            server: 'gws',
            'content-length': '220',
            'x-xss-protection': '0',
            'x-frame-options': 'SAMEORIGIN',
            'alt-svc': 'h3-Q050=":443"; ma=2592000,h3-29=":443"; ma=2592000,h3-T051=":443"; ma=2592000,h3-Q046=":443"; ma=2592000,h3-Q043=":443"; ma=2592000,quic=":443"; ma=2592000; v="46,43"',
            connection: 'close'
          }
        }
      }

and later on

  ● test getStatusCode  › fetches raw response but we are only interested in the statuscode

    expect(received).toBeGreaterThan(expected)

    Matcher error: received value must be a number or bigint

    Received has value: undefined

So clearly I haven't reproduced the response from axios.get() correct.

What am I doing wrong?

1 Answers

Your function getStatusCode checks the response and returns -1 or 0.

So you can't expect it to have a property status

You can check if it is toBeGreaterThanOrEqual to zero

expect(response).toBeGreaterThanOrEqual(0)

working example

Edit: If you want to make an assertion that the mock function have returned a promise resolved with an object that has data.status you can use jest mock function's mock property like this:

expect(await axios.get.mock.results[0].value).toHaveProperty('data.status', 301)

// where axios.get.mock.results is an array with the result for each call
// and "[0].value" is the result for the first call
// which would be a reference to the promise object, hence the await

But generally you want to test your implementation, not the mocked functions

Related