banner



How To Mock Service With Ribbonclient Configuration

Cover image for The only 3 steps you need to mock an API call in Jest

Zak Laughton

The only 3 steps you demand to mock an API call in Jest

I recently institute myself working in a Javascript codebase where I needed to implement new Jest tests. I knew very piffling at the time about writing tests, so I looked to Jest docs and existing patterns in the codebase to effigy out all-time practices and how to do it. It was adequately straightforward, and I even plant myself enjoying testing. But I could not for the life of me reliably mock an API call.

Dog with caption "I have no idea what I'm doing"

The docs seemed clear, and the existing code appeared to have practiced patterns, only there were but so many ways to mock things. The existing tests used all sorts of mocking methods such as jest.genMockFromModule(), jest.spyOn(), and jest.mock(). Sometimes the mocks were inline, sometimes they were in variables, and sometimes they were imported and exported in magical means from mysterious __mocks__ folders. I used these techniques interchangeably every fourth dimension I got a flare-up of confidence in agreement, only to find myself stumbling over the dissimilar methods and their effects. I had no idea what I was doing.

The event

The issue was that I was trying to learn how to run before I even knew how to walk. Jest has many powerful ways to mock functions and optimize those mocks, but they're all useless if you don't know how to make a simple mock in the first place. And while the Jest documentation provides a lot of great insight and techniques, I couldn't figure out where to start.

In this commodity, I promise to give you absolute basics to mock an API telephone call so you lot can benefit from my 2020 hindsight (heh). If you're going crazy like I was considering you can't effigy out how to just make a simple damn mock, Start here…

(NOTE: The lawmaking below was written in Node.js, only the mocking concepts also apply to frontend Javascript and ES6 modules)

The unmocked lawmaking

We're going to be testing this getFirstAlbumTitle() function, which fetches an array of albums from an API and returns the title of the first anthology:

                          // index.js              const              axios              =              require              (              '              axios              '              );              async              function              getFirstAlbumTitle              ()              {              const              response              =              await              axios              .              get              (              '              https://jsonplaceholder.typicode.com/albums              '              );              render              response              .              data              [              0              ].              title              ;              }              module              .              exports              =              getFirstAlbumTitle              ;                      

Enter fullscreen mode Exit fullscreen way

...and here'due south our initial mock-less test for this part, which verifies the function actually returns the title of the first album in the list:

                          // alphabetize.test.js              const              getFirstAlbumTitle              =              require              (              '              ./index              '              );              it              (              '              returns the title of the first album              '              ,              async              ()              =>              {              const              championship              =              expect              getFirstAlbumTitle              ();              // Run the function              expect              (              title              ).              toEqual              (              '              quidem molestiae enim              '              );              // Brand an assertion on the result              });                      

Enter fullscreen mode Exit fullscreen mode

The test above does its job, but the exam actually makes a network request to an API when information technology runs. This opens the test up to all sorts of false negatives if the API isn't working exactly every bit expected (e.chiliad. the list order changes, API is downward, dev machine loses network connexion, etc.). Not to mention, making these requests in a large number of tests tin bring your test runs to a slow crawl.

Simply how can we change this? The API request is beingness fabricated with axios as a part of getFirstAlbumTitle(). How in the earth are we supposed to reach inside the function and change the behavior?

Mock it in 3 steps

Alright, hither it is. This is the big hush-hush that would have saved me mountains of fourth dimension as I was wrestling with learning mocks. To mock an API phone call in a role, you only need to exercise these iii steps:

1. Import the module you want to mock into your exam file.
2. jest.mock() the module.
three. Utilize .mockResolvedValue(<mocked response>) to mock the response.

That'southward it!

Hither'southward what our test looks like afterward doing this:

                          // index.test.js              const              getFirstAlbumTitle              =              require              (              '              ./index              '              );              const              axios              =              crave              (              '              axios              '              );              jest              .              mock              (              '              axios              '              );              information technology              (              '              returns the title of the kickoff anthology              '              ,              async              ()              =>              {              axios              .              get              .              mockResolvedValue              ({              data              :              [              {              userId              :              ane              ,              id              :              1              ,              championship              :              '              My First Anthology              '              },              {              userId              :              i              ,              id              :              2              ,              title              :              '              Album: The Sequel              '              }              ]              });              const              title              =              await              getFirstAlbumTitle              ();              await              (              title              ).              toEqual              (              '              My First Album              '              );              });                      

Enter fullscreen style Go out fullscreen mode

What's going on here?

Allow'south break this downward. The most important part to sympathize here is the import and jest.mock():

                          const              axios              =              require              (              '              axios              '              );              jest              .              mock              (              '              axios              '              );                      

Enter fullscreen mode Exit fullscreen mode

When you import a module into a test file, then telephone call it in jest.mock(<module-proper noun>), yous take complete control over all functions from that module, even if they're called inside another imported function. Immediately after calling jest.mock('axios'), Jest replaces every function in the axios module with empty "mock" functions that essentially do nothing and return undefined:

                          const              axios              =              require              (              '              axios              '              );              jest              .              mock              (              '              axios              '              )              // Does cipher, so returns undefined:              axios              .              get              (              '              https://world wide web.google.com              '              )              // Does nothing, then returns undefined:              axios              .              postal service              (              '              https://jsonplaceholder.typicode.com/albums              '              ,              {              id              :              3              ,              title              :              '              Album with a Vengeance              '              })                      

Enter fullscreen mode Get out fullscreen mode

So at present that you've eliminated the default beliefs, y'all tin can replace it with your own...

                          axios              .              get              .              mockResolvedValue              ({              data              :              [              {              userId              :              i              ,              id              :              i              ,              championship              :              '              My First Album              '              },              {              userId              :              1              ,              id              :              2              ,              championship              :              '              Album: The Sequel              '              }              ]              });                      

Enter fullscreen mode Exit fullscreen mode

The mocked replacement functions that Jest inserted into axios happen to come with a whole bunch of absurd superpower methods to control their behavior! The most important one here, for the purposes of a simple beginner mock, is .mockResolvedValue(). When y'all call this on a mocked method, anything you laissez passer in will be the default return value when the mocked function is chosen for the remainder of the test. Just put: you can make axios.get() return whatever you want! And it doesn't matter whether it'southward called direct in your exam file or as a part of a part imported into your examination – Jest will mock the function no matter where information technology'due south chosen!

Apply this newfound power to give your functions exactly what they should expect from the API calls. Finish worrying about what the network requests render, and merely focus on what YOUR lawmaking does once it gets the response!

If y'all want to play around with the examples, feel free to use this demo repository:

Wrapping up

There y'all have information technology! This is the very nuts of what you need to mock functions from some other module: import the module, jest.mock() the module, then insert your own return values with .mockResolvedValue()!

I recommend starting hither, using only these techniques equally yous kickoff building out your kickoff mocks for your network calls. Once you have a foundational understanding of what's going on here, you can slowly start adding the other robust mocking features included in Jest.

See besides: Mocking Modules (Jest documentation).

EDIT: Also, be certain to clear your mocks between tests past running jest.resetAllMocks() afterward each test. This will assist ensure your mocks won't interfere with future tests. (Thanks for pointing this out, @mjeffe!)


Where to go from here

Alright, yous've learned the basics of mocking and successfully implemented the strategies above in several tests. Y'all tin can import and mock resolved values for all your API calls like an erstwhile pro. What's next?

While the methods described above volition cover most simple use cases, Jest has a lot of mocking functionality and methods to do some really powerful things. You can incrementally add some of the concepts below to super-accuse your mocks:

  1. Bank check out the other mock part methods listed in the Jest docs: Mock Functions. You tin use methods such equally mockReturnedValue() to mock synchronous returns and mockResolvedValueOnce() to only render a value the kickoff time it's called.
  2. Want to encounter how many times a mocked role is chosen, what it was called with, and what it returned? Bank check out the mock.calls and mock.results backdrop (also in the Mock Functions documentation)
  3. Exercise you lot accept your own custom functions that brand network requests? You can mock your own modules also subsequently they're imported into the examination file: jest.mock('./path/to/js/module/file')! Careful here though that you're but mocking what's necessary. Your tests should make certain your functions practice what'due south expected with a given mock input, and it can be easy to end up writing tests that instead only confirm you lot passed in mocked information.
  4. Want a role to human action as it was originally written, only withal want to come across how many times it was called? Check out jest.spyOn().
  5. Find yourself mocking the same office over and over in multiple tests? Give it default mock responses in __mocks__ folders using Manual Mocks!

I hope this saves others some of the wasted time and frustration I went through! If anything doesn't make sense here, delight get out a annotate and I'd be happy to attempt to answer any questions. Also, allow me know if in that location's anything else that helped you have an "Aha!" moment while learning to mock!


Did you lot observe this this commodity useful? Feel gratis to subscribe to my articles below or follow me on Twitter for more developer tips and article announcements!

Source: https://dev.to/zaklaughton/the-only-3-steps-you-need-to-mock-an-api-call-in-jest-39mb

Posted by: connellyhica1947.blogspot.com

0 Response to "How To Mock Service With Ribbonclient Configuration"

Post a Comment

Iklan Atas Artikel

Iklan Tengah Artikel 1

Iklan Tengah Artikel 2

Iklan Bawah Artikel