Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do you mock just certain parts of a module with jest?

I've built a calendar around moment.js and I'm working on unit tests right now.

The first problem I solved was how the date will change when the tests run, so I've been able to lock down the moment using this guidance.

Currently, I'm stuck on an error:

"TypeError: Cannot read property 'weekdaysShort' of undefined"

My code has a line: const dateHeaders = moment.weekdaysShort();

By implementing the mocked moment().format(), I've essentially lost the rest of the library.

My immediate question is how I can set up jest to let me return the array that you get from moment.weekdaysShort();

My larger question is whether I've gone down the wrong path and should come up with another strategy.

Things I've tried with unsuccessful results

  1. Manually adding in the weekdayShort function:
const mockMoment = function() {
  return {format: '2016–12–09T12:34:56+00:00'}
};

mockMoment['weekdaysShort'] = () => ['Sun', 'Mon', 'Tues']; // etc etc etc

jest.mock('moment', () => mockMoment);
  1. Assembling a manual mock in a __mocks__ folder. I didn't go too far down this path because it started to feel like I'd have to copy/paste the entire Moment.js library into the mock. And while it'd be cool to figure out how they do what they do, that's a project for another day.
  2. jest.spyOn - doesn't work because I'm not spying on a module.

At this point, I'm considering abandoning the Moment function for an array passed in through props. And while I'm confident that'll get me past this problem, it feels like I'm gonna hit another roadblock quickly afterwards.

Thanks in advance for the help.

like image 407
Marc Avatar asked Dec 10 '19 17:12

Marc


People also ask

How do I mock a function in jest?

Spying on the function using jest.spyOn Another approach to mock a particular function from an imported module is to use the jest.spyOn function. The API for this function seems to be exactly what we need for our use case, as it accepts an entire module and the particular export that should be spied on.

How do I mock only one function of a module?

There are three simple (and a bit confusing) steps of mocking only one function of a module and leaving the rest of it to its default implementation. Create a mock for the entire module. Tell that mock to use actual (non-mocked) implementations for everything. Mock the desired function of the mock. A bit of a tongue twister, isn’t it?

What is the use of @jest requireactual?

jest.requireActual (moduleName) Returns the actual module instead of a mock, bypassing all checks on whether the module should receive a mock implementation or not

Is there a jest testing guide for CommonJS and ES modules?

This isn’t strictly a Jest testing guide, the same principles can be applied to any application/tests that need to mock CommonJS or ES Modules. CommonJS: Node.js’ built-in import system which uses calls to a global require ('module-y') function, packages on npm expose a CommonJS compatible entry file.


Video Answer


1 Answers

Just found out the pattern I commonly use was provided in a 2016 github thread and, in all honesty, that's probably where I found it even though I don't specifically remember it :)

jest.mock('moment', () => 
  const original = jest.requireActual('moment');
  return {
    __esModule: true,
    default: {
       ...original,
       ...just the parts you want to mock
    }
  }
);
like image 199
Adam Avatar answered Oct 10 '22 02:10

Adam