1

I am trying to write a test that uses a mock implementation of request-promise with defaults set.

In my code, I require request using const request = require('request-promise').defaults({ jar: true });

In my test file, I have tried

const request = require('request-promise');

jest.mock('request-promise');
request.mockImplementation(() => Promise.resolve(JSON.stringify(someVar)));

// This returns the error 'TypeError: request is not a function'
const request = require('request-promise').defaults({ jar: true });

jest.mock('request-promise');
request.mockImplementation(() => Promise.resolve(JSON.stringify(someVar)));

// This returns the error 'TypeError: Cannot read property 'mockImplementation' of undefined'
const request = require('request-promise').defaults({ jar: true });

jest.mock('request-promise').defaults({ jar: true });
request.mockImplementation(() => Promise.resolve(JSON.stringify(someVar)));

// This returns the error 'TypeError: jest.mock(...).defaults is not a function'
const request = require('request-promise').defaults({ jar: true });

jest.mock(('request-promise').defaults({ jar: true }));
request.mockImplementation(() => Promise.resolve(JSON.stringify(someVar)));

// This returns the error 'TypeError: "request-promise".defaults is not a function'

My function looks like

const request = require('request-promise').defaults({ jar: true });

const getData = async function getData(
  previousRequestResponse,
  uniqueId,
) {

  // Below function carries out some manipulation of previous response
  const body = await getRequestBody(previousRequestResponse);

  const response = await request(method, url, body, headers)
    .then(response => JSON.parse(response.body))
    .catch((err) => {
      Logger.error('Failed');
      Logger.error(`ERROR - ${err.message}`);
      throw err;
    });

  const newResponse = manipulate(response);

  return newResponse;
};

I want to mock request, so that response is a stubbed value and I can assert the correct value is returned at the end of the function.

Heather
  • 41
  • 2
  • 5
  • Hi @Heather, can you further elaborate on what are you trying to achieve? I get that you have in your code something like `request.defaults({ jar: true })`. What are you trying to test? – mgarcia Apr 18 '20 at 10:07
  • @mgarcia Thanks for replying! So, in my code I have a function that uses request to make multiple calls to a 3rd party API. Each call uses the cookies from the last, hence the need to add the jar. Thanks for looking @mg When testing this function, I want to mock these calls, using jest.mock so instead of actually calling the 3rd party API, they just return a stub, in this example `someVar`. I will then assert that when calling my function, I get the expected result based on my stubbed data. Hope that makes a bit more sense. – Heather Apr 18 '20 at 14:37
  • Mmm, maybe you can the calls done with `request-promise` without having to mock the `defaults` call. If you could show the minimal, relevant version of the code you are trying to test I could set a test example. – mgarcia Apr 18 '20 at 18:31
  • I have tried to add some additional info above and an example of my code. Hope this helps! – Heather Apr 19 '20 at 13:18

1 Answers1

4

If you want to mock the request-promise module you can do it using the jest.mock method and providing the factory parameter.

If you were to test your getData method you can create a factory that looks like:

jest.mock('request-promise', () => {
    const mock = {
        __esModule: true,
        default: (method, url, body, headers) => Promise.resolve({
            body: JSON.stringify([])
        }),
        defaults: () => mock.default
    };

    return mock;
});

With this code, your calls to request will always return an object with a body property that contains an empty array (as string so that the JSON.parse call in the getData method can parse it).

Appendix: Why the attempts you tried so far were not successful

Attempt 1

const request = require('request-promise');

jest.mock('request-promise');
request.mockImplementation(() => Promise.resolve(JSON.stringify(someVar)));

Here you are calling jest.mock on the module without a factory parameter. Thus, jest will auto-mock all the module methods and they will all return undefined when called. Hence, when in your code you import the module and call the defaults method:

const request = require('request-promise').defaults({ jar: true });

the request variable results in undefined. Later, when you call the request method it throws:

'TypeError: request is not a function'

Attempt 2

const request = require('request-promise').defaults({ jar: true });

jest.mock('request-promise');
request.mockImplementation(() => Promise.resolve(JSON.stringify(someVar)));

The same logic of the previous attempt applies here. The request variable will be undefined and when you try to call the mockImplementation method it throws:

'TypeError: Cannot read property 'mockImplementation' of undefined'

Attempt 3

const request = require('request-promise').defaults({ jar: true });

jest.mock('request-promise').defaults({ jar: true });
request.mockImplementation(() => Promise.resolve(JSON.stringify(someVar)));

Here you are calling the method defaults on the returning value of the call to jest.mock. As the call to jest.mock does not return your mocked version of the request-promise module, it does not contain a defaults method. So, when you call that method it throws:

'TypeError: jest.mock(...).defaults is not a function'

Attempt 4

const request = require('request-promise').defaults({ jar: true });

jest.mock(('request-promise').defaults({ jar: true }));
request.mockImplementation(() => Promise.resolve(JSON.stringify(someVar)));

In this attempt you are trying to call a defaults method from the string request-promise. Strings have no such method, so calling it throws:

'TypeError: "request-promise".defaults is not a function'

mgarcia
  • 5,669
  • 3
  • 16
  • 35