As a front-end engineer by profession, and having a few JavaScript open source projects myself, I’ve faced some challenges around unit testing, in my particular case, with Jest.
For several times I question myself: “How did the test get to the point in which it’s so much more complex to implement than the feature itself?” - It’s usually like that, don’t take me wrong here, I’m just referring to extreme cases, where 3rd party libraries or even architectural decisions, make your code super hard to test.
Nevertheless, I wanted to share with you a super pragmatic and short list of tips that might help you get that tricky stubborn mock to work.
»1. Mocking defaults
In this example, I mock a 3rd party dependency called ScottHamper/Cookies. This 3rd party exports only a default property that is a wrapper to all the cookie operations that one can perform. Internally it’s actually implemented as a singleton. The trick is to use __esModule: true
flag within the jest.mock
call.
»2. Mocking files that don’t exist in the file system! 🤯
If you depend on a file that is generated at runtime, or a file that only exists in the context of the client (e.g., a runtime configuration file), this file it’s not most likely in your filesystem when you trigger the test, but your program depends on it to run. There’s a way to mock this nonexistent file with Jest, one just needs to make use of the mock configuration flag virtual.
»3. Complex/large assertions on function calls
Consider the following scenario where you have a set of star wars characters and you can fetch them according to different kinds of sorting options.
(Note! let’s ignore the return value, let’s say we were only interested in knowing whether or not
sortedByName
function was called).
You might have seen the following testing code somewhere:
source: https://imgflip.com/memegenerator/31952703/morpheus
In this cases, you can make use of mockFn.mock.calls to assert on the arguments that were passed into the function call, and you can use snapshot testing in order to keep your test case gracefully thin.
»4. Inline require to mock large datasets
In the event of facing the ideal scenario where you need to mock a full JSON API response, you might want to place your JSON separate file and then use an inline require statement to mimic a response for a particular method.
Let’s again make use of the previous example with data from the SWAPI (The Star Wars API).
If you would have a static list of all characters in you program, or a mock of a response that you would
want to use within your test case, you case use an inline require
statement (in alternative of importing the mock on the top of the file).
»5. Make use of async/await
It might also come the time where you need to perform some asynchronous work inside your test case, in that case, don’t hesitate in recurring to async/await.
Oh, and there’s also .resolves.
Do you have more tips that in your opinion, fit nicely in this list? I would love to hear them.
»Updates
- I talked about this on the JavaScript Jabber Podcast, you can listen to the episode here: JSJ 411: Unit Testing Jest with Daniel Caldas
- My friend @ayusharma_ told me that I should mention jest.doMock in this article. So here it is:
When using babel-jest, calls to mock will automatically be hoisted to the top of the code block. Use this method if you want to explicitly avoid this behavior.
Think of jest.doMock
as a resource for you to mock differently the same module in various test cases that live under the same test file.
Cheers!