1

Maybe I am so badly dumb, but I cannot understand what jest.fn() does precisely and how it is used. I am new to testing and I've got basicly most functionality of jest, but jest.fn() makes me shaking.

I tried to refer to docs, watch tutorials, but all I know at the moment is that jest.fn() can spy on a function or a method.

Why do we need it if we can check the returned value with .toBe or .toEqual, check its existence with .toBeDefined() and its parameters with .toBeCalledWith()?

I'm struggling with it for about a week. I am definetely missing something but I have noone to ask.

Firanolfind
  • 1,559
  • 2
  • 17
  • 36
  • 1
    Have you heard of [mock functions](https://jestjs.io/docs/en/mock-functions)? The linked doc page contains a good example for using `jest.fn` to see if a callback passed to a function is getting executed (and with what parameter it was called). Spying, e.g. with `.toBeCalledWith()`, is also only avaiable on mock functions afaik. This [SO question](https://stackoverflow.com/questions/40992628/how-does-jest-fn-work) also discusses your question. – FK82 Jul 28 '18 at 15:25
  • Yes, I've heard of them and I saw that example but something was missing for me. Now, after @Sergeon 's explaination that very example makes sense for me. – Alexander Prisazhny Jul 29 '18 at 06:53

1 Answers1

2

The problem that mocks and stubs are intended to solve, is that you usually don't want to really call some methods or dependencies in your test, because:

  • They are unreliable, like http requests:

    If you have a module than display a list of users grabbed from the internet, when you test your module you don't want your test to fail due to bad network connectivity, lack of credentials etc. etc.

  • They are difficult to set up in your tests:

    Some modules or dependencies requires a lot of parameters/setup conditions to be able to be used by the module under test, thus making it difficult and error prone to be tested. By mocking or stubbing such a dependency you can test the logic of the module under test without having to handle the burden of managing the dependency needs.

  • They have their own tests:

    If you're testing a carousel module, which relies on an i18n module, and you have yet tested your i18n module, you don't want to test that it works properly again. You mock it, so you're free to the i18n module setup and dependencies.

  • They are computationally intense:

    Let's say you want to test a react/Angular/Vue... component that display UI dashboard and menus for a web videogame. You absolutely don't want to actually have the game running while you test that the navbar of the game dashboard behaves as expected.

So, while testing, you end up mocking and stubbing a lot of dependencies, should they be functions that perform http calls or structural modules like a flux store or a i18n plugin.

jest.fn() in particular does this at the level of functions. For instance you're testing a vue component that in its created() hook calls some method that performs something you don't want to deal with in your test:

maybe it calls an API, mess with local storage or do something computationally intense. So you spy that method placing jest.fn() in its place, and you just assert that it gets called when it should.

Sergeon
  • 6,638
  • 2
  • 23
  • 43
  • Awesome! I think I finally got it. Jest.fn() becomes a supplement for a functionality we don't care about in a particular test and it has a convenient API to simulate cases of its behaviour, is this right? – Alexander Prisazhny Jul 28 '18 at 16:48
  • 1
    Right! Also, if we care about only about the function return value, disregaerding its parameters or dependencies, we can setup a jest.fn to return a specific value: https://jestjs.io/docs/en/mock-functions#mock-return-values – Sergeon Jul 28 '18 at 18:47
  • Brilliant! I cannot be thankful enough for your explicit explaination of the most common use cases and basic concepts! – Alexander Prisazhny Jul 28 '18 at 22:27