Sandra Schlichting
Sandra Schlichting

Reputation: 26046

Why do Jest give ReferenceError's?

Question

Can anyone figure out, why I get this error?:

● Test suite failed to run

  ReferenceError: Cannot access 'mockResponseData' before initialization

  > 1 | const axios = require('axios');
      |               ^

Here is a online version. https://repl.it/@SandraSchlichti/jest-playground-2#getStatusCode.test.js

getStatusCode.test.js

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

const mockResponseData = {
  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'
  }
};

// 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: mockResponseData
    })
  };
});

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();
  });

  describe('return value', () => {
    it('should be greater than or equal to zero', () => {
      expect(response).toBeGreaterThanOrEqual(0)
    })

      describe('have mocked axios.get() returned data.status', () => {
        it('should have returned 301', async () => {
          expect(await axios.get.mock.results[0].value).toHaveProperty('data.status', 301)
        })
      })
    })

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

    describe('called with arguments', () => {
      let response;
      beforeAll(async () => {
        response = await getStatusCode({
          url: 'https://google.com',
          statusCode: 200,
          timeout: 1000,
          maxRedirects: 0
        });
      });

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

});

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);


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

Upvotes: 3

Views: 508

Answers (1)

Teneff
Teneff

Reputation: 32148

Jest hoists all of the calls to jest.mock on the top of the scope (it's mentioned in few places in the documentation). And even though it's also mentioned that the variables prefixed with mock will also be hoisted apparently they go below the jest.mock calls causing this error to happen.

I can advice you to use the auto-mocking feature of jest

import axios from 'axios';

jest.mock('axios')

// and then you'll be able to mock it's return value
axios.get.mockResolvedValue({
  data: mockResponseData
})

it will include the module and will generate a mock function for each of it's methods. And it's biggest benefit is whenever a library method is removed jest won't generate a mock function for it and your test will fail.

repl.it example

Upvotes: 3

Related Questions