Jest Mock returns undefined instead of data

Viewed 12446

I'm trying to mock a function and not sure what i'm doing wrong here. I have this function "getGroups"

getGroups:

export const getGroups = async () => {
  try {
    const groupApiUrl = getDashboardPath(GROUPS_TAB_INDEX);
    const data = await fetch(groupApiUrl, { cache: 'force-cache' });
    const userData = await data.json();
    return userData;
  } catch (error) {
    throw Error(error);
  }
};

___mocks___/getGroups.js:

export default async () => {
  return {
    groups: [
      { id: 1, name: 'Data1' },
      { id: 2, name: 'Data2' }
    ]
  };
};

getGroups.test.js:

jest.mock('./getGroups.js');
// eslint-disable-next-line import/first
import { getGroups } from './getGroups';

const fakeRespose = {
  groups: [
    { id: 1, name: 'Data1' },
    { id: 2, name: 'Data2' }
  ]
};

describe('getGroups', () => {
  it('returns data', async () => {
    const data = await getGroups();
    console.log('DATA', data);  <---- UNDEFINED?
    expect(data).toBeDefined();
    expect(data).toMatchObject(fakeRespose);
  });

  it('handles error', async () => {
    // const data = await getGroups();
    await getGroups().toThrow('Failed');
  });
});
2 Answers

What are you doing wrong here?

  1. Default export in your mock instead of named as in the implementation

In your implementation you're using named export and you're importing { getGroups } so to make it work you need to change your mock like this

__mocks__\getGroups.js
export const getGroups = async () => {
  return {
    groups: [
      { id: 1, name: 'Data1' },
      { id: 2, name: 'Data2' }
    ]
  };
};

working example


TL;DR

  1. Testing mock

There is no point at all to test mock function. This does not proves your implementation is working. Even if you change your implementation your tests will still pass.

Use mocks only for the dependencies of your implementation

  1. Use jest.genMockFromModule It will create jest.fn() for each of the module's exported methods and will preserve the constants, allowing you to change the return value/implementation for some test cases and will also be able to write assertions if the function have been called
__mocks__\getGroups.js
const mock = jest.genMockFromModule('../getGroups');
mock.getGroups.mockResolvedValue({
  groups: [
    { id: 1, name: 'Data1' },
    { id: 2, name: 'Data2' }
  ]
})

module.exports = mock;
  1. Jest will automatically hoist jest.mock calls (read more...)

So you can safely leave the import statements first and then call jest.mock

From Jest Docs, here's an example of a Mock.

jest.mock('../moduleName', () => {
  return jest.fn(() => 42);
});

// This runs the function specified as second argument to `jest.mock`.
const moduleName = require('../moduleName');
moduleName(); // Will return '42';

In your case data is undefined, because you haven't actually supplied a mocked implementation for the function or the mock hasn't worked and you're still calling the original function.

Example Reference: https://jestjs.io/docs/en/jest-object#jestmockmodulename-factory-options

However, in your simple case you could also solve this with a spy, either jest.spyOn or jest.fn(). Here are two solutions to what you're trying to achieve. You can look at the code and run it here: https://repl.it/repls/FairUnsungMice

UPDATE after comment:

Manual mocks are defined by writing a module in a __mocks__/ subdirectory immediately adjacent to the module. For example, to mock a module called user in the models directory, create a file called user.js and put it in the models/__mocks__ directory. Note that the __mocks__ folder is case-sensitive, so naming the directory __MOCKS__ will break on some systems.

Double check the naming, directory structure & type of exports you've setup - they should match. Also, it's worth checking this out: https://github.com/facebook/jest/issues/6127 - looks like an open issue with jest. If you need a solution, look at using a different approach as I mentioned.

Reference: https://jestjs.io/docs/en/manual-mocks

Related