<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Mattiz</title>
    <description>The latest articles on DEV Community by Mattiz (@mattiz).</description>
    <link>https://dev.to/mattiz</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1283246%2Fd1b2c22e-98b6-4f8e-8690-32496cfb54b6.png</url>
      <title>DEV Community: Mattiz</title>
      <link>https://dev.to/mattiz</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/mattiz"/>
    <language>en</language>
    <item>
      <title>Mock modules properly with Jest and Typescript</title>
      <dc:creator>Mattiz</dc:creator>
      <pubDate>Sat, 17 Feb 2024 15:32:44 +0000</pubDate>
      <link>https://dev.to/mattiz/mock-modules-properly-with-jest-and-typescript-3nao</link>
      <guid>https://dev.to/mattiz/mock-modules-properly-with-jest-and-typescript-3nao</guid>
      <description>&lt;p&gt;Jest provides a comprehensive suite of features designed to easily mock JavaScript modules.&lt;br&gt;
At its core lies a concept that many developers will struggle with, if they haven't read carefully the documentation: the hoisting of mocks.&lt;br&gt;
This often leads to unnecessary long and messy mock-related code, strange errors, and poor typings.&lt;br&gt;
This article exposes the best way to succinctly and efficiently mock an ESM module, with strong typings.&lt;/p&gt;

&lt;h3&gt;
  
  
  How do I do it?
&lt;/h3&gt;

&lt;p&gt;For the readers in a hurry, here you have it:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;foo&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;some-module&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="c1"&gt;// Mocked module&lt;/span&gt;

&lt;span class="nx"&gt;jest&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;mock&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;some-module&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;mockFoo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;jest&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;mocked&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;foo&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;code&gt;jest.mocked()&lt;/code&gt; is only avaivable in Jest v27+.&lt;br&gt;
Be sure you have installed &lt;code&gt;@types/jest&lt;/code&gt; in your project, otherwise Typescript may not be aware of it.&lt;br&gt;
🌵 Do not confuse it &lt;code&gt;jest.mocked()&lt;/code&gt; with &lt;code&gt;jest.mock()&lt;/code&gt;!&lt;/p&gt;

&lt;p&gt;For older versions of Jest, use the form below, which will work in any version of Jest with Typescript support.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;foo&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;some-module&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="c1"&gt;// Mocked module&lt;/span&gt;

&lt;span class="nx"&gt;jest&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;mock&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;some-module&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;mockFoo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;foo&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;jest&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;MockedFunction&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;foo&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;




&lt;p&gt;You can then ensure your mock is properly typed by using &lt;code&gt;mockReturnValue&lt;/code&gt;&lt;/p&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;

&lt;p&gt;&lt;span class="nx"&gt;mockFoo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;mockReturnValue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// Works&lt;/span&gt;&lt;br&gt;
&lt;span class="nx"&gt;mockFoo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;mockReturnValue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;a&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// Typescript error: foo must return a number&lt;/span&gt;&lt;/p&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h3&gt;
&lt;br&gt;
  &lt;br&gt;
  &lt;br&gt;
  Under the hood&lt;br&gt;
&lt;/h3&gt;

&lt;p&gt;Understanding what happens will prevent you some headaches in the future.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Did you ever wonder why Jest is called like this?&lt;br&gt;
While the authors did not state why this exact name why chosen, I like to think that it is because the framework likes to "mock" and do tricks. 🤡&lt;br&gt;
In our example, Typescript is the victim. 😢&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6jys0xq8n4nsp92t1aen.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6jys0xq8n4nsp92t1aen.png" alt="Jest mock hoisting"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Jest hoists mocks&lt;/strong&gt;&lt;br&gt;
Jest processes the mocks definitions &lt;em&gt;before&lt;/em&gt; the imports.&lt;br&gt;
This process is called &lt;em&gt;mock hoisting&lt;/em&gt; and can be confusing at first.&lt;br&gt;
  🐨 Tips: I like to add the &lt;code&gt;// Mocked module&lt;/code&gt; comment next to the mocked import, to make it obvious to everybody that we are dealing with a mocked module.  &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;jest.mock()&lt;/code&gt; replaces all functions of the module by mock functions&lt;/strong&gt;&lt;br&gt;
  You therefore don't need to define those mocks by hand.&lt;br&gt;
  Thanks to &lt;em&gt;mock hoisting&lt;/em&gt;, you can import them through the usual &lt;code&gt;import&lt;/code&gt; keyword.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Typescript needs helps&lt;/strong&gt;&lt;br&gt;
  Typescript does not know about Jest's hoisting shenanigans; and think the function is imported without alterations.&lt;br&gt;
  There are various ways to hint Typescript that the function is a mock, depending on your needs and your preferences.&lt;/p&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;

&lt;p&gt;&lt;span class="c1"&gt;// A bit verbose, but works everywhere.&lt;/span&gt;&lt;br&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;mockFoo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;foo&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;jest&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;MockedFunction&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;foo&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;span class="c1"&gt;// Equivalent to the 1rst form.&lt;/span&gt;&lt;br&gt;
&lt;span class="c1"&gt;// From jest 27+&lt;/span&gt;&lt;br&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;mockFoo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;jest&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;mocked&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;foo&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;span class="c1"&gt;// A less verbose form, but you won't benefit from type-checking when mocking the returned value.&lt;/span&gt;&lt;br&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;mockFoo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;foo&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;jest&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Mock&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;span class="c1"&gt;// For one-time use, if you want to save a line not creating a variable.&lt;/span&gt;&lt;br&gt;
&lt;span class="nx"&gt;jest&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;mocked&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;foo&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toHaveBeenCalled&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;span class="c1"&gt;// For one-time use 🤮&lt;/span&gt;&lt;br&gt;
&lt;span class="p"&gt;;(&lt;/span&gt;&lt;span class="nx"&gt;foo&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;jest&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Mock&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toHaveBeenCalled&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;/p&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h3&gt;
&lt;br&gt;
  &lt;br&gt;
  &lt;br&gt;
  Scope&lt;br&gt;
&lt;/h3&gt;

&lt;p&gt;In this article, in order to bring the focus on principles linked to writing and typing Jest mocks, the focus was on ESM modules, with exported named functions.&lt;br&gt;
This is probably the most common form of modules that you'll encounter, when consuming a library.&lt;br&gt;
Mocking CommonJs (&lt;code&gt;require&lt;/code&gt;), default exports or classes could be covered in an future article.&lt;/p&gt;

</description>
      <category>testing</category>
      <category>jest</category>
      <category>typescript</category>
      <category>mock</category>
    </item>
  </channel>
</rss>
