<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/">
    <channel>
        <title>João Forja</title>
        <link>https://joaoforja.com</link>
        <description>Articles about React, testing, frontend architecture, and software quality.</description>
        <lastBuildDate>Fri, 10 Jul 2026 17:46:19 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>João Forja</title>
            <url>https://joaoforja.com/favicon.ico</url>
            <link>https://joaoforja.com</link>
        </image>
        <copyright>All rights reserved 2026</copyright>
        <item>
            <title><![CDATA[4 resources to learn React under the hood]]></title>
            <link>https://joaoforja.com/articles/4-resources-to-learn-react-under-the-hood</link>
            <guid isPermaLink="false">https://joaoforja.com/articles/4-resources-to-learn-react-under-the-hood</guid>
            <pubDate>Thu, 12 Mar 2020 20:12:03 GMT</pubDate>
            <content:encoded><![CDATA[<p>One of the best ways to improve as a developer is to understand how the tools we use work. If you've been working with React for a while, and you are pretty comfortable working with its API, it's time to take the next step and find out how it works under the hood.</p>
<p>In this article you'll find a compilation of excellent resources that will help you understand how React does what it does.</p>
<h2><a href="https://pomb.us/build-your-own-react/">1. Build your own React</a></h2>
<p><a href="https://pomb.us/build-your-own-react/">Build your own React</a> is a fantastic article written by <a href="https://twitter.com/pomber">Rodrigo Pombo</a> that goes over how to build your own React from scratch. It is an amazing place to start the journey of learning how React works, since it goes over most of the core functionalities and structure of React. On <a href="https://pomb.us/build-your-own-react/">Build your own React</a> you'll learn about the following topics:</p>
<ol>
<li>The createElement Function</li>
<li>The render Function</li>
<li>Concurrent Mode</li>
<li>Fibers</li>
<li>Render and Commit Phases</li>
<li>Reconciliation</li>
<li>Function Components</li>
<li>Hooks</li>
</ol>
<p>To better learn the content, my suggestion is that you code along with the article. By the end of it, you'll have implemented your own version of React from scratch.</p>
<h2><a href="https://overreacted.io/">2. Overreacted</a></h2>
<p><a href="https://overreacted.io/">Overreacted</a> is the personal blog of <a href="https://twitter.com/dan_abramov">Dan Abramov</a>. In case you didn't know, Dan Abramov is a member of the React core team and a co-author of <a href="https://create-react-app.dev/">Create-React-App</a>.</p>
<p>In Dan's blog you'll be able to find a lot of interesting articles about the inner workings of React. Some of those article are:</p>
<ol>
<li><a href="https://overreacted.io/react-as-a-ui-runtime/">React as a UI Runtime</a></li>
<li><a href="https://overreacted.io/a-complete-guide-to-useeffect/">A Complete Guide to useEffect</a></li>
<li><a href="https://overreacted.io/why-do-hooks-rely-on-call-order/">Why Do React Hooks Rely on Call Order?</a></li>
<li><a href="https://overreacted.io/how-does-react-tell-a-class-from-a-function/">How Does React Tell a Class from a Function?</a></li>
</ol>
<p>Overreact articles tend to be long, and the content can be quite heavy. My suggestion is that you focus on it and try to not get distracted. Otherwise, it might be hard to grasp the concepts being explained.</p>
<p>Dan will probably keep updating his blog with more interesting content, so it's a good idea to keep an eye out for it.</p>
<h2><a href="https://reactjs.org/docs/codebase-overview.html">3. React codebase overview</a></h2>
<p>If you really want to go deep, the <a href="https://reactjs.org/docs/codebase-overview.html">overview page</a> of React's codebase is the place to go.</p>
<p>By going over the documentation, you'll not only learn more about the overall architecture of React, you'll also find a lot of interesting resources each of the core main components of the React architecture.</p>
<p>Also, by going over the codebase overview and its recommended resource, you'll be in better shape to give back to the community and one day make a contribution to React itself. It's a pretty good investment.</p>
<h2><a href="https://www.reactiflux.com/">4. Reactiflux's channel react-internals</a></h2>
<p>Getting to know a codebase as complex as React's can be difficult. So it's always good to know where to ask for help.</p>
<p><a href="https://www.reactiflux.com/">Reactiflux</a> is a chat community for developers who want to chat about React &amp; Javascript. In there you'll find a channel dedicated to the inner workings of React, called react-internals.</p>
<p>If you've got a doubt about how React does something, react-internals is a good place to ask for help.</p>
<p>It's also a good idea to just go to the channel and read the messages that are in there. You'll often find really good material that will help you better understand how React works.</p>
<h2>Conclusion</h2>
<p>By now, you already know some good resources to get started learning React under the hood.</p>
<p>However, beware that learning a lot of material at once can be quite hard and takes some time. So look at this as a continued effort, and not as something to get done in a day. It's more of a marathon and less of a sprint.</p>
<p>Schedule slots of your days to go over these resources. Try to not get distracted or interrupted during those slots. Follow the order the resources were presented in this article. And really focus on the content. Sooner rather than later, you'll feel a lot more confident on your skills as a React developer.</p>]]></content:encoded>
            <author>João Forja</author>
        </item>
        <item>
            <title><![CDATA[5 steps to perform a search when user stops typing using React + Hooks in a controlled component]]></title>
            <link>https://joaoforja.com/articles/5-steps-to-perform-a-search-when-user-stops-typing-using-react-+-hooks-in-a-cont</link>
            <guid isPermaLink="false">https://joaoforja.com/articles/5-steps-to-perform-a-search-when-user-stops-typing-using-react-+-hooks-in-a-cont</guid>
            <pubDate>Tue, 21 Jan 2020 22:12:03 GMT</pubDate>
            <content:encoded><![CDATA[<blockquote>
<p>I need to perform a search when the user stops typing. But with React I can't find how it works!</p>
</blockquote>
<p>It's a common use-case to want to perform a search after the user stops typing. This way the user doesn't have to manually click on a button to get feedback from his actions. Despite being a simple use-case to understand, it can present some challenges when trying to implement it with React.</p>
<p>To illustrate the problem and the solution, I'll use a simple React app that makes requests to the Hacker News API based on the values of an input field. For this solution, we'll be using a controlled input and <code>useEffect</code> hook.</p>
<p>As a starting point, we might have something like the code below:</p>
<pre class="language-jsx"><code class="language-jsx"><span class="token keyword module">import</span> <span class="token imports"><span class="token maybe-class-name">React</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> useState<span class="token punctuation">,</span> useEffect<span class="token punctuation">,</span> useReducer <span class="token punctuation">}</span></span> <span class="token keyword module">from</span> <span class="token string">'react'</span>
<span class="token keyword module">import</span> <span class="token imports">axios</span> <span class="token keyword module">from</span> <span class="token string">'axios'</span>

<span class="token keyword">function</span> <span class="token function">fetchReducer</span><span class="token punctuation">(</span><span class="token parameter">state<span class="token punctuation">,</span> action</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword control-flow">switch</span> <span class="token punctuation">(</span>action<span class="token punctuation">.</span><span class="token property-access">type</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">case</span> <span class="token string">'FETCH_START'</span><span class="token operator">:</span>
      <span class="token keyword control-flow">return</span> <span class="token punctuation">{</span>
        <span class="token spread operator">...</span>state<span class="token punctuation">,</span>
        <span class="token literal-property property">isLoading</span><span class="token operator">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span>
        <span class="token literal-property property">hasError</span><span class="token operator">:</span> <span class="token boolean">false</span><span class="token punctuation">,</span>
      <span class="token punctuation">}</span>
    <span class="token keyword">case</span> <span class="token string">'FETCH_SUCCESS'</span><span class="token operator">:</span>
      <span class="token keyword control-flow">return</span> <span class="token punctuation">{</span>
        <span class="token spread operator">...</span>state<span class="token punctuation">,</span>
        <span class="token literal-property property">isLoading</span><span class="token operator">:</span> <span class="token boolean">false</span><span class="token punctuation">,</span>
        <span class="token literal-property property">hasError</span><span class="token operator">:</span> <span class="token boolean">false</span><span class="token punctuation">,</span>
        <span class="token literal-property property">hits</span><span class="token operator">:</span> action<span class="token punctuation">.</span><span class="token property-access">payload</span><span class="token punctuation">,</span>
      <span class="token punctuation">}</span>
    <span class="token keyword">case</span> <span class="token string">'FETCH_FAILURE'</span><span class="token operator">:</span>
      <span class="token keyword control-flow">return</span> <span class="token punctuation">{</span>
        <span class="token spread operator">...</span>state<span class="token punctuation">,</span>
        <span class="token literal-property property">isLoading</span><span class="token operator">:</span> <span class="token boolean">false</span><span class="token punctuation">,</span>
        <span class="token literal-property property">hasError</span><span class="token operator">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span>
      <span class="token punctuation">}</span>
    <span class="token keyword module">default</span><span class="token operator">:</span>
      <span class="token keyword control-flow">throw</span> <span class="token keyword">new</span> <span class="token class-name">Error</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span>

<span class="token keyword">async</span> <span class="token keyword">function</span> <span class="token function">fetchHits</span><span class="token punctuation">(</span><span class="token parameter">query<span class="token punctuation">,</span> dispatch</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token function">dispatch</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token literal-property property">type</span><span class="token operator">:</span> <span class="token string">'FETCH_START'</span> <span class="token punctuation">}</span><span class="token punctuation">)</span>
  <span class="token keyword control-flow">try</span> <span class="token punctuation">{</span>
    <span class="token keyword">const</span> result <span class="token operator">=</span> <span class="token keyword control-flow">await</span> <span class="token function">axios</span><span class="token punctuation">(</span>
      <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">https://hn.algolia.com/api/v1/search?query=</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>query<span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">,</span>
    <span class="token punctuation">)</span>
    <span class="token function">dispatch</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token literal-property property">type</span><span class="token operator">:</span> <span class="token string">'FETCH_SUCCESS'</span><span class="token punctuation">,</span> <span class="token literal-property property">payload</span><span class="token operator">:</span> result<span class="token punctuation">.</span><span class="token property-access">data</span><span class="token punctuation">.</span><span class="token property-access">hits</span> <span class="token punctuation">}</span><span class="token punctuation">)</span>
  <span class="token punctuation">}</span> <span class="token keyword control-flow">catch</span> <span class="token punctuation">(</span>err<span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token function">dispatch</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token literal-property property">type</span><span class="token operator">:</span> <span class="token string">'FETCH_FAILURE'</span> <span class="token punctuation">}</span><span class="token punctuation">)</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span>

<span class="token keyword">function</span> <span class="token function"><span class="token maybe-class-name">App</span></span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">const</span> <span class="token punctuation">[</span><span class="token punctuation">{</span> hits<span class="token punctuation">,</span> hasError<span class="token punctuation">,</span> isLoading <span class="token punctuation">}</span><span class="token punctuation">,</span> dispatch<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">useReducer</span><span class="token punctuation">(</span>fetchReducer<span class="token punctuation">,</span> <span class="token punctuation">{</span>
    <span class="token literal-property property">hits</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
    <span class="token literal-property property">isLoading</span><span class="token operator">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span>
    <span class="token literal-property property">hasError</span><span class="token operator">:</span> <span class="token boolean">false</span><span class="token punctuation">,</span>
  <span class="token punctuation">}</span><span class="token punctuation">)</span>
  <span class="token keyword">const</span> <span class="token punctuation">[</span>query<span class="token punctuation">,</span> setQuery<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">useState</span><span class="token punctuation">(</span><span class="token string">'react'</span><span class="token punctuation">)</span>

  <span class="token function">useEffect</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token arrow operator">=&gt;</span> <span class="token punctuation">{</span>
    <span class="token function">fetchHits</span><span class="token punctuation">(</span>query<span class="token punctuation">,</span> dispatch<span class="token punctuation">)</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">[</span>query<span class="token punctuation">]</span><span class="token punctuation">)</span>

  <span class="token keyword control-flow">return</span> <span class="token punctuation">(</span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span></span><span class="token punctuation">&gt;</span></span><span class="token plain-text">
      </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>input</span>
        <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>text<span class="token punctuation">"</span></span>
        <span class="token attr-name">value</span><span class="token script language-javascript"><span class="token script-punctuation punctuation">=</span><span class="token punctuation">{</span>query<span class="token punctuation">}</span></span>
        <span class="token attr-name">onChange</span><span class="token script language-javascript"><span class="token script-punctuation punctuation">=</span><span class="token punctuation">{</span><span class="token punctuation">(</span><span class="token parameter">event</span><span class="token punctuation">)</span> <span class="token arrow operator">=&gt;</span> <span class="token function">setQuery</span><span class="token punctuation">(</span>event<span class="token punctuation">.</span><span class="token property-access">target</span><span class="token punctuation">.</span><span class="token property-access">value</span><span class="token punctuation">)</span><span class="token punctuation">}</span></span>
      <span class="token punctuation">/&gt;</span></span><span class="token plain-text">
      </span><span class="token punctuation">{</span>hasError <span class="token operator">&amp;&amp;</span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span><span class="token punctuation">&gt;</span></span><span class="token plain-text">Something went wrong ...</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span><span class="token punctuation">}</span><span class="token plain-text">
      </span><span class="token punctuation">{</span>isLoading <span class="token operator">?</span> <span class="token punctuation">(</span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span><span class="token punctuation">&gt;</span></span><span class="token plain-text">Loading ...</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>
      <span class="token punctuation">)</span> <span class="token operator">:</span> <span class="token punctuation">(</span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>ul</span><span class="token punctuation">&gt;</span></span><span class="token plain-text">
          </span><span class="token punctuation">{</span>hits<span class="token punctuation">.</span><span class="token method function property-access">map</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">item</span><span class="token punctuation">)</span> <span class="token arrow operator">=&gt;</span> <span class="token punctuation">(</span>
            <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>li</span> <span class="token attr-name">key</span><span class="token script language-javascript"><span class="token script-punctuation punctuation">=</span><span class="token punctuation">{</span>item<span class="token punctuation">.</span><span class="token property-access">objectID</span><span class="token punctuation">}</span></span><span class="token punctuation">&gt;</span></span><span class="token plain-text">
              </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>a</span> <span class="token attr-name">href</span><span class="token script language-javascript"><span class="token script-punctuation punctuation">=</span><span class="token punctuation">{</span>item<span class="token punctuation">.</span><span class="token property-access">url</span><span class="token punctuation">}</span></span><span class="token punctuation">&gt;</span></span><span class="token punctuation">{</span>item<span class="token punctuation">.</span><span class="token property-access">title</span><span class="token punctuation">}</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>a</span><span class="token punctuation">&gt;</span></span><span class="token plain-text">
            </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>li</span><span class="token punctuation">&gt;</span></span>
          <span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">}</span><span class="token plain-text">
        </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>ul</span><span class="token punctuation">&gt;</span></span>
      <span class="token punctuation">)</span><span class="token punctuation">}</span><span class="token plain-text">
    </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span></span><span class="token punctuation">&gt;</span></span>
  <span class="token punctuation">)</span>
<span class="token punctuation">}</span>
<span class="token keyword module">export</span> <span class="token keyword module">default</span> <span class="token maybe-class-name">App</span>
</code></pre>
<h2>1. Apply debounce</h2>
<p>Since we're using the <code>onChange</code> event handler to trigger calls to <code>setQuery</code>, and given <code>query</code> is a <code>useEffect</code> dependency, for every character the user changes on the input the process of fetching data will be started. As we only want to start fetching data some time after the user has stopped typing, we are going to debounce <code>fetchHits()</code>.</p>
<p>Given that correctly writing a debounce function can be a hard task, we'll be using the <code>debounce()</code> function from Lodash.
A first try might look like this:</p>
<pre class="language-jsx"><code class="language-jsx"><span class="token keyword">function</span> <span class="token function"><span class="token maybe-class-name">App</span></span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">const</span> <span class="token punctuation">[</span><span class="token punctuation">{</span> hits<span class="token punctuation">,</span> hasError<span class="token punctuation">,</span> isLoading <span class="token punctuation">}</span><span class="token punctuation">,</span> dispatch<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">useReducer</span><span class="token punctuation">(</span>fetchReducer<span class="token punctuation">,</span> <span class="token punctuation">{</span>
    <span class="token literal-property property">hits</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
    <span class="token literal-property property">isLoading</span><span class="token operator">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span>
    <span class="token literal-property property">hasError</span><span class="token operator">:</span> <span class="token boolean">false</span><span class="token punctuation">,</span>
  <span class="token punctuation">}</span><span class="token punctuation">)</span>
  <span class="token keyword">const</span> <span class="token punctuation">[</span>query<span class="token punctuation">,</span> setQuery<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">useState</span><span class="token punctuation">(</span><span class="token string">'react'</span><span class="token punctuation">)</span>

  <span class="token function">useEffect</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token arrow operator">=&gt;</span> <span class="token punctuation">{</span>
    _<span class="token punctuation">.</span><span class="token method function property-access">debounce</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token arrow operator">=&gt;</span> <span class="token function">fetchHits</span><span class="token punctuation">(</span>query<span class="token punctuation">,</span> dispatch<span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token number">500</span><span class="token punctuation">)</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">[</span>query<span class="token punctuation">]</span><span class="token punctuation">)</span>

  <span class="token keyword control-flow">return</span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span></span><span class="token punctuation">&gt;</span></span><span class="token plain-text">...</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span></span><span class="token punctuation">&gt;</span></span>
<span class="token punctuation">}</span>
</code></pre>
<p>If you run the new version of the code, you'll notice that although there is a delay between the user typing and <code>fetchHits()</code> being called, there's still going to be one call every time the user types something. Even though we've debounced <code>fetchHits()</code>, we're not using the same debounced function on every render of the component. A new debounced version of <code>fetchHits()</code> is being created every time <code>useEffect</code> runs. In order for this solution to work, we need to guarantee that it's always the same debounced function that is called for the lifetime of the component.</p>
<h2>2. Keep the identity of the debounced function</h2>
<p>To keep the identity of the function through the lifetime of the component, we'll be using the <code>useRef</code> hook.</p>
<p>At first, it might seem like a good idea to use the <code>useCallback</code> or <code>useMemo</code> hooks. However, those hooks do not guarantee the identity of the value given to them across all renders, which might lead to hard to track bugs in our case. If you're not sure why this might lead to bugs, you'll find this <a href="/articles/a-common-misconception-with-use-memo-and-use-callback/">article</a> interesting.</p>
<pre class="language-jsx"><code class="language-jsx"><span class="token keyword">function</span> <span class="token function"><span class="token maybe-class-name">App</span></span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">const</span> <span class="token punctuation">[</span><span class="token punctuation">{</span> hits<span class="token punctuation">,</span> hasError<span class="token punctuation">,</span> isLoading <span class="token punctuation">}</span><span class="token punctuation">,</span> dispatch<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">useReducer</span><span class="token punctuation">(</span>fetchReducer<span class="token punctuation">,</span> <span class="token punctuation">{</span>
    <span class="token literal-property property">hits</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
    <span class="token literal-property property">isLoading</span><span class="token operator">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span>
    <span class="token literal-property property">hasError</span><span class="token operator">:</span> <span class="token boolean">false</span><span class="token punctuation">,</span>
  <span class="token punctuation">}</span><span class="token punctuation">)</span>
  <span class="token keyword">const</span> <span class="token punctuation">[</span>query<span class="token punctuation">,</span> setQuery<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">useState</span><span class="token punctuation">(</span><span class="token string">'react'</span><span class="token punctuation">)</span>
  <span class="token keyword">const</span> debouncedFetchHits <span class="token operator">=</span> <span class="token function">useRef</span><span class="token punctuation">(</span>
    _<span class="token punctuation">.</span><span class="token method function property-access">debounce</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">query</span><span class="token punctuation">)</span> <span class="token arrow operator">=&gt;</span> <span class="token function">fetchHits</span><span class="token punctuation">(</span>query<span class="token punctuation">,</span> dispatch<span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token number">500</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
  <span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token property-access">current</span>

  <span class="token function">useEffect</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token arrow operator">=&gt;</span> <span class="token punctuation">{</span>
    <span class="token function">debouncedFetchHits</span><span class="token punctuation">(</span>query<span class="token punctuation">)</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">[</span>debouncedFetchHits<span class="token punctuation">,</span> query<span class="token punctuation">]</span><span class="token punctuation">)</span>

  <span class="token keyword control-flow">return</span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span></span><span class="token punctuation">&gt;</span></span><span class="token plain-text">...</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span></span><span class="token punctuation">&gt;</span></span>
<span class="token punctuation">}</span>
</code></pre>
<p>You may have noticed that we added <code>query</code> as an argument to the debounced version of <code>fetchHits()</code>. This is necessary since we'll be using the same function throughout the lifetime of the component. If we had captured <code>query</code> through a closure, the value of <code>query</code> used by the debounced version of <code>fetchHits()</code> would always be the one present on the component's first render. This is not a problem with <code>dispatch</code> since React guarantees that the identity of <code>dispatch</code> is stable through the lifetime of the component.</p>
<p>If you try this code now, it will look like everything is working fine. But actually, there still are some bugs that we need to fix.</p>
<h2>3. Cancel irrelevant requests</h2>
<p>When making asynchronous requests, we must not forget that we have no guarantees regarding how much time those requests will take to complete, neither if the requests will be completed in the same order that they were done. What this means for our app, is that a user might have an old search of his, override the result of a new one.</p>
<p>To further illustrate the problem, let's examine the following scenario:</p>
<ol>
<li>A user makes a search for MobX.</li>
<li>Waits debounce time.</li>
<li>Before getting a response from the API, searches for Redux.</li>
<li>Waits debounce time.</li>
</ol>
<p>Now, which search result will the user see? The answer is, we don't know. It's a race condition! Whichever API request is solved last, is the one that the user will end up seeing. And if that ends up being the search request for MobX, the user won't get what he's expecting.</p>
<p>One way to fix this issue is to cancel the API requests made for searches that the user is no longer interested in. To do that, we'll use Axios cancellation API, and we'll add a clean-up function to <code>useEffect</code> to trigger the cancellation.</p>
<pre class="language-jsx"><code class="language-jsx"><span class="token keyword">async</span> <span class="token keyword">function</span> <span class="token function">fetchHits</span><span class="token punctuation">(</span><span class="token parameter">query<span class="token punctuation">,</span> dispatch<span class="token punctuation">,</span> cancelToken</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token function">dispatch</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token literal-property property">type</span><span class="token operator">:</span> <span class="token string">'FETCH_START'</span> <span class="token punctuation">}</span><span class="token punctuation">)</span>
  <span class="token keyword control-flow">try</span> <span class="token punctuation">{</span>
    <span class="token keyword">const</span> result <span class="token operator">=</span> <span class="token keyword control-flow">await</span> <span class="token function">axios</span><span class="token punctuation">(</span>
      <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">https://hn.algolia.com/api/v1/search?query=</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>query<span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">,</span>
      <span class="token punctuation">{</span>
        cancelToken<span class="token punctuation">,</span>
      <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token punctuation">)</span>
    <span class="token function">dispatch</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token literal-property property">type</span><span class="token operator">:</span> <span class="token string">'FETCH_SUCCESS'</span><span class="token punctuation">,</span> <span class="token literal-property property">payload</span><span class="token operator">:</span> result<span class="token punctuation">.</span><span class="token property-access">data</span><span class="token punctuation">.</span><span class="token property-access">hits</span> <span class="token punctuation">}</span><span class="token punctuation">)</span>
  <span class="token punctuation">}</span> <span class="token keyword control-flow">catch</span> <span class="token punctuation">(</span>err<span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token console class-name">console</span><span class="token punctuation">.</span><span class="token method function property-access">error</span><span class="token punctuation">(</span>err<span class="token punctuation">)</span>
    axios<span class="token punctuation">.</span><span class="token method function property-access">isCancel</span><span class="token punctuation">(</span>err<span class="token punctuation">)</span> <span class="token operator">||</span> <span class="token function">dispatch</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token literal-property property">type</span><span class="token operator">:</span> <span class="token string">'FETCH_FAILURE'</span> <span class="token punctuation">}</span><span class="token punctuation">)</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span>

<span class="token keyword">function</span> <span class="token function"><span class="token maybe-class-name">App</span></span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">const</span> <span class="token punctuation">[</span><span class="token punctuation">{</span> hits<span class="token punctuation">,</span> hasError<span class="token punctuation">,</span> isLoading <span class="token punctuation">}</span><span class="token punctuation">,</span> dispatch<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">useReducer</span><span class="token punctuation">(</span>fetchReducer<span class="token punctuation">,</span> <span class="token punctuation">{</span>
    <span class="token literal-property property">hits</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
    <span class="token literal-property property">isLoading</span><span class="token operator">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span>
    <span class="token literal-property property">hasError</span><span class="token operator">:</span> <span class="token boolean">false</span><span class="token punctuation">,</span>
  <span class="token punctuation">}</span><span class="token punctuation">)</span>
  <span class="token keyword">const</span> <span class="token punctuation">[</span>query<span class="token punctuation">,</span> setQuery<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">useState</span><span class="token punctuation">(</span><span class="token string">'react'</span><span class="token punctuation">)</span>
  <span class="token keyword">const</span> debouncedFetchHits <span class="token operator">=</span> <span class="token function">useRef</span><span class="token punctuation">(</span>
    _<span class="token punctuation">.</span><span class="token method function property-access">debounce</span><span class="token punctuation">(</span>
      <span class="token punctuation">(</span><span class="token parameter">query<span class="token punctuation">,</span> cancelToken</span><span class="token punctuation">)</span> <span class="token arrow operator">=&gt;</span> <span class="token function">fetchHits</span><span class="token punctuation">(</span>query<span class="token punctuation">,</span> dispatch<span class="token punctuation">,</span> cancelToken<span class="token punctuation">)</span><span class="token punctuation">,</span>
      <span class="token number">500</span><span class="token punctuation">,</span>
    <span class="token punctuation">)</span><span class="token punctuation">,</span>
  <span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token property-access">current</span>

  <span class="token function">useEffect</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token arrow operator">=&gt;</span> <span class="token punctuation">{</span>
    <span class="token keyword">const</span> <span class="token punctuation">{</span> cancel<span class="token punctuation">,</span> token <span class="token punctuation">}</span> <span class="token operator">=</span> axios<span class="token punctuation">.</span><span class="token property-access"><span class="token maybe-class-name">CancelToken</span></span><span class="token punctuation">.</span><span class="token method function property-access">source</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
    <span class="token function">debouncedFetchHits</span><span class="token punctuation">(</span>query<span class="token punctuation">,</span> token<span class="token punctuation">)</span>
    <span class="token keyword control-flow">return</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token arrow operator">=&gt;</span> <span class="token function">cancel</span><span class="token punctuation">(</span><span class="token string">'No longer latest query'</span><span class="token punctuation">)</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">[</span>debouncedFetchHits<span class="token punctuation">,</span> query<span class="token punctuation">]</span><span class="token punctuation">)</span>

  <span class="token keyword control-flow">return</span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span></span><span class="token punctuation">&gt;</span></span><span class="token plain-text">...</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span></span><span class="token punctuation">&gt;</span></span>
<span class="token punctuation">}</span>
</code></pre>
<h2>4. Avoid invoking debounced function on unmounted component</h2>
<p>We're almost done. There's still only one minor detail we need to address. On the unlikely event that the component unmounts before the debounced <code>fetchHits()</code> is invoked, <code>dispatch</code> will be called on an unmounted component. Thus a warning will be shown on the console saying that our app might have memory leaks. For this specific case, there is no memory leak. But we can get rid of that warning by canceling the execution of the debounced function on the <code>useEffect</code> cleanup.</p>
<pre class="language-jsx"><code class="language-jsx"><span class="token function">useEffect</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token arrow operator">=&gt;</span> <span class="token punctuation">{</span>
  <span class="token keyword">const</span> <span class="token punctuation">{</span> cancel<span class="token punctuation">,</span> token <span class="token punctuation">}</span> <span class="token operator">=</span> axios<span class="token punctuation">.</span><span class="token property-access"><span class="token maybe-class-name">CancelToken</span></span><span class="token punctuation">.</span><span class="token method function property-access">source</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
  <span class="token function">debouncedFetchHits</span><span class="token punctuation">(</span>query<span class="token punctuation">,</span> token<span class="token punctuation">)</span>
  <span class="token keyword control-flow">return</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token arrow operator">=&gt;</span> <span class="token function">cancel</span><span class="token punctuation">(</span><span class="token string">'No longer latest query'</span><span class="token punctuation">)</span> <span class="token operator">||</span> debouncedFetchHits<span class="token punctuation">.</span><span class="token method function property-access">cancel</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">[</span>debouncedFetchHits<span class="token punctuation">,</span> query<span class="token punctuation">]</span><span class="token punctuation">)</span>
</code></pre>
<p>From the perspective of the behavior of the app, we are done! There are, however, some simplifications that we can do.</p>
<h2>5. Simplify</h2>
<p>If you were looking carefully, you might have noticed that since we're canceling the debounced <code>fetchHits()</code> on every <code>useEffect</code> clean up, we no longer need to guarantee that the identity of the debounced <code>fetchHits()</code> remains the same through the lifetime of the component. Because we'll always be canceling the old debounce function before calling the new one. Therefore, we can now debounce <code>fetchHits()</code> inside the <code>useEffect</code> hooks.</p>
<pre class="language-jsx"><code class="language-jsx"><span class="token function">useEffect</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token arrow operator">=&gt;</span> <span class="token punctuation">{</span>
  <span class="token keyword">const</span> <span class="token punctuation">{</span> cancel<span class="token punctuation">,</span> token <span class="token punctuation">}</span> <span class="token operator">=</span> axios<span class="token punctuation">.</span><span class="token property-access"><span class="token maybe-class-name">CancelToken</span></span><span class="token punctuation">.</span><span class="token method function property-access">source</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
  <span class="token keyword">const</span> debouncedFetchHits <span class="token operator">=</span> _<span class="token punctuation">.</span><span class="token method function property-access">debounce</span><span class="token punctuation">(</span>
    <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token arrow operator">=&gt;</span> <span class="token function">fetchHits</span><span class="token punctuation">(</span>query<span class="token punctuation">,</span> dispatch<span class="token punctuation">,</span> token<span class="token punctuation">)</span><span class="token punctuation">,</span>
    <span class="token number">500</span><span class="token punctuation">,</span>
  <span class="token punctuation">)</span>
  <span class="token function">debouncedFetchHits</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
  <span class="token keyword control-flow">return</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token arrow operator">=&gt;</span> <span class="token function">cancel</span><span class="token punctuation">(</span><span class="token string">'No longer latest query'</span><span class="token punctuation">)</span> <span class="token operator">||</span> debouncedFetchHits<span class="token punctuation">.</span><span class="token method function property-access">cancel</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">[</span>query<span class="token punctuation">]</span><span class="token punctuation">)</span>
</code></pre>
<p>But now, we are using <code>debounce()</code> as a simple timeout function. So we can use the browser's <code>setTimeout()</code> instead and get rid of the Lodash dependency.</p>
<pre class="language-jsx"><code class="language-jsx"><span class="token keyword">function</span> <span class="token function"><span class="token maybe-class-name">App</span></span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">const</span> <span class="token punctuation">[</span><span class="token punctuation">{</span> hits<span class="token punctuation">,</span> hasError<span class="token punctuation">,</span> isLoading <span class="token punctuation">}</span><span class="token punctuation">,</span> dispatch<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">useReducer</span><span class="token punctuation">(</span>fetchReducer<span class="token punctuation">,</span> <span class="token punctuation">{</span>
    <span class="token literal-property property">hits</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
    <span class="token literal-property property">isLoading</span><span class="token operator">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span>
    <span class="token literal-property property">hasError</span><span class="token operator">:</span> <span class="token boolean">false</span>
  <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token keyword">const</span> <span class="token punctuation">[</span>query<span class="token punctuation">,</span> setQuery<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">useState</span><span class="token punctuation">(</span><span class="token string">"react"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

  <span class="token function">useEffect</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token arrow operator">=&gt;</span> <span class="token punctuation">{</span>
    <span class="token keyword">const</span> <span class="token punctuation">{</span> cancel<span class="token punctuation">,</span> token <span class="token punctuation">}</span> <span class="token operator">=</span> axios<span class="token punctuation">.</span><span class="token property-access"><span class="token maybe-class-name">CancelToken</span></span><span class="token punctuation">.</span><span class="token method function property-access">source</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">const</span> timeOutId <span class="token operator">=</span> <span class="token function">setTimeout</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token arrow operator">=&gt;</span> <span class="token function">fetchHits</span><span class="token punctuation">(</span>query<span class="token punctuation">,</span> dispatch<span class="token punctuation">,</span> token<span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token number">500</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword control-flow">return</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token arrow operator">=&gt;</span> <span class="token function">cancel</span><span class="token punctuation">(</span><span class="token string">"No longer latest query"</span><span class="token punctuation">)</span> <span class="token operator">||</span> <span class="token function">clearTimeout</span><span class="token punctuation">(</span>timeOutId<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">[</span>query<span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

  <span class="token keyword control-flow">return</span> <span class="token spread operator">...</span>
<span class="token punctuation">}</span>
</code></pre>
<p>And we are finally done!</p>
<p>I could have just jumped straight to this final solution using <code>setTimeout()</code> instead of having gone through Lodash <code>debounce()</code>. But I think that going through all these steps is an enriching experience. Since it touches on interesting details of React and on how to correctly use a debounce function with React hooks that may be applicable in other contexts.</p>
<h2>Put it into practice</h2>
<p>Next time you're faced with having to perform a search only when the user stops typing, remember to:</p>
<ol>
<li>Use <code>setTimeout()</code> to create a small delay between when the user stops typing and making a call to the API</li>
<li>Clear the timeout on the <code>useEffect</code> hook cleanup to avoid making multiple calls to the API and to avoid performing actions on an unmounted component.</li>
<li>Cancel the requests that are no longer relevant to the user, on the <code>useEffect</code> hook cleanup, to guarantee the user won't see results of old searches instead of the most recent search.</li>
</ol>
<hr>
<p>If you enjoyed this article, you might also like <a href="/articles/how-to-implement-infinite-scroll-in-react/">this one</a> about how to implement infinite scroll with React using Hooks and Intersection Observers.</p>]]></content:encoded>
            <author>João Forja</author>
        </item>
        <item>
            <title><![CDATA[7 questions to find out corner cases when fetching data from an API in a React application.]]></title>
            <link>https://joaoforja.com/articles/7-questions-for-fetching-data-in-a-react-app</link>
            <guid isPermaLink="false">https://joaoforja.com/articles/7-questions-for-fetching-data-in-a-react-app</guid>
            <pubDate>Wed, 15 Apr 2020 16:12:03 GMT</pubDate>
            <content:encoded><![CDATA[<blockquote>
<p>Anyone can write a basic fetch request and get some data back. But what other things should be considered? What are more production-grade requirements?</p>
</blockquote>
<p>Fetching data from APIs is something that almost all React applications do. However, this doesn't mean doing it correctly is easy. While it's straightforward to fetch data and show it on the screen, it's not trivial to get all the corner cases right.</p>
<p>In this article, we'll go over 7 questions we can make to find out corner cases when fetching data from an API. We'll start with an overview of all of them, and then go into detail on each one.</p>
<h2>Questions</h2>
<ol>
<li>Are we canceling API requests when the response is no longer needed?</li>
<li>Are we handling all possible error and success cases?</li>
<li>Can the application handle exceptions thrown from API requests?</li>
<li>Is it possible for the user to get stuck on a loading screen?</li>
<li>Is the application ready to deal with API requests that may take a while to complete?</li>
<li>When will it be necessary to fetch the data again?</li>
<li>Are we handling race conditions?</li>
</ol>
<h2>Are we canceling API requests when the response is no longer needed?</h2>
<p>When the result of an API request isn't needed anymore, we should cancel it. Otherwise, we might run into errors like <code>Can't call setState on an unmounted component,</code> or we might end up showing the user information that isn't correct.</p>
<p>There are multiple ways for the data returned from an API request to become unnecessary. I find out that the most common ones are when the component that was going to store the data is no longer mounted, and when the <code>state</code>/<code>props</code> used to make the request or handle its response are no longer up to date.</p>
<h2>Are we handling all possible error and success cases?</h2>
<p>When fetching data from an API it's easy to think of successes and errors as rendering data on the screen or showing a generic error message. However, it can be a lot more complicated than that.</p>
<p><em>We might not want to handle all success responses equally</em>. As an example, we might be fetching data from a collection. What happens when the collection is empty? We may want to redirect the user to another page or render a custom screen just for that situation. Another example is implementing <a href="/articles/how-to-implement-infinite-scroll-in-react/">infinite scroll</a>. The user may, eventually, reach the end of the feed. How will the application handle that?</p>
<p>The same is true for errors. For some errors, a generic try again message might be the only solution. However, other errors may require different approaches. If we're making a request to an API that needs authentication, we might have an error due to an expired session. On an expired session, it might be a good idea to tell the user that his session has expired and that he'll have to log in again. Other errors might be sporadic, and it might be a good idea to retry the request before showing an error message.</p>
<p>Handling the variety of responses from an API can have a significant impact on the design of the application. So it's essential to be aware of them when implementing a solution.</p>
<h2>Can the application handle exceptions thrown from API requests?</h2>
<p>It's easy to forget that the API we're using to make requests may throw an exception. To avoid the application crashing horribly in the hands of our users, it's a good idea to <code>.catch()</code> those errors or to surround them in a try-catch block.</p>
<h2>Is it possible for the user to get stuck on a loading screen?</h2>
<p>When it's necessary, we rarely forget to set a component state to loading when we're going to fetch data. But what about removing that loading state? When we get our code ready to handle exceptions and error responses, depending on how we designed our code, it's easy to let an execution path slip by that doesn't remove the loading state. Better to keep an eye out for it.</p>
<h2>Is the application ready to deal with API requests that may take a while to complete?</h2>
<p>Due to a server receiving a lot of traffic at the time of the request or simply because the API request triggers an operation that takes a while to complete, the user might be left watching a loading screen.</p>
<p>To prevent a depressing UX, we need to be aware of when loading might take a while and choose an appropriate strategy to mitigate it. Common strategies involve setting a timeout for the request to showing an entertaining UI to make time go by faster.</p>
<h2>When will it be necessary to fetch the data again?</h2>
<p>As soon as we get data back from the server, it might already be stale. If that's a problem or not depends on the domain and nature of the application and data.</p>
<p>In real-time applications, there's a high effort to keep data in sync between server and clients. But on a blog, we can wait for the user to navigate back to the page to show him the most up to date articles.</p>
<p>The crucial thing here is to analyze the domain and nature of the application and data and look for situations where the <em>user not seeing the most up to date data might be problematic</em>.</p>
<h2>Are we handling race conditions?</h2>
<p>A common pitfall when making API requests that may run in parallel is to forget that <em>the order in which we made the requests, is not necessarily the same order in which we'll get the responses</em>. For example, if we make request A followed by B, we might get the response from B first than A. Depending on the context, this might lead to inconsistent and buggy behavior.</p>
<p>A classic example where this might be an issue, is when making a <a href="/articles/5-steps-to-perform-a-search-when-user-stops-typing-using-react-+-hooks-in-a-controlled-component/">search box</a> with auto-complete. If we make an API request each time the search box query changes, we'll end making multiple requests that will run in parallel. When we're not careful to display the response related to the most up to date query, we may have a response from an older query override the most recent one.</p>
<h2>Conclusion</h2>
<p>Correctly handling all the corner cases of fetching data from an API can be hard. One way to deal with it is to have strategies we can systematically apply and rely on. These seven questions are part of my strategy to deal with fetching data. Another useful strategy is to send logs made on the application to a server for later analysis. Analyzing logs can help track undesired behaviors.</p>
<p>Next time you have to fetch data for an application, give these questions a try and see how many corner cases you uncover because of them.</p>
<p><em>Programming with strategies and principles is useful regardless of what we're building.</em> I'd say it is the cornerstone of consistently making high-quality software. If this idea resonates with you, subscribe to the newsletter at the end of this page. I'm always trying to improve my strategies and development processes, and I share my findings in this blog.</p>
<p>I hope this article is useful to you, and feel free to hit me up on <a href="https://twitter.com/JooForja">twitter</a> if you want to talk about it :)</p>]]></content:encoded>
            <author>João Forja</author>
        </item>
        <item>
            <title><![CDATA[A common misconception with useMemo and useCallback]]></title>
            <link>https://joaoforja.com/articles/a-common-misconception-with-use-memo-and-use-callback</link>
            <guid isPermaLink="false">https://joaoforja.com/articles/a-common-misconception-with-use-memo-and-use-callback</guid>
            <pubDate>Tue, 24 Mar 2020 09:12:03 GMT</pubDate>
            <content:encoded><![CDATA[<p>If you've been programming with React for a while, you have already used <code>useCallback</code> and <code>useMemo</code> hooks. A common misconception with <code>useCallback</code> and <code>useMemo</code> is that their purpose is to preserve the identity of values across renders. However, their goal is to optimize the performance of React applications.</p>
<p>The difference might seem meaningless since performance will be optimized by recomputing values only if a dependency changes. This makes us think that the identity of the memoized value should be preserved. And it will, but not always.</p>
<p>If we take a look at React's <a href="https://reactjs.org/docs/hooks-reference.html#usecallback">documentation</a> on <code>useCallback</code> and <code>useMemo</code>, we can find the following:</p>
<blockquote>
<p>useCallback(fn, deps) is equivalent to useMemo(() =&gt; fn, deps)</p>
</blockquote>
<blockquote>
<p><strong>You may rely on useMemo as a performance optimization, not as a semantic guarantee.</strong> In the future, React may choose to “forget” some previously memoized values and recalculate them on next render, e.g. to free memory for offscreen components. Write your code so that it still works without useMemo — and then add it to optimize performance.</p>
</blockquote>
<p>If by reading the documentation, you're still not sure if when using <code>useCallback</code> you should have the same considerations as when using <code>useMemo</code>, you can check this <a href="https://github.com/facebook/react/issues/15278">issue</a> on React's repository.</p>
<p>In short, what the documentation tells us, is that we can't rely on <code>useMemo</code> and <code>useCallback</code> as a means to preserve identity, only as a performance optimization that might recompute the memoized value when it sees fit.</p>
<h2>When might this misconception be a problem</h2>
<p>Whenever we reach for <code>useMemo</code> or <code>useCallback</code> and preserving the identity across renders of a value or callback is crucial for our app to work correctly, we are susceptible to bugs.</p>
<p>A concrete example is when using a debounced function. When using a debounced function, we need to make sure that we're preserving its identity. Otherwise, it won't work as expected.</p>
<p>Let's imagine a use-case where we want to perform a search only after the user stops typing. For that, we are going to
debounce the function that will trigger the API request, and have it called every time the user types something.</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">function</span> <span class="token function">fetchHits</span><span class="token punctuation">(</span><span class="token parameter">query<span class="token punctuation">,</span> dispatch</span><span class="token punctuation">)</span><span class="token punctuation">{</span> <span class="token comment">/* Makes API call*/</span> <span class="token punctuation">}</span>
<span class="token keyword">function</span> <span class="token function"><span class="token maybe-class-name">App</span></span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token spread operator">...</span>
  <span class="token keyword">const</span> debouncedFetchHits <span class="token operator">=</span> <span class="token function">debounce</span><span class="token punctuation">(</span><span class="token parameter">query</span> <span class="token arrow operator">=&gt;</span> <span class="token function">fetchHits</span><span class="token punctuation">(</span>query<span class="token punctuation">,</span> dispatch<span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token number">500</span><span class="token punctuation">)</span>
  <span class="token keyword control-flow">return</span> <span class="token operator">&lt;</span><span class="token operator">&gt;</span><span class="token spread operator">...</span><span class="token operator">&lt;</span><span class="token operator">/</span><span class="token operator">&gt;</span>
<span class="token punctuation">}</span>
</code></pre>
<p>Due to the nature of React function components, we know that the identity <code>debouncedFetchHits</code> won't be preserved across renders. So our implementation is broken. To fix that, we'll wrap the debounced function in a <code>useCallback</code>.</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">function</span> <span class="token function">fetchHits</span><span class="token punctuation">(</span><span class="token parameter">query<span class="token punctuation">,</span> dispatch</span><span class="token punctuation">)</span><span class="token punctuation">{</span> <span class="token comment">/* Makes API call*/</span> <span class="token punctuation">}</span>
<span class="token keyword">function</span> <span class="token function"><span class="token maybe-class-name">App</span></span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token spread operator">...</span>
  <span class="token keyword">const</span> debouncedFetchHits <span class="token operator">=</span> <span class="token function">useCallback</span><span class="token punctuation">(</span>
    <span class="token function">debounce</span><span class="token punctuation">(</span><span class="token parameter">query</span> <span class="token arrow operator">=&gt;</span> <span class="token function">fetchHits</span><span class="token punctuation">(</span>query<span class="token punctuation">,</span> dispatch<span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token number">500</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
    <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">)</span>
    <span class="token comment">// NOTE: fetchHits is on outer scope, so it shouldn't be in the dependencies []</span>
  <span class="token keyword control-flow">return</span> <span class="token operator">&lt;</span><span class="token operator">&gt;</span><span class="token spread operator">...</span><span class="token operator">&lt;</span><span class="token operator">/</span><span class="token operator">&gt;</span>
<span class="token punctuation">}</span>
</code></pre>
<p>If we test this solution, it will seem to work. However, it might not work all the time since the identity of <code>debouncedFetchHits</code> might not always be the same across renders. In our use-case, that would mean that, occasionally, we would be making API requests for queries that aren't relevant to the user, and showing him results that are not of his interest.</p>
<p>Note: If you'd like to know how to fully implement the perform a search only after the user stops typing use-case, you might like this <a href="/articles/5-steps-to-perform-a-search-when-user-stops-typing-using-react-+-hooks-in-a-controlled-component/">article</a>.</p>
<h2>Solution</h2>
<p>The solution is to use <code>useRef</code> hook instead of the <code>useCallback</code>.</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">function</span> <span class="token function">fetchHits</span><span class="token punctuation">(</span><span class="token parameter">query<span class="token punctuation">,</span> dispatch</span><span class="token punctuation">)</span><span class="token punctuation">{</span> <span class="token comment">/* Makes API call*/</span> <span class="token punctuation">}</span>
<span class="token keyword">function</span> <span class="token function"><span class="token maybe-class-name">App</span></span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token spread operator">...</span>
<span class="token keyword">const</span> debouncedFetchHits <span class="token operator">=</span> <span class="token function">useRef</span><span class="token punctuation">(</span>
    <span class="token function">debounce</span><span class="token punctuation">(</span><span class="token parameter">query</span> <span class="token arrow operator">=&gt;</span> <span class="token function">fetchHits</span><span class="token punctuation">(</span>query<span class="token punctuation">,</span> dispatch<span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token number">500</span><span class="token punctuation">)</span>
  <span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token property-access">current</span>
  <span class="token keyword control-flow">return</span> <span class="token operator">&lt;</span><span class="token operator">&gt;</span><span class="token spread operator">...</span><span class="token operator">&lt;</span><span class="token operator">/</span><span class="token operator">&gt;</span>
<span class="token punctuation">}</span>
</code></pre>
<p>The <code>useRef</code> hook gives us the semantic guarantee of identity across renders that <code>useCallback</code> and <code>useMemo</code> don't. Thus, we no longer need to worry about hard to track bugs caused by changes to the identity of <code>debouncedFetchHits</code>.</p>
<h2>Conclusion</h2>
<p>Next time you reach out to <code>useMemo</code> or <code>useCallback</code>, ask yourself if you want to do a performance optimization or if you want a guarantee of identity. If what you're looking for is a performance optimization, <code>useMemo</code> and <code>useCallback</code> are the way to go. Otherwise, <code>useRef</code> is what you're looking for.</p>]]></content:encoded>
            <author>João Forja</author>
        </item>
        <item>
            <title><![CDATA[Guideline from the 70's on how to split your React components]]></title>
            <link>https://joaoforja.com/articles/guideline-on-how-to-decompose-a-react-component</link>
            <guid isPermaLink="false">https://joaoforja.com/articles/guideline-on-how-to-decompose-a-react-component</guid>
            <pubDate>Sun, 15 Aug 2021 12:12:03 GMT</pubDate>
            <content:encoded><![CDATA[<blockquote>
<p>Are there particular guidelines to follow when deciding how to split a React component?</p>
</blockquote>
<p>Deciding how to break a component into sub-components isn't easy and is a challenge that isn't specific to React. This is fortunate since it means we can go outside React's ecosystem and get some ideas on how to do it.</p>
<p>In this article, I'll present a guideline to validate ideas on splitting a React component to increase code reuse and reduce maintenance costs. This guideline comes from the paper "Designing Software for Ease of Extension and Contraction" written in 1979 by David Parnas.</p>
<p>To paraphrase Parnas:</p>
<blockquote>
<p>Component A is allowed to use component B when all the following conditions
are met:</p>
<ol>
<li>A is essentially simpler because it uses B.</li>
<li>B is not substantially more complex because it is not
allowed to use A.</li>
<li>There is a useful subset containing B but not A.</li>
<li>There is no conceivable useful subset containing A but not B.</li>
</ol>
</blockquote>
<p>Let's clarify a bit each of the criteria:</p>
<ol>
<li>Since A will become simpler to implement because it uses B, that relationship makes sense to exist.</li>
<li>We want to avoid cyclic dependencies for all the known reasons, and we also want to keep our components as simple as possible. Situations where two components benefit from using each other, hint that the decomposition needs some rework.</li>
<li>It only makes sense for B to exist without A if component B is useful to other components besides A.</li>
<li>An implementation of A that doesn't have the functionality provided by B doesn't make sense.</li>
</ol>
<p>For the context of this article, we can consider that the term "use" means to allow a component to reference another one in the code. In truth, it is more nuanced than that, but I won't get into that in this article.</p>
<p>To make this all concrete, let's look at a Video Player component as an example.</p>
<p>The requirements for the Video Player are:</p>
<ol>
<li>Optimized for videos with a 16:9 aspect ratio.</li>
<li>Supports play and pause any time during the video.</li>
<li>Allows for quick navigation to any part of the video.</li>
<li>Supports mute and unmute.</li>
<li>Has full-screen support.</li>
</ol>
<p><img src="/articles/guideline-on-how-to-decompose-a-react-component/VideoPlayerMockup.png" alt="Mockup of VideoPlayer" title="Mockup of VideoPlayer"></p>
<h2>Valid decomposition</h2>
<p>By looking at the requirements and the mockup, one way to split the component would be:
<img src="/articles/guideline-on-how-to-decompose-a-react-component/ValidSplit.png" alt="Mockup of VideoPlayer with the different used components highlighted" title="Mockup of VideoPlayer with the different used components highlighted"></p>
<p>As shown above, VideoPlayer can be decomposed into 4 different components: <a href="https://css-tricks.com/aspect-ratio-boxes/">AspectRatioBox</a>, SliderInput, Button, and Icons. This is not an exhaustive decomposition, but for the purpose of this article, it should be enough.</p>
<p>Let's go over AspectRatioBox and see if it should be its own component according to the guideline.</p>
<h3>VideoPlayer is essentially simpler because it uses AspectRatioBox.</h3>
<p>If VideoPlayer didn't use AspectRatioBox it would have to implement that functionality itself, which would make it more complex than if it used AspectRatioBox.</p>
<h3>AspectRatioBox isn't substantially more complex because it can't use VideoPlayer.</h3>
<p>There's no scenario in which AspectRatioBox would benefit from using VideoPlayer, therefore prohibiting it from using the VideoPlayer won't affect its complexity.</p>
<h3>There is a useful subset containing an AspectRatioBox but not a VideoPlayer.</h3>
<p>Any time we need to define an element's aspect ratio, the AspectRatioBox will be useful. Hero Images with a background and a grid/list of thumbnails are examples of other situations where the AspectRatioBox would be useful.</p>
<h3>There is no conceivable useful subset containing VideoPlayer but not AspectRatioBox box.</h3>
<p>Given the requirements for VideoPlayer, I don't see how it could be implemented without the behavior that AspectRatioBox provides.</p>
<p>There will be situations where it isn't obvious if some of the above criteria hold up before starting the implementation. The same can be said about figuring out how to split a component. My suggestion is to first come up with a rough idea on how to split the component, follow it, and keep re-evaluating it as the implementation progresses.</p>
<h2>Invalid decomposition</h2>
<p>Let's try a slightly different split and see how it holds up:</p>
<p><img src="/articles/guideline-on-how-to-decompose-a-react-component/InvalidSplit.png" alt="Mockup of VideoPlayer highlighting the bar containing the player's button as its own component" title="Mockup of VideoPlayer highlighting the bar containing the player's button as its own component"></p>
<p>We've added an ActionsBar component that contains all the actions a user can do. It is supposed to be a simple UI component that receives callbacks for when the user clicks on the buttons. Let's analyze how it holds up:</p>
<h3>VideoPlayer is essentially simpler because it uses ActionsBar.</h3>
<p>This one I'm not entirely sure about. ActionsBar would have to receive a lot of callbacks from VideoPlayer would they be separate components, and that could end up resulting in more code cognitive load as we'd be forced to create all of those callbacks and pass them around. If I were to make this separation between VideoPlayer and ActionsBar, I'd keep an eye out during implementation for whether VideoPlayer was simpler because it used ActionsBar or not.</p>
<h3>ActionsBar isn't substantially more complex because it can't use the VideoPlayer.</h3>
<p>There's no scenario in which ActionsBar would benefit from using VideoPlayer, thus prohibiting it from using the VideoPlayer won't be an issue.</p>
<h3>There is a useful subset containing ActionBar but not a VideoPlayer.</h3>
<p>I'd argue that there isn't. The visuals and actions provided by ActionsBar are really specific to VideoPlayer.</p>
<h3>There is no conceivable useful subset containing VideoPlayer but not ActionsBar.</h3>
<p>Given the requirements for VideoPlayer, it will always need to have the behavior and UI provided by ActionsBar.</p>
<p>As we've seen, ActionsBar is not a good candidate for a component that should exist by itself due to how specific it is to VideoPlayer. Therefore, this decomposition wouldn't likely be one I'd do, and I'd have the behavior and UI given by the ActionsBar be part of VideoPlayer.</p>
<h2>Further notes</h2>
<p>In this example, the decomposition was done in terms of UI components, but the same guideline applies to any piece of code that could live in isolation (e.g. hooks, functions, etc).</p>
<p>As a component evolves and gets added functionalities, the initial decomposition will get outdated and we'll have to think of a new one. Hopefully, with this approach, we should still be able to reuse many of the components we initially had.</p>
<p>This guideline aims at splitting a component into multiple ones that can be reused across the same or different applications. Inside the component itself, we may still opt to split it further for other reasons such as improving performance.</p>
<h2>Give it a try</h2>
<p>Next time you're developing a new component try to use this guideline to decompose it into reusable pieces.</p>
<ol>
<li>A is essentially simpler because it uses B</li>
<li>B is not substantially more complex because it is not
allowed to use A</li>
<li>There is a useful subset containing B but not A</li>
<li>There is no conceivable useful subset containing A but not B</li>
</ol>
<p>I'd suggest coming up with a decomposition before starting to code, and as you go on and learn more about the component you're writing, adjust the decomposition accordingly.</p>
<p>Also, keep in mind that you're the only person that knows the context you're in. So don't follow the guideline blindly and check that it makes sense in the context you're in.</p>]]></content:encoded>
            <author>João Forja</author>
        </item>
        <item>
            <title><![CDATA[How important is testing for a React developer?]]></title>
            <link>https://joaoforja.com/articles/how-important-is-testing-for-a-react-developer</link>
            <guid isPermaLink="false">https://joaoforja.com/articles/how-important-is-testing-for-a-react-developer</guid>
            <pubDate>Tue, 02 Jun 2020 21:12:03 GMT</pubDate>
            <content:encoded><![CDATA[<p>A common question to have when we're starting to learn React is how important it is to know how to write automated tests.</p>
<p>To understand how important automated tests can be, we first need to know why we write them.</p>
<h2>Why automated tests</h2>
<p><em>We write automated tests because we expect them to save us money, time, or both.</em></p>
<p>How much money and time automated tests will save us depends on the context we're working on. The domain of the application, the number of people working on the team, and the size of the codebase, alongside other things, influence how useful automated tests can be. Therefore, how important it is to know how to write automated tests will depend on the project's characteristics.</p>
<h2>Where automated tests aren't important</h2>
<p>There are several ways automated tests can save time and money. Some of them are:
Reduce manual testing time.
Prevent regression bugs.
Give feedback on the modularity of the codebase, which can be used to make it easier to maintain.</p>
<p>If we're using React to work on projects where none of the issues addressed by automated tests exist, not knowing how to make them isn't a problem. Simple blogs, portfolios, and landing pages tend to fit this category. We can manually test them quickly, and they usually don't get new functionalities or benefit from activities such as refactoring. I'd even say that for projects of this nature, writing automated tests might be detrimental as the cost of creating and maintaining them may surpass the benefits.</p>
<h2>Where automated tests make all the difference</h2>
<p>Automated tests can make a significant difference in projects that will continuously get new features, have multiple people working on it, and long term maintainability is a real concern. Which if we're working on a company with a React-based product will be the case most of the time.</p>
<p>As the project starts to grow and more people begin to work on it, not everyone will know every corner of the codebase. And that together with how much frontends tend to change, the probability that someone introduces a regression skyrockets.</p>
<p>Manual testing becomes prohibitively expensive as the number of logic branches only increases. And that's not to mention how mind-numbingly boring manual testing can become when we need to test for quirky browsers like Safari.</p>
<p>The codebase design starts to matter, as it is hard to add new features or change existing ones in a poorly designed application, thus reducing the maintainability of the project.</p>
<p>These are all issues that cost us time and money, and that automated tests can help us with. This is not to say that automated tests are the definitive cure for all software problems, far from it. But it can make such a difference that some companies won't accept developers that don't know how to write automated tests.</p>
<h2>Conclusion</h2>
<p>In summary, the importance of automated tests depends on the characteristics of each project.</p>
<p>If we only work on projects where automated tests won't save us money or time, learning how to do them might be unnecessary.</p>
<p>However, on complex applications with multiple people working on it, automated tests can make such a difference that we might not even be allowed to work on the project if we don't write automated tests for what we develop.</p>
<h2>Other articles about testing</h2>
<p>If you enjoyed this article, you might also like the following:</p>
<ol>
<li><a href="/articles/how-to-get-started-testing-react-applications/">How to get started testing React applications</a></li>
<li><a href="/articles/learn-how-to-make-a-test-list/">Don't know what to test on your React App? Learn how to make a test list.</a></li>
<li><a href="/articles/how-to-write-tests-react-app-case-study/">Not sure how to write tests for your React app? This might help.</a></li>
</ol>]]></content:encoded>
            <author>João Forja</author>
        </item>
        <item>
            <title><![CDATA[How to animate an image in React when it changes]]></title>
            <link>https://joaoforja.com/articles/how-to-animate-an-image-in-react-when-it-changes</link>
            <guid isPermaLink="false">https://joaoforja.com/articles/how-to-animate-an-image-in-react-when-it-changes</guid>
            <pubDate>Tue, 25 Feb 2020 10:01:03 GMT</pubDate>
            <content:encoded><![CDATA[<blockquote>
<p>I want an image to do an animation whenever it is changed. I've created the animation but it only happens once upon creation.</p>
</blockquote>
<p>Let's say we want to build a simple app that displays an image chosen by the user. Each time a new image
appears, we want to show it with an animation.</p>
<pre class="language-jsx"><code class="language-jsx"><span class="token keyword">function</span> <span class="token function"><span class="token maybe-class-name">ImageAnimation</span></span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">const</span> <span class="token punctuation">[</span>imgId<span class="token punctuation">,</span> setImgId<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">useState</span><span class="token punctuation">(</span><span class="token number">10</span><span class="token punctuation">)</span>

  <span class="token keyword control-flow">return</span> <span class="token punctuation">(</span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span><span class="token punctuation">&gt;</span></span><span class="token plain-text">
      </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>input</span>
        <span class="token attr-name">style</span><span class="token script language-javascript"><span class="token script-punctuation punctuation">=</span><span class="token punctuation">{</span><span class="token punctuation">{</span> <span class="token literal-property property">display</span><span class="token operator">:</span> <span class="token string">'block'</span> <span class="token punctuation">}</span><span class="token punctuation">}</span></span>
        <span class="token attr-name">value</span><span class="token script language-javascript"><span class="token script-punctuation punctuation">=</span><span class="token punctuation">{</span>imgId<span class="token punctuation">}</span></span>
        <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>number<span class="token punctuation">"</span></span>
        <span class="token attr-name">onChange</span><span class="token script language-javascript"><span class="token script-punctuation punctuation">=</span><span class="token punctuation">{</span><span class="token punctuation">(</span><span class="token parameter">e</span><span class="token punctuation">)</span> <span class="token arrow operator">=&gt;</span> <span class="token function">setImgId</span><span class="token punctuation">(</span>e<span class="token punctuation">.</span><span class="token property-access">target</span><span class="token punctuation">.</span><span class="token property-access">value</span><span class="token punctuation">)</span><span class="token punctuation">}</span></span>
      <span class="token punctuation">/&gt;</span></span><span class="token plain-text">
      </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>img</span>
        <span class="token attr-name">style</span><span class="token script language-javascript"><span class="token script-punctuation punctuation">=</span><span class="token punctuation">{</span><span class="token punctuation">{</span> <span class="token literal-property property">animation</span><span class="token operator">:</span> <span class="token string">'flash 1.5s .5s'</span> <span class="token punctuation">}</span><span class="token punctuation">}</span></span>
        <span class="token attr-name">alt</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>user selected<span class="token punctuation">"</span></span>
        <span class="token attr-name">src</span><span class="token script language-javascript"><span class="token script-punctuation punctuation">=</span><span class="token punctuation">{</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">https://i.picsum.photos/id/</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>imgId<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">/300/300.jpg</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">}</span></span>
      <span class="token punctuation">/&gt;</span></span><span class="token plain-text">
    </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>
  <span class="token punctuation">)</span>
<span class="token punctuation">}</span>
</code></pre>
<p>The code above makes a request to <a href="https://picsum.photos/">Lorem Picsum</a> API to fetch an image. The image
shown will depend on value of the input. If the user changes the input value, a new request to the API will be done
to fetch the photo with an id equal to the current input value.</p>
<p>Currently, the animation will only work on the first shown image. It won't work as the user changes the image.</p>
<p><img src="/articles/how-to-animate-an-image-in-react-when-it-changes/not_working_animation.gif" alt="Animation not working on change" title="Animation not working on change"></p>
<p>The animation works for the first the image, because an animation executes when a DOM element enters the DOM.
But it won't execute again if the <code>src</code> attribute of the element is changed. This is important since, for our current code, React will only update the <code>src</code> attribute whenever the image changes. It won't unmount and remount the image element.</p>
<p>In vanilla JS, what React is doing is analogous to the following:</p>
<pre class="language-javascript"><code class="language-javascript">imageDomElement<span class="token punctuation">.</span><span class="token method function property-access">setAttribute</span><span class="token punctuation">(</span>
  <span class="token string">'src'</span><span class="token punctuation">,</span>
  <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">https://i.picsum.photos/id/</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>newImageId<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">/300/300.jpg</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">,</span>
<span class="token punctuation">)</span>
</code></pre>
<p>One way to solve this bug, is to tell React that whenever the image is changed, it should be considered a new element. Thus,
React shouldn't reuse the existing DOM element and should use a new one instead. What we want to happen, is something similar to what the code below does:</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">var</span> imageParent <span class="token operator">=</span> imageDomElement<span class="token punctuation">.</span><span class="token property-access">parentNode</span>
imageParent<span class="token punctuation">.</span><span class="token method function property-access">removeChild</span><span class="token punctuation">(</span>imageDomElement<span class="token punctuation">)</span>

<span class="token keyword">var</span> newImageElement <span class="token operator">=</span> <span class="token dom variable">document</span><span class="token punctuation">.</span><span class="token method function property-access">createElement</span><span class="token punctuation">(</span><span class="token string">'img'</span><span class="token punctuation">)</span>
newImageElement<span class="token punctuation">.</span><span class="token method function property-access">setAttribute</span><span class="token punctuation">(</span><span class="token string">'style'</span><span class="token punctuation">,</span> <span class="token string">'animation: flash 1.5s .5s;'</span><span class="token punctuation">)</span>
newImageElement<span class="token punctuation">.</span><span class="token method function property-access">setAttribute</span><span class="token punctuation">(</span>
  <span class="token string">'src'</span><span class="token punctuation">,</span>
  <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">https://i.picsum.photos/id/</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>newImageId<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">/300/300.jpg</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">,</span>
<span class="token punctuation">)</span>

imageParent<span class="token punctuation">.</span><span class="token method function property-access">appendChild</span><span class="token punctuation">(</span>newImageElement<span class="token punctuation">)</span>
</code></pre>
<p>To do this, we can use React's <code>key</code> attribute. If we add a <code>key</code> attribute with the value of the input to the image, and change it whenever the input value is updated, React won't try to reuse the current DOM element. You can read more about the key attribute <a href="https://reactjs.org/docs/reconciliation.html#recursing-on-children">here</a>.</p>
<pre class="language-jsx"><code class="language-jsx"><span class="token keyword">function</span> <span class="token function"><span class="token maybe-class-name">ImageAnimation</span></span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">const</span> <span class="token punctuation">[</span>imgId<span class="token punctuation">,</span> setImgId<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">useState</span><span class="token punctuation">(</span><span class="token number">10</span><span class="token punctuation">)</span>

  <span class="token keyword control-flow">return</span> <span class="token punctuation">(</span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span><span class="token punctuation">&gt;</span></span><span class="token plain-text">
      </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>input</span>
        <span class="token attr-name">style</span><span class="token script language-javascript"><span class="token script-punctuation punctuation">=</span><span class="token punctuation">{</span><span class="token punctuation">{</span> <span class="token literal-property property">display</span><span class="token operator">:</span> <span class="token string">'block'</span> <span class="token punctuation">}</span><span class="token punctuation">}</span></span>
        <span class="token attr-name">value</span><span class="token script language-javascript"><span class="token script-punctuation punctuation">=</span><span class="token punctuation">{</span>imgId<span class="token punctuation">}</span></span>
        <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>number<span class="token punctuation">"</span></span>
        <span class="token attr-name">onChange</span><span class="token script language-javascript"><span class="token script-punctuation punctuation">=</span><span class="token punctuation">{</span><span class="token punctuation">(</span><span class="token parameter">e</span><span class="token punctuation">)</span> <span class="token arrow operator">=&gt;</span> <span class="token function">setImgId</span><span class="token punctuation">(</span>e<span class="token punctuation">.</span><span class="token property-access">target</span><span class="token punctuation">.</span><span class="token property-access">value</span><span class="token punctuation">)</span><span class="token punctuation">}</span></span>
      <span class="token punctuation">/&gt;</span></span><span class="token plain-text">
      </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>img</span>
        <span class="token attr-name">key</span><span class="token script language-javascript"><span class="token script-punctuation punctuation">=</span><span class="token punctuation">{</span>imgId<span class="token punctuation">}</span></span>
        <span class="token attr-name">style</span><span class="token script language-javascript"><span class="token script-punctuation punctuation">=</span><span class="token punctuation">{</span><span class="token punctuation">{</span> <span class="token literal-property property">animation</span><span class="token operator">:</span> <span class="token string">'flash 1.5s .5s'</span> <span class="token punctuation">}</span><span class="token punctuation">}</span></span>
        <span class="token attr-name">alt</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>user selected<span class="token punctuation">"</span></span>
        <span class="token attr-name">src</span><span class="token script language-javascript"><span class="token script-punctuation punctuation">=</span><span class="token punctuation">{</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">https://i.picsum.photos/id/</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>imgId<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">/300/300.jpg</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">}</span></span>
      <span class="token punctuation">/&gt;</span></span><span class="token plain-text">
    </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>
  <span class="token punctuation">)</span>
<span class="token punctuation">}</span>
</code></pre>
<p>This way, the animation will be triggered when the image is changed since it just got added to the DOM.</p>
<p><img src="/articles/how-to-animate-an-image-in-react-when-it-changes/working_animation.gif" alt="Animation working on change" title="Animation working on change"></p>
<h2>Conclusion</h2>
<p>The takeaway from this blog post could easily be to remember that an animation will be triggered
when a DOM element gets added into the DOM, and that we can make React not reuse the current DOM
element by using the <code>key</code> attribute. But I think it runs deeper than that.</p>
<p>I'd say the takeaway from this blog post is that we need to understand how the tools we use work. Without
that, we'll be limited in what we can build and the problems we can solve.</p>
<p>Keep learning about how the tools
you use work, and why they were designed like that. It will make you a much better software developer.</p>]]></content:encoded>
            <author>João Forja</author>
        </item>
        <item>
            <title><![CDATA[How to be more confident about the quality of the code of our React applications]]></title>
            <link>https://joaoforja.com/articles/how-to-be-more-confident-about-the-quality-of-the-code-of-our-react-applications</link>
            <guid isPermaLink="false">https://joaoforja.com/articles/how-to-be-more-confident-about-the-quality-of-the-code-of-our-react-applications</guid>
            <pubDate>Thu, 05 Mar 2020 19:12:03 GMT</pubDate>
            <content:encoded><![CDATA[<blockquote>
<p>My code works, but I think it is implemented incorrectly.</p>
</blockquote>
<p>After we've been programming for a while, we reach the conclusion that making our React applications work is not enough to produce good quality software.</p>
<p>We now worry about things like maintainability, readability, and best practices. And that's a good thing and a sign that we're becoming better developers. But when we don't have a concrete grasp of what those concepts mean, and of what really makes software valuable, it's easy to start constantly doubting the quality of our work.</p>
<p>In this article I'm sharing mental models and a strategy we can use to get more confident about the code we make. I Hope this proves to be as useful to other as it is to me.</p>
<p>The content of this article is applicable not only to React applications. And so that we don't get distracted by React technicalities, I'll keep the terms used as general to the context of software development as possible.</p>
<p>We'll start by going over what makes software valuable, so we can understand what good quality software is. After we've got a grasp of what that is, let's talk about an intuitive strategy that doesn't really help improve code quality and why. Then we'll go into some characteristics of poor quality software and how those can be addressed. After that, we'll go over a simple but effective strategy we can use to help us improve the quality of our software. Let's get started.</p>
<h2>The characteristics of good quality software</h2>
<p>The value of software comes from its correctness and its maintainability. Correctness is about software conforming to the requirements. If a piece of software does what the requirements expect of it, it is correct. Maintainability refers to the software ability to adapt to the future. We can consider that a piece of software is maintainable if, as time goes by, the cost of adding, removing or changing features does not increase.</p>
<p>Given that correctness and maintainability are what make software valuable, we can therefore conclude that good quality software needs to fill the expected requirements at all times, and have a structure which will allow it to adapt to the future.</p>
<p>If you'd like to know why correctness and maintainability are what make software valuable, you can read this <a href="/articles/understanding-the-value-of-software-can-help-us-code-better/">article</a></p>
<h2>What makes a code base unmaintainable</h2>
<p>Usually it is fairly simple to tell the correctness of our software. We can perform tests, automated and manual, that will give us confidence that the requirements are being filled. However, when dealing with maintainability it tends not to be as straight forward, since we don't have that obvious and immediate feedback as we have with correctness. Therefore, we are sort of left in the uncertainty wondering if our software will be able to adapt to the future or not.</p>
<p>As a rule of thumb, it's easier to find out what will make something fail than it is what will make it succeed. So when we're not sure of the decisions we have to take, just keeping in mind the ones we have to avoid can be a good pretty good strategy. So let's look at one of the most instinctive ways of trying to make our code adapt to the future, and know why we need to resist that urge.</p>
<h3>Don't try to predict the future</h3>
<p>One of the first instincts that comes when dealing with the uncertainty of the future, is to try to predict it. As such, we'll try to write our code in a way that it is prepared for the changes we believe will happen.</p>
<p>The problem with forecasting is that we as humans are awful at it. If we weren't, software wouldn't change nearly as much as it does. We tend to believe that a feature will be a hit, only to find out later that no one really uses it. As such, if we try to make guesses as to where the software is headed, and the more long term those guesses are the worse, we'll end up with a lot of code that does not contribute to correctness, and probably never will. And code that does not contribute to correctness nor improves maintainability, only makes our lives harder and wastes our time.</p>
<p>Another big problem with the forecasting approach is that it makes it really hard to tell when we're done implementing a feature. Since now we have to imagine all the possible ways that the feature might evolve, it's really easy to start getting paranoid and thinking that we are not writing the necessary code to protect our software from the future. The negative impact this has on the confidence we have on our code is huge! And not to mention how unnecessarily long a feature development can get.</p>
<p>Avoid predicting the future. Let's stick to what we know for sure and not make more code than the necessary to fill requirements we currently have at hand.</p>
<h3>Know what makes a code base hard to change</h3>
<p>In the spirit of avoiding the path of failure to achieve success, let's look at what generally makes a code base really hard to change, and try to figure out a strategy to deal with that.</p>
<ol>
<li>Fear of breaking what's already working</li>
<li>Incomprehensible code</li>
<li>Highly coupled code</li>
</ol>
<h4>Fear of breaking what's already working</h4>
<p>When making a change to an existing code base, the number one risk we're taking is breaking features that already work. Technically speaking, we have to avoid regressions.</p>
<p>Aside from having a huge negative impact in the morale of the development team, regressions can have a devastating impact on the goals that the software is trying to accomplish. If the goal is a business goal, it might mean a big loss of revenue. A single introduced bug might cause hundreds of clients to lose their trust on the software and stop using it, and that's a risk no one wants to take.</p>
<p>Also, if when we're trying to change or add something new, we're breaking what's already working, when will we be finished with our work? The answer might as well be never.</p>
<h4>Incomprehensible code</h4>
<p>If we want to change some feature on our software, but can't reason about the code we're looking at, how effective can we really be? What if we can't even find the code responsible for making a feature work, because it is scattered all around or due to it being really poorly named?</p>
<p>Code that gives no way for a developer to understand how it works as a whole, and/or how its individuals pieces work, is doomed to be unmaintainable.</p>
<h4>Highly coupled code</h4>
<p>If we have to change 10s of files to make a small change in our software behavior, we have highly coupled code.</p>
<p>The problem with highly coupled code, besides being hard to understand, is that it takes a lot of time to change. Because we have to figure out all the places we'll need to modify, as well as be careful not to inadvertently modify any other features.</p>
<p>As time goes by, if there's not a conscious effort to prevent it, code bases tend to rot. To deal with this, a code base needs to allow us to make small and continuous improvements to the existing code, without compromising the release of new features. If we've got highly coupled code, we won't be able to do those improvements fast enough not to jeopardize the time to market of new features.</p>
<h2>Keeping it maintainable</h2>
<p>So now that we've seen what generally makes a code base hard to maintain, let's look at how we can address those concerns.</p>
<h3>Fear of breaking what's already working</h3>
<p>Fear of breaking what's already working can be mitigated by tests. A well-built and taken care suite of tests can save developers from countless hours of anxiety and despair, as well as save the life of the business that depends on the software working correctly.</p>
<p>It's important that the test suite is mainly composed of automated tests that can be quickly executed. This makes it possible for developers to know if they broke something almost immediately. The test suite should also contain some tests that simulate a user and interact with the system as a whole. Manual testing, as part of a test suite, should be kept to a minimum and reserved to situations where the automation might be prohibitively expensive. After executing all the tests of our test suite, we should have gone through all the possible use-cases for our software.</p>
<p>An automated suite of tests allows us to quickly change our software. Therefore, improving maintainability.</p>
<h3>Incomprehensible code</h3>
<p>Incomprehensible code comes from not being able to understand what a piece of code intends to do. Some reasons that can happen are:</p>
<ol>
<li>Code organized into huge pieces, that are so big, that it's too much for us to reason about.</li>
<li>Code organized in a way that we can't reason about each piece in isolation.</li>
<li>Code for a single functionality being scattered all around the code base</li>
<li>Misleading names</li>
</ol>
<p>We can address all the points above if we modularize our code into small independent modules that make sense on their own, and give them a name that reveals what they intend to do.</p>
<p>By keeping our modules small and independent, we avoid our modules being too big for us to understand, as well as allow us to ignore other modules that the current module may interact with. This greatly reduces the cognitive load necessary to understand a code base, because now we can reason about one module at a time.</p>
<p>By grouping our code into modules that we can name in a way that reveal what it intends to do in the context of the software's domain, we are grouping small pieces of code into units that belong together. Otherwise, we wouldn't be able to give our modules meaningful names. This results in code that is easier to understand what it does as a whole, as well as what each single piece does. Also, by following this approach, code that contributes to the same behavior will tend not to be scattered.</p>
<p>Understandable code allows for changes to our software to be made quickly and with confidence. Thus, directly improving its maintainability.</p>
<h3>Highly coupled code</h3>
<p>When solving the problem of incomprehensible code by organizing our code into small independent modules which make sense on their own, we are already solving the problem of highly coupled code.</p>
<p>Think about it, if we can reason about a piece of code in isolation, that means there is a clear boundary between modules and is easy to understand what each module should do. If we can understand what each module does, and given that it is small, we can safely and quickly refactor it. <em>We can even throw an entire module away and re-write if it needs to be!</em> This kind of modularity allows developers to continuously improve the quality of a code base, without compromising the time to market of new features.</p>
<p>Decoupled code allow us to continuously and quickly improve the quality of our code base. This allows us to renew rotten code that is making our software harder to change as time goes by.</p>
<p>Testing and modular design may not be the only way to keep a code base maintainable. But it certainly is a proven way that works across many kinds of code bases.</p>
<h2>Building a strategy to improve code quality</h2>
<p>We know that for software to have quality it needs to fill its requirements and it needs to be capable of adapt to future change. We've seen that forecasting is not a good approach to maintainability, and that "Fear of breaking what's working", "Incomprehensible code" and "Highly coupled code" are the main reasons that make a code base unmaintainable. We've also looked at how automated testing and modular design can help us stay away from what makes our code hard to change.</p>
<p>Now, let's organize all of this knowledge into questions that will give us feedback about the quality of our code, and that we can constantly ask ourselves when we are faced with a design decisions or when we've finished implementing or changing a feature.</p>
<p>These questions have the goal of making us check if our code is correct and of maximizing its capacity of changing in the future. If we can answer yes to all the questions, we can have confidence in the quality of our code. So let's go over what each question means and how we can use testing and modular design to answer each one.</p>
<ol>
<li>Does the code do what the requirements ask of it?</li>
<li>If a working feature broke, would we quickly know it and be able to easily find out what and where it broke?</li>
<li>If we wanted to add, remove or change a feature, would we know exactly where to look?</li>
<li>Can we rewrite any feature in a timely manner?</li>
</ol>
<h3>Does the code do what the requirements ask of it?</h3>
<p>This question assures our software is doing what it is intended to do. If it doesn't do what is expected, it probably won't be contributing to achieve the established goals. So we can't really call it good quality software.</p>
<p>We can answer this question by relentlessly testing our software and making no assumptions that something works without solid proof of it.</p>
<h3>If a working feature broke, would we quickly know it and be able to easily find out what and where it broke?</h3>
<p>As we've already talked about, if we want software that can adapt to the future, we need to know when something that was already done, stopped working. We need to know it fast, and we need to be able to fix it quickly.</p>
<p>One way to accomplish this is to have a suite of automated tests that are quick to execute, and that when they fail, point us to the piece of code that is failing. By having a suite of automated tests that points us to the piece of code that is failing, we are also designing our code into small independent modules. Otherwise, we won't be able to tell what part of our code stopped working.</p>
<h3>If we wanted to add, remove or change a feature, would we know exactly where to look?</h3>
<p>When we want to change the behavior of our software, first we need to know where the code responsible for that behavior is. If we can't tell where it is, we can't really change it.</p>
<p>To achieve this, we can organize our code into modules that we can name in such a way that it's obvious what it does in the context of our software. We should do it at an higher and lower level. When done correctly, our names will work out as road signs that will tell us what our code does and where to look when we want to make changes.</p>
<p>Also, if we were able to give our modules meaningful names, it's likely that we succeed at grouping our code such that the reasons for it to change are the same or very closely related. The result is not having to look at wildly scattered code when wanting to change some behavior. Which makes our task of finding out what needs to change much easier.</p>
<h3>Can we rewrite any feature in a timely manner?</h3>
<p>As we've already talked about, a code base will change a lot during its lifetime. And as it undergoes many changes, it will start to deteriorate. It might be because we had a wrong understanding of the requirements. Maybe the requirements proved out to not be appropriate to achieve the software goal. Or simply there was not enough time to implement the feature in a none sloppy way. Either way, after the mess is done, we need to be capable of cleaning it in a timely manner. Otherwise, the mess will start to spread out and contaminate every part of the code base. The result of that is a code base that can't be changed.</p>
<p>By timely manner I mean an amount of time that is small enough not to compromise the release of new features. I do not mean that any complete rewrite of a feature should be able to be done in one go, but that we should at least be able to do it little by little without compromising the schedule. It might be hard to convince management that we need a refactor sprint, better if we don't even need to ask for it.</p>
<p>Yet again, organizing our code into small independent modules can allow us to answer yes to this question. If our modules are small we can quickly rewrite them. And if they are independent of one another, we won't have to worry much about breaking any other modules. This allows us to continuously and quickly renew our code base.</p>
<h3>When to ask the questions</h3>
<p>Let's ask these questions when we're done implementing or changing a feature. Let's also ask them whenever we have decision to make that is not so obvious. If after asking these questions we still don't know which path to take, let's get back to the principle of maximizing the capacity to change.</p>
<h2>Conclusion</h2>
<p>Next time we're programming, let's remember that every line of code should either contribute to our code correctness or to its maintainability. If we implement a feature in a way that makes it harder for us to change it in the future, we are not helping ourselves.</p>
<p>In order to get feedback about the correctness and maintainability of our code, we can ask ourselves these questions:</p>
<ol>
<li>Does it do what the requirements ask of it?</li>
<li>If a working feature broke, would we quickly know it and be able to easily find out what and where it broke?</li>
<li>If we wanted to add, remove or change a feature, would we know exactly where to look?</li>
<li>Can we rewrite any feature in a timely manner?</li>
</ol>
<p>If we can answer yes to the questions above and if we keep in mind that our decisions should make our code base easier to change, we can be confident that we have produced good quality code.</p>
<hr>
<p>As said at the beginning, I didn't go over how to apply these principles in a React app. But if you liked what you read, or have any question, let me know! You can send me a message on twitter at <a href="https://twitter.com/JooForja">@JooForja</a>.</p>
<p>I hope you liked this article and that it proved useful to you!</p>]]></content:encoded>
            <author>João Forja</author>
        </item>
        <item>
            <title><![CDATA[5 steps to deal with bugs on your React applications]]></title>
            <link>https://joaoforja.com/articles/how-to-deal-with-bugs-react-app</link>
            <guid isPermaLink="false">https://joaoforja.com/articles/how-to-deal-with-bugs-react-app</guid>
            <pubDate>Thu, 02 Jul 2020 19:30:03 GMT</pubDate>
            <content:encoded><![CDATA[<p>When we find a bug in our applications, fixing it is only the beginning. We also need to make sure the same bug won't happen again, and we should also take the opportunity to prevent similar bugs from happening. To help us achieve those goals, we can use the following process:</p>
<ol>
<li>Analyze the defect and find the broken code.</li>
<li>Reproduce the bug in a targeted automated test and fix it.</li>
<li>Improve the code design to reduce the likelihood of bugs.</li>
<li>Perform root-cause analysis to find the origin of the bug.</li>
<li>Conduct exploratory testing to find similar bugs.</li>
</ol>
<p>In this article, we'll go over a bug on a React application and use this 5 step approach to fix it and prevent future ones. By the end of this article, you'll have a better understanding of how this process works and how to apply it to bugs you might find on your applications.</p>
<h2>Applying the process</h2>
<p>To show how this process would work in practice, we'll use a simplistic React application that allows a user to select a book from a list and then fetches the name author of the chosen book from an API and displays it.</p>
<p>Below is the code that's relevant for this example:</p>
<pre class="language-jsx"><code class="language-jsx"><span class="token keyword">const</span> <span class="token constant">NO_BOOK_SELECTED</span> <span class="token operator">=</span> <span class="token string">'no-book-selected'</span>
<span class="token keyword">const</span> <span class="token constant">LOADING</span> <span class="token operator">=</span> <span class="token string">'loading'</span>
<span class="token keyword">const</span> <span class="token constant">SHOW_AUTHOR</span> <span class="token operator">=</span> <span class="token string">'show-author'</span>
<span class="token keyword">const</span> <span class="token constant">ERROR</span> <span class="token operator">=</span> <span class="token string">'error'</span>

<span class="token keyword">function</span> <span class="token function"><span class="token maybe-class-name">Books</span></span><span class="token punctuation">(</span><span class="token parameter"><span class="token punctuation">{</span> fetchBookAuthor <span class="token punctuation">}</span></span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">const</span> <span class="token punctuation">[</span><span class="token punctuation">{</span> author<span class="token punctuation">,</span> status <span class="token punctuation">}</span><span class="token punctuation">,</span> setState<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">useState</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
    <span class="token literal-property property">status</span><span class="token operator">:</span> <span class="token constant">NO_BOOK_SELECTED</span><span class="token punctuation">,</span>
    <span class="token literal-property property">author</span><span class="token operator">:</span> <span class="token keyword null nil">null</span><span class="token punctuation">,</span>
  <span class="token punctuation">}</span><span class="token punctuation">)</span>

  <span class="token keyword">function</span> <span class="token function">fetchSelectedBookAuthor</span><span class="token punctuation">(</span><span class="token parameter">event</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token function">setState</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token literal-property property">status</span><span class="token operator">:</span> <span class="token constant">LOADING</span> <span class="token punctuation">}</span><span class="token punctuation">)</span>
    <span class="token function">fetchBookAuthor</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token literal-property property">bookId</span><span class="token operator">:</span> event<span class="token punctuation">.</span><span class="token property-access">target</span><span class="token punctuation">.</span><span class="token property-access">value</span> <span class="token punctuation">}</span><span class="token punctuation">)</span>
      <span class="token punctuation">.</span><span class="token method function property-access">then</span><span class="token punctuation">(</span>
        <span class="token punctuation">(</span><span class="token parameter">bookAuthor</span><span class="token punctuation">)</span> <span class="token arrow operator">=&gt;</span> <span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token literal-property property">status</span><span class="token operator">:</span> <span class="token constant">SHOW_AUTHOR</span><span class="token punctuation">,</span> <span class="token literal-property property">author</span><span class="token operator">:</span> bookAuthor <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
        <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token arrow operator">=&gt;</span> <span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token literal-property property">status</span><span class="token operator">:</span> <span class="token constant">ERROR</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
      <span class="token punctuation">)</span>
      <span class="token punctuation">.</span><span class="token method function property-access">then</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">newState</span><span class="token punctuation">)</span> <span class="token arrow operator">=&gt;</span> <span class="token function">setState</span><span class="token punctuation">(</span>newState<span class="token punctuation">)</span><span class="token punctuation">)</span>
  <span class="token punctuation">}</span>

  <span class="token keyword control-flow">return</span> <span class="token punctuation">(</span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span></span><span class="token punctuation">&gt;</span></span><span class="token plain-text">
      </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>form</span><span class="token punctuation">&gt;</span></span><span class="token plain-text">
        </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>label</span> <span class="token attr-name">htmlFor</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>book<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span><span class="token plain-text">Book</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>label</span><span class="token punctuation">&gt;</span></span><span class="token plain-text">
        </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>select</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>book<span class="token punctuation">"</span></span> <span class="token attr-name">defaultValue</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span><span class="token punctuation">"</span></span> <span class="token attr-name">onChange</span><span class="token script language-javascript"><span class="token script-punctuation punctuation">=</span><span class="token punctuation">{</span>fetchSelectedBookAuthor<span class="token punctuation">}</span></span><span class="token punctuation">&gt;</span></span><span class="token plain-text">
          </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>option</span> <span class="token attr-name">value</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span><span class="token punctuation">"</span></span> <span class="token attr-name">disabled</span> <span class="token attr-name">hidden</span><span class="token punctuation">&gt;</span></span><span class="token plain-text">
            Select a book
          </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>option</span><span class="token punctuation">&gt;</span></span><span class="token plain-text">
          </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>option</span> <span class="token attr-name">value</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>1<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span><span class="token plain-text">TDD by example</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>option</span><span class="token punctuation">&gt;</span></span><span class="token plain-text">
          </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>option</span> <span class="token attr-name">value</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>2<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span><span class="token plain-text">Clean Architecture</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>option</span><span class="token punctuation">&gt;</span></span><span class="token plain-text">
          </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>option</span> <span class="token attr-name">value</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>3<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span><span class="token plain-text">The Software Craftsman</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>option</span><span class="token punctuation">&gt;</span></span><span class="token plain-text">
          </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>option</span> <span class="token attr-name">value</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>4<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span><span class="token plain-text">Refactoring</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>option</span><span class="token punctuation">&gt;</span></span><span class="token plain-text">
        </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>select</span><span class="token punctuation">&gt;</span></span><span class="token plain-text">
      </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>form</span><span class="token punctuation">&gt;</span></span><span class="token plain-text">
      </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span><span class="token punctuation">&gt;</span></span><span class="token plain-text">
        </span><span class="token punctuation">{</span>status <span class="token operator">===</span> <span class="token constant">NO_BOOK_SELECTED</span> <span class="token operator">&amp;&amp;</span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>p</span><span class="token punctuation">&gt;</span></span><span class="token plain-text">No book is selected.</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>p</span><span class="token punctuation">&gt;</span></span><span class="token punctuation">}</span><span class="token plain-text">
        </span><span class="token punctuation">{</span>status <span class="token operator">===</span> <span class="token constant">SHOW_AUTHOR</span> <span class="token operator">&amp;&amp;</span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>p</span><span class="token punctuation">&gt;</span></span><span class="token punctuation">{</span>author<span class="token punctuation">}</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>p</span><span class="token punctuation">&gt;</span></span><span class="token punctuation">}</span><span class="token plain-text">
        </span><span class="token punctuation">{</span>status <span class="token operator">===</span> <span class="token constant">LOADING</span> <span class="token operator">&amp;&amp;</span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>p</span><span class="token punctuation">&gt;</span></span><span class="token plain-text">Loading...</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>p</span><span class="token punctuation">&gt;</span></span><span class="token punctuation">}</span><span class="token plain-text">
        </span><span class="token punctuation">{</span>status <span class="token operator">===</span> <span class="token constant">ERROR</span> <span class="token operator">&amp;&amp;</span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>p</span><span class="token punctuation">&gt;</span></span><span class="token plain-text">There was an error.</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>p</span><span class="token punctuation">&gt;</span></span><span class="token punctuation">}</span><span class="token plain-text">
      </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span><span class="token plain-text">
    </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span></span><span class="token punctuation">&gt;</span></span>
  <span class="token punctuation">)</span>
<span class="token punctuation">}</span>
</code></pre>
<h3>1. Analyze the defect and find the responsible code</h3>
<video autoplay="" loop="" aria-label="bug demo"><source src="bug_demo.webm" type="video/webm"><source src="bug_demo.mp4" type="video/mp4"><p></p><p>Your browser doesn't support HTML5 video. Here is a<!-- --> <!-- -->
<a href="bug_demo.mp4">link to the video</a> instead.</p><p></p></video>
<p>As we can see in the video above, the user selected the book "TDD by example" and before giving the API time to answer with the author, changed the book to "Clean Architecture". The result is that the application shows "Kent Beck" as the author of "Clean Architecture" when it should have shown "Robert C. Martin".</p>
<p>Since we are at the first step of the process, our focus is on making a hypothesis about why this bug might be happening and locate the area, or areas, of the code that we'll need to change to fix the bug.</p>
<p>From experience, I know that this kind of bug tends to happen due to race conditions. In particular, it occurs when responses from requests come out of order. So I hypothesize that the response for "TDD by example" came last even though it was made first, and that resulted in the UI updating the author to "Kent Beck" even though "TDD by example" was no longer the book the user selected.</p>
<p>Since we're dealing with a small example, we know that we'll have to change <code>&lt;Books/&gt;</code> to fix the bug.</p>
<h3>2. Reproduce the bug with an automated test and fix it</h3>
<p>Since we now have a hypothesis of what might be causing the bug, we will write an automated test to prove our hypothesis correct. By having an automated test, we also prevent the same bug from happening again. But before writing the test, we have to decide our testing boundary.</p>
<p>When defining a testing boundary that tries to reproduce a bug, I tend to establish it as close as possible to the faulty code without coupling the tests too much to the details. The goal is that if someone introduces this bug again in the system, they know that something broke and where it exactly broke. Therefore, I'll prefer using unit-level tests instead of E2E like tests since when an E2E test breaks, it can be tough to know where the problem is. For our specific example, let's place the testing boundary at the <code>&lt;Books/&gt;</code> component.</p>
<p>The test below reproduces the steps we think are responsible for the bug.</p>
<pre class="language-jsx"><code class="language-jsx"><span class="token comment">// This test uses Jest + React testing library</span>
<span class="token function">test</span><span class="token punctuation">(</span>
  <span class="token string">"Avoids race conditions when responses for requests to get books' author "</span> <span class="token operator">+</span>
    <span class="token string">'come out of order'</span><span class="token punctuation">,</span>
  <span class="token keyword">function</span> <span class="token function">test</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">let</span> resolveAuthorForTDDByExample
    <span class="token keyword">let</span> resolveAuthorForCleanArchitecture

    <span class="token keyword">const</span> fetchBookAuthor <span class="token operator">=</span> jest
      <span class="token punctuation">.</span><span class="token method function property-access">fn</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
      <span class="token punctuation">.</span><span class="token method function property-access">mockReturnValueOnce</span><span class="token punctuation">(</span>
        <span class="token keyword">new</span> <span class="token class-name">Promise</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">res</span><span class="token punctuation">)</span> <span class="token arrow operator">=&gt;</span> <span class="token punctuation">{</span>
          <span class="token function-variable function">resolveAuthorForTDDByExample</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token arrow operator">=&gt;</span> <span class="token function">res</span><span class="token punctuation">(</span><span class="token string">'Kent Beck'</span><span class="token punctuation">)</span>
        <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
      <span class="token punctuation">)</span>
      <span class="token punctuation">.</span><span class="token method function property-access">mockReturnValueOnce</span><span class="token punctuation">(</span>
        <span class="token keyword">new</span> <span class="token class-name">Promise</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">res</span><span class="token punctuation">)</span> <span class="token arrow operator">=&gt;</span> <span class="token punctuation">{</span>
          <span class="token function-variable function">resolveAuthorForCleanArchitecture</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token arrow operator">=&gt;</span> <span class="token function">res</span><span class="token punctuation">(</span><span class="token string">'Robert C. Martin'</span><span class="token punctuation">)</span>
        <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
      <span class="token punctuation">)</span>

    <span class="token function">render</span><span class="token punctuation">(</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span><span class="token class-name">Books</span></span> <span class="token attr-name">fetchBookAuthor</span><span class="token script language-javascript"><span class="token script-punctuation punctuation">=</span><span class="token punctuation">{</span>fetchBookAuthor<span class="token punctuation">}</span></span> <span class="token punctuation">/&gt;</span></span><span class="token punctuation">)</span>

    <span class="token keyword">const</span> bookInput <span class="token operator">=</span> screen<span class="token punctuation">.</span><span class="token method function property-access">getByLabelText</span><span class="token punctuation">(</span><span class="token string">'Book'</span><span class="token punctuation">)</span>
    userEvent<span class="token punctuation">.</span><span class="token method function property-access">selectOptions</span><span class="token punctuation">(</span>bookInput<span class="token punctuation">,</span> screen<span class="token punctuation">.</span><span class="token method function property-access">getByText</span><span class="token punctuation">(</span><span class="token string">'TDD by example'</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
    userEvent<span class="token punctuation">.</span><span class="token method function property-access">selectOptions</span><span class="token punctuation">(</span>bookInput<span class="token punctuation">,</span> screen<span class="token punctuation">.</span><span class="token method function property-access">getByText</span><span class="token punctuation">(</span><span class="token string">'Clean Architecture'</span><span class="token punctuation">)</span><span class="token punctuation">)</span>

    <span class="token function">resolveAuthorForCleanArchitecture</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
    <span class="token function">resolveAuthorForTDDByExample</span><span class="token punctuation">(</span><span class="token punctuation">)</span>

    <span class="token keyword control-flow">return</span> <span class="token function">waitFor</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token arrow operator">=&gt;</span> <span class="token punctuation">{</span>
      <span class="token function">expect</span><span class="token punctuation">(</span>screen<span class="token punctuation">.</span><span class="token method function property-access">getByText</span><span class="token punctuation">(</span><span class="token string">'Robert C. Martin'</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token method function property-access">toBeVisible</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
    <span class="token punctuation">}</span><span class="token punctuation">)</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token punctuation">)</span>
</code></pre>
<p>The test above fails, proving our hypothesis correct. Next, we need to fix the code to make the test pass.</p>
<p>To make the test pass, we'll introduce a mechanism to detect if the response from a request is still relevant to the user or not. If it isn't, we'll ignore the response. For now, we'll worry about making it work. Later we'll take care of the design.</p>
<pre class="language-jsx"><code class="language-jsx"><span class="token keyword">function</span> <span class="token function"><span class="token maybe-class-name">Books</span></span><span class="token punctuation">(</span><span class="token parameter"><span class="token punctuation">{</span> fetchBookAuthor <span class="token punctuation">}</span></span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">const</span> <span class="token punctuation">[</span><span class="token punctuation">{</span> author<span class="token punctuation">,</span> status <span class="token punctuation">}</span><span class="token punctuation">,</span> setState<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">useState</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
    <span class="token literal-property property">status</span><span class="token operator">:</span> <span class="token constant">NO_BOOK_SELECTED</span><span class="token punctuation">,</span>
    <span class="token literal-property property">author</span><span class="token operator">:</span> <span class="token keyword null nil">null</span><span class="token punctuation">,</span>
  <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token comment">// Added ref to DOM element so we can check the current selected book</span>
  <span class="token keyword">const</span> bookSelectInputRef <span class="token operator">=</span> <span class="token function">useRef</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

  <span class="token keyword">function</span> <span class="token function">fetchSelectedBookAuthor</span><span class="token punctuation">(</span><span class="token parameter">event</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">const</span> bookId <span class="token operator">=</span> event<span class="token punctuation">.</span><span class="token property-access">target</span><span class="token punctuation">.</span><span class="token property-access">value</span><span class="token punctuation">;</span>
    <span class="token function">setState</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token literal-property property">status</span><span class="token operator">:</span> <span class="token constant">LOADING</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token function">fetchBookAuthor</span><span class="token punctuation">(</span><span class="token punctuation">{</span> bookId <span class="token punctuation">}</span><span class="token punctuation">)</span>
      <span class="token punctuation">.</span><span class="token method function property-access">then</span><span class="token punctuation">(</span>
        <span class="token punctuation">(</span><span class="token parameter">bookAuthor</span><span class="token punctuation">)</span> <span class="token arrow operator">=&gt;</span> <span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token literal-property property">status</span><span class="token operator">:</span> <span class="token constant">SHOW_AUTHOR</span><span class="token punctuation">,</span> <span class="token literal-property property">author</span><span class="token operator">:</span> bookAuthor <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
        <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token arrow operator">=&gt;</span> <span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token literal-property property">status</span><span class="token operator">:</span> <span class="token constant">ERROR</span> <span class="token punctuation">}</span><span class="token punctuation">)</span>
      <span class="token punctuation">)</span>
      <span class="token punctuation">.</span><span class="token method function property-access">then</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">newState</span><span class="token punctuation">)</span> <span class="token arrow operator">=&gt;</span> <span class="token punctuation">{</span>
        <span class="token keyword">const</span> currentSelectedBook <span class="token operator">=</span> bookSelectInputRef<span class="token punctuation">.</span><span class="token property-access">current</span><span class="token punctuation">.</span><span class="token property-access">value</span><span class="token punctuation">;</span>
        currentSelectedBook <span class="token operator">===</span> bookId <span class="token operator">&amp;&amp;</span> <span class="token function">setState</span><span class="token punctuation">(</span>newState<span class="token punctuation">)</span><span class="token punctuation">;</span>
      <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>

  <span class="token keyword control-flow">return</span> <span class="token punctuation">(</span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span></span><span class="token punctuation">&gt;</span></span><span class="token plain-text">
      </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>form</span><span class="token punctuation">&gt;</span></span><span class="token plain-text">
        </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>label</span> <span class="token attr-name">htmlFor</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>book<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span><span class="token plain-text">Book</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>label</span><span class="token punctuation">&gt;</span></span><span class="token plain-text">
        </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>select</span>
          <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>book<span class="token punctuation">"</span></span>
          <span class="token attr-name">defaultValue</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span><span class="token punctuation">"</span></span>
          <span class="token attr-name">ref</span><span class="token script language-javascript"><span class="token script-punctuation punctuation">=</span><span class="token punctuation">{</span>bookSelectInputRef<span class="token punctuation">}</span></span>
          <span class="token attr-name">onChange</span><span class="token script language-javascript"><span class="token script-punctuation punctuation">=</span><span class="token punctuation">{</span>fetchSelectedBookAuthor<span class="token punctuation">}</span></span>
        <span class="token punctuation">&gt;</span></span><span class="token plain-text">
         ...
    </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span></span><span class="token punctuation">&gt;</span></span><span class="token plain-text">
  );
}
</span></code></pre>
<p>Now our test passes so we can go to the next step.</p>
<h3>3. Improve the code design to prevent bugs</h3>
<p>The goal of this step is to try to understand how the current code design might have caused the bug to happen, and improve the design to prevent bugs in the same area of the code.</p>
<p>The specific ways in which we can improve an existing design are many, and a topic that I won't go over in this article. But as a general guideline I try to guide the code towards better readability by reducing complexity and making hidden concepts explicit.</p>
<p>For our specific example, I find it confusing how we use the state in the <code>&lt;select/&gt;</code> DOM element to determine if a response is still useful to the user. I think it doesn't express intent well. I'd like to refactor the code to make it evident that when the user changes the book, we no longer care about any responses from ongoing requests. I think that the concept of cancellation might be a good fit here. So let's refactor the code in that direction.</p>
<pre class="language-jsx"><code class="language-jsx"><span class="token keyword">function</span> <span class="token function"><span class="token maybe-class-name">Books</span></span><span class="token punctuation">(</span><span class="token parameter"><span class="token punctuation">{</span> fetchBookAuthor <span class="token punctuation">}</span></span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">const</span> <span class="token punctuation">[</span><span class="token punctuation">{</span> author<span class="token punctuation">,</span> status <span class="token punctuation">}</span><span class="token punctuation">,</span> setState<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">useState</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
    <span class="token literal-property property">status</span><span class="token operator">:</span> <span class="token constant">NO_BOOK_SELECTED</span><span class="token punctuation">,</span>
    <span class="token literal-property property">author</span><span class="token operator">:</span> <span class="token keyword null nil">null</span><span class="token punctuation">,</span>
  <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token keyword">const</span> <span class="token punctuation">[</span>selectedBookId<span class="token punctuation">,</span> setSelectedBookId<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">useState</span><span class="token punctuation">(</span><span class="token string">""</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

  <span class="token function">useEffect</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token arrow operator">=&gt;</span> <span class="token punctuation">{</span>
    <span class="token keyword control-flow">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>selectedBookId<span class="token punctuation">)</span> <span class="token keyword control-flow">return</span><span class="token punctuation">;</span>

    <span class="token keyword">let</span> cancelled <span class="token operator">=</span> <span class="token boolean">false</span><span class="token punctuation">;</span>
    <span class="token function">setState</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token literal-property property">status</span><span class="token operator">:</span> <span class="token constant">LOADING</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token function">fetchBookAuthor</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token literal-property property">bookId</span><span class="token operator">:</span> selectedBookId <span class="token punctuation">}</span><span class="token punctuation">)</span>
      <span class="token punctuation">.</span><span class="token method function property-access">then</span><span class="token punctuation">(</span>
        <span class="token punctuation">(</span><span class="token parameter">bookAuthor</span><span class="token punctuation">)</span> <span class="token arrow operator">=&gt;</span> <span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token literal-property property">status</span><span class="token operator">:</span> <span class="token constant">SHOW_AUTHOR</span><span class="token punctuation">,</span> <span class="token literal-property property">author</span><span class="token operator">:</span> bookAuthor <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
        <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token arrow operator">=&gt;</span> <span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token literal-property property">status</span><span class="token operator">:</span> <span class="token constant">ERROR</span> <span class="token punctuation">}</span><span class="token punctuation">)</span>
      <span class="token punctuation">)</span>
      <span class="token punctuation">.</span><span class="token method function property-access">then</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">newState</span><span class="token punctuation">)</span> <span class="token arrow operator">=&gt;</span> <span class="token operator">!</span>cancelled <span class="token operator">&amp;&amp;</span> <span class="token function">setState</span><span class="token punctuation">(</span>newState<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

    <span class="token keyword control-flow">return</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token arrow operator">=&gt;</span> <span class="token punctuation">(</span>cancelled <span class="token operator">=</span> <span class="token boolean">true</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">[</span>fetchBookAuthor<span class="token punctuation">,</span> selectedBookId<span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

  <span class="token keyword control-flow">return</span> <span class="token punctuation">(</span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span></span><span class="token punctuation">&gt;</span></span><span class="token plain-text">
      </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>form</span><span class="token punctuation">&gt;</span></span><span class="token plain-text">
        </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>label</span> <span class="token attr-name">htmlFor</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>book<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span><span class="token plain-text">Book</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>label</span><span class="token punctuation">&gt;</span></span><span class="token plain-text">
        </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>select</span>
          <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>book<span class="token punctuation">"</span></span>
          <span class="token attr-name">value</span><span class="token script language-javascript"><span class="token script-punctuation punctuation">=</span><span class="token punctuation">{</span>selectedBookId<span class="token punctuation">}</span></span>
          <span class="token attr-name">onChange</span><span class="token script language-javascript"><span class="token script-punctuation punctuation">=</span><span class="token punctuation">{</span><span class="token punctuation">(</span><span class="token parameter">e</span><span class="token punctuation">)</span> <span class="token arrow operator">=&gt;</span> <span class="token function">setSelectedBookId</span><span class="token punctuation">(</span>e<span class="token punctuation">.</span><span class="token property-access">target</span><span class="token punctuation">.</span><span class="token property-access">value</span><span class="token punctuation">)</span><span class="token punctuation">}</span></span>
        <span class="token punctuation">&gt;</span></span><span class="token plain-text">
          ...
    </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span></span><span class="token punctuation">&gt;</span></span><span class="token plain-text">
  );
}
</span></code></pre>
<p>The above was just an example of a possible refactor. We could have opted for other refactors that might give better results, like using a finite state machine to make the available states and transitions of the component easier to understand.</p>
<p>Keep in mind that not all bugs are caused by bad code design, so there might be nothing to do in this step.</p>
<h3>4. Perform root-cause analysis to find the origin of the bug</h3>
<p>The goal of this step is to determine the origin of a bug, so we can then improve what might be at fault. In my opinion, this is the most valuable step of the process as it can find some surprising issues that can tremendously help individuals and organizations move forward when solved.</p>
<p>There are multiple ways we can do a root-cause analysis, but a simple and effective is to use the "5 Whys" technique. This technique aims to look at a problem and continually ask why it happened until we reach what seems to be its root.</p>
<p>For our specific example, using the 5 whys technique could go something along the following lines:</p>
<ol>
<li>Why did we have a race condition bug? - The developer that implemented the feature wasn't aware of the possibility of race conditions when making API requests.</li>
<li>Why didn't the developer know about race conditions? - It was his first time dealing with API requests, and he did it alone.</li>
<li>Why didn't he ask for help from a colleague? - He felt afraid of being judged by his colleagues.</li>
<li>Why was he afraid of being judged? - Because at the office, people believe that asking for help is a sign of incompetence.</li>
</ol>
<p>From the example above, we can see that by following the bug, we revealed a cultural problem at the company that we can now decide how to address. Of course, there might be more causes than just that one, and choosing which cause to address will depend on the context. Nonetheless, the issues that this type of analysis can uncover are invaluable.</p>
<p>An important thing to keep in mind when doing this is to try not to blame individuals. Blaming individuals tends not to lead us to productive results. Keep the focus on the faults of the process.</p>
<h3>5. Conduct exploratory testing to find similar bugs</h3>
<p>The core idea behind this step is that bugs tend to cluster. So if someone found a bug in our application, we likely have others that follow the same pattern, and we should try to find them.</p>
<p>For our specific example, we would do some exploratory testing on our application focused on finding bugs related to making API requests and race conditions.</p>
<p>If you're not familiar with the term Exploratory Testing, I recommend you check this <a href="https://pragprog.com/titles/ehxta/">book</a>. This is arguably a topic that's more important for QA than for developers. However, I believe that having this kind of knowledge as a developer can make a massive difference in the robustness of the applications we build.</p>
<h2>Conclusion</h2>
<p>When we find a bug in our applications, we can use the 5 step process explained in this article to fix the found bug and prevent future ones. So next time you spot a bug in your application, give this process a try.</p>
<p>I couldn't end this article without saying that I didn't come up with this process. I've learned it from <a href="https://twitter.com/jamesshore">James Shore</a>, and I highly recommend you check out his <a href="https://www.jamesshore.com/Blog/">blog</a>.</p>]]></content:encoded>
            <author>João Forja</author>
        </item>
        <item>
            <title><![CDATA[How to fix CORS errors on the development environment of a React application]]></title>
            <link>https://joaoforja.com/articles/how-to-fix-cors-on-dev-env-of-react-app</link>
            <guid isPermaLink="false">https://joaoforja.com/articles/how-to-fix-cors-on-dev-env-of-react-app</guid>
            <pubDate>Thu, 19 Mar 2020 07:15:03 GMT</pubDate>
            <content:encoded><![CDATA[<blockquote>
<p>Can't make a query from the browser since CORS blocks it</p>
</blockquote>
<p>Whenever we're developing a React application that has to communicate with an API, we'll probably run into Cross-Origin Resource Sharing (CORS) errors. The error message will be similar to this:</p>
<p class="bg-red-100 p-4 text-base font-semibold text-red-900"></p><p>Access to fetch at '<a href="http://localhost:8081/auth">http://localhost:8081/auth</a>' from origin
'<a href="http://localhost:3000">http://localhost:3000</a>' has been blocked by CORS policy: No
'Access-Control-Allow-Origin' header is present on the requested resource.
Origin '<a href="http://localhost:3000">http://localhost:3000</a>' is therefore not allowed access. If an opaque
response serves your needs, set the request's mode to 'no-cors' to fetch the
resource with CORS disabled.</p><p></p>
<p>A CORS error may happen whenever a web application makes a request for a resource that has a different origin (domain, protocol, or port) from its own. In the case of the error message above, the web app which was served from <code>http://localhost:3000</code> was making a request for <code>http://localhost:8081/auth</code>. Since the ports are different and <code>localhost:8081</code> does not allow for CORS request, we got an error. You can read more about CORS <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS">here</a>.</p>
<h2>Solutions</h2>
<p>There are two common ways to solve CORS issues in a development environment:</p>
<ol>
<li>Enable CORS on the API server.</li>
<li>Configure a proxy on the development server that's serving the React application.</li>
</ol>
<p>Depending on the context in which we're developing the application, it might not be possible, or desirable, to configure the API server to allow for CORS. Therefore, adding a proxy tends to be the preferable solution.</p>
<p>The idea behind using a proxy to solve this issue is simple. Instead of making a request directly to the API server, we'll be making a request to the development server and have the development server forward unknown requests to the API server. This way, the React application will be making requests to its own origin, therefore solving the CORS issue.</p>
<p>In order for the proxy solution to work, we need to make sure that the React app is making requests to the development server. So if we were using absolute paths to reach the API server, we'll now use relative ones to make the requests go to the development server instead. So if we have code like <code>fetch('http://localhost:8081/auth')</code>, we'll have to change it to <code>fetch('/auth')</code>.</p>
<p>Given we're now making API requests to the development server, all that's left is to configure a proxy so the requests are forwarded to the API server.</p>
<p>How to exactly set up a proxy will depend on the set up of the React application. So I won't be going in detail on that in this article. It is usually easy, so don't worry. If you used Create React App (CRA) to set up your React application, you can check this <a href="https://create-react-app.dev/docs/proxying-api-requests-in-development/">page</a> of their documentation on how to configure a proxy. If you're serving your React app with webpack-dev-server, this <a href="https://webpack.js.org/configuration/dev-server/#devserverproxy">page</a> of the documentation might be helpful. In case you're using other tools, looking up their documentation for proxy or making a google search should do the trick.</p>
<p>By now the CORS issue should be solved. However, if the API server is using https, you may need to configure the development server to use https as well. Yet again, how to do it will depend on the tools you're using. If you've used CRA to setup the application check this <a href="https://create-react-app.dev/docs/using-https-in-development/">page</a>, otherwise check the documentation of the tools you're using.</p>
<h2>Conclusion</h2>
<p>If you're facing a CORS issue when making a request to your API server, you can fix it with these steps:</p>
<ol>
<li>Make the requests to the API server go to the development server instead.</li>
<li>Configure a proxy on the development server to forward unknown requests to the API server.</li>
<li>If the API server uses https, configure the development server to use https as well.</li>
</ol>]]></content:encoded>
            <author>João Forja</author>
        </item>
        <item>
            <title><![CDATA[How to get started testing React applications]]></title>
            <link>https://joaoforja.com/articles/how-to-get-started-testing-react-applications</link>
            <guid isPermaLink="false">https://joaoforja.com/articles/how-to-get-started-testing-react-applications</guid>
            <pubDate>Fri, 24 Apr 2020 20:12:03 GMT</pubDate>
            <content:encoded><![CDATA[<blockquote>
<p>All of this testing thing is like I'm in a maze!</p>
</blockquote>
<p>If you don't have experience writing tests, getting started can be daunting. Especially if you're trying to test code that interacts with a framework/library like it is when you're testing a React application.</p>
<p>In this article, we'll go over the usual tools to test a React application, how to get unstuck when we don't know how to test a piece of code, and also a basic testing methodology that allows us to get started right away. In the end, there will be an exercise to put into practice what we've covered.</p>
<h2>Learning how to write tests is a long process. Don't be discouraged!</h2>
<p>Keep in mind that learning how to write tests effectively has a steep learning curve. You'll have doubts about what to test. You won't know how to test some piece of code. You'll under-test. You'll over-test. You'll feel slowed down by testing and start wondering why to do it at all, and eventually, you'll reach a point where you're comfortable writing automated tests and understand the tradeoffs you're making with each test you write.</p>
<p>The struggle is normal, and it's part of the journey, don't be discouraged by it. Keep testing, and it will get better.</p>
<h2>Tools</h2>
<p>To run and write tests, you'll need support from tools. In the React ecosystem, as of now, the mainstream tools for testing are <a href="https://jestjs.io/">Jest</a>, <a href="https://testing-library.com/docs/react-testing-library/intro">React Testing Library</a> and <a href="https://www.cypress.io/">Cypress</a></p>
<p>Jest is a testing framework that allows you to run your automated tests and also provides you with functions to make assertions, such as "did this function returned the expected value?" or "has this function thrown the expected exception?".</p>
<p>Testing React components has some peculiarities. So the community uses React Testing Library, which is a library that provides utility functions to make testing React components easier.</p>
<p>Cypress is a tool that's normally used to run E2E tests. If you're starting, don't worry too much about learning this tool. You'll be using it the least, and if you feel comfortable using Jest and React Testing Library, it'll be easier to get the hang of Cypress.</p>
<p>To avoid complications setting up a testing environment with
Jest, while still getting familiar with the tools, I suggest starting a project with <a href="https://create-react-app.dev/">Create React App</a>. It already has Jest configured, and also has excellent documentation on how to <a href="https://create-react-app.dev/docs/running-tests/">run</a> and <a href="https://create-react-app.dev/docs/debugging-tests/">debug</a> tests.</p>
<h2>Recipes</h2>
<p>One of the challenges with testing is knowing how to test a particular use-case. Use-cases can be general like data-fetching or triggering events, or more particular like how to test a piece of code that uses <a href="https://reacttraining.com/react-router/web/guides/quick-start">React Router</a>. The strategies to handle those use-cases we call testing recipes or testing patterns.</p>
<p>You don't need to know all recipes before starting to write tests. What's important is that you know that the concept of recipes exist and you know where to look for them when you need them.</p>
<p>The best place to find testing recipes is usually the documentation of the tools you're using to write tests and the documentation of the libraries you're using to write your production code.</p>
<p>Testing some code that uses React Router? Check their documentation on <a href="https://reacttraining.com/react-router/web/guides/testing">testing</a>. Using React Testing Library? Check their guides and <a href="https://testing-library.com/docs/recipes">recipes</a>. Using React? React also has documentation on <a href="https://reactjs.org/docs/testing-recipes.html">testing</a>. And the same goes for <a href="https://jestjs.io/docs/en/tutorial-async">Jest</a>.</p>
<p><em>When you don't know how to test a piece of code or want to find a better way to test it, check the documentation of the tools you're using.</em></p>
<h2>Methodology</h2>
<p>Recipes tell you how to test something, but they won't tell you what to test and how to incorporate testing in your development process. That's where a methodology comes in.</p>
<p>Some of the important things about a testing methodology are:</p>
<ol>
<li><em>Give you confidence that the code you wrote works.</em></li>
<li><em>Allow you to refactor code without fear of breaking what's working.</em></li>
<li><em>It makes you more productive on the medium to long term.</em></li>
</ol>
<p>Effectively using a testing methodology is the hardest of writing automated. Most of your frustrations and doubts will come from here.</p>
<p>My suggestion when starting is to keep it as simple as possible, so you can start writing tests right away. Usually, the more natural approach is to program a feature or a sub-feature and then write tests for it, so I recommend you start there. You may need to change the code you've written to write tests for it, and that's fine.</p>
<p>If you're not sure what constitutes a feature, think of it as a set of behaviors your user cares about. Are you making an app that lets your user search for movies? Then it's a good idea to have a set of tests that checks the user can search for a movie and see the results of that search, as well as what happens when you don't find any movies or if there was an error.</p>
<p>I use Test-Driven-Development(TDD), so my testing methodology is embedded in this broader development process. Although some people can take it way too far and turn it into a religion, I recommend you try it out with a pragmatic mindset. It helps me know what to test and stay focused on my work. If you're curious about learning TDD, I recommend you read the book <a href="https://www.goodreads.com/book/show/387190.Test_Driven_Development">Test Driven Development: By example</a> by Kent Beck.</p>
<h2>Exercise: Get comfortable with testing tools and documentation</h2>
<p>The goal of this exercise is to get you familiar with the tools you'll be using for testing, and also to create the habit of checking documentation for testing recipes. Keep in mind that the tests you'll be writing in this exercise aren't necessarily the tests you'd be writing in a professional application.</p>
<h3>1. Read Create React App documentation on <a href="https://create-react-app.dev/docs/running-tests/">running</a> and <a href="https://create-react-app.dev/docs/debugging-tests/">debugging</a> tests</h3>
<p>Even if not everything on those two pages seems useful, finish reading them. It will help breed familiarity with the tools and make them easier to use.</p>
<h3>2. Create a React application using Create React App</h3>
<p>This application is where you'll be writing your tests.</p>
<h3>3. Write a test for an add function</h3>
<p>Write a simple add function and then write a test to assert that 6 + 4 = 10. If you're not sure how to assert two values are equal, check Jest's <a href="https://jestjs.io/docs/en/expect">documentation</a>. Now that you've written a test, run it. If you read Create React App documentation on <a href="https://create-react-app.dev/docs/running-tests/">running</a> tests, you should know how to do it.</p>
<h3>4. Read React Testing Library <a href="https://testing-library.com/docs/react-testing-library/intro">Introduction</a> and <a href="https://testing-library.com/docs/react-testing-library/example-intro">Example</a></h3>
<p>Reading React Testing Library documentation will give you familiarity with the tool principles and API and thus make you use it better. Yet again, don't worry if not everything makes sense from the start.</p>
<p>Notice that the version of React Testing Library that comes by default with the Create React App may not be the most up to date, so the methods shown in the documentation may not be available to you. To update to the current version of React Testing Library, you'll need to reinstall it. You may also need to update the <a href="https://github.com/jsdom/jsdom">jsdom</a> version Jest is using. To do that, install the most up to date package of the jsdom environment for Jest, as of now <a href="https://www.npmjs.com/package/jest-environment-jsdom-sixteen">jest-environment-jsdom-sixteen</a>, and change the testing script to use the new environment. It should look something like this: <code>"test": "react-scripts test --env=jest-environment-jsdom-sixteen"</code></p>
<h3>5. Write tests for a React component that adds two numbers</h3>
<p>Make a simple React component that allows a user to add two numbers and see the result. Use the add function from before. Keep the UI simple. Two labeled inputs for the numbers, a button to make the addition, and a place to see the result.</p>
<p>Now write a simple test using React Testing Library to assert that the two inputs and the button to perform the addition are rendered. If you've read Jest's documentation on <a href="https://create-react-app.dev/docs/running-tests#option-2-react-testing-library">running</a> tests, you've already seen a piece of code that uses what you need for this.</p>
<p>Now write a test that asserts 3 + 4 = 7. For this, you'll need to simulate a user entering numbers and clicking on the button to perform the addition. If you've read Rect Testing Library <a href="https://testing-library.com/docs/react-testing-library/example-intro">example</a>, you already know what module from React Testing Library you'll have to use to simulate a user changing an input and clicking on a button. If you're still lost, use the search bar on React Testing Library documentation to look for docs about what you're trying to test.</p>
<h3>6. Make your add function async and adapt your code and tests to the change</h3>
<p>Make your add function return a <code>Promise</code> of a number instead of a number. The <code>Promise</code> should resolve after 500ms. Also, adapt the React component to work with the now asynchronous add function.</p>
<p>You now have to change the tests for the add function and the React component, since now they're failing.</p>
<p>For the add function, you'll have to change your test to assert the result of a <code>Promise</code>. You may not be sure how to test a function that returns a promise, in which case check the <a href="https://jestjs.io/docs/en/tutorial-async#resolves">documentation</a>.</p>
<p>For the React component, you'll have to deal with the fact that the result of the addition won't be there right after the user clicks the button. A simple approach to this problem is to wait for the result to appear on the screen. By now, you probably already know where to look for that. But in case you're in doubt, <a href="https://testing-library.com/docs/guide-disappearance">here's</a> the react testing library documentation.</p>
<p>If you've managed to get to the end of this exercise congratulations! You now have some familiarity with the tools involved in the day to day testing of a React application, as well as some experience with testing asynchronous code.</p>
<p>If doing this exercise felt hard and not that straightforward, don't worry. Struggling with the tools and exploring documentation is part of the learning process. Next time it will be easier.</p>
<p>In case you want to check what a solution to this exercise, you can check this <a href="https://gist.github.com/Jnforja/fc8af531e23791ee676ab244d11b5a29">gist</a>.</p>
<h2>Conclusion</h2>
<p>Keep in mind that learning how to write tests effectively has a steep learning curve. Don't be discouraged if it feels like it's hard work.</p>
<p>To effectively write tests, you'll need to know some tools, know where you can find testing recipes, and have a testing methodology established.</p>
<p>If you're struggling with testing a piece of code, look for a solution on the documentation of tools and libraries you're using.</p>
<p>Start with the simple testing methodology of writing automated tests after writing the code for a feature. Test the behavior the user cares about and test enough to make yourself comfortable that the code works. If you want to check other testing methodology, consider reading <a href="https://www.goodreads.com/book/show/387190.Test_Driven_Development">Test Driven Development: By example</a></p>
<p>Do the exercise shown in this article so that you get comfortable with testing tools and documentation.</p>
<p>And last but not least, keep writing tests and evaluate the value they're bringing to you and the project. If you do this, the quality of your tests and code will keep improving.</p>
<h2>Next steps</h2>
<p>One of the challenges of writing automated tests is knowing what to test. And great way to deal with this problem is to learn <a href="/articles/learn-how-to-make-a-test-list/">how to make a test list out of feature requirements</a>.</p>
<p>So if you're looking to improve your testing skills, learning <a href="/articles/learn-how-to-make-a-test-list/">how to make a test list</a> is a great next step to take.</p>]]></content:encoded>
            <author>João Forja</author>
        </item>
        <item>
            <title><![CDATA[How to have different mock responses for multiple tests using Jest and React]]></title>
            <link>https://joaoforja.com/articles/how-to-have-different-mock-responses-for-multiple-tests-using-jest-and-react</link>
            <guid isPermaLink="false">https://joaoforja.com/articles/how-to-have-different-mock-responses-for-multiple-tests-using-jest-and-react</guid>
            <pubDate>Fri, 08 May 2020 09:12:03 GMT</pubDate>
            <content:encoded><![CDATA[<blockquote>
<p>I am quite confused with mocking in Jest. I just want to mock different expected behaviors per test</p>
</blockquote>
<p>Although not always possible, a more straightforward approach than mocking a module with Jest is to change the React component to receive the dependency as a prop. This approach allows us to pass a different mock function or mock value per test, without having to worry about the quirks of mocking modules.</p>
<p>So we don't have to change code that uses the component we're testing, we can use
<a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Default_parameters">default parameters</a>.</p>
<p>Here's how this approach looks like:</p>
<pre class="language-jsx"><code class="language-jsx"><span class="token keyword module">import</span> <span class="token imports"><span class="token punctuation">{</span> fetchTodosFromAPI <span class="token punctuation">}</span></span> <span class="token keyword module">from</span> <span class="token string">'./api-client'</span>

<span class="token keyword">function</span> <span class="token function"><span class="token maybe-class-name">TodosList</span></span><span class="token punctuation">(</span><span class="token parameter"><span class="token punctuation">{</span> fetchTodos <span class="token operator">=</span> fetchTodosFromAPI <span class="token punctuation">}</span></span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token comment">// gets todos from fetchTodos() and renders result</span>
<span class="token punctuation">}</span>
</code></pre>
<pre class="language-jsx"><code class="language-jsx"><span class="token comment">// tests using react-testing-library</span>
<span class="token function">test</span><span class="token punctuation">(</span><span class="token string">'shows message when to-do list is empty'</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token arrow operator">=&gt;</span> <span class="token punctuation">{</span>
  <span class="token keyword">const</span> fetchEmptyListOfTodos <span class="token operator">=</span> jest<span class="token punctuation">.</span><span class="token method function property-access">fn</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token method function property-access">mockResolvedValue</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">)</span>
  <span class="token function">render</span><span class="token punctuation">(</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span><span class="token class-name">TodosList</span></span> <span class="token attr-name">fetchTodos</span><span class="token script language-javascript"><span class="token script-punctuation punctuation">=</span><span class="token punctuation">{</span>fetchEmptyListOfTodos<span class="token punctuation">}</span></span> <span class="token punctuation">/&gt;</span></span><span class="token punctuation">)</span>
  <span class="token comment">// asserts renders message for empty to-dos list</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span>

<span class="token function">test</span><span class="token punctuation">(</span><span class="token string">'shows list with one to-do'</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token arrow operator">=&gt;</span> <span class="token punctuation">{</span>
  <span class="token keyword">const</span> fetchListWithOneTodo <span class="token operator">=</span> jest
    <span class="token punctuation">.</span><span class="token method function property-access">fn</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
    <span class="token punctuation">.</span><span class="token method function property-access">mockResolvedValue</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token punctuation">{</span> <span class="token literal-property property">id</span><span class="token operator">:</span> <span class="token number">1</span><span class="token punctuation">,</span> <span class="token literal-property property">title</span><span class="token operator">:</span> <span class="token string">'Study testing'</span> <span class="token punctuation">}</span><span class="token punctuation">]</span><span class="token punctuation">)</span>
  <span class="token function">render</span><span class="token punctuation">(</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span><span class="token class-name">TodosList</span></span> <span class="token attr-name">fetchTodos</span><span class="token script language-javascript"><span class="token script-punctuation punctuation">=</span><span class="token punctuation">{</span>fetchListWithOneTodo<span class="token punctuation">}</span></span> <span class="token punctuation">/&gt;</span></span><span class="token punctuation">)</span>
  <span class="token comment">// assert renders single todo</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span>

<span class="token function">test</span><span class="token punctuation">(</span><span class="token string">'shows error message when there is a network failure'</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token arrow operator">=&gt;</span> <span class="token punctuation">{</span>
  <span class="token keyword">const</span> rejectWithNetworkFailure <span class="token operator">=</span> jest
    <span class="token punctuation">.</span><span class="token method function property-access">fn</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
    <span class="token punctuation">.</span><span class="token method function property-access">mockRejectedValue</span><span class="token punctuation">(</span><span class="token keyword">new</span> <span class="token class-name">Error</span><span class="token punctuation">(</span><span class="token string">'Network failure'</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
  <span class="token function">render</span><span class="token punctuation">(</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span><span class="token class-name">TodosList</span></span> <span class="token attr-name">fetchTodos</span><span class="token script language-javascript"><span class="token script-punctuation punctuation">=</span><span class="token punctuation">{</span>rejectWithNetworkFailure<span class="token punctuation">}</span></span> <span class="token punctuation">/&gt;</span></span><span class="token punctuation">)</span>
  <span class="token comment">// asserts renders error message</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span>
</code></pre>
<h2>Put it into practice</h2>
<ol>
<li>Change the component to receive the dependency as a prop.</li>
<li>Use default parameters to pass the production dependency to the component.</li>
<li>Go to your tests, and instead of mocking the dependency module, give a mock function to the component through the new prop.</li>
</ol>
<p>Although I only referenced React components, this approach also works well for everyday javascript function.</p>]]></content:encoded>
            <author>João Forja</author>
        </item>
        <item>
            <title><![CDATA[How to implement infinite scroll using React, Hooks and Intersection Observers]]></title>
            <link>https://joaoforja.com/articles/how-to-implement-infinite-scroll-in-react</link>
            <guid isPermaLink="false">https://joaoforja.com/articles/how-to-implement-infinite-scroll-in-react</guid>
            <pubDate>Fri, 03 Apr 2020 09:15:03 GMT</pubDate>
            <content:encoded><![CDATA[<p>When we want to add an infinite scroll to a React app, we can try to find a library that already does it for us, or we can implement our version from scratch. Since building things is one of the best ways to improve as a software developer, in this article, we'll go over how to develop an infinite scroll.</p>
<p>Before we start to develop something, we need to have a good grasp of what it is that we want to build. So let's elaborate a bit more on the context in which we'll implement an infinite scroll and how exactly it should behave.</p>
<h2>Context and Requirements</h2>
<p>We will implement an infinite scroll in the context of a simple web app, which its goal is to show images from the API <a href="https://picsum.photos/">Lorem Picsum</a>. The app will have a single page that will work similarly to a feed from a social networking app. But instead of showing posts, it will show images.</p>
<p>The requirements for the infinite scroll app are:</p>
<ol>
<li>Shows images from Lorem Picsum API;</li>
<li>While fetching images, the app should show a loading message;</li>
<li>If there's an error fetching images, the app should allow the user to retry fetching;</li>
<li>Whenever the user has seen all the images on his screen, the app should request new ones;</li>
<li>If the user has consumed all the content from the API, the app should show him a message saying so;</li>
<li>After the user has seen all the images from the API, the app shouldn't make more API requests;</li>
<li>While the app is making an API request, there shouldn't be any more API requests.</li>
</ol>
<p>Note: If you're curious about how the app will look like, you can take a look at this <a href="https://jnforja.github.io/infinite-scroll-react-app/">demo</a>.</p>
<h2>States, actions, and transitions</h2>
<p>A useful way to structure UIs that have some complexity is as a state machine. For our app, the following states come right up to mind:</p>
<ol>
<li><strong>Idle</strong> - The app isn't fetching images.</li>
<li><strong>Loading</strong> - The app is fetching new images</li>
<li><strong>Error</strong> - There was an error fetching images.</li>
<li><strong>Finished</strong> - The app has fetched all images from the API.</li>
</ol>
<p>We'll need to have actions to transition our app from state to state. The actions that come to mind are:</p>
<ol>
<li><strong>Start Fetch</strong> - Fetch new images.</li>
<li><strong>Fetch Success</strong> - Successfully fetched new images.</li>
<li><strong>Fetch Error</strong> - There was an error fetching new images.</li>
<li><strong>Reached End</strong> - The API didn't have more images.</li>
</ol>
<p>We can represent our states and actions in code using constants:</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">const</span> startFetch <span class="token operator">=</span> <span class="token string">'START_FETCH'</span>
<span class="token keyword">const</span> fetchSuccess <span class="token operator">=</span> <span class="token string">'FETCH_SUCCESS'</span>
<span class="token keyword">const</span> errorFetch <span class="token operator">=</span> <span class="token string">'FETCH_ERROR'</span>
<span class="token keyword">const</span> reachedEnd <span class="token operator">=</span> <span class="token string">'REACHED_END'</span>

<span class="token keyword">const</span> idleStatus <span class="token operator">=</span> <span class="token string">'IDLE'</span>
<span class="token keyword">const</span> errorStatus <span class="token operator">=</span> <span class="token string">'ERROR'</span>
<span class="token keyword">const</span> loadingStatus <span class="token operator">=</span> <span class="token string">'LOADING'</span>
<span class="token keyword">const</span> finishedStatus <span class="token operator">=</span> <span class="token string">'FINISHED'</span>
</code></pre>
<p>We also need to define how the states and actions will interact with each other. In other words, we need to set the transitions.</p>
<p>When the app is <code>IDLE</code>, the only action that we'll need to listen to is <code>START_FETCH</code>, and that will cause a transition to <code>LOADING</code>.</p>
<p>The state <code>ERROR</code> is the same as the <code>IDLE</code> on from the perspective of transitions. It also only listens to <code>START_FETCH</code>, which will cause a change to <code>LOADING</code>.</p>
<p>State <code>LOADING</code> listens to the actions <code>FETCH_SUCCESS</code>, <code>FETCH_ERROR</code>, and <code>REACHED_END</code>. On <code>FETCH_SUCCESS</code> it should go to <code>IDLE</code>. On <code>FETCH_ERROR</code> it should go to <code>ERROR</code>. And on <code>REACHED_END</code> it should go to <code>FINISHED</code>.</p>
<p>The state <code>FINISHED</code> is a terminal state. The app won't have any more state changes from there, so it doesn't need to listen to any actions.</p>
<p>Since we're using React and React has the <a href="https://reactjs.org/docs/hooks-reference.html#usereducer">useReducer</a> hook, we'll be representing the state transitions in our code using a reducer.</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">function</span> <span class="token function">infiniteScrollReducer</span><span class="token punctuation">(</span><span class="token parameter">state<span class="token punctuation">,</span> action</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword control-flow">switch</span> <span class="token punctuation">(</span>state<span class="token punctuation">.</span><span class="token property-access">status</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">case</span> <span class="token literal-property property">idleStatus</span><span class="token operator">:</span>
    <span class="token keyword">case</span> <span class="token literal-property property">errorStatus</span><span class="token operator">:</span>
      <span class="token keyword control-flow">return</span> action<span class="token punctuation">.</span><span class="token property-access">type</span> <span class="token operator">===</span> startFetch
        <span class="token operator">?</span> <span class="token punctuation">{</span> <span class="token spread operator">...</span>state<span class="token punctuation">,</span> <span class="token literal-property property">status</span><span class="token operator">:</span> loadingStatus <span class="token punctuation">}</span>
        <span class="token operator">:</span> state

    <span class="token keyword">case</span> <span class="token literal-property property">loadingStatus</span><span class="token operator">:</span>
      <span class="token keyword control-flow">if</span> <span class="token punctuation">(</span>action<span class="token punctuation">.</span><span class="token property-access">type</span> <span class="token operator">===</span> errorFetch<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token keyword control-flow">return</span> <span class="token punctuation">{</span> <span class="token spread operator">...</span>state<span class="token punctuation">,</span> <span class="token literal-property property">status</span><span class="token operator">:</span> errorStatus <span class="token punctuation">}</span>
      <span class="token punctuation">}</span>
      <span class="token keyword control-flow">if</span> <span class="token punctuation">(</span>action<span class="token punctuation">.</span><span class="token property-access">type</span> <span class="token operator">===</span> reachedEnd<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token keyword control-flow">return</span> <span class="token punctuation">{</span> <span class="token spread operator">...</span>state<span class="token punctuation">,</span> <span class="token literal-property property">status</span><span class="token operator">:</span> finishedStatus <span class="token punctuation">}</span>
      <span class="token punctuation">}</span>
      <span class="token keyword control-flow">if</span> <span class="token punctuation">(</span>action<span class="token punctuation">.</span><span class="token property-access">type</span> <span class="token operator">===</span> fetchSuccess<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token keyword control-flow">return</span> <span class="token punctuation">{</span>
          <span class="token spread operator">...</span>state<span class="token punctuation">,</span>
          <span class="token literal-property property">status</span><span class="token operator">:</span> idleStatus<span class="token punctuation">,</span>
        <span class="token punctuation">}</span>
      <span class="token punctuation">}</span>
      <span class="token keyword control-flow">return</span> state
    <span class="token keyword">case</span> <span class="token literal-property property">finishedStatus</span><span class="token operator">:</span>
      <span class="token keyword control-flow">return</span> state
    <span class="token keyword module">default</span><span class="token operator">:</span>
      <span class="token keyword control-flow">throw</span> <span class="token keyword">new</span> <span class="token class-name">Error</span><span class="token punctuation">(</span><span class="token string">'Unknown state'</span><span class="token punctuation">)</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre>
<h2>Fetch images request</h2>
<p>Now that we've gone over the states and actions the app will have, let's implement the function that will fetch the images.</p>
<p>Given we need to have an error and a finished state, we need to define what constitutes an error, and what signals that we've reached the end.</p>
<p>We'll consider that there was an error if the API response status is different than 200 or if the request throws an error. We'll assume that we've consumed all images if the API returns an empty array.</p>
<p>Since we're fetching images to show later, we'll need to store them somewhere. The API uses a pagination system, so we'll also have to save the current page as well. Given we're already using a reducer, let's add those values to the reducer state and have the fetch function receive it.</p>
<p>We'll also need the fetch request to dispatch actions, so we'll give it the dispatch function as well.</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">async</span> <span class="token keyword">function</span> <span class="token function">fetchImages</span><span class="token punctuation">(</span><span class="token parameter">state<span class="token punctuation">,</span> dispatch</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword control-flow">try</span> <span class="token punctuation">{</span>
    <span class="token keyword">const</span> res <span class="token operator">=</span> <span class="token keyword control-flow">await</span> <span class="token function">fetch</span><span class="token punctuation">(</span>
      <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">https://picsum.photos/v2/list?page=</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>state<span class="token punctuation">.</span><span class="token property-access">pageNumber</span><span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">&amp;limit=5</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">,</span>
    <span class="token punctuation">)</span>
    <span class="token keyword control-flow">if</span> <span class="token punctuation">(</span>res<span class="token punctuation">.</span><span class="token property-access">status</span> <span class="token operator">===</span> <span class="token number">200</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
      <span class="token keyword">const</span> imgs <span class="token operator">=</span> <span class="token keyword control-flow">await</span> res<span class="token punctuation">.</span><span class="token method function property-access">json</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
      <span class="token keyword control-flow">if</span> <span class="token punctuation">(</span>imgs<span class="token punctuation">.</span><span class="token property-access">length</span> <span class="token operator">===</span> <span class="token number">0</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token keyword control-flow">return</span> <span class="token function">dispatch</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token literal-property property">type</span><span class="token operator">:</span> reachedEnd <span class="token punctuation">}</span><span class="token punctuation">)</span>
      <span class="token punctuation">}</span>
      <span class="token keyword control-flow">return</span> <span class="token function">dispatch</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
        <span class="token literal-property property">type</span><span class="token operator">:</span> fetchSuccess<span class="token punctuation">,</span>
        <span class="token literal-property property">payload</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token literal-property property">imagesUrls</span><span class="token operator">:</span> imgs<span class="token punctuation">.</span><span class="token method function property-access">map</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">i</span><span class="token punctuation">)</span> <span class="token arrow operator">=&gt;</span> i<span class="token punctuation">.</span><span class="token property-access">download_url</span><span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token punctuation">}</span><span class="token punctuation">)</span>
    <span class="token punctuation">}</span> <span class="token keyword control-flow">else</span> <span class="token punctuation">{</span>
      <span class="token function">dispatch</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token literal-property property">type</span><span class="token operator">:</span> errorFetch <span class="token punctuation">}</span><span class="token punctuation">)</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span> <span class="token keyword control-flow">catch</span> <span class="token punctuation">(</span>e<span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token function">dispatch</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token literal-property property">type</span><span class="token operator">:</span> errorFetch <span class="token punctuation">}</span><span class="token punctuation">)</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre>
<p>To wrap up this part of our code, all we have left to do is to store the newly retrieved images and to increment the page number if the request was successful. We can handle that at the reducer.</p>
<pre class="language-javascript"><code class="language-javascript"> <span class="token keyword">case</span> <span class="token literal-property property">loadingStatus</span><span class="token operator">:</span>
      <span class="token comment">//code to handle other actions</span>
      <span class="token spread operator">...</span>
      <span class="token keyword control-flow">if</span> <span class="token punctuation">(</span>action<span class="token punctuation">.</span><span class="token property-access">type</span> <span class="token operator">===</span> fetchSuccess<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token keyword control-flow">return</span> <span class="token punctuation">{</span>
          <span class="token spread operator">...</span>state<span class="token punctuation">,</span>
          <span class="token literal-property property">imagesUrls</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token spread operator">...</span>state<span class="token punctuation">.</span><span class="token property-access">imagesUrls</span><span class="token punctuation">,</span> <span class="token spread operator">...</span>action<span class="token punctuation">.</span><span class="token property-access">payload</span><span class="token punctuation">.</span><span class="token property-access">imagesUrls</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
          <span class="token literal-property property">pageNumber</span><span class="token operator">:</span> state<span class="token punctuation">.</span><span class="token property-access">pageNumber</span> <span class="token operator">+</span> <span class="token number">1</span><span class="token punctuation">,</span>
          <span class="token literal-property property">status</span><span class="token operator">:</span> idleStatus
        <span class="token punctuation">}</span><span class="token punctuation">;</span>
      <span class="token punctuation">}</span>
</code></pre>
<h2>Trigger images fetch</h2>
<p>To fulfill the requirements, we need to fetch and show new images when the user has seen all the current ones. Which pops up the question "How do we know the user has seen all the images?"</p>
<p>A common approach is to check the scroll bar position. If the scroll bar is at the end of the page, the user has seen all content. However, this approach takes for granted that we'll fetch enough images from the start to fill up the height of the user's screen, thus creating a scroll bar. Depending on the height of the user's screen, this might not be true.</p>
<p>A more robust approach is to use the browser's <a href="https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API">Intersection Observer API</a>.</p>
<p>Intersection Observers allow us to know when an element is being shown on the screen. So what we'll do is have an HTML element that will be after the last image shown to the user. If that element appears on the screen, we know the user as seen all the images. Let's call that element <code>borderBottom</code>.</p>
<p>When the Intersection Observer notifies us that <code>borderBottom</code> is showing, we want to fetch new images, so we should dispatch <code>START_FETCH</code>.</p>
<p>To use an Intersection Observer on a React component, we need to have the <code>borderBottom</code> HTML element. To do that we'll use a <a href="https://reactjs.org/docs/refs-and-the-dom.html#callback-refs">callback ref</a>. After React creates the HTML element of <code>borderBottom</code>, it will call the callback ref, and we'll check for when <code>borderBottom</code> becomes visible to the user through an Intersection Observer. This approach results in the following:</p>
<pre class="language-jsx"><code class="language-JSX"><span class="token keyword">const</span> observeBorder <span class="token operator">=</span> <span class="token function">useCallback</span><span class="token punctuation">(</span><span class="token parameter">node</span> <span class="token arrow operator">=&gt;</span> <span class="token punctuation">{</span>
    <span class="token keyword control-flow">if</span> <span class="token punctuation">(</span>node <span class="token operator">!==</span> <span class="token keyword null nil">null</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
      <span class="token keyword">new</span> <span class="token class-name">IntersectionObserver</span><span class="token punctuation">(</span>
        <span class="token parameter">entries</span> <span class="token arrow operator">=&gt;</span> <span class="token punctuation">{</span>
          entries<span class="token punctuation">.</span><span class="token method function property-access">forEach</span><span class="token punctuation">(</span><span class="token parameter">en</span> <span class="token arrow operator">=&gt;</span> <span class="token punctuation">{</span>
            <span class="token keyword control-flow">if</span> <span class="token punctuation">(</span>en<span class="token punctuation">.</span><span class="token property-access">intersectionRatio</span> <span class="token operator">===</span> <span class="token number">1</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
              <span class="token function">dispatch</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token literal-property property">type</span><span class="token operator">:</span> startFetch <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
            <span class="token punctuation">}</span>
          <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span><span class="token punctuation">,</span>
        <span class="token punctuation">{</span> <span class="token literal-property property">threshold</span><span class="token operator">:</span> <span class="token number">1</span> <span class="token punctuation">}</span>
      <span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token method function property-access">observe</span><span class="token punctuation">(</span>node<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token keyword">function</span> <span class="token function">renderBottomBorder</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword control-flow">return</span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">ref</span><span class="token script language-javascript"><span class="token script-punctuation punctuation">=</span><span class="token punctuation">{</span>observeBorder<span class="token punctuation">}</span></span> <span class="token punctuation">/&gt;</span></span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>
</code></pre>
<p>The only thing that's left to do is the actual API call.</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token function">useEffect</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token arrow operator">=&gt;</span> <span class="token punctuation">{</span>
  <span class="token keyword control-flow">if</span> <span class="token punctuation">(</span>state<span class="token punctuation">.</span><span class="token property-access">status</span> <span class="token operator">===</span> loadingStatus<span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token function">fetchImages</span><span class="token punctuation">(</span>state<span class="token punctuation">,</span> dispatch<span class="token punctuation">)</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">[</span>state<span class="token punctuation">]</span><span class="token punctuation">)</span>
</code></pre>
<p>By giving state as a dependency to <code>useEffect</code> hook, we get the possibility to execute a function when entering a new state. For our app, we only want to execute a function when entering <code>LOADING</code>. So we check that we're now loading and fetch new images. We must be careful not to change the identity of the object <code>state</code>, unless we're changing the state of the app. Otherwise, we'll be triggering the <code>useEffect</code> callback. Which, in our case, might result in doing API calls while the app is loading. This is especially easy to happen when implementing the reducer. All it takes is to return <code>{...state}</code> instead of <code>state</code> on default cases.</p>
<h2>Views</h2>
<p>We're almost done. All that's left is to render the images, messages, and the error button when the state is appropriate. Also, remember that the user should be able to click the error button to fetch the images again. So we'll have to dispatch an action when the user clicks the button.</p>
<pre class="language-jsx"><code class="language-JSX"><span class="token keyword control-flow">return</span> <span class="token punctuation">(</span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span></span><span class="token punctuation">&gt;</span></span><span class="token plain-text">
      </span><span class="token punctuation">{</span><span class="token function">renderImages</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">}</span><span class="token plain-text">
      </span><span class="token punctuation">{</span>state<span class="token punctuation">.</span><span class="token property-access">status</span> <span class="token operator">===</span> errorStatus <span class="token operator">&amp;&amp;</span> <span class="token function">renderErrorRetryButton</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">}</span><span class="token plain-text">
      </span><span class="token punctuation">{</span>state<span class="token punctuation">.</span><span class="token property-access">status</span> <span class="token operator">===</span> loadingStatus <span class="token operator">&amp;&amp;</span> <span class="token function">renderLoadingMessage</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">}</span><span class="token plain-text">
      </span><span class="token punctuation">{</span>state<span class="token punctuation">.</span><span class="token property-access">status</span> <span class="token operator">===</span> finishedStatus <span class="token operator">&amp;&amp;</span> <span class="token function">renderNoMoreImagesMessage</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">}</span><span class="token plain-text">
      </span><span class="token punctuation">{</span><span class="token function">renderBottomBorder</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">}</span><span class="token plain-text">
    </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span></span><span class="token punctuation">&gt;</span></span>
  <span class="token punctuation">)</span><span class="token punctuation">;</span>

  <span class="token keyword">function</span> <span class="token function">renderBottomBorder</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword control-flow">return</span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">ref</span><span class="token script language-javascript"><span class="token script-punctuation punctuation">=</span><span class="token punctuation">{</span>observeBorder<span class="token punctuation">}</span></span> <span class="token punctuation">/&gt;</span></span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>

  <span class="token keyword">function</span> <span class="token function">renderNoMoreImagesMessage</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword control-flow">return</span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>p</span><span class="token punctuation">&gt;</span></span><span class="token plain-text">There aren't more images</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>p</span><span class="token punctuation">&gt;</span></span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>

  <span class="token keyword">function</span> <span class="token function">renderImages</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword control-flow">return</span> state<span class="token punctuation">.</span><span class="token property-access">imagesUrls</span><span class="token punctuation">.</span><span class="token method function property-access">map</span><span class="token punctuation">(</span><span class="token parameter">url</span> <span class="token arrow operator">=&gt;</span> <span class="token punctuation">(</span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>img</span> <span class="token attr-name">key</span><span class="token script language-javascript"><span class="token script-punctuation punctuation">=</span><span class="token punctuation">{</span>url<span class="token punctuation">}</span></span> <span class="token attr-name">style</span><span class="token script language-javascript"><span class="token script-punctuation punctuation">=</span><span class="token punctuation">{</span>imageStyle<span class="token punctuation">}</span></span> <span class="token attr-name">src</span><span class="token script language-javascript"><span class="token script-punctuation punctuation">=</span><span class="token punctuation">{</span>url<span class="token punctuation">}</span></span> <span class="token attr-name">alt</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>mock alt<span class="token punctuation">"</span></span> <span class="token punctuation">/&gt;</span></span>
    <span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>

  <span class="token keyword">function</span> <span class="token function">renderErrorRetryButton</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword control-flow">return</span> <span class="token punctuation">(</span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>button</span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>button<span class="token punctuation">"</span></span> <span class="token attr-name">onClick</span><span class="token script language-javascript"><span class="token script-punctuation punctuation">=</span><span class="token punctuation">{</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token arrow operator">=&gt;</span> <span class="token function">dispatch</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token literal-property property">type</span><span class="token operator">:</span> startFetch <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">}</span></span><span class="token punctuation">&gt;</span></span><span class="token plain-text">
        Error! Click to try again
      </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>button</span><span class="token punctuation">&gt;</span></span>
    <span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>

  <span class="token keyword">function</span> <span class="token function">renderLoadingMessage</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword control-flow">return</span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>p</span><span class="token punctuation">&gt;</span></span><span class="token plain-text">Loading...</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>p</span><span class="token punctuation">&gt;</span></span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>
</code></pre>
<h2>End result</h2>
<p>We've implemented all the pieces of the app. Let's take a look at the final result.</p>
<pre class="language-jsx"><code class="language-JSX"><span class="token keyword">const</span> startFetch <span class="token operator">=</span> <span class="token string">"START_FETCH"</span><span class="token punctuation">;</span>
<span class="token keyword">const</span> fetchSuccess <span class="token operator">=</span> <span class="token string">"FETCH_SUCCESS"</span><span class="token punctuation">;</span>
<span class="token keyword">const</span> errorFetch <span class="token operator">=</span> <span class="token string">"FETCH_ERROR"</span><span class="token punctuation">;</span>
<span class="token keyword">const</span> reachedEnd <span class="token operator">=</span> <span class="token string">"REACHED_END"</span><span class="token punctuation">;</span>

<span class="token keyword">const</span> idleStatus <span class="token operator">=</span> <span class="token string">"IDLE"</span><span class="token punctuation">;</span>
<span class="token keyword">const</span> errorStatus <span class="token operator">=</span> <span class="token string">"ERROR"</span><span class="token punctuation">;</span>
<span class="token keyword">const</span> loadingStatus <span class="token operator">=</span> <span class="token string">"LOADING"</span><span class="token punctuation">;</span>
<span class="token keyword">const</span> finishedStatus <span class="token operator">=</span> <span class="token string">"FINISHED"</span><span class="token punctuation">;</span>

<span class="token keyword">function</span> <span class="token function">infiniteScrollReducer</span><span class="token punctuation">(</span><span class="token parameter">state<span class="token punctuation">,</span> action</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword control-flow">switch</span> <span class="token punctuation">(</span>state<span class="token punctuation">.</span><span class="token property-access">status</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">case</span> <span class="token literal-property property">idleStatus</span><span class="token operator">:</span>
    <span class="token keyword">case</span> <span class="token literal-property property">errorStatus</span><span class="token operator">:</span>
      <span class="token keyword control-flow">return</span> action<span class="token punctuation">.</span><span class="token property-access">type</span> <span class="token operator">===</span> startFetch
        <span class="token operator">?</span> <span class="token punctuation">{</span> <span class="token spread operator">...</span>state<span class="token punctuation">,</span> <span class="token literal-property property">status</span><span class="token operator">:</span> loadingStatus <span class="token punctuation">}</span>
        <span class="token operator">:</span> state<span class="token punctuation">;</span>

    <span class="token keyword">case</span> <span class="token literal-property property">loadingStatus</span><span class="token operator">:</span>
      <span class="token keyword control-flow">if</span> <span class="token punctuation">(</span>action<span class="token punctuation">.</span><span class="token property-access">type</span> <span class="token operator">===</span> errorFetch<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token keyword control-flow">return</span> <span class="token punctuation">{</span> <span class="token spread operator">...</span>state<span class="token punctuation">,</span> <span class="token literal-property property">status</span><span class="token operator">:</span> errorStatus <span class="token punctuation">}</span><span class="token punctuation">;</span>
      <span class="token punctuation">}</span>
      <span class="token keyword control-flow">if</span> <span class="token punctuation">(</span>action<span class="token punctuation">.</span><span class="token property-access">type</span> <span class="token operator">===</span> reachedEnd<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token keyword control-flow">return</span> <span class="token punctuation">{</span> <span class="token spread operator">...</span>state<span class="token punctuation">,</span> <span class="token literal-property property">status</span><span class="token operator">:</span> finishedStatus <span class="token punctuation">}</span><span class="token punctuation">;</span>
      <span class="token punctuation">}</span>
      <span class="token keyword control-flow">if</span> <span class="token punctuation">(</span>action<span class="token punctuation">.</span><span class="token property-access">type</span> <span class="token operator">===</span> fetchSuccess<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token keyword control-flow">return</span> <span class="token punctuation">{</span>
          <span class="token spread operator">...</span>state<span class="token punctuation">,</span>
          <span class="token literal-property property">imagesUrls</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token spread operator">...</span>state<span class="token punctuation">.</span><span class="token property-access">imagesUrls</span><span class="token punctuation">,</span> <span class="token spread operator">...</span>action<span class="token punctuation">.</span><span class="token property-access">payload</span><span class="token punctuation">.</span><span class="token property-access">imagesUrls</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
          <span class="token literal-property property">pageNumber</span><span class="token operator">:</span> state<span class="token punctuation">.</span><span class="token property-access">pageNumber</span> <span class="token operator">+</span> <span class="token number">1</span><span class="token punctuation">,</span>
          <span class="token literal-property property">status</span><span class="token operator">:</span> idleStatus
        <span class="token punctuation">}</span><span class="token punctuation">;</span>
      <span class="token punctuation">}</span>
      <span class="token keyword control-flow">return</span> state<span class="token punctuation">;</span>
    <span class="token keyword">case</span> <span class="token literal-property property">finishedStatus</span><span class="token operator">:</span>
      <span class="token keyword control-flow">return</span> state<span class="token punctuation">;</span>
    <span class="token keyword module">default</span><span class="token operator">:</span>
      <span class="token keyword control-flow">throw</span> <span class="token keyword">new</span> <span class="token class-name">Error</span><span class="token punctuation">(</span><span class="token string">"Unknown state"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span>

<span class="token keyword">async</span> <span class="token keyword">function</span> <span class="token function">fetchImages</span><span class="token punctuation">(</span><span class="token parameter">state<span class="token punctuation">,</span> dispatch</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword control-flow">try</span> <span class="token punctuation">{</span>
    <span class="token keyword">const</span> res <span class="token operator">=</span> <span class="token keyword control-flow">await</span> <span class="token function">fetch</span><span class="token punctuation">(</span>
      <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">https://picsum.photos/v2/list?page=</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>state<span class="token punctuation">.</span><span class="token property-access">pageNumber</span><span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">&amp;limit=5</span><span class="token template-punctuation string">`</span></span>
    <span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword control-flow">if</span> <span class="token punctuation">(</span>res<span class="token punctuation">.</span><span class="token property-access">status</span> <span class="token operator">===</span> <span class="token number">200</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
      <span class="token keyword">const</span> imgs <span class="token operator">=</span> <span class="token keyword control-flow">await</span> res<span class="token punctuation">.</span><span class="token method function property-access">json</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
      <span class="token keyword control-flow">if</span> <span class="token punctuation">(</span>imgs<span class="token punctuation">.</span><span class="token property-access">length</span> <span class="token operator">===</span> <span class="token number">0</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token keyword control-flow">return</span> <span class="token function">dispatch</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token literal-property property">type</span><span class="token operator">:</span> reachedEnd <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
      <span class="token punctuation">}</span>
      <span class="token keyword control-flow">return</span> <span class="token function">dispatch</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
        <span class="token literal-property property">type</span><span class="token operator">:</span> fetchSuccess<span class="token punctuation">,</span>
        <span class="token literal-property property">payload</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token literal-property property">imagesUrls</span><span class="token operator">:</span> imgs<span class="token punctuation">.</span><span class="token method function property-access">map</span><span class="token punctuation">(</span><span class="token parameter">i</span> <span class="token arrow operator">=&gt;</span> i<span class="token punctuation">.</span><span class="token property-access">download_url</span><span class="token punctuation">)</span> <span class="token punctuation">}</span>
      <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span> <span class="token keyword control-flow">else</span> <span class="token punctuation">{</span>
      <span class="token function">dispatch</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token literal-property property">type</span><span class="token operator">:</span> errorFetch <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span> <span class="token keyword control-flow">catch</span> <span class="token punctuation">(</span>e<span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token function">dispatch</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token literal-property property">type</span><span class="token operator">:</span> errorFetch <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span>

<span class="token keyword">const</span> initialState <span class="token operator">=</span> <span class="token punctuation">{</span> <span class="token literal-property property">imagesUrls</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token literal-property property">status</span><span class="token operator">:</span> idleStatus<span class="token punctuation">,</span> <span class="token literal-property property">pageNumber</span><span class="token operator">:</span> <span class="token number">1</span> <span class="token punctuation">}</span><span class="token punctuation">;</span>

<span class="token keyword">function</span> <span class="token function"><span class="token maybe-class-name">InfiniteScroll</span></span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">const</span> <span class="token punctuation">[</span>state<span class="token punctuation">,</span> dispatch<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">useReducer</span><span class="token punctuation">(</span>infiniteScrollReducer<span class="token punctuation">,</span> initialState<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token function">useEffect</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token arrow operator">=&gt;</span> <span class="token punctuation">{</span>
    <span class="token keyword control-flow">if</span> <span class="token punctuation">(</span>state<span class="token punctuation">.</span><span class="token property-access">status</span> <span class="token operator">===</span> loadingStatus<span class="token punctuation">)</span> <span class="token punctuation">{</span>
      <span class="token function">fetchImages</span><span class="token punctuation">(</span>state<span class="token punctuation">,</span> dispatch<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">[</span>state<span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

  <span class="token keyword">const</span> observeBorder <span class="token operator">=</span> <span class="token function">useCallback</span><span class="token punctuation">(</span><span class="token parameter">node</span> <span class="token arrow operator">=&gt;</span> <span class="token punctuation">{</span>
    <span class="token keyword control-flow">if</span> <span class="token punctuation">(</span>node <span class="token operator">!==</span> <span class="token keyword null nil">null</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
      <span class="token keyword">new</span> <span class="token class-name">IntersectionObserver</span><span class="token punctuation">(</span>
        <span class="token parameter">entries</span> <span class="token arrow operator">=&gt;</span> <span class="token punctuation">{</span>
          entries<span class="token punctuation">.</span><span class="token method function property-access">forEach</span><span class="token punctuation">(</span><span class="token parameter">en</span> <span class="token arrow operator">=&gt;</span> <span class="token punctuation">{</span>
            <span class="token keyword control-flow">if</span> <span class="token punctuation">(</span>en<span class="token punctuation">.</span><span class="token property-access">intersectionRatio</span> <span class="token operator">===</span> <span class="token number">1</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
              <span class="token function">dispatch</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token literal-property property">type</span><span class="token operator">:</span> startFetch <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
            <span class="token punctuation">}</span>
          <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span><span class="token punctuation">,</span>
        <span class="token punctuation">{</span> <span class="token literal-property property">threshold</span><span class="token operator">:</span> <span class="token number">1</span> <span class="token punctuation">}</span>
      <span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token method function property-access">observe</span><span class="token punctuation">(</span>node<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

  <span class="token keyword control-flow">return</span> <span class="token punctuation">(</span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span></span><span class="token punctuation">&gt;</span></span><span class="token plain-text">
      </span><span class="token punctuation">{</span><span class="token function">renderImages</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">}</span><span class="token plain-text">
      </span><span class="token punctuation">{</span>state<span class="token punctuation">.</span><span class="token property-access">status</span> <span class="token operator">===</span> errorStatus <span class="token operator">&amp;&amp;</span> <span class="token function">renderErrorRetryButton</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">}</span><span class="token plain-text">
      </span><span class="token punctuation">{</span>state<span class="token punctuation">.</span><span class="token property-access">status</span> <span class="token operator">===</span> loadingStatus <span class="token operator">&amp;&amp;</span> <span class="token function">renderLoadingMessage</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">}</span><span class="token plain-text">
      </span><span class="token punctuation">{</span>state<span class="token punctuation">.</span><span class="token property-access">status</span> <span class="token operator">===</span> finishedStatus <span class="token operator">&amp;&amp;</span> <span class="token function">renderNoMoreImagesMessage</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">}</span><span class="token plain-text">
      </span><span class="token punctuation">{</span><span class="token function">renderBottomBorder</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">}</span><span class="token plain-text">
    </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span></span><span class="token punctuation">&gt;</span></span>
  <span class="token punctuation">)</span><span class="token punctuation">;</span>

  <span class="token keyword">function</span> <span class="token function">renderBottomBorder</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword control-flow">return</span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">ref</span><span class="token script language-javascript"><span class="token script-punctuation punctuation">=</span><span class="token punctuation">{</span>observeBorder<span class="token punctuation">}</span></span> <span class="token punctuation">/&gt;</span></span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>

  <span class="token keyword">function</span> <span class="token function">renderNoMoreImagesMessage</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword control-flow">return</span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>p</span><span class="token punctuation">&gt;</span></span><span class="token plain-text">There aren't more images</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>p</span><span class="token punctuation">&gt;</span></span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>

  <span class="token keyword">function</span> <span class="token function">renderImages</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword control-flow">return</span> state<span class="token punctuation">.</span><span class="token property-access">imagesUrls</span><span class="token punctuation">.</span><span class="token method function property-access">map</span><span class="token punctuation">(</span><span class="token parameter">url</span> <span class="token arrow operator">=&gt;</span> <span class="token punctuation">(</span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>img</span> <span class="token attr-name">key</span><span class="token script language-javascript"><span class="token script-punctuation punctuation">=</span><span class="token punctuation">{</span>url<span class="token punctuation">}</span></span> <span class="token attr-name">style</span><span class="token script language-javascript"><span class="token script-punctuation punctuation">=</span><span class="token punctuation">{</span>imageStyle<span class="token punctuation">}</span></span> <span class="token attr-name">src</span><span class="token script language-javascript"><span class="token script-punctuation punctuation">=</span><span class="token punctuation">{</span>url<span class="token punctuation">}</span></span> <span class="token attr-name">alt</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>mock alt<span class="token punctuation">"</span></span> <span class="token punctuation">/&gt;</span></span>
    <span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>

  <span class="token keyword">function</span> <span class="token function">renderErrorRetryButton</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword control-flow">return</span> <span class="token punctuation">(</span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>button</span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>button<span class="token punctuation">"</span></span> <span class="token attr-name">onClick</span><span class="token script language-javascript"><span class="token script-punctuation punctuation">=</span><span class="token punctuation">{</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token arrow operator">=&gt;</span> <span class="token function">dispatch</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token literal-property property">type</span><span class="token operator">:</span> startFetch <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">}</span></span><span class="token punctuation">&gt;</span></span><span class="token plain-text">
        Error! Click to try again
      </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>button</span><span class="token punctuation">&gt;</span></span>
    <span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>

  <span class="token keyword">function</span> <span class="token function">renderLoadingMessage</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword control-flow">return</span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>p</span><span class="token punctuation">&gt;</span></span><span class="token plain-text">Loading...</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>p</span><span class="token punctuation">&gt;</span></span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span>

<span class="token keyword">const</span> imageStyle <span class="token operator">=</span> <span class="token punctuation">{</span>
  <span class="token literal-property property">width</span><span class="token operator">:</span> <span class="token string">"300px"</span><span class="token punctuation">,</span>
  <span class="token literal-property property">height</span><span class="token operator">:</span> <span class="token string">"200px"</span><span class="token punctuation">,</span>
  <span class="token literal-property property">display</span><span class="token operator">:</span> <span class="token string">"block"</span><span class="token punctuation">,</span>
  <span class="token literal-property property">marginBottom</span><span class="token operator">:</span> <span class="token string">"20px"</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span>
</code></pre>
<h2>Considerations</h2>
<p>Since we're dealing with images in the context of our app, we could have done some further optimizations. Lazy loading images and making them responsive being two that come right up to my mind. But given the focus of this article is on implementing infinite scroll, I left that part out of the scope.</p>
<p>Another vital thing that I didn't go over in this article is how to test this implementation. The way I prefer to do it is actually to start out by writing tests and then the implementation. However, I couldn't manage to mirror that process in this article while keeping it at a reasonable size and understandable. Instead, I opted to leave a <a href="https://github.com/Jnforja/infinite-scroll-react-app">link</a> to a Repository where you can find this app and the tests to it. In the future, I might write an article on how to test/test drive this app.</p>
<p>I hope that this approach of defining the requirements, followed by designing architecture and then going over to implementation, made sense to you. It's an approach that has proved useful to me time and time again.</p>
<p>If you enjoyed this article, you might also like <a href="/articles/5-steps-to-perform-a-search-when-user-stops-typing-using-react-+-hooks-in-a-controlled-component/">this one</a> about how to perform a search when a user stops typing using React and Hooks.</p>]]></content:encoded>
            <author>João Forja</author>
        </item>
        <item>
            <title><![CDATA[How to pass state between components]]></title>
            <link>https://joaoforja.com/articles/how-to-pass-state-between-components</link>
            <guid isPermaLink="false">https://joaoforja.com/articles/how-to-pass-state-between-components</guid>
            <pubDate>Fri, 21 Feb 2020 22:12:03 GMT</pubDate>
            <content:encoded><![CDATA[<blockquote>
<p>How do I pass state to a child component? How can I get state from a child component to a parent?</p>
</blockquote>
<p>A decision we constantly have to make when developing a React app, is how
to share state between multiple component. There are a lot of tools and patterns
that we can use to tackle this problem. However, sometimes we can get to a better
solution by removing instead of adding.</p>
<p>If you don't have multiple components, you don't have to worry about passing state
between them.</p>
<p>Ask yourself, do I really need this to be a component?</p>
<p>If you don't intend on reusing it across multiple different components, and it isn't
so complex that it's hard to reason unless it is isolated, then you probably don't
need it to be it's own component.</p>
<p>As an alternative, to keep your code readable,
we can just have our previous child components be variables inside the parent component.
Using this method all previous components will have direct access to the intended
state, which means we no longer have to worry about passing it.</p>
<p>Below is an example of what it looks like to use variables instead of components.</p>
<pre class="language-jsx"><code class="language-jsx"><span class="token keyword">function</span> <span class="token function"><span class="token maybe-class-name">CounterPage</span></span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">const</span> <span class="token punctuation">[</span>counter<span class="token punctuation">,</span> setCounter<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">useState</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">)</span>

  <span class="token keyword">const</span> header <span class="token operator">=</span> <span class="token punctuation">(</span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>header</span><span class="token punctuation">&gt;</span></span><span class="token plain-text">
      </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>h1</span><span class="token punctuation">&gt;</span></span><span class="token plain-text">This is a page for a counter</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>h1</span><span class="token punctuation">&gt;</span></span><span class="token plain-text">
    </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>header</span><span class="token punctuation">&gt;</span></span>
  <span class="token punctuation">)</span>

  <span class="token keyword">const</span> counterValueSection <span class="token operator">=</span> <span class="token punctuation">(</span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>section</span><span class="token punctuation">&gt;</span></span><span class="token plain-text">
      </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>h2</span><span class="token punctuation">&gt;</span></span><span class="token plain-text">Counter value</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>h2</span><span class="token punctuation">&gt;</span></span><span class="token plain-text">
      </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>p</span><span class="token punctuation">&gt;</span></span><span class="token punctuation">{</span>counter<span class="token punctuation">}</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>p</span><span class="token punctuation">&gt;</span></span><span class="token plain-text">
    </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>section</span><span class="token punctuation">&gt;</span></span>
  <span class="token punctuation">)</span>

  <span class="token keyword">const</span> counterControllersSection <span class="token operator">=</span> <span class="token punctuation">(</span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>section</span><span class="token punctuation">&gt;</span></span><span class="token plain-text">
      </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>h2</span><span class="token punctuation">&gt;</span></span><span class="token plain-text">Counter controllers</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>h2</span><span class="token punctuation">&gt;</span></span><span class="token plain-text">
      </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>button</span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>button<span class="token punctuation">"</span></span> <span class="token attr-name">onClick</span><span class="token script language-javascript"><span class="token script-punctuation punctuation">=</span><span class="token punctuation">{</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token arrow operator">=&gt;</span> <span class="token function">setCounter</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">c</span><span class="token punctuation">)</span> <span class="token arrow operator">=&gt;</span> c <span class="token operator">+</span> <span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">}</span></span><span class="token punctuation">&gt;</span></span><span class="token plain-text">
        +
      </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>button</span><span class="token punctuation">&gt;</span></span><span class="token plain-text">
      </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>button</span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>button<span class="token punctuation">"</span></span> <span class="token attr-name">onClick</span><span class="token script language-javascript"><span class="token script-punctuation punctuation">=</span><span class="token punctuation">{</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token arrow operator">=&gt;</span> <span class="token function">setCounter</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">c</span><span class="token punctuation">)</span> <span class="token arrow operator">=&gt;</span> c <span class="token operator">-</span> <span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">}</span></span><span class="token punctuation">&gt;</span></span><span class="token plain-text">
        -
      </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>button</span><span class="token punctuation">&gt;</span></span><span class="token plain-text">
    </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>section</span><span class="token punctuation">&gt;</span></span>
  <span class="token punctuation">)</span>

  <span class="token keyword control-flow">return</span> <span class="token punctuation">(</span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span><span class="token punctuation">&gt;</span></span><span class="token plain-text">
      </span><span class="token punctuation">{</span>header<span class="token punctuation">}</span><span class="token plain-text">
      </span><span class="token punctuation">{</span>counterValueSection<span class="token punctuation">}</span><span class="token plain-text">
      </span><span class="token punctuation">{</span>counterControllersSection<span class="token punctuation">}</span><span class="token plain-text">
    </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>
  <span class="token punctuation">)</span>
<span class="token punctuation">}</span>
</code></pre>
<p>Next time you're faced with the decision of how to pass state between components, ask yourself
if you really need to have multiples components, or if they can just be one.</p>
<p>You'll be amazed by how easy your life will get if you try to solve problems by removing instead
of adding.</p>]]></content:encoded>
            <author>João Forja</author>
        </item>
        <item>
            <title><![CDATA[How to persist state after a page refresh in React using local storage]]></title>
            <link>https://joaoforja.com/articles/how-to-persist-state-after-a-page-refresh-in-react-using-local-storage</link>
            <guid isPermaLink="false">https://joaoforja.com/articles/how-to-persist-state-after-a-page-refresh-in-react-using-local-storage</guid>
            <pubDate>Tue, 10 Dec 2019 22:12:03 GMT</pubDate>
            <content:encoded><![CDATA[<blockquote>
<p>What if the browser gets Refreshed? How do we keep the state persistent?</p>
</blockquote>
<p>Sometimes it is necessary to keep <strong>the state of a React component persistent even after a browser refresh</strong>. A simple way to accomplish this without having to rely on any third party library, is to use the localStorage API together with <code>useEffect</code> hook.</p>
<h2>Making state persistent</h2>
<p>Let's say we want to build a counter component which its state should persist after a page refresh. Starting out, our component would look something along these lines:</p>
<pre class="language-jsx"><code class="language-jsx"><span class="token keyword">function</span> <span class="token function"><span class="token maybe-class-name">Counter</span></span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">const</span> <span class="token punctuation">[</span>count<span class="token punctuation">,</span> setCount<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">useState</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">)</span>

  <span class="token keyword control-flow">return</span> <span class="token punctuation">(</span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span><span class="token punctuation">&gt;</span></span><span class="token plain-text">
      </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span><span class="token punctuation">&gt;</span></span><span class="token punctuation">{</span>count<span class="token punctuation">}</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span><span class="token plain-text">
      </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>button</span> <span class="token attr-name">onClick</span><span class="token script language-javascript"><span class="token script-punctuation punctuation">=</span><span class="token punctuation">{</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token arrow operator">=&gt;</span> <span class="token function">setCount</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">c</span><span class="token punctuation">)</span> <span class="token arrow operator">=&gt;</span> c <span class="token operator">+</span> <span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">}</span></span><span class="token punctuation">&gt;</span></span><span class="token plain-text">+</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>button</span><span class="token punctuation">&gt;</span></span><span class="token plain-text">
      </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>button</span> <span class="token attr-name">onClick</span><span class="token script language-javascript"><span class="token script-punctuation punctuation">=</span><span class="token punctuation">{</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token arrow operator">=&gt;</span> <span class="token function">setCount</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">c</span><span class="token punctuation">)</span> <span class="token arrow operator">=&gt;</span> c <span class="token operator">-</span> <span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">}</span></span><span class="token punctuation">&gt;</span></span><span class="token plain-text">-</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>button</span><span class="token punctuation">&gt;</span></span><span class="token plain-text">
    </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>
  <span class="token punctuation">)</span>
<span class="token punctuation">}</span>
</code></pre>
<p>First, we want to save the value of count to the local storage every time it changes. For that we'll use <code>useEffect</code> hook.</p>
<pre class="language-jsx"><code class="language-jsx"><span class="token keyword">function</span> <span class="token function"><span class="token maybe-class-name">Counter</span></span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">const</span> <span class="token punctuation">[</span>count<span class="token punctuation">,</span> setCount<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">useState</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">)</span>

  <span class="token function">useEffect</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token arrow operator">=&gt;</span> <span class="token punctuation">{</span>
    <span class="token dom variable">localStorage</span><span class="token punctuation">.</span><span class="token method function property-access">setItem</span><span class="token punctuation">(</span><span class="token string">'count'</span><span class="token punctuation">,</span> <span class="token known-class-name class-name">String</span><span class="token punctuation">(</span>count<span class="token punctuation">)</span><span class="token punctuation">)</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">[</span>count<span class="token punctuation">]</span><span class="token punctuation">)</span>

  <span class="token keyword control-flow">return</span> <span class="token punctuation">(</span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span><span class="token punctuation">&gt;</span></span><span class="token plain-text">
      </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span><span class="token punctuation">&gt;</span></span><span class="token punctuation">{</span>count<span class="token punctuation">}</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span><span class="token plain-text">
      </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>button</span> <span class="token attr-name">onClick</span><span class="token script language-javascript"><span class="token script-punctuation punctuation">=</span><span class="token punctuation">{</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token arrow operator">=&gt;</span> <span class="token function">setCount</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">c</span><span class="token punctuation">)</span> <span class="token arrow operator">=&gt;</span> c <span class="token operator">+</span> <span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">}</span></span><span class="token punctuation">&gt;</span></span><span class="token plain-text">+</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>button</span><span class="token punctuation">&gt;</span></span><span class="token plain-text">
      </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>button</span> <span class="token attr-name">onClick</span><span class="token script language-javascript"><span class="token script-punctuation punctuation">=</span><span class="token punctuation">{</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token arrow operator">=&gt;</span> <span class="token function">setCount</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">c</span><span class="token punctuation">)</span> <span class="token arrow operator">=&gt;</span> c <span class="token operator">-</span> <span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">}</span></span><span class="token punctuation">&gt;</span></span><span class="token plain-text">-</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>button</span><span class="token punctuation">&gt;</span></span><span class="token plain-text">
    </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>
  <span class="token punctuation">)</span>
<span class="token punctuation">}</span>
</code></pre>
<p>If you try to refresh you app right now, you'll notice that the value of the counter is still not persistent. However, if you inspect the local storage, you'll notice that <code>count</code> is being stored. Now we only need to pass the value of <code>count</code> to the counter component before it has been rendered for the first time. To do that, we'll pass the value in local storage as the initial state of <code>useState</code>.</p>
<pre class="language-jsx"><code class="language-jsx"><span class="token keyword">function</span> <span class="token function"><span class="token maybe-class-name">Counter</span></span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">const</span> storedValueAsNumber <span class="token operator">=</span> <span class="token known-class-name class-name">Number</span><span class="token punctuation">(</span><span class="token dom variable">localStorage</span><span class="token punctuation">.</span><span class="token method function property-access">getItem</span><span class="token punctuation">(</span><span class="token string">'count'</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
  <span class="token keyword">const</span> <span class="token punctuation">[</span>count<span class="token punctuation">,</span> setCount<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">useState</span><span class="token punctuation">(</span>
    <span class="token known-class-name class-name">Number</span><span class="token punctuation">.</span><span class="token method function property-access">isInteger</span><span class="token punctuation">(</span>storedValueAsNumber<span class="token punctuation">)</span> <span class="token operator">?</span> storedValueAsNumber <span class="token operator">:</span> <span class="token number">0</span><span class="token punctuation">,</span>
  <span class="token punctuation">)</span>

  <span class="token function">useEffect</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token arrow operator">=&gt;</span> <span class="token punctuation">{</span>
    <span class="token dom variable">localStorage</span><span class="token punctuation">.</span><span class="token method function property-access">setItem</span><span class="token punctuation">(</span><span class="token string">'count'</span><span class="token punctuation">,</span> <span class="token known-class-name class-name">String</span><span class="token punctuation">(</span>count<span class="token punctuation">)</span><span class="token punctuation">)</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">[</span>count<span class="token punctuation">]</span><span class="token punctuation">)</span>

  <span class="token keyword control-flow">return</span> <span class="token punctuation">(</span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span><span class="token punctuation">&gt;</span></span><span class="token plain-text">
      </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span><span class="token punctuation">&gt;</span></span><span class="token punctuation">{</span>count<span class="token punctuation">}</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span><span class="token plain-text">
      </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>button</span> <span class="token attr-name">onClick</span><span class="token script language-javascript"><span class="token script-punctuation punctuation">=</span><span class="token punctuation">{</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token arrow operator">=&gt;</span> <span class="token function">setCount</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">c</span><span class="token punctuation">)</span> <span class="token arrow operator">=&gt;</span> c <span class="token operator">+</span> <span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">}</span></span><span class="token punctuation">&gt;</span></span><span class="token plain-text">+</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>button</span><span class="token punctuation">&gt;</span></span><span class="token plain-text">
      </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>button</span> <span class="token attr-name">onClick</span><span class="token script language-javascript"><span class="token script-punctuation punctuation">=</span><span class="token punctuation">{</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token arrow operator">=&gt;</span> <span class="token function">setCount</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">c</span><span class="token punctuation">)</span> <span class="token arrow operator">=&gt;</span> c <span class="token operator">-</span> <span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">}</span></span><span class="token punctuation">&gt;</span></span><span class="token plain-text">-</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>button</span><span class="token punctuation">&gt;</span></span><span class="token plain-text">
    </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>
  <span class="token punctuation">)</span>
<span class="token punctuation">}</span>
</code></pre>
<p>Using the <code>Number</code> constructor is necessary, since an item retrieved from local storage comes as a string. Since a user can change the number persisted to the local storage to any arbitrary value, it's a good idea to check if the retrieved value is actually an integer.</p>
<h2>Considerations about this solution</h2>
<p>By using this solution, we're actually creating shared mutable state between all instances of the Counter component. This might or might not be a problem depending on the specific situation. As a rule of thumb, if we want to reuse a component across an application, this is not a good approach. However, remember to always think things through according to your current situation. <strong>No rule of thumb is better than a well done analysis of the situation that is right in front of you</strong>.</p>
<p>For this example, we used the string <code>count</code> as key for our counter value. On a real world application, we may want to use a unique ID to make sure we are not using and/or overriding any value that is being stored at the local stored. A key such as <code>count-mhvXdrZT4jP5T8vBxuvm75</code> would be appropriate.</p>
<p>As an alternative, if we don't want different instances of the Counter component to share state, we could receive the key for the local storage as a prop to the component.</p>
<h2>Give it a try</h2>
<p>Next time you're faced with having to make a React component's state persistent across a browser refresh, remember to:</p>
<ol>
<li>Analyze your current situation to check if using Local Storage together with <code>useEffect</code> hook is appropriate</li>
<li>Get a unique key to store your component state in order to avoid collisions at the Local Storage</li>
<li>Add the necessary <code>useEffect</code> hook to update your component's persisted state</li>
</ol>]]></content:encoded>
            <author>João Forja</author>
        </item>
        <item>
            <title><![CDATA[How to test a React application index.js]]></title>
            <link>https://joaoforja.com/articles/how-to-test-a-rect-app-indexjs</link>
            <guid isPermaLink="false">https://joaoforja.com/articles/how-to-test-a-rect-app-indexjs</guid>
            <pubDate>Fri, 01 May 2020 09:10:26 GMT</pubDate>
            <content:encoded><![CDATA[<blockquote>
<p>index.js keeps failing in my test coverage report</p>
</blockquote>
<p>When we start a project with <a href="https://create-react-app.dev/">Create React App</a> and set test coverage thresholds, <code>index.js</code> file
becomes a problem since it prevents us from hitting the configured thresholds.</p>
<p>We can solve this by writing the following test for <code>index.js</code> and get 100% test coverage on it.</p>
<pre class="language-jsx"><code class="language-jsx"><span class="token comment">// index.test.js</span>
<span class="token keyword module">import</span> <span class="token imports"><span class="token maybe-class-name">React</span></span> <span class="token keyword module">from</span> <span class="token string">'react'</span>
<span class="token keyword module">import</span> <span class="token imports"><span class="token maybe-class-name">ReactDOM</span></span> <span class="token keyword module">from</span> <span class="token string">'react-dom'</span>
<span class="token keyword module">import</span> <span class="token imports"><span class="token maybe-class-name">App</span></span> <span class="token keyword module">from</span> <span class="token string">'./App'</span>

<span class="token comment">// mocks react-dom and its render method</span>
<span class="token comment">// so that we can assert that render is</span>
<span class="token comment">// called with &lt;App /&gt; and HTML element with id = root</span>
jest<span class="token punctuation">.</span><span class="token method function property-access">mock</span><span class="token punctuation">(</span><span class="token string">'react-dom'</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token arrow operator">=&gt;</span> <span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token literal-property property">render</span><span class="token operator">:</span> jest<span class="token punctuation">.</span><span class="token method function property-access">fn</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">)</span>

<span class="token function">test</span><span class="token punctuation">(</span><span class="token string">'renders with App and root div'</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token arrow operator">=&gt;</span> <span class="token punctuation">{</span>
  <span class="token comment">// Create and append to document body</span>
  <span class="token comment">// an HTML element with id = root</span>
  <span class="token keyword">const</span> root <span class="token operator">=</span> <span class="token dom variable">document</span><span class="token punctuation">.</span><span class="token method function property-access">createElement</span><span class="token punctuation">(</span><span class="token string">'div'</span><span class="token punctuation">)</span>
  root<span class="token punctuation">.</span><span class="token property-access">id</span> <span class="token operator">=</span> <span class="token string">'root'</span>
  <span class="token dom variable">document</span><span class="token punctuation">.</span><span class="token property-access">body</span><span class="token punctuation">.</span><span class="token method function property-access">appendChild</span><span class="token punctuation">(</span>root<span class="token punctuation">)</span>

  <span class="token comment">// Requires index.js so that react-dom render method is called</span>
  <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'./index.js'</span><span class="token punctuation">)</span>

  <span class="token comment">// Asserts render was called with &lt;App /&gt;</span>
  <span class="token comment">// and HTML element with id = root</span>
  <span class="token function">expect</span><span class="token punctuation">(</span><span class="token maybe-class-name">ReactDOM</span><span class="token punctuation">.</span><span class="token property-access">render</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token method function property-access">toHaveBeenCalledWith</span><span class="token punctuation">(</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span><span class="token class-name">App</span></span> <span class="token punctuation">/&gt;</span></span><span class="token punctuation">,</span> root<span class="token punctuation">)</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span>
</code></pre>
<pre class="language-jsx"><code class="language-jsx"><span class="token comment">// index.js</span>
<span class="token keyword module">import</span> <span class="token imports"><span class="token maybe-class-name">React</span></span> <span class="token keyword module">from</span> <span class="token string">'react'</span>
<span class="token keyword module">import</span> <span class="token imports"><span class="token maybe-class-name">ReactDOM</span></span> <span class="token keyword module">from</span> <span class="token string">'react-dom'</span>
<span class="token keyword module">import</span> <span class="token string">'./index.css'</span>
<span class="token keyword module">import</span> <span class="token imports"><span class="token maybe-class-name">App</span></span> <span class="token keyword module">from</span> <span class="token string">'./App'</span>

<span class="token maybe-class-name">ReactDOM</span><span class="token punctuation">.</span><span class="token method function property-access">render</span><span class="token punctuation">(</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span><span class="token class-name">App</span></span> <span class="token punctuation">/&gt;</span></span><span class="token punctuation">,</span> <span class="token dom variable">document</span><span class="token punctuation">.</span><span class="token method function property-access">getElementById</span><span class="token punctuation">(</span><span class="token string">'root'</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
</code></pre>
<p>However, an important question to ask before we write a test is <em>"What are we trying to achieve with this test?"</em>.</p>
<p>When we write tests, we should write them with a clear vision of their goals, and not just for the sake of test coverage.</p>
<p>The code above tests that <code>index.js</code> does what we expect of it. But it doesn't test that the application starts, and maybe that's what we want to check.</p>
<p>To test that the application starts without problems, we can write an E2E test that asserts an element of the home page is rendered. We can use a tool like <a href="https://www.cypress.io/">Cypress</a> for that.</p>
<p>Writing the E2E test and a test specifically for <code>index.js</code> are not mutually exclusive approaches, and we should do both if that gives us more confidence that our application is working correctly. But I'd argue that since an E2E test covers 100% of <code>index.js</code> and since <code>index.js</code> is easy to understand, that writing a test just for it ends up being redundant.</p>
<p>If you end up going with only doing the E2E test, you'll need to remove <code>index.js</code> from the test coverage report. Otherwise, you won't meet the test coverage threshold. To do that, add the option below to <code>package.json</code>.</p>
<pre class="language-json"><code class="language-json"><span class="token property">"jest"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
<span class="token property">"collectCoverageFrom"</span><span class="token operator">:</span> <span class="token punctuation">[</span>
    <span class="token string">"src/**/*.{js,jsx,ts,tsx}"</span><span class="token punctuation">,</span>
    <span class="token string">"!src/index.js"</span>
  <span class="token punctuation">]</span><span class="token punctuation">,</span>
  ...
<span class="token punctuation">}</span>
</code></pre>
<h2>Put it into practice</h2>
<ol>
<li>Define what you want to test.</li>
<li>If it is that the application starts, write an E2E test, and remove <code>index.js</code> from the test coverage.</li>
<li>If it is that <code>index.js</code> does what is expected, write a targeted test like the one shown in this article.</li>
<li>If you want to test both, write the E2E test and the targeted <code>index.js</code> test.</li>
</ol>]]></content:encoded>
            <author>João Forja</author>
        </item>
        <item>
            <title><![CDATA[How to test React components that depend on route changes]]></title>
            <link>https://joaoforja.com/articles/how-to-test-react-components-route-change</link>
            <guid isPermaLink="false">https://joaoforja.com/articles/how-to-test-react-components-route-change</guid>
            <pubDate>Tue, 09 Jun 2020 10:12:03 GMT</pubDate>
            <content:encoded><![CDATA[<p>In this article, we'll go over a process to test React components that exhibit some behavior when the current route changes.</p>
<p>To illustrate the process, we'll test a component that scrolls to the top of the page whenever there's a change in the current route.</p>
<pre class="language-jsx"><code class="language-jsx"><span class="token comment">// Uses React router, Jest and react testing library</span>
<span class="token keyword">function</span> <span class="token function"><span class="token maybe-class-name">ScrollToTop</span></span><span class="token punctuation">(</span><span class="token parameter"><span class="token punctuation">{</span> children<span class="token punctuation">,</span> scrollTo <span class="token operator">=</span> <span class="token dom variable">window</span><span class="token punctuation">.</span><span class="token property-access">scrollTo</span> <span class="token punctuation">}</span></span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">const</span> prevLocation <span class="token operator">=</span> <span class="token function">useRef</span><span class="token punctuation">(</span><span class="token keyword null nil">null</span><span class="token punctuation">)</span>
  <span class="token keyword">const</span> <span class="token dom variable">location</span> <span class="token operator">=</span> <span class="token function">useLocation</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
  <span class="token function">useEffect</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token arrow operator">=&gt;</span> <span class="token punctuation">{</span>
    <span class="token keyword control-flow">if</span> <span class="token punctuation">(</span>prevLocation<span class="token punctuation">.</span><span class="token property-access">current</span> <span class="token operator">&amp;&amp;</span> <span class="token dom variable">location</span> <span class="token operator">!==</span> prevLocation<span class="token punctuation">.</span><span class="token property-access">current</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
      <span class="token function">scrollTo</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">)</span>
    <span class="token punctuation">}</span>
    <span class="token keyword control-flow">return</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token arrow operator">=&gt;</span> <span class="token punctuation">(</span>prevLocation<span class="token punctuation">.</span><span class="token property-access">current</span> <span class="token operator">=</span> <span class="token dom variable">location</span><span class="token punctuation">)</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token dom variable">location</span><span class="token punctuation">,</span> scrollTo<span class="token punctuation">]</span><span class="token punctuation">)</span>
  <span class="token keyword control-flow">return</span> children
<span class="token punctuation">}</span>
<span class="token comment">// NOTE: This implementation serves the purpose of supporting this article.</span>
<span class="token comment">// It doesn't have production concerns in mind.</span>
</code></pre>
<p>To test the code above, we'll have to figure out how to simulate a change in the current route. We could try to mock <code>useLocation</code> and return different values each time we call it, but this approach exposes to our test that we use the <code>useLocation</code> hook. This means that if we refactor <code>ScrollToTop</code> not to use <code>useLocation</code>, our tests will break. A more robust way to write this test is to recreate the environment in which <code>ScrollToTop</code> will be used and trigger a route change similarly to how a user would.</p>
<p>For our test, we'll start by wrapping <code>ScrollToTop</code> in a Router and have it render two routes. The first route will have a link that points to the second route, and the second route will have some text. Then we'll simulate a click on the link of the first route and wait for the text on the second route to appear. After that, all that's left is to assert that we've scrolled to the top of the page.</p>
<p>To assert we've scrolled to the top of the page, we'll mock the <code>scrollTo</code> function and check that we called it with the coordinates that correspond to the top of the page. You might be wondering if this approach has the same issues that mocking <code>useLocation</code> had. The answer is that it does, but we don't have a better option. Since Jest uses JSDOM to simulate a browser, and since JSDOM doesn't implement <code>window.scrollTo</code> the best we can do in this environment is to mock <code>scrollTo</code> and confirm we're calling it correctly.</p>
<p>This approach results in the test bellow.</p>
<pre class="language-jsx"><code class="language-jsx"><span class="token function">test</span><span class="token punctuation">(</span><span class="token string">'Scrolls to top of page when route changes'</span><span class="token punctuation">,</span> <span class="token keyword">async</span> <span class="token keyword">function</span> <span class="token function">test</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">const</span> scrollTo <span class="token operator">=</span> jest<span class="token punctuation">.</span><span class="token method function property-access">fn</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
  <span class="token function">render</span><span class="token punctuation">(</span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span><span class="token class-name">MemoryRouter</span></span> <span class="token attr-name">initialEntries</span><span class="token script language-javascript"><span class="token script-punctuation punctuation">=</span><span class="token punctuation">{</span><span class="token punctuation">[</span><span class="token string">'/'</span><span class="token punctuation">]</span><span class="token punctuation">}</span></span><span class="token punctuation">&gt;</span></span><span class="token plain-text">
      </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span><span class="token class-name">ScrollToTop</span></span> <span class="token attr-name">scrollTo</span><span class="token script language-javascript"><span class="token script-punctuation punctuation">=</span><span class="token punctuation">{</span>scrollTo<span class="token punctuation">}</span></span><span class="token punctuation">&gt;</span></span><span class="token plain-text">
        </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span><span class="token class-name">Route</span></span> <span class="token attr-name">exact</span> <span class="token attr-name">path</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>/<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span><span class="token plain-text">
          </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span><span class="token class-name">Link</span></span> <span class="token attr-name">to</span><span class="token script language-javascript"><span class="token script-punctuation punctuation">=</span><span class="token punctuation">{</span><span class="token string">'/other'</span><span class="token punctuation">}</span></span><span class="token punctuation">&gt;</span></span><span class="token plain-text">Change route</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span><span class="token class-name">Link</span></span><span class="token punctuation">&gt;</span></span><span class="token plain-text">
        </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span><span class="token class-name">Route</span></span><span class="token punctuation">&gt;</span></span><span class="token plain-text">
        </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span><span class="token class-name">Route</span></span> <span class="token attr-name">exact</span> <span class="token attr-name">path</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>/other<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span><span class="token plain-text">
          </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>p</span><span class="token punctuation">&gt;</span></span><span class="token plain-text">Other route</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>p</span><span class="token punctuation">&gt;</span></span><span class="token plain-text">
        </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span><span class="token class-name">Route</span></span><span class="token punctuation">&gt;</span></span><span class="token plain-text">
      </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span><span class="token class-name">ScrollToTop</span></span><span class="token punctuation">&gt;</span></span><span class="token plain-text">
    </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span><span class="token class-name">MemoryRouter</span></span><span class="token punctuation">&gt;</span></span><span class="token punctuation">,</span>
  <span class="token punctuation">)</span>
  fireEvent<span class="token punctuation">.</span><span class="token method function property-access">click</span><span class="token punctuation">(</span>screen<span class="token punctuation">.</span><span class="token method function property-access">getByText</span><span class="token punctuation">(</span><span class="token string">'Change route'</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
  <span class="token keyword control-flow">await</span> screen<span class="token punctuation">.</span><span class="token method function property-access">findByText</span><span class="token punctuation">(</span><span class="token string">'Other route'</span><span class="token punctuation">)</span>

  <span class="token function">expect</span><span class="token punctuation">(</span>scrollTo<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token method function property-access">toHaveBeenCalledTimes</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span>
  <span class="token function">expect</span><span class="token punctuation">(</span>scrollTo<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token method function property-access">toHaveBeenLastCalledWith</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">)</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span>
</code></pre>
<h2>Put it into practice</h2>
<p>We can look at the work we did to test <code>ScrollToTop</code> as the following 4 step process:</p>
<ol>
<li>Recreate a routing environment similar to that in which the component will be used.</li>
<li>Perform an action that causes navigation between routes.</li>
<li>Assert that the navigation was done.</li>
<li>Assert the component under test behaved as expected.</li>
</ol>
<p>Next time you have to test a component that exhibits some behavior when a route changes, try the steps above.</p>
<h2>Exercise: test component that shows an alert when routes change</h2>
<p>Try to use the process delineated in this article to test the following component that creates an alert with the message
"Hello world!" when there's a change in the current route.</p>
<pre class="language-jsx"><code class="language-jsx"><span class="token keyword">function</span> <span class="token function"><span class="token maybe-class-name">AlertOnRouteChange</span></span><span class="token punctuation">(</span><span class="token parameter"><span class="token punctuation">{</span> children<span class="token punctuation">,</span> message<span class="token punctuation">,</span> alert <span class="token operator">=</span> <span class="token dom variable">window</span><span class="token punctuation">.</span><span class="token property-access">alert</span> <span class="token punctuation">}</span></span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">const</span> prevLocation <span class="token operator">=</span> <span class="token function">useRef</span><span class="token punctuation">(</span><span class="token keyword null nil">null</span><span class="token punctuation">)</span>
  <span class="token keyword">const</span> <span class="token dom variable">location</span> <span class="token operator">=</span> <span class="token function">useLocation</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
  <span class="token function">useEffect</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token arrow operator">=&gt;</span> <span class="token punctuation">{</span>
    <span class="token keyword control-flow">if</span> <span class="token punctuation">(</span>prevLocation<span class="token punctuation">.</span><span class="token property-access">current</span> <span class="token operator">&amp;&amp;</span> <span class="token dom variable">location</span> <span class="token operator">!==</span> prevLocation<span class="token punctuation">.</span><span class="token property-access">current</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
      <span class="token function">alert</span><span class="token punctuation">(</span><span class="token string">'Hello world!'</span><span class="token punctuation">)</span>
    <span class="token punctuation">}</span>
    <span class="token keyword control-flow">return</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token arrow operator">=&gt;</span> <span class="token punctuation">(</span>prevLocation<span class="token punctuation">.</span><span class="token property-access">current</span> <span class="token operator">=</span> <span class="token dom variable">location</span><span class="token punctuation">)</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">[</span>alert<span class="token punctuation">,</span> <span class="token dom variable">location</span><span class="token punctuation">]</span><span class="token punctuation">)</span>
  <span class="token keyword control-flow">return</span> children
<span class="token punctuation">}</span>
</code></pre>
<details><summary>Solution</summary><pre class="language-jsx"><code class="language-jsx"><span class="token function">test</span><span class="token punctuation">(</span><span class="token string">'Alerts when route changes'</span><span class="token punctuation">,</span> <span class="token keyword">async</span> <span class="token keyword">function</span> <span class="token function">test</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">const</span> alert <span class="token operator">=</span> jest<span class="token punctuation">.</span><span class="token method function property-access">fn</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
  <span class="token function">render</span><span class="token punctuation">(</span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span><span class="token class-name">MemoryRouter</span></span> <span class="token attr-name">initialEntries</span><span class="token script language-javascript"><span class="token script-punctuation punctuation">=</span><span class="token punctuation">{</span><span class="token punctuation">[</span><span class="token string">'/'</span><span class="token punctuation">]</span><span class="token punctuation">}</span></span><span class="token punctuation">&gt;</span></span><span class="token plain-text">
      </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span><span class="token class-name">AlertOnRouteChange</span></span> <span class="token attr-name">alert</span><span class="token script language-javascript"><span class="token script-punctuation punctuation">=</span><span class="token punctuation">{</span>alert<span class="token punctuation">}</span></span><span class="token punctuation">&gt;</span></span><span class="token plain-text">
        </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span><span class="token class-name">Route</span></span> <span class="token attr-name">exact</span> <span class="token attr-name">path</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>/<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span><span class="token plain-text">
          </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span><span class="token class-name">Link</span></span> <span class="token attr-name">to</span><span class="token script language-javascript"><span class="token script-punctuation punctuation">=</span><span class="token punctuation">{</span><span class="token string">'/other'</span><span class="token punctuation">}</span></span><span class="token punctuation">&gt;</span></span><span class="token plain-text">Change route</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span><span class="token class-name">Link</span></span><span class="token punctuation">&gt;</span></span><span class="token plain-text">
        </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span><span class="token class-name">Route</span></span><span class="token punctuation">&gt;</span></span><span class="token plain-text">
        </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span><span class="token class-name">Route</span></span> <span class="token attr-name">exact</span> <span class="token attr-name">path</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>/other<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span><span class="token plain-text">
          </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>p</span><span class="token punctuation">&gt;</span></span><span class="token plain-text">Other route</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>p</span><span class="token punctuation">&gt;</span></span><span class="token plain-text">
        </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span><span class="token class-name">Route</span></span><span class="token punctuation">&gt;</span></span><span class="token plain-text">
      </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span><span class="token class-name">AlertOnRouteChange</span></span><span class="token punctuation">&gt;</span></span><span class="token plain-text">
    </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span><span class="token class-name">MemoryRouter</span></span><span class="token punctuation">&gt;</span></span><span class="token punctuation">,</span>
  <span class="token punctuation">)</span>
  fireEvent<span class="token punctuation">.</span><span class="token method function property-access">click</span><span class="token punctuation">(</span>screen<span class="token punctuation">.</span><span class="token method function property-access">getByText</span><span class="token punctuation">(</span><span class="token string">'Change route'</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
  <span class="token keyword control-flow">await</span> screen<span class="token punctuation">.</span><span class="token method function property-access">findByText</span><span class="token punctuation">(</span><span class="token string">'Other route'</span><span class="token punctuation">)</span>

  <span class="token function">expect</span><span class="token punctuation">(</span>alert<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token method function property-access">toHaveBeenCalledTimes</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span>
  <span class="token function">expect</span><span class="token punctuation">(</span>alert<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token method function property-access">toHaveBeenLastCalledWith</span><span class="token punctuation">(</span><span class="token string">'Hello world!'</span><span class="token punctuation">)</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span>
</code></pre></details>]]></content:encoded>
            <author>João Forja</author>
        </item>
        <item>
            <title><![CDATA[Thought process for testing a React application.]]></title>
            <link>https://joaoforja.com/articles/how-to-write-tests-react-app-case-study</link>
            <guid isPermaLink="false">https://joaoforja.com/articles/how-to-write-tests-react-app-case-study</guid>
            <pubDate>Sun, 24 May 2020 22:00:03 GMT</pubDate>
            <content:encoded><![CDATA[<blockquote>
<p>What concerns should I have when writing tests?</p>
</blockquote>
<p>In this article, we'll go over the thought process for testing and implementing a React application that will fetch data from an API and display it. While this is a relatively simple application, it is enough for us to go over some key topics like:</p>
<ol>
<li>Preparation before writing tests</li>
<li>Defining boundaries for testing</li>
<li>Mocking</li>
</ol>
<h2>What we'll be testing and implementing</h2>
<p>Here's a <a href="https://jnforja.github.io/case-study-testing-react/">demo</a> of what we'll be building. As you can see, we'll be testing and implementing an application that shows Rick and Morty characters. The characters' information will come from <a href="https://rickandmortyapi.com/">Rick and Morty API</a>.</p>
<p>It's important to mention that before working on an application or feature, it helps to write a test list. By making a test list, we'll have a starting point to write our tests. In a <a href="/articles/learn-how-to-make-a-test-list/">previous article</a>, I went over the process to make a test list, so give if you want to know more.</p>
<p>We'll use the following test list to get us started:</p>
<ol>
<li>Shows an empty message when there aren't characters</li>
<li>Shows one character with expected info</li>
<li>Shows three characters, each with the expected info</li>
<li>Shows an error message when there was an error getting characters</li>
</ol>
<p>However, before we pick a test to implement, there are some ideas we need to go over to make the process easier.</p>
<h2>It's hard to make tests for production code we have no idea how to write</h2>
<p>If we have no idea how to write the production code, writing tests for it will be hard. So before trying to implement something, it's helpful to have some familiarity with the tools and services we'll be using and have a rough idea of how to use them to solve the problem we have at hand. Otherwise, when we're writing tests, it will be hard to define the boundaries for our tests, and when a test fails, we won't know if the problem is in the tests or the production code.</p>
<p>In situations where we're not familiar with a service or a library, we can create a test and use it as a REPL to make requests to the service or try out the library. For situations where we're exploring libraries that manipulate the DOM, we can try them out by writing a component and rendering it in the browser.</p>
<p>For this application, the only thing we're probably not familiar with is the <a href="https://rickandmortyapi.com/">Rick and Morty API</a>. So before starting, we'd make a couple of requests to get an idea of how it works.</p>
<h2>Small steps make tests and production code easier to write</h2>
<p>An excellent way to have analysis paralysis is to try to solve too much at once. This is also true for building applications with automated tests. If the test we choose to start with will require a lot of production code to pass, we'll have an unnecessarily complicated time.</p>
<p>The key here is to start with a simple test that is simple to write and simple to make the production code for it to pass. This heuristic usually makes us take small enough steps that allow us to tackle one problem at a time.</p>
<p>One of the critical things to keep in mind while taking small steps is to focus on the current step and forget the others. For example, if we are working on showing an empty message when there aren't characters, we do not worry about showing an error message when there's an error getting characters from the server. We first make the test and production code for the empty message case, and then we make the necessary changes to show an error message when there's an error.</p>
<p>It's particularly important to start small on the first test. We may not realize it, but on that first test, we'll have to make a lot of decisions regarding the design of the module we're building as well as how we are going to test it. It's helpful to start with a simple test not to make our task more complicated than it needs to be.</p>
<p>In situations where no test out of the test list is simple enough, we'll likely be able to decompose those tests into simpler ones. In case we end up producing test cases that are so simple that they don't provide any documentation value or are redundant due to other more complicated tests we end up writing, we can always delete them.</p>
<h2>Picking the first test</h2>
<p>Out of the test list, the tests that seem more simple are:</p>
<ol>
<li>Shows an empty message when there aren't characters</li>
<li>Shows an error message when there was an error getting characters</li>
</ol>
<p>To make those tests pass, we only need to render a message to the screen, so the production code is reasonably straightforward. Given both tests are good places to start, we'll just pick the first one.</p>
<h2>Defining the boundaries we'll use to test the behavior</h2>
<p>To write this first test, we'll have to decide the boundaries we'll use to test the application shows an empty message when the list is empty. In other words, we have to determine the module or component that we will interact with to check the behavior we want to test and implement. Should we test it from a component dedicated to rendering characters, something like <code>&lt;Characters/&gt;</code>? Or should we test it through somewhere else?</p>
<p>Different people will have different answers to the question above. But one approach that's been working well for me when building web applications is to start from the user perspective. As the tests become too complex and difficult to write, I begin to isolate the behaviors I want to test and test them more directly. Following this approach means that we usually start writing from the page the user would access to use a feature.</p>
<p>What's good about starting from the user perspective and then isolating behavior to reduce complexity in the tests, is that it gives a nice balance between tests that aren't too sensitive to changes in the code structure and tests that aren't too far away from the behavior we're interested in. In other words, it strikes a balance between tests that won't break on every refactor and tests that are straightforward to read and write.</p>
<p>Following the strategy above, we would place the boundary of interaction between tests and production code at the component that represents the page where the Rick and Morty characters will be. Something like <code>&lt;RickAndMortyCharactersPage/&gt;</code>.</p>
<h2>Passing the characters to the page component</h2>
<p>The next decision we have to make is how is <code>&lt;RickAndMortyCharactersPage/&gt;</code> going to have access to the character's data. We know that the characters will come from the <a href="https://rickandmortyapi.com/">Rick and Morty API</a>, and we also know that we don't have control over the behavior of the API. For example, we can't force it to give an error response. This means that we won't be able to create the situations we want to test if we're using the real Rick and Morty API in our tests.</p>
<p>One approach to deal with not controlling the responses from the Rick and Morty API is to mock the interaction with the API. This way, it becomes easy to simulate the situations we want to test. But how exactly should we do it? Should we use something like <a href="https://miragejs.com/">MirageJS</a> to simulate a server? Should we mock the HTTP client module?</p>
<p>Either making a fake server or mocking the HTTP client would solve the issue of simulating the situation we want to test. However, both approaches force our tests to deal with the details of HTTP interactions. In other words, we would need to do quite a bit of setup to test that given an empty list of characters, we show the right message.</p>
<p>The issue with tests that have complicated setups is that they tend to be hard to write and hard to read. One approach to this problem is to create a function that wraps the HTTP interaction to get the characters and have <code>&lt;RickAndMortyCharactersPage/&gt;</code> use it. Now we can have whichever response we need for our tests just by mocking the new wrapper function. The signature of the wrapper function would look something like this:</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">async</span> <span class="token keyword">function</span> <span class="token function">fetchCharactersFromServer</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token comment">// Makes request to API and returns characters</span>
<span class="token punctuation">}</span>
</code></pre>
<h3>Making the assertion</h3>
<p>From the behavior standpoint, what we want to assert is that when the list of characters is empty, we render a message saying that there aren't characters. So we'll have to search the DOM for the expected message. We also have to keep in mind that fetching the characters from the server is an asynchronous operation, so we'll have to wait for the message to appear.</p>
<p>Dealing with the asynchronous nature of fetching data in this test made me realize that we hadn't written in our test list that we should show the user a loading message while he's waiting for the response with the characters. So at this point, we should add that test to the list.</p>
<p>Taking into account all that we've gone over so far, the test would look like this:</p>
<pre class="language-jsx"><code class="language-jsx"><span class="token function">test</span><span class="token punctuation">(</span><span class="token string">"Shows empty message when there aren't characters"</span><span class="token punctuation">,</span> <span class="token keyword">async</span> <span class="token keyword">function</span> <span class="token function">test</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">const</span> fetchCharacters <span class="token operator">=</span> jest<span class="token punctuation">.</span><span class="token method function property-access">fn</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token method function property-access">mockResolvedValueOnce</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">)</span>
  <span class="token function">render</span><span class="token punctuation">(</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span><span class="token class-name">RickAndMortyCharactersPage</span></span> <span class="token attr-name">fetchCharacters</span><span class="token script language-javascript"><span class="token script-punctuation punctuation">=</span><span class="token punctuation">{</span>fetchCharacters<span class="token punctuation">}</span></span> <span class="token punctuation">/&gt;</span></span><span class="token punctuation">)</span>
  <span class="token function">expect</span><span class="token punctuation">(</span>
    <span class="token keyword control-flow">await</span> screen<span class="token punctuation">.</span><span class="token method function property-access">findByText</span><span class="token punctuation">(</span><span class="token string">"There aren't characters to show"</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
  <span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token method function property-access">toBeVisible</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span>
</code></pre>
<p>But there's one assertion that we're missing in the test above.</p>
<h2>Test interactions when using mocks</h2>
<p>Whenever we use a mock function, like we just used for our test, we need to make sure that the code under test is calling the mocked function as we intend it to call the real function. We'll also need to make sure that the real version of the function behaves like the mocked version. These kinds of assertions are testing the interactions between modules. It's crucial to test interactions when using mocks since failed interactions give origin to the problem of units that work in isolation but fail to work as a whole.</p>
<p>This means that when we are using mocks, in addition to our tests going over behavior the user can observe, our tests will also cover the interactions between different modules. It's essential to keep those two roles of tests in mind. Otherwise, we'll lose track of what we're trying to test, which leads to frustration when we're trying to write tests.</p>
<p>What this approach means for our test, is it that we'll need to assert that we're calling <code>fetchCharactersFromServer</code> with the expected arguments.</p>
<pre class="language-jsx"><code class="language-jsx"><span class="token function">test</span><span class="token punctuation">(</span><span class="token string">"Shows empty message when there aren't characters"</span><span class="token punctuation">,</span> <span class="token keyword">async</span> <span class="token keyword">function</span> <span class="token function">test</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">const</span> fetchCharacters <span class="token operator">=</span> jest<span class="token punctuation">.</span><span class="token method function property-access">fn</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token method function property-access">mockResolvedValueOnce</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">)</span>
  <span class="token function">render</span><span class="token punctuation">(</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span><span class="token class-name">RickAndMortyCharactersPage</span></span> <span class="token attr-name">fetchCharacters</span><span class="token script language-javascript"><span class="token script-punctuation punctuation">=</span><span class="token punctuation">{</span>fetchCharacters<span class="token punctuation">}</span></span> <span class="token punctuation">/&gt;</span></span><span class="token punctuation">)</span>
  <span class="token function">expect</span><span class="token punctuation">(</span>
    <span class="token keyword control-flow">await</span> screen<span class="token punctuation">.</span><span class="token method function property-access">findByText</span><span class="token punctuation">(</span><span class="token string">"There aren't characters to show"</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
  <span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token method function property-access">toBeVisible</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
  <span class="token function">expect</span><span class="token punctuation">(</span>fetchCharacters<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token method function property-access">toHaveBeenCalledWith</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span>
</code></pre>
<p>When we get to testing the <code>fetchCharactersFromServer</code>, we'll need to write a test for it that proves it can return a Promise with an array when things go well. But more on that later in the article.</p>
<h2>A look at the code after making the first test pass</h2>
<p>After writing this first test and the production code to make it pass, we ended up with this:</p>
<pre class="language-jsx"><code class="language-jsx"><span class="token function">test</span><span class="token punctuation">(</span><span class="token string">"Shows empty message when there aren't characters"</span><span class="token punctuation">,</span> <span class="token keyword">async</span> <span class="token keyword">function</span> <span class="token function">test</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">const</span> fetchCharacters <span class="token operator">=</span> jest<span class="token punctuation">.</span><span class="token method function property-access">fn</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token method function property-access">mockResolvedValueOnce</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">)</span>
  <span class="token function">render</span><span class="token punctuation">(</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span><span class="token class-name">RickAndMortyCharactersPage</span></span> <span class="token attr-name">fetchCharacters</span><span class="token script language-javascript"><span class="token script-punctuation punctuation">=</span><span class="token punctuation">{</span>fetchCharacters<span class="token punctuation">}</span></span> <span class="token punctuation">/&gt;</span></span><span class="token punctuation">)</span>
  <span class="token function">expect</span><span class="token punctuation">(</span>
    <span class="token keyword control-flow">await</span> screen<span class="token punctuation">.</span><span class="token method function property-access">findByText</span><span class="token punctuation">(</span><span class="token string">"There aren't characters to show"</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
  <span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token method function property-access">toBeVisible</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
  <span class="token function">expect</span><span class="token punctuation">(</span>fetchCharacters<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token method function property-access">toHaveBeenCalledWith</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span>

<span class="token keyword">function</span> <span class="token function"><span class="token maybe-class-name">RickAndMortyCharactersPage</span></span><span class="token punctuation">(</span><span class="token parameter"><span class="token punctuation">{</span> fetchCharacters <span class="token punctuation">}</span></span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token function">useEffect</span><span class="token punctuation">(</span>
    <span class="token keyword">function</span> <span class="token function">fetchCharactersOnStart</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
      <span class="token function">fetchCharacters</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token punctuation">[</span>fetchCharacters<span class="token punctuation">]</span><span class="token punctuation">,</span>
  <span class="token punctuation">)</span>
  <span class="token keyword control-flow">return</span> <span class="token punctuation">(</span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span><span class="token punctuation">&gt;</span></span><span class="token plain-text">
      </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>p</span><span class="token punctuation">&gt;</span></span><span class="token plain-text">There aren't characters to show</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>p</span><span class="token punctuation">&gt;</span></span><span class="token plain-text">
    </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>
  <span class="token punctuation">)</span>
<span class="token punctuation">}</span>
</code></pre>
<p>Notice that there is only enough production code to make the tests pass. This is a crucial aspect of taking small steps that allow us to focus on the current task.</p>
<p>As we write more tests, the production will change to make the new tests pass, but since we have the older tests in place, we can have confidence that we haven't broken anything.</p>
<h2>The remaining tests from the test list</h2>
<p>After all the work we had to define the boundaries to test our code during the first test, the remaining tests from the test list are very straightforward. So I'll just highlight some interesting points from them, and we'll go straight into testing the code that fetches data from the server.</p>
<h3>Testing for errors is simple</h3>
<p>Since we decided to wrap in a function the HTTP call to get characters, we can now easily test error situations by having the promise returned from the mock function reject.</p>
<pre class="language-jsx"><code class="language-jsx"><span class="token function">test</span><span class="token punctuation">(</span><span class="token string">"shows error message when there's an error fetching characters"</span><span class="token punctuation">,</span> <span class="token keyword">async</span> <span class="token keyword">function</span> <span class="token function">test</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">const</span> fetchCharacters <span class="token operator">=</span> jest<span class="token punctuation">.</span><span class="token method function property-access">fn</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token method function property-access">mockRejectedValueOnce</span><span class="token punctuation">(</span><span class="token keyword">new</span> <span class="token class-name">Error</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
  <span class="token function">render</span><span class="token punctuation">(</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span><span class="token class-name">RickAndMortyCharactersPage</span></span> <span class="token attr-name">fetchCharacters</span><span class="token script language-javascript"><span class="token script-punctuation punctuation">=</span><span class="token punctuation">{</span>fetchCharacters<span class="token punctuation">}</span></span> <span class="token punctuation">/&gt;</span></span><span class="token punctuation">)</span>
  <span class="token function">expect</span><span class="token punctuation">(</span>
    <span class="token keyword control-flow">await</span> screen<span class="token punctuation">.</span><span class="token method function property-access">findByText</span><span class="token punctuation">(</span><span class="token string">'There was an error. Please reload page.'</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
  <span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token method function property-access">toBeVisible</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
  <span class="token function">expect</span><span class="token punctuation">(</span>fetchCharacters<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token method function property-access">toHaveBeenCalledWith</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span>
</code></pre>
<p>Since our application doesn't distinguish between errors, we only have a single error test case. But with this approach, testing for other errors would be as simple as changing the error we use when rejecting the promise.</p>
<h3>Only the necessary data for the tests</h3>
<p>When we wrapped the HTTP call to get the characters, we added a layer of abstraction between the code that renders what we want to show to the user, and the code that fetches the characters. This abstraction layer gives us the flexibility to model the data returned from the server into something that perfectly fits what the view code needs. The results are easier to read and easier to write tests, since the amount of data not relevant to what we're testing, is low.</p>
<pre class="language-jsx"><code class="language-jsx"><span class="token function">test</span><span class="token punctuation">(</span><span class="token string">'Shows 1 character'</span><span class="token punctuation">,</span> <span class="token keyword">async</span> <span class="token keyword">function</span> <span class="token function">test</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">const</span> armorthy <span class="token operator">=</span> <span class="token punctuation">{</span>
    <span class="token literal-property property">id</span><span class="token operator">:</span> <span class="token number">25</span><span class="token punctuation">,</span>
    <span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">'Armorthy'</span><span class="token punctuation">,</span>
    <span class="token literal-property property">status</span><span class="token operator">:</span> <span class="token string">'Dead'</span><span class="token punctuation">,</span>
    <span class="token literal-property property">species</span><span class="token operator">:</span> <span class="token string">'unknown'</span><span class="token punctuation">,</span>
    <span class="token literal-property property">gender</span><span class="token operator">:</span> <span class="token string">'male'</span><span class="token punctuation">,</span>
    <span class="token literal-property property">image</span><span class="token operator">:</span> <span class="token string">'/mockArmorthyImageUrl'</span><span class="token punctuation">,</span>
  <span class="token punctuation">}</span>
  <span class="token keyword">const</span> fetchCharacters <span class="token operator">=</span> jest<span class="token punctuation">.</span><span class="token method function property-access">fn</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token method function property-access">mockResolvedValueOnce</span><span class="token punctuation">(</span><span class="token punctuation">[</span>armorthy<span class="token punctuation">]</span><span class="token punctuation">)</span>
  <span class="token function">render</span><span class="token punctuation">(</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span><span class="token class-name">RickAndMortyCharactersPage</span></span> <span class="token attr-name">fetchCharacters</span><span class="token script language-javascript"><span class="token script-punctuation punctuation">=</span><span class="token punctuation">{</span>fetchCharacters<span class="token punctuation">}</span></span> <span class="token punctuation">/&gt;</span></span><span class="token punctuation">)</span>

  <span class="token keyword control-flow">await</span> <span class="token function">assertCharacterIsVisible</span><span class="token punctuation">(</span>armorthy<span class="token punctuation">)</span>
  <span class="token function">expect</span><span class="token punctuation">(</span>fetchCharacters<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token method function property-access">toHaveBeenCalledWith</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span>
</code></pre>
<h2>Testing we can get characters from the server</h2>
<p>The tests for fetching characters come in two parts. The first one is making sure the function <code>fetchCharactersFromServer</code> behaves as expected, and the second one that it interacts correctly with the server.</p>
<h3>Making sure the module behaves as described</h3>
<p>Since we have mocked out the function that fetches characters from the server, we now need to write tests that assert the real function behaves in a way that is compatible with how the mocked function behaves. This is important to make sure that <code>fetchCharactersFromServer</code> and <code>&lt;RickAndMortyCharactersPage/&gt;</code> will work well together.</p>
<p>By looking at the code from the previous tests, we can get an idea of the assertions we'll need to write.</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token comment">// Defines how function should behave when there's an error</span>
<span class="token keyword">const</span> fetchCharacters <span class="token operator">=</span> jest<span class="token punctuation">.</span><span class="token method function property-access">fn</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token method function property-access">mockRejectedValueOnce</span><span class="token punctuation">(</span><span class="token keyword">new</span> <span class="token class-name">Error</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
<span class="token comment">// Defines how function should behave when all goes well</span>
<span class="token keyword">const</span> characters <span class="token operator">=</span> <span class="token punctuation">[</span>
  <span class="token punctuation">{</span>
    <span class="token literal-property property">id</span><span class="token operator">:</span> <span class="token number">25</span><span class="token punctuation">,</span>
    <span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">'Armorthy'</span><span class="token punctuation">,</span>
    <span class="token literal-property property">status</span><span class="token operator">:</span> <span class="token string">'Dead'</span><span class="token punctuation">,</span>
    <span class="token literal-property property">species</span><span class="token operator">:</span> <span class="token string">'unknown'</span><span class="token punctuation">,</span>
    <span class="token literal-property property">gender</span><span class="token operator">:</span> <span class="token string">'male'</span><span class="token punctuation">,</span>
    <span class="token literal-property property">image</span><span class="token operator">:</span> <span class="token string">'/mockArmorthyImageUrl'</span><span class="token punctuation">,</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span>
  <span class="token comment">// more characters...</span>
<span class="token punctuation">]</span>
<span class="token keyword">const</span> fetchCharacters <span class="token operator">=</span> jest<span class="token punctuation">.</span><span class="token method function property-access">fn</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token method function property-access">mockResolvedValueOnce</span><span class="token punctuation">(</span>characters<span class="token punctuation">)</span>
</code></pre>
<p>From looking at the code above, we know that we'll have to assert that<code>fetchCharactersFromServer</code> rejects a promise when something goes wrong, and that it returns an array with characters when things go right. The structure of the characters should be compatible with what the code above specified, of course.</p>
<h3>Interacting with the server</h3>
<p>The logic for testing the interaction between <code>fetchCharactersFromServer</code> and the server, is the same we used when we decided to mock the <code>fetchCharactersFromServer</code> on the previous tests. Since we have no control over the server's responses, we'll mock it out for our tests. But given the server API is already established, we'll need to make sure that our mock behaves as the server would and that we're making the HTTP request as the server expects.</p>
<p>In this article, we've previously talked about two options to mock the server: simulating a server using a library like <a href="https://miragejs.com/">MirageJS</a>, or mock the HTTP client. Since mocking the HTTP client will make our code break if we decide to change the client, and we don't get any significant benefits from doing so, we'll write the tests for <code>fetchCharactersFromServer</code> using MirageJS.</p>
<p>A straightforward way to bring the behavior of the fake server close to the real server is to make manual requests to the real server and observe the headers necessary to make the request, as well as the format of the response. Then on the fake server, we can check if the required headers are present and make it return a response with the same structure as the real server would.</p>
<p>In situations where we have access to the code of the server, looking at tests against the endpoints can give a helpful idea of the behavior we have to replicate.</p>
<p>Following what we've just talked, we end up writing the tests below:</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword module">import</span> <span class="token imports"><span class="token punctuation">{</span> <span class="token maybe-class-name">Server</span><span class="token punctuation">,</span> <span class="token maybe-class-name">Response</span> <span class="token punctuation">}</span></span> <span class="token keyword module">from</span> <span class="token string">'miragejs'</span>
<span class="token keyword module">import</span> <span class="token imports">charactersApiResponse</span> <span class="token keyword module">from</span> <span class="token string">'./characters-api-response.json'</span>
<span class="token keyword module">import</span> <span class="token imports"><span class="token punctuation">{</span> fetchCharactersFromServer <span class="token punctuation">}</span></span> <span class="token keyword module">from</span> <span class="token string">'../RickAndMortyCharacters'</span>

<span class="token function">test</span><span class="token punctuation">(</span><span class="token string">'On error fetching characters, rejects promise'</span><span class="token punctuation">,</span> <span class="token keyword">async</span> <span class="token keyword">function</span> <span class="token function">test</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">const</span> server <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Server</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
    <span class="token literal-property property">environment</span><span class="token operator">:</span> <span class="token string">'test'</span><span class="token punctuation">,</span>
    <span class="token function">routes</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
      <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token property-access">urlPrefix</span> <span class="token operator">=</span> <span class="token string">'https://rickandmortyapi.com'</span>
      <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token method function property-access">get</span><span class="token punctuation">(</span><span class="token string">'/api/character/'</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token arrow operator">=&gt;</span> <span class="token punctuation">{</span>
        <span class="token keyword control-flow">return</span> <span class="token keyword">new</span> <span class="token class-name">Response</span><span class="token punctuation">(</span><span class="token number">500</span><span class="token punctuation">)</span>
      <span class="token punctuation">}</span><span class="token punctuation">)</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
  <span class="token punctuation">}</span><span class="token punctuation">)</span>

  <span class="token keyword control-flow">await</span> <span class="token function">expect</span><span class="token punctuation">(</span><span class="token function">fetchCharactersFromServer</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token property-access">rejects</span><span class="token punctuation">.</span><span class="token method function property-access">toEqual</span><span class="token punctuation">(</span><span class="token keyword nil">undefined</span><span class="token punctuation">)</span>

  server<span class="token punctuation">.</span><span class="token method function property-access">shutdown</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span>

<span class="token function">test</span><span class="token punctuation">(</span><span class="token string">'On success fetching characters, returns them'</span><span class="token punctuation">,</span> <span class="token keyword">async</span> <span class="token keyword">function</span> <span class="token function">test</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">const</span> server <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Server</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
    <span class="token literal-property property">environment</span><span class="token operator">:</span> <span class="token string">'test'</span><span class="token punctuation">,</span>
    <span class="token function">routes</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
      <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token property-access">urlPrefix</span> <span class="token operator">=</span> <span class="token string">'https://rickandmortyapi.com'</span>
      <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token method function property-access">get</span><span class="token punctuation">(</span><span class="token string">'/api/character/'</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token arrow operator">=&gt;</span> <span class="token punctuation">{</span>
        <span class="token keyword control-flow">return</span> charactersApiResponse
      <span class="token punctuation">}</span><span class="token punctuation">)</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
  <span class="token punctuation">}</span><span class="token punctuation">)</span>

  <span class="token keyword">const</span> characters <span class="token operator">=</span> <span class="token keyword control-flow">await</span> <span class="token function">fetchCharactersFromServer</span><span class="token punctuation">(</span><span class="token punctuation">)</span>

  <span class="token function">expect</span><span class="token punctuation">(</span>characters<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token method function property-access">toMatchObject</span><span class="token punctuation">(</span><span class="token punctuation">[</span>
    <span class="token punctuation">{</span>
      <span class="token literal-property property">id</span><span class="token operator">:</span> <span class="token number">1</span><span class="token punctuation">,</span>
      <span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">'Rick Sanchez'</span><span class="token punctuation">,</span>
      <span class="token literal-property property">status</span><span class="token operator">:</span> <span class="token string">'Alive'</span><span class="token punctuation">,</span>
      <span class="token literal-property property">species</span><span class="token operator">:</span> <span class="token string">'Human'</span><span class="token punctuation">,</span>
      <span class="token literal-property property">gender</span><span class="token operator">:</span> <span class="token string">'Male'</span><span class="token punctuation">,</span>
      <span class="token literal-property property">image</span><span class="token operator">:</span> <span class="token string">'https://rickandmortyapi.com/api/character/avatar/1.jpeg'</span><span class="token punctuation">,</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token comment">// more characters...</span>
  <span class="token punctuation">]</span><span class="token punctuation">)</span>
  server<span class="token punctuation">.</span><span class="token method function property-access">shutdown</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span>
</code></pre>
<p>And this brings us to the last tests of this application.</p>
<h2>Putting it all together</h2>
<p>The only thing that's left now to make this application work, is to connect the <code>fetchCharactersFromServer</code> with the <code>&lt;RickAndMortyCharactersPage/&gt;</code>. We can do that with the code below:</p>
<pre class="language-jsx"><code class="language-jsx"><span class="token keyword">function</span> <span class="token function"><span class="token maybe-class-name">RickAndMortyCharactersPage</span></span><span class="token punctuation">(</span><span class="token parameter"><span class="token punctuation">{</span>
  fetchCharacters <span class="token operator">=</span> fetchCharactersFromServer<span class="token punctuation">,</span>
<span class="token punctuation">}</span></span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token comment">//...</span>
<span class="token punctuation">}</span>
</code></pre>
<p>To ensure the two modules are connected, we could write an E2E test. But given how straightforward the connection between modules is, it's easier to run the application and look at the browser.</p>
<p>You might be wondering where styling the application fits in all of this. Although visuals are a vital part of any web application, the tests we wrote almost only cover the application's behavior. That is, they assert that the application shows the data the user wants to see and that it responds as expected to user interactions. Visual regression testing is an exciting topic that I'd like to cover on a future article, but what's written in this article doesn't apply to it.</p>
<p>Regarding when to style the application using the process of this case study, I think that will mostly depend on the context we're developing. With that said, I like to do it after I've finished implementing a feature or sub-feature. Because by then, I usually have a better sense of how the feature will work, so adapting a design becomes easier.</p>
<h2>A closer look into the code</h2>
<p>In case you're interested in observing the little details that went into building this application, you can take a look at this <a href="https://github.com/Jnforja/case-study-testing-react">repository</a>. There's one commit at least every time a new test passes, so if you look at the commit history, you can get a reasonably detailed view of the process.</p>
<h2>Key takeaways</h2>
<p>Next time you're faced with writing tests for a React application, remember the following:</p>
<ol>
<li>It's easier to write tests for code we have some idea on how to implement. So explore the services and tools you'll be using before starting.</li>
<li>Small steps will make tests and production code easier to write. So go one test at a time and only worry about making the current test pass.</li>
<li>Start testing from the user perspective, and as tests become too hard to write, use mocks to isolate the behavior you want to test and bring down the complexity of the tests.</li>
<li>Whenever we mock a module, we need to test that the code using the mocked module interacts with it as the real module expects to. We also need to test that the real module behaves as the mocked module.</li>
</ol>]]></content:encoded>
            <author>João Forja</author>
        </item>
        <item>
            <title><![CDATA[Don't know what to test on your React App? Learn how to make a test list.]]></title>
            <link>https://joaoforja.com/articles/learn-how-to-make-a-test-list</link>
            <guid isPermaLink="false">https://joaoforja.com/articles/learn-how-to-make-a-test-list</guid>
            <pubDate>Fri, 15 May 2020 12:12:03 GMT</pubDate>
            <content:encoded><![CDATA[<blockquote>
<p>How in general should I know what to test?</p>
</blockquote>
<p>During the daily meeting with your team, you find out that the client wants a new feature, and you're in charge of implementing it. You've wanted to write automated tests for a while, and this seems like an excellent opportunity. But where do you start? What tests should you even write?</p>
<p>In this article, we'll go over a process to turn a feature request into a list of tests that we can automate and use to help us in our development process. We'll start by looking at the requirements for the feature, and then go over the goals we want to achieve with the tests we'll be writing. After that, we'll make a more thorough analysis of the requirements that will allow us to write the test list.</p>
<h2>The feature we'll be implementing</h2>
<p>The goal of the feature is to allow users to see information about characters from Rick and Morty. More specifically, the user should be able to:</p>
<ol>
<li>See a character name, picture, species, gender, and status (Alive/Dead/Unknown).</li>
<li>Search characters for their name.</li>
<li>Search characters for their status (Alive/Dead/Unknown).</li>
<li>See the characters in a paginated fashion.</li>
</ol>
<p>We're also told that there's an API that will give us the character information.</p>
<h2>Goals for the tests</h2>
<p>When writing a test list, we need to keep in mind the goals of the tests. Otherwise, we'll be lost, and we won't know what tests to write. The main objectives are:</p>
<ol>
<li>Document the feature - After someone has read the tests, he/she should know the behaviors of the feature.</li>
<li>Prevent errors now and/or in the future - Whenever the feature stops working, tests should tell us.</li>
</ol>
<p>Notice that I didn't put "finding unexpected bugs" as a goal for the tests of the test list. That's because trying to think about possible bugs for a feature that doesn't exist yet is extremely hard, time-consuming, and ineffective.</p>
<p>A better approach to find unexpected bugs in a feature is to build the feature worrying only about filling the given requirements and then use a technique like <a href="https://en.wikipedia.org/wiki/Exploratory_testing">Exploratory Testing</a> to find bugs.</p>
<h2>Making the test list</h2>
<p>By making a test list, we're looking to discover a set of examples that define essential behaviors of the feature. Those examples will then guide the automated tests we'll write, and by consequence, the implementation of the feature.</p>
<p>The test list is not something that we do once before implementing a feature, and we're done with it. While developing, we'll discover new behaviors that we'll want to test. When that happens, we should add the new test to the test list, so we don't forget about it.</p>
<p>Since we probably won't know every test we should have on our test list before starting to implement the feature, it's not worth it being too exhaustive. If we've got a couple of tests and we've been thinking about more examples for a minute and can't find new ones, we're in a good place to start writing code.</p>
<h3>Decompose the feature</h3>
<p>Depending on the size of the feature, knowing which tests to write first can be hard. One solution is to decompose it into smaller sub-features that we know how to write tests for.</p>
<p>Helpful questions to ask when trying to decompose a feature are "What's the simplest version of this feature that will still mean progress?" and "What's the behavior of this feature that without nothing else makes sense?". By answering these questions, we'll instinctively start to decompose the feature into sub-features, and we'll get to the core behavior(s). After we get to the core, we should be able to plan tests for it.</p>
<p>If we analyze the requirements for our Rick and Morty characters feature, we can decompose it into at least three sub-feature:</p>
<ol>
<li>Search for characters by name and status</li>
<li>Show the characters' information</li>
<li>Shows characters in a paginated format</li>
</ol>
<p>The core behavior for this example is "Show the characters' information". Without that, searching for characters and pagination doesn't make sense. Also, the application showing the characters' information means substantial progress towards the completion of the feature.</p>
<p>We have already concluded that the sub-feature "Show the characters' information" is a good place to start. And from the requirements, we also know that for each character, we need to show its name, picture, gender, and status. But besides asserting that the application shows the expected information, what other tests can we write?</p>
<h3>Look at the inputs and outputs for test ideas</h3>
<p>A great way to find tests is to look at the inputs and outputs of a feature and ask, "What values can the inputs have, and how does that affect the outputs?"</p>
<p>If we analyze our sub-feature, we can consider that there are one main input and one main output. The main input is the API response with the list of Rick and Morty characters. The main output is the information about the characters.</p>
<p>So what kind of values can the list of characters have, and how will that influence what we show to the user? Since we're dealing with a collection, we can use the "Zero One Many Lots Oops" analysis.</p>
<p>The idea of "Zero One Many Lots Oops" is to make us question what happens when:</p>
<ol>
<li>The collection is empty</li>
<li>Only has one item</li>
<li>Has multiple items</li>
<li>Has a vast number of items</li>
<li>There's an error trying to get the collection.</li>
</ol>
<p>Looking at situation 1 makes us wonder if the API can return 0 characters, and what to do if that happens. I'm not entirely sure if that can happen, so to stay on the safe side, let's prepare the app for it and show a message. So we should write a test that asserts the app shows a message if the API returns an empty list.</p>
<p>Situations 2 and 3 represent common success paths for our sub-feature, so we want to write some tests to tell us if they stop working.</p>
<p>Since we won't work on pagination right now, we won't worry about situation 4. We'll assume that if we can show a small number of characters, like 3, we can also display a large number like 250. We can always get back to this in the end if it gives us more confidence that the application works.</p>
<p>Situation 5 makes us deal with errors. What kind of errors can happen? Should we distinguish between them or not? For our particular example and to not make this overly complicated, we'll treat any HTTP response besides a 200 as an error and don't distinguish between them. If an error happens, we just show a message to the user saying he/she has to reload the application.</p>
<h2>The test list</h2>
<p>So we've gone over the basic requirements, we settled on the core behavior of the feature and we also did an input output analysis aided by the "Zero One Many Lots Oops" methodology to help us find interesting test cases. That lead us to the following tests:</p>
<ol>
<li>Shows an empty message when there aren't characters</li>
<li>Shows one character with expected info</li>
<li>Shows three characters, each with the expected info</li>
<li>Shows an error message when there was an error getting characters</li>
</ol>
<p>Remember that this is by no means an exhaustive list, but it is enough to get us started and to produce something of value when we're done making these tests pass. While we're implementing these tests and writing the code for them, we'll surely remember more use cases that should be tested. When that happens we write those down and implement them when we find it appropriate.</p>
<p>After we're finished with these tests and others that may appear during development, we go back to the feature requirements and repeat the process for the search behavior and the pagination behavior.</p>
<h2>Put it into practice</h2>
<p>Next time you'll be implementing a feature, follow these steps to help you produce a test list that can get you started testing and developing:</p>
<ol>
<li>Go over the requirements.</li>
<li>Decompose the feature into sub-features and start with the core one. If it's not possible to decompose, start with what you have.</li>
<li>Analyze the feature inputs and outputs to get test ideas.</li>
<li>Turn the requirements and input/output analysis into a list of tests and start developing. Don't worry if the list is thorough. You'll find more test-cases as you implement the feature.</li>
<li>One by one, make the tests pass.</li>
<li>If there are other sub-features, go back to them and repeat the process.</li>
</ol>
<p>If after applying steps 1, 2, and 3 you don't know where to start, chances are you're not sure about what the feature should do. Try to clarify the requirements with the management team if that's the case.</p>
<h2>Exercise: test list for the search sub-feature</h2>
<p>If you want an exercise to put the above steps into practice, try to make a test list for the search behavior of the Rick and Morty feature. You can find the test list I'd write for that sub-feature at the end of this section.</p>
<p>Don't worry if your test list doesn't match mine exactly. What's important is that the relevant input/output combinations are covered.</p>
<details><summary>Solution</summary><ol>
<li>When the name to search is not specified, all characters are shown despite their name.</li>
<li>When searching for the name "Rick", shows all characters that contain "Rick" in its name.</li>
<li>When searching for the name "ick", shows all characters that contain "ick" in its name.</li>
<li>When searching for a name that's not part of any character's name, a message is shown to inform the user that there are no characters for their search.</li>
<li>Searching for a name should be case insensitive.</li>
<li>When the status is not specified, all characters are shown despite their status.</li>
<li>When searching for characters with status, "Alive", shows all characters that are alive.</li>
<li>When searching for characters with status, "Dead", shows all characters that are dead.</li>
<li>When searching for characters with status "Unknown", shows all characters that is not known if they're alive or dead.</li>
<li>When searching for a character with the name "Rick" and the status "Alive", all characters with the name Rick that are alive are shown.</li>
</ol></details>
<h2>Implementing the tests</h2>
<p>Do you want to know how the actual code for the tests would look like? Then you will like this <a href="/articles/how-to-write-tests-react-app-case-study/">article</a>.</p>]]></content:encoded>
            <author>João Forja</author>
        </item>
        <item>
            <title><![CDATA[12 recipes for testing React applications using Testing Library]]></title>
            <link>https://joaoforja.com/articles/recipes-for-testing-react-apps-tl</link>
            <guid isPermaLink="false">https://joaoforja.com/articles/recipes-for-testing-react-apps-tl</guid>
            <pubDate>Mon, 22 Jun 2020 10:20:03 GMT</pubDate>
            <content:encoded><![CDATA[<p>If you're not sure how to test a specific part of your React application, this article might be useful to you. Although you probably won't find a direct answer that you can copy and paste, by understanding how the examples work, you'll be able to adapt them to your specific situation.</p>
<p>I plan to keep updating this Cheat Sheet as more meaningful recipes come to mind. If you'd like to be notified of updates to this cheat sheet, you can <a href="#newsletter">subscribe to the newsletter</a> at the bottom of this article.</p>
<p class="note"></p><p>Note: Keep in mind that the components or hooks under test aren't
production-ready and that their only purpose is to illustrate how to test a
particular behavior.</p><p></p>
<h2>Table of Contents</h2>
<ol>
<li><a href="#callback">Invokes given callback</a></li>
<li><a href="#changes-route">Changes current route</a></li>
<li><a href="#hoc">High Order Component</a></li>
<li><a href="#cleanup">Component cleans up on unmount</a></li>
<li><a href="#context-provider">Depends on Context Provider</a></li>
<li><a href="#time">Uses functions that depend on time</a></li>
<li><a href="#hooks">Custom hooks</a></li>
<li><a href="#portal">Portal</a></li>
<li><a href="#focus">Focus is on correct element</a></li>
<li><a href="#elements-order">Order of elements</a></li>
<li><a href="#options">Selected Option</a></li>
<li><a href="#page-titles">Dynamic page titles</a></li>
<li><a href="#other">Other resources</a></li>
</ol>
<h2>Invokes given callback <a name="callback"></a></h2>
<ul>
<li>We're testing that after some interaction the component calls a given callback.</li>
<li>We give a mock function to the component under test and interact with it so that it calls the callback.
Then we assert we called the function with the expected parameters. If relevant, we also check the number of times the function was called.</li>
</ul>
<pre class="language-jsx"><code class="language-jsx"><span class="token keyword module">import</span> <span class="token imports"><span class="token maybe-class-name">React</span></span> <span class="token keyword module">from</span> <span class="token string">'react'</span>
<span class="token keyword module">import</span> <span class="token imports"><span class="token punctuation">{</span> render<span class="token punctuation">,</span> screen <span class="token punctuation">}</span></span> <span class="token keyword module">from</span> <span class="token string">'@testing-library/react'</span>
<span class="token keyword module">import</span> <span class="token imports">userEvent</span> <span class="token keyword module">from</span> <span class="token string">'@testing-library/user-event'</span>

<span class="token function">test</span><span class="token punctuation">(</span><span class="token string">'callback is called on button click'</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token function">test</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">const</span> callback <span class="token operator">=</span> jest<span class="token punctuation">.</span><span class="token method function property-access">fn</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
  <span class="token function">render</span><span class="token punctuation">(</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span><span class="token class-name">Button</span></span> <span class="token attr-name">action</span><span class="token script language-javascript"><span class="token script-punctuation punctuation">=</span><span class="token punctuation">{</span>callback<span class="token punctuation">}</span></span> <span class="token punctuation">/&gt;</span></span><span class="token punctuation">)</span>

  userEvent<span class="token punctuation">.</span><span class="token method function property-access">click</span><span class="token punctuation">(</span>screen<span class="token punctuation">.</span><span class="token method function property-access">getByRole</span><span class="token punctuation">(</span><span class="token string">'button'</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> <span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token regex"><span class="token regex-delimiter">/</span><span class="token regex-source language-regex">call</span><span class="token regex-delimiter">/</span><span class="token regex-flags">i</span></span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">)</span>

  <span class="token function">expect</span><span class="token punctuation">(</span>callback<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token method function property-access">toHaveBeenCalledTimes</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span>
  <span class="token function">expect</span><span class="token punctuation">(</span>callback<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token method function property-access">toHaveBeenCalledWith</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span>

<span class="token keyword">function</span> <span class="token function"><span class="token maybe-class-name">Button</span></span><span class="token punctuation">(</span><span class="token parameter"><span class="token punctuation">{</span> action <span class="token punctuation">}</span></span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword control-flow">return</span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>button</span> <span class="token attr-name">onClick</span><span class="token script language-javascript"><span class="token script-punctuation punctuation">=</span><span class="token punctuation">{</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token arrow operator">=&gt;</span> <span class="token function">action</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">}</span></span><span class="token punctuation">&gt;</span></span><span class="token plain-text">Call</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>button</span><span class="token punctuation">&gt;</span></span>
<span class="token punctuation">}</span>
</code></pre>
<h2>Changes current route <a name="changes-route"></a></h2>
<ul>
<li>We're testing that the component redirects the user to an expected router with the expected query parameters after an interaction.</li>
<li>We first create a routing environment similar to that in which we'll use the component. We set up that environment so we can capture the URL to which the component will redirect us. We interact with the component to cause the redirect. We then assert that we were redirected to the URL we expected.</li>
</ul>
<pre class="language-jsx"><code class="language-jsx"><span class="token keyword module">import</span> <span class="token imports"><span class="token maybe-class-name">React</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> useState <span class="token punctuation">}</span></span> <span class="token keyword module">from</span> <span class="token string">'react'</span>
<span class="token keyword module">import</span> <span class="token imports"><span class="token punctuation">{</span> render<span class="token punctuation">,</span> screen <span class="token punctuation">}</span></span> <span class="token keyword module">from</span> <span class="token string">'@testing-library/react'</span>
<span class="token keyword module">import</span> <span class="token imports">userEvent</span> <span class="token keyword module">from</span> <span class="token string">'@testing-library/user-event'</span>
<span class="token keyword module">import</span> <span class="token imports"><span class="token punctuation">{</span> <span class="token maybe-class-name">MemoryRouter</span><span class="token punctuation">,</span> <span class="token maybe-class-name">Route</span><span class="token punctuation">,</span> useHistory <span class="token punctuation">}</span></span> <span class="token keyword module">from</span> <span class="token string">'react-router-dom'</span>

<span class="token function">test</span><span class="token punctuation">(</span><span class="token string">'On search redirects to new route'</span><span class="token punctuation">,</span> <span class="token keyword">async</span> <span class="token keyword">function</span> <span class="token function">test</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">let</span> <span class="token dom variable">location</span>
  <span class="token function">render</span><span class="token punctuation">(</span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span><span class="token class-name">MemoryRouter</span></span> <span class="token attr-name">initialEntries</span><span class="token script language-javascript"><span class="token script-punctuation punctuation">=</span><span class="token punctuation">{</span><span class="token punctuation">[</span><span class="token string">'/'</span><span class="token punctuation">]</span><span class="token punctuation">}</span></span><span class="token punctuation">&gt;</span></span><span class="token plain-text">
      </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span><span class="token class-name">Route</span></span> <span class="token attr-name">path</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>/<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span><span class="token plain-text">
        </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span><span class="token class-name">SearchBar</span></span> <span class="token punctuation">/&gt;</span></span><span class="token plain-text">
      </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span><span class="token class-name">Route</span></span><span class="token punctuation">&gt;</span></span><span class="token plain-text">
      </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span><span class="token class-name">Route</span></span>
        <span class="token attr-name">path</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>/*<span class="token punctuation">"</span></span>
        <span class="token attr-name">render</span><span class="token script language-javascript"><span class="token script-punctuation punctuation">=</span><span class="token punctuation">{</span><span class="token punctuation">(</span><span class="token parameter"><span class="token punctuation">{</span> <span class="token literal-property property">location</span><span class="token operator">:</span> loc <span class="token punctuation">}</span></span><span class="token punctuation">)</span> <span class="token arrow operator">=&gt;</span> <span class="token punctuation">{</span>
          <span class="token dom variable">location</span> <span class="token operator">=</span> loc
          <span class="token keyword control-flow">return</span> <span class="token keyword null nil">null</span>
        <span class="token punctuation">}</span><span class="token punctuation">}</span></span>
      <span class="token punctuation">/&gt;</span></span><span class="token plain-text">
    </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span><span class="token class-name">MemoryRouter</span></span><span class="token punctuation">&gt;</span></span><span class="token punctuation">,</span>
  <span class="token punctuation">)</span>

  <span class="token keyword control-flow">await</span> userEvent<span class="token punctuation">.</span><span class="token method function property-access">type</span><span class="token punctuation">(</span>screen<span class="token punctuation">.</span><span class="token method function property-access">getByLabelText</span><span class="token punctuation">(</span><span class="token regex"><span class="token regex-delimiter">/</span><span class="token regex-source language-regex">search</span><span class="token regex-delimiter">/</span><span class="token regex-flags">i</span></span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token string">'react'</span><span class="token punctuation">)</span>
  userEvent<span class="token punctuation">.</span><span class="token method function property-access">click</span><span class="token punctuation">(</span>screen<span class="token punctuation">.</span><span class="token method function property-access">getByRole</span><span class="token punctuation">(</span><span class="token string">'button'</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> <span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token regex"><span class="token regex-delimiter">/</span><span class="token regex-source language-regex">submit</span><span class="token regex-delimiter">/</span><span class="token regex-flags">i</span></span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">)</span>

  <span class="token function">expect</span><span class="token punctuation">(</span><span class="token dom variable">location</span><span class="token punctuation">.</span><span class="token property-access">pathname</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token method function property-access">toEqual</span><span class="token punctuation">(</span><span class="token string">'/search-results'</span><span class="token punctuation">)</span>
  <span class="token keyword">const</span> searchParams <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">URLSearchParams</span><span class="token punctuation">(</span><span class="token dom variable">location</span><span class="token punctuation">.</span><span class="token property-access">search</span><span class="token punctuation">)</span>
  <span class="token function">expect</span><span class="token punctuation">(</span>searchParams<span class="token punctuation">.</span><span class="token method function property-access">has</span><span class="token punctuation">(</span><span class="token string">'query'</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token method function property-access">toBe</span><span class="token punctuation">(</span><span class="token boolean">true</span><span class="token punctuation">)</span>
  <span class="token function">expect</span><span class="token punctuation">(</span>searchParams<span class="token punctuation">.</span><span class="token method function property-access">get</span><span class="token punctuation">(</span><span class="token string">'query'</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token method function property-access">toBe</span><span class="token punctuation">(</span><span class="token string">'react'</span><span class="token punctuation">)</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span>

<span class="token keyword">function</span> <span class="token function"><span class="token maybe-class-name">SearchBar</span></span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">const</span> history <span class="token operator">=</span> <span class="token function">useHistory</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
  <span class="token keyword">const</span> <span class="token punctuation">[</span>query<span class="token punctuation">,</span> setQuery<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">useState</span><span class="token punctuation">(</span><span class="token string">''</span><span class="token punctuation">)</span>

  <span class="token keyword control-flow">return</span> <span class="token punctuation">(</span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>form</span>
      <span class="token attr-name">onSubmit</span><span class="token script language-javascript"><span class="token script-punctuation punctuation">=</span><span class="token punctuation">{</span><span class="token keyword">function</span> <span class="token function">redirectToResultsPage</span><span class="token punctuation">(</span><span class="token parameter">e</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
        e<span class="token punctuation">.</span><span class="token method function property-access">preventDefault</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
        history<span class="token punctuation">.</span><span class="token method function property-access">push</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">/search-results?query=</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>query<span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span>
      <span class="token punctuation">}</span><span class="token punctuation">}</span></span>
    <span class="token punctuation">&gt;</span></span><span class="token plain-text">
      </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>label</span> <span class="token attr-name">htmlFor</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>query<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span><span class="token plain-text">search</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>label</span><span class="token punctuation">&gt;</span></span><span class="token plain-text">
      </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>input</span>
        <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>text<span class="token punctuation">"</span></span>
        <span class="token attr-name">value</span><span class="token script language-javascript"><span class="token script-punctuation punctuation">=</span><span class="token punctuation">{</span>query<span class="token punctuation">}</span></span>
        <span class="token attr-name">onChange</span><span class="token script language-javascript"><span class="token script-punctuation punctuation">=</span><span class="token punctuation">{</span><span class="token punctuation">(</span><span class="token parameter">e</span><span class="token punctuation">)</span> <span class="token arrow operator">=&gt;</span> <span class="token function">setQuery</span><span class="token punctuation">(</span>e<span class="token punctuation">.</span><span class="token property-access">currentTarget</span><span class="token punctuation">.</span><span class="token property-access">value</span><span class="token punctuation">)</span><span class="token punctuation">}</span></span>
        <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>query<span class="token punctuation">"</span></span>
      <span class="token punctuation">/&gt;</span></span><span class="token plain-text">
      </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>input</span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>submit<span class="token punctuation">"</span></span> <span class="token attr-name">value</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>go<span class="token punctuation">"</span></span> <span class="token punctuation">/&gt;</span></span><span class="token plain-text">
    </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>form</span><span class="token punctuation">&gt;</span></span>
  <span class="token punctuation">)</span>
<span class="token punctuation">}</span>
</code></pre>
<h2>High Order Component <a name="hoc"></a></h2>
<ul>
<li>We're testing that a HOC gives the props we expect to the wrapped component.</li>
<li>We first create a mock component for the HOC to wrap. The mock component will store the received props in a variable. After rendering the component returned by the HOC we assert that it gave the mock component the props we expected.</li>
</ul>
<pre class="language-jsx"><code class="language-jsx"><span class="token keyword module">import</span> <span class="token imports"><span class="token maybe-class-name">React</span></span> <span class="token keyword module">from</span> <span class="token string">'react'</span>
<span class="token keyword module">import</span> <span class="token imports"><span class="token punctuation">{</span> render <span class="token punctuation">}</span></span> <span class="token keyword module">from</span> <span class="token string">'@testing-library/react'</span>

<span class="token function">test</span><span class="token punctuation">(</span><span class="token string">'Adds number and gives result as a prop'</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token function">test</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">let</span> result
  <span class="token keyword">function</span> <span class="token function"><span class="token maybe-class-name">WrappedComponent</span></span><span class="token punctuation">(</span><span class="token parameter"><span class="token punctuation">{</span> sum <span class="token punctuation">}</span></span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    result <span class="token operator">=</span> sum
    <span class="token keyword control-flow">return</span> <span class="token keyword null nil">null</span>
  <span class="token punctuation">}</span>
  <span class="token keyword">const</span> <span class="token maybe-class-name">ComponentWithSum</span> <span class="token operator">=</span> <span class="token function">withSum</span><span class="token punctuation">(</span><span class="token maybe-class-name">WrappedComponent</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token number">4</span><span class="token punctuation">,</span> <span class="token number">6</span><span class="token punctuation">]</span><span class="token punctuation">)</span>
  <span class="token function">render</span><span class="token punctuation">(</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span><span class="token class-name">ComponentWithSum</span></span> <span class="token punctuation">/&gt;</span></span><span class="token punctuation">)</span>

  <span class="token function">expect</span><span class="token punctuation">(</span>result<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token method function property-access">toBe</span><span class="token punctuation">(</span><span class="token number">10</span><span class="token punctuation">)</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span>

<span class="token keyword">function</span> <span class="token function">withSum</span><span class="token punctuation">(</span><span class="token parameter"><span class="token maybe-class-name">WrappedComponent</span><span class="token punctuation">,</span> numbersToSum</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">const</span> sum <span class="token operator">=</span> numbersToSum<span class="token punctuation">.</span><span class="token method function property-access">reduce</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">a<span class="token punctuation">,</span> b</span><span class="token punctuation">)</span> <span class="token arrow operator">=&gt;</span> a <span class="token operator">+</span> b<span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">)</span>
  <span class="token keyword control-flow">return</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token arrow operator">=&gt;</span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span><span class="token class-name">WrappedComponent</span></span> <span class="token attr-name">sum</span><span class="token script language-javascript"><span class="token script-punctuation punctuation">=</span><span class="token punctuation">{</span>sum<span class="token punctuation">}</span></span> <span class="token punctuation">/&gt;</span></span>
<span class="token punctuation">}</span>
</code></pre>
<h2>Component cleans up on unmount <a name="cleanup"></a></h2>
<ul>
<li>We want to assert that a component subscribes after mount and unsubscribes after unmount.</li>
<li>We start by mocking the subscription methods so we can assert they get called. We then
render the component and assert that it subscribed. All that's left to do is make the
component unmount and assert it unsubscribed.</li>
</ul>
<pre class="language-jsx"><code class="language-jsx"><span class="token keyword module">import</span> <span class="token imports"><span class="token maybe-class-name">React</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> useEffect <span class="token punctuation">}</span></span> <span class="token keyword module">from</span> <span class="token string">'react'</span>
<span class="token keyword module">import</span> <span class="token imports"><span class="token punctuation">{</span> render <span class="token punctuation">}</span></span> <span class="token keyword module">from</span> <span class="token string">'@testing-library/react'</span>

<span class="token function">test</span><span class="token punctuation">(</span><span class="token string">'Subscribes and unsubscribes when appropriate'</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token function">test</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">const</span> subscriptionService <span class="token operator">=</span> <span class="token punctuation">{</span>
    <span class="token literal-property property">subscribe</span><span class="token operator">:</span> jest<span class="token punctuation">.</span><span class="token method function property-access">fn</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
    <span class="token literal-property property">unsubscribe</span><span class="token operator">:</span> jest<span class="token punctuation">.</span><span class="token method function property-access">fn</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
  <span class="token punctuation">}</span>

  <span class="token keyword">const</span> <span class="token punctuation">{</span> unmount <span class="token punctuation">}</span> <span class="token operator">=</span> <span class="token function">render</span><span class="token punctuation">(</span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span><span class="token class-name">ComponentThatSubscribes</span></span> <span class="token attr-name">subscriptionService</span><span class="token script language-javascript"><span class="token script-punctuation punctuation">=</span><span class="token punctuation">{</span>subscriptionService<span class="token punctuation">}</span></span> <span class="token punctuation">/&gt;</span></span><span class="token punctuation">,</span>
  <span class="token punctuation">)</span>

  <span class="token function">expect</span><span class="token punctuation">(</span>subscriptionService<span class="token punctuation">.</span><span class="token property-access">subscribe</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token method function property-access">toHaveBeenCalledTimes</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span>
  <span class="token function">expect</span><span class="token punctuation">(</span>subscriptionService<span class="token punctuation">.</span><span class="token property-access">subscribe</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token method function property-access">toHaveBeenCalledWith</span><span class="token punctuation">(</span><span class="token punctuation">)</span>

  <span class="token function">unmount</span><span class="token punctuation">(</span><span class="token punctuation">)</span>

  <span class="token function">expect</span><span class="token punctuation">(</span>subscriptionService<span class="token punctuation">.</span><span class="token property-access">unsubscribe</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token method function property-access">toHaveBeenCalledTimes</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span>
  <span class="token function">expect</span><span class="token punctuation">(</span>subscriptionService<span class="token punctuation">.</span><span class="token property-access">unsubscribe</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token method function property-access">toHaveBeenCalledWith</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span>

<span class="token keyword">function</span> <span class="token function"><span class="token maybe-class-name">ComponentThatSubscribes</span></span><span class="token punctuation">(</span><span class="token parameter"><span class="token punctuation">{</span> subscriptionService <span class="token punctuation">}</span></span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token function">useEffect</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token arrow operator">=&gt;</span> <span class="token punctuation">{</span>
    subscriptionService<span class="token punctuation">.</span><span class="token method function property-access">subscribe</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
    <span class="token keyword control-flow">return</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token arrow operator">=&gt;</span> subscriptionService<span class="token punctuation">.</span><span class="token method function property-access">unsubscribe</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">[</span>subscriptionService<span class="token punctuation">]</span><span class="token punctuation">)</span>
  <span class="token keyword control-flow">return</span> <span class="token keyword null nil">null</span>
<span class="token punctuation">}</span>
</code></pre>
<h2>Depends on Context Provider <a name="context-provider"></a></h2>
<ul>
<li>We want to test a component that depends on a context Provider</li>
<li>To test the component, we'll recreate the environment in which we'll use the component. In other words, we'll wrap the component in the Context Provider.</li>
</ul>
<pre class="language-jsx"><code class="language-jsx"><span class="token keyword module">import</span> <span class="token imports"><span class="token maybe-class-name">React</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> useContext <span class="token punctuation">}</span></span> <span class="token keyword module">from</span> <span class="token string">'react'</span>
<span class="token keyword module">import</span> <span class="token imports"><span class="token punctuation">{</span> render<span class="token punctuation">,</span> screen <span class="token punctuation">}</span></span> <span class="token keyword module">from</span> <span class="token string">'@testing-library/react'</span>

<span class="token function">test</span><span class="token punctuation">(</span><span class="token string">'displays name of current user'</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token function">test</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token function">render</span><span class="token punctuation">(</span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span><span class="token class-name">UserContext.Provider</span></span> <span class="token attr-name">value</span><span class="token script language-javascript"><span class="token script-punctuation punctuation">=</span><span class="token punctuation">{</span><span class="token punctuation">{</span> <span class="token literal-property property">user</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token literal-property property">fullName</span><span class="token operator">:</span> <span class="token string">'Giorno Giovanna'</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span><span class="token punctuation">}</span></span><span class="token punctuation">&gt;</span></span><span class="token plain-text">
      </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span><span class="token class-name">UserFullName</span></span> <span class="token punctuation">/&gt;</span></span><span class="token plain-text">
    </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span><span class="token class-name">UserContext.Provider</span></span><span class="token punctuation">&gt;</span></span><span class="token punctuation">,</span>
  <span class="token punctuation">)</span>
  <span class="token function">expect</span><span class="token punctuation">(</span>screen<span class="token punctuation">.</span><span class="token method function property-access">getByText</span><span class="token punctuation">(</span><span class="token string">'Giorno Giovanna'</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token method function property-access">toBeVisible</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span>

<span class="token keyword">const</span> <span class="token maybe-class-name">UserContext</span> <span class="token operator">=</span> <span class="token maybe-class-name">React</span><span class="token punctuation">.</span><span class="token method function property-access">createContext</span><span class="token punctuation">(</span><span class="token punctuation">)</span>

<span class="token keyword">function</span> <span class="token function"><span class="token maybe-class-name">UserFullName</span></span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">const</span> <span class="token punctuation">{</span> user <span class="token punctuation">}</span> <span class="token operator">=</span> <span class="token function">useContext</span><span class="token punctuation">(</span><span class="token maybe-class-name">UserContext</span><span class="token punctuation">)</span>
  <span class="token keyword control-flow">return</span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>p</span><span class="token punctuation">&gt;</span></span><span class="token punctuation">{</span>user<span class="token punctuation">.</span><span class="token property-access">fullName</span><span class="token punctuation">}</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>p</span><span class="token punctuation">&gt;</span></span>
<span class="token punctuation">}</span>
</code></pre>
<h2>Uses functions that depend on time <a name="time"></a></h2>
<ul>
<li>We want to test a component that depends on real-time. In this example, that dependency comes from using <code>setTimeout()</code>.</li>
<li>When testing components that depend on real-time, we need to be aware that those tests shouldn't take too long. One way to do that is to have the component receive the time interval as a prop to allow us to configure a shorter time interval for tests than we would have in production.</li>
</ul>
<pre class="language-jsx"><code class="language-jsx"><span class="token keyword module">import</span> <span class="token imports"><span class="token maybe-class-name">React</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> useState<span class="token punctuation">,</span> useEffect <span class="token punctuation">}</span></span> <span class="token keyword module">from</span> <span class="token string">'react'</span>
<span class="token keyword module">import</span> <span class="token imports"><span class="token punctuation">{</span>
  render<span class="token punctuation">,</span>
  screen<span class="token punctuation">,</span>
  waitForElementToBeRemoved<span class="token punctuation">,</span>
<span class="token punctuation">}</span></span> <span class="token keyword module">from</span> <span class="token string">'@testing-library/react'</span>

<span class="token function">test</span><span class="token punctuation">(</span><span class="token string">'Changes from red to green to after timeout'</span><span class="token punctuation">,</span> <span class="token keyword">async</span> <span class="token keyword">function</span> <span class="token function">test</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token function">render</span><span class="token punctuation">(</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span><span class="token class-name">TrafficLight</span></span> <span class="token attr-name">timeUntilChange</span><span class="token script language-javascript"><span class="token script-punctuation punctuation">=</span><span class="token punctuation">{</span><span class="token number">10</span><span class="token punctuation">}</span></span> <span class="token punctuation">/&gt;</span></span><span class="token punctuation">)</span>

  <span class="token function">expect</span><span class="token punctuation">(</span>screen<span class="token punctuation">.</span><span class="token method function property-access">getByText</span><span class="token punctuation">(</span><span class="token regex"><span class="token regex-delimiter">/</span><span class="token regex-source language-regex">red</span><span class="token regex-delimiter">/</span><span class="token regex-flags">i</span></span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token method function property-access">toBeVisible</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
  <span class="token keyword control-flow">await</span> <span class="token function">waitForElementToBeRemoved</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token arrow operator">=&gt;</span> screen<span class="token punctuation">.</span><span class="token method function property-access">getByText</span><span class="token punctuation">(</span><span class="token regex"><span class="token regex-delimiter">/</span><span class="token regex-source language-regex">red</span><span class="token regex-delimiter">/</span><span class="token regex-flags">i</span></span><span class="token punctuation">)</span><span class="token punctuation">)</span>
  <span class="token function">expect</span><span class="token punctuation">(</span>screen<span class="token punctuation">.</span><span class="token method function property-access">getByText</span><span class="token punctuation">(</span><span class="token regex"><span class="token regex-delimiter">/</span><span class="token regex-source language-regex">green</span><span class="token regex-delimiter">/</span><span class="token regex-flags">i</span></span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token method function property-access">toBeVisible</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span>

<span class="token keyword">function</span> <span class="token function"><span class="token maybe-class-name">TrafficLight</span></span><span class="token punctuation">(</span><span class="token parameter"><span class="token punctuation">{</span> timeUntilChange <span class="token operator">=</span> <span class="token number">500</span> <span class="token punctuation">}</span></span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">const</span> <span class="token punctuation">[</span>light<span class="token punctuation">,</span> setLight<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">useState</span><span class="token punctuation">(</span><span class="token string">'Red'</span><span class="token punctuation">)</span>
  <span class="token function">useEffect</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token arrow operator">=&gt;</span> <span class="token punctuation">{</span>
    <span class="token function">setTimeout</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token arrow operator">=&gt;</span> <span class="token function">setLight</span><span class="token punctuation">(</span><span class="token string">'Green'</span><span class="token punctuation">)</span><span class="token punctuation">,</span> timeUntilChange<span class="token punctuation">)</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">[</span>timeUntilChange<span class="token punctuation">]</span><span class="token punctuation">)</span>
  <span class="token keyword control-flow">return</span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>p</span><span class="token punctuation">&gt;</span></span><span class="token punctuation">{</span>light<span class="token punctuation">}</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>p</span><span class="token punctuation">&gt;</span></span>
<span class="token punctuation">}</span>
</code></pre>
<h2>Custom hooks <a name="hooks"></a></h2>
<ul>
<li>We want to test a custom hook.</li>
<li>Since we're testing a hook, we'll need to call it inside a component otherwise we'll get an error. Therefore, we'll create a mock component, use the hook inside it, and store what the hook returns in a variable. Now we can assert what we need to assert using that variable.</li>
</ul>
<pre class="language-jsx"><code class="language-jsx"><span class="token keyword module">import</span> <span class="token imports"><span class="token maybe-class-name">React</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> useState<span class="token punctuation">,</span> useCallback <span class="token punctuation">}</span></span> <span class="token keyword module">from</span> <span class="token string">'react'</span>
<span class="token keyword module">import</span> <span class="token imports"><span class="token punctuation">{</span> render<span class="token punctuation">,</span> act <span class="token punctuation">}</span></span> <span class="token keyword module">from</span> <span class="token string">'@testing-library/react'</span>

<span class="token function">test</span><span class="token punctuation">(</span><span class="token string">'counter increments'</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token function">test</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">let</span> counter
  <span class="token keyword">function</span> <span class="token function"><span class="token maybe-class-name">MockComponent</span></span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    counter <span class="token operator">=</span> <span class="token function">useCounter</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
    <span class="token keyword control-flow">return</span> <span class="token keyword null nil">null</span>
  <span class="token punctuation">}</span>

  <span class="token function">render</span><span class="token punctuation">(</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span><span class="token class-name">MockComponent</span></span> <span class="token punctuation">/&gt;</span></span><span class="token punctuation">)</span>

  <span class="token function">expect</span><span class="token punctuation">(</span>counter<span class="token punctuation">.</span><span class="token property-access">count</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token method function property-access">toEqual</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">)</span>
  <span class="token function">act</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token arrow operator">=&gt;</span> counter<span class="token punctuation">.</span><span class="token method function property-access">increment</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
  <span class="token function">expect</span><span class="token punctuation">(</span>counter<span class="token punctuation">.</span><span class="token property-access">count</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token method function property-access">toEqual</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span>

<span class="token keyword">function</span> <span class="token function">useCounter</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">const</span> <span class="token punctuation">[</span>count<span class="token punctuation">,</span> setCount<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">useState</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">)</span>
  <span class="token keyword">const</span> increment <span class="token operator">=</span> <span class="token function">useCallback</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token arrow operator">=&gt;</span> <span class="token function">setCount</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">x</span><span class="token punctuation">)</span> <span class="token arrow operator">=&gt;</span> x <span class="token operator">+</span> <span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">)</span>
  <span class="token keyword control-flow">return</span> <span class="token punctuation">{</span> count<span class="token punctuation">,</span> increment <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre>
<ul>
<li>Another approach is to use <a href="https://react-hooks-testing-library.com/">react hooks testing library</a>.</li>
</ul>
<pre class="language-jsx"><code class="language-jsx"><span class="token keyword module">import</span> <span class="token imports"><span class="token maybe-class-name">React</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> useState<span class="token punctuation">,</span> useCallback <span class="token punctuation">}</span></span> <span class="token keyword module">from</span> <span class="token string">'react'</span>
<span class="token keyword module">import</span> <span class="token imports"><span class="token punctuation">{</span> renderHook<span class="token punctuation">,</span> act <span class="token punctuation">}</span></span> <span class="token keyword module">from</span> <span class="token string">'@testing-library/react-hooks'</span>

<span class="token function">test</span><span class="token punctuation">(</span><span class="token string">'counter increments with react hooks testing library'</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token function">test</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">const</span> <span class="token punctuation">{</span> result <span class="token punctuation">}</span> <span class="token operator">=</span> <span class="token function">renderHook</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token arrow operator">=&gt;</span> <span class="token function">useCounter</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
  <span class="token function">expect</span><span class="token punctuation">(</span>result<span class="token punctuation">.</span><span class="token property-access">current</span><span class="token punctuation">.</span><span class="token property-access">count</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token method function property-access">toBe</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">)</span>
  <span class="token function">act</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token arrow operator">=&gt;</span> result<span class="token punctuation">.</span><span class="token property-access">current</span><span class="token punctuation">.</span><span class="token method function property-access">increment</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
  <span class="token function">expect</span><span class="token punctuation">(</span>result<span class="token punctuation">.</span><span class="token property-access">current</span><span class="token punctuation">.</span><span class="token property-access">count</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token method function property-access">toBe</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span>

<span class="token keyword">function</span> <span class="token function">useCounter</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">const</span> <span class="token punctuation">[</span>count<span class="token punctuation">,</span> setCount<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">useState</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">)</span>
  <span class="token keyword">const</span> increment <span class="token operator">=</span> <span class="token function">useCallback</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token arrow operator">=&gt;</span> <span class="token function">setCount</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">x</span><span class="token punctuation">)</span> <span class="token arrow operator">=&gt;</span> x <span class="token operator">+</span> <span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">)</span>
  <span class="token keyword control-flow">return</span> <span class="token punctuation">{</span> count<span class="token punctuation">,</span> increment <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre>
<ul>
<li>If you're looking for more examples on how to test react hooks, I recommend you take a look at the usage section of the <a href="https://react-hooks-testing-library.com/">react hooks testing library</a> documentation. They have excellent documentation on how to deal with other use cases like errors and asynchronous updates.</li>
</ul>
<h2>Portal <a name="portal"></a></h2>
<ul>
<li>We want to test a component that's a portal.</li>
<li>A portal needs a DOM node to be rendered into. So to test it, we'll have to create that DOM node. After we make the assertions, we'll have to remove the DOM node as not to affect other tests.</li>
</ul>
<pre class="language-jsx"><code class="language-jsx"><span class="token keyword module">import</span> <span class="token imports"><span class="token maybe-class-name">React</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> useRef<span class="token punctuation">,</span> useEffect<span class="token punctuation">,</span> useState <span class="token punctuation">}</span></span> <span class="token keyword module">from</span> <span class="token string">'react'</span>
<span class="token keyword module">import</span> <span class="token imports"><span class="token maybe-class-name">ReactDOM</span></span> <span class="token keyword module">from</span> <span class="token string">'react-dom'</span>
<span class="token keyword module">import</span> <span class="token imports"><span class="token punctuation">{</span> render<span class="token punctuation">,</span> screen <span class="token punctuation">}</span></span> <span class="token keyword module">from</span> <span class="token string">'@testing-library/react'</span>
<span class="token keyword module">import</span> <span class="token imports">userEvent</span> <span class="token keyword module">from</span> <span class="token string">'@testing-library/user-event'</span>

<span class="token function">test</span><span class="token punctuation">(</span><span class="token string">'PortalCounter starts at 0 and increments'</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token function">test</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">const</span> modalRoot <span class="token operator">=</span> <span class="token dom variable">document</span><span class="token punctuation">.</span><span class="token method function property-access">createElement</span><span class="token punctuation">(</span><span class="token string">'div'</span><span class="token punctuation">)</span>
  modalRoot<span class="token punctuation">.</span><span class="token method function property-access">setAttribute</span><span class="token punctuation">(</span><span class="token string">'id'</span><span class="token punctuation">,</span> <span class="token string">'modal-root'</span><span class="token punctuation">)</span>
  <span class="token dom variable">document</span><span class="token punctuation">.</span><span class="token property-access">body</span><span class="token punctuation">.</span><span class="token method function property-access">appendChild</span><span class="token punctuation">(</span>modalRoot<span class="token punctuation">)</span>

  <span class="token function">render</span><span class="token punctuation">(</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span><span class="token class-name">PortalCounter</span></span> <span class="token punctuation">/&gt;</span></span><span class="token punctuation">)</span>

  <span class="token function">expect</span><span class="token punctuation">(</span>screen<span class="token punctuation">.</span><span class="token method function property-access">getByTestId</span><span class="token punctuation">(</span><span class="token string">'counter'</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token method function property-access">toHaveTextContent</span><span class="token punctuation">(</span><span class="token string">'0'</span><span class="token punctuation">)</span>
  userEvent<span class="token punctuation">.</span><span class="token method function property-access">click</span><span class="token punctuation">(</span>screen<span class="token punctuation">.</span><span class="token method function property-access">getByRole</span><span class="token punctuation">(</span><span class="token string">'button'</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> <span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">'inc'</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
  <span class="token function">expect</span><span class="token punctuation">(</span>screen<span class="token punctuation">.</span><span class="token method function property-access">getByTestId</span><span class="token punctuation">(</span><span class="token string">'counter'</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token method function property-access">toHaveTextContent</span><span class="token punctuation">(</span><span class="token string">'1'</span><span class="token punctuation">)</span>

  <span class="token dom variable">document</span><span class="token punctuation">.</span><span class="token property-access">body</span><span class="token punctuation">.</span><span class="token method function property-access">removeChild</span><span class="token punctuation">(</span>modalRoot<span class="token punctuation">)</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span>

<span class="token keyword">function</span> <span class="token function"><span class="token maybe-class-name">PortalCounter</span></span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">const</span> el <span class="token operator">=</span> <span class="token function">useRef</span><span class="token punctuation">(</span><span class="token dom variable">document</span><span class="token punctuation">.</span><span class="token method function property-access">createElement</span><span class="token punctuation">(</span><span class="token string">'div'</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
  <span class="token keyword">const</span> <span class="token punctuation">[</span>count<span class="token punctuation">,</span> setCount<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">useState</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">)</span>

  <span class="token function">useEffect</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token arrow operator">=&gt;</span> <span class="token punctuation">{</span>
    <span class="token keyword">const</span> modalRoot <span class="token operator">=</span> <span class="token dom variable">document</span><span class="token punctuation">.</span><span class="token method function property-access">getElementById</span><span class="token punctuation">(</span><span class="token string">'modal-root'</span><span class="token punctuation">)</span>
    <span class="token keyword">const</span> currentEl <span class="token operator">=</span> el<span class="token punctuation">.</span><span class="token property-access">current</span>
    modalRoot<span class="token punctuation">.</span><span class="token method function property-access">appendChild</span><span class="token punctuation">(</span>currentEl<span class="token punctuation">)</span>
    <span class="token keyword control-flow">return</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token arrow operator">=&gt;</span> modalRoot<span class="token punctuation">.</span><span class="token method function property-access">removeChild</span><span class="token punctuation">(</span>currentEl<span class="token punctuation">)</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">)</span>

  <span class="token keyword control-flow">return</span> <span class="token maybe-class-name">ReactDOM</span><span class="token punctuation">.</span><span class="token method function property-access">createPortal</span><span class="token punctuation">(</span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span></span><span class="token punctuation">&gt;</span></span><span class="token plain-text">
      </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>section</span> <span class="token attr-name">aria-live</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>polite<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span><span class="token plain-text">
        count: </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>span</span> <span class="token attr-name">data-testid</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>counter<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span><span class="token punctuation">{</span>count<span class="token punctuation">}</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>span</span><span class="token punctuation">&gt;</span></span><span class="token plain-text">
      </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>section</span><span class="token punctuation">&gt;</span></span><span class="token plain-text">
      </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>button</span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>button<span class="token punctuation">"</span></span> <span class="token attr-name">onClick</span><span class="token script language-javascript"><span class="token script-punctuation punctuation">=</span><span class="token punctuation">{</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token arrow operator">=&gt;</span> <span class="token function">setCount</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">c</span><span class="token punctuation">)</span> <span class="token arrow operator">=&gt;</span> c <span class="token operator">+</span> <span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">}</span></span><span class="token punctuation">&gt;</span></span><span class="token plain-text">
        inc
      </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>button</span><span class="token punctuation">&gt;</span></span><span class="token plain-text">
    </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span></span><span class="token punctuation">&gt;</span></span><span class="token punctuation">,</span>
    el<span class="token punctuation">.</span><span class="token property-access">current</span><span class="token punctuation">,</span>
  <span class="token punctuation">)</span>
<span class="token punctuation">}</span>
</code></pre>
<h2>Focus is on correct element <a name="focus"></a></h2>
<ul>
<li>We want to test that the focus on the element we expect.</li>
<li>We can verify if an element has focus or not by using <a href="https://github.com/testing-library/jest-dom#tohavefocus">toHaveFocus()</a>.</li>
</ul>
<pre class="language-jsx"><code class="language-jsx"><span class="token keyword module">import</span> <span class="token imports"><span class="token maybe-class-name">React</span></span> <span class="token keyword module">from</span> <span class="token string">'react'</span>
<span class="token keyword module">import</span> <span class="token imports"><span class="token punctuation">{</span> render <span class="token punctuation">}</span></span> <span class="token keyword module">from</span> <span class="token string">'@testing-library/react'</span>
<span class="token keyword module">import</span> <span class="token imports">userEvent</span> <span class="token keyword module">from</span> <span class="token string">'@testing-library/user-event'</span>

<span class="token function">test</span><span class="token punctuation">(</span><span class="token string">'clicking on label gives focus to name input'</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token arrow operator">=&gt;</span> <span class="token punctuation">{</span>
  <span class="token keyword">const</span> <span class="token punctuation">{</span> getByText<span class="token punctuation">,</span> getByLabelText <span class="token punctuation">}</span> <span class="token operator">=</span> <span class="token function">render</span><span class="token punctuation">(</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span><span class="token class-name">NameForm</span></span> <span class="token punctuation">/&gt;</span></span><span class="token punctuation">)</span>

  <span class="token keyword">const</span> nameLabel <span class="token operator">=</span> <span class="token function">getByText</span><span class="token punctuation">(</span><span class="token string">'Name'</span><span class="token punctuation">)</span>
  userEvent<span class="token punctuation">.</span><span class="token method function property-access">click</span><span class="token punctuation">(</span>nameLabel<span class="token punctuation">)</span>

  <span class="token keyword">const</span> nameInput <span class="token operator">=</span> <span class="token function">getByLabelText</span><span class="token punctuation">(</span><span class="token string">'Name'</span><span class="token punctuation">)</span>
  <span class="token function">expect</span><span class="token punctuation">(</span>nameInput<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token method function property-access">toHaveFocus</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span>

<span class="token keyword">function</span> <span class="token function"><span class="token maybe-class-name">NameForm</span></span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword control-flow">return</span> <span class="token punctuation">(</span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>form</span><span class="token punctuation">&gt;</span></span><span class="token plain-text">
      </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>label</span> <span class="token attr-name">htmlFor</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>name<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span><span class="token plain-text">Name</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>label</span><span class="token punctuation">&gt;</span></span><span class="token plain-text">
      </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>input</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>name<span class="token punctuation">"</span></span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>text<span class="token punctuation">"</span></span> <span class="token punctuation">/&gt;</span></span><span class="token plain-text">
    </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>form</span><span class="token punctuation">&gt;</span></span>
  <span class="token punctuation">)</span>
<span class="token punctuation">}</span>
</code></pre>
<h2>Order of elements <a name="elements-order"></a></h2>
<ul>
<li>We want to test that a list of elements is rendered in the expected order.</li>
<li>We'll take advantage of AllBy queries returning elements in the order in which they appear on the HTML.</li>
<li>It's important to note that this approach doesn't take into account CSS that might change the order in which the elements are displayed.</li>
</ul>
<pre class="language-jsx"><code class="language-jsx"><span class="token keyword module">import</span> <span class="token imports"><span class="token maybe-class-name">React</span></span> <span class="token keyword module">from</span> <span class="token string">'react'</span>
<span class="token keyword module">import</span> <span class="token imports"><span class="token punctuation">{</span> render<span class="token punctuation">,</span> screen <span class="token punctuation">}</span></span> <span class="token keyword module">from</span> <span class="token string">'@testing-library/react'</span>

<span class="token function">test</span><span class="token punctuation">(</span><span class="token string">'renders names in given order'</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token arrow operator">=&gt;</span> <span class="token punctuation">{</span>
  <span class="token keyword">const</span> names <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token string">'Bucciarati'</span><span class="token punctuation">,</span> <span class="token string">'Abbacchio'</span><span class="token punctuation">,</span> <span class="token string">'Narancia'</span><span class="token punctuation">]</span>

  <span class="token function">render</span><span class="token punctuation">(</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span><span class="token class-name">NamesList</span></span> <span class="token attr-name">names</span><span class="token script language-javascript"><span class="token script-punctuation punctuation">=</span><span class="token punctuation">{</span>names<span class="token punctuation">}</span></span> <span class="token punctuation">/&gt;</span></span><span class="token punctuation">)</span>

  <span class="token keyword">const</span> renderedNames <span class="token operator">=</span> screen<span class="token punctuation">.</span><span class="token method function property-access">getAllByRole</span><span class="token punctuation">(</span><span class="token string">'listitem'</span><span class="token punctuation">)</span>
  <span class="token function">expect</span><span class="token punctuation">(</span>renderedNames<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token method function property-access">toHaveTextContent</span><span class="token punctuation">(</span><span class="token string">'Bucciarati'</span><span class="token punctuation">)</span>
  <span class="token function">expect</span><span class="token punctuation">(</span>renderedNames<span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token method function property-access">toHaveTextContent</span><span class="token punctuation">(</span><span class="token string">'Abbacchio'</span><span class="token punctuation">)</span>
  <span class="token function">expect</span><span class="token punctuation">(</span>renderedNames<span class="token punctuation">[</span><span class="token number">2</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token method function property-access">toHaveTextContent</span><span class="token punctuation">(</span><span class="token string">'Narancia'</span><span class="token punctuation">)</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span>

<span class="token keyword">function</span> <span class="token function"><span class="token maybe-class-name">NamesList</span></span><span class="token punctuation">(</span><span class="token parameter"><span class="token punctuation">{</span> names <span class="token punctuation">}</span></span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword control-flow">return</span> <span class="token punctuation">(</span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>ul</span><span class="token punctuation">&gt;</span></span><span class="token plain-text">
      </span><span class="token punctuation">{</span>names<span class="token punctuation">.</span><span class="token method function property-access">map</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">name</span><span class="token punctuation">)</span> <span class="token arrow operator">=&gt;</span> <span class="token punctuation">(</span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>li</span> <span class="token attr-name">key</span><span class="token script language-javascript"><span class="token script-punctuation punctuation">=</span><span class="token punctuation">{</span>name<span class="token punctuation">}</span></span><span class="token punctuation">&gt;</span></span><span class="token punctuation">{</span>name<span class="token punctuation">}</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>li</span><span class="token punctuation">&gt;</span></span>
      <span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">}</span><span class="token plain-text">
    </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>ul</span><span class="token punctuation">&gt;</span></span>
  <span class="token punctuation">)</span>
<span class="token punctuation">}</span>
</code></pre>
<h2>Selected Option <a name="options"></a></h2>
<ul>
<li>We want to test that an input is checked.</li>
<li>We can use <a href="https://github.com/testing-library/jest-dom#tobechecked">toBeChecked()</a> to test if an element is checked.</li>
</ul>
<pre class="language-jsx"><code class="language-jsx"><span class="token keyword module">import</span> <span class="token imports"><span class="token maybe-class-name">React</span></span> <span class="token keyword module">from</span> <span class="token string">'react'</span>
<span class="token keyword module">import</span> <span class="token imports"><span class="token punctuation">{</span> render<span class="token punctuation">,</span> screen <span class="token punctuation">}</span></span> <span class="token keyword module">from</span> <span class="token string">'@testing-library/react'</span>

<span class="token function">test</span><span class="token punctuation">(</span><span class="token string">'Has Summer pre-selected'</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token function">test</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token function">render</span><span class="token punctuation">(</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span><span class="token class-name">SeasonsForm</span></span> <span class="token punctuation">/&gt;</span></span><span class="token punctuation">)</span>
  <span class="token function">expect</span><span class="token punctuation">(</span>screen<span class="token punctuation">.</span><span class="token method function property-access">getByRole</span><span class="token punctuation">(</span><span class="token string">'radio'</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> <span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token regex"><span class="token regex-delimiter">/</span><span class="token regex-source language-regex">summer</span><span class="token regex-delimiter">/</span><span class="token regex-flags">i</span></span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token method function property-access">toBeChecked</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span>

<span class="token keyword">function</span> <span class="token function"><span class="token maybe-class-name">SeasonsForm</span></span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword control-flow">return</span> <span class="token punctuation">(</span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>form</span><span class="token punctuation">&gt;</span></span><span class="token plain-text">
      </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>p</span><span class="token punctuation">&gt;</span></span><span class="token plain-text">Beast season:</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>p</span><span class="token punctuation">&gt;</span></span><span class="token plain-text">
      </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>section</span><span class="token punctuation">&gt;</span></span><span class="token plain-text">
        </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>input</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>season<span class="token punctuation">"</span></span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>radio<span class="token punctuation">"</span></span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>winter<span class="token punctuation">"</span></span> <span class="token attr-name">value</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>winter<span class="token punctuation">"</span></span> <span class="token punctuation">/&gt;</span></span><span class="token plain-text">
        </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>label</span> <span class="token attr-name">htmlFor</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>winter<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span><span class="token plain-text">Winter</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>label</span><span class="token punctuation">&gt;</span></span><span class="token plain-text">
        </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>input</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>season<span class="token punctuation">"</span></span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>radio<span class="token punctuation">"</span></span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>spring<span class="token punctuation">"</span></span> <span class="token attr-name">value</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>spring<span class="token punctuation">"</span></span> <span class="token punctuation">/&gt;</span></span><span class="token plain-text">
        </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>label</span> <span class="token attr-name">htmlFor</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>spring<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span><span class="token plain-text">Spring</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>label</span><span class="token punctuation">&gt;</span></span><span class="token plain-text">
        </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>input</span>
          <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>season<span class="token punctuation">"</span></span>
          <span class="token attr-name">checked</span>
          <span class="token attr-name">readOnly</span>
          <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>radio<span class="token punctuation">"</span></span>
          <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>summer<span class="token punctuation">"</span></span>
          <span class="token attr-name">value</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>summer<span class="token punctuation">"</span></span>
        <span class="token punctuation">/&gt;</span></span><span class="token plain-text">
        </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>label</span> <span class="token attr-name">htmlFor</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>summer<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span><span class="token plain-text">Summer</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>label</span><span class="token punctuation">&gt;</span></span><span class="token plain-text">
        </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>input</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>season<span class="token punctuation">"</span></span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>radio<span class="token punctuation">"</span></span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>autumn<span class="token punctuation">"</span></span> <span class="token attr-name">value</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>autumn<span class="token punctuation">"</span></span> <span class="token punctuation">/&gt;</span></span><span class="token plain-text">
        </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>label</span> <span class="token attr-name">htmlFor</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>autumn<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span><span class="token plain-text">Autumn</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>label</span><span class="token punctuation">&gt;</span></span><span class="token plain-text">
      </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>section</span><span class="token punctuation">&gt;</span></span><span class="token plain-text">
    </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>form</span><span class="token punctuation">&gt;</span></span>
  <span class="token punctuation">)</span>
<span class="token punctuation">}</span>
</code></pre>
<h2>Dynamic page titles <a name="page-titles"></a></h2>
<ul>
<li>We want to test that the title of the current page is updated.</li>
<li>We access the current title by using <code>document.title</code>. Since the document title won't be immediately updated, we need to wait for the change using <code>waitFor</code>.</li>
</ul>
<pre class="language-jsx"><code class="language-jsx"><span class="token keyword module">import</span> <span class="token imports"><span class="token maybe-class-name">React</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> useState <span class="token punctuation">}</span></span> <span class="token keyword module">from</span> <span class="token string">'react'</span>
<span class="token keyword module">import</span> <span class="token imports"><span class="token punctuation">{</span> waitFor<span class="token punctuation">,</span> render<span class="token punctuation">,</span> screen <span class="token punctuation">}</span></span> <span class="token keyword module">from</span> <span class="token string">'@testing-library/react'</span>
<span class="token keyword module">import</span> <span class="token imports">userEvent</span> <span class="token keyword module">from</span> <span class="token string">'@testing-library/user-event'</span>
<span class="token keyword module">import</span> <span class="token imports"><span class="token punctuation">{</span> <span class="token maybe-class-name">Helmet</span> <span class="token punctuation">}</span></span> <span class="token keyword module">from</span> <span class="token string">'react-helmet'</span>

<span class="token function">test</span><span class="token punctuation">(</span><span class="token string">'Increments document title'</span><span class="token punctuation">,</span> <span class="token keyword">async</span> <span class="token keyword">function</span> <span class="token function">test</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token function">render</span><span class="token punctuation">(</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span><span class="token class-name">DocTitleCounter</span></span> <span class="token punctuation">/&gt;</span></span><span class="token punctuation">)</span>
  <span class="token keyword control-flow">await</span> <span class="token function">waitFor</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token arrow operator">=&gt;</span> <span class="token function">expect</span><span class="token punctuation">(</span><span class="token dom variable">document</span><span class="token punctuation">.</span><span class="token property-access">title</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token method function property-access">toEqual</span><span class="token punctuation">(</span><span class="token string">'0'</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
  userEvent<span class="token punctuation">.</span><span class="token method function property-access">click</span><span class="token punctuation">(</span>screen<span class="token punctuation">.</span><span class="token method function property-access">getByRole</span><span class="token punctuation">(</span><span class="token string">'button'</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> <span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token regex"><span class="token regex-delimiter">/</span><span class="token regex-source language-regex">inc</span><span class="token regex-delimiter">/</span><span class="token regex-flags">i</span></span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
  <span class="token keyword control-flow">return</span> <span class="token function">waitFor</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token arrow operator">=&gt;</span> <span class="token function">expect</span><span class="token punctuation">(</span><span class="token dom variable">document</span><span class="token punctuation">.</span><span class="token property-access">title</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token method function property-access">toEqual</span><span class="token punctuation">(</span><span class="token string">'1'</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span>

<span class="token keyword">function</span> <span class="token function"><span class="token maybe-class-name">DocTitleCounter</span></span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">const</span> <span class="token punctuation">[</span>counter<span class="token punctuation">,</span> setCounter<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">useState</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">)</span>

  <span class="token keyword control-flow">return</span> <span class="token punctuation">(</span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span></span><span class="token punctuation">&gt;</span></span><span class="token plain-text">
      </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span><span class="token class-name">Helmet</span></span><span class="token punctuation">&gt;</span></span><span class="token plain-text">
        </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>title</span><span class="token punctuation">&gt;</span></span><span class="token punctuation">{</span><span class="token known-class-name class-name">String</span><span class="token punctuation">(</span>counter<span class="token punctuation">)</span><span class="token punctuation">}</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>title</span><span class="token punctuation">&gt;</span></span><span class="token plain-text">
      </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span><span class="token class-name">Helmet</span></span><span class="token punctuation">&gt;</span></span><span class="token plain-text">
      </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>button</span> <span class="token attr-name">onClick</span><span class="token script language-javascript"><span class="token script-punctuation punctuation">=</span><span class="token punctuation">{</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token arrow operator">=&gt;</span> <span class="token function">setCounter</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">c</span><span class="token punctuation">)</span> <span class="token arrow operator">=&gt;</span> c <span class="token operator">+</span> <span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">}</span></span><span class="token punctuation">&gt;</span></span><span class="token plain-text">inc</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>button</span><span class="token punctuation">&gt;</span></span><span class="token plain-text">;
    </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span></span><span class="token punctuation">&gt;</span></span>
  <span class="token punctuation">)</span>
<span class="token punctuation">}</span>
</code></pre>
<h2>Other resources <a name="other"></a></h2>
<ul>
<li>For more testing recipes check <a href="https://testing-library.com/docs/recipes">testing library documentation</a> and <a href="https://react-testing-examples.com/">React testing examples</a></li>
<li>For readable DOM related assertions take a look at the <a href="https://github.com/testing-library/jest-dom#custom-matchers">custom matchers from jest-dom</a></li>
<li>If you're not sure how to test code that uses a specific library or framework, check its documentation. There's usually a section dedicated to testing.</li>
</ul>
<a name="newsletter"></a>]]></content:encoded>
            <author>João Forja</author>
        </item>
        <item>
            <title><![CDATA[Testing and developing with React and TS: Data structures (part 1)]]></title>
            <link>https://joaoforja.com/articles/testing-and-developing-with-react-ts-pt1</link>
            <guid isPermaLink="false">https://joaoforja.com/articles/testing-and-developing-with-react-ts-pt1</guid>
            <pubDate>Sat, 26 Dec 2020 17:12:03 GMT</pubDate>
            <content:encoded><![CDATA[<p>With this series, I hope to share ideas on developing React components that are safer from bugs and easier to maintain.</p>
<p>To explain and exemplify the principles involved, we'll be building a Multilevel-list. We'll go from requirements to a fully functional React component. Along the way, we'll touch on the topics of:</p>
<ol>
<li>Using TypeScript to:<!-- -->
<ol>
<li>Prevent bugs</li>
<li>Make code safer to change</li>
</ol>
</li>
<li>Designing data structures to reduce possible bugs</li>
<li>Structuring components for testability</li>
<li>What tests to write and at what level</li>
</ol>
<h2>Requirements</h2>
<p>Our Multilevel-list component has the following requirements:</p>
<ol>
<li>Show items content</li>
<li>Collapse sub-lists of items</li>
<li>Expand sub-lists of items</li>
<li>Accessible to key-board users</li>
</ol>
<p>Before we go on, it's important to keep in mind the role and limitations of requirements.</p>
<p>Requirements exist to form an understanding between clients and developers on what we want to build. We know both parties are aligned enough to start development if they can come up with acceptance tests to verify the requirements.</p>
<p>In this context, an acceptance test doesn't imply an automated test. It can be a simple sentence about the system that we can say it's true or false. For example, an acceptance test to verify the requirement "Accessible to keyboard users" could be "We can collapse or expand any sub-list using only the keyboard".</p>
<p>Requirements won't fully specify the software behavior, meaning there will be a margin for interpretation. For example, for "Accessible to keyboard users" we could implement navigation with keyboard arrows or tabs. We make these decisions by using our experience and talking with the client if it impacts the business.</p>
<h2>Defining the views</h2>
<p>After looking at the requirements, we come up with some sketches of the component.</p>
<p><img src="/articles/testing-and-developing-with-react-ts-pt1/multilevel-list-sketch.png" alt="Sketch of multilevel-list" title="Sketches of an empty multilevel-list and a populated one"></p>
<p>Through the sketches, we can start to decompose the component into views.</p>
<p>I suggest we model the Multilevel-list around two entities: lists and items. A list can either be empty or populated with items. An item can either be open, closed, or empty. Open items show populated lists.</p>
<p>In all, we decomposed the component into the below five views:</p>
<p><img src="/articles/testing-and-developing-with-react-ts-pt1/view-states.png" alt="views of multilevel-list" title="Empty list, populated list, open item, empty item, and closed item"></p>
<h2>Designing the data structure</h2>
<p>Now that we've defined the views and know the requirements, we can work on a data structure to support the component.</p>
<p>There are multiple concerns when designing a data structure besides fulfilling behavioral requirements. Required memory, ease of manipulation, and operations performance are some of them. In this article, we'll focus on reducing the space of invalid representations and having a 1 to 1 mapping between types and views. These concerns will minimize the chances for bugs and make the code easier to maintain.</p>
<p>As we've seen earlier, a list can either be empty or populated. An empty list has no items associated, and a populated list has at least one.
We can represent those invariants as follows:</p>
<pre class="language-typescript"><code class="language-typescript"><span class="token keyword">type</span> <span class="token class-name"><span class="token maybe-class-name">MultiLevelList</span></span> <span class="token operator">=</span> <span class="token maybe-class-name">EmptyList</span> <span class="token operator">|</span> <span class="token maybe-class-name">PopulatedList</span>
<span class="token keyword">type</span> <span class="token class-name"><span class="token maybe-class-name">EmptyList</span></span> <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token punctuation">]</span>
<span class="token keyword">type</span> <span class="token class-name"><span class="token maybe-class-name">PopulatedList</span></span> <span class="token operator">=</span> <span class="token maybe-class-name">NonEmptyArray</span><span class="token operator">&lt;</span><span class="token maybe-class-name">Item</span><span class="token operator">&gt;</span>
<span class="token keyword">type</span> <span class="token class-name"><span class="token maybe-class-name">NonEmptyArray</span><span class="token operator">&lt;</span><span class="token constant">T</span><span class="token operator">&gt;</span></span> <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token constant">T</span><span class="token punctuation">,</span> <span class="token spread operator">...</span><span class="token constant">T</span><span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">]</span>
</code></pre>
<p>An item is either empty, opened, or closed. All items have content that's text. Empty items don't have a populated list of items, while closed and open items do.</p>
<pre class="language-typescript"><code class="language-typescript"><span class="token keyword">type</span> <span class="token class-name"><span class="token maybe-class-name">Item</span></span> <span class="token operator">=</span> <span class="token maybe-class-name">OpenItem</span> <span class="token operator">|</span> <span class="token maybe-class-name">ClosedItem</span> <span class="token operator">|</span> <span class="token maybe-class-name">EmptyItem</span>
<span class="token keyword">type</span> <span class="token class-name"><span class="token maybe-class-name">OpenItem</span></span> <span class="token operator">=</span> <span class="token punctuation">{</span>
  id<span class="token operator">:</span> <span class="token builtin">string</span>
  content<span class="token operator">:</span> <span class="token builtin">string</span>
  state<span class="token operator">:</span> <span class="token string">'OPEN'</span>
  children<span class="token operator">:</span> <span class="token maybe-class-name">PopulatedList</span>
<span class="token punctuation">}</span>
<span class="token keyword">type</span> <span class="token class-name"><span class="token maybe-class-name">ClosedItem</span></span> <span class="token operator">=</span> <span class="token punctuation">{</span>
  id<span class="token operator">:</span> <span class="token builtin">string</span>
  content<span class="token operator">:</span> <span class="token builtin">string</span>
  state<span class="token operator">:</span> <span class="token string">'CLOSED'</span>
  children<span class="token operator">:</span> <span class="token maybe-class-name">PopulatedList</span>
<span class="token punctuation">}</span>
<span class="token keyword">type</span> <span class="token class-name"><span class="token maybe-class-name">EmptyItem</span></span> <span class="token operator">=</span> <span class="token punctuation">{</span>
  id<span class="token operator">:</span> <span class="token builtin">string</span>
  content<span class="token operator">:</span> <span class="token builtin">string</span>
  state<span class="token operator">:</span> <span class="token string">'EMPTY'</span>
<span class="token punctuation">}</span>
<span class="token comment">// Note: Although not influencing any view,</span>
<span class="token comment">//  we'll need the id's to render the items using React.</span>
</code></pre>
<h3>Invalid states</h3>
<p>Notice how there's very little room to represent an invalid state of a Multilevel-list. Compare it with the type below that we could also use to represent an Item:</p>
<pre class="language-typescript"><code class="language-typescript"><span class="token keyword">type</span> <span class="token class-name"><span class="token maybe-class-name">Item</span></span> <span class="token operator">=</span> <span class="token punctuation">{</span>
  id<span class="token operator">:</span> <span class="token builtin">string</span>
  content<span class="token operator">:</span> <span class="token builtin">string</span>
  isOpen<span class="token operator">:</span> <span class="token builtin">boolean</span>
  isClosed<span class="token operator">:</span> <span class="token builtin">boolean</span>
  isEmpty<span class="token operator">:</span> <span class="token builtin">boolean</span>
  children<span class="token operator">?</span><span class="token operator">:</span> <span class="token maybe-class-name">PopulatedList</span>
<span class="token punctuation">}</span>
</code></pre>
<p>This structure of Item gives much more margin to represent invalid states. It allows some invariants of Item to be violated, which previously couldn't. For example, it's now possible to describe an item that's simultaneously open and closed. Another example would be an open item that doesn't have an associated list.</p>
<p>Invalid states are a huge source of bugs. If we can structure our data to make those states impossible and rely on a type checker to enforce them, we will:</p>
<ol>
<li>Reduce possible bugs</li>
<li>Make code easier to understand</li>
<li>Save lines of code spent on code to deal with inconsistent states</li>
</ol>
<p>Overall, we'll bring down the development and maintenance costs.</p>
<h3>1 Type to 1 View</h3>
<p>Currently, we have a 1 view to 1 type relation. This allows, when rendering, to code branch over types instead of conditions. This approach's advantage is that now we can rely on TypeScript's <a href="https://www.typescriptlang.org/docs/handbook/unions-and-intersections.html#union-exhaustiveness-checking">exhaustive checking</a> to tell us if we handled all possible views at compile-time.</p>
<p>Following this approach and given the current types, the rendering code will follow the pattern below:</p>
<pre class="language-typescript"><code class="language-typescript"><span class="token keyword control-flow">if</span> <span class="token punctuation">(</span><span class="token function">isEmptyList</span><span class="token punctuation">(</span>list<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword control-flow">return</span> <span class="token operator">&lt;</span>div<span class="token operator">&gt;</span><span class="token comment">/*render empty list*/</span><span class="token operator">&lt;</span><span class="token operator">/</span>div<span class="token operator">&gt;</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>
<span class="token keyword control-flow">if</span> <span class="token punctuation">(</span><span class="token function">isPopulatedList</span><span class="token punctuation">(</span>list<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword control-flow">return</span> <span class="token operator">&lt;</span>div<span class="token operator">&gt;</span><span class="token comment">/*render populated list*/</span><span class="token operator">&lt;</span><span class="token operator">/</span>div<span class="token operator">&gt;</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token function">assertNever</span><span class="token punctuation">(</span>list<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// isEmptyList() and isPopulatedList() are type guards</span>

<span class="token spread operator">...</span>

<span class="token keyword control-flow">switch</span> <span class="token punctuation">(</span>item<span class="token punctuation">.</span><span class="token property-access">state</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">case</span> <span class="token string">"OPEN"</span><span class="token operator">:</span>
    <span class="token keyword control-flow">return</span> <span class="token operator">&lt;</span>div<span class="token operator">&gt;</span><span class="token comment">/*render open item*/</span><span class="token operator">&lt;</span><span class="token operator">/</span>div<span class="token operator">&gt;</span>
  <span class="token keyword">case</span> <span class="token string">"CLOSED"</span><span class="token operator">:</span>
    <span class="token keyword control-flow">return</span> <span class="token operator">&lt;</span>div<span class="token operator">&gt;</span><span class="token comment">/*render closed item*/</span><span class="token operator">&lt;</span><span class="token operator">/</span>div<span class="token operator">&gt;</span>
  <span class="token keyword">case</span> <span class="token string">"EMPTY"</span><span class="token operator">:</span>
    <span class="token keyword control-flow">return</span> <span class="token operator">&lt;</span>div<span class="token operator">&gt;</span><span class="token comment">/*render empty item*/</span><span class="token operator">&lt;</span><span class="token operator">/</span>div<span class="token operator">&gt;</span>
  <span class="token keyword module">default</span><span class="token operator">:</span>
    <span class="token keyword control-flow">return</span> <span class="token function">assertNever</span><span class="token punctuation">(</span>item<span class="token punctuation">)</span>
<span class="token punctuation">}</span>

<span class="token keyword">function</span> <span class="token function">assertNever</span><span class="token punctuation">(</span>x<span class="token operator">:</span> <span class="token builtin">never</span><span class="token punctuation">)</span><span class="token operator">:</span> <span class="token builtin">never</span> <span class="token punctuation">{</span>
  <span class="token keyword control-flow">throw</span> <span class="token keyword">new</span> <span class="token class-name"><span class="token known-class-name class-name">Error</span></span><span class="token punctuation">(</span><span class="token string">"Unexpected object: "</span> <span class="token operator">+</span> x<span class="token punctuation">)</span>
<span class="token punctuation">}</span>
</code></pre>
<p>Exhaustive checking might not seem a big deal when we've just written the code. However, as time goes by and code changes, we'll introduce new types. Forgetting, or not knowing, that there's code we need to update to handle the new type is likely. With exhaustive checking that's not a problem, the compiler will tell us where we have to make changes.</p>
<p>If you want to know more about exhaustive checking and how the compile error happens, you can check the <a href="https://www.typescriptlang.org/docs/handbook/unions-and-intersections.html#union-exhaustiveness-checking">documentation</a>.</p>
<h3>Still room for invalid states?</h3>
<p>You may have noticed that it's still possible to represent some invalid states with the current data structure. In specific, a Multilevel-list can contain the same item twice. This shouldn't happen as it will cause bugs. However, there's no way to enforce this restriction at compile-time. In these situations, it's important to find other options to make the restriction explicit. Documentation is one way to do it.</p>
<p>Taking all into consideration, we end up with the following:</p>
<pre class="language-typescript"><code class="language-typescript"><span class="token comment">/*
 * Invariants:
 *  There shouldn't be repeated Items
 */</span>
<span class="token keyword">type</span> <span class="token class-name"><span class="token maybe-class-name">MultiLevelList</span></span> <span class="token operator">=</span> <span class="token maybe-class-name">EmptyList</span> <span class="token operator">|</span> <span class="token maybe-class-name">PopulatedList</span>
<span class="token keyword">type</span> <span class="token class-name"><span class="token maybe-class-name">EmptyList</span></span> <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token punctuation">]</span>
<span class="token keyword">type</span> <span class="token class-name"><span class="token maybe-class-name">PopulatedList</span></span> <span class="token operator">=</span> <span class="token maybe-class-name">NonEmptyArray</span><span class="token operator">&lt;</span><span class="token maybe-class-name">Item</span><span class="token operator">&gt;</span>
<span class="token keyword">type</span> <span class="token class-name"><span class="token maybe-class-name">NonEmptyArray</span><span class="token operator">&lt;</span><span class="token constant">T</span><span class="token operator">&gt;</span></span> <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token constant">T</span><span class="token punctuation">,</span> <span class="token spread operator">...</span><span class="token constant">T</span><span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">]</span>

<span class="token keyword">type</span> <span class="token class-name"><span class="token maybe-class-name">Item</span></span> <span class="token operator">=</span> <span class="token maybe-class-name">OpenItem</span> <span class="token operator">|</span> <span class="token maybe-class-name">ClosedItem</span> <span class="token operator">|</span> <span class="token maybe-class-name">EmptyItem</span>
<span class="token keyword">type</span> <span class="token class-name"><span class="token maybe-class-name">OpenItem</span></span> <span class="token operator">=</span> <span class="token punctuation">{</span>
  id<span class="token operator">:</span> <span class="token builtin">string</span>
  content<span class="token operator">:</span> <span class="token builtin">string</span>
  state<span class="token operator">:</span> <span class="token string">'OPEN'</span>
  children<span class="token operator">:</span> <span class="token maybe-class-name">PopulatedList</span>
<span class="token punctuation">}</span>
<span class="token keyword">type</span> <span class="token class-name"><span class="token maybe-class-name">ClosedItem</span></span> <span class="token operator">=</span> <span class="token punctuation">{</span>
  id<span class="token operator">:</span> <span class="token builtin">string</span>
  content<span class="token operator">:</span> <span class="token builtin">string</span>
  state<span class="token operator">:</span> <span class="token string">'CLOSED'</span>
  children<span class="token operator">:</span> <span class="token maybe-class-name">PopulatedList</span>
<span class="token punctuation">}</span>
<span class="token keyword">type</span> <span class="token class-name"><span class="token maybe-class-name">EmptyItem</span></span> <span class="token operator">=</span> <span class="token punctuation">{</span>
  id<span class="token operator">:</span> <span class="token builtin">string</span>
  content<span class="token operator">:</span> <span class="token builtin">string</span>
  state<span class="token operator">:</span> <span class="token string">'EMPTY'</span>
<span class="token punctuation">}</span>

<span class="token comment">// Type guards. Necessary to distinguish between types.</span>
<span class="token keyword">function</span> <span class="token function">isPopulatedList</span><span class="token punctuation">(</span>list<span class="token operator">:</span> <span class="token maybe-class-name">MultiLevelList</span><span class="token punctuation">)</span><span class="token operator">:</span> list <span class="token keyword">is</span> <span class="token maybe-class-name">PopulatedList</span> <span class="token punctuation">{</span>
  <span class="token keyword control-flow">return</span> list<span class="token punctuation">.</span><span class="token property-access">length</span> <span class="token operator">&gt;</span> <span class="token number">0</span>
<span class="token punctuation">}</span>
<span class="token keyword">function</span> <span class="token function">isEmptyList</span><span class="token punctuation">(</span>list<span class="token operator">:</span> <span class="token maybe-class-name">MultiLevelList</span><span class="token punctuation">)</span><span class="token operator">:</span> list <span class="token keyword">is</span> <span class="token maybe-class-name">EmptyList</span> <span class="token punctuation">{</span>
  <span class="token keyword control-flow">return</span> list<span class="token punctuation">.</span><span class="token property-access">length</span> <span class="token operator">===</span> <span class="token number">0</span>
<span class="token punctuation">}</span>
</code></pre>
<h2>Next Steps</h2>
<p>In the next article, we'll look at how to structure our multilevel-list component to be easy to test and what tests to write.</p>
<p>If you'd like to be notified when the article comes out, be sure to subscribe to the newsletter below.</p>]]></content:encoded>
            <author>João Forja</author>
        </item>
        <item>
            <title><![CDATA[How to write fewer tests but find more bugs in your React components]]></title>
            <link>https://joaoforja.com/articles/this-is-what-you-can-do-to-know-what-to-test-on-your-react-components</link>
            <guid isPermaLink="false">https://joaoforja.com/articles/this-is-what-you-can-do-to-know-what-to-test-on-your-react-components</guid>
            <pubDate>Thu, 16 Sep 2021 16:12:03 GMT</pubDate>
            <content:encoded><![CDATA[<blockquote>
<p>How in general should I know what to test?</p>
</blockquote>
<p>Whenever we're deciding how to test a component, the main challenge is choosing which tests to write. That's because even a simple function like <code>add(a: number, b: number)</code> has a potentially infinite number of input values it can receive. And since we have limited time and budget we can't do them all. Thus we need to be able to choose a small number of inputs, out of all the possible inputs, that will reveal as many bugs as possible.</p>
<p>To solve this issue, I've been using an approach that combines Input Space Partitioning and Whitebox testing.</p>
<h2>Input space partitioning</h2>
<p>To put it simply, the idea behind Input Space Partitioning is that by analyzing the desired outputs of a piece of code, we can group its inputs such that if the code works for an input of a group, it will also work for any input of that same group. Therefore, we only need to write one test for each group.</p>
<p>Note that inputs include everything that affects the behavior of a component (e.g. props, user action, API response values, etc...), and outputs everything it produces (e.g. rendered elements, API requests, values persisted to storage, etc...).</p>
<p>Take as an example a <a href="https://wiki.c2.com/?FizzBuzzTest">FizzBuzz</a> inspired React component. The component should allow users to type numbers. When given a number that's a multiple of 3 the component should show <code>Fizz</code>, a number multiple of 5 should show <code>Buzz</code>, a number multiple of 3 and 5 should show <code>FizzBuzz</code>, and a number that's multiple of neither 3 or 5 shows the given number.</p>
<table><thead><tr><th>Number</th><th>Renders</th></tr></thead><tbody><tr><td>Multiple of 3 and not 5</td><td>"Fizz"</td></tr><tr><td>Multiple of 5 and not 3</td><td>"Buzz"</td></tr><tr><td>Multiple of 3 and 5</td><td>"FizzBuzz"</td></tr><tr><td>Multiple of neither 3 or 5</td><td>Given number</td></tr></tbody></table>
<p>Following the logic of Input Space Partitioning, the FizzBuzz input domain can be split into four different categories which are represented by the left column of the table above. This means that we only need to write four tests, one for each of the input categories.</p>
<h2>WhiteBox testing</h2>
<p>You might be wondering how can we be sure, just by looking at the description of the behavior of the FizzBuzz component, that we've chosen the minimal amount of tests that will reveal as many bugs as possible. The answer is we can't. And that's why we also rely on Whitebox testing.</p>
<p>Whitebox testing, in this context, means we'll use the knowledge of how a component is implemented to decide which tests to write. By looking at the implementation, we can have a better idea of what bugs we might have and thus allow us to choose tests more cost-effectively.</p>
<h3>Example 1 - Implementation matches the Input Space Partitioning analysis</h3>
<p>If the FizzBuzz code is written as follows, then for each input category, we only need to write one test assertion.</p>
<pre class="language-tsx"><code class="language-tsx"><span class="token keyword">function</span> <span class="token function"><span class="token maybe-class-name">FizzBuzz</span></span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">const</span> <span class="token punctuation">[</span>value<span class="token punctuation">,</span> setValue<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">useState</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span>

  <span class="token keyword">function</span> <span class="token function">fizzBuzz</span><span class="token punctuation">(</span><span class="token builtin">number</span><span class="token operator">:</span> <span class="token builtin">number</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword control-flow">if</span> <span class="token punctuation">(</span><span class="token builtin">number</span> <span class="token operator">%</span> <span class="token number">3</span> <span class="token operator">===</span> <span class="token number">0</span> <span class="token operator">&amp;&amp;</span> <span class="token builtin">number</span> <span class="token operator">%</span> <span class="token number">5</span> <span class="token operator">===</span> <span class="token number">0</span><span class="token punctuation">)</span> <span class="token keyword control-flow">return</span> <span class="token string">'FizzBuzz'</span>
    <span class="token keyword control-flow">if</span> <span class="token punctuation">(</span><span class="token builtin">number</span> <span class="token operator">%</span> <span class="token number">3</span> <span class="token operator">===</span> <span class="token number">0</span><span class="token punctuation">)</span> <span class="token keyword control-flow">return</span> <span class="token string">'Fizz'</span>
    <span class="token keyword control-flow">if</span> <span class="token punctuation">(</span><span class="token builtin">number</span> <span class="token operator">%</span> <span class="token number">5</span> <span class="token operator">===</span> <span class="token number">0</span><span class="token punctuation">)</span> <span class="token keyword control-flow">return</span> <span class="token string">'Buzz'</span>
    <span class="token keyword control-flow">return</span> <span class="token builtin">number</span>
  <span class="token punctuation">}</span>

  <span class="token keyword control-flow">return</span> <span class="token punctuation">(</span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span></span><span class="token punctuation">&gt;</span></span><span class="token plain-text">
      </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>label</span> <span class="token attr-name">htmlFor</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>fizzBuzz<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span><span class="token plain-text">Enter a FizzBuzz number:</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>label</span><span class="token punctuation">&gt;</span></span><span class="token plain-text">
      </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>input</span>
        <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>number<span class="token punctuation">"</span></span>
        <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>fizzBuzz<span class="token punctuation">"</span></span>
        <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>fizzBuzz<span class="token punctuation">"</span></span>
        <span class="token attr-name">value</span><span class="token script language-javascript"><span class="token script-punctuation punctuation">=</span><span class="token punctuation">{</span>value<span class="token punctuation">}</span></span>
        <span class="token attr-name">onChange</span><span class="token script language-javascript"><span class="token script-punctuation punctuation">=</span><span class="token punctuation">{</span><span class="token punctuation">(</span>e<span class="token punctuation">)</span> <span class="token arrow operator">=&gt;</span> <span class="token function">setValue</span><span class="token punctuation">(</span><span class="token known-class-name class-name">Number</span><span class="token punctuation">(</span>e<span class="token punctuation">.</span><span class="token property-access">target</span><span class="token punctuation">.</span><span class="token property-access">value</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">}</span></span>
      <span class="token punctuation">/&gt;</span></span><span class="token plain-text">
      </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>p</span><span class="token punctuation">&gt;</span></span><span class="token punctuation">{</span><span class="token function">fizzBuzz</span><span class="token punctuation">(</span>value<span class="token punctuation">)</span><span class="token punctuation">}</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>p</span><span class="token punctuation">&gt;</span></span><span class="token plain-text">
    </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span></span><span class="token punctuation">&gt;</span></span>
  <span class="token punctuation">)</span>
<span class="token punctuation">}</span>
</code></pre>
<p>The corresponding tests for this implementation would be as follows:</p>
<pre class="language-typescript"><code class="language-typescript">test<span class="token punctuation">.</span><span class="token property-access">each</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">
  number  | result        | description
  </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span><span class="token string">'15'</span><span class="token interpolation-punctuation punctuation">}</span></span><span class="token string"> | </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span><span class="token string">'FizzBuzz'</span><span class="token interpolation-punctuation punctuation">}</span></span><span class="token string"> | </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span><span class="token string">'Multiples of 3 and 5'</span><span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">
  </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span><span class="token string">'6'</span><span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">  | </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span><span class="token string">'Fizz'</span><span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">     | </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span><span class="token string">'Multiples of 3 but not 5'</span><span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">
  </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span><span class="token string">'10'</span><span class="token interpolation-punctuation punctuation">}</span></span><span class="token string"> | </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span><span class="token string">'Buzz'</span><span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">     | </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span><span class="token string">'Multiples of 5 but not 3'</span><span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">
  </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span><span class="token string">'7'</span><span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">  | </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span><span class="token string">'7'</span><span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">        | </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span><span class="token string">'Multiples of neither 3 or 5'</span><span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">
</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">(</span><span class="token string">'$description - $number'</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token builtin">number</span><span class="token punctuation">,</span> result <span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token arrow operator">=&gt;</span> <span class="token punctuation">{</span>
  <span class="token function">render</span><span class="token punctuation">(</span><span class="token operator">&lt;</span><span class="token maybe-class-name">FizzBuzz</span> <span class="token operator">/</span><span class="token operator">&gt;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  userEvent<span class="token punctuation">.</span><span class="token method function property-access">type</span><span class="token punctuation">(</span>screen<span class="token punctuation">.</span><span class="token method function property-access">getByLabelText</span><span class="token punctuation">(</span><span class="token string">'Enter a FizzBuzz number:'</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token builtin">number</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token function">expect</span><span class="token punctuation">(</span>screen<span class="token punctuation">.</span><span class="token method function property-access">getByText</span><span class="token punctuation">(</span>result<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token method function property-access">toBeVisible</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre>
<p>We don't need to write more than one assertion per input domain because with just one assertion we cover all the input domains we determined in the Input Space Analysis, and we cover all the relevant code branches.</p>
<h3>Example 2 - Implementation has more branches than Input Partitions</h3>
<pre class="language-tsx"><code class="language-tsx"><span class="token keyword">function</span> <span class="token function"><span class="token maybe-class-name">FizzBuzz</span></span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">const</span> <span class="token punctuation">[</span>value<span class="token punctuation">,</span> setValue<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">useState</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span>

  <span class="token keyword">function</span> <span class="token function">fizzBuzz</span><span class="token punctuation">(</span><span class="token builtin">number</span><span class="token operator">:</span> <span class="token builtin">number</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword control-flow">if</span> <span class="token punctuation">(</span><span class="token builtin">number</span> <span class="token operator">===</span> <span class="token number">1</span><span class="token punctuation">)</span> <span class="token keyword control-flow">return</span> <span class="token string">'1'</span>
    <span class="token keyword control-flow">if</span> <span class="token punctuation">(</span><span class="token builtin">number</span> <span class="token operator">===</span> <span class="token number">2</span><span class="token punctuation">)</span> <span class="token keyword control-flow">return</span> <span class="token string">'2'</span>
    <span class="token keyword control-flow">if</span> <span class="token punctuation">(</span><span class="token builtin">number</span> <span class="token operator">%</span> <span class="token number">3</span> <span class="token operator">===</span> <span class="token number">0</span> <span class="token operator">&amp;&amp;</span> <span class="token builtin">number</span> <span class="token operator">%</span> <span class="token number">5</span> <span class="token operator">===</span> <span class="token number">0</span><span class="token punctuation">)</span> <span class="token keyword control-flow">return</span> <span class="token string">'FizzBuzz'</span>
    <span class="token keyword control-flow">if</span> <span class="token punctuation">(</span><span class="token builtin">number</span> <span class="token operator">%</span> <span class="token number">3</span> <span class="token operator">===</span> <span class="token number">0</span><span class="token punctuation">)</span> <span class="token keyword control-flow">return</span> <span class="token string">'Fizz'</span>
    <span class="token keyword control-flow">if</span> <span class="token punctuation">(</span><span class="token builtin">number</span> <span class="token operator">%</span> <span class="token number">5</span> <span class="token operator">===</span> <span class="token number">0</span><span class="token punctuation">)</span> <span class="token keyword control-flow">return</span> <span class="token string">'Buzz'</span>
    <span class="token keyword control-flow">return</span> <span class="token builtin">number</span>
  <span class="token punctuation">}</span>

  <span class="token keyword control-flow">return</span> <span class="token comment">// rest as it was...</span>
<span class="token punctuation">}</span>
</code></pre>
<p>If we're given an implementation like the one above, then one test assertion per input domain won't be enough, since the first two branches of the <code>fizzBuzz</code> function won't be covered. So we'll need to adjust the test assertions so we cover everything in the <code>Multiples of neither 3 or 5</code> partition.</p>
<pre class="language-typescript"><code class="language-typescript">test<span class="token punctuation">.</span><span class="token property-access">each</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">
  number  | result        | description
  </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span><span class="token string">'15'</span><span class="token interpolation-punctuation punctuation">}</span></span><span class="token string"> | </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span><span class="token string">'FizzBuzz'</span><span class="token interpolation-punctuation punctuation">}</span></span><span class="token string"> | </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span><span class="token string">'Multiples of 3 and 5'</span><span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">
  </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span><span class="token string">'6'</span><span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">  | </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span><span class="token string">'Fizz'</span><span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">     | </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span><span class="token string">'Multiples of 3 but not 5'</span><span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">
  </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span><span class="token string">'10'</span><span class="token interpolation-punctuation punctuation">}</span></span><span class="token string"> | </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span><span class="token string">'Buzz'</span><span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">     | </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span><span class="token string">'Multiples of 5 but not 3'</span><span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">
  </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span><span class="token string">'7'</span><span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">  | </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span><span class="token string">'7'</span><span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">        | </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span><span class="token string">'Multiples of neither 3 or 5'</span><span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">
  </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span><span class="token string">'1'</span><span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">  | </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span><span class="token string">'1'</span><span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">        | </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span><span class="token string">'Multiples of neither 3 or 5 - special case 1'</span><span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">
  </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span><span class="token string">'2'</span><span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">  | </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span><span class="token string">'2'</span><span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">        | </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span><span class="token string">'Multiples of neither 3 or 5 - special case 2'</span><span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">
</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">(</span><span class="token string">'$description - $number'</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token builtin">number</span><span class="token punctuation">,</span> result <span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token arrow operator">=&gt;</span> <span class="token punctuation">{</span>
  <span class="token function">render</span><span class="token punctuation">(</span><span class="token operator">&lt;</span><span class="token maybe-class-name">FizzBuzz</span> <span class="token operator">/</span><span class="token operator">&gt;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  userEvent<span class="token punctuation">.</span><span class="token method function property-access">type</span><span class="token punctuation">(</span>screen<span class="token punctuation">.</span><span class="token method function property-access">getByLabelText</span><span class="token punctuation">(</span><span class="token string">'Enter a FizzBuzz number:'</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token builtin">number</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token function">expect</span><span class="token punctuation">(</span>screen<span class="token punctuation">.</span><span class="token method function property-access">getByText</span><span class="token punctuation">(</span>result<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token method function property-access">toBeVisible</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre>
<p>One might argue that those first two assertions are simple enough that they're obviously correct and thus not worth testing. That's a fair observation and one of the advantages of this way of testing is exactly that we can take the implementation into account to write fewer tests. I'd still argue that it's a good principle to have every bit of code run at least once during tests, but I wouldn't reject a PR due to this.</p>
<p>In case you're wondering, changing <code>fizzBuzz</code> so we only need one assertion per test is an option. So if you're ever in a situation like this, take the opportunity and try to simplify the code.</p>
<h3>Example 3 - Implementation uses a production-grade library</h3>
<p>Imagine this implementation that uses a library underneath that's been battle-tested. Which tests should we write for it?</p>
<pre class="language-tsx"><code class="language-tsx"><span class="token keyword">function</span> <span class="token function"><span class="token maybe-class-name">FizzBuzz</span></span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">const</span> <span class="token punctuation">[</span>value<span class="token punctuation">,</span> setValue<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">useState</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span>

  <span class="token keyword">function</span> <span class="token function">fizzBuzz</span><span class="token punctuation">(</span><span class="token builtin">number</span><span class="token operator">:</span> <span class="token builtin">number</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword control-flow">return</span> <span class="token function">battleTestedFizzBuzz</span><span class="token punctuation">(</span><span class="token builtin">number</span><span class="token punctuation">)</span>
  <span class="token punctuation">}</span>

  <span class="token keyword control-flow">return</span> <span class="token comment">// rest as it was...</span>
<span class="token punctuation">}</span>
</code></pre>
<p>I'd argue we only need one. Since the underlying library gives us confidence that the FizzBuzz logic works as expected, and the React-specific code is straightforward, just one test to see that the code runs should be enough.</p>
<pre class="language-tsx"><code class="language-tsx"><span class="token function">test</span><span class="token punctuation">(</span><span class="token string">'Runs as expected'</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token arrow operator">=&gt;</span> <span class="token punctuation">{</span>
  <span class="token function">render</span><span class="token punctuation">(</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span><span class="token class-name">FizzBuzz</span></span> <span class="token punctuation">/&gt;</span></span><span class="token punctuation">)</span>
  userEvent<span class="token punctuation">.</span><span class="token method function property-access">type</span><span class="token punctuation">(</span>screen<span class="token punctuation">.</span><span class="token method function property-access">getByLabelText</span><span class="token punctuation">(</span><span class="token string">'Enter a FizzBuzz number:'</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token string">'15'</span><span class="token punctuation">)</span>
  <span class="token function">expect</span><span class="token punctuation">(</span>screen<span class="token punctuation">.</span><span class="token method function property-access">getByText</span><span class="token punctuation">(</span><span class="token string">'FizzBuzz'</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token method function property-access">toBeVisible</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span>
</code></pre>
<h3>Example 4 - Really complex implementation</h3>
<p>To finish these examples, take a look at the project <a href="https://github.com/EnterpriseQualityCoding/FizzBuzzEnterpriseEdition">FizzBuzzEnterpriseEdition</a>. Imagine that somehow the React component communicated with a running instance of that project to know what it should show the user based on its input. What tests would you write for it?</p>
<p>My answer is that I don't know. Aside from picking one test assertion per partition determined in the Input Space Analysis, I have no idea what other inputs to pick. <strong>The code is so complex that it hides the bugs it might have.</strong></p>
<p>All of these examples give us an interesting insight. <strong>The harder the code is to understand, the more test we'll have to write to be confident it works</strong>. Therefore, having a clear logic for what we're implementing is essential to enable effective testing.</p>
<h2>Put it into action</h2>
<p>If you were not familiar with any of the ideas in this article, this can be a lot to process. So here's a summary of how you can put these ideas into practice next time you have to test a component.</p>
<ol>
<li>Start by explicitly defining the behavior of the component.</li>
<li>Make sure that for every possible input you know what the output should be.</li>
<li>Partition the inputs based on the characteristics of the produced outputs.</li>
<li>Look at the implementation of the component.</li>
<li>Verify if one test per input partition is enough or too much.</li>
<li>Write the tests.</li>
</ol>
<h2>Would you like to see a more complex example?</h2>
<p>I wrote a follow-up article to this one where I go over a more complex component and test it using the methodology described in this article. It is available for subscribers of my newsletter. So if you'd like to see it, be sure to subscribe below.</p>]]></content:encoded>
            <author>João Forja</author>
        </item>
        <item>
            <title><![CDATA[Understanding the value of software can help us code better]]></title>
            <link>https://joaoforja.com/articles/understanding-the-value-of-software-can-help-us-code-better</link>
            <guid isPermaLink="false">https://joaoforja.com/articles/understanding-the-value-of-software-can-help-us-code-better</guid>
            <pubDate>Mon, 09 Mar 2020 13:12:03 GMT</pubDate>
            <content:encoded><![CDATA[<blockquote>
<p>I think this is the best way to implement this, but I'm not sure</p>
</blockquote>
<p>One of the constants of software development is decision-making. However, it's not always that clear which decision we should make. That uncertainty can cause us to feel lost and stressed out, and start wondering if we are compromising the quality of our software.</p>
<p>A good strategy we can follow when we're not sure about which decision to make, is to remind ourselves of what really makes our software valuable. If we can keep that in mind, we can better align our decisions to move forward in that direction.</p>
<h2>What makes software valuable</h2>
<p>Software has no intrinsic value. The value of software comes from the positive impact it has on achieving a particular goal or set of goals. Think of it this way, if the website twitter wasn't ever put into production, but the code was written, would the company twitter be valued at the billion $ mark as it is today? My guess is a big no. The twitter website value resides in the revenue it is able to create for its company. If it didn't generate revenue, it would have no value, and the company would probably be out of business by now.</p>
<p>So the question now becomes, <em>what does an app need to do in order for it to achieve the expected goals?</em> From my experience as a project manager, we don't know for sure. In the context of software developed by a company, usually the executives have a faint idea of what the software should do, but it tends to be wrong most of the time. The truth is that it's an exploratory process. We start with those faint ideas and as the software implements those ideas, and we try them on the field, we get a broader view of what steps we should take next. And adjustment by adjustment, change by change, iteration by iteration, we find out what features our software needs to have in order to achieve the goals the company wants.</p>
<p>By keeping in mind that software only has value if it achieves goals, and by looking at the process of discovering what software needs to do, we can infer the properties that makes it valuable. I like to think of them as:</p>
<ol>
<li>Correctness</li>
<li>Maintainability</li>
</ol>
<h3>Correctness</h3>
<p>Correctness can be expressed by answering the question "Does this software fill the requirements we think need to be filled in order to achieve our goals?". If the answer is yes, then the software is correct.</p>
<p>The requirements can go from very domain specific, like adding or removing a To-Do from a list if we're making a to-do app, to more generic requirements, such as performance and browsers support.</p>
<p>Initially, I believed that correctness concerns should always trump maintainability concerns. Nowadays, I'm not so sure. While I still keep the belief that correctness should come first most of the time, there might be situations where fulfilling a given requirement puts such a burden in the software maintainability, that we might be better off trying to get rid of the requirement and finding a new one that may achieve the purposed goal.</p>
<h3>Maintainability</h3>
<p>Maintainability refers to the capacity the software has to adapt to the changing requirements. In other words, we can consider that a piece of software is maintainable if, as time goes by, the cost of adding, removing or changing features does not increase.</p>
<p>Given the process of finding out requirements, we can expect that a piece of software will have to change a lot. And Keep in mind that requirements are ever-changing. Their volatility may decrease as time goes by, but due to the impermanence of our world, they will never be fully stable. Therefore, it is vital for software to be capable of adapting to changes. Otherwise, there will be a day when it will lose its correctness and become worthless.</p>
<h2>Making a decision</h2>
<p>Next time we have to make a decision on our code base, let's remember that correctness and maintainability are what make software valuable. Therefore, every decision we make should either make our code base closer to filling the requirements and/or make it more adaptable to the future.</p>
<p>When in doubt between two seemingly good enough approaches, we should just choose one. It probably won't matter, and if it does, the faster we move the sooner we'll find out.</p>
<p>It's usually pretty easy to find out if our software is correct or not. But knowing if it is maintainable or not, tends to be not that straight forward. If you'd like to know a strategy that will help you make your code more maintainable, you might find this <a href="/articles/how-to-be-more-confident-about-the-quality-of-the-code-of-our-react-applications/">article</a> interesting.</p>]]></content:encoded>
            <author>João Forja</author>
        </item>
        <item>
            <title><![CDATA[Unsure of what tests to write? Here's what that might mean.]]></title>
            <link>https://joaoforja.com/articles/what-being-unsure-on-what-to-test-might-mean</link>
            <guid isPermaLink="false">https://joaoforja.com/articles/what-being-unsure-on-what-to-test-might-mean</guid>
            <pubDate>Mon, 17 Aug 2020 11:00:03 GMT</pubDate>
            <content:encoded><![CDATA[<p>When we're unsure of what to test, the project might be at <em>risk of failure</em>.</p>
<p>Tests turn our client's ideas into <em>unequivocal</em> specifications. They make the bridge between what's on a customer's head and what we need to build. If we can't write tests, we're <em>lost</em> on what we need to program.</p>
<p><strong>That's a fast track to disaster.</strong></p>
<p>We might think it's the client's fault. After all, we're unable to write tests because requirements are vague and volatile.</p>
<p>But pointing fingers never solved any problems.</p>
<h2>So what can we do?</h2>
<p><strong>A really effective strategy is to reduce the scope of the current release.</strong></p>
<p>Smaller deliverables mitigate two common reasons for failure to clarify what software should do:</p>
<ol>
<li>Trying to discuss <em>too many features</em> at once.</li>
<li><em>Insecurity</em> on what the application has to offer to succeed.</li>
</ol>
<p>A narrower scope means we have less to focus on at once. So there's more time and energy to dig deeper and define concrete requirements to guide our acceptance tests.</p>
<p>With less to develop, we can ship faster. Thus, get <em>feedback</em> from the market sooner. That will shed light on what the app should do to satisfy users.</p>
<p>As programmers, it's easy to disregard deliverables as a project manager's responsibility.</p>
<p>However, it's we that <em>find</em> gaps in the specifications. If we stay silent, no one will know misunderstandings exist until the project is delivered.</p>
<p><strong>That may be too late.</strong></p>
<p>Even when we believe management will turn a deaf ear, let's speak up. We might end up <em>saving</em> the project.</p>]]></content:encoded>
            <author>João Forja</author>
        </item>
        <item>
            <title><![CDATA[Why use useState functional update even when everything seems to work]]></title>
            <link>https://joaoforja.com/articles/why_use_usestate_functional_update_even_when_everything_seems_to_work</link>
            <guid isPermaLink="false">https://joaoforja.com/articles/why_use_usestate_functional_update_even_when_everything_seems_to_work</guid>
            <pubDate>Wed, 05 Feb 2020 09:05:00 GMT</pubDate>
            <content:encoded><![CDATA[<p>If you read React documentation on <a href="https://reactjs.org/docs/hooks-reference.html#functional-updates">useState</a> hook functional updates, you'll find a Counter component together with the following information:</p>
<pre class="language-jsx"><code class="language-jsx"><span class="token keyword">function</span> <span class="token function"><span class="token maybe-class-name">Counter</span></span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">const</span> <span class="token punctuation">[</span>count<span class="token punctuation">,</span> setCount<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">useState</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">)</span>
  <span class="token keyword control-flow">return</span> <span class="token punctuation">(</span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span></span><span class="token punctuation">&gt;</span></span><span class="token plain-text">
      Count: </span><span class="token punctuation">{</span>count<span class="token punctuation">}</span><span class="token plain-text">
      </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>button</span> <span class="token attr-name">onClick</span><span class="token script language-javascript"><span class="token script-punctuation punctuation">=</span><span class="token punctuation">{</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token arrow operator">=&gt;</span> <span class="token function">setCount</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">}</span></span><span class="token punctuation">&gt;</span></span><span class="token plain-text">Reset</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>button</span><span class="token punctuation">&gt;</span></span><span class="token plain-text">
      </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>button</span> <span class="token attr-name">onClick</span><span class="token script language-javascript"><span class="token script-punctuation punctuation">=</span><span class="token punctuation">{</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token arrow operator">=&gt;</span> <span class="token function">setCount</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">c</span><span class="token punctuation">)</span> <span class="token arrow operator">=&gt;</span> c <span class="token operator">+</span> <span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">}</span></span><span class="token punctuation">&gt;</span></span><span class="token plain-text">+</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>button</span><span class="token punctuation">&gt;</span></span><span class="token plain-text">
      </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>button</span> <span class="token attr-name">onClick</span><span class="token script language-javascript"><span class="token script-punctuation punctuation">=</span><span class="token punctuation">{</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token arrow operator">=&gt;</span> <span class="token function">setCount</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">c</span><span class="token punctuation">)</span> <span class="token arrow operator">=&gt;</span> c <span class="token operator">-</span> <span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">}</span></span><span class="token punctuation">&gt;</span></span><span class="token plain-text">-</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>button</span><span class="token punctuation">&gt;</span></span><span class="token plain-text">
    </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span></span><span class="token punctuation">&gt;</span></span>
  <span class="token punctuation">)</span>
<span class="token punctuation">}</span>
</code></pre>
<blockquote>
<p>The ”+” and ”-” buttons use the functional form, because the updated value is based on the previous value.</p>
</blockquote>
<p>Now you may be wondering what problems exactly would happen if we used the normal <code>setState</code> form <code>setCount(count+1)</code>, instead of the functional one. After testing, everything still seems to be working fine.</p>
<h2>A first explanation</h2>
<p>Confused by the result, you googled a bit and came across the following explanation:</p>
<blockquote>
<p>User can click on + twice very quick, before the component can re-render, and in the second call the value of count would not be updated</p>
</blockquote>
<p>This explanation is incorrect for the current use case. If + button is clicked twice, that will produce two click events. Given the + button has an event handler which increments the counter value when there's a click event, React will re-render twice. Once for each click event. Even if those two clicks happen before there's an opportunity to re-render.</p>
<p>We can prove this by quickly clicking twice on + button of the Counter below and watching the logs produced from it</p>
<pre class="language-jsx"><code class="language-jsx"><span class="token keyword">function</span> <span class="token function"><span class="token maybe-class-name">Counter</span></span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">const</span> <span class="token punctuation">[</span>count<span class="token punctuation">,</span> setCount<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">useState</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">)</span>
  <span class="token function">useEffect</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token arrow operator">=&gt;</span> <span class="token console class-name">console</span><span class="token punctuation">.</span><span class="token method function property-access">log</span><span class="token punctuation">(</span><span class="token string">'render'</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
  <span class="token keyword control-flow">return</span> <span class="token punctuation">(</span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span></span><span class="token punctuation">&gt;</span></span><span class="token plain-text">
      Count: </span><span class="token punctuation">{</span>count<span class="token punctuation">}</span><span class="token plain-text">
      </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>button</span> <span class="token attr-name">onClick</span><span class="token script language-javascript"><span class="token script-punctuation punctuation">=</span><span class="token punctuation">{</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token arrow operator">=&gt;</span> <span class="token function">setCount</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">}</span></span><span class="token punctuation">&gt;</span></span><span class="token plain-text">Reset</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>button</span><span class="token punctuation">&gt;</span></span><span class="token plain-text">
      </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>button</span>
        <span class="token attr-name">onClick</span><span class="token script language-javascript"><span class="token script-punctuation punctuation">=</span><span class="token punctuation">{</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token arrow operator">=&gt;</span>
          <span class="token console class-name">console</span><span class="token punctuation">.</span><span class="token method function property-access">log</span><span class="token punctuation">(</span><span class="token string">'clicked'</span><span class="token punctuation">)</span> <span class="token operator">||</span> <span class="token function">setCount</span><span class="token punctuation">(</span>count <span class="token operator">+</span> <span class="token number">1</span><span class="token punctuation">)</span> <span class="token operator">||</span> <span class="token function">syncWait</span><span class="token punctuation">(</span><span class="token number">2000</span><span class="token punctuation">)</span>
        <span class="token punctuation">}</span></span>
      <span class="token punctuation">&gt;</span></span><span class="token plain-text">
        +
      </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>button</span><span class="token punctuation">&gt;</span></span><span class="token plain-text">
      </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>button</span> <span class="token attr-name">onClick</span><span class="token script language-javascript"><span class="token script-punctuation punctuation">=</span><span class="token punctuation">{</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token arrow operator">=&gt;</span> <span class="token function">setCount</span><span class="token punctuation">(</span>count <span class="token operator">-</span> <span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">}</span></span><span class="token punctuation">&gt;</span></span><span class="token plain-text">-</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>button</span><span class="token punctuation">&gt;</span></span><span class="token plain-text">
    </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span></span><span class="token punctuation">&gt;</span></span>
  <span class="token punctuation">)</span>
<span class="token punctuation">}</span>

<span class="token comment">// Blocks main thread for a given amount of milliseconds</span>
<span class="token keyword">function</span> <span class="token function">syncWait</span><span class="token punctuation">(</span><span class="token parameter">ms</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">const</span> date <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Date</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
  <span class="token keyword control-flow">while</span> <span class="token punctuation">(</span><span class="token keyword">new</span> <span class="token class-name">Date</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">-</span> date <span class="token operator">&lt;=</span> ms<span class="token punctuation">)</span> <span class="token punctuation">{</span><span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre>
<p>If we do the experiment, we'll see that counter value will be 2, and we'll have the following logs:</p>
<ol>
<li>render - First render of the component before any click.</li>
<li>clicked - Log from first click.</li>
<li>render - First re-render of the component. This will appear 2 seconds after first click.</li>
<li>clicked - Log from second click.</li>
<li>render - Second re-render of the component. This will appear 2 seconds after second click.</li>
</ol>
<p>As we can observe from the logs, React re-rendered twice and no increment to count was lost.</p>
<p>You might have heard that React batches <code>setState</code> calls so that it only re-renders once. And that is true.
But it only applies to <code>setState</code> calls done in event handlers addressing the same event. Which is not our use case. You can read more about how React batches <code>setState</code> calls in the section batching of this <a href="https://overreacted.io/react-as-a-ui-runtime/#batching">post</a></p>
<h2>A second explanation</h2>
<p>So, what's the problem with implementing the counter component with the normal form of <code>setState</code>? From the perspective of code behavior, there's no problem at all. It works just fine. <strong>But developing software is not just about making it work, it's also about making it right</strong>.</p>
<p>By not using the functional form of <code>setState</code> when we're updating state based on the previous state, we're leaving behind code that, as time goes by and the code base changes, can easily create bugs. For instance, as a code base becomes more complex it's easy to lose track of where state is being updated, and we might be making multiple updates in response to the same event. This will result in lost updates. Also, when asynchronous operations get added into the mix, it's really easy to have bugs related to <a href="https://reactjs.org/docs/hooks-faq.html#why-am-i-seeing-stale-props-or-state-inside-my-function">stale state</a> if we're not using the functional form of <code>setState</code>.</p>
<p>The point is, <strong>using the functional <code>setState</code> form when wanting to update state based on previous state, is a better default than using the normal <code>setState</code> form</strong>. The normal form will work some times. The functional form will work every time the normal form works and also in other situations where it won't. So this little decision will move our code closer to be better prepared for future change.</p>
<p>If you're updating state based on previous state and wondering if you should use the functional form or the normal form, use the functional form.</p>]]></content:encoded>
            <author>João Forja</author>
        </item>
    </channel>
</rss>