<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/"
    xmlns:atom="http://www.w3.org/2005/Atom" xmlns:media="http://search.yahoo.com/mrss/" version="2.0">
    <channel>
        
        <title>
            <![CDATA[ ِAya Nabil Othman - freeCodeCamp.org ]]>
        </title>
        <description>
            <![CDATA[ Browse thousands of programming tutorials written by experts. Learn Web Development, Data Science, DevOps, Security, and get developer career advice. ]]>
        </description>
        <link>https://www.freecodecamp.org/news/</link>
        <image>
            <url>https://cdn.freecodecamp.org/universal/favicons/favicon.png</url>
            <title>
                <![CDATA[ ِAya Nabil Othman - freeCodeCamp.org ]]>
            </title>
            <link>https://www.freecodecamp.org/news/</link>
        </image>
        <generator>Eleventy</generator>
        <lastBuildDate>Sun, 17 May 2026 11:35:23 +0000</lastBuildDate>
        <atom:link href="https://www.freecodecamp.org/news/author/AyaNabilOthman/rss.xml" rel="self" type="application/rss+xml" />
        <ttl>60</ttl>
        
            <item>
                <title>
                    <![CDATA[ How to Handle Side Effects in Jest – A Guide to Effective Mocking ]]>
                </title>
                <description>
                    <![CDATA[ Unit testing is a major topic for every developer. It is a fundamental practice in building software applications. Unit testing helps you to identify bugs early and makes code maintenance easier. By isolating and testing single units or components of... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-handle-side-effects-in-jest/</link>
                <guid isPermaLink="false">66e89d0c848b849d734302b0</guid>
                
                    <category>
                        <![CDATA[ Testing ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Node.js ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ ِAya Nabil Othman ]]>
                </dc:creator>
                <pubDate>Mon, 16 Sep 2024 21:03:08 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/res/hashnode/image/upload/v1726038899380/6210fc66-17fb-4db9-9f91-1e7d38dc256c.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Unit testing is a major topic for every developer. It is a fundamental practice in building software applications. Unit testing helps you to identify bugs early and makes code maintenance easier. By isolating and testing single units or components of your application, you can ensure their reliability and functionality.</p>
<p>When applying unit testing, you need to focus on the main logic of a component without affecting external dependencies or causing side effects—unintended changes that occur outside a function's scope, like database queries or network requests.</p>
<p>Jest is a popular testing framework that offers powerful capabilities to help in effective testing. Mocking in Jest helps you test and manage external dependencies and handle side effects.</p>
<p>In this guide, you will learn about unit testing essentials, focusing on Jest mocks. Whether you're just starting or looking to enhance your testing strategy, this guide will equip you with the knowledge to write effective and efficient tests.</p>
<h3 id="heading-heres-what-well-cover"><strong>Here's what we'll cover:</strong></h3>
<ul>
<li><p><a class="post-section-overview" href="#heading-what-is-unit-testing">What is Unit Testing?</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-what-are-external-dependencies">What are External Dependencies?</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-what-are-side-effects">What are Side Effects?</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-what-is-mocking">What is Mocking?</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-use-case-login-express-controller">Use Case: Login Express Controller</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-summary">Summary</a></p>
</li>
</ul>
<h2 id="heading-what-is-unit-testing"><strong>What is Unit Testing?</strong></h2>
<p>Unit testing is a software testing technique used to test a single component of your application in isolation. This component may be a class, a method, or a module.</p>
<h3 id="heading-why-you-should-use-unit-testing">Why You Should Use Unit Testing</h3>
<ol>
<li><p>You will be able to detect bugs earlier, it helps you to detect if a component behaves as expected.</p>
</li>
<li><p>Enables you to modify your component safely. If you update your component and, by mistake, add or modify something you should not, the test will fail if these changes introduce a new bug.</p>
</li>
<li><p>It can serve as a documentation that shows how individual units of your app work.</p>
</li>
<li><p>Encourages you to write cleaner code. The cleaner your component is, the easier and simpler your test will be.</p>
</li>
<li><p>It helps you to easily integrate different parts of your application, as you will be sure that every single component works correctly.</p>
</li>
<li><p>In the long term, you can maintain your application faster.</p>
</li>
</ol>
<p>Let us dive-deep into some practical usages:</p>
<p>Let’s assume that you have a multiplication function that should take two arguments and return the result.</p>
<p>Here’s the code:</p>
<pre><code class="lang-javascript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">multiply</span>(<span class="hljs-params">a,b</span>) </span>{
    <span class="hljs-keyword">return</span> a*b
}
<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> multiply
</code></pre>
<p><strong>Note</strong>: To use Jest with Node.js ECMAScript modules, check out this <a target="_blank" href="https://ayanabilothman.hashnode.dev/configure-jest-to-use-it-with-nodejs-ecmascript-modules">article</a> for configuration.</p>
<p>So how can you test this function using Jest?</p>
<ol>
<li><p>Create <strong><em>__tests__</em></strong> folder in the root folder.</p>
</li>
<li><p>Create file <strong><em>multiply.test.js</em></strong> inside <strong><em>__tests__</em></strong> .</p>
<p> Note that any file ending with <strong><em>.test.js</em></strong> will be executed by Jest.</p>
</li>
<li><p>Start writing your tests by calling the <code>it("",()=&gt;{})</code> Jest method.</p>
</li>
</ol>
<p>Let's understand what `<code>it("",()=&gt;{})</code>` does:</p>
<p>The <code>it</code> method is a Jest function used to test certain behaviors in your function.<br>The first argument should be the test name, which can be an assertion text for what you expect from this test.</p>
<p>For example, if you need to test whether the <code>multiply</code> function returns the right result using the arguments and if they are numbers, you can write <code>it("should return the multiplication of inputs of type number",()=&gt;{})</code>.</p>
<p>The second argument is a function for your test logic. It gets invoked once you run your test<strong>.</strong></p>
<p>To effectively write your tests, you should apply the AAA (Arrange-Act-Assert) Pattern.</p>
<ol>
<li><p><strong>Arrange</strong>: Setup the data or configure any dependencies you will use in this test.</p>
</li>
<li><p><strong>Act:</strong> Call the function you are testing.</p>
</li>
<li><p><strong>Assert:</strong> Write your expectations—how you are expecting the function you are testing to behave. For assertion, you will always use the <code>expect</code> Jest method.</p>
</li>
</ol>
<p>Think of every <code>it("",()=&gt;{})</code> statement as a different scenario of your function.</p>
<p>Here’s an example:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> multiply <span class="hljs-keyword">from</span> <span class="hljs-string">'./../multiply.js'</span>

it(<span class="hljs-string">"should return the multiplication of inputs of type number"</span>, <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-comment">// Arrange</span>
  <span class="hljs-keyword">const</span> testArg1 = <span class="hljs-number">5</span>;
  <span class="hljs-keyword">const</span> testArg2 = <span class="hljs-number">2</span>;
  <span class="hljs-comment">// Act</span>
  <span class="hljs-keyword">const</span> result = multiply(testArg1, testArg2);
  <span class="hljs-comment">// Assert</span>
  expect(result).toBe(<span class="hljs-number">10</span>);
});

it(<span class="hljs-string">"should returns NaN if no arguments are passed"</span>, <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-comment">// Arrange</span>
  <span class="hljs-comment">// Act</span>
  <span class="hljs-keyword">const</span> result = multiply();
  <span class="hljs-comment">// Assert</span>
  expect(result).toBeNaN();
});

it(<span class="hljs-string">"should returns NaN if only one argument is passed"</span>, <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-comment">// Arrange</span>
  <span class="hljs-keyword">const</span> arg = <span class="hljs-number">5</span>;
  <span class="hljs-comment">// Act</span>
  <span class="hljs-keyword">const</span> result = multiply(arg);
  <span class="hljs-comment">// Assert</span>
  expect(result).toBeNaN();
});

it(<span class="hljs-string">"should returns Zero if one of the arguments is empty string"</span>, <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-comment">// Arrange</span>
  <span class="hljs-keyword">const</span> testArg1 = <span class="hljs-string">""</span>;
  <span class="hljs-keyword">const</span> testArg2 = <span class="hljs-number">5</span>;
  <span class="hljs-comment">// Act</span>
  <span class="hljs-keyword">const</span> result = multiply(testArg1, testArg2);
  <span class="hljs-comment">// Assert</span>
  expect(result).toBe(<span class="hljs-number">0</span>);
});
</code></pre>
<p>These tests are some of the tests you can add to your file. You can add more tests or eliminate some depending on the different scenarios of the function you are testing.</p>
<h2 id="heading-what-are-external-dependencies">What are External Dependencies?</h2>
<p>External dependencies are modules or functions that your code relies on, which originates outside your own codebase. These can include libraries, APIs, databases, functions or any service that your application interacts with.  </p>
<p>Testing with external dependencies can be challenging because:</p>
<ul>
<li><p>They can slow down tests due to network or processing delays.</p>
</li>
<li><p>They might not be available during the testing, which in turn causes failures.</p>
</li>
</ul>
<p>As shown in the following function, what if your function calls another function? Most of the functions you write daily actually call other functions.</p>
<p>That is:</p>
<pre><code class="lang-javascript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">processNumbers</span>(<span class="hljs-params">numbers, callback</span>) </span>{
    <span class="hljs-comment">// numbers: array</span>
    <span class="hljs-comment">// callback: function</span>
  <span class="hljs-keyword">return</span> numbers.map(callback);
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> processNumbers;
</code></pre>
<p>When applying unit testing, units should be tested in isolation. <code>processNumbers</code> function depends on another function <code>callback</code>.</p>
<p>So what should you do in this case? Mocking is the solution and we’ll talk about it later in a different section.</p>
<h2 id="heading-what-are-side-effects"><strong>What are Side Effects?</strong></h2>
<p>Side effects occur when a function modifies some state outside its own scope or has observable interactions with the outside world apart from returning a value.</p>
<p>Examples include modifying a global variable, changing a file system, or sending an HTTP request.</p>
<p>Side effects can make tests unpredictable and difficult to manage because they:</p>
<ul>
<li><p>Might interact with other systems, causing alteration of external states.</p>
</li>
<li><p>Can lead to flaky tests if not isolated properly.</p>
</li>
</ul>
<p>Here’s an example that returns a user from a database using their <code>id</code>:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getUserFromDatabase</span>(<span class="hljs-params">userId</span>) </span>{
  <span class="hljs-comment">// Simulates fetching from a database</span>
  <span class="hljs-keyword">return</span> { <span class="hljs-attr">id</span>: userId, <span class="hljs-attr">name</span>: <span class="hljs-string">'John'</span> };
}

<span class="hljs-keyword">export</span> {getUserFromDatabase}
</code></pre>
<p>Here’s another function that makes use of <code>getUserFromDatabase</code> in the code above:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getProfile</span>(<span class="hljs-params">userId</span>) </span>{
  <span class="hljs-keyword">return</span> <span class="hljs-keyword">await</span> getUserFromDatabase(userId);
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> getProfile
</code></pre>
<p>While testing this function, you should not actually send a real request, all you need is to test the behavior of the <code>getProfile</code> function without hitting any external system.</p>
<p>You can also use mocking to solve this situation.</p>
<h2 id="heading-what-is-mocking"><strong>What is Mocking?</strong></h2>
<p>Mocking is about simulation—you need to isolate a function that you are testing. If the function relies on any external dependency or may cause any side effect, you should simulate the behavior of those aspects.</p>
<p>Mocking involves creating a fake version of a function, object, or module to control its behavior during testing. This allows you to simulate different scenarios and verify interactions without relying on actual implementations.</p>
<p>We will focus on two approaches to mocking:</p>
<ol>
<li><p><strong>Function Mocks (also called Spies):</strong><br> You can use <code>jest.fn()</code> to create a mock function that can be used to track a function or replace real implementations. Or use <code>jest.spyOn(object, methodName)</code> to track the calls of <code>object[methodName]</code>.</p>
</li>
<li><p><strong>Module Mocks</strong>: You can use <code>jest.mock(“path-of-your-module”)</code> to mock entire modules or specific imports. By using it, all functions inside this module become mock functions. In addition, during testing, modules you are testing will receive a fake mocked version of this module.</p>
</li>
</ol>
<p>Any mock function has methods that you can use to simulate the behavior of the function. Some of the most used methods are:</p>
<ul>
<li><p><code>mockFn.mockImplementation(fn)</code> : Used to replace the actual implementation of a function. <code>fn</code> is the replacement implementation.</p>
</li>
<li><p><code>mockFn.mockReturnValue(value)</code> : You can use this if all you care about is the return value of a function.</p>
</li>
<li><p><code>mockFn.mockResolvedValue(value)</code>: You can use this if the mock function returns a promise.</p>
</li>
</ul>
<h3 id="heading-example-usage-1"><strong>Example Usage 1</strong></h3>
<p>Let’s test <code>processNumbers</code> by using function mocks. The challenge here is that <code>processNumbers</code> takes a callback function as an argument. What if you need to test if this callback function get invoked inside <code>processNumbers</code>?</p>
<p>Here’s the code:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> processNumbers <span class="hljs-keyword">from</span> <span class="hljs-string">'file-path'</span>;

test(<span class="hljs-string">'processNumbers applies callback and return the right result'</span>, <span class="hljs-function">() =&gt;</span> {
    <span class="hljs-comment">// Arrange</span>
    <span class="hljs-keyword">const</span> arr = [<span class="hljs-number">2</span>, <span class="hljs-number">3</span>]
    <span class="hljs-keyword">const</span> mockedCallback = jest.fn().mockImplementation(<span class="hljs-function"><span class="hljs-params">x</span> =&gt;</span> x + <span class="hljs-number">2</span>);
    <span class="hljs-comment">// Act</span>
    <span class="hljs-keyword">const</span> result = processNumbers(arr, mockedCallback);
    <span class="hljs-comment">// Assert</span>
    expect(result).toEqual([<span class="hljs-number">4</span>, <span class="hljs-number">5</span>]);
    expect(mockedCallback).toHaveBeenCalledTimes(arr.length);
});
</code></pre>
<p>We started by arranging the arguments:</p>
<ul>
<li><p><code>arr</code> variable is an array of numbers. We assigned it an array with random numbers in the test.</p>
</li>
<li><p>The <code>callback</code> variable is a callback function. This function should be mocked in the test.</p>
</li>
</ul>
<p>You may ask yourself why you should mock <code>callback</code>, why not assign it as a normal function?</p>
<p>The answer is that, without mocking the <code>callback</code> argument, you will not be able to track it inside <code>processNumbers</code> while you are testing it. Because mocking creates a fake version of the function, it creates a spy that has a tracker through which you can assert any action taken in this mocked function, whether it gets called or any arguments are passed to it.</p>
<p>The <code>jest.fn()</code> creates a mock function. You can pass a function to <code>fn</code> in place of the real function.</p>
<p>Next, we “act” by calling the function we are testing: <code>processNumbers</code>.</p>
<p>Finally, we wrote the assertions, which are expectations about how <code>processNumbers</code> should behave and if <code>processNumbers</code> applied <code>callback</code> and returned the result.</p>
<h3 id="heading-example-usage-2"><strong>Example Usage 2</strong></h3>
<p>Side effects are another aspect you need to handle in testing. In the <code>getProfile</code> function, an external system is called, which calls a database to retrieve data, and this is a side effect.</p>
<p>In another scenario, a function may connect a database to create a user, and through testing you will not need to add or change actual data in the database.</p>
<p>To simulate the behavior of <code>getUserFromDatabase</code> without actually hitting the database, you should mock its module, and by default, <code>getUserFromDatabase</code> will be an empty mock function that can be tracked during your test.</p>
<p>Here’s the code:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> getProfile <span class="hljs-keyword">from</span> <span class="hljs-string">'file-path'</span>;
<span class="hljs-keyword">import</span> { getUserFromDatabase } <span class="hljs-keyword">from</span> <span class="hljs-string">'file-path'</span>;

<span class="hljs-comment">// Mock the module of getUserFromDatabase method</span>
jest.mock(<span class="hljs-string">'./../DB/databaseMethods.js'</span>);

describe(<span class="hljs-string">'getProfile'</span>, <span class="hljs-function">() =&gt;</span> {
  it(<span class="hljs-string">'should call getUserFromDatabase with the correct userId and return the result'</span>, <span class="hljs-keyword">async</span> () =&gt; {
    <span class="hljs-comment">// Arrange    </span>
    <span class="hljs-keyword">const</span> userId = <span class="hljs-string">'123'</span>;
    <span class="hljs-keyword">const</span> dummyUser = { <span class="hljs-attr">id</span>: userId, <span class="hljs-attr">name</span>: <span class="hljs-string">'John'</span> };
    getUserFromDatabase.mockResolvedValue(dummyUser);
    <span class="hljs-comment">// Act</span>
    <span class="hljs-keyword">const</span> result = <span class="hljs-keyword">await</span> getProfile(userId);
    <span class="hljs-comment">// Assert</span>
    expect(result).toEqual(dummyUser);
    expect(getUserFromDatabase).toHaveBeenCalledWith(userId);
    expect(getUserFromDatabase).toHaveBeenCalledTimes(<span class="hljs-number">1</span>);
  });
});
</code></pre>
<p>We started by arranging the arguments:</p>
<ul>
<li><p><code>userId</code> is just a number.</p>
</li>
<li><p><code>dummyUser</code> is an object that simulates a fake user data.</p>
</li>
<li><p>We returned <code>dummyUser</code> from <code>getUserFromDatabas</code> by using <code>mockResolvedValue</code>.</p>
</li>
</ul>
<p>Similar to the last example, we “act” by calling the function being tested: <code>getProfile</code>.</p>
<p>Finally, we wrote the assertions, you expectations about how <code>getProfile</code> should behave and if the <code>getUserFromDatabase</code> got called correctly and the result returned as expected.</p>
<h2 id="heading-use-case-login-express-controller">Use Case: Login Express Controller</h2>
<p>Here is a login controller that receives the email and password of a user through the <code>req</code> object, and then searches for the user in the database. It does some checks, then returns a <code>res</code> if everything is ok, or call <code>next</code> with an error object.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> User <span class="hljs-keyword">from</span> <span class="hljs-string">"file-path"</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> login = <span class="hljs-keyword">async</span> (req, res, next) =&gt; {
  <span class="hljs-keyword">const</span> { email, password } = req.body;

  <span class="hljs-keyword">const</span> user = <span class="hljs-keyword">await</span> User.findOne({ email });
  <span class="hljs-keyword">if</span> (!user) <span class="hljs-keyword">return</span> next(<span class="hljs-keyword">new</span> <span class="hljs-built_in">Error</span>(<span class="hljs-string">"Invalid Email!"</span>));

  <span class="hljs-keyword">const</span> checkPassword = user.checkPassword(password);
  <span class="hljs-keyword">if</span> (!checkPassword) <span class="hljs-keyword">return</span> next(<span class="hljs-keyword">new</span> <span class="hljs-built_in">Error</span>(<span class="hljs-string">"Invalid Password!"</span>));

  <span class="hljs-keyword">const</span> token = user.generateToken();

  <span class="hljs-keyword">return</span> res.status(<span class="hljs-number">200</span>).json({ <span class="hljs-attr">success</span>: <span class="hljs-literal">true</span>, <span class="hljs-attr">results</span>: { token } });
};
</code></pre>
<p>Think about the steps you can use to test the login function. You can ask some questions that’ll help you come up with ideas:</p>
<p>What are the scenarios of <code>login</code> function workflow?</p>
<ol>
<li><p>The user is not found.</p>
</li>
<li><p>Password is incorrect.</p>
</li>
<li><p>Everything is ok, and a response is returned with a token.</p>
</li>
</ol>
<p>So you may assert <code>login</code> to do the following:</p>
<ul>
<li><p><code>login</code> should call <code>next</code> if user not found.</p>
</li>
<li><p><code>login</code> should call <code>next</code> if password doesn't match.</p>
</li>
<li><p><code>login</code> should call <strong>res.json</strong> with the token and call <strong>res.status</strong> with 200 if everything is ok.</p>
</li>
</ul>
<p>What are the arguments that <code>login</code> method should receive?</p>
<ol>
<li><p><code>req</code> object with <code>body</code> property.</p>
</li>
<li><p><code>res</code> object with <code>status</code> and <code>json</code> property.</p>
</li>
<li><p><code>next</code> function.</p>
</li>
</ol>
<p><code>res.json()</code> or <code>res.status()</code> or <code>next()</code> all are functions that <code>login</code> needs to do its work. During testing, you have no access to these arguments so you should mock them.</p>
<ul>
<li><p><code>req</code> can be defined as <code>{body: { email: "</code><a target="_blank" href="mailto:test@foo.com"><code>test@foo.com</code></a><code>", password: "bar" }}</code></p>
</li>
<li><p><code>res</code> can be defined as <code>{json: jest.fn().mockReturnThis(), status: jest.fn().mockReturnThis()}</code></p>
</li>
<li><p><code>next</code> can be defined as <code>jest.fn()</code></p>
</li>
</ul>
<p>Are there any interactions with external systems or any dependencies?</p>
<ol>
<li><p><code>User.findOne()</code></p>
</li>
<li><p><code>user.checkPassword()</code></p>
</li>
<li><p><code>user.generateToken()</code></p>
</li>
</ol>
<p>Thus, mocking is the solution:</p>
<ul>
<li><p>For <code>User.findOne()</code>, you should mock the entire <code>User</code> module and set up the fake <code>findOne()</code> to return a fake <code>user</code>. The challenge here is that <code>findOne</code> is an object method. How can you track it? <code>jest.spyOn(object, methodName)</code> is the soultion.<br>  The <code>spyOn</code> method is used to track the calls of <code>object[methodName]</code>, which, in our case, is <code>User.findOne</code></p>
</li>
<li><p><code>user.checkPassword()</code> and <code>user.generateToken()</code> should be mock functions.</p>
</li>
</ul>
<p>To apply all of these concepts and put blocks with each other, the final test should be:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> User <span class="hljs-keyword">from</span> <span class="hljs-string">"file-path"</span>;
<span class="hljs-keyword">import</span> { login } <span class="hljs-keyword">from</span> <span class="hljs-string">"file-path"</span>;

jest.mock(<span class="hljs-string">"../DB/models/user.model.js"</span>);

<span class="hljs-keyword">let</span> mockReq, mockRes, mockNext, dummyUser;
describe(<span class="hljs-string">"login controller"</span>, <span class="hljs-function">() =&gt;</span> {
  beforeEach(<span class="hljs-function">() =&gt;</span> {
    mockReq = { <span class="hljs-attr">body</span>: { <span class="hljs-attr">email</span>: <span class="hljs-string">"test@foo.com"</span>, <span class="hljs-attr">password</span>: <span class="hljs-string">"bar"</span> } };
    mockRes = {
      <span class="hljs-attr">json</span>: jest.fn().mockReturnThis(),
      <span class="hljs-attr">status</span>: jest.fn().mockReturnThis(),
    };
    mockNext = jest.fn();

    dummyUser = {
      <span class="hljs-attr">checkPassword</span>: jest.fn(<span class="hljs-function">() =&gt;</span> <span class="hljs-literal">true</span>),
      <span class="hljs-attr">generateToken</span>: jest.fn(<span class="hljs-function">() =&gt;</span> <span class="hljs-string">"token"</span>),
    };
  });

  it(<span class="hljs-string">"should call next if user not found"</span>, <span class="hljs-keyword">async</span> () =&gt; {
    <span class="hljs-comment">// Arrange</span>
    jest.spyOn(User, <span class="hljs-string">"findOne"</span>).mockResolvedValueOnce(<span class="hljs-literal">null</span>);
    <span class="hljs-comment">// Act</span>
    <span class="hljs-keyword">await</span> login(mockReq, mockRes, mockNext);
    <span class="hljs-comment">// Assert</span>
    expect(mockNext).toHaveBeenCalledWith(<span class="hljs-keyword">new</span> <span class="hljs-built_in">Error</span>(<span class="hljs-string">"Invalid Email!"</span>));
    expect(mockRes.json).not.toHaveBeenCalled();
  });

  it(<span class="hljs-string">"should call next if password doesn't match"</span>, <span class="hljs-keyword">async</span> () =&gt; {
    <span class="hljs-comment">// Arrange</span>
    dummyUser.checkPassword.mockReturnValueOnce(<span class="hljs-literal">false</span>);
    jest.spyOn(User, <span class="hljs-string">"findOne"</span>).mockResolvedValue(dummyUser);
    <span class="hljs-comment">// Act</span>
    <span class="hljs-keyword">await</span> login(mockReq, mockRes, mockNext);
    <span class="hljs-comment">// Assert</span>
    expect(mockNext).toHaveBeenCalledWith(<span class="hljs-keyword">new</span> <span class="hljs-built_in">Error</span>(<span class="hljs-string">"Invalid Password!"</span>));
    expect(dummyUser.generateToken).not.toHaveBeenCalled();
    expect(mockRes.json).not.toHaveBeenCalled();
  });

  it(<span class="hljs-string">"should call res.json with the token and call res.status with 200 if everything is ok"</span>, <span class="hljs-keyword">async</span> () =&gt; {
    <span class="hljs-comment">// Arrange</span>
    jest.spyOn(User, <span class="hljs-string">"findOne"</span>).mockResolvedValue(dummyUser);
    <span class="hljs-comment">// Act</span>
    <span class="hljs-keyword">await</span> login(mockReq, mockRes, mockNext);
    <span class="hljs-comment">// Assert</span>
    expect(mockNext).not.toHaveBeenCalled();
    expect(User.findOne).toHaveBeenCalledWith({ <span class="hljs-attr">email</span>: mockReq.body.email });

    expect(dummyUser.checkPassword).toHaveBeenCalledWith(mockReq.body.password);
    expect(dummyUser.generateToken).toHaveBeenCalled();

    expect(mockRes.status).toHaveBeenCalledWith(<span class="hljs-number">200</span>);
    expect(mockRes.json).toHaveBeenCalledWith({
      <span class="hljs-attr">success</span>: <span class="hljs-literal">true</span>,
      <span class="hljs-attr">results</span>: { <span class="hljs-attr">token</span>: <span class="hljs-string">"token"</span> },
    });
  });
});
</code></pre>
<p><strong>Final note</strong>: <code>beforeEach</code> is a Jest hook, you can use it to implement some code before each test. Inside <code>beforeEach</code> function, you can write any common variables your tests may need instead of writing them independently for each test.</p>
<h2 id="heading-summary">Summary</h2>
<p>In this tutorial you learned the basics of unit testing with Jest, focusing on how to use mocks. Unit testing helps ensure that individual parts of your code work correctly by testing them in isolation.  </p>
<p>Handling external dependencies, managing side effects, and utilizing mocking are essential skills for robust testing. Jest provides powerful tools to address these challenges, making your tests more reliable, faster, and easier to maintain.</p>
<p>Understanding these concepts will help you write better tests and produce more resilient applications.</p>
<p>This tutorial explained how to use Jest’s mocking features to simulate external dependencies and manage side effects. It includes a practical example of testing an Express.js login controller, showing how to mock functions and control test scenarios.</p>
<p>This approach helps you create reliable tests and maintain code quality by isolating and managing dependencies effectively.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Write Cleaner Code Using Mongoose Schemas ]]>
                </title>
                <description>
                    <![CDATA[ If you are used to building NodeJS applications using the Mongoose ORM, this article is for you. In it, we'll discuss some cool features of Mongoose schemas that'll help you write more organized and maintainable code. To get the most out of this guid... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-write-cleaner-code-using-mongoose-schemas/</link>
                <guid isPermaLink="false">66db07581905f28bb66717a2</guid>
                
                    <category>
                        <![CDATA[ mongoose ]]>
                    </category>
                
                    <category>
                        <![CDATA[ clean code ]]>
                    </category>
                
                    <category>
                        <![CDATA[ JavaScript ]]>
                    </category>
                
                    <category>
                        <![CDATA[ MongoDB ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Object Oriented Programming ]]>
                    </category>
                
                    <category>
                        <![CDATA[ dry ]]>
                    </category>
                
                    <category>
                        <![CDATA[ APIs ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ ِAya Nabil Othman ]]>
                </dc:creator>
                <pubDate>Fri, 06 Sep 2024 13:44:56 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/res/hashnode/image/upload/v1725431278897/86823d79-7b9c-4512-a834-edcdd4e11ac3.jpeg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>If you are used to building NodeJS applications using the Mongoose ORM, this article is for you. In it, we'll discuss some cool features of Mongoose schemas that'll help you write more organized and maintainable code.</p>
<p>To get the most out of this guide, you should have a background in JavaScript, understand how Mongoose works, and know Object-Oriented Programming basics.</p>
<h3 id="heading-heres-what-well-cover">Here's what we'll cover:</h3>
<ol>
<li><p><a class="post-section-overview" href="#heading-what-is-a-mongoose-schema">What is a Mongoose Schema?</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-discriminator">Discriminator</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-statics">Statics</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-methods">Methods</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-query-builder">Query Builder</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-hooks">Hooks</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-summary">Summary</a></p>
</li>
</ol>
<h2 id="heading-what-is-a-mongoose-schema">W<strong>hat is a Mongoose Schema?</strong></h2>
<p>Mongoose schemas provide a structured way to model data in a MongoDB database, allowing you to define the properties and behavior of the documents. Schemas serve as a blueprint for a document that gets saved in the database. They enables developers to enforce data integrity and work with MongoDB in a more intuitive and organized manner.</p>
<p>Within a MongoDB collection, a schema outlines the fields of the documents, their data types, validation rules, default values, constraints, and more.</p>
<p>Programmatically, a Mongoose schema is a JavaScript object. Actually, it is an instance of a built-in class called <code>Schema</code> inside the <code>mongoose</code> module. For this reason, you can add more methods to its prototype. This will help you implement many features as middleware, methods, statics, and more. You will learn about some of them in this tutorial.</p>
<h3 id="heading-features-youll-learn-how-to-implement"><strong>Features you'll learn how to implement:</strong></h3>
<ul>
<li><p><a class="post-section-overview" href="#discriminator">Discriminator</a></p>
</li>
<li><p><a class="post-section-overview" href="#statics">Statics</a></p>
</li>
<li><p><a class="post-section-overview" href="#methods">Methods</a></p>
</li>
<li><p><a class="post-section-overview" href="#query-builder">Query Builder</a></p>
</li>
<li><p><a class="post-section-overview" href="#hooks">Hooks</a></p>
</li>
</ul>
<h2 id="heading-discriminator">Discriminator</h2>
<p>A discriminator is a feature that enables you to create multiple models (subtypes) that inherit from a base model (parent). This happens by defining a base schema and then extending it with extra fields specific to each subtype or each child schema.</p>
<p>All documents, regardless of their specific model, are stored in the same MongoDB collection. This keeps your data organized in a single collection while allowing for flexible querying and data management. Also, each document includes a special field that indicates its specific model type, allowing Mongoose to distinguish between the different subtypes.</p>
<p><strong>How to use</strong> <code>discriminator</code><strong>:</strong></p>
<ol>
<li><p>Start by defining a base schema, which will have the common fields among the subtypes. After that, create a model from it.</p>
<pre><code class="lang-javascript"> <span class="hljs-keyword">import</span> mongoose <span class="hljs-keyword">from</span> <span class="hljs-string">'mongoose'</span>;

 <span class="hljs-keyword">const</span> baseSchema = <span class="hljs-keyword">new</span> mongoose.Schema({
     <span class="hljs-attr">name</span>: { <span class="hljs-attr">type</span>: <span class="hljs-built_in">String</span>, <span class="hljs-attr">required</span>: <span class="hljs-literal">true</span> },
 }, { <span class="hljs-attr">discriminatorKey</span>: <span class="hljs-string">'kind'</span> }; <span class="hljs-comment">// defaults to '__t');</span>

 <span class="hljs-keyword">const</span> BaseModel = mongoose.model(<span class="hljs-string">'Base'</span>, baseSchema);
</code></pre>
</li>
<li><p>Create the subtypes that extend the base schema by defining the <code>discriminator</code> for each one.</p>
<pre><code class="lang-javascript"> <span class="hljs-keyword">const</span> catSchema = <span class="hljs-keyword">new</span> mongoose.Schema({
     <span class="hljs-attr">meow</span>: { <span class="hljs-attr">type</span>: <span class="hljs-built_in">Boolean</span>, <span class="hljs-attr">default</span>: <span class="hljs-literal">true</span> }
 });
 <span class="hljs-comment">// subtype</span>
 <span class="hljs-keyword">const</span> Cat = BaseModel.discriminator(<span class="hljs-string">'Cat'</span>, catSchema);

 <span class="hljs-keyword">const</span> dogSchema = <span class="hljs-keyword">new</span> mongoose.Schema({
     <span class="hljs-attr">bark</span>: { <span class="hljs-attr">type</span>: <span class="hljs-built_in">Boolean</span>, <span class="hljs-attr">default</span>: <span class="hljs-literal">true</span> }
 });
 <span class="hljs-comment">// subtype</span>
 <span class="hljs-keyword">const</span> Dog = BaseModel.discriminator(<span class="hljs-string">'Dog'</span>, dogSchema);
</code></pre>
</li>
<li><p>You can then create documents in the regular way. All the documents will be stored in the same collection, but each has its own type depending on its subtype model.</p>
<pre><code class="lang-javascript"> <span class="hljs-keyword">const</span> fluffy = <span class="hljs-keyword">await</span> Cat.create({ <span class="hljs-attr">name</span>: <span class="hljs-string">'Fluffy'</span> });
 <span class="hljs-keyword">const</span> rover = <span class="hljs-keyword">await</span> Dog.create({ <span class="hljs-attr">name</span>: <span class="hljs-string">'Rover'</span> });
</code></pre>
</li>
</ol>
<h3 id="heading-discriminator-use-case"><code>discriminator</code> use case:</h3>
<p>Let's say that you're building a multi-user Ecommerce web application which accommodates three main user roles: <em>admins</em>, <em>clients</em>, and <em>sellers</em>. Each of these roles plays a crucial part in the ecosystem of online shopping.</p>
<p>If you try to build a class for each role, you'll find that all the three have common fields and methods. You may decide to create a parent schema (user) and some other children schemas (client, seller, admin) that inherit from it.</p>
<p>You can use the <code>discriminator</code> to achieve this.</p>
<p>In your <code>user.model.js</code> file, add the following code:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> mongoose <span class="hljs-keyword">from</span> <span class="hljs-string">"mongoose"</span>;

<span class="hljs-keyword">const</span> userSchema = mongoose.Schema(
  {
    <span class="hljs-attr">name</span>: <span class="hljs-built_in">String</span>,
    <span class="hljs-attr">profilePic</span>: <span class="hljs-built_in">String</span>,
    <span class="hljs-attr">email</span>: <span class="hljs-built_in">String</span>,
    <span class="hljs-attr">password</span>: <span class="hljs-built_in">String</span>,
    <span class="hljs-attr">birthDate</span>: <span class="hljs-built_in">Date</span>,
    <span class="hljs-attr">accountAcctivated</span>: { <span class="hljs-attr">type</span>: <span class="hljs-built_in">Boolean</span>, <span class="hljs-attr">default</span>: <span class="hljs-literal">false</span> },
  },
  {
    <span class="hljs-attr">timestamps</span>: <span class="hljs-literal">true</span>,
    <span class="hljs-attr">discriminatorKey</span>: <span class="hljs-string">"role"</span>,
  }
);

<span class="hljs-keyword">const</span> User = mongoose.model(<span class="hljs-string">"User"</span>, userSchema);
<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> User;
</code></pre>
<p>Now you have the base model (<code>User</code>) from which other subtypes will inherit. In this parent schema, you define the common fields that all users will share regardless of their roles.</p>
<p>In your <code>client.model.js</code> file:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> mongoose <span class="hljs-keyword">from</span> <span class="hljs-string">"mongoose"</span>;
<span class="hljs-keyword">import</span> User <span class="hljs-keyword">from</span> <span class="hljs-string">"./user.model.js"</span>;

<span class="hljs-keyword">const</span> clientSchema = mongoose.Schema(
  {
    <span class="hljs-attr">products</span>: <span class="hljs-built_in">Array</span>,
    <span class="hljs-attr">address</span>: <span class="hljs-built_in">String</span>,
    <span class="hljs-attr">phone</span>: <span class="hljs-built_in">String</span>,
  }
);

<span class="hljs-keyword">const</span> Client = User.discriminator(<span class="hljs-string">"Client"</span>, clientSchema);
<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> Client;
</code></pre>
<p>In your <code>seller.model.js</code> file:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> mongoose <span class="hljs-keyword">from</span> <span class="hljs-string">"mongoose"</span>;
<span class="hljs-keyword">import</span> User <span class="hljs-keyword">from</span> <span class="hljs-string">"./user.model.js"</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> sellerSchema = mongoose.Schema(
  {
    <span class="hljs-attr">rating</span>: <span class="hljs-built_in">Number</span>,
    <span class="hljs-attr">businessType</span>: { <span class="hljs-attr">type</span>: <span class="hljs-built_in">String</span>, <span class="hljs-attr">enum</span>: [<span class="hljs-string">"individual"</span>, <span class="hljs-string">"corporation"</span>] },
  }
);

<span class="hljs-keyword">const</span> Seller = User.discriminator(<span class="hljs-string">"Seller"</span>, sellerSchema);
<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> Seller;
</code></pre>
<p>In your <code>admin.model.js</code> file:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> mongoose <span class="hljs-keyword">from</span> <span class="hljs-string">"mongoose"</span>;
<span class="hljs-keyword">import</span> User <span class="hljs-keyword">from</span> <span class="hljs-string">"./user.model.js"</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> adminSchema = mongoose.Schema(
  {
    <span class="hljs-attr">permissions</span>: <span class="hljs-built_in">Array</span>,
    <span class="hljs-attr">assignedTasks</span>: <span class="hljs-built_in">Array</span>,
    <span class="hljs-attr">department</span>: <span class="hljs-built_in">String</span>,
  }
);

<span class="hljs-keyword">const</span> Admin = User.discriminator(<span class="hljs-string">"Admin"</span>, adminSchema);
<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> Admin;
</code></pre>
<p>The subtypes or children will be the <code>Client</code>, <code>Seller</code>, and <code>Admin</code>. In each subtype schema, you should add any extra fields or behaviors specific to this subtype only. By creating the child model using the discriminator, the child model will inherit all the fields and methods of its parent model <code>User</code>.  </p>
<p>So the previous code will create a <code>user</code> collection in the database with each document having a <code>role</code> field either Client, or Seller, or Admin. All documents are now sharing the parent (<code>user</code>) fields, and depending on the <code>role</code> of each document, each has another extra field.</p>
<p>Although all the documents will be saved in one single collection, models are fully separated while coding. What does this mean?</p>
<p>For instance, If you need to retrieve all clients from the <code>User</code> collection, you should write <code>Client.find({})</code>. This statement uses the discriminator key to find all documents whose <code>role</code> is <code>Client</code>. This way, any operations or queries that refer to one of the child models will still be written separately from the parent model.</p>
<p><strong>Note:</strong> Before diving into the next sections, just keep in mind that any statics, methods, query builders, or hooks should be defined before creating the model itself (that is, before <code>const User = mongoose.model("User", userSchema);</code>).</p>
<h2 id="heading-statics">Statics</h2>
<p>Statics are useful for defining functions that operate on the model level. They allow you to define reusable functions for operations related to the entire model. They help encapsulate logic that applies to the model rather than individual documents, making your code cleaner, more organized and maintainable</p>
<p>Methods like <code>find</code>, <code>findOne</code>, <code>findById</code> and others all are methods attached to the model. By using the <code>statics</code> property of Mongoose schemas, you will be able to build your own model method.  </p>
<p>Statics are powerful. By using them, you can encapsulate complex queries that you might want to reuse. Also, you can create statics for operations that modify or aggregate data, such as counting documents or finding documents based on specific criteria.</p>
<h3 id="heading-statics-use-case"><code>statics</code> use case</h3>
<p>Statics are easy to build. You define a static method on your schema using the <code>statics</code> object.</p>
<p>In your <code>user.model.js</code> file, add these static methods, <code>countUsers</code> and <code>findByEmail</code>:</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// model method</span>
userSchema.statics.countUsers = <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{
    <span class="hljs-keyword">return</span> <span class="hljs-built_in">this</span>.countDocuments({});
};

<span class="hljs-comment">// model method</span>
userSchema.statics.findByEmail = <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">email</span>) </span>{
  <span class="hljs-keyword">return</span> <span class="hljs-keyword">await</span> <span class="hljs-built_in">this</span>.findOne({ email });
};
</code></pre>
<p>Inside any static method, <code>this</code> refers to the <strong>model</strong> itself. In this example, <code>this</code> in <code>this.findOne({ email })</code> refers to the <code>User</code> model.</p>
<p>Example usage:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> user = <span class="hljs-keyword">await</span> User.findByEmail(<span class="hljs-string">"foo@bar.com"</span>);
<span class="hljs-comment">//or</span>
<span class="hljs-keyword">const</span> client = <span class="hljs-keyword">await</span> Client.findByEmail(<span class="hljs-string">"foo@bar.com"</span>);
<span class="hljs-comment">//or</span>
<span class="hljs-keyword">const</span> seller = <span class="hljs-keyword">await</span> Seller.findByEmail(<span class="hljs-string">"foo@bar.com"</span>);
<span class="hljs-comment">//or</span>
<span class="hljs-keyword">const</span> admin = <span class="hljs-keyword">await</span> Admin.findByEmail(<span class="hljs-string">"foo@bar.com"</span>);
</code></pre>
<p>When you call the static method on your model, the method gets called and <code>this</code> is replaced by the model you called the statics on. This line performs a query to find a single document in the MongoDB collection where the <code>email</code> field matches the provided <code>email</code> argument.</p>
<h2 id="heading-methods">Methods</h2>
<p>Methods are functions that you can define on a schema and that can be called on instances of documents created from this schema. They help encapsulate logic within the document itself, making your code cleaner and more modular.</p>
<p>By using instance methods, you can easily interact with and manipulate the data associated with specific documents.</p>
<h3 id="heading-methods-use-case"><code>methods</code> use case</h3>
<p>You can define methods on the schema using the <code>methods</code> object.</p>
<p>In your <code>user.model.js</code> file, add a document method through which you can check the password of a user:</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// instance or document method</span>
userSchema.methods.getProfile = <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{
    <span class="hljs-keyword">return</span> <span class="hljs-string">`<span class="hljs-subst">${<span class="hljs-built_in">this</span>.name}</span> (<span class="hljs-subst">${<span class="hljs-built_in">this</span>.email}</span>)`</span>;
};

<span class="hljs-comment">// instance or document method</span>
userSchema.methods.checkPassword = <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">password</span>) </span>{
    <span class="hljs-keyword">return</span> password === <span class="hljs-built_in">this</span>.password ? <span class="hljs-literal">true</span> : <span class="hljs-literal">false</span>;
};
</code></pre>
<p>Inside any document method, <code>this</code> refers to the <strong>document</strong> itself. In this example, <code>this</code> in <code>this.password</code> refers to the <code>user</code> document at which the method will get called on. This means that you can access all the fields of this document. This is so valuable because you can retrieve, modify, and check for anything related to this document.</p>
<p>Example usage:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> client = <span class="hljs-keyword">await</span> Client.findById(...)
client.checkPassword(<span class="hljs-string">"12345"</span>)
<span class="hljs-comment">//or</span>
<span class="hljs-keyword">const</span> seller = <span class="hljs-keyword">await</span> Seller.findById(...)
seller.checkPassword(<span class="hljs-string">"12345"</span>)
<span class="hljs-comment">//or</span>
<span class="hljs-keyword">const</span> admin = <span class="hljs-keyword">await</span> Admin.findById(...)
admin.checkPassword(<span class="hljs-string">"12345"</span>)
</code></pre>
<p>Since methods are instance-level functions, they are called on the documents. <code>await Client.findById(...)</code> will return a document that has all the built-in methods as well as your own predefined methods <code>checkPassword</code> and <code>getProfile</code>. So by calling, for example <code>client.checkPassword("12345")</code>, the <code>this</code> keyword in the <code>checkPassword</code> function definition will get replaced with the <code>client</code> document. This in turn will compare the user password with the password saved earlier in the database.</p>
<h2 id="heading-query-builder">Query Builder</h2>
<p>A query builder in Mongoose is a custom method that you can define on the query object to simplify and encapsulate common query patterns. These query builders allow you to create reusable and readable query logic, making it easier to work with your data.</p>
<p>One of the most valuable usages of query builders is chaining. They can be chained with other query builders that you've built or with standard query methods like find, sort, and so on.</p>
<h3 id="heading-query-builder-use-case">Query builder use case</h3>
<p>You define query builders by adding them to the <code>query</code> property of a Mongoose schema.</p>
<p>In your <code>user.model.js</code> file, add a query helper method that lets you implement pagination.</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// query helper</span>
userSchema.query.paginate = <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">{ page, limit }</span>) </span>{
    <span class="hljs-comment">// some code</span>
    <span class="hljs-keyword">const</span> skip = limit * (page - <span class="hljs-number">1</span>);
    <span class="hljs-keyword">return</span> <span class="hljs-built_in">this</span>.skip(skip).limit(limit);
};
</code></pre>
<p>To implement pagination, you need two important variables: first, the page number, and second, the number of items you will retrieve per page.</p>
<p>To query the database for a specific count of documents, you will always use the <code>skip</code> and <code>limit</code> built-in query methods in <code>mongoose</code>. <code>skip</code> is used to set a cursor after a certain number of documents, after which the query will get implemented. <code>limit</code> is used to retrieve a specific number of documents.</p>
<p>Inside any query builder method, <code>this</code> refers to the <strong>query</strong> itself. And since query builders are chainable, you can call any of them after each other.</p>
<p>Finally, any query builder method should return a <code>mongoose query object</code>, which is why you must write <code>return this.skip(skip).limit(limit)</code>.</p>
<p>Example usage:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> results = <span class="hljs-keyword">await</span> Client.find().paginate({ <span class="hljs-attr">page</span>: <span class="hljs-number">2</span>, <span class="hljs-attr">limit</span>: <span class="hljs-number">5</span> });
<span class="hljs-comment">//or</span>
<span class="hljs-keyword">const</span> results = <span class="hljs-keyword">await</span> Seller.find().paginate({ <span class="hljs-attr">page</span>: <span class="hljs-number">2</span>, <span class="hljs-attr">limit</span>: <span class="hljs-number">5</span> });
<span class="hljs-comment">//or</span>
<span class="hljs-keyword">const</span> results = <span class="hljs-keyword">await</span> Admin.find().paginate({ <span class="hljs-attr">page</span>: <span class="hljs-number">2</span>, <span class="hljs-attr">limit</span>: <span class="hljs-number">5</span> });
</code></pre>
<p>You can then call it on any query, and <code>await Client.find().paginate({ page: 2, limit: 5 })</code> will invoke the <code>paginate</code> function and replace the <code>this</code> keyword with <code>Client.find()</code> using the query builder.</p>
<p>You can implement pagination with certain conditions, but you'll always call <code>skip</code> and <code>limit</code>. By defining the <code>paginate</code> query builder you won't repeat yourself and you'll be able to encapsulate the logic in one single function.</p>
<h2 id="heading-hooks">Hooks</h2>
<p>Hooks (also known as middleware) are functions that are executed at specific points in the lifecycle of a document. They allow you to add custom behavior before or after certain operations, such as saving, updating, or removing documents.</p>
<p>Types of Hooks</p>
<ul>
<li><p>Pre Hooks: Executed before an operation.</p>
</li>
<li><p>Post Hooks: Executed after an operation.</p>
</li>
</ul>
<h3 id="heading-hooks-use-case">Hooks use case</h3>
<p>In your <code>user.model.js</code> file, add a <code>post</code> save middleware through which you can send an email for account activation once the user document is saved in the database.</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// post hook</span>
userSchema.post(<span class="hljs-string">"save"</span>, <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">doc, next</span>) </span>{
  <span class="hljs-comment">// send email logic</span>
  <span class="hljs-comment">// if succeeded</span>
  <span class="hljs-keyword">return</span> next();
  <span class="hljs-comment">// if failed</span>
  <span class="hljs-keyword">return</span> next(<span class="hljs-keyword">new</span> <span class="hljs-built_in">Error</span>(<span class="hljs-string">"Failed to send email!"</span>));
});
</code></pre>
<p>The callback function will get invoked once you create a user through <code>model.create()</code> or any time you call <code>save()</code> method on the user document.</p>
<p>In this this example, if you need to avoid sending emails on save, you should write a condition to be sure that this <code>save</code> is for a new user only. You can write something like <code>if (doc.createdAt.getTime() === doc.updatedAt.getTime())</code>.</p>
<h3 id="heading-summary"><strong>Summary</strong></h3>
<p>In this overview of Mongoose features, we've explored four key concepts: discriminators, statics, methods, and hooks.</p>
<p><strong>Discriminators</strong> allow you to create multiple models that share a common schema enabling different document types to be stored in a single collection. This facilitates data management and querying.  </p>
<p><strong>Statics</strong> are model-level methods that provide reusable functionality applicable to the entire model. They encapsulate complex queries and data manipulation logic, helping to keep your codebase clean and maintainable.  </p>
<p><strong>Methods</strong> are instance-level functions that operate on individual document instances. They allow for custom behaviors and data manipulations specific to each document, so you can modify the document’s data in a specific way, such as formatting or calculating values based on its fields.  </p>
<p><strong>Hooks</strong> (or middleware) enable you to run functions at specific points in the document lifecycle, such as before or after saving, updating or deleting a document. This is useful for implementing validation, logging, or any other side effects related to database operations.  </p>
<p>Together, these features enhance the versatility and organization of your Mongoose models, making it easier to build robust and maintainable applications with MongoDB.</p>
<p><a target="_blank" href="https://github.com/Ayanabilothman/mongoose-schema-features">Here</a> can will find a repository where you can learn more about Mongoose schemas and use cases.</p>
 ]]>
                </content:encoded>
            </item>
        
    </channel>
</rss>
