<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/"
    xmlns:atom="http://www.w3.org/2005/Atom" xmlns:media="http://search.yahoo.com/mrss/" version="2.0">
    <channel>
        
        <title>
            <![CDATA[ react testing library - freeCodeCamp.org ]]>
        </title>
        <description>
            <![CDATA[ Browse thousands of programming tutorials written by experts. Learn Web Development, Data Science, DevOps, Security, and get developer career advice. ]]>
        </description>
        <link>https://www.freecodecamp.org/news/</link>
        <image>
            <url>https://cdn.freecodecamp.org/universal/favicons/favicon.png</url>
            <title>
                <![CDATA[ react testing library - freeCodeCamp.org ]]>
            </title>
            <link>https://www.freecodecamp.org/news/</link>
        </image>
        <generator>Eleventy</generator>
        <lastBuildDate>Tue, 28 Jul 2026 09:16:00 +0000</lastBuildDate>
        <atom:link href="https://www.freecodecamp.org/news/tag/react-testing-library/rss.xml" rel="self" type="application/rss+xml" />
        <ttl>60</ttl>
        
            <item>
                <title>
                    <![CDATA[ How to Test Your Apps using Jest, Testing Library, Cypress, and Supertest ]]>
                </title>
                <description>
                    <![CDATA[ Hi everyone! In this article we're going to talk about testing. I'll give you a good overview of what testing is and an introduction of how you can implement it on your JavaScript projects. We'll use four very popular tools – Jest, Testing library, C... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/test-a-react-app-with-jest-testing-library-and-cypress/</link>
                <guid isPermaLink="false">66d45f22264384a65d5a9528</guid>
                
                    <category>
                        <![CDATA[ Quality Assurance ]]>
                    </category>
                
                    <category>
                        <![CDATA[ React ]]>
                    </category>
                
                    <category>
                        <![CDATA[ react testing library ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Software Testing ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Testing ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ German Cocca ]]>
                </dc:creator>
                <pubDate>Mon, 25 Apr 2022 17:13:36 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2022/04/pexels-rodolfo-clix-1366942.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Hi everyone! In this article we're going to talk about testing. I'll give you a good overview of what testing is and an introduction of how you can implement it on your JavaScript projects. We'll use four very popular tools – Jest, Testing library, Cypress and Supertest.</p>
<p>First we're going to talk about what testing is, why is it a good idea to test our code, and the different kinds of tests that can be implemented.</p>
<p>Then we're going to introduce each of the tools we will be using, and finally we'll give practical examples for vanilla JS code, a front-end React app, and a back-end Node app.</p>
<p>Andiamo via!</p>
<h2 id="heading-table-of-contents">Table of Contents</h2>
<ul>
<li><p><a class="post-section-overview" href="#heading-what-is-testing-and-why-is-it-valuable">What is testing and why is it valuable</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-different-types-of-tests">Different types of tests</a></p>
<ul>
<li><p><a class="post-section-overview" href="#heading-manual-vs-automated-testing">Manual vs Automated testing</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-functional-vs-non-functional-testing">Functional vs Non-functional testing</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-unit-vs-integration-testing-vs-end-to-end-testing">Unit vs Integration vs End-to-end testing</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-white-box-vs-black-box-vs-grey-box-testing">White box vs Black box vs Grey box testing</a></p>
</li>
</ul>
</li>
<li><p><a class="post-section-overview" href="#heading-when-to-test">When to test</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-our-toolset">Our toolset</a></p>
<ul>
<li><p><a class="post-section-overview" href="#heading-what-is-jest">What is Jest</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-what-is-testing-library">What is Testing library</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-what-is-cypress">What is Cypress</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-what-is-supertest">What is Supertest</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-tools-roundup">Tools roundup</a></p>
</li>
</ul>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-test-vanilla-js-code">How to test vanilla JS code</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-test-a-front-end-react-app-with-jest-and-react-testing-library">How to test a front-end React app with Jest and React testing library</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-test-a-front-end-react-app-with-cypress">How to test a front-end React app with Cypress</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-test-a-back-end-node-app">How to test a back-end Node app</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-wrap-up">Wrap up</a></p>
</li>
</ul>
<h1 id="heading-what-is-testing-and-why-is-it-valuable">What is Testing and Why is it Valuable</h1>
<p>Testing is the practice of checking if a piece of software runs as expected. This is often recognized as QA or quality assurance, and aims to reduce to a bare minimum the amount of bugs that get to production.</p>
<p>We test software to identify errors, gaps or missing requirements and fix those things before shipping code to production.</p>
<p>Testing our code thoroughly improves our project's reliability, saves us later bug-fixing time and hence reduces costs, and improves the chance of our customer being fully satisfied with our product.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/04/BvIJ1M5-1.gif" alt="Image" width="600" height="400" loading="lazy"></p>
<p><a target="_blank" href="https://www.youtube.com/watch?v=u6QfIXgjwGQ&amp;t=6s">Here's a nice short video by Fireship</a> introducing some of the concepts we'll talk about later.</p>
<h1 id="heading-different-types-of-tests">Different Types of Tests</h1>
<p>Testing practices can be classified in different types according to many factors. Personally I think there's a lot of mumbo jumbo about this topic, with hundreds of terms that often refer to very similar things. So let's keep it simple and review only the most popular terms and what they mean.</p>
<p>This will help clarify the many ways in which a software can be tested and better understand the tools we're going to present later on.</p>
<h3 id="heading-manual-vs-automated-testing">Manual vs Automated testing</h3>
<p>Depending on the tools we use to test our software, we can classify testing into <strong>manual</strong> or <strong>automated testing</strong>.</p>
<p><strong>Manual testing</strong> is the practice of "clicking around" and manually checking all the features our product has, simulating what an actual user would do.</p>
<p><strong>Automated testing</strong> is done through code, writing programs that check how our application runs.</p>
<p>There're many testing frameworks and libraries we can use for this. When it comes to functional testing (we're going to see what that means in a sec), most libraries work in a similar way:</p>
<ul>
<li><p>First we <strong>define</strong> what piece of code we want to test.</p>
</li>
<li><p>Then we provide that piece of code some sort of <strong>input</strong> or execute an <strong>action</strong> on it.</p>
</li>
<li><p>Then we define what that piece of code <strong>should do</strong> given the input/action we performed.</p>
</li>
<li><p>And finally we will <strong>compare</strong> what that piece of code actually did against what we said it should do.</p>
</li>
</ul>
<p>If it did what we said it should, the test passed. If it didn't, it failed.</p>
<h3 id="heading-functional-vs-non-functional-testing">Functional vs Non-functional testing</h3>
<p><strong>Functional</strong> testing refers to the actual <strong>features of our product</strong>. For example, if we have a blog platform, functional testing should assure the users can create new articles, edit those articles, browse through articles written by other people, and so on.</p>
<p><strong>Non-functional</strong> testing refers to anything that's <strong>not strictly related to the core features</strong> of our product. And that again can be classified into different categories, for example:</p>
<ul>
<li><p><strong>Stress testing</strong> checks how infrastructure responds to heavy usage.</p>
</li>
<li><p><strong>Security testing</strong> checks if an application is vulnerable to common hacking attacks.</p>
</li>
<li><p><strong>Accessibility testing</strong> checks if an application is coded in a way that is accessible for people with different disabilities.</p>
</li>
</ul>
<h3 id="heading-unit-vs-integration-testing-vs-end-to-end-testing">Unit vs Integration testing vs End-to-end testing</h3>
<p>Another way to classify testing is depending how broad or comprehensive it is.</p>
<p><strong>Unit testing</strong> aims to test individual functions, methods or small chunks of code in an independent way. In unit testing, small pieces of code are checked in an isolated way.</p>
<p><strong>Integration testing</strong> checks how individual pieces of code interact with each other and work together. In integration testing, we put pieces together and see if they interact correctly.</p>
<p><strong>End-to-end testing</strong>, also known as E2E, executes programs in a simulated environment that emulates actual user behavior. Having a website as an example, our code would open in an actual browser and all the features would be executed in the same way a user would use them. E2E testing is a lot like manual testing in that sense, but fully automated.</p>
<p>E2E testing is the most broad or comprehensive type of these three, as it evaluates whole features and behaviors, not specific parts of our code.</p>
<h3 id="heading-white-box-vs-black-box-vs-grey-box-testing">White box vs Black box vs Grey box testing</h3>
<p>The last classification we're going to see depends on how much our tests focus on implementation details or user experience.</p>
<p>Let's say we have a simple website with a button that, when it gets clicked, it opens a modal. In our code, the button has a click event listener that executes a function. That function changes the CSS class of our modal HTML element, and that gets the modal rendered in the screen.</p>
<p>We talk about "<strong>white box</strong>" testing when we test <strong>implementation details</strong>. Following the example, under this paradigm we could test that the button click executes the corresponding function, and that after the function execution, the CSS class of our modal element is changed accordingly.</p>
<p>Another way to do this is to forget about implementation all together and just check if the modal is rendered after the button click. We don't care what the CSS class is, or if the corresponding function is executed or not. We just focus on testing <strong>what the user should perceive.</strong> That's "<strong>black box</strong>" testing.</p>
<p>And, as you may have guessed, "grey box" testing is just a combination of the previous two.</p>
<p>One last thing to mention here is that these different types of tests aren't necessarily mutually exclusive. I mean, they can and often are implemented at the same time on the same projects.</p>
<p>It's very common to have both manual and automated testing, functional and non-functional testing, unit and E2E testing ... The idea will always be to try to anticipate and solve the greatest possible number of problems in reasonable time and effort.</p>
<h1 id="heading-when-to-test">When to Test</h1>
<p>This may seem like a simple question at first, but there are actually different approaches to this, too.</p>
<p>Some people like to test their app once it's been fully developed. Others like to write tests at the same time they code the application, and test each feature as it's being developed.</p>
<p>Others like to write tests first before anything else, defining in this way the minimum requirements for the program to accomplish. And then they code the app in a way that passes those tests as fast as possible (this is called <a target="_blank" href="https://en.wikipedia.org/wiki/Test-driven_development">test driven development or TDD</a>).</p>
<p>Once you have an app or a whole feature developed, and you have a test suite in place (a test suite is a group of tests that check a particular feature or an entire app), another common practice is to run your tests each time you make any kind of modification to the codebase, to verify nothing gets broken.</p>
<p>Lastly, if you have a <a target="_blank" href="https://en.wikipedia.org/wiki/CI/CD">CI/CD</a> system in place, it's common to automate the execution of tests before any deployment. So that if any test fails, the deployment is stopped and some kind of alert is dispatched (which of course is always better than seeing your app catch fire on prod 🔥😱).</p>
<p>Same as with test types, it's common to test applications at different times. Each company normally has its own testing schedule or practice to follow, tailored to their needs.</p>
<h1 id="heading-our-toolset">Our Toolset</h1>
<p>Ok, now that we have a clearer idea of what testing is and the types of tests we can perform, let's review the tools we're going to use in our examples.</p>
<p>As mentioned before, there are a lot of different libraries to choose to run our tests. I chose these four because they are some of the most popular when it comes to JavaScript apps, but know there are more options out there. I'll be naming alternatives for most of the tools we'll use in case you'd like to investigate more. 😉</p>
<h2 id="heading-what-is-jest">What is Jest</h2>
<p><a target="_blank" href="https://jestjs.io/">Jest</a> is a JavaScript test-runner. A test-runner is a piece of software that allows you to run tests to evaluate your app. It's an open-source project maintained by Meta (formerly Facebook), and was first open-sourced in 2014.</p>
<p>Side comment: Every time I say "test runner" I picture this. Am I the only one? 🤔</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/04/8gTI-1.gif" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Test runner, not Blade runner!</em></p>
<p>Anyway...you can use Jest in projects that use <a target="_blank" href="https://babeljs.io/">Babel</a>, <a target="_blank" href="https://www.typescriptlang.org/">TypeScript</a>, <a target="_blank" href="https://nodejs.org/en/">Node.js</a>, <a target="_blank" href="https://reactjs.org/">React</a>, <a target="_blank" href="https://angular.io/">Angular</a>, <a target="_blank" href="https://vuejs.org/">Vue.js</a>, <a target="_blank" href="https://svelte.dev/">Svelte</a> and other technologies too. You can install Jest through NPM just like any library and it requires very little configuration to start off.</p>
<p>Jest comes installed by default when setting up React apps with <a target="_blank" href="https://create-react-app.dev/">create-react-app</a>.</p>
<p>Jest is often also called a testing framework, as it comes with many other built-in features besides just running tests (which is not the case with all test runners). Some of those features are:</p>
<ul>
<li><p><strong>Assertion library:</strong> Jest comes with a lot of built-in functions and methods you can use to assert your code (asserting basically means checking if a piece of code behaves like it's expected).</p>
</li>
<li><p><strong>Snapshot testing:</strong> Jest allows you to use snapshots, which are a way of capturing a large object and storing it in memory so you can later on compare it with something else.</p>
</li>
<li><p><strong>Code coverage:</strong> Jest allows you to get code coverage reports of your tests. These reports show what percentage of your code is currently being tested, and you can even see the exact lines of code that aren't currently being covered.</p>
</li>
<li><p><strong>Mocking library:</strong> Jest also works like a mocking library in the sense that it allows you to mock data (like a function or a module) and use that in your tests.</p>
</li>
</ul>
<p>Some well known alternatives to Jest are <a target="_blank" href="https://mochajs.org/">Mocha</a>, <a target="_blank" href="https://jasmine.github.io/">Jasmine</a>, and <a target="_blank" href="https://karma-runner.github.io/latest/index.html">Karma</a>.</p>
<p>Here's <a target="_blank" href="https://www.youtube.com/watch?v=SyHzgcFefBk">a nice little video</a> explaining what Jest is.</p>
<h2 id="heading-what-is-testing-library">What is Testing Library?</h2>
<p>Testing library is not a test runner, but a set of utilities that will work together with a test runner like Jest or Mocha. This utilities are tools we can use to test our code easily and with a deeper focus on user experience (black box testing).</p>
<p>Testing library was developed by <a target="_blank" href="https://kentcdodds.com/">Kent C Dodds</a> (who also happens to be one of the best JS teachers on earth, so I recommend that you follow him).</p>
<p>Quoting <a target="_blank" href="https://testing-library.com/">the official docs:</a></p>
<blockquote>
<p><em>"The Testing Library family of libraries is a very light-weight solution for testing without all the implementation details.</em></p>
<p><em>The main utilities it provides involve querying for nodes similarly to how users would find them. In this way, testing-library helps ensure your tests give you confidence in your UI code."</em></p>
</blockquote>
<p>In plain English, with the testing library we can test UI elements (like a paragraph, a button, a div...) instead of testing the code responsible for rendering the UI.</p>
<p>The principle behind the library is:</p>
<blockquote>
<p><em>"The more your tests resemble the way your software is used, the more confidence they can give you."</em></p>
</blockquote>
<p>... and that's exactly what we mean by "black box" testing. 😉</p>
<p>The testing library is actually a <strong>set of libraries</strong>, each created to achieve the same objective but adapted to work with different technologies such as React, Angular, Vue, Svelte, React Native and more... That's why you might hear "React-testing-library" or "Vue-testing-library". It's the same thing but adapted to work with different technologies.</p>
<p>React-testing-library comes installed by default when setting up React apps with <a target="_blank" href="https://create-react-app.dev/">create-react-app</a>.</p>
<p>An alternative to testing library is <a target="_blank" href="https://enzymejs.github.io/enzyme/">Enzyme</a> (a UI testing set of utilities developed by Airbnb).</p>
<h2 id="heading-what-is-cypress">What is Cypress?</h2>
<p>Cypress is an open source test-runner that allows you to execute your projects in an automated browser, in the same way a user would.</p>
<p>With Cypress, we can program what the browser will do (like visit a URL, click a button, complete and submit a form...) and check that each action is matched with the corresponding response.</p>
<p>What's sweet about this is that the testing resembles A LOT to what the user will experience. And since the whole point of making software is the user, the closer we are to their perspective, the closer we should be to catching the most meaningful bugs in our code. (Plus it's really cool to see an automated browser go through your entire app in just a few seconds... 🤓)</p>
<p>Another nice feature of Cypress is "time travel". On Cypress's automated browser we can see all the test's we've written, and simply hover over them to see a graphical snapshot of its result. It's a very useful thing to better understand what's breaking and when.</p>
<p>Even though it can be used for unit and integration testing, Cypress is mostly used for end-to-end testing as it can easily evaluate complete features in a matter of seconds.</p>
<p>You can use Cypress to test anything that runs in a browser, so you can easily implement it on React, Angular, Vue, and so on.</p>
<p>Unlike Jest and React-Testing-Library, Cypress doesn't come pre-installed with create-react-app. But we can easily install it with NPM or your package manager of choice.</p>
<p>Some alternatives to Cypress are <a target="_blank" href="https://www.selenium.dev/">Selenium</a> and <a target="_blank" href="https://pptr.dev/">Puppeteer</a>.</p>
<p><a target="_blank" href="https://www.youtube.com/watch?v=BQqzfHQkREo">Here's a sweet video by Fireship explaining what Cypress is and how it works.</a></p>
<p>Side comment: ...and every time I talk about Cypress <a target="_blank" href="https://www.youtube.com/watch?v=BV3CYz34ziE">this plays in my mind</a>. 😎</p>
<h2 id="heading-what-is-supertest">What is Supertest?</h2>
<p><a target="_blank" href="https://github.com/visionmedia/supertest">Supertest</a> is a library that simulates HTTP requests. It's super handy to test back-end Node apps together with Jest (as we will see in the coming examples).</p>
<h3 id="heading-tools-roundup">Tools roundup</h3>
<p>As a quick round-up about this topic:</p>
<ul>
<li><p>Jest is the library that we'll use to write and run tests for JavaScript.</p>
</li>
<li><p>Testing library works together with Jest, and provides us with functions and methods to test the UI directly, forgetting about the code behind it.</p>
</li>
<li><p>Cypress runs your app in a simulated browser and checks if actions performed in the UI respond as expected.</p>
</li>
<li><p>Supertest is a library that mocks HTTP requests and it can be used together with Jest to test back-end apps.</p>
</li>
</ul>
<p>Now let's begin with the fun part ...</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/04/giphy-2.gif" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Let the testing begin!!</em></p>
<h1 id="heading-how-to-test-vanilla-js-code">How to Test Vanilla JS Code</h1>
<p>Ok, let's start by testing some simple vanilla JS code. The idea here is to see how we can implement Jest in our project and learn the basics of how it works.</p>
<p>Let's start by creating a new directory in our machine and creating a Node app with <code>npm init -y</code>. Then install Jest by running <code>npm i -D jest</code> (<code>-D</code> saves it as a development dependency).</p>
<p>Now you should see something like this in your <code>package.json</code> file: <code>"devDependencies": { "jest": "^27.5.1" }</code> .</p>
<p>And speaking about it, in your <code>package.json</code>, replace your <code>test</code> script with <code>"test": "jest"</code>. This will allow us to later run our tests by running <code>npm test</code>. ;)</p>
<p>Your entire <code>package.json</code> file should look something like this:</p>
<pre><code class="lang-plaintext">{
  "name": "vanillatesting",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "jest"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "jest": "^27.5.1"
  }
}
</code></pre>
<p>Cool, we're all set to write some JS we can actually test! Create an <code>index.js</code> file and put this code in it:</p>
<pre><code class="lang-plaintext">// index.js
function isPalindrome(string) {
    // O(n)
    // Put a pointer at each extreme of the word and iterate "inwards"
    // At each iteration, check if the pointers represent equal values
    // If this condition isn't accomplished, the word isn't a palindrome
    let left = 0
    let right = string.length-1

    while (left &lt; right) {
        if (string[left] === string[right]) {
            left += 1
            right -= 1
        }
        else return false
    }

    return true
}
</code></pre>
<p>This function is a <a target="_blank" href="https://en.wikipedia.org/wiki/Palindrome">palindrome</a> checker. It receives a string as parameter, and returns <code>true</code> if the string is a palindrome and <code>false</code> if it's not. (This is a classic technical interview question btw, but that's stuff for another article.🤫)</p>
<p>See that we're exporting the function too. Side comment: If you'd like to know more about this and how JS modules work, I recently wrote <a target="_blank" href="https://www.freecodecamp.org/news/modules-in-javascript">an article</a> about it.</p>
<p>Great, so now let's test this function and see if it works as expected. Let's create a file called <code>index.test.js</code>.</p>
<p>This file is where we'll write our tests. The suffix we're using (<code>.test.js</code>) is important here, as Jest will automatically identify the <code>.test</code> files and execute them when we order Jest to test our project.</p>
<p>Jest also identifies files with the <code>.spec</code> suffix, like <code>index.spec.js</code> (for "specification", which refers to the requirements of your project). Personally I prefer <code>.test</code> as it feels more explicit to me, but both work the same.</p>
<p>Now let's write our first tests! Put this within your <code>index.test.js</code> file.</p>
<pre><code class="lang-plaintext">// index.test.js
isPalindrome = require('./index.js')

test('neuquen is palindrom', () =&gt; {
    expect(isPalindrome("neuquen")).toBe(true)
})

test('bariloche is not palindrom', () =&gt; {
    expect(isPalindrome("bariloche")).toBe(false)
})
</code></pre>
<p>Let's recap what we're actually doing:</p>
<ol>
<li><p>Require the function we want to test: <code>isPalindrome = require('./index.js')</code></p>
</li>
<li><p>The <code>test()</code> function is provided by Jest and within it we will put the code we want Jest to execute.</p>
</li>
<li><p><code>test()</code> takes two parameters. The first is a test description, which is a distinctive name that will show on our console when the test is run. We'll see an example in a sec.</p>
</li>
<li><p>The second parameter is a callback, which contains the actual testing code.</p>
</li>
<li><p>Within this callback we're calling the <code>expect()</code> function (also provided by Jest). <code>expect()</code> takes our function as parameter, which itself is receiving a parameter we made up.</p>
</li>
<li><p>Last, we chain the <code>.toBe()</code> function (provided by Jest too) and as parameter we pass it the value we expect <code>isPalindrome()</code> to return for each case. ("neuquen" is a palindrome so our function should return <code>true</code>, and "bariloche" is not, so it should return <code>false</code>.)</p>
</li>
</ol>
<p>One of the things I like the most about Jest is how easy it is to set it up. Another thing I like a lot is how self explanatory its syntax is. Notice that we can easily understand what our tests will evaluate by just reading them.👌</p>
<p>Now let's try this! If we run <code>npm test</code> in our console, we should get the following:</p>
<pre><code class="lang-plaintext">// console
&gt; jest PASS 
./index.test.js
✓ neuquen is palindrom (1 ms)
✓ bariloche is not palindrom

Test Suites: 1 passed, 1
total Tests:       2 passed, 2
total Snapshots:   0
total Time:        0.244 s
Ran all test suites.
</code></pre>
<p>Congratulations, you just passed your first Jest test ever.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/04/mr-miyagi-nod-1.gif" alt="Image" width="600" height="400" loading="lazy"></p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/04/lets-get-this-party-started-yeah-1.gif" alt="Image" width="600" height="400" loading="lazy"></p>
<p>To see how a failing test looks too, let's change our function by editing the <code>return</code> lines.</p>
<pre><code class="lang-plaintext">// index.js
function isPalindrome(string) {
    // O(n)
    // Put a pointr at each extreme of the word and iterate "inwards"
    // At each iteration, check if the pointers represent equal values
    // If this condition isn't accomplished, the word isn't a palindrome
    let left = 0
    let right = string.length-1

    while (left &lt; right) {
        if (string[left] === string[right]) {
            left += 1
            right -= 1
        }
        else return 1
    }

    return 2
}
</code></pre>
<p>Now you should get something like this:</p>
<pre><code class="lang-plaintext">// console
&gt; vanillatesting@1.0.0 test
&gt; jest

 FAIL  ./index.test.js
  ✕ neuquen is palindrom (4 ms)
  ✕ bariloche is not palindrom

  ● neuquen is palindrom

    expect(received).toBe(expected) // Object.is equality

    Expected: true
    Received: 2

      3 | // describe('isPalindrome function', () =&gt; {
      4 |   test('neuquen is palindrom', () =&gt; {
    &gt; 5 |     expect(isPalindrome("neuquen")).toBe(true)
        |                                     ^
      6 |   })
      7 |
      8 |   test('bariloche is not palindrom', () =&gt; {

      at Object.&lt;anonymous&gt; (index.test.js:5:37)

  ● bariloche is not palindrom

    expect(received).toBe(expected) // Object.is equality

    Expected: false
    Received: 1

       7 |
       8 |   test('bariloche is not palindrom', () =&gt; {
    &gt;  9 |     expect(isPalindrome("bariloche")).toBe(false)
         |                                       ^
      10 |   })
      11 | // })
      12 |

      at Object.&lt;anonymous&gt; (index.test.js:9:39)

Test Suites: 1 failed, 1 total
Tests:       2 failed, 2 total
Snapshots:   0 total
Time:        0.28 s, estimated 1 s
Ran all test suites.
</code></pre>
<p>See that you get a nice description of what tests failed and at which point they failed. In our case they failed when we asserted (checked) the return values.</p>
<p>This is very useful and we should always pay attention to these descriptions, as some times our tests may fail because they're not written correctly. And we don't normally write tests for our tests, yet... 😅 So when you see a failing test, first check that it's working as expected and then go review your actual code.</p>
<p>Now let's add and test another function to show some more Jest features:</p>
<pre><code class="lang-plaintext">// index.js
function twoSum(nums, target) {
    // O(n)
    // Iterate the array once
    // At each iteration, calculate the value needed to get to the target, which is target - currentValue
    // If the neededValue exists in the array, return [currentValue, neededValue], else continue iteration
    for (let i = 0; i &lt; nums.length; i++) {
        const neededNum = target - nums[i]
        if (nums.indexOf(neededNum) !== -1 &amp;&amp; nums.indexOf(neededNum) !== i) return [nums[i], nums[nums.indexOf(neededNum)]]
    }
    return false
}

module.exports = { isPalindrome, twoSum }
</code></pre>
<p>This is another classic interview question. The function takes two parameters, an array of numbers and a target value number. What it does is to identify if there are two numbers in the array that add up to the second parameter value. If the two values exist in the array, it returns them in an array, and if they don't, it returns false.</p>
<p>Now let's write some tests for this:</p>
<pre><code class="lang-plaintext">({ isPalindrome, twoSum } = require('./index.js'))

...

test('[2,7,11,15] and 9 returns [2, 7]', () =&gt; {
    expect(twoSum([2,7,11,15], 9)).toEqual([2,7])
})

test('[3,2,4] and 6 returns [2, 4]', () =&gt; {
    expect(twoSum([3,2,4], 6)).toEqual([2,4])
})

test('[3,2,4] and 10 returns false', () =&gt; {
    expect(twoSum([3,2,4], 10)).toBe(false)
})
</code></pre>
<p>See that the structure is almost the same, except we're using a different <strong>matcher</strong> in two of the tests, <code>toEqual()</code>.</p>
<p><strong>Matchers</strong> are the functions Jests provides us with to evaluate values. There are many types of matchers that can be used for many different occasions.</p>
<p>For example, <code>.toBe()</code> is used to evaluate primitives like strings, numbers, or booleans. <code>toEqual()</code> is used to evaluate objects (which covers pretty much everything else in Javascript).</p>
<p>If you need to compare the return value with a number you could use <code>.toBeGreaterThan()</code> or <code>toBeGreaterThanOrEqual()</code> and so on...</p>
<p>To see a full list of the available matchers, <a target="_blank" href="https://jestjs.io/docs/using-matchers">check the docs</a>.</p>
<p>If we run our tests now, we will get the following:</p>
<pre><code class="lang-plaintext">&gt; vanillatesting@1.0.0 test
&gt; jest

 PASS  ./index.test.js
  ✓ neuquen is palindrom (2 ms)
  ✓ bariloche is not palindrom
  ✓ [2,7,11,15] and 9 returns [2, 7] (1 ms)
  ✓ [3,2,4] and 6 returns [2, 4]
  ✓ [3,2,4] and 10 returns false (1 ms)

Test Suites: 1 passed, 1 total
Tests:       5 passed, 5 total
Snapshots:   0 total
Time:        0.256 s, estimated 1 s
Ran all test suites.
</code></pre>
<p>That's cool, but our tests results look a bit messy. And as our tests suite grows, it will probably be harder to identify each separate result.</p>
<p>To help us with this, Jest provides us with a <code>describe()</code> function, which we can use to group tests together and show results in a more schematic way. We can use it like this:</p>
<pre><code class="lang-plaintext">({ isPalindrome, twoSum } = require('./index.js'))

describe('isPalindrome function', () =&gt; {
  test('neuquen is palindrom', () =&gt; {
    expect(isPalindrome("neuquen")).toBe(true)
  })

  test('bariloche is not palindrom', () =&gt; {
    expect(isPalindrome("bariloche")).toBe(false)
  })
})

describe('twoSum function', () =&gt; {
  test('[2,7,11,15] and 9 returns [2, 7]', () =&gt; {
    expect(twoSum([2,7,11,15], 9)).toEqual([2,7])
  })

  test('[3,2,4] and 6 returns [2, 4]', () =&gt; {
    expect(twoSum([3,2,4], 6)).toEqual([2,4])
  })

  test('[3,2,4] and 10 returns false', () =&gt; {
    expect(twoSum([3,2,4], 10)).toBe(false)
  })
})
</code></pre>
<p>The first parameter is the description we want to show for the given group of tests, and the second is a callback that contains our tests. Now if we run <code>npm test</code> again, we get this 😎:</p>
<pre><code class="lang-plaintext">// console
&gt; vanillatesting@1.0.0 test
&gt; jest

 PASS  ./index.test.js
  isPalindrome function
    ✓ neuquen is palindrom (2 ms)
    ✓ bariloche is not palindrom
  twoSum function
    ✓ [2,7,11,15] and 9 returns [2, 7] (1 ms)
    ✓ [3,2,4] and 6 returns [2, 4]
    ✓ [3,2,4] and 10 returns false

Test Suites: 1 passed, 1 total
Tests:       5 passed, 5 total
Snapshots:   0 total
Time:        0.216 s, estimated 1 s
Ran all test suites.
</code></pre>
<h1 id="heading-how-to-test-a-front-end-react-app-with-jest-and-react-testing-library">How to Test a Front-end React App with Jest and React Testing Library</h1>
<p>Now that we know the basics of Jest, let's hop on to see how we can combine it with Testing library to test a React app.</p>
<p>For this we're going to use a dead simple example. Just a page with random text, a button that toggles another piece of text, a text input, and a button that toggles the rendering of the input.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/04/Recording-2022-04-23-at-21.11.24.gif" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Take into account we'll be using <a target="_blank" href="https://create-react-app.dev/">create-react-app</a> to create this app (which has Jest and Testing library installed by default). If you're not using create-react-app, you might need to install both libraries and add some extra config.</p>
<p>We're not going to see any React code here, we're just going to focus on the tests.</p>
<p>The folder structure of our project is the following:</p>
<pre><code class="lang-plaintext">&gt; src
    &gt; components
        - About.jsx
    - App.jsx
    - Index.js
    - setupTests.js
</code></pre>
<p>The <code>setupTests.js</code> file is important here. It's created by default with create-react-app with this content:</p>
<pre><code class="lang-plaintext">// jest-dom adds custom jest matchers for asserting on DOM nodes.
// allows you to do things like:
// expect(element).toHaveTextContent(/react/i)
// learn more: https://github.com/testing-library/jest-dom
import '@testing-library/jest-dom';
</code></pre>
<p>It globally imports the <code>jest-dom</code> library provided by Testing library, which gives us additional Jest matchers we can use to test the DOM (like <code>toHaveTextContent(), toBeInTheDocument()</code>, etc).</p>
<p>We're going to see examples in a bit, but know that some of the functions and matchers we'll use come from here.</p>
<p>Regarding our tests files, the common practice is to have a different test file for each component we're testing.</p>
<p>Regarding where to place them, two common practices are to have them all together in a single folder, like <code>__tests__</code> or similar, or to have each test file in the same folder as the component it's testing.</p>
<p>I prefer the later as I'll often be hopping from the component code to the test code, and it's nice to have them nearby. But trully it doesn't matter. As long as we use the <code>.test</code> or <code>.spec</code> suffixes, Jest will identify and run the files anyway.</p>
<p>Having created our tests files, our folder structure should look like this:</p>
<pre><code class="lang-plaintext">&gt; src
    &gt; components
        - About.jsx
        - About.test.jsx
    - App.jsx
    - Index.js
    - setupTests.js
</code></pre>
<p>Cool! Let's start by testing our <code>About</code> component.</p>
<p>First lets test that it's rendering correctly, like this:</p>
<pre><code class="lang-plaintext">// About.test.jsx
import { render, screen } from '@testing-library/react'
import About from './About'

describe('About', () =&gt; {

  test('About renders correctly', () =&gt; {
    render( &lt;About/&gt; )
    expect(screen.getByText("I'm the about page!")).toBeInTheDocument()
  })

})
</code></pre>
<ul>
<li>See that we start by importing two things from Testing library: <code>import { render, screen } from '@testing-library/react'</code>.</li>
</ul>
<p>The <code>render</code> function takes a React component as a parameter and it will render it so we can test it.</p>
<p><code>screen</code> is an object that comes with lots of queries we can use to test the UI directly, skipping implementation details and focusing on what the user will actually see.</p>
<ul>
<li><p>Then we import our <code>About</code> component: <code>import About from './About'</code></p>
</li>
<li><p>We use the <code>describe</code> and <code>test</code> Jest functions previously mentioned.</p>
</li>
<li><p>We render the <code>About</code> component: <code>render( &lt;About/&gt; )</code></p>
</li>
<li><p>We use the <code>expect</code> Jest function, and as a parameter we use the <code>screen</code> object provided by Testing library. We use its <code>getByText</code> query, which scans the React component for the text we pass as parameter.</p>
</li>
<li><p>To end, we use the Testing library's <code>.toBeInTheDocument()</code> matcher, which just checks if the previous query result is being rendered.</p>
</li>
</ul>
<p>Then we can test that the "Switch state" toggle button works correctly, like this:</p>
<pre><code class="lang-plaintext">// About.test.jsx
import { render, screen } from '@testing-library/react'
import userEvent from '@testing-library/user-event'
import About from './About'

describe('About', () =&gt; {

  ...

  test('Switch state works correctly', async () =&gt; {
    render( &lt;About/&gt; )

    expect(screen.getByText("It's on!")).toBeInTheDocument()
    userEvent.click(screen.getByText('Switch state'))
    expect(screen.getByText("It's rolling!")).toBeInTheDocument()
    userEvent.click(screen.getByText('Switch state'))
    expect(screen.getByText("It's on!")).toBeInTheDocument()
  })

})
</code></pre>
<p>See that we import an additional utility called <code>userEvent</code>. This is an object that contains many methods we can use to simulate user fired events, like clicks, hovers, writting in an input, and so on.</p>
<ul>
<li><p>We first check that the default string is rendered: <code>expect(screen.getByText("It's on!")).toBeInTheDocument()</code></p>
</li>
<li><p>Then we simulate a click and check that the string changes in the screen:</p>
</li>
</ul>
<pre><code class="lang-plaintext">userEvent.click(screen.getByText('Switch state'))
expect(screen.getByText("It's rolling!")).toBeInTheDocument()
</code></pre>
<ul>
<li>And last we simulate another click and check that the string reverses back to default:</li>
</ul>
<pre><code class="lang-plaintext">userEvent.click(screen.getByText('Switch state'))
expect(screen.getByText("It's on!")).toBeInTheDocument()
</code></pre>
<p>To finish, we're going to write another test to verify that the text input and its toggle work correctly.</p>
<pre><code class="lang-plaintext">import { render, screen } from '@testing-library/react'
import userEvent from '@testing-library/user-event'
import About from './About'

describe('About', () =&gt; {

  ...

  test('Input works correctly', async () =&gt; {
    render( &lt;About/&gt; )

    userEvent.type(screen.getByTestId("testInput"), "Testing the test")
    userEvent.click(screen.getByText("Print input"))

    expect(screen.getByText("Testing the test")).toBeInTheDocument()

    userEvent.click(screen.getByText("Print input"))
    expect(screen.queryByText("Testing the test")).not.toBeInTheDocument()
  })


})
</code></pre>
<ul>
<li><p>Again we use the <code>userEvent</code> to simulate text being writen into our input element: <code>userEvent.type(screen.getByTestId("testInput"), "Testing the test")</code></p>
</li>
<li><p>Then we simulate a click on the toggle button, and check for the input text to be in the document:</p>
</li>
</ul>
<pre><code class="lang-plaintext">userEvent.click(screen.getByText("Print input"))
expect(screen.getByText("Testing the test")).toBeInTheDocument()
</code></pre>
<ul>
<li>And we close by simulating another click and checking that the test is no longer present:</li>
</ul>
<pre><code class="lang-plaintext">userEvent.click(screen.getByText("Print input"))
expect(screen.getByText("Testing the test")).toBeInTheDocument()
</code></pre>
<p>You can see how nice the utilities provided by Testing libraries are, and how easy it is to combine them with Jest. 🤓</p>
<p>We can run this specific test file by running <code>npm test -- About.test.jsx</code> and this is the result we get:</p>
<pre><code class="lang-plaintext">// console
PASS  src/components/About.test.jsx
  About
    ✓ About renders correctly (34 ms)
    ✓ Switch state works correctly (66 ms)
    ✓ Input works correctly (67 ms)

Test Suites: 1 passed, 1 total
Tests:       3 passed, 3 total
Snapshots:   0 total
Time:        0.997 s, estimated 1 s
Ran all test suites matching /About.test.jsx/i.
</code></pre>
<p>The last Jest feature I'd like to show you is <strong>test coverage</strong>. You can obtain a coverage report by running <code>npm test -- --coverage</code>.</p>
<p>This will run your tests normally and at the end of the results report you should see something like this:</p>
<pre><code class="lang-plaintext">// console
...

----------------|---------|----------|---------|---------|-------------------
File            | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s 
----------------|---------|----------|---------|---------|-------------------
All files       |      75 |      100 |   85.71 |      70 |                   
 src            |       0 |      100 |       0 |       0 |                   
  App.jsx       |       0 |      100 |       0 |       0 | 7                 
  App.t.js      |       0 |        0 |       0 |       0 |                   
  index.js      |       0 |      100 |     100 |       0 | 5-6               
 src/components |     100 |      100 |     100 |     100 |                   
  About.jsx     |     100 |      100 |     100 |     100 |                   
----------------|---------|----------|---------|---------|-------------------
</code></pre>
<p>In the report we can see that our <code>About.jsx</code> component is completely covered, but our <code>App.jsx</code> and <code>index.js</code> files are not being tested.</p>
<p>This feature is very handy when working on big projects and you want to quickly know if most of your code is being tested correctly.</p>
<h1 id="heading-how-to-test-a-front-end-react-app-with-cypress">How to Test a Front-end React App with Cypress</h1>
<p>We've talked a lot about Jest, so now let's take a look at how we can test our app using Cypress.</p>
<p>We'll start off by installing Cypress by running <code>npm i -D cypress</code>.</p>
<p>This should add this to our <code>package.json</code>:</p>
<pre><code class="lang-plaintext">"devDependencies": {
    "cypress": "^9.5.4"
}
</code></pre>
<p>Then we'll run <code>npx cypress open</code>. This will open the Cypress browser, and create a <code>cypress</code> directory within our project. Within this directory you'll find examples, documentation, and config options.</p>
<p>You'llo also find an "integration" folder, in which we have to put our tests. So let's create our <code>About.test.js</code> file in that folder and replicate the same test examples we've seen with Jest:</p>
<pre><code class="lang-plaintext">// About.test.js
describe('AboutPage', () =&gt; {
    it('Renders correctly', () =&gt; {
        cy.visit('http://localhost:3000/about')
        cy.contains("I'm the about page!")
    })

    it('switch btn toggles text', () =&gt; {
        cy.contains("It's on!")
        cy.get('.switchBtn').click()
        cy.contains("It's rolling!")
        cy.get('.switchBtn').click()
        cy.contains("It's on!")
    })

    it('Input works correctly', () =&gt; {
        cy.get(".testInput").type("Testing the test")
        cy.get('.printInputBtn').click()
        cy.contains("Testing the test")

        cy.get('.printInputBtn').click()
        cy.contains("Testing the test").should('not.exist')
    })
})
</code></pre>
<ul>
<li><p>The <code>describe</code> function works the same as in jest.</p>
</li>
<li><p><code>it()</code> is the same as the <code>test()</code> function we've previously seen.</p>
</li>
<li><p>In the first test we tell the browser to visit our app's URL and check that the corresponding text is rendered:</p>
</li>
</ul>
<pre><code class="lang-plaintext">cy.visit('http://localhost:3000/about')
cy.contains("I'm the about page!")
</code></pre>
<ul>
<li>Then we check that the default toggle text is rendered, simulate a click and check that it changes accordingly:</li>
</ul>
<pre><code class="lang-plaintext">cy.contains("It's on!")
cy.get('.switchBtn').click()
cy.contains("It's rolling!")
cy.get('.switchBtn').click()
cy.contains("It's on!")
</code></pre>
<ul>
<li>And to end we simulate a text input, simulate a click, and check that the input text is rendered:</li>
</ul>
<pre><code class="lang-plaintext">cy.get(".testInput").type("Testing the test")
cy.get('.printInputBtn').click()
cy.contains("Testing the test")

cy.get('.printInputBtn').click()
cy.contains("Testing the test").should('not.exist')
</code></pre>
<p>The syntaxt is slightly different than Jest, but the idea and structure are pretty much the same.🤙</p>
<p>Now if we run <code>npx cypress open</code> again, a window should open with this content:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/04/2022-04-23_22-30.png" alt="2022-04-23_22-30" width="600" height="400" loading="lazy"></p>
<p>We can click on "Run integration spec" and our test will run automatically in the mock browser. After the tests have run, on the left panel we'll see the results:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/04/2022-04-23_22-31.png" alt="2022-04-23_22-31" width="600" height="400" loading="lazy"></p>
<p>We can open those results to see each step the test executed. If we hover over each step, we'll see it executed in the browser in real time. A real sweet feature of Cypress.👌👌</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/04/2022-04-23_22-34.png" alt="2022-04-23_22-34" width="600" height="400" loading="lazy"></p>
<p>As you can see, it's very easy to set up tests with Cypress. And if you're already familiar with Jest, you can quickly pick it up as the syntax is not that different.</p>
<p>If you're wondering if it makes sense to use both Jest and Cypress as test runners in the same project, <a target="_blank" href="https://stackoverflow.com/questions/66217682/should-i-use-both-cypress-and-jest-together">I think this stack-overflow answe</a>r sums it up quite nicely.</p>
<h1 id="heading-how-to-test-a-back-end-node-app">How to Test a Back-end Node App</h1>
<p>Now that we have a basic understanding of the ways we can tests a front-end app, let's cross the river and see how we can use similar tools to test a back end app.</p>
<p>For this we'll use a simple Node and Express API with just 3 endpoints.</p>
<p>Create a directory and run <code>npm init -y</code> to create a Node app. Run <code>npm i express</code> to install Express, and then run <code>npm i -D jest supertest</code> to install both Jest and Supertest as development dependencies.</p>
<p>Inside your <code>package.json</code>, add <code>"scripts": { "test": "jest" }</code>. Your entire <code>package.json</code> should look like this:</p>
<pre><code class="lang-plaintext">{
  "dependencies": {
    "express": "^4.17.3"
  },
  "devDependencies": {
    "jest": "^27.5.1",
    "supertest": "^6.2.2"
  },
    "scripts": {
    "test": "jest"
  }
}
</code></pre>
<p>Then create an <code>app.js</code> file and put this code in it:</p>
<pre><code class="lang-plaintext">// app.js
/* Import and initialize express */
const express = require('express')
const app = express()
const server = require('http').Server(app)
/* Global middlewares */
app.use(express.json())

/* Endpoint 1 */
app.get('/', async (req, res) =&gt; {

    try {
        res.status(200).json({ greeting: "Hello there!" })
    } catch (err) {
        res.status(500).send(err)
    }
})

/* Endpoint 2 */
app.get('/isPalindrome', async (req, res) =&gt; {

    try {
        const string = req.body.string
        let result = true        
        let left = 0
        let right = string.length-1

        while (left &lt; right &amp;&amp; result) {
            if (string[left] === string[right]) {
                left += 1
                right -= 1
            }
            else result = false
        }

        res.status(200).json({ result: result })

    } catch (err) {
        res.status(500).send(err)
    }
})

/* Endpoint 3 */
app.get('/twoSum', async (req, res) =&gt; {

    try {
        const nums = JSON.parse(req.body.nums)
        const target = JSON.parse(req.body.target)

        let result = false

        for (let i = 0; i &lt; nums.length; i++) {
            const neededNum = target - nums[i]
            if (nums.indexOf(neededNum) !== -1 &amp;&amp; nums.indexOf(neededNum) !== i) result = [nums[i], nums[nums.indexOf(neededNum)]]
        }

        res.status(200).json({ result: result })

    } catch (err) {
        res.status(500).send(err)
    }
})

/* Export server object */
module.exports = server

/* Initialize server */
server.listen(3001, () =&gt; console.log('Server is listening.') )
server.on('error', error =&gt; console.error(error) )
</code></pre>
<p>As you can see, endpoint 1 just returns a greeting message. Endpoint 2 and 3 are adaptations of the functions we've seen in our vanilla JS examples. They now receive the parameters within the request and the return values go in the response. 😉</p>
<p>Now the testing! Create an <code>app.test.js</code> file and put this code within it:</p>
<pre><code class="lang-plaintext">// app.test.js
const supertest = require('supertest') // Import supertest
const server = require("./app") // Import the server object
const requestWithSupertest = supertest(server) // We will use this function to mock HTTP requests

afterEach(done =&gt; { // afterEach function is provided by Jest and executes once all tests are finished
    server.close() // We close the server connection once all tests have finished
    done()
})

test('GET "/" returns greeting', async () =&gt; {
    const res = await requestWithSupertest.get('/')
    expect(res.status).toEqual(200)
    expect(res.type).toEqual(expect.stringContaining('json'))
    expect(res.body).toEqual({ greeting: "Hello there!" })
})

describe("/isPalindrome", () =&gt; {
    test('GET "/isPalindrome" neuquen returns true', async () =&gt; {
        const res = await requestWithSupertest.get('/isPalindrome').set('Content-type', 'application/json').send({ "string":"neuquen" })
        expect(res.status).toEqual(200)
        expect(res.type).toEqual(expect.stringContaining('json'))
        expect(res.body).toEqual({ result: true })
    })

    test('GET "/isPalindrome" bariloche returns true', async () =&gt; {
        const res = await requestWithSupertest.get('/isPalindrome').set('Content-type', 'application/json').send({ "string":"bariloche" })
        expect(res.status).toEqual(200)
        expect(res.type).toEqual(expect.stringContaining('json'))
        expect(res.body).toEqual({ result: false })
    })
})

describe("/twoSum", () =&gt; {
    test('GET "/twoSum" [2,7,11,15] and 9 returns [7, 2]', async () =&gt; {
        const res = await requestWithSupertest.get('/twoSum').set('Content-type', 'application/json').send({ "nums":"[2,7,11,15]", "target": "9" })
        expect(res.status).toEqual(200)
        expect(res.type).toEqual(expect.stringContaining('json'))
        expect(res.body).toEqual({ result: [7, 2] })
    })

    test('GET "/twoSum" [3,2,4] and 6 returns [4, 2]', async () =&gt; {
        const res = await requestWithSupertest.get('/twoSum').set('Content-type', 'application/json').send({ "nums":"[3,2,4]", "target": "6" })
        expect(res.status).toEqual(200)
        expect(res.type).toEqual(expect.stringContaining('json'))
        expect(res.body).toEqual({ result: [4, 2] })
    })

    test('GET "/twoSum" [3,2,4] and 10 returns false', async () =&gt; {
        const res = await requestWithSupertest.get('/twoSum').set('Content-type', 'application/json').send({ "nums":"[3,2,4]", "target": "10" })
        expect(res.status).toEqual(200)
        expect(res.type).toEqual(expect.stringContaining('json'))
        expect(res.body).toEqual({ result: false })
    })
})
</code></pre>
<p>Let's analyze what we're doing:</p>
<ul>
<li><p>We mock the request with <code>requestWithSupertest.get('/')</code></p>
</li>
<li><p>Then we "break" the <code>res</code> object in pieces and assert each part of it:</p>
<ul>
<li><p>Check the response status: <code>expect(res.status).toEqual(200)</code></p>
</li>
<li><p>Check the response format: <code>expect(res.type).toEqual(expect.stringContaining('json'))</code></p>
</li>
<li><p>Check the response body content: <code>expect(res.body).toEqual({ greeting: "Hello there!" })</code></p>
</li>
</ul>
</li>
</ul>
<p>The other tests are really similar, except we're sending data in the mock requests bodies, like this:</p>
<pre><code class="lang-plaintext">const res = await requestWithSupertest.get('/isPalindrome').set('Content-type', 'application/json').send({ "string":"bariloche" })
</code></pre>
<p>As you can see, testing in this way is really simple once you're familiar with Jest. We just need a little help by Supertest to mock the HTTP request and the rest is just asserting the response. 👏👏</p>
<p>We can run our tests with <code>npm test</code> and we should get the following response:</p>
<pre><code class="lang-plaintext">// console
 PASS  ./app.test.js
  ✓ GET "/" returns greeting (46 ms)
  /isPalindrome
    ✓ GET "/isPalindrome" neuquen returns true (18 ms)
    ✓ GET "/isPalindrome" bariloche returns true (3 ms)
  /twoSum
    ✓ GET "/twoSum" [2,7,11,15] and 9 returns [7, 2] (4 ms)
    ✓ GET "/twoSum" [3,2,4] and 6 returns [4, 2] (3 ms)
    ✓ GET "/twoSum" [3,2,4] and 10 returns false (2 ms)

Test Suites: 1 passed, 1 total
Tests:       6 passed, 6 total
Snapshots:   0 total
Time:        0.552 s, estimated 1 s
Ran all test suites.
</code></pre>
<h1 id="heading-wrap-up">Wrap up</h1>
<p>And that's it! We've covered the basics of four very popular tools that will allow you to test both the front-end and back-end of your JS apps.</p>
<p>Of course there's much more to all the tools we've seen and many features we haven't covered. But the idea was to give you an introduction so you can take your first steps in the testing world.</p>
<p>As always, I hope you enjoyed the article and learned something new. If you want, you can also follow me on <a target="_blank" href="https://www.linkedin.com/in/germancocca/">linkedin</a> or <a target="_blank" href="https://twitter.com/CoccaGerman">twitter</a>.</p>
<p>Cheers and see you in the next one! =D</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/04/goodbye-bye--1-.gif" alt="Image" width="600" height="400" loading="lazy"></p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Create a Great User Experience with React, TypeScript, and the React Testing Library ]]>
                </title>
                <description>
                    <![CDATA[ By TK I'm always willing to learn, no matter how much I know. As a software engineer, my thirst for knowledge has increased a lot. I know that I have a lot of things to learn daily. But before I could learn more, I wanted to master the fundamentals. ... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/ux-studies-with-react-typescript-and-testing-library/</link>
                <guid isPermaLink="false">66d852c7b56109a3fff9ddc3</guid>
                
                    <category>
                        <![CDATA[ automation testing  ]]>
                    </category>
                
                    <category>
                        <![CDATA[ JavaScript ]]>
                    </category>
                
                    <category>
                        <![CDATA[ react hooks ]]>
                    </category>
                
                    <category>
                        <![CDATA[ react testing library ]]>
                    </category>
                
                    <category>
                        <![CDATA[ React ]]>
                    </category>
                
                    <category>
                        <![CDATA[ TypeScript ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Web Development ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Mon, 22 Jun 2020 09:30:00 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2020/06/cover-2.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By TK</p>
<p>I'm always willing to learn, no matter how much I know. As a software engineer, my thirst for knowledge has increased a lot. I know that I have a lot of things to learn daily.</p>
<p>But before I could learn more, I wanted to master the fundamentals. To make myself a better developer, I wanted to understand more about how to create great product experiences.</p>
<p>This post is my attempt to illustrate a Proof of Concept (PoC) I built to try out some ideas.</p>
<p>I had some topics in mind for this project. It needed to:</p>
<ul>
<li>Use high-quality software</li>
<li>Provide a great user experience</li>
</ul>
<p>When I say high-quality software, this can mean so many different things. But I wanted to focus on three parts:</p>
<ul>
<li>Clean Code: Strive to write human-readable code that is easy to read and simple to maintain. Separate responsibility for functions and components.</li>
<li>Good test coverage: It's actually not about coverage. It's about tests that cover important parts of components' behavior without knowing too much about implementation details.</li>
<li>Consistent state management: I wanted to build with software that enables the app to have consistent data. Predictability is important.</li>
</ul>
<p>User experience was the main focus of this PoC. The software and techniques would be the foundation that enabled a good experience for users.</p>
<p>To make the state consistent, I wanted a type system. So I chose TypeScript. This was my first time using Typescript with React. This project also allowed me to build custom hooks and test it properly.</p>
<h2 id="heading-setting-up-the-project">Setting up the project</h2>
<p>I came across this library called <a target="_blank" href="https://github.com/jaredpalmer/tsdx">tsdx</a> that sets up all the Typescript configuration for you. It's mainly used to build packages. Since this was a simple side project, I didn't mind giving it a try.</p>
<p>After installing it, I chose the React template and I was ready to code. But before the fun part, I wanted to set up the test configuration too. I used the <a target="_blank" href="https://github.com/testing-library/react-testing-library">React Testing Library</a> as the main library together with <a target="_blank" href="https://github.com/testing-library/jest-dom">jest-dom</a> to provide some awesome custom methods (I really like the <code>toBeInTheDocument</code> matcher).</p>
<p>With all that installed, I overwrote the jest config by adding a new <code>jest.config.js</code>:</p>
<pre><code class="lang-typescript"><span class="hljs-built_in">module</span>.<span class="hljs-built_in">exports</span> = {
  verbose: <span class="hljs-literal">true</span>,
  setupFilesAfterEnv: [<span class="hljs-string">"./setupTests.ts"</span>],
};
</code></pre>
<p>And a <code>setupTests.ts</code> to import everything I needed.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> <span class="hljs-string">"@testing-library/jest-dom"</span>;
</code></pre>
<p>In this case, I just had the <code>jest-dom</code> library to import. That way, I didn't need to import this package in my test files. Now it worked out of the box.</p>
<p>To test this installation and configuration, I built a simple component:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> Thing = <span class="hljs-function">() =&gt;</span> &lt;h1&gt;I<span class="hljs-string">'m TK&lt;/h1&gt;;</span>
</code></pre>
<p>In my test, I wanted to render it and see if it was in the DOM.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> React <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;
<span class="hljs-keyword">import</span> { render } <span class="hljs-keyword">from</span> <span class="hljs-string">'@testing-library/react'</span>;
<span class="hljs-keyword">import</span> { Thing } <span class="hljs-keyword">from</span> <span class="hljs-string">'../index'</span>;

describe(<span class="hljs-string">'Thing'</span>, <span class="hljs-function">() =&gt;</span> {
  it(<span class="hljs-string">'renders the correct text in the document'</span>, <span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">const</span> { getByText } = render(&lt;Thing /&gt;);

    expect(getByText(<span class="hljs-string">"I'm TK"</span>)).toBeInTheDocument();
  });
});
</code></pre>
<p>Now we are ready for the next step.</p>
<h2 id="heading-configuring-routes">Configuring routes</h2>
<p>Here I wanted to have only two routes for now. The home page and the search page - even though I'll do nothing about the home page.</p>
<p>For this project, I'm using the <code>react-router-dom</code> library to handle all things router-related. It's simple, easy, and fun to work with.</p>
<p>After installing it, I added the router components in the <code>app.typescript</code>.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { BrowserRouter <span class="hljs-keyword">as</span> Router, Switch, Route } <span class="hljs-keyword">from</span> <span class="hljs-string">'react-router-dom'</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> App = <span class="hljs-function">() =&gt;</span> (
  &lt;Router&gt;
    &lt;Switch&gt;
      &lt;Route path=<span class="hljs-string">"/search"</span>&gt;
        &lt;h1&gt;It<span class="hljs-string">'s the search!&lt;/h1&gt;
      &lt;/Route&gt;
      &lt;Route path="/"&gt;
        &lt;h1&gt;It'</span>s Home&lt;/h1&gt;
      &lt;/Route&gt;
    &lt;/Switch&gt;
  &lt;/Router&gt;
);
</code></pre>
<p>Now if we enter the <code>localhost:1234</code>, we see the title <code>It's Home</code>. Go to the <code>localhost:1234/search</code>, and we'll see the text <code>It's the search!</code>.</p>
<p>Before we continue to start implementing our search page, I wanted to build a simple menu to switch between home and search pages without manipulating the URL. For this project, I'm using <a target="_blank" href="https://material-ui.com/">Material UI</a> to build the UI foundation.</p>
<p>For now, we are just installing the <code>@material-ui/core</code>.</p>
<p>To build the menu, we have the button to open the menu options. In this case they're the "home" and "search" options. </p>
<p>But to build a better component abstraction, I prefer to hide the content (link and label) for the menu items and make the <code>Menu</code> component receive this data as a prop. This way, the menu doesn't know about the items, it will just iterate through the items list and render them.</p>
<p>It looks like this:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> React, { Fragment, useState, MouseEvent } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;
<span class="hljs-keyword">import</span> { Link } <span class="hljs-keyword">from</span> <span class="hljs-string">'react-router-dom'</span>;
<span class="hljs-keyword">import</span> Button <span class="hljs-keyword">from</span> <span class="hljs-string">'@material-ui/core/Button'</span>;
<span class="hljs-keyword">import</span> MuiMenu <span class="hljs-keyword">from</span> <span class="hljs-string">'@material-ui/core/Menu'</span>;
<span class="hljs-keyword">import</span> MuiMenuItem <span class="hljs-keyword">from</span> <span class="hljs-string">'@material-ui/core/MenuItem'</span>;

<span class="hljs-keyword">import</span> { MenuItem } <span class="hljs-keyword">from</span> <span class="hljs-string">'../../types/MenuItem'</span>;

<span class="hljs-keyword">type</span> MenuPropsType = { menuItems: MenuItem[] };

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> Menu = <span class="hljs-function">(<span class="hljs-params">{ menuItems }: MenuPropsType</span>) =&gt;</span> {
  <span class="hljs-keyword">const</span> [anchorEl, setAnchorEl] = useState&lt;<span class="hljs-literal">null</span> | HTMLElement&gt;(<span class="hljs-literal">null</span>);

  <span class="hljs-keyword">const</span> handleClick = (event: MouseEvent&lt;HTMLButtonElement&gt;): <span class="hljs-function"><span class="hljs-params">void</span> =&gt;</span> {
    setAnchorEl(event.currentTarget);
  };

  <span class="hljs-keyword">const</span> handleClose = (): <span class="hljs-function"><span class="hljs-params">void</span> =&gt;</span> {
    setAnchorEl(<span class="hljs-literal">null</span>);
  };

  <span class="hljs-keyword">return</span> (
    &lt;Fragment&gt;
      &lt;Button aria-controls=<span class="hljs-string">"menu"</span> aria-haspopup=<span class="hljs-string">"true"</span> onClick={handleClick}&gt;
        Open Menu
      &lt;/Button&gt;
      &lt;MuiMenu
        id=<span class="hljs-string">"simple-menu"</span>
        anchorEl={anchorEl}
        keepMounted
        open={<span class="hljs-built_in">Boolean</span>(anchorEl)}
        onClose={handleClose}
      &gt;
        {menuItems.map(<span class="hljs-function">(<span class="hljs-params">item: MenuItem</span>) =&gt;</span> (
          &lt;Link to={item.linkTo} onClick={handleClose} key={item.key}&gt;
            &lt;MuiMenuItem&gt;{item.label}&lt;/MuiMenuItem&gt;
          &lt;/Link&gt;
        ))}
      &lt;/MuiMenu&gt;
    &lt;/Fragment&gt;
  );
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> Menu;
</code></pre>
<p>Don't panic! I know it is a huge block of code, but it is pretty simple. the <code>Fragment</code> wrap the <code>Button</code> and <code>MuiMenu</code> (<code>Mui</code> stands for Material UI. I needed to rename the component because the component I'm building is also called menu).</p>
<p>It receives the <code>menuItems</code> as a prop and maps through it to build the menu item wrapped by the <code>Link</code> component. Link is a component from react-router to link to a given URL.</p>
<p>The menu behavior is also simple: we bind the <code>handleClick</code> function to the button's <code>onClick</code>. That way, we can change <code>anchorEl</code> when the button is triggered (or clicked if you prefer). The <code>anchorEl</code> is just a component state that represents the Mui menu element to open the menu switch. So it will open the menu items to let the user chooses one of those.</p>
<p>Now, how do we use this component?</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { Menu } <span class="hljs-keyword">from</span> <span class="hljs-string">'./components/Menu'</span>;
<span class="hljs-keyword">import</span> { MenuItem } <span class="hljs-keyword">from</span> <span class="hljs-string">'./types/MenuItem'</span>;

<span class="hljs-keyword">const</span> menuItems: MenuItem[] = [
  {
    linkTo: <span class="hljs-string">'/'</span>,
    label: <span class="hljs-string">'Home'</span>,
    key: <span class="hljs-string">'link-to-home'</span>,
  },
  {
    linkTo: <span class="hljs-string">'/search'</span>,
    label: <span class="hljs-string">'Search'</span>,
    key: <span class="hljs-string">'link-to-search'</span>,
  },
];

&lt;Menu menuItems={menuItems} /&gt;
</code></pre>
<p>The <code>menuItems</code> is a list of objects. The object has the correct contract expected by the <code>Menu</code> component. The type <code>MenuItem</code> ensures that the contract is correct. It is just a Typescript <code>type</code>:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">export</span> <span class="hljs-keyword">type</span> MenuItem = {
  linkTo: <span class="hljs-built_in">string</span>;
  label: <span class="hljs-built_in">string</span>;
  key: <span class="hljs-built_in">string</span>;
};
</code></pre>
<h2 id="heading-search">Search</h2>
<p>Now we are ready to build the search page with all the products and a great experience. But before building the list of products, I wanted to create a fetch function to handle the request for products. As I don't have an API of products yet, I can just mock the fetch request.</p>
<p>At first, I just built the fetching with <code>useEffect</code> in the <code>Search</code> component. The idea would look like this:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> React, { useState, useEffect } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;
<span class="hljs-keyword">import</span> { getProducts } <span class="hljs-keyword">from</span> <span class="hljs-string">'api'</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> Search = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">const</span> [products, setProducts] = useState([]);
  <span class="hljs-keyword">const</span> [isLoading, setIsLoading] = useState(<span class="hljs-literal">false</span>);
  <span class="hljs-keyword">const</span> [hasError, setHasError] = useState(<span class="hljs-literal">false</span>);

  useEffect(<span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">const</span> fetchProducts = <span class="hljs-keyword">async</span> () =&gt; {
      <span class="hljs-keyword">try</span> {
        setIsLoading(<span class="hljs-literal">true</span>);

        <span class="hljs-keyword">const</span> fetchedProducts = <span class="hljs-keyword">await</span> getProducts();

        setIsLoading(<span class="hljs-literal">false</span>);
        setProducts(fetchedProducts);
      } <span class="hljs-keyword">catch</span> (error) {
        setIsLoading(<span class="hljs-literal">false</span>);
        setHasError(<span class="hljs-literal">true</span>);
      }
    };

    fetchProducts();
  }, []);
};
</code></pre>
<p>I have:</p>
<ul>
<li><code>products</code> initialized as an empty array</li>
<li><code>isLoading</code> initialized as false</li>
<li><code>hasError</code> initialized as false</li>
<li>The <code>fetchProducts</code> is an async function that calls <code>getProducts</code> from the <code>api</code> module. As we don't have a proper API for products yet, this <code>getProducts</code> would return a mock data.</li>
<li>When the <code>fetchProducts</code> is executed, we set the <code>isLoading</code> to true, fetch the products, and then set the <code>isLoading</code> to false, because the fetching finished, and the set the fetched products into <code>products</code> to be used in the component.</li>
<li>If it gets any error in the fetching, we catch them, set the <code>isLoading</code> to false, and the <code>hasError</code> to true. In this context, the component will know that we had an error while fetching and can handle this case.</li>
<li>Everything is encapsulated into a <code>useEffect</code> because we are doing a side effect here.</li>
</ul>
<p>To handle all the state logic (when to update each part for the specific context), we can extract it to a simple reducer.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { State, FetchActionType, FetchAction } <span class="hljs-keyword">from</span> <span class="hljs-string">'./types'</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> fetchReducer = (state: State, action: FetchAction): <span class="hljs-function"><span class="hljs-params">State</span> =&gt;</span> {
  <span class="hljs-keyword">switch</span> (action.type) {
    <span class="hljs-keyword">case</span> FetchActionType.FETCH_INIT:
      <span class="hljs-keyword">return</span> {
        ...state,
        isLoading: <span class="hljs-literal">true</span>,
        hasError: <span class="hljs-literal">false</span>,
      };
    <span class="hljs-keyword">case</span> FetchActionType.FETCH_SUCCESS:
      <span class="hljs-keyword">return</span> {
        ...state,
        hasError: <span class="hljs-literal">false</span>,
        isLoading: <span class="hljs-literal">false</span>,
        data: action.payload,
      };
    <span class="hljs-keyword">case</span> FetchActionType.FETCH_ERROR:
      <span class="hljs-keyword">return</span> {
        ...state,
        hasError: <span class="hljs-literal">true</span>,
        isLoading: <span class="hljs-literal">false</span>,
      };
    <span class="hljs-keyword">default</span>:
      <span class="hljs-keyword">return</span> state;
  }
};
</code></pre>
<p>The idea here is to separate each action type and handle each state update. So the <code>fetchReducer</code> will receive the state and the action and it will return a new state. This part is interesting because it gets the current state and then returns a new state, but we keep the state contract by using the <code>State</code> type.</p>
<p>And for each action type, we will update the state the right way.</p>
<ul>
<li><code>FETCH_INIT</code>: <code>isLoading</code> is true and <code>hasError</code> is false.</li>
<li><code>FETCH_SUCCESS</code>: <code>hasError</code> is false, <code>isLoading</code> is false, and the data (products) is updated.</li>
<li><code>FETCH_ERROR</code>: <code>hasError</code> is true and <code>isLoading</code> is false.</li>
</ul>
<p>In case it doesn't match any action type, just return the current state.</p>
<p>The <code>FetchActionType</code> is a simple Typescript enum:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">export</span> <span class="hljs-built_in">enum</span> FetchActionType {
  FETCH_INIT = <span class="hljs-string">'FETCH_INIT'</span>,
  FETCH_SUCCESS = <span class="hljs-string">'FETCH_SUCCESS'</span>,
  FETCH_ERROR = <span class="hljs-string">'FETCH_ERROR'</span>,
}
</code></pre>
<p>And the <code>State</code> is just a simple type:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">export</span> <span class="hljs-keyword">type</span> ProductType = {
  name: <span class="hljs-built_in">string</span>;
  price: <span class="hljs-built_in">number</span>;
  imageUrl: <span class="hljs-built_in">string</span>;
  description: <span class="hljs-built_in">string</span>;
  isShippingFree: <span class="hljs-built_in">boolean</span>;
  discount: <span class="hljs-built_in">number</span>;
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">type</span> Data = ProductType[];

<span class="hljs-keyword">export</span> <span class="hljs-keyword">type</span> State = {
  isLoading: <span class="hljs-built_in">boolean</span>;
  hasError: <span class="hljs-built_in">boolean</span>;
  data: Data;
};
</code></pre>
<p>With this new reducer, now we can <code>useReducer</code> in our fetch. We pass the new reducer and the initial state to it:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">const</span> initialState: State = {
  isLoading: <span class="hljs-literal">false</span>,
  hasError: <span class="hljs-literal">false</span>,
  data: fakeData,
};

<span class="hljs-keyword">const</span> [state, dispatch] = useReducer(fetchReducer, initialState);

useEffect(<span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">const</span> fetchAPI = <span class="hljs-keyword">async</span> () =&gt; {
    dispatch({ <span class="hljs-keyword">type</span>: FetchActionType.FETCH_INIT });

    <span class="hljs-keyword">try</span> {
      <span class="hljs-keyword">const</span> payload = <span class="hljs-keyword">await</span> fetchProducts();

      dispatch({
        <span class="hljs-keyword">type</span>: FetchActionType.FETCH_SUCCESS,
        payload,
      });
    } <span class="hljs-keyword">catch</span> (error) {
      dispatch({ <span class="hljs-keyword">type</span>: FetchActionType.FETCH_ERROR });
    }
  };

  fetchAPI();
}, []);
</code></pre>
<p>The <code>initialState</code> has the same contract type. And we pass it to the <code>useReducer</code> together with the <code>fetchReducer</code> we just built. The <code>useReducer</code> provides the state and a function called <code>dispatch</code> to call actions to update our state.</p>
<ul>
<li>State fetching: dispatch <code>FETCH_INIT</code></li>
<li>Finished fetch: dispatch <code>FETCH_SUCCESS</code> with the products payload</li>
<li>Get an error while fetching: dispatch <code>FETCH_ERROR</code></li>
</ul>
<p>This abstraction got very big and can be very verbose in our component. We could extract it as a separate hook called <code>useProductFetchAPI</code>.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> useProductFetchAPI = (): <span class="hljs-function"><span class="hljs-params">State</span> =&gt;</span> {
  <span class="hljs-keyword">const</span> initialState: State = {
    isLoading: <span class="hljs-literal">false</span>,
    hasError: <span class="hljs-literal">false</span>,
    data: fakeData,
  };

  <span class="hljs-keyword">const</span> [state, dispatch] = useReducer(fetchReducer, initialState);

  useEffect(<span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">const</span> fetchAPI = <span class="hljs-keyword">async</span> () =&gt; {
      dispatch({ <span class="hljs-keyword">type</span>: FetchActionType.FETCH_INIT });

      <span class="hljs-keyword">try</span> {
        <span class="hljs-keyword">const</span> payload = <span class="hljs-keyword">await</span> fetchProducts();

        dispatch({
          <span class="hljs-keyword">type</span>: FetchActionType.FETCH_SUCCESS,
          payload,
        });
      } <span class="hljs-keyword">catch</span> (error) {
        dispatch({ <span class="hljs-keyword">type</span>: FetchActionType.FETCH_ERROR });
      }
    };

    fetchAPI();
  }, []);

  <span class="hljs-keyword">return</span> state;
};
</code></pre>
<p>It is just a function that wraps our fetch operation. Now, in the <code>Search</code> component, we can import and call it.</p>
<pre><code><span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> Search = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">const</span> { isLoading, hasError, data }: State = useProductFetchAPI();
};
</code></pre><p>We have all the API: <code>isLoading</code>, <code>hasError</code>, and <code>data</code> to use in our component. With this API, we can render a loading spinner or a skeleton based on the <code>isLoading</code> data. We can render an error message based on the <code>hasError</code> value. Or just render the list of products using the <code>data</code>.</p>
<p>Before starting implementing our products list, I want to stop and add tests for our custom hook. We have two parts to test here: the reducer and the custom hook.</p>
<p>The reducer is easier as it is just a pure function. It receives value, process, and returns a new value. No side-effect. Everything deterministic.</p>
<p>To cover all the possibilities of this reducer, I created three contexts: <code>FETCH_INIT</code>, <code>FETCH_SUCCESS</code>, and <code>FETCH_ERROR</code> actions.</p>
<p>Before implementing anything, I set up the initial data to work with.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">const</span> initialData: Data = [];
<span class="hljs-keyword">const</span> initialState: State = {
  isLoading: <span class="hljs-literal">false</span>,
  hasError: <span class="hljs-literal">false</span>,
  data: initialData,
};
</code></pre>
<p>Now I can pass this initial state for the reducer together with the specific action I want to cover. For this first test, I wanted to cover the <code>FETCH_INIT</code> action:</p>
<pre><code class="lang-typescript">describe(<span class="hljs-string">'when dispatch FETCH_INIT action'</span>, <span class="hljs-function">() =&gt;</span> {
  it(<span class="hljs-string">'returns the isLoading as true without any error'</span>, <span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">const</span> action: FetchAction = {
      <span class="hljs-keyword">type</span>: FetchActionType.FETCH_INIT,
    };

    expect(fetchReducer(initialState, action)).toEqual({
      isLoading: <span class="hljs-literal">true</span>,
      hasError: <span class="hljs-literal">false</span>,
      data: initialData,
    });
  });
});
</code></pre>
<p>It's pretty simple. It receives the initial state and the action, and we expect the proper return value: the new state with the <code>isLoading</code> as <code>true</code>.</p>
<p>The <code>FETCH_ERROR</code> is pretty similar:</p>
<pre><code class="lang-typescript">describe(<span class="hljs-string">'when dispatch FETCH_ERROR action'</span>, <span class="hljs-function">() =&gt;</span> {
  it(<span class="hljs-string">'returns the isLoading as true without any error'</span>, <span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">const</span> action: FetchAction = {
      <span class="hljs-keyword">type</span>: FetchActionType.FETCH_ERROR,
    };

    expect(fetchReducer(initialState, action)).toEqual({
      isLoading: <span class="hljs-literal">false</span>,
      hasError: <span class="hljs-literal">true</span>,
      data: [],
    });
  });
});
</code></pre>
<p>But we pass a different action and expect the <code>hasError</code> to be <code>true</code>.</p>
<p>The <code>FETCH_SUCCESS</code> is a bit complex as we just need to build a new state and add it to the payload attribute in the action.</p>
<pre><code class="lang-typescript">describe(<span class="hljs-string">'when dispatch FETCH_SUCCESS action'</span>, <span class="hljs-function">() =&gt;</span> {
  it(<span class="hljs-string">'returns the the API data'</span>, <span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">const</span> product: ProductType = {
      name: <span class="hljs-string">'iPhone'</span>,
      price: <span class="hljs-number">3500</span>,
      imageUrl: <span class="hljs-string">'image-url.png'</span>,
      description: <span class="hljs-string">'Apple mobile phone'</span>,
      isShippingFree: <span class="hljs-literal">true</span>,
      discount: <span class="hljs-number">0</span>,
    };

    <span class="hljs-keyword">const</span> action: FetchAction = {
      <span class="hljs-keyword">type</span>: FetchActionType.FETCH_SUCCESS,
      payload: [product],
    };

    expect(fetchReducer(initialState, action)).toEqual({
      isLoading: <span class="hljs-literal">false</span>,
      hasError: <span class="hljs-literal">false</span>,
      data: [product],
    });
  });
});
</code></pre>
<p>But nothing too complex here. The new data is there. A list of products. In this case, just one, the iPhone product.</p>
<p>The second test will cover the custom hook we built. In these tests, I wrote three contexts: a time-out request, a failed network request, and a success request.</p>
<p>Here, as I'm using <code>axios</code> to fetch data (when I have an API to fetch the data, I will use it properly), I'm using <code>axios-mock-adapter</code> to mock each context for our tests.</p>
<p>The set up first: Initializing our data and set up an axios mock.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">const</span> mock: MockAdapter = <span class="hljs-keyword">new</span> MockAdapter(axios);
<span class="hljs-keyword">const</span> url: <span class="hljs-built_in">string</span> = <span class="hljs-string">'/search'</span>;
<span class="hljs-keyword">const</span> initialData: Data = [];
</code></pre>
<p>We start implementing a test for the timeout request:</p>
<pre><code class="lang-typescript">it(<span class="hljs-string">'handles error on timed-out api request'</span>, <span class="hljs-keyword">async</span> () =&gt; {
  mock.onGet(url).timeout();

  <span class="hljs-keyword">const</span> { result, waitForNextUpdate } = renderHook(<span class="hljs-function">() =&gt;</span>
    useProductFetchAPI(url, initialData)
  );

  <span class="hljs-keyword">await</span> waitForNextUpdate();

  <span class="hljs-keyword">const</span> { isLoading, hasError, data }: State = result.current;

  expect(isLoading).toEqual(<span class="hljs-literal">false</span>);
  expect(hasError).toEqual(<span class="hljs-literal">true</span>);
  expect(data).toEqual(initialData);
});
</code></pre>
<p>We set up the mock to return a timeout. The test calls the <code>useProductFetchAPI</code>, wait for an update, and then we can get the state. The <code>isLoading</code> is false, the <code>data</code> is still the same (an empty list), and the <code>hasError</code> is now true as expected.</p>
<p>The network request is pretty much the same behavior. The only difference is that the mock will have a network error instead of a timeout.</p>
<pre><code class="lang-typescript">it(<span class="hljs-string">'handles error on failed network api request'</span>, <span class="hljs-keyword">async</span> () =&gt; {
  mock.onGet(url).networkError();

  <span class="hljs-keyword">const</span> { result, waitForNextUpdate } = renderHook(<span class="hljs-function">() =&gt;</span>
    useFetchAPI(url, initialData)
  );

  <span class="hljs-keyword">await</span> waitForNextUpdate();

  <span class="hljs-keyword">const</span> { isLoading, hasError, data }: State = result.current;

  expect(isLoading).toEqual(<span class="hljs-literal">false</span>);
  expect(hasError).toEqual(<span class="hljs-literal">true</span>);
  expect(data).toEqual(initialData);
});
</code></pre>
<p>And for the success case, we need to create a product object to use it as a request-response data. We also expect the <code>data</code> to be a list of this product object. The <code>hasError</code> and the <code>isLoading</code> are false in this case.</p>
<pre><code class="lang-typescript">it(<span class="hljs-string">'gets and updates data from the api request'</span>, <span class="hljs-keyword">async</span> () =&gt; {
  <span class="hljs-keyword">const</span> product: ProductType = {
    name: <span class="hljs-string">'iPhone'</span>,
    price: <span class="hljs-number">3500</span>,
    imageUrl: <span class="hljs-string">'image-url.png'</span>,
    description: <span class="hljs-string">'Apple mobile phone'</span>,
    isShippingFree: <span class="hljs-literal">true</span>,
    discount: <span class="hljs-number">0</span>,
  };

  <span class="hljs-keyword">const</span> mockedResponseData: Data = [product];

  mock.onGet(url).reply(<span class="hljs-number">200</span>, mockedResponseData);

  <span class="hljs-keyword">const</span> { result, waitForNextUpdate } = renderHook(<span class="hljs-function">() =&gt;</span>
    useFetchAPI(url, initialData)
  );

  <span class="hljs-keyword">await</span> waitForNextUpdate();

  <span class="hljs-keyword">const</span> { isLoading, hasError, data }: State = result.current;

  expect(isLoading).toEqual(<span class="hljs-literal">false</span>);
  expect(hasError).toEqual(<span class="hljs-literal">false</span>);
  expect(data).toEqual([product]);
});
</code></pre>
<p>Great. We covered everything we needed for this custom hook and the reducer we created. Now we can focus on building the products list.</p>
<h2 id="heading-products-list">Products list</h2>
<p>The idea of the products list is to list products that have some information: title, description, price, discount, and if it has free shipping. The final product card would look like this:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/06/Screen-Shot-2020-06-06-at-15.52.17.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>To build this card, I created the foundation for the product component:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">const</span> Product = <span class="hljs-function">() =&gt;</span> (
  &lt;Box&gt;
    &lt;Image /&gt;
    &lt;TitleDescription/&gt;
    &lt;Price /&gt;
    &lt;Tag /&gt;
  &lt;/Box&gt;
);
</code></pre>
<p>To build the product, we will need to build each component that is inside it.</p>
<p>But before start building the product component, I want to show the <code>JSON</code> data that the fake API will return for us.</p>
<pre><code class="lang-typescript">{
  imageUrl: <span class="hljs-string">'a-url-for-tokyo-tower.png'</span>,
  name: <span class="hljs-string">'Tokyo Tower'</span>,
  description: <span class="hljs-string">'Some description here'</span>,
  price: <span class="hljs-number">45</span>,
  discount: <span class="hljs-number">20</span>,
  isShippingFree: <span class="hljs-literal">true</span>,
}
</code></pre>
<p>This data is passed from the <code>Search</code> component to the <code>ProductList</code> component:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> Search = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">const</span> { isLoading, hasError, data }: State = useProductFetchAPI();

  <span class="hljs-keyword">if</span> (hasError) {
    <span class="hljs-keyword">return</span> &lt;h2&gt;<span class="hljs-built_in">Error</span>&lt;/h2&gt;;
  }

  <span class="hljs-keyword">return</span> &lt;ProductList products={data} isLoading={isLoading} /&gt;;
};
</code></pre>
<p>As I'm using Typescript, I can enforce the static types for the component props. In this case, I have the prop <code>products</code> and the <code>isLoading</code>.</p>
<p>I built a <code>ProductListPropsType</code> type to handle the product list props.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">type</span> ProductListPropsType = {
  products: ProductType[];
  isLoading: <span class="hljs-built_in">boolean</span>;
};
</code></pre>
<p>And the <code>ProductType</code> is a simple type representing the product:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">export</span> <span class="hljs-keyword">type</span> ProductType = {
  name: <span class="hljs-built_in">string</span>;
  price: <span class="hljs-built_in">number</span>;
  imageUrl: <span class="hljs-built_in">string</span>;
  description: <span class="hljs-built_in">string</span>;
  isShippingFree: <span class="hljs-built_in">boolean</span>;
  discount: <span class="hljs-built_in">number</span>;
};
</code></pre>
<p>To build the ProductList, I'll use the <code>Grid</code> component from Material UI. First, we have a grid container and then, for each product, we will render a grid item.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> ProductList = <span class="hljs-function">(<span class="hljs-params">{ products, isLoading }: ProductListPropsType</span>) =&gt;</span> (
  &lt;Grid container spacing={<span class="hljs-number">3</span>}&gt;
    {products.map(<span class="hljs-function"><span class="hljs-params">product</span> =&gt;</span> (
      &lt;Grid
        item
        xs={<span class="hljs-number">6</span>}
        md={<span class="hljs-number">3</span>}
        key={<span class="hljs-string">`grid-<span class="hljs-subst">${product.name}</span>-<span class="hljs-subst">${product.description}</span>-<span class="hljs-subst">${product.price}</span>`</span>}
      &gt;
        &lt;Product
          key={<span class="hljs-string">`product-<span class="hljs-subst">${product.name}</span>-<span class="hljs-subst">${product.description}</span>-<span class="hljs-subst">${product.price}</span>`</span>}
          imageUrl={product.imageUrl}
          name={product.name}
          description={product.description}
          price={product.price}
          discount={product.discount}
          isShippingFree={product.isShippingFree}
          isLoading={isLoading}
        /&gt;
      &lt;/Grid&gt;
    ))}
  &lt;/Grid&gt;
);
</code></pre>
<p>The <code>Grid</code> item will display 2 items per row for mobile as we use the value <code>6</code> for each column. And for the desktop version, it will render 4 items per row.</p>
<p>We iterate through the <code>products</code> list and render the <code>Product</code> component passing all the data it will need.</p>
<p>Now we can focus on building the <code>Product</code> component.</p>
<p>Let's start with the easiest one: the <code>Tag</code>. We will pass three data to this component. <code>label</code>, <code>isVisible</code>, and <code>isLoading</code>. When it is not visible, we just return <code>null</code> to don't render it. If it is loading, we will render a <code>Skeleton</code> component from Material UI. But after loading it, we render the tag info with the <code>Free Shipping</code> label.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> Tag = <span class="hljs-function">(<span class="hljs-params">{ label, isVisible, isLoading }: TagProps</span>) =&gt;</span> {
  <span class="hljs-keyword">if</span> (!isVisible) <span class="hljs-keyword">return</span> <span class="hljs-literal">null</span>;
  <span class="hljs-keyword">if</span> (isLoading) {
    <span class="hljs-keyword">return</span> (
      &lt;Skeleton width=<span class="hljs-string">"110px"</span> height=<span class="hljs-string">"40px"</span> data-testid=<span class="hljs-string">"tag-skeleton-loader"</span> /&gt;
    );
  }

  <span class="hljs-keyword">return</span> (
    &lt;Box mt={<span class="hljs-number">1</span>} data-testid=<span class="hljs-string">"tag-label-wrapper"</span>&gt;
      &lt;span style={tabStyle}&gt;{label}&lt;/span&gt;
    &lt;/Box&gt;
  );
};
</code></pre>
<p>The <code>TagProps</code> is a simple type:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">type</span> TagProps = {
  label: <span class="hljs-built_in">string</span>;
  isVisible: <span class="hljs-built_in">boolean</span>;
  isLoading: <span class="hljs-built_in">boolean</span>;
};
</code></pre>
<p>I'm also using an object to style the <code>span</code>:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">const</span> tabStyle = {
  padding: <span class="hljs-string">'4px 8px'</span>,
  backgroundColor: <span class="hljs-string">'#f2f3fe'</span>,
  color: <span class="hljs-string">'#87a7ff'</span>,
  borderRadius: <span class="hljs-string">'4px'</span>,
};
</code></pre>
<p>I also wanted to build tests for this component trying to think of its behavior:</p>
<ul>
<li>when it's not visible: the tag will not be in the document.</li>
</ul>
<pre><code class="lang-typescript">describe(<span class="hljs-string">'when is not visible'</span>, <span class="hljs-function">() =&gt;</span> {
  it(<span class="hljs-string">'does not render anything'</span>, <span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">const</span> { queryByTestId } = render(
      &lt;Tag label=<span class="hljs-string">"a label"</span> isVisible={<span class="hljs-literal">false</span>} isLoading={<span class="hljs-literal">false</span>} /&gt;
    );

    expect(queryByTestId(<span class="hljs-string">'tag-label-wrapper'</span>)).not.toBeInTheDocument();
  });
});
</code></pre>
<ul>
<li>when it's loading: the skeleton will be in the document.</li>
</ul>
<pre><code class="lang-typescript">describe(<span class="hljs-string">'when is loading'</span>, <span class="hljs-function">() =&gt;</span> {
  it(<span class="hljs-string">'renders the tag label'</span>, <span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">const</span> { queryByTestId } = render(
      &lt;Tag label=<span class="hljs-string">"a label"</span> isVisible isLoading /&gt;
    );

    expect(queryByTestId(<span class="hljs-string">'tag-skeleton-loader'</span>)).toBeInTheDocument();
  });
});
</code></pre>
<ul>
<li>when it's ready to render: the tag will be in the document.</li>
</ul>
<pre><code class="lang-typescript">describe(<span class="hljs-string">'when is visible and not loading'</span>, <span class="hljs-function">() =&gt;</span> {
  it(<span class="hljs-string">'renders the tag label'</span>, <span class="hljs-function">() =&gt;</span> {
    render(&lt;Tag label=<span class="hljs-string">"a label"</span> isVisible isLoading={<span class="hljs-literal">false</span>} /&gt;);

    expect(screen.getByText(<span class="hljs-string">'a label'</span>)).toBeInTheDocument();
  });
});
</code></pre>
<ul>
<li>bonus point: accessibility. I also built an automated test to cover accessibility violations using <code>jest-axe</code>.</li>
</ul>
<pre><code class="lang-typescript">it(<span class="hljs-string">'has no accessibility violations'</span>, <span class="hljs-keyword">async</span> () =&gt; {
  <span class="hljs-keyword">const</span> { container } = render(
    &lt;Tag label=<span class="hljs-string">"a label"</span> isVisible isLoading={<span class="hljs-literal">false</span>} /&gt;
  );

  <span class="hljs-keyword">const</span> results = <span class="hljs-keyword">await</span> axe(container);

  expect(results).toHaveNoViolations();
});
</code></pre>
<p>We are ready to implement another component: the <code>TitleDescription</code>. It will work almost similar to the <code>Tag</code> component. It receives some props: <code>name</code>, <code>description</code>, and <code>isLoading</code>.</p>
<p>As we have the <code>Product</code> type with the type definition for the <code>name</code> and the <code>description</code>, I wanted to reuse it. I tried different things - and you can <a target="_blank" href="https://leandrotk.github.io/tk/2020/05/typescript-learnings-interesting-types/index.html">take a look here for more details</a> - and I found the <code>Pick</code> type. With that, I could get the <code>name</code> and the <code>description</code> from the <code>ProductType</code>:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">type</span> TitleDescriptionType = Pick&lt;ProductType, <span class="hljs-string">'name'</span> | <span class="hljs-string">'description'</span>&gt;;
</code></pre>
<p>With this new type, I could create the <code>TitleDescriptionPropsType</code> for the component:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">type</span> TitleDescriptionPropsType = TitleDescriptionType &amp; {
  isLoading: <span class="hljs-built_in">boolean</span>;
};
</code></pre>
<p>Now working inside the component, If the <code>isLoading</code> is true, the component renders the proper skeleton component before it renders the actual title and description texts.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">if</span> (isLoading) {
  <span class="hljs-keyword">return</span> (
    &lt;Fragment&gt;
      &lt;Skeleton
        width=<span class="hljs-string">"60%"</span>
        height=<span class="hljs-string">"24px"</span>
        data-testid=<span class="hljs-string">"name-skeleton-loader"</span>
      /&gt;
      &lt;Skeleton
        style={descriptionSkeletonStyle}
        height=<span class="hljs-string">"20px"</span>
        data-testid=<span class="hljs-string">"description-skeleton-loader"</span>
      /&gt;
    &lt;/Fragment&gt;
  );
}
</code></pre>
<p>If the component is not loading anymore, we render the title and description texts. Here we use the <code>Typography</code> component.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">return</span> (
  &lt;Fragment&gt;
    &lt;Typography data-testid=<span class="hljs-string">"product-name"</span>&gt;{name}&lt;/Typography&gt;
    &lt;Typography
      data-testid=<span class="hljs-string">"product-description"</span>
      color=<span class="hljs-string">"textSecondary"</span>
      variant=<span class="hljs-string">"body2"</span>
      style={descriptionStyle}
    &gt;
      {description}
    &lt;/Typography&gt;
  &lt;/Fragment&gt;
);
</code></pre>
<p>For the tests, we want three things:</p>
<ul>
<li>when it is loading, the component renders the skeletons</li>
<li>when it is not loading anymore, the component renders the texts</li>
<li>make sure the component doesn't violate the accessibility</li>
</ul>
<p>We will use the same idea we use for the <code>Tag</code> tests: see if it in the document or not based on the state.</p>
<p>When it is loading, we want to see if the skeleton is in the document, but the title and description texts are not.</p>
<pre><code class="lang-typescript">describe(<span class="hljs-string">'when is loading'</span>, <span class="hljs-function">() =&gt;</span> {
  it(<span class="hljs-string">'does not render anything'</span>, <span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">const</span> { queryByTestId } = render(
      &lt;TitleDescription
        name={product.name}
        description={product.description}
        isLoading
      /&gt;
    );

    expect(queryByTestId(<span class="hljs-string">'name-skeleton-loader'</span>)).toBeInTheDocument();
    expect(queryByTestId(<span class="hljs-string">'description-skeleton-loader'</span>)).toBeInTheDocument();
    expect(queryByTestId(<span class="hljs-string">'product-name'</span>)).not.toBeInTheDocument();
    expect(queryByTestId(<span class="hljs-string">'product-description'</span>)).not.toBeInTheDocument();
  });
});
</code></pre>
<p>When it is not loading anymore, it renders the texts in the DOM:</p>
<pre><code class="lang-typescript">describe(<span class="hljs-string">'when finished loading'</span>, <span class="hljs-function">() =&gt;</span> {
  it(<span class="hljs-string">'renders the product name and description'</span>, <span class="hljs-function">() =&gt;</span> {
    render(
      &lt;TitleDescription
        name={product.name}
        description={product.description}
        isLoading={<span class="hljs-literal">false</span>}
      /&gt;
    );

    expect(screen.getByText(product.name)).toBeInTheDocument();
    expect(screen.getByText(product.description)).toBeInTheDocument();
  });
});
</code></pre>
<p>And a simple test to cover accessibility issues:</p>
<pre><code class="lang-typescript">it(<span class="hljs-string">'has no accessibility violations'</span>, <span class="hljs-keyword">async</span> () =&gt; {
  <span class="hljs-keyword">const</span> { container } = render(
    &lt;TitleDescription
      name={product.name}
      description={product.description}
      isLoading={<span class="hljs-literal">false</span>}
    /&gt;
  );

  <span class="hljs-keyword">const</span> results = <span class="hljs-keyword">await</span> axe(container);

  expect(results).toHaveNoViolations();
});
</code></pre>
<p>The next component is the <code>Price</code>. In this component we will provide a skeleton when it is still loading as we did in the other component, and add three different components here:</p>
<ul>
<li><code>PriceWithDiscount</code>: we apply the discount into the original price and render it</li>
<li><code>OriginalPrice</code>: it just renders the product price</li>
<li><code>Discount</code>: it renders the discount percentage when the product has a discount</li>
</ul>
<p>But before I start implementing these components, I wanted to structure the data to be used. The <code>price</code> and the <code>discount</code> values are numbers. So let's build a function called <code>getPriceInfo</code> that receives the <code>price</code> and the <code>discount</code> and it will return this data:</p>
<pre><code class="lang-typescript">{
  priceWithDiscount,
  originalPrice,
  discountOff,
  hasDiscount,
};
</code></pre>
<p>With this type contract:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">type</span> PriceInfoType = {
  priceWithDiscount: <span class="hljs-built_in">string</span>;
  originalPrice: <span class="hljs-built_in">string</span>;
  discountOff: <span class="hljs-built_in">string</span>;
  hasDiscount: <span class="hljs-built_in">boolean</span>;
};
</code></pre>
<p>In this function, it will get the <code>discount</code> and transform it into a <code>boolean</code>, then apply the <code>discount</code> to build the <code>priceWithDiscount</code>, use the <code>hasDiscount</code> to build the discount percentage, and build the <code>originalPrice</code> with the dollar sign:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> applyDiscount = (price: <span class="hljs-built_in">number</span>, discount: <span class="hljs-built_in">number</span>): <span class="hljs-function"><span class="hljs-params">number</span> =&gt;</span>
  price - (price * discount) / <span class="hljs-number">100</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> getPriceInfo = (
  price: <span class="hljs-built_in">number</span>,
  discount: <span class="hljs-built_in">number</span>
): <span class="hljs-function"><span class="hljs-params">PriceInfoType</span> =&gt;</span> {
  <span class="hljs-keyword">const</span> hasDiscount: <span class="hljs-built_in">boolean</span> = <span class="hljs-built_in">Boolean</span>(discount);
  <span class="hljs-keyword">const</span> priceWithDiscount: <span class="hljs-built_in">string</span> = hasDiscount
    ? <span class="hljs-string">`$<span class="hljs-subst">${applyDiscount(price, discount)}</span>`</span>
    : <span class="hljs-string">`$<span class="hljs-subst">${price}</span>`</span>;

  <span class="hljs-keyword">const</span> originalPrice: <span class="hljs-built_in">string</span> = <span class="hljs-string">`$<span class="hljs-subst">${price}</span>`</span>;
  <span class="hljs-keyword">const</span> discountOff: <span class="hljs-built_in">string</span> = hasDiscount ? <span class="hljs-string">`<span class="hljs-subst">${discount}</span>% OFF`</span> : <span class="hljs-string">''</span>;

  <span class="hljs-keyword">return</span> {
    priceWithDiscount,
    originalPrice,
    discountOff,
    hasDiscount,
  };
};
</code></pre>
<p>Here I also built an <code>applytDiscount</code> function to extract the discount calculation.</p>
<p>I added some tests to cover these functions. As they are pure functions, we just need to pass some values and expect new data.</p>
<p>Test for the <code>applyDiscount</code>:</p>
<pre><code class="lang-typescript">describe(<span class="hljs-string">'applyDiscount'</span>, <span class="hljs-function">() =&gt;</span> {
  it(<span class="hljs-string">'applies 20% discount in the price'</span>, <span class="hljs-function">() =&gt;</span> {
    expect(applyDiscount(<span class="hljs-number">100</span>, <span class="hljs-number">20</span>)).toEqual(<span class="hljs-number">80</span>);
  });

  it(<span class="hljs-string">'applies 95% discount in the price'</span>, <span class="hljs-function">() =&gt;</span> {
    expect(applyDiscount(<span class="hljs-number">100</span>, <span class="hljs-number">95</span>)).toEqual(<span class="hljs-number">5</span>);
  });
});
</code></pre>
<p>Test for the <code>getPriceInfo</code>:</p>
<pre><code class="lang-typescript">describe(<span class="hljs-string">'getPriceInfo'</span>, <span class="hljs-function">() =&gt;</span> {
  describe(<span class="hljs-string">'with discount'</span>, <span class="hljs-function">() =&gt;</span> {
    it(<span class="hljs-string">'returns the correct price info'</span>, <span class="hljs-function">() =&gt;</span> {
      expect(getPriceInfo(<span class="hljs-number">100</span>, <span class="hljs-number">20</span>)).toMatchObject({
        priceWithDiscount: <span class="hljs-string">'$80'</span>,
        originalPrice: <span class="hljs-string">'$100'</span>,
        discountOff: <span class="hljs-string">'20% OFF'</span>,
        hasDiscount: <span class="hljs-literal">true</span>,
      });
    });
  });

  describe(<span class="hljs-string">'without discount'</span>, <span class="hljs-function">() =&gt;</span> {
    it(<span class="hljs-string">'returns the correct price info'</span>, <span class="hljs-function">() =&gt;</span> {
      expect(getPriceInfo(<span class="hljs-number">100</span>, <span class="hljs-number">0</span>)).toMatchObject({
        priceWithDiscount: <span class="hljs-string">'$100'</span>,
        originalPrice: <span class="hljs-string">'$100'</span>,
        discountOff: <span class="hljs-string">''</span>,
        hasDiscount: <span class="hljs-literal">false</span>,
      });
    });
  });
});
</code></pre>
<p>Now we can use the <code>getPriceInfo</code> in the <code>Price</code> components to get this structure data and pass down for the other components like this:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> Price = <span class="hljs-function">(<span class="hljs-params">{ price, discount, isLoading }: PricePropsType</span>) =&gt;</span> {
  <span class="hljs-keyword">if</span> (isLoading) {
    <span class="hljs-keyword">return</span> (
      &lt;Skeleton width=<span class="hljs-string">"80%"</span> height=<span class="hljs-string">"18px"</span> data-testid=<span class="hljs-string">"price-skeleton-loader"</span> /&gt;
    );
  }

  <span class="hljs-keyword">const</span> {
    priceWithDiscount,
    originalPrice,
    discountOff,
    hasDiscount,
  }: PriceInfoType = getPriceInfo(price, discount);

  <span class="hljs-keyword">return</span> (
    &lt;Fragment&gt;
      &lt;PriceWithDiscount price={priceWithDiscount} /&gt;
      &lt;OriginalPrice hasDiscount={hasDiscount} price={originalPrice} /&gt;
      &lt;Discount hasDiscount={hasDiscount} discountOff={discountOff} /&gt;
    &lt;/Fragment&gt;
  );
};
</code></pre>
<p>As we talked earlier, when it is loading, we just render the <code>Skeleton</code> component. When it finishes the loading, it will build the structured data and render the price info. Let's build each component now!</p>
<p>Let's start with the <code>OriginalPrice</code>. We just need to pass the <code>price</code> as a prop and it renders with the <code>Typography</code> component.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">type</span> OriginalPricePropsType = {
  price: <span class="hljs-built_in">string</span>;
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> OriginalPrice = <span class="hljs-function">(<span class="hljs-params">{ price }: OriginalPricePropsType</span>) =&gt;</span> (
  &lt;Typography display=<span class="hljs-string">"inline"</span> style={originalPriceStyle} color=<span class="hljs-string">"textSecondary"</span>&gt;
    {price}
  &lt;/Typography&gt;
);
</code></pre>
<p>Very simple! Let's add a test now.</p>
<p>Just pass a price and see it if was rendered in the DOM:</p>
<pre><code class="lang-typescript">it(<span class="hljs-string">'shows the price'</span>, <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">const</span> price = <span class="hljs-string">'$200'</span>;
  render(&lt;OriginalPrice price={price} /&gt;);
  expect(screen.getByText(price)).toBeInTheDocument();
});
</code></pre>
<p>I also added a test to cover accessibility issues:</p>
<pre><code class="lang-typescript">it(<span class="hljs-string">'has no accessibility violations'</span>, <span class="hljs-keyword">async</span> () =&gt; {
  <span class="hljs-keyword">const</span> { container } = render(&lt;OriginalPrice price=<span class="hljs-string">"$200"</span> /&gt;);
  <span class="hljs-keyword">const</span> results = <span class="hljs-keyword">await</span> axe(container);

  expect(results).toHaveNoViolations();
});
</code></pre>
<p>The <code>PriceWithDiscount</code> component has a very similar implementation, but we pass the <code>hasDiscount</code> boolean to render this price or not. If it has a discount, render the price with the discount. Otherwise, it won't render anything.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">type</span> PricePropsType = {
  hasDiscount: <span class="hljs-built_in">boolean</span>;
  price: <span class="hljs-built_in">string</span>;
};
</code></pre>
<p>The props type has the <code>hasDiscount</code> and the <code>price</code>. And the component just renders things based on the <code>hasDiscount</code> value.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> PriceWithDiscount = <span class="hljs-function">(<span class="hljs-params">{ price, hasDiscount }: PricePropsType</span>) =&gt;</span> {
  <span class="hljs-keyword">if</span> (!hasDiscount) {
    <span class="hljs-keyword">return</span> <span class="hljs-literal">null</span>;
  }

  <span class="hljs-keyword">return</span> (
    &lt;Typography display=<span class="hljs-string">"inline"</span> style={priceWithDiscountStyle}&gt;
      {price}
    &lt;/Typography&gt;
  );
};
</code></pre>
<p>The tests will cover this logic when it has or doesn't have the discount. If it hasn't the discount, the prices will not be rendered.</p>
<pre><code class="lang-typescript">describe(<span class="hljs-string">'when the product has no discount'</span>, <span class="hljs-function">() =&gt;</span> {
  it(<span class="hljs-string">'shows nothing'</span>, <span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">const</span> { queryByTestId } = render(
      &lt;PriceWithDiscount hasDiscount={<span class="hljs-literal">false</span>} price=<span class="hljs-string">""</span> /&gt;
    );

    expect(queryByTestId(<span class="hljs-string">'discount-off-label'</span>)).not.toBeInTheDocument();
  });
});
</code></pre>
<p>If it has the discount, it will be the rendered in the DOM:</p>
<pre><code class="lang-typescript">describe(<span class="hljs-string">'when the product has a discount'</span>, <span class="hljs-function">() =&gt;</span> {
  it(<span class="hljs-string">'shows the price'</span>, <span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">const</span> price = <span class="hljs-string">'$200'</span>;
    render(&lt;PriceWithDiscount hasDiscount price={price} /&gt;);
    expect(screen.getByText(price)).toBeInTheDocument();
  });
});
</code></pre>
<p>And as always, a test to cover accessibility violations:</p>
<pre><code class="lang-typescript">it(<span class="hljs-string">'has no accessibility violations'</span>, <span class="hljs-keyword">async</span> () =&gt; {
  <span class="hljs-keyword">const</span> { container } = render(
    &lt;PriceWithDiscount hasDiscount price=<span class="hljs-string">"$200"</span> /&gt;
  );

  <span class="hljs-keyword">const</span> results = <span class="hljs-keyword">await</span> axe(container);

  expect(results).toHaveNoViolations();
});
</code></pre>
<p>The <code>Discount</code> component is pretty much the same as the <code>PriceWithDiscount</code>. Render the discount tag if the product has a discount:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">type</span> DiscountPropsType = {
  hasDiscount: <span class="hljs-built_in">boolean</span>;
  discountOff: <span class="hljs-built_in">string</span>;
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> Discount = <span class="hljs-function">(<span class="hljs-params">{ hasDiscount, discountOff }: DiscountPropsType</span>) =&gt;</span> {
  <span class="hljs-keyword">if</span> (!hasDiscount) {
    <span class="hljs-keyword">return</span> <span class="hljs-literal">null</span>;
  }

  <span class="hljs-keyword">return</span> (
    &lt;Typography
      display=<span class="hljs-string">"inline"</span>
      color=<span class="hljs-string">"secondary"</span>
      data-testid=<span class="hljs-string">"discount-off-label"</span>
    &gt;
      {discountOff}
    &lt;/Typography&gt;
  );
};
</code></pre>
<p>And all the tests we did for the other component, we do the same thing for the <code>Discount</code> component:</p>
<pre><code class="lang-typescript">describe(<span class="hljs-string">'Discount'</span>, <span class="hljs-function">() =&gt;</span> {
  describe(<span class="hljs-string">'when the product has a discount'</span>, <span class="hljs-function">() =&gt;</span> {
    it(<span class="hljs-string">'shows the discount label'</span>, <span class="hljs-function">() =&gt;</span> {
      <span class="hljs-keyword">const</span> discountOff = <span class="hljs-string">'20% OFF'</span>;
      render(&lt;Discount hasDiscount discountOff={discountOff} /&gt;);
      expect(screen.getByText(discountOff)).toBeInTheDocument();
    });
  });

  describe(<span class="hljs-string">'when the product has no discount'</span>, <span class="hljs-function">() =&gt;</span> {
    it(<span class="hljs-string">'shows nothing'</span>, <span class="hljs-function">() =&gt;</span> {
      <span class="hljs-keyword">const</span> { queryByTestId } = render(
        &lt;Discount hasDiscount={<span class="hljs-literal">false</span>} discountOff=<span class="hljs-string">""</span> /&gt;
      );

      expect(queryByTestId(<span class="hljs-string">'discount-off-label'</span>)).not.toBeInTheDocument();
    });
  });

  it(<span class="hljs-string">'has no accessibility violations'</span>, <span class="hljs-keyword">async</span> () =&gt; {
    <span class="hljs-keyword">const</span> { container } = render(
      &lt;Discount hasDiscount discountOff=<span class="hljs-string">"20% OFF"</span> /&gt;
    );

    <span class="hljs-keyword">const</span> results = <span class="hljs-keyword">await</span> axe(container);

    expect(results).toHaveNoViolations();
  });
});
</code></pre>
<p>Now we will build an <code>Image</code> component. This component has the basic skeleton as any other component we've built. If it is loading, wait to render the image source and render the skeleton instead. When it finishes the loading, we will render the image, but only if the component is in the intersection of the browser window.</p>
<p>What does it mean? When you are on a website on your mobile device, you'll probably see the first 4 products. They will render the skeleton and then the image. But below these 4 products, as you're not seeing any of them, it doesn't matter if we are rendering them or not. And we can choose to not render them. Not for now. But on-demand. When you are scrolling, if the product's image is at the intersection of the browser window, we start rendering the image source.</p>
<p>That way we gain performance by speeding up the page load time and reduce the cost by requesting images on demand.</p>
<p>We will use the Intersection Observer API to download images on demand. But before writing any code about this technology, let's start building our component with the image and the skeleton view.</p>
<p>Image props will have this object:</p>
<pre><code class="lang-typescript">{
  imageUrl,
  imageAlt,
  width,
  isLoading,
  imageWrapperStyle,
  imageStyle,
}
</code></pre>
<p>The <code>imageUrl</code>, <code>imageAlt</code>, and the <code>isLoading</code> props are passed by the product component. The <code>width</code> is an attribute for the skeleton and the image tag. The <code>imageWrapperStyle</code> and the <code>imageStyle</code> are props that have a default value in the image component. We'll talk about this later.</p>
<p>Let's add a type for this props:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">type</span> ImageUrlType = Pick&lt;ProductType, <span class="hljs-string">'imageUrl'</span>&gt;;
<span class="hljs-keyword">type</span> ImageAttrType = { imageAlt: <span class="hljs-built_in">string</span>; width: <span class="hljs-built_in">string</span> };
<span class="hljs-keyword">type</span> ImageStateType = { isLoading: <span class="hljs-built_in">boolean</span> };
<span class="hljs-keyword">type</span> ImageStyleType = {
  imageWrapperStyle: CSSProperties;
  imageStyle: CSSProperties;
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">type</span> ImagePropsType = ImageUrlType &amp;
  ImageAttrType &amp;
  ImageStateType &amp;
  ImageStyleType;
</code></pre>
<p>The idea here is to give meaning for the types and then compose everything. We can get the <code>imageUrl</code> from the <code>ProductType</code>. The attribute type will have the <code>imageAlt</code> and the <code>width</code>. The image state has the <code>isLoading</code> state. And the image style has some <code>CSSProperties</code>.</p>
<p>At first, the component would like this:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> Image = <span class="hljs-function">(<span class="hljs-params">{
  imageUrl,
  imageAlt,
  width,
  isLoading,
  imageWrapperStyle,
  imageStyle,
}: ImagePropsType</span>) =&gt;</span> {
  <span class="hljs-keyword">if</span> (isLoading) {
    &lt;Skeleton
      variant=<span class="hljs-string">"rect"</span>
      width={width}
      data-testid=<span class="hljs-string">"image-skeleton-loader"</span>
    /&gt;
  }

  <span class="hljs-keyword">return</span> (
    &lt;img
      src={imageUrl}
      alt={imageAlt}
      width={width}
      style={imageStyle}
    /&gt;
  );
};
</code></pre>
<p>Let's build the code to make the intersection observer works.</p>
<p>The idea of the intersection observer is to receive a target to be observed and a callback function that is executed whenever the observed target enters or exits the viewport. So the implementation would be very simple:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">const</span> observer: IntersectionObserver = <span class="hljs-keyword">new</span> IntersectionObserver(
  onIntersect,
  options
);

observer.observe(target);
</code></pre>
<p>Instantiate the <code>IntersectionObserver</code> class by passing an options object and the callback function. The <code>observer</code> will observe the <code>target</code> element.</p>
<p>As it is an effect in the DOM, we can wrap this into a <code>useEffect</code>.</p>
<pre><code class="lang-typescript">useEffect(<span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">const</span> observer: IntersectionObserver = <span class="hljs-keyword">new</span> IntersectionObserver(
    onIntersect,
    options
  );

  observer.observe(target);

  <span class="hljs-keyword">return</span> <span class="hljs-function">() =&gt;</span> {
    observer.unobserve(target);
  };
}, [target]);
</code></pre>
<p>Using <code>useEffect</code>, we have two different things here: the dependency array and the returning function. We pass the <code>target</code> as the dependency function to make sure that we will re-run the effect if the <code>target</code> changes. And the returning function is a cleanup function. React performs the cleanup when the component unmounts, so it will clean up the effect before running another effect for every render.</p>
<p>In this cleanup function, we just stop observing the <code>target</code> element.</p>
<p>When the component starts rendering, the <code>target</code> reference is not set yet, so we need to have a guard to not observe an <code>undefined</code> target.</p>
<pre><code class="lang-typescript">useEffect(<span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">if</span> (!target) {
    <span class="hljs-keyword">return</span>;
  }

  <span class="hljs-keyword">const</span> observer: IntersectionObserver = <span class="hljs-keyword">new</span> IntersectionObserver(
    onIntersect,
    options
  );

  observer.observe(target);

  <span class="hljs-keyword">return</span> <span class="hljs-function">() =&gt;</span> {
    observer.unobserve(target);
  };
}, [target]);
</code></pre>
<p>Instead of using this effect in our component, we could build a custom hook to receive the target, some options to customize the configuration, and it would provide a boolean telling if the target is at the intersection of the viewport or not.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">export</span> <span class="hljs-keyword">type</span> TargetType = Element | HTMLDivElement | <span class="hljs-literal">undefined</span>;
<span class="hljs-keyword">export</span> <span class="hljs-keyword">type</span> IntersectionStatus = {
  isIntersecting: <span class="hljs-built_in">boolean</span>;
};

<span class="hljs-keyword">const</span> defaultOptions: IntersectionObserverInit = {
  rootMargin: <span class="hljs-string">'0px'</span>,
  threshold: <span class="hljs-number">0.1</span>,
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> useIntersectionObserver = (
  target: TargetType,
  options: IntersectionObserverInit = defaultOptions
): <span class="hljs-function"><span class="hljs-params">IntersectionStatus</span> =&gt;</span> {
  <span class="hljs-keyword">const</span> [isIntersecting, setIsIntersecting] = useState(<span class="hljs-literal">false</span>);

  useEffect(<span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">if</span> (!target) {
      <span class="hljs-keyword">return</span>;
    }

    <span class="hljs-keyword">const</span> onIntersect = <span class="hljs-function">(<span class="hljs-params">[entry]: IntersectionObserverEntry[]</span>) =&gt;</span> {
      setIsIntersecting(entry.isIntersecting);

            <span class="hljs-keyword">if</span> (entry.isIntersecting) {
        observer.unobserve(target);
      }
    };

    <span class="hljs-keyword">const</span> observer: IntersectionObserver = <span class="hljs-keyword">new</span> IntersectionObserver(
      onIntersect,
      options
    );

    observer.observe(target);

    <span class="hljs-keyword">return</span> <span class="hljs-function">() =&gt;</span> {
      observer.unobserve(target);
    };
  }, [target]);

  <span class="hljs-keyword">return</span> { isIntersecting };
};
</code></pre>
<p>In our callback function, we just set if the entry target is intersecting the viewport or not. The <code>setIsIntersecting</code> is a setter from the <code>useState</code> hook we define at the top of our custom hook.</p>
<p>It is initialized as <code>false</code> but will update to <code>true</code> if it is intersecting the viewport.</p>
<p>With this new information in the component, we can render the image or not. If it is intersecting, we can render the image. If not, just render a skeleton until the user gets to the viewport intersection of the product image.</p>
<p>How does it look in practice?</p>
<p>First we define the wrapper reference using <code>useState</code>:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">const</span> [wrapperRef, setWrapperRef] = useState&lt;HTMLDivElement&gt;();
</code></pre>
<p>It start as <code>undefined</code>. Then build a wrapper callback to set the element node:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">const</span> wrapperCallback = useCallback(<span class="hljs-function"><span class="hljs-params">node</span> =&gt;</span> {
  setWrapperRef(node);
}, []);
</code></pre>
<p>With that, we can use it to get the wrapper reference by using a <code>ref</code> prop in our <code>div</code>.</p>
<pre><code class="lang-typescript">&lt;div ref={wrapperCallback}&gt;
</code></pre>
<p>After setting the <code>wrapperRef</code>, we can pass it as the <code>target</code> for our <code>useIntersectionObserver</code> and expect a <code>isIntersecting</code> status as a result:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">const</span> { isIntersecting }: IntersectionStatus = useIntersectionObserver(wrapperRef);
</code></pre>
<p>With this new value, we can build a boolean value to know if we render the skeleton or the product image.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">const</span> showImageSkeleton: <span class="hljs-built_in">boolean</span> = isLoading || !isIntersecting;
</code></pre>
<p>So now we can render the appropriate node to the DOM.</p>
<pre><code class="lang-typescript">&lt;div ref={wrapperCallback} style={imageWrapperStyle}&gt;
  {showImageSkeleton ? (
    &lt;Skeleton
      variant=<span class="hljs-string">"rect"</span>
      width={width}
      height={imageWrapperStyle.height}
      style={skeletonStyle}
      data-testid=<span class="hljs-string">"image-skeleton-loader"</span>
    /&gt;
  ) : (
    &lt;img
      src={imageUrl}
      alt={imageAlt}
      width={width}
    /&gt;
  )}
&lt;/div&gt;
</code></pre>
<p>The full component looks like this:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> Image = <span class="hljs-function">(<span class="hljs-params">{
  imageUrl,
  imageAlt,
  width,
  isLoading,
  imageWrapperStyle,
}: ImagePropsType</span>) =&gt;</span> {
  <span class="hljs-keyword">const</span> [wrapperRef, setWrapperRef] = useState&lt;HTMLDivElement&gt;();
  <span class="hljs-keyword">const</span> wrapperCallback = useCallback(<span class="hljs-function"><span class="hljs-params">node</span> =&gt;</span> {
    setWrapperRef(node);
  }, []);

  <span class="hljs-keyword">const</span> { isIntersecting }: IntersectionStatus = useIntersectionObserver(wrapperRef);
  <span class="hljs-keyword">const</span> showImageSkeleton: <span class="hljs-built_in">boolean</span> = isLoading || !isIntersecting;

  <span class="hljs-keyword">return</span> (
    &lt;div ref={wrapperCallback} style={imageWrapperStyle}&gt;
      {showImageSkeleton ? (
        &lt;Skeleton
          variant=<span class="hljs-string">"rect"</span>
          width={width}
          height={imageWrapperStyle.height}
          style={skeletonStyle}
          data-testid=<span class="hljs-string">"image-skeleton-loader"</span>
        /&gt;
      ) : (
        &lt;img
          src={imageUrl}
          alt={imageAlt}
          width={width}
        /&gt;
      )}
    &lt;/div&gt;
  );
};
</code></pre>
<p>Great, now the loading on-demand works well. But I want to build a slightly better experience. The idea here is to have two different sizes of the same image. The low-quality image is requested and we make it visible, but blur while the high-quality image is requested in the background. When the high-quality image finally finishes loading, we transition from the low-quality to the high-quality image with an ease-in/ease-out transition to make it a smooth experience.</p>
<p>Let's build this logic. We could build this into the component, but we could also extract this logic into a custom hook.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> useImageOnLoad = (): <span class="hljs-function"><span class="hljs-params">ImageOnLoadType</span> =&gt;</span> {
  <span class="hljs-keyword">const</span> [isLoaded, setIsLoaded] = useState(<span class="hljs-literal">false</span>);
  <span class="hljs-keyword">const</span> handleImageOnLoad = <span class="hljs-function">() =&gt;</span> setIsLoaded(<span class="hljs-literal">true</span>);

  <span class="hljs-keyword">const</span> imageVisibility: CSSProperties = {
    visibility: isLoaded ? <span class="hljs-string">'hidden'</span> : <span class="hljs-string">'visible'</span>,
    filter: <span class="hljs-string">'blur(10px)'</span>,
    transition: <span class="hljs-string">'visibility 0ms ease-out 500ms'</span>,
  };

  <span class="hljs-keyword">const</span> imageOpactity: CSSProperties = {
    opacity: isLoaded ? <span class="hljs-number">1</span> : <span class="hljs-number">0</span>,
    transition: <span class="hljs-string">'opacity 500ms ease-in 0ms'</span>,
  };

  <span class="hljs-keyword">return</span> { handleImageOnLoad, imageVisibility, imageOpactity };
};
</code></pre>
<p>This hook just provides some data and behavior for the component. The <code>handleImageOnLoad</code> we talked earlier, the <code>imageVisibility</code> to make the low-quality image visible or not, and the <code>imageOpactity</code> to make the transition from transparent to opaque, that way we make it visible after loading it.</p>
<p>The <code>isLoaded</code> is a simple boolean to handle the visibility of the images. Another small detail is the <code>filter: 'blur(10px)'</code> to make the low-quality-image blur and then slowly focusing while transitioning from the low-quality image to the high-quality image.</p>
<p>With this new hook, we just import it, and call inside the component:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">const</span> {
  handleImageOnLoad,
  imageVisibility,
  imageOpactity,
}: ImageOnLoadType = useImageOnLoad();
</code></pre>
<p>And start using the data and behavior we built.</p>
<pre><code class="lang-typescript">&lt;Fragment&gt;
  &lt;img
    src={thumbUrl}
    alt={imageAlt}
    width={width}
    style={{ ...imageStyle, ...imageVisibility }}
  /&gt;
  &lt;img
    onLoad={handleImageOnLoad}
    src={imageUrl}
    alt={imageAlt}
    width={width}
    style={{ ...imageStyle, ...imageOpactity }}
  /&gt;
&lt;/Fragment&gt;
</code></pre>
<p>The first one has a low-quality image, the <code>thumbUrl</code>. The second has the original high-quality image, the <code>imageUrl</code>. When the high-quality image is loaded, it calls the <code>handleImageOnLoad</code> function. This function will make the transition between one image to the other.</p>

  


<h2 id="heading-wrapping-up">Wrapping up</h2>
<p>This is the first part of this project to learn more about user experience, native APIs, typed frontend, and tests.</p>
<p>For the next part of this series, we are going to think more in an architectural way to build the search with filters, but keeping the mindset to bring technical solutions to make the user experience as smooth as possible.</p>
<p>You can find other articles like this on <a target="_blank" href="https://leandrotk.github.io/tk/2020/06/ux-studies-with-react-typescript-and-testing-library/index.html">TK's blog</a>.</p>
<h2 id="heading-resources">Resources</h2>
<ul>
<li><a target="_blank" href="https://developers.google.com/web/fundamentals/performance/lazy-loading-guidance/images-and-video">Lazy Loading Images and Video</a></li>
<li><a target="_blank" href="https://css-tricks.com/a-few-functional-uses-for-intersection-observer-to-know-when-an-element-is-in-view/">Functional Uses for Intersection Observer</a></li>
<li><a target="_blank" href="https://css-tricks.com/tips-for-rolling-your-own-lazy-loading/">Tips for rolling your own lazy loading</a></li>
<li><a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API">Intersection Observer API - MDN</a></li>
<li><a target="_blank" href="https://github.com/typescript-cheatsheets/react-typescript-cheatsheet">React Typescript Cheatsheet</a></li>
</ul>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Tips to Enhance the Performance of Your React App ]]>
                </title>
                <description>
                    <![CDATA[ By Shifa Martin ReactJS is an open-source framework that facilitates the development of UI interfaces for web and mobile applications. Developers globally use the framework to build state-of-the-art applications which subsequently generate revenues a... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/tips-to-enhance-the-performance-of-your-react-app/</link>
                <guid isPermaLink="false">66d460fa4a0edd9b48e83589</guid>
                
                    <category>
                        <![CDATA[ create-react-app ]]>
                    </category>
                
                    <category>
                        <![CDATA[ React ]]>
                    </category>
                
                    <category>
                        <![CDATA[ React context ]]>
                    </category>
                
                    <category>
                        <![CDATA[ react testing library ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Reactive Programming ]]>
                    </category>
                
                    <category>
                        <![CDATA[ React ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Tue, 27 Aug 2019 13:46:33 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2019/08/react.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Shifa Martin</p>
<p>ReactJS is an open-source framework that facilitates the development of UI interfaces for web and mobile applications. Developers globally use the framework to build state-of-the-art applications which subsequently generate revenues as well as expand the audience for businesses.  </p>
<p>However, building a great UI with React isn’t enough, You’ve got to add that extra glitter to make the app more polished, functional and remarkably better than the competition. </p>
<p>This is exactly what I’m going to help you with as I describe some key methods to increase performance in React apps.</p>
<h3 id="heading-1-making-good-use-of-identities">1. Making good use of Identities</h3>
<p>When building mobile apps with React,  it is possible to wrap functions and variables with React.useMemo. Doing so provides the ability to memoize them so they remain identical for renders in the future.  </p>
<p>When functions and variables are not memoized, any references to them might vanish from future renders. Memoizing helps in negating wasteful processes and operations in every situation where you’d leverage functions and variables.</p>
<p><em><strong>Example:</strong></em> </p>
<p>Say, we’re preparing a custom hook for a list of urls as arguments. Using the hook, we can collect them into an array of promise objects and resolve them with Promise.all. The results of this accumulation will enter the state and be passed the app component once done. The list of promises now map over the urls array from where it fetches the urls.</p>
<pre><code class="lang-react">import React from 'react'
import axios from 'axios'

export const useApp = ({ urls }) =&gt; {
  const [results, setResults] = React.useState(null)

  const promises = urls.map(axios.get)

  React.useEffect(() =&gt; {
    Promise.all(promises).then(setResults)
  }, [])

  return { results }
}

const App = () =&gt; {
  const urls = [
    'https://clinicaltables.nlm.nih.gov/api/icd10cm/v3/search?terms=a',
    'https://clinicaltables.nlm.nih.gov/api/icd10cm/v3/search?terms=b',
    'https://clinicaltables.nlm.nih.gov/api/icd10cm/v3/search?terms=c',
  ]

  useApp({ urls })

  return null
}

export default App
</code></pre>
<p>Since we want to obtain data from 3 urls here, only 3 requests are supposed to be sent out, one for each url. However,  when looking at it through the inspect element feature on Google Chrome, we find that 6 requests are sent instead of the supposed 3.<br>This happens because the urls argument did not retain its previous identity. When the app is re-rendered, it’s instantiating a new array each time, as React treats it as a different value.  </p>
<p><img src="https://lh5.googleusercontent.com/XE6rCdOL110eYARSgVTgcwiecF2qNAT96yBYn_-FbQ2_ffjdRAplLqRxu4eQh-NniyF0doEPRtsT3X0lYxeHcSu35UN0giiteCsIJTrVP9tw1mITk5-P5hH3PmdWd2ss5R0E2pb3" alt="Image" width="665" height="160" loading="lazy"></p>
<p>To fix this problem, we can use React.useMemo as previously mentioned. When using React.useMemo, the array of promise objects won’t recompute in each new render unless the array with the list of urls changes. As long as it stays the same, the identities remain.</p>
<p><strong>Here’s what happens when applying React.useMemo to this example:</strong></p>
<pre><code class="lang-react">const useApp = ({ urls }) =&gt; {
  const [results, setResults] = React.useState(null)

  const promises = urls.map((url) =&gt; axios.get(url))

  React.useEffect(() =&gt; {
    Promise.all(promises).then(setResults)
  }, [])

  return { results }
}

const App = () =&gt; {
  const urls = React.useMemo(() =&gt; {
    return [
      'https://clinicaltables.nlm.nih.gov/api/icd10cm/v3/search?terms=a',
      'https://clinicaltables.nlm.nih.gov/api/icd10cm/v3/search?terms=b',
    ]
  }, [])

  const { results } = useApp({ urls })

  return null
}
</code></pre>
<p>It will send 6 requests even now since we’ve only memoized the urls array. The promises variables are also instantiating when running the hook. So in order to send only 3  requests, we also have to memorize the promises variables as well.</p>
<pre><code class="lang-react">const promises = React.useMemo(() =&gt; {
  return urls.map((url) =&gt; axios.get(url))
}, [urls])
</code></pre>
<blockquote>
<p>After memoizing both the urls array and the promises variables, this is what we get: </p>
</blockquote>
<p><img src="https://lh4.googleusercontent.com/P-8qvsq_Nu229Eod2_FIlqLtY1_lAxkPXZfw3a9D7P25VIyGrw--kTnOuTF4rmXPsA3vxGRifwprsI_VGGDU9pFIafOAsfPKiQE3L3Zv1MHXzPH25e2g39MaCikn2AActzgJlftr" alt="Image" width="740" height="162" loading="lazy"></p>
<h3 id="heading-2-merging-props-to-children">2. Merging Props to Children</h3>
<p>At times, developers get into situations where they prefer merging a prop with children before rendering. To facilitate the same, React allows viewing the props to all react elements including others, and also allows exposing their key.</p>
<p>So developers can choose to wrap the children element with a newer one, and insert new props there or they can simply merge the props with React.</p>
<p>Say, we have an app component that uses a useModal and offers the ability to manage modals by using controls such as open, close, opened and activated. Before merging props to children, we can pass them to a VisbilityControl component which provides some additional functionality.</p>
<pre><code class="lang-react">import React from 'react'

const UserContext = React.createContext({
  user: {
    firstName: 'Kelly',
    email: 'frogLover123@gmail.com',
  },
  activated: true,
})

const VisibilityControl = ({ children, opened, close }) =&gt; {
  const ctx = React.useContext(UserContext)
  return React.cloneElement(children, {
    opened: ctx.activated ? opened : false,
    onClick: close,
  })
}

export const useModal = ({ urls } = {}) =&gt; {
  const [opened, setOpened] = React.useState(false)
  const open = () =&gt; setOpened(true)
  const close = () =&gt; setOpened(false)

  return {
    opened,
    open,
    close,
  }
}

const App = ({ children }) =&gt; {
  const modal = useModal()

  return (
    &lt;div&gt;
      &lt;button type="button" onClick={modal.opened ? modal.close : modal.open}&gt;
        {modal.opened ? 'Close' : 'Open'} the Modal
      &lt;/button&gt;
      &lt;VisibilityControl {...modal}&gt;{children}&lt;/VisibilityControl&gt;
    &lt;/div&gt;
  )
}

const Window = ({ opened }) =&gt; {
  if (!opened) return null
  return (
    &lt;div style={{ border: '1px solid teal', padding: 12 }}&gt;
      &lt;h2&gt;I am a window&lt;/h2&gt;
    &lt;/div&gt;
  )
}

export default () =&gt; (
  &lt;App&gt;
    &lt;Window /&gt;
  &lt;/App&gt;
)
</code></pre>
<p>Using Visibility control allows developers to ascertain whether the control activated is true before allowing the control opened to be used by children. In case the Visibility Control feature is used via a secret route, there’s an option to prevent unactivated users from accessing the content.  </p>
<h3 id="heading-3-making-a-larger-reducer">3. Making a larger reducer</h3>
<p>It is possible to combine to or more reducer to make a single, much larger reducer that can help boost a react app.</p>
<p>Say, you think of building a large app that provides access to a wide variety of small services. How would you go about the development of such an app? </p>
<p><strong>There are two options:</strong></p>
<ol>
<li>We can give each microservice within the app a separate part of its own from where its state and context can be managed directly.  </li>
</ol>
<ol start="2">
<li>Or we can combine all states into a single large state and manage all of them within the same environment.  </li>
</ol>
<blockquote>
<p>The first approach seems to highly tedious, so obviously, the second one is the way to go.  </p>
</blockquote>
<p><strong>Now we have three reducers to combine -</strong> </p>
<p>frogsreducer.js, authreducer.js and finally, ownersreducer.js.  </p>
<p><strong>Let's start with authReducer.js</strong></p>
<pre><code class="lang-react">const authReducer = (state, action) =&gt; {
  switch (action.type) {
    case 'set-authenticated':
      return { ...state, authenticated: action.authenticated }
    default:
      return state
  }
}

export default authReducer

ownersReducer.js
</code></pre>
<p><strong>ownersReducer.js</strong></p>
<pre><code class="lang-react">const ownersReducer = (state, action) =&gt; {
  switch (action.type) {
    case 'add-owner':
      return {
        ...state,
        profiles: [...state.profiles, action.owner],
      }
    case 'add-owner-id':
      return { ...state, ids: [...state.ids, action.id] }
    default:
      return state
  }
}

export default ownersReducer
</code></pre>
<p><strong>frogsReducer.js</strong></p>
<pre><code class="lang-react">const frogsReducer = (state, action) =&gt; {
  switch (action.type) {
    case 'add-frog':
      return {
        ...state,
        profiles: [...state.profiles, action.frog],
      }
    case 'add-frog-id':
      return { ...state, ids: [...state.ids, action.id] }
    default:
      return state
  }
}

export default frogsReducer
</code></pre>
<blockquote>
<p>Now we can put all three into the main app file and define their state:  </p>
</blockquote>
<p><strong>App.js</strong></p>
<pre><code class="lang-react">import React from 'react'
import authReducer from './authReducer'
import ownersReducer from './ownersReducer'
import frogsReducer from './frogsReducer'

const initialState = {
  auth: {
    authenticated: false,
  },
  owners: {
    profiles: [],
    ids: [],
  },
  frogs: {
    profiles: [],
    ids: [],
  },
}

function rootReducer(state, action) {
  return {
    auth: authReducer(state.auth, action),
    owners: ownersReducer(state.owners, action),
    frogs: frogsReducer(state.frogs, action),
  }
}

const useApp = () =&gt; {
  const [state, dispatch] = React.useReducer(rootReducer, initialState)

  const addFrog = (frog) =&gt; {
    dispatch({ type: 'add-frog', frog })
    dispatch({ type: 'add-frog-id', id: frog.id })
  }

  const addOwner = (owner) =&gt; {
    dispatch({ type: 'add-owner', owner })
    dispatch({ type: 'add-owner-id', id: owner.id })
  }

  React.useEffect(() =&gt; {
    console.log(state)
  }, [state])

  return {
    ...state,
    addFrog,
    addOwner,
  }
}

const App = () =&gt; {
  const { addFrog, addOwner } = useApp()

  const onAddFrog = () =&gt; {
    addFrog({
      name: 'giant_frog123',
      id: 'jakn39eaz01',
    })
  }

  const onAddOwner = () =&gt; {
    addOwner({
      name: 'bob_the_frog_lover',
      id: 'oaopskd2103z',
    })
  }

  return (
    &lt;&gt;
      &lt;div&gt;
        &lt;button type="button" onClick={onAddFrog}&gt;
          add frog
        &lt;/button&gt;
        &lt;button type="button" onClick={onAddOwner}&gt;
          add owner
        &lt;/button&gt;
      &lt;/div&gt;
    &lt;/&gt;
  )
}
export default () =&gt; &lt;App /&gt;

This is what it looks like combining all three reducers into one large reducer, along with rootReducer

function rootReducer(state, action) {
  return {
    auth: authReducer(state.auth, action),
    owners: ownersReducer(state.owners, action),
    frogs: frogsReducer(state.frogs, action),
  }
</code></pre>
<p>This is what it looks like combining all three reducers into one large reducer, along with rootReducer.</p>
<h3 id="heading-using-sentry-for-analyzing-errors">Using Sentry for Analyzing Errors</h3>
<p><img src="https://lh5.googleusercontent.com/ySh7MjcCdU2XUVc1GASq8HBz0ym9Yn3mQt8xP0fygcYWqf-UoSkOAV1gOxUSgOQ3o79FJb7R3P9iwIYngWY8MtNB6uAqHBh-UXY5gf_G-C9kN_Nuxx73iYllkPSqKKOSjDTXWvmb" alt="Image" width="1544" height="770" loading="lazy"></p>
<p>Any mobile app development project can benefit greatly from <a target="_blank" href="https://sentry.io/welcome/">Sentry.</a> It provides everything a developer needs to handle errors and exceptions when building apps with React. Sentry identifies all errors and displays them at one central location so they can be accessed and analyzed all at once.</p>
<p>Getting started with Sentry on React is easy. Just use npm install @sentry/browser and set it up. Once done, developers can log in at sentry.io and analyze all error reports of a project on a single dashboard.</p>
<p>The error reports from sentry are incredibly detailed. They provide all sorts of important information which include the user’s device information, browser, URL, stack trace, how the error was handled, source code, IP address, breadcrumbs to trace the source of error, the error function name and much more.  </p>
<h3 id="heading-5-using-axios-for-http-requests">5. Using Axios for HTTP requests</h3>
<p>Though <a target="_blank" href="https://github.com/axios/axios">Axios</a> is commonly used for HTTP requests. I felt it is important to mention this point because it's actually not common for developers to use other request libraries such as fetch for React apps.  </p>
<p>Windows.fetch provides no support for Internet Explorer 11 (most don’t really care though). But for what it's worth, Axios does work there as well and offers the ability to cancel requests in mid-flight.  </p>
<h3 id="heading-final-words">Final Words</h3>
<p>The 5 mentioned methods can greatly help speed up your React app. It helps developers, the business you’re in and of course, those who’d be using it eventually. But honestly, the success of your React App mostly depends on those who work on them. </p>
<p>As a consumer, you’d want better performance from your app, so it is what denotes success. As a developer, these methods could make your app easier to develop, and efficiency is key to being more productive. </p>
<p><strong>ValueCoders is an expert <a target="_blank" href="https://www.valuecoders.com/">IT outsourcing company</a> for software development. If you are looking for offshore React programmers or <a target="_blank" href="https://www.valuecoders.com/hire-developers/hire-android-developers">hire Android developers</a>, feel free to get in touch.</strong> </p>
<p>Also, I hope this post helps you learn new things and get a deeper insight into what goes into making the perfect react application. </p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Test React Components: the Complete Guide ]]>
                </title>
                <description>
                    <![CDATA[ By Mohammad Iqbal When I first started learning to test my apps back in the day, I would get very frustrated with the different types, styles and technologies used for testing, along with the disbanded array of blog posts, tutorials and articles. I f... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/testing-react-hooks/</link>
                <guid isPermaLink="false">66d45f4547a8245f78752a6a</guid>
                
                    <category>
                        <![CDATA[ Jest ]]>
                    </category>
                
                    <category>
                        <![CDATA[ React ]]>
                    </category>
                
                    <category>
                        <![CDATA[ react testing library ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Software Testing ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Thu, 11 Jul 2019 21:18:12 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2019/07/photo-1562679817-2aac4f5581ec.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Mohammad Iqbal</p>
<p>When I first started learning to test my apps back in the day, I would get very frustrated with the different types, styles and technologies used for testing, along with the disbanded array of blog posts, tutorials and articles. I found this to be true as well for React testing. </p>
<p>So I decided to just write a complete React testing guide in one article. </p>
<p>Complete Guide, huh, are you going to cover every possible testing scenario? Of course not. However, it will be a complete foundational guide to testing and will be enough to build off of for most other edge cases.</p>
<p>Also I have curated an extensive collection of blog posts, articles and tutorials in the further reading section at the end that should give you enough knowledge to be in the top 10% of developers in terms of testing.</p>
<p>You can find the completed project here:</p>
<p><a target="_blank" href="https://github.com/iqbal125/react-hooks-testing-complete">https://github.com/iqbal125/react-hooks-testing-complete</a>  </p>
<h2 id="heading-table-of-contents">Table of Contents</h2>
<p>     <strong>Theory</strong></p>
<ul>
<li>What is Testing?   </li>
<li>Why Test? </li>
<li>What to Test? </li>
<li>What Not to Test? </li>
<li>How I test</li>
<li>Shallow vs Mount</li>
<li><p>unit vs integration vs e to e</p>
<p> <strong>Preliminary Info</strong></p>
</li>
<li><p>a few odds and ends</p>
<p>  <strong>Enzyme</strong></p>
</li>
<li><p>Enyme Setup</p>
</li>
<li>react-test-renderer</li>
<li>snapshot testing</li>
<li><p>testing implementation details</p>
<p>  <strong>React Testing Library</strong></p>
</li>
<li><p>useState and props </p>
</li>
<li>useReducer()</li>
<li>useContext()</li>
<li>Controlled component Forms</li>
<li><p>useEffect() and Axios API requests</p>
<p>  <strong>Cypress</strong> </p>
</li>
<li><p>A complete end to end test</p>
<p>  <strong>Continuous Integration</strong></p>
</li>
<li><p>Travis.yml</p>
</li>
<li>Code Coverage with coveralls </li>
</ul>
<h2 id="heading-theory">Theory</h2>
<h3 id="heading-what-is-testing">What is testing?</h3>
<p>Let's start at the beginning and discuss what testing is. Testing is a 3 step process that looks like this:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2019/07/image-12.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Arrange, your app is in a certain original state. Act, then something happens (click event, input, etc.). Then you assert, or make a hypothesis, of the new state of your app. The tests will pass if your hypothesis is correct and fail if it is wrong. </p>
<p>Unlike your react components, your tests are not executed in the browser. Jest is the test runner and testing framework used by React. Jest is the environment where all your tests are actually executed. This is why you do not need to import <code>expect</code> and <code>describe</code> into this file. These functions are already available globally in the jest environment. </p>
<p>Your tests syntax will look something like this:</p>
<pre><code class="lang-javascript">describe(<span class="hljs-string">'Testing sum'</span>, <span class="hljs-function">() =&gt;</span> {
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">sum</span>(<span class="hljs-params">a, b</span>) </span>{
       <span class="hljs-keyword">return</span> a + b;
    }

    it(<span class="hljs-string">'should equal 4'</span>,<span class="hljs-function">()=&gt;</span>{
       expect(sum(<span class="hljs-number">2</span>,<span class="hljs-number">2</span>)).toBe(<span class="hljs-number">4</span>);
      })

    test(<span class="hljs-string">'also should equal 4'</span>, <span class="hljs-function">() =&gt;</span> {
        expect(sum(<span class="hljs-number">2</span>,<span class="hljs-number">2</span>)).toBe(<span class="hljs-number">4</span>);
      }) 
});
</code></pre>
<p><code>describe</code> wraps our <code>it</code> or <code>test</code> blocks, and is a way to group our tests. Both <code>it</code> and <code>test</code> are keywords and can be used interchangeably. The string will be something that should happen with your tests and will be printed to the console. <code>toBe()</code> is a matcher that works with expect to allow you to make assertions. There are many more matchers and global variables offered by jest, see the links below for a complete list. </p>
<p><a target="_blank" href="https://jestjs.io/docs/en/using-matchers">https://jestjs.io/docs/en/using-matchers</a></p>
<p><a target="_blank" href="https://jestjs.io/docs/en/api">https://jestjs.io/docs/en/api</a></p>
<h3 id="heading-ia"> </h3>
<p>Why test?</p>
<p>Testing is done to ensure that your app will work as intended for your end users. Having tests will make your app more robust and less error prone. It is a way to verify that the code is doing what the developers intended. </p>
<p>Potential Drawbacks:</p>
<ul>
<li>Writing tests is time consuming and difficult. </li>
<li>In certain scenarios executing tests in CI can cost actual money. </li>
<li>If done incorrectly, it can give you false positives. Your tests pass, but your app doesn’t function as intended. </li>
<li>Or false negatives. Your tests fail but your app is functioning as intended.</li>
</ul>
<h3 id="heading-what-to-test">What to test?</h3>
<p>To build upon the previous point, Your tests should test the functionality of the app, that mimic how it will be used by your end users. This will give you confidence that your app will function as intended in your production environment.  We will of course go into much more detail through out this article but this is the basic gist of it. </p>
<h3 id="heading-what-not-to-test">What not to test?</h3>
<p>I like to use Kent C dodds philosophy here that you shouldn’t test implementation details. </p>
<p>Implementation details meaning testing things that are not end user functionality. We will see an example of this in the Enzyme section below. </p>
<p>It seems that you are testing functionality there but you are actually not. You are testing the name of the function. Because you can change the name of the function and your tests will break but your app will still work giving you a false negative. </p>
<p>Constantly having to worry about function and variable names is a headache, and having to rewrite tests every time you change them is tedious, I will show you a better approach. </p>
<p><strong>Const variables:</strong> these are unchanging variables, no need to test them.    </p>
<p><strong>Third party libraries:</strong> It is not your job to test these libraries. It is up to the creators of these libraries to test it. If you are not sure if a library is tested you should not use it. Or you can read the source code to see if the author included tests. You can download the source code and run these tests yourself. You can also ask the author if their library is production ready or not.     </p>
<h3 id="heading-my-personal-philosophy-on-testing">My personal philosophy on testing</h3>
<p>A lot of my testing philosophy is based on Kent C dodds teachings so you will see a lot of his sentiments echoed here, but I some of my own thoughts as well.</p>
<p>Many integration tests. No snapshot tests. Few unit tests. Few e to e tests. </p>
<p>Unit testing is step above snapshot testing but its not ideal. It is however much easier to understand and maintain then snapshot testing. </p>
<p>Write mostly integration tests. Unit tests are good but they don't really resemble the way your end user interacts with your app. It is very easy to test implementation details with unit tests, especially with shallow render.  </p>
<p>Integration tests should mock as little as possible</p>
<p>Do not test implementation details such as names of functions and variables. </p>
<p>For example if we are testing a button and change the name of the function in the onClick method from increment() to handleClick() our tests would break but our component will still function. This is bad practice because we are basically just testing the name of the function which is an implementation detail, which our end user does not care about.</p>
<h3 id="heading-shallow-vs-mount">Shallow vs mount</h3>
<p>Mount actually executes the html, css and js code like a browser would, but does so in a simulated way. It is “headless” for example, meaning it doesn’t render or paint anything to a UI, but acts as a simulated web browser and executes the code in the background. </p>
<p>Not spending time painting anything to the UI makes your tests much faster. However mount tests are still much slower than shallow tests. </p>
<p>This is why you unmount or cleanup  the component after each test, because it’s almost a live app and one test will affect another test. </p>
<p>Mount/render is typically used for integration testing and shallow is used for unit testing.</p>
<p>shallow rendering only renders the single component we are testing. It does not render child components. This allows us to test our component in isolation. </p>
<p>For example consider this child and parent component.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> React <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;

<span class="hljs-keyword">const</span> App = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span> 
      <span class="hljs-tag">&lt;<span class="hljs-name">ChildComponent</span> /&gt;</span> 
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span> 
  )
}

<span class="hljs-keyword">const</span> ChildComponent = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
     <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span> Child components<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  )
}
</code></pre>
<p>If we used shallow rendering of <code>App.js</code> we would get something like this, notice none of the DOM nodes for the child component are present, hence the term shallow render. </p>
<pre><code>&lt;App&gt;
  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span> 
    <span class="hljs-tag">&lt;<span class="hljs-name">ChildComponent</span> /&gt;</span> 
  <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
&lt;/App&gt;
</code></pre><p>Now we can compare this to mounting the component: </p>
<pre><code>&lt;App&gt;
  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span> 
    <span class="hljs-tag">&lt;<span class="hljs-name">ChildComponent</span>&gt;</span> 
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
       <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span> Child components<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">ChildComponent</span>&gt;</span>
   <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
&lt;/App&gt;
</code></pre><p>What we have above is much closer to what our app will look like in the browser, hence the superiority of mount/render. </p>
<h3 id="heading-unit-vs-integration-vs-end-to-end">unit vs integration vs end to end</h3>
<p><strong>unit testing</strong>: testing an isolated part of your app, usually done in combination with shallow rendering. example: a component renders with the default props.</p>
<p><strong>integration testing:</strong> testing if different parts work or integrate with each other. Usually done with mounting or rendering a component. example: test if a child component can update context state in a parent. </p>
<p><strong>e to e testing</strong>: Stands for end to end. Usually a multi step test combining multiple unit and integration tests into one big test. Usually very little is mocked or stubbed. Tests are done in a simulated browser, there may or may not be a UI while the test is running. example: testing an entire authentication flow.</p>
<h2 id="heading-preliminary-info">Preliminary Info</h2>
<p><strong>react-testing-library:</strong> I personally like to use react-testing-library but the common way is to use Enzyme. I will show you one example of Enzyme because it is important to be aware of Enzyme at a basic level and the rest of the examples with react-testing-library. </p>
<p><strong>Examples Outline:</strong> Our examples will follow a pattern. I will first show you the React component and then the tests for it, with detailed explanations of each. You can also follow along with the repo linked at the beginning. </p>
<p><strong>Configuration:</strong> I will also assume you are using create-react-app with the default testing setup with jest so I will skip manual configurations.</p>
<p><strong>Sinon, mocha, chai:</strong> A lot of the functionality offered by sinon is available by default with jest so you dont need sinon. Mocha and chai are a replacement for jest. Jest comes pre configured out of the box to work with your app, so it doesnt make sense to use Mocha and chai.</p>
<p><strong>Components Naming scheme:</strong> My naming scheme for the components is <code>&lt;TestSomething /&gt;</code> but that does not mean they are fake components in any way. They are regular React components, this is just the naming scheme.</p>
<p><strong>npm test and jest watch mode</strong>: <code>yarn test</code>   worked for me. <code>npm test</code> did not work correctly with jest watch mode.</p>
<p><strong>testing a single file:</strong> <code>yarn test</code> name of file</p>
<p><strong>React Hooks vs Classes:</strong> I use React Hooks components for most of the examples but due to the power of react-testing-library all these tests will directly work with class components as well. </p>
<p>With the preliminary background info out of the way we can go over some code.</p>
<h2 id="heading-enzyme">Enzyme</h2>
<h3 id="heading-enzyme-setup">Enzyme Setup</h3>
<p>Our third party libraries</p>
<p><code>npm install enzyme enzyme-to-json  enzyme-adapter-react-16</code></p>
<p>Lets first start with our imports</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> React <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;
<span class="hljs-keyword">import</span> ReactDOM <span class="hljs-keyword">from</span> <span class="hljs-string">'react-dom'</span>;
<span class="hljs-keyword">import</span> Basic <span class="hljs-keyword">from</span> <span class="hljs-string">'../basic_test'</span>;

<span class="hljs-keyword">import</span> Enzyme, { shallow, render, mount } <span class="hljs-keyword">from</span> <span class="hljs-string">'enzyme'</span>;
<span class="hljs-keyword">import</span> toJson <span class="hljs-keyword">from</span> <span class="hljs-string">'enzyme-to-json'</span>;
<span class="hljs-keyword">import</span> Adapter <span class="hljs-keyword">from</span> <span class="hljs-string">'enzyme-adapter-react-16'</span>;

Enzyme.configure({ <span class="hljs-attr">adapter</span>: <span class="hljs-keyword">new</span> Adapter() })
</code></pre>
<p>We will start with our basic imports Our first 3 imports are for react and our component. </p>
<p>After this we import Enzyme. Then we import the toJson function from the 'enzyme-to-json' library. We will need this to convert our shallow rendered component into JSON which can be saved to the snapshot file. </p>
<p>Finally we import our Adapter to make enzyme work with react 16 and initialize it as shown above. </p>
<p>react-test-renderer</p>
<p>React actually comes with its own test renderer you can use instead of enzyme and the syntax will look like this. </p>
<pre><code class="lang-javascript"><span class="hljs-comment">// import TestRenderer from 'react-test-renderer';</span>
<span class="hljs-comment">// import ShallowRenderer from 'react-test-renderer/shallow';</span>


<span class="hljs-comment">// Basic Test with React-test-renderer</span>
<span class="hljs-comment">// it('renders correctly react-test-renderer', () =&gt; {</span>
<span class="hljs-comment">//   const renderer = new ShallowRenderer();</span>
<span class="hljs-comment">//   renderer.render(&lt;Basic /&gt;);</span>
<span class="hljs-comment">//   const result = renderer.getRenderOutput();</span>
<span class="hljs-comment">//</span>
<span class="hljs-comment">//   expect(result).toMatchSnapshot();</span>
<span class="hljs-comment">// });</span>
</code></pre>
<p>But even the react-test-render docs suggest using enzyme instead because it has a slightly nicer syntax and does the same thing. Just something to be aware of.   </p>
<h3 id="heading-snapshot-testing">SnapShot Testing</h3>
<p>Now our first test which is a snapshot test</p>
<pre><code class="lang-javascript">it(<span class="hljs-string">'renders correctly enzyme'</span>, <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">const</span> wrapper = shallow(<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">Basic</span> /&gt;</span></span>)

  expect(toJson(wrapper)).toMatchSnapshot();
});
</code></pre>
<p>If you have not ran this command before, a <strong>snapshots</strong> folder and test.js.snap file will be created for you automatically. On every subsequent test the new snapshot will be compared to the existing snapshot file. The test will pass if the snapshot has not changed and fail if it has changed.</p>
<p>So essentially snapshot testing allows you to see how your component has changed since the last test, line for line. The lines of code that have changed is known as the diff.</p>
<p>Here is our basic component we are snapshot testing: </p>
<pre><code><span class="hljs-keyword">import</span> React <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;


<span class="hljs-keyword">const</span> Basic = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> &gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span> Basic Test<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
         <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span> This is a basic Test Component<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> Basic;
</code></pre><p>Running the above test will generate a file that will look like this. This is essentially our tree of React DOM nodes. </p>
<pre><code><span class="hljs-comment">// Jest Snapshot v1, https://goo.gl/fbAQLP</span>

<span class="hljs-built_in">exports</span>[<span class="hljs-string">`renders correctly enzyme 1`</span>] = <span class="hljs-string">`
&lt;div&gt;
  &lt;h1&gt;
     Basic Test
  &lt;/h1&gt;
  &lt;p&gt;
     This is a basic Test Component
  &lt;/p&gt;
&lt;/div&gt;
`</span>;
</code></pre><p>And will produce a folder structure that will look like this: </p>
<p><img src="https://www.freecodecamp.org/news/content/images/2019/07/image-6.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Your terminal output will look like this:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2019/07/image-7.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>However what happens if we changed our basic component to this</p>
<pre><code><span class="hljs-keyword">import</span> React <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;


<span class="hljs-keyword">const</span> Basic = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> &gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span> Basic Test<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>

    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> Basic;
</code></pre><p>Our snapshots will now fail   </p>
<p><img src="https://www.freecodecamp.org/news/content/images/2019/07/image-8.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>And will also give us the diff</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2019/07/image-9.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Just like in git the " - " before each line means it was removed. </p>
<p>We just need to press "w" to activate watch mode then press "u" to update the snapshot. </p>
<p>our snap shot file will be automatically updated with the new snapshot and will pass our tests </p>
<pre><code><span class="hljs-comment">// Jest Snapshot v1, https://goo.gl/fbAQLP</span>

<span class="hljs-built_in">exports</span>[<span class="hljs-string">`renders correctly enzyme 1`</span>] = <span class="hljs-string">`
&lt;div&gt;
  &lt;h1&gt;
     Basic Test
  &lt;/h1&gt;
&lt;/div&gt;
`</span>;
</code></pre><p>This is it for snapshot testing but if you read my personal thoughts section you know I dont snapshot test. I included it here because like Enzyme it is very common and something you should be aware of, but below I'll try to explain why I dont use it.  </p>
<p>Let's go over again what snapshot testing is. It essentially allows you to see how your component has changed since the last test. What are the benefits of this. </p>
<ul>
<li>Its very quick and easy to implement and sometimes requires only a few lines of code. </li>
<li>You can see if our component is rendering correctly. You can see the DOM nodes clearly with the .debug() function.  </li>
</ul>
<p><strong>Cons, Arguments against snapshot testing:</strong></p>
<ul>
<li>The only thing a snapshot test does is tell you whether the syntax of your code has changed since the last test. </li>
<li>So what is it really testing? Some would argue not much.</li>
<li>Also basic rendering of the app correctly is React’s job so you're going a little into testing a third party library territory. </li>
<li>Also comparing diffs can be done with git version control. This should not be the job of snapshot testing.</li>
<li>A failed test doesn’t mean your app isn’t working as intended, only that your code has changed since the last time you ran the test. This can lead to a lot of false negatives and a lack of trust in the test. This can also lead to people just updating the test without looking too closely at it. </li>
<li>Snapshot testing also tells you if your JSX is syntactically correct, but again this can be easily done in the dev environment. Running a snapshot test just to check syntax errors doesnt make any sense. </li>
<li>It can become hard to understand what’s happening in a Snapshot test, since most people use snapshot testing with shallow rendering, which doesnt render child components so it doesnt give the developer any insights at all.    </li>
</ul>
<p>See the further reading section for more info</p>
<h3 id="heading-testing-implementation-details-with-enzyme">Testing Implementation details with Enzyme</h3>
<p>Here I will give an example on why not to test implementation details. Say we have simple counter component like so: </p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> React, { Component } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;


<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Counter</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Component</span> </span>{
  <span class="hljs-keyword">constructor</span>(props) {
    <span class="hljs-built_in">super</span>(props)

    <span class="hljs-built_in">this</span>.state = {
      <span class="hljs-attr">count</span>: <span class="hljs-number">0</span>
    }
  }

  increment = <span class="hljs-function">() =&gt;</span> {
    <span class="hljs-built_in">this</span>.setState({<span class="hljs-attr">count</span>: <span class="hljs-built_in">this</span>.state.count + <span class="hljs-number">1</span>})
  }

  <span class="hljs-comment">//This incorrect code will still cause tests to pass</span>
  <span class="hljs-comment">// &lt;button onClick={this.incremen}&gt;</span>
  <span class="hljs-comment">//   Clicked: {this.state.count}</span>
  <span class="hljs-comment">// &lt;/button&gt;</span>

  render() {
    <span class="hljs-keyword">return</span> (
      <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"counter-button"</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{this.incremen}</span>&gt;</span>
          Clicked: {this.state.count}
        <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  )}
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> Counter;
</code></pre>
<p>You will notice I have a comment suggesting that a non-working app will still cause the tests to pass, for example by misspelling the name of the function in the onClick event. </p>
<p>And let's see the tests which will make it clear why. </p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> React <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;
<span class="hljs-keyword">import</span> ReactDOM <span class="hljs-keyword">from</span> <span class="hljs-string">'react-dom'</span>;
<span class="hljs-keyword">import</span> Counter <span class="hljs-keyword">from</span> <span class="hljs-string">'../counter'</span>;

<span class="hljs-keyword">import</span> Enzyme, { shallow, render, mount } <span class="hljs-keyword">from</span> <span class="hljs-string">'enzyme'</span>;
<span class="hljs-keyword">import</span> toJson <span class="hljs-keyword">from</span> <span class="hljs-string">'enzyme-to-json'</span>;
<span class="hljs-keyword">import</span> Adapter <span class="hljs-keyword">from</span> <span class="hljs-string">'enzyme-adapter-react-16'</span>;

Enzyme.configure({ <span class="hljs-attr">adapter</span>: <span class="hljs-keyword">new</span> Adapter() })

<span class="hljs-comment">// incorrect function assignment in the onClick method</span>
<span class="hljs-comment">// will still pass the tests.</span>

test(<span class="hljs-string">'the increment method increments count'</span>, <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">const</span> wrapper = mount(<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">Counter</span> /&gt;</span></span>)

  expect(wrapper.instance().state.count).toBe(<span class="hljs-number">0</span>)

  <span class="hljs-comment">// wrapper.find('button.counter-button').simulate('click')</span>
  <span class="hljs-comment">// wrapper.setState({count: 1})</span>
  wrapper.instance().increment()
  expect(wrapper.instance().state.count).toBe(<span class="hljs-number">1</span>)
})
</code></pre>
<p>Running the above code will pass the tests. So will using <code>wrapper.setState()</code>. So we have passing tests with a non functional app. I dont know about you but this doesnt give me confidence that our app will function as intended for our end users. </p>
<p>Simulating click on the button will not pass the tests but it might give us the opposite problem, a false negative. Say we want to change the styling on the button by declaring a new CSS class for it, a very common situation. Our tests will now fail because we cant find our button anymore but our app will still be working, giving us a false negative. This is also true whenever we change the names of our functions or state variables.  </p>
<p>Every time we want to change our function and CSS class names we have to rewrite our tests, a very inefficient and tedious process. </p>
<p>So what can we do instead? </p>
<h2 id="heading-react-testing-library">React-testing-library</h2>
<h3 id="heading-usestate">useState</h3>
<p>From the react-testing-library docs we see that the main guiding principle is </p>
<blockquote>
<p>The more your tests resemble the way your software is used the more confidence they can give you. </p>
</blockquote>
<p>We will keep this guiding principle in mind as we explore further with our tests. </p>
<p>Let's start with a basic React Hooks component and test the state and props. </p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> React, { useState } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;


<span class="hljs-keyword">const</span> TestHook = <span class="hljs-function">(<span class="hljs-params">props</span>) =&gt;</span> {
  <span class="hljs-keyword">const</span> [state, setState] = useState(<span class="hljs-string">"Initial State"</span>)

  <span class="hljs-keyword">const</span> changeState = <span class="hljs-function">() =&gt;</span> {
    setState(<span class="hljs-string">"Initial State Changed"</span>)
  }

  <span class="hljs-keyword">const</span> changeNameToSteve = <span class="hljs-function">() =&gt;</span> {
    props.changeName()
  }

  <span class="hljs-keyword">return</span> (
  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{changeState}</span>&gt;</span>
      State Change Button
    <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>{state}<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{changeNameToSteve}</span>&gt;</span>
       Change Name
    <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>{props.name}<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  )
}


<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> TestHook;
</code></pre>
<p>Our props are coming from the root parent component</p>
<pre><code class="lang-javascript">  <span class="hljs-keyword">const</span> App = <span class="hljs-function">() =&gt;</span> {
      <span class="hljs-keyword">const</span> [state, setState] = useState(<span class="hljs-string">"Some Text"</span>)
      <span class="hljs-keyword">const</span> [name, setName] = useState(<span class="hljs-string">"Moe"</span>)
  ...
      const changeName = <span class="hljs-function">() =&gt;</span> {
        setName(<span class="hljs-string">"Steve"</span>)
      }

      <span class="hljs-keyword">return</span> (
        <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"App"</span>&gt;</span>
         <span class="hljs-tag">&lt;<span class="hljs-name">Basic</span> /&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span> Counter <span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
         <span class="hljs-tag">&lt;<span class="hljs-name">Counter</span> /&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span> Basic Hook useState <span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
         <span class="hljs-tag">&lt;<span class="hljs-name">TestHook</span> <span class="hljs-attr">name</span>=<span class="hljs-string">{name}</span> <span class="hljs-attr">changeName</span>=<span class="hljs-string">{changeName}/</span>&gt;</span>
    ...</span>
</code></pre>
<p>So keeping our guiding principle in mind, what will our tests look like? </p>
<p>The way our end user will use this app will be to: see some text on the UI, see the text in the button, then click on it, finally see some new text on UI. </p>
<p>This is how we will write our tests using the React testing library. </p>
<p>Use this command to install react testing library. </p>
<p><code>npm install @testing-library/react</code></p>
<p><strong>not</strong> </p>
<p><code>npm install react-testing-library</code></p>
<p>Now for our tests</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> React <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;
<span class="hljs-keyword">import</span> ReactDOM <span class="hljs-keyword">from</span> <span class="hljs-string">'react-dom'</span>;
<span class="hljs-keyword">import</span> TestHook <span class="hljs-keyword">from</span> <span class="hljs-string">'../test_hook.js'</span>;
<span class="hljs-keyword">import</span> {render, fireEvent, cleanup} <span class="hljs-keyword">from</span> <span class="hljs-string">'@testing-library/react'</span>;
<span class="hljs-keyword">import</span> App <span class="hljs-keyword">from</span> <span class="hljs-string">'../../../App'</span>

afterEach(cleanup)

it(<span class="hljs-string">'Text in state is changed when button clicked'</span>, <span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">const</span> { getByText } = render(<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">TestHook</span> /&gt;</span></span>);

    expect(getByText(<span class="hljs-regexp">/Initial/i</span>).textContent).toBe(<span class="hljs-string">"Initial State"</span>)

    fireEvent.click(getByText(<span class="hljs-string">"State Change Button"</span>))

    expect(getByText(<span class="hljs-regexp">/Initial/i</span>).textContent).toBe(<span class="hljs-string">"Initial State Changed"</span>)
 })


it(<span class="hljs-string">'button click changes props'</span>, <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">const</span> { getByText } = render(<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">App</span>&gt;</span>
                                <span class="hljs-tag">&lt;<span class="hljs-name">TestHook</span> /&gt;</span>
                               <span class="hljs-tag">&lt;/<span class="hljs-name">App</span>&gt;</span></span>)

  expect(getByText(<span class="hljs-regexp">/Moe/i</span>).textContent).toBe(<span class="hljs-string">"Moe"</span>)

  fireEvent.click(getByText(<span class="hljs-string">"Change Name"</span>))

  expect(getByText(<span class="hljs-regexp">/Steve/i</span>).textContent).toBe(<span class="hljs-string">"Steve"</span>)
})
</code></pre>
<p>We first start with our usual imports.</p>
<p>Next we have the <code>afterEach(cleanup)</code> function. Since we are not using shallow render we have to unmount or cleanup after every test. And this is exactly what this function is doing. </p>
<p><code>getByText</code> is the query method we get by using object destructuring on the value of the render function. There are several more query methods but this is the one you will want to use most of the time.</p>
<p>To test our state notice we are not using any function names or the names of our state variables. We are keeping with our guiding principle and not testing implementation details. Since a user will see the text on the UI, this is how we will query the DOM nodes. We will also query the button this way and click it. Finally we will query the final state based on the text as well. </p>
<p><code>(/Initial/i)</code> is a regex expression that returns the first node that at least contains the text "Initial".  </p>
<p>We can do the same exact thing with props as well. Since the <strong>props</strong> are going to be changed in <code>App.js</code> we will need to render it along with our component. Like the previous example we are not using function and variable names. We are testing the same way a user would use our app and that is through the text they will see. </p>
<p>Hopefully this gives you a good idea of how to test with the <code>react-testing-library</code> and the guiding principle, you generally want to use <code>getByText</code> most of the time. There are a few exceptions we will see as we continue further. </p>
<h3 id="heading-usereducer">useReducer</h3>
<p>Now we can test a component with the useReducer hook. We will of course need actions and reducers to work with our component so let's set them up like so: </p>
<p>Our reducer</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> * <span class="hljs-keyword">as</span> ACTIONS <span class="hljs-keyword">from</span> <span class="hljs-string">'./actions'</span>

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> initialState = {
    <span class="hljs-attr">stateprop1</span>: <span class="hljs-literal">false</span>,
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> Reducer1 = <span class="hljs-function">(<span class="hljs-params">state = initialState, action</span>) =&gt;</span> {
  <span class="hljs-keyword">switch</span>(action.type) {
    <span class="hljs-keyword">case</span> <span class="hljs-string">"SUCCESS"</span>:
      <span class="hljs-keyword">return</span> {
        ...state,
        <span class="hljs-attr">stateprop1</span>: <span class="hljs-literal">true</span>,
      }
    <span class="hljs-keyword">case</span> <span class="hljs-string">"FAILURE"</span>:
      <span class="hljs-keyword">return</span> {
        ...state,
        <span class="hljs-attr">stateprop1</span>: <span class="hljs-literal">false</span>,
      }
    <span class="hljs-attr">default</span>:
      <span class="hljs-keyword">return</span> state
  }
}
</code></pre>
<p>And the actions: </p>
<pre><code>


<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> SUCCESS = {
  <span class="hljs-attr">type</span>: <span class="hljs-string">'SUCCESS'</span>
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> FAILURE = {
  <span class="hljs-attr">type</span>: <span class="hljs-string">'FAILURE'</span>
}
</code></pre><p>we will keep things simple and use actions instead of action creators. </p>
<p>And finally the component that will use these actions and reducers: </p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> React, { useReducer } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;
<span class="hljs-keyword">import</span> * <span class="hljs-keyword">as</span> ACTIONS <span class="hljs-keyword">from</span> <span class="hljs-string">'../store/actions'</span>
<span class="hljs-keyword">import</span> * <span class="hljs-keyword">as</span> Reducer <span class="hljs-keyword">from</span> <span class="hljs-string">'../store/reducer'</span>


<span class="hljs-keyword">const</span> TestHookReducer = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">const</span> [reducerState, dispatch] = useReducer(Reducer.Reducer1, Reducer.initialState)

  <span class="hljs-keyword">const</span> dispatchActionSuccess = <span class="hljs-function">() =&gt;</span> {
    dispatch(ACTIONS.SUCCESS)
  }

  <span class="hljs-keyword">const</span> dispatchActionFailure = <span class="hljs-function">() =&gt;</span> {
    dispatch(ACTIONS.FAILURE)
  }


  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
       <span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
        {reducerState.stateprop1
           ? <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>stateprop1 is true<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
           : <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>stateprop1 is false<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>}
       <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
       <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{dispatchActionSuccess}</span>&gt;</span>
         Dispatch Success
       <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  )
}


<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> TestHookReducer;
</code></pre>
<p>This is a simple component that will change <code>stateprop1</code> from false to true by dispatching a <code>SUCCESS</code> action.</p>
<p>And now for our test. </p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> React <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;
<span class="hljs-keyword">import</span> ReactDOM <span class="hljs-keyword">from</span> <span class="hljs-string">'react-dom'</span>;
<span class="hljs-keyword">import</span> TestHookReducer <span class="hljs-keyword">from</span> <span class="hljs-string">'../test_hook_reducer.js'</span>;
<span class="hljs-keyword">import</span> {render, fireEvent, cleanup} <span class="hljs-keyword">from</span> <span class="hljs-string">'@testing-library/react'</span>;
<span class="hljs-keyword">import</span> * <span class="hljs-keyword">as</span> Reducer <span class="hljs-keyword">from</span> <span class="hljs-string">'../../store/reducer'</span>;
<span class="hljs-keyword">import</span> * <span class="hljs-keyword">as</span> ACTIONS <span class="hljs-keyword">from</span> <span class="hljs-string">'../../store/actions'</span>;


afterEach(cleanup)

describe(<span class="hljs-string">'test the reducer and actions'</span>, <span class="hljs-function">() =&gt;</span> {
  it(<span class="hljs-string">'should return the initial state'</span>, <span class="hljs-function">() =&gt;</span> {
    expect(Reducer.initialState).toEqual({ <span class="hljs-attr">stateprop1</span>: <span class="hljs-literal">false</span> })
  })

  it(<span class="hljs-string">'should change stateprop1 from false to true'</span>, <span class="hljs-function">() =&gt;</span> {
    expect(Reducer.Reducer1(Reducer.initialState, ACTIONS.SUCCESS ))
      .toEqual({ <span class="hljs-attr">stateprop1</span>: <span class="hljs-literal">true</span>  })
  })
})

it(<span class="hljs-string">'Reducer changes stateprop1 from false to true'</span>, <span class="hljs-function">() =&gt;</span> {
   <span class="hljs-keyword">const</span> { container, getByText } = render(<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">TestHookReducer</span> /&gt;</span></span>);

   expect(getByText(<span class="hljs-regexp">/stateprop1 is/i</span>).textContent).toBe(<span class="hljs-string">"stateprop1 is false"</span>)

   fireEvent.click(getByText(<span class="hljs-string">"Dispatch Success"</span>))

   expect(getByText(<span class="hljs-regexp">/stateprop1 is/i</span>).textContent).toBe(<span class="hljs-string">"stateprop1 is true"</span>)
})
</code></pre>
<p>We first start off by testing our reducer. And we can wrap the tests for the reducer in the <code>describe</code> block. These are fairly basic tests we are using to make sure the <strong>initial state</strong> is what we want and the actions produce the output we want. </p>
<p>You can make an argument that testing the reducer is testing implementation details, but I found in practice that testing actions and reducers is one unit test that is always necessary. </p>
<p>This is a simple example so it doesn't seem like its a big deal but in larger more complex apps not testing reducers and actions can prove disastrous. So actions and reducers would be one exception to the testing implementation details rule.</p>
<p>Next we have our tests for the actual component. Notice again here we are not testing implementation details. We use the same pattern from the previous useState example we are getting our DOM nodes by the text and also finding and clicking the button with the text as well. </p>
<h3 id="heading-usecontext">useContext</h3>
<p>Let's now move on and test if a child component can update the context state in a parent component. This may seem complex but it is rather simple and straight forward. </p>
<p>We will first need our context object that we can initialize in its own file. </p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> React <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;

<span class="hljs-keyword">const</span> Context = React.createContext()

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> Context
</code></pre>
<p>We also need our parent app component which will hold the Context provider. The value passed down to the <code>Provider</code> will be the state value and the <code>setState</code> function of the <code>App.js</code> component. </p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> React, { useState } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;
<span class="hljs-keyword">import</span> TestHookContext <span class="hljs-keyword">from</span> <span class="hljs-string">'./components/react-testing-lib/test_hook_context'</span>;


<span class="hljs-keyword">import</span> Context <span class="hljs-keyword">from</span> <span class="hljs-string">'./components/store/context'</span>;


<span class="hljs-keyword">const</span> App = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">const</span> [state, setState] = useState(<span class="hljs-string">"Some Text"</span>)


  <span class="hljs-keyword">const</span> changeText = <span class="hljs-function">() =&gt;</span> {
    setState(<span class="hljs-string">"Some Other Text"</span>)
  }


  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"App"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span> Basic Hook useContext<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
     <span class="hljs-tag">&lt;<span class="hljs-name">Context.Provider</span> <span class="hljs-attr">value</span>=<span class="hljs-string">{{changeTextProp:</span> <span class="hljs-attr">changeText</span>,
                               <span class="hljs-attr">stateProp:</span> <span class="hljs-attr">state</span>
                                 }} &gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">TestHookContext</span> /&gt;</span>
     <span class="hljs-tag">&lt;/<span class="hljs-name">Context.Provider</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> App;
</code></pre>
<p>And for our component</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> React, { useContext } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;

<span class="hljs-keyword">import</span> Context <span class="hljs-keyword">from</span> <span class="hljs-string">'../store/context'</span>;

<span class="hljs-keyword">const</span> TestHookContext = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">const</span> context = useContext(Context)

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{context.changeTextProp}</span>&gt;</span>
        Change Text
    <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>{context.stateProp}<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  )
}


<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> TestHookContext;
</code></pre>
<p>We have a simple component that displays the text we initialized in <code>App.js</code> and also we pass the <code>setState</code> function to the <code>onClick</code> method. </p>
<p><strong>Note:</strong> The state is changed, initialized and contained in our <code>App.js</code> component. We have simply passed down the state value and <code>setState</code> function to our child component through context, but ultimately the state is handled in the <code>App.js</code> component. This will be important to understanding our test. </p>
<p>And our test: </p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> React <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;
<span class="hljs-keyword">import</span> ReactDOM <span class="hljs-keyword">from</span> <span class="hljs-string">'react-dom'</span>;
<span class="hljs-keyword">import</span> TestHookContext <span class="hljs-keyword">from</span> <span class="hljs-string">'../test_hook_context.js'</span>;
<span class="hljs-keyword">import</span> {act, render, fireEvent, cleanup} <span class="hljs-keyword">from</span> <span class="hljs-string">'@testing-library/react'</span>;
<span class="hljs-keyword">import</span> App <span class="hljs-keyword">from</span> <span class="hljs-string">'../../../App'</span>

<span class="hljs-keyword">import</span> Context <span class="hljs-keyword">from</span> <span class="hljs-string">'../../store/context'</span>;

afterEach(cleanup)

it(<span class="hljs-string">'Context value is updated by child component'</span>, <span class="hljs-function">() =&gt;</span> {

   <span class="hljs-keyword">const</span> { container, getByText } = render(<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">App</span>&gt;</span>
                                            <span class="hljs-tag">&lt;<span class="hljs-name">Context.Provider</span>&gt;</span>
                                             <span class="hljs-tag">&lt;<span class="hljs-name">TestHookContext</span> /&gt;</span>
                                            <span class="hljs-tag">&lt;/<span class="hljs-name">Context.Provider</span>&gt;</span>
                                           <span class="hljs-tag">&lt;/<span class="hljs-name">App</span>&gt;</span></span>);

   expect(getByText(<span class="hljs-regexp">/Some/i</span>).textContent).toBe(<span class="hljs-string">"Some Text"</span>)

   fireEvent.click(getByText(<span class="hljs-string">"Change Text"</span>))

   expect(getByText(<span class="hljs-regexp">/Some/i</span>).textContent).toBe(<span class="hljs-string">"Some Other Text"</span>)
})
</code></pre>
<p>Even for context you can see we don't break our pattern of tests, we still find and simulate our events with the text. </p>
<p>I have included the <code>&lt;Context.Provider/&gt;</code> and <code>&lt;TestHookContext /&gt;</code>  components in the render function because it makes the code easier to read but we actually dont need either of them. Our test will still work if we passed only the <code>&lt;App /&gt;</code> component to the render function. </p>
<pre><code><span class="hljs-keyword">const</span> { container, getByText } = render(<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">App</span>/&gt;</span></span>)
</code></pre><p>Why is this the case? </p>
<p>Let's think back to what we know about context. All the context state is handled in <code>App.js</code>, for this reason this is the main component we are actually testing, even though it seems like we are testing the child component that uses the <strong>useContext</strong> Hook. This code also works because of <strong>mount/render</strong>. As we know in shallow render the child components are <strong>not rendered</strong>, but in mount/render they are. Since <code>&lt;Context.Provider /&gt;</code> and <code>&lt;TestHookContext /&gt;</code> are both child components of <code>&lt;App /&gt;</code> they are rendered automatically.  </p>
<h3 id="heading-controlled-component-forms">Controlled component Forms</h3>
<p>A controlled component form essentially means the form will work through the React state instead of the form maintaining its own state. Meaning the <code>onChange</code> handler will save the input text to the React state on every keystroke. </p>
<p>Testing the form will be a little bit different than what we have seen so far, but we will try to still keep our guiding principle in mind. </p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> React, { useState } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;

<span class="hljs-keyword">const</span> HooksForm1 = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">const</span> [valueChange, setValueChange] = useState(<span class="hljs-string">''</span>)
  <span class="hljs-keyword">const</span> [valueSubmit, setValueSubmit] = useState(<span class="hljs-string">''</span>)

  <span class="hljs-keyword">const</span> handleChange = <span class="hljs-function">(<span class="hljs-params">event</span>) =&gt;</span> (
    setValueChange(event.target.value)
  );

  <span class="hljs-keyword">const</span> handleSubmit = <span class="hljs-function">(<span class="hljs-params">event</span>) =&gt;</span> {
    event.preventDefault();
    setValueSubmit(event.target.text1.value)
  };

    <span class="hljs-keyword">return</span> (
      <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
       <span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span> React Hooks Form <span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">form</span> <span class="hljs-attr">data-testid</span>=<span class="hljs-string">"form"</span> <span class="hljs-attr">onSubmit</span>=<span class="hljs-string">{handleSubmit}</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">label</span> <span class="hljs-attr">htmlFor</span>=<span class="hljs-string">"text1"</span>&gt;</span>Input Text:<span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"text1"</span> <span class="hljs-attr">onChange</span>=<span class="hljs-string">{handleChange}</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"text"</span> /&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"submit"</span>&gt;</span>Submit<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">form</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">h3</span>&gt;</span>React State:<span class="hljs-tag">&lt;/<span class="hljs-name">h3</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>Change: {valueChange}<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>Submit Value: {valueSubmit}<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">br</span> /&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
    )
}


<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> HooksForm1;
</code></pre>
<p>This is a basic form we have here and we also display the value of the change and submit value in our JSX. We have the <code>data-testid="form"</code>  attribute which we will use in our test to the query for the form. </p>
<p>And our tests: </p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> React <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;
<span class="hljs-keyword">import</span> ReactDOM <span class="hljs-keyword">from</span> <span class="hljs-string">'react-dom'</span>;
<span class="hljs-keyword">import</span> HooksForm1 <span class="hljs-keyword">from</span> <span class="hljs-string">'../test_hook_form.js'</span>;
<span class="hljs-keyword">import</span> {render, fireEvent, cleanup} <span class="hljs-keyword">from</span> <span class="hljs-string">'@testing-library/react'</span>;

afterEach(cleanup)

<span class="hljs-comment">//testing a controlled component form.</span>
it(<span class="hljs-string">'Inputing text updates the state'</span>, <span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">const</span> { getByText, getByLabelText } = render(<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">HooksForm1</span> /&gt;</span></span>);

    expect(getByText(<span class="hljs-regexp">/Change/i</span>).textContent).toBe(<span class="hljs-string">"Change: "</span>)

    fireEvent.change(getByLabelText(<span class="hljs-string">"Input Text:"</span>), {<span class="hljs-attr">target</span>: {<span class="hljs-attr">value</span>: <span class="hljs-string">'Text'</span> } } )

    expect(getByText(<span class="hljs-regexp">/Change/i</span>).textContent).not.toBe(<span class="hljs-string">"Change: "</span>)
 })


 it(<span class="hljs-string">'submiting a form works correctly'</span>, <span class="hljs-function">() =&gt;</span> {
     <span class="hljs-keyword">const</span> { getByTestId, getByText } = render(<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">HooksForm1</span> /&gt;</span></span>);

     expect(getByText(<span class="hljs-regexp">/Submit Value/i</span>).textContent).toBe(<span class="hljs-string">"Submit Value: "</span>)

     fireEvent.submit(getByTestId(<span class="hljs-string">"form"</span>), {<span class="hljs-attr">target</span>: {<span class="hljs-attr">text1</span>: {<span class="hljs-attr">value</span>: <span class="hljs-string">'Text'</span> } } })

     expect(getByText(<span class="hljs-regexp">/Submit Value/i</span>).textContent).not.toBe(<span class="hljs-string">"Submit Value: "</span>)
  })
</code></pre>
<p>Since an empty input element does not have text, we will use a <code>getByLabelText()</code> function to get the input node. This will still be keeping with our guiding principle, since the label text is what the user will read before inputting text. </p>
<p>Notice we will fire the <code>.change()</code> event instead of the usual <code>.click()</code> event. We also pass in dummy data in the form of: </p>
<p><code>{ target: { value: "Text" } }</code> </p>
<p>Since the value from the form will be accessed in the form of <code>event.target.value</code>, this is what we pass to the simulated event. </p>
<p>Since we will generally not know what the text is the user will submit, we can just use a <code>.not</code> keyword to make sure the text has changed in our render method. </p>
<p>We can test the submitting of the form in a similar way.  The only difference is we use the <code>.submit()</code> event and pass in dummy data in this way: </p>
<p><code>{ target: { text1: { value: 'Text' } } }</code> </p>
<p>This is how to access form data from the synthetic event when a user submits a form. where <code>text1</code> is the id of our input element. We will have to break our pattern a little bit here, and use the <code>data-testid="form"</code>   attribute to query for the form since there is really no other way to get the form.  </p>
<p>And thats it for the form. It isnt that different from our other examples. If you think you got it, let's move onto something a little more complex. </p>
<p>### </p>
<h3 id="heading-useeffect-and-api-requests-with-axios">useEffect and API requests with axios</h3>
<p>Let's now see how we would test the <strong>useEffect hook</strong> and API requests. This will be fairly different than what we have seen so far. </p>
<p>Say we have a url passed down to a child component from the root parent. </p>
<pre><code class="lang-javascript">
...

     &lt;TestAxios url=<span class="hljs-string">'https://jsonplaceholder.typicode.com/posts/1'</span> /&gt;

 ...
</code></pre>
<p>And the component itself. </p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> React, { useState, useEffect } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;
<span class="hljs-keyword">import</span> axios <span class="hljs-keyword">from</span> <span class="hljs-string">'axios'</span>;


<span class="hljs-keyword">const</span> TestAxios = <span class="hljs-function">(<span class="hljs-params">props</span>) =&gt;</span> {
  <span class="hljs-keyword">const</span> [state, setState] = useState()

  useEffect(<span class="hljs-function">() =&gt;</span> {
    axios.get(props.url)
      .then(<span class="hljs-function"><span class="hljs-params">res</span> =&gt;</span> setState(res.data))
  }, [])


  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span> Axios Test <span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
        {state
          ? <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">data-testid</span>=<span class="hljs-string">"title"</span>&gt;</span>{state.title}<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
          : <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>...Loading<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>}
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  )
}


<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> TestAxios;
</code></pre>
<p>We simply make an API request and save the results in the local state. We also use a ternary expression in our render method to wait until the request is complete to display the title data from json placeholder. </p>
<p>You will notice we will again out of necessity have to make use of the <code>data-testid</code> attribute, and again it is an implementation detail since a user will not see or interact with this attribute in any way, but this is more realistic, since we will generally not know the text from a API request beforehand. </p>
<p>We will also be using mocks in this test. </p>
<p>A <strong>mock</strong> is way to simulate behavior we dont actually want to do in our tests. For example we mock API requests because we dont want to make real requests in our tests. </p>
<p>We dont want to make real API requests in our tests for various reasons: it will make our tests much slower, might give us a false negative, the API request will cost us money, or we will mess up our database with test data. </p>
<pre><code><span class="hljs-keyword">import</span> React <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;
<span class="hljs-keyword">import</span> ReactDOM <span class="hljs-keyword">from</span> <span class="hljs-string">'react-dom'</span>;
<span class="hljs-keyword">import</span> TestAxios <span class="hljs-keyword">from</span> <span class="hljs-string">'../test_axios.js'</span>;
<span class="hljs-keyword">import</span> {act, render, fireEvent, cleanup, waitForElement} <span class="hljs-keyword">from</span> <span class="hljs-string">'@testing-library/react'</span>;

<span class="hljs-keyword">import</span> axiosMock <span class="hljs-keyword">from</span> <span class="hljs-string">"axios"</span>;
</code></pre><p>We have our usual imports but you will notice something peculiar. We are importing <code>axiosMock</code> from the <code>axios</code> library. We are not importing a mock axios object from the <code>axios</code> library. We are actually mocking the <code>axios</code> library <em>itself</em>. </p>
<p>How? </p>
<p>By using the mocking functionality offered by jest. </p>
<p>We first will make a <code>__mocks__</code> folder adjacent to our test folder, so something like this. </p>
<p><img src="https://www.freecodecamp.org/news/content/images/2019/07/image-13.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>And inside the mocks folder we have an <code>axios.js</code> file and this is our fake <strong>axios</strong> library. And inside our fake <strong>axios</strong> library we have our <strong>jest mock function</strong>. </p>
<p>Mock functions allow us to use functions in our jest environment without having to implement the actual logic of the function. </p>
<p>So basically we are not going to implement the actual logic behind an axios get request. We will just use this mock function instead. </p>
<pre><code class="lang-javascript"><span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> {
  <span class="hljs-attr">get</span>: jest.fn(<span class="hljs-function">() =&gt;</span> <span class="hljs-built_in">Promise</span>.resolve({ <span class="hljs-attr">data</span>: {} }) )
};
</code></pre>
<p>Here we have our fake get function. It is a simple function that is actually a JS object. <code>get</code> is our key and the value is the <strong>mock function</strong>. Like an <strong>axios</strong> API request, we resolve a promise. We wont pass in any data here, we will do that in our testing setup. </p>
<p>Now our testing setup</p>
<pre><code class="lang-javascript"><span class="hljs-comment">//imports</span>
...

afterEach(cleanup)

it(<span class="hljs-string">'Async axios request works'</span>, <span class="hljs-keyword">async</span> () =&gt; {
  axiosMock.get.mockResolvedValue({<span class="hljs-attr">data</span>: { <span class="hljs-attr">title</span>: <span class="hljs-string">'some title'</span> } })

  <span class="hljs-keyword">const</span> url = <span class="hljs-string">'https://jsonplaceholder.typicode.com/posts/1'</span>
  <span class="hljs-keyword">const</span> { getByText, getByTestId, rerender } = render(<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">TestAxios</span> <span class="hljs-attr">url</span>=<span class="hljs-string">{url}</span> /&gt;</span></span>);

  expect(getByText(<span class="hljs-regexp">/...Loading/i</span>).textContent).toBe(<span class="hljs-string">"...Loading"</span>)

  <span class="hljs-keyword">const</span> resolvedEl = <span class="hljs-keyword">await</span> waitForElement(<span class="hljs-function">() =&gt;</span> getByTestId(<span class="hljs-string">"title"</span>));

  expect((resolvedEl).textContent).toBe(<span class="hljs-string">"some title"</span>)

  expect(axiosMock.get).toHaveBeenCalledTimes(<span class="hljs-number">1</span>);
  expect(axiosMock.get).toHaveBeenCalledWith(url);
 })
</code></pre>
<p>The first thing we do in our test is call our fake <strong>axios get request</strong>, and mock the resolved value with ironically the <code>mockResolvedValue</code> function offered by jest. This function does exactly what its name says, it resolves a promise with the data we pass in, which simulates what axios does. </p>
<p>This function has to be called before our <code>render()</code> function otherwise the test wont work. Because remember we are mocking the <strong>axios library</strong> itself. When our component runs the <code>import axios from 'axios';</code> command it will be <strong>importing our fake axios library</strong> instead of the real one and this fake axios will be substituted in our component wherever we used axios. </p>
<p>Next we get our "...Loading" text node since this is what will be displayed before the promise resolves. After this we a function we havent seen before the <code>waitForElement()</code>  function, which will wait until the promise resolves before going to the next assertion. </p>
<p>Also notice the <strong>await</strong> and <strong>async</strong> keywords, these are used in the exact same way as they are used in a non testing environment. </p>
<p>Once resolved the DOM node will have the text of "some title" which is the data we passed to our fake mock axios library. </p>
<p>Next we make sure the request was only called once and with the right url. Even though we are testing the url we didnt make an API request with this url. </p>
<p>And this is it for API requests with axios. In the next section we will look at e to e tests with cypress. </p>
<h2 id="heading-cypress">Cypress</h2>
<p>Lets now go over cypress which I believe is the best framework to run e to e tests. We are now longer in jest land, we will now be working solely with cypress which has its own testing environment and syntax.</p>
<p>Cypress is pretty amazing and powerful. So amazing and powerful in fact that we can run every test we just went over in one test block and watch cypress run these tests in real time in a simulated browser. </p>
<p>Pretty cool, huh? </p>
<p>I think so. Anyway, before we can do that we need to setup cypress. Surprisingly Cypress can be installed as a regular npm module. </p>
<p><code>npm install cypress</code></p>
<p>To run cypress you will need to use this command. </p>
<p><code>node_modules/.bin/cypress open</code></p>
<p>If that seems cumbersome to write every time you want open cypress so you can add it to your package.json. </p>
<pre><code class="lang-javascript">...

  <span class="hljs-string">"scripts"</span>: {
    <span class="hljs-string">"start"</span>: <span class="hljs-string">"react-scripts start"</span>,
    <span class="hljs-string">"build"</span>: <span class="hljs-string">"react-scripts build"</span>,
    <span class="hljs-string">"test"</span>: <span class="hljs-string">"react-scripts test"</span>,
    <span class="hljs-string">"eject"</span>: <span class="hljs-string">"react-scripts eject"</span>,
    <span class="hljs-string">"cypress"</span>: <span class="hljs-string">"node_modules/.bin/cypress open"</span>, 

   ...
</code></pre>
<p>this will allow you to open up cypress with just the <code>npm run cypress</code> command. </p>
<p>Opening up cypress will give you a GUI that looks like this.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2019/07/image-14.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>To actually run the cypress tests, your app will have to be running at the same time, which we will see in a second. </p>
<p>Running the <code>cypress open</code> command will give you a basic configuration of cypress and create some files and folders for your automatically. A cypress folder will be created in the project root. We will write our code in the integration folder. </p>
<p>We can begin by deleting the examples folder. Unlike jest, cypress files take a <code>.spec.js</code> extension.  Because this is a e to e test we will run it on our main <code>App.js</code> file. So you should have a directory structure that now looks like this. </p>
<p><img src="https://www.freecodecamp.org/news/content/images/2019/07/image-21.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>We can also set a Base url in the cypress.json file. Just like this: </p>
<p><code>{ "baseUrl": "[http://localhost:3000](http://localhost:3000)" }</code></p>
<p>Now for our large monolithic test </p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> React <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;

describe (<span class="hljs-string">'complete e to e test'</span>, <span class="hljs-function">() =&gt;</span> {
  it(<span class="hljs-string">'e to e test'</span>, <span class="hljs-function">() =&gt;</span> {
    cy.visit(<span class="hljs-string">'/'</span>)
    <span class="hljs-comment">//counter test</span>
    cy.contains(<span class="hljs-string">"Clicked: 0"</span>)
      .click()
    cy.contains(<span class="hljs-string">"Clicked: 1"</span>)
    <span class="hljs-comment">// basic hooks test</span>
    cy.contains(<span class="hljs-string">"Initial State"</span>)
    cy.contains(<span class="hljs-string">"State Change Button"</span>)
      .click()
    cy.contains(<span class="hljs-string">"Initial State Changed"</span>)
    cy.contains(<span class="hljs-string">"Moe"</span>)
    cy.contains(<span class="hljs-string">"Change Name"</span>)
      .click()
    cy.contains(<span class="hljs-string">"Steve"</span>)
    <span class="hljs-comment">//useReducer test</span>
    cy.contains(<span class="hljs-string">'stateprop1 is false'</span>)
    cy.contains(<span class="hljs-string">'Dispatch Success'</span>)
      .click()
    cy.contains(<span class="hljs-string">'stateprop1 is true'</span>)
    <span class="hljs-comment">//useContext test</span>
    cy.contains(<span class="hljs-string">"Some Text"</span>)
    cy.contains(<span class="hljs-string">'Change Text'</span>)
      .click()
    cy.contains(<span class="hljs-string">"Some Other Text"</span>)
    <span class="hljs-comment">//form test</span>
    cy.get(<span class="hljs-string">'#text1'</span>)
      .type(<span class="hljs-string">'New Text {enter}'</span>)
    cy.contains(<span class="hljs-string">"Change: New Text"</span>)
    cy.contains(<span class="hljs-string">"Submit Value: New Text"</span>)
    <span class="hljs-comment">//axios test</span>
    cy.request(<span class="hljs-string">'https://jsonplaceholder.typicode.com/posts/1'</span>)
      .should(<span class="hljs-function"><span class="hljs-params">res</span> =&gt;</span> {
          expect(res.body).not.to.be.null
          cy.contains(res.body.title)
        })
  });
});
</code></pre>
<p>As mentioned we are running every single test we just went over in one test block. I have separated each section with a comment so it will easier to see. </p>
<p>Our test may look intimidating at first but most of the individual tests will follow a basic arrange-act-assert pattern.  </p>
<pre><code class="lang-javascript">
cy.contains(Some innerHTML text <span class="hljs-keyword">of</span> DOM node)

cy.contains (text <span class="hljs-keyword">of</span> button)
.click()

cy.contains(Updated innerHTML text <span class="hljs-keyword">of</span> DOM node)
</code></pre>
<p>Since this is a e to e test you will find no mocking at all. Our app will be running in its full development version in a simulated browser with a UI. This will be as close to testing our app in realistic way as we can get.   </p>
<p>Unlike unit and integration tests we do not need to explicitly assert some things. This is because some Cypress commands have built in default assertions. <strong>Default assertions</strong> are exactly what they sound like, they are asserted by default so no need to add a matcher.  </p>
<p> <a target="_blank" href="https://docs.cypress.io/guides/core-concepts/introduction-to-cypress.html#Default-Assertions">Cypress default assertions</a> </p>
<p>Commands are chained together so order is important and one command will wait until a previous command is completed before running. </p>
<p>Even when testing with cypress we will stick to our philosophy of not testing implementation details. In practice this is going to mean that we will not use html/css classes, ids or properties as selectors if we can help it. The only time we will need to use id is to get our form input element.  </p>
<p>We will make use of the <code>cy.contains()</code> command which will return a DOM node with matching text. Seeing and Interacting with text on the UI is what our end user will do, so testing this way will be in line with our guiding principle. </p>
<p>Since we are not stubbing or mocking anything you will notice our tests will look very simplistic. This is good since this is a live running app, our tests will not have any artificial values. </p>
<p>In our axios test we will make a real http request to our endpoint. Making a real http request in an e to e test is common. Then we will check to see if that value is not null. Then make sure that the data of the response appears in our UI. </p>
<p>If done correctly you should see that cypress successfully ran the tests in chromium.   </p>
<p><img src="https://www.freecodecamp.org/news/content/images/2019/07/image-22.png" alt="Image" width="600" height="400" loading="lazy"></p>
<h2 id="heading-continuous-integration">Continuous Integration</h2>
<p>Keeping track and Running all these tests manually can become tedious. So we have Continuous Integration, A way to automatically run our tests continuously.</p>
<h3 id="heading-travis-ci">Travis CI</h3>
<p>To keep things simple we'll just use Travis CI for our Continuous integration. You should know though that there are much more complex CI setups using Docker and Jenkins.</p>
<p>You will need to sign up for a Travis and Github account, both of these are luckily free. </p>
<p>I would suggest just using the "Sign Up with Github" option on Travis CI. </p>
<p>Once there you can just go on your profile icon and click the slider button next to the repository you want CI on.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2019/07/image-15.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>So that Travis CI knows what to do we will need to configure a .travis.yml file in our project root. </p>
<pre><code class="lang-yaml"><span class="hljs-attr">language:</span> <span class="hljs-string">node_js</span>

<span class="hljs-attr">node_js:</span> 
  <span class="hljs-bullet">-</span> <span class="hljs-string">stable</span>


<span class="hljs-attr">install:</span>
  <span class="hljs-bullet">-</span> <span class="hljs-string">npm</span> <span class="hljs-string">install</span>

<span class="hljs-attr">script:</span>
  <span class="hljs-bullet">-</span> <span class="hljs-string">npm</span> <span class="hljs-string">run</span> <span class="hljs-string">test</span>
  <span class="hljs-bullet">-</span> <span class="hljs-string">npm</span> <span class="hljs-string">run</span> <span class="hljs-string">coveralls</span>
</code></pre>
<p>This essentially tells Travis that we are using node_js, download the stable version, install the dependencies and run the npm run test and npm run coveralls command.  </p>
<p>And this is it. You can know go on the dashboard and start the build. Travis will run the tests automatically and give you an output like this.  If your tests pass you are good to go. If they fail, your build will fail and you will need to fix your code and restart the build. </p>
<p><img src="https://www.freecodecamp.org/news/content/images/2019/07/image-16.png" alt="Image" width="600" height="400" loading="lazy"></p>
<h3 id="heading-coveralls">Coveralls</h3>
<p>coverall gives us a coverage report that essentially tells us how much of our code is being tested. </p>
<p>You will need to sign up to coveralls and sync with your github account. Similar to Travis CI, just go to the add repos tab and turn on the repo that you also activated on Travis CI. </p>
<p><img src="https://www.freecodecamp.org/news/content/images/2019/07/image-17.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Next go to your package.json file and add this line of code </p>
<pre><code>  <span class="hljs-string">"scripts"</span>: {
    <span class="hljs-string">"start"</span>: <span class="hljs-string">"react-scripts start"</span>,
    <span class="hljs-string">"build"</span>: <span class="hljs-string">"react-scripts build"</span>,
    <span class="hljs-string">"test"</span>: <span class="hljs-string">"react-scripts test --coverage"</span>,
    <span class="hljs-string">"eject"</span>: <span class="hljs-string">"react-scripts eject"</span>,
    <span class="hljs-string">"cypress"</span>: <span class="hljs-string">"node_modules/.bin/cypress open"</span>, 
    <span class="hljs-string">"coveralls"</span>: <span class="hljs-string">"cat ./coverage/lcov.info | node node_modules/.bin/coveralls"</span>
  },
</code></pre><p>Be sure to add the <code>--coverage</code>  flag to the <code>react-scripts test</code> command. This is what will generate the coverage data that coveralls will use to generate a coverage report. </p>
<p>And you can actually see this coverage data on the Travis CI console after your tests have ran.  </p>
<p><img src="https://www.freecodecamp.org/news/content/images/2019/07/image-18.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Since we are not dealing with a private repo or Travis CI pro, we dont need to worry about repo tokens. </p>
<p>Once your done you can add a badge to your repo README by copying the provided link on the dashboard. </p>
<p><img src="https://www.freecodecamp.org/news/content/images/2019/07/image-19.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>It will look like this. </p>
<p><img src="https://www.freecodecamp.org/news/content/images/2019/07/image-20.png" alt="Image" width="600" height="400" loading="lazy"></p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>Count yourself among the top 20% of developers in terms of React testing skill if you made it through the entire tutorial. </p>
<p>Thanks for reading. cheers. </p>
<blockquote>
<p>You can follow me on twitter for more tutorials in the future: <a target="_blank" href="https://twitter.com/iqbal125sf?lang=en">https://twitter.com/iqbal125sf?lang=en</a></p>
</blockquote>
<h3 id="heading-further-reading">Further Reading</h3>
<p><strong>Blog Posts:</strong></p>
<p><a target="_blank" href="https://djangostars.com/blog/what-and-how-to-test-with-enzyme-and-jest-full-instruction-on-react-component-testing/#utm_source=medium&amp;utm_medium=blog.bitsrc.io&amp;utm_campaign=react%20components%20testing&amp;utm_content=continue%20reading%20the%20original%20article%20on%20our%C2%A0blog">https://djangostars.com/blog/what-and-how-to-test-with-enzyme-and-jest-full-instruction-on-react-component-testing/</a></p>
<p><a target="_blank" href="https://engineering.ezcater.com/the-case-against-react-snapshot-testing">https://engineering.ezcater.com/the-case-against-react-snapshot-testing</a></p>
<p><a target="_blank" href="https://medium.com/@tomgold_48918/why-i-stopped-using-snapshot-testing-with-jest-3279fe41ffb2">https://medium.com/@tomgold_48918/why-i-stopped-using-snapshot-testing-with-jest-3279fe41ffb2</a></p>
<p><a target="_blank" href="https://circleci.com/blog/continuously-testing-react-applications-with-jest-and-enzyme/">https://circleci.com/blog/continuously-testing-react-applications-with-jest-and-enzyme/</a></p>
<p><a target="_blank" href="https://testing.googleblog.com/2015/04/just-say-no-to-more-end-to-end-tests.html">https://testing.googleblog.com/2015/04/just-say-no-to-more-end-to-end-tests.html</a></p>
<p><a target="_blank" href="https://willowtreeapps.com/ideas/best-practices-for-unit-testing-with-a-react-redux-approach">https://willowtreeapps.com/ideas/best-practices-for-unit-testing-with-a-react-redux-approach</a></p>
<p><a target="_blank" href="https://blog.pragmatists.com/genuine-guide-to-testing-react-redux-applications-6f3265c11f63">https://blog.pragmatists.com/genuine-guide-to-testing-react-redux-applications-6f3265c11f63</a></p>
<p><a target="_blank" href="https://hacks.mozilla.org/2018/04/testing-strategies-for-react-and-redux/">https://hacks.mozilla.org/2018/04/testing-strategies-for-react-and-redux/</a></p>
<p><a target="_blank" href="https://codeburst.io/deliberate-practice-what-i-learned-from-reading-redux-mock-store-8d2d79a4b24d">https://codeburst.io/deliberate-practice-what-i-learned-from-reading-redux-mock-store-8d2d79a4b24d</a></p>
<p><a target="_blank" href="https://www.robinwieruch.de/react-testing-tutorial/">https://www.robinwieruch.de/react-testing-tutorial/</a></p>
<p><a target="_blank" href="https://medium.com/@ryandrewjohnson/unit-testing-components-using-reacts-new-context-api-4a5219f4b3fe">https://medium.com/@ryandrewjohnson/unit-testing-components-using-reacts-new-context-api-4a5219f4b3fe</a>  </p>
<p><strong>Kent C dodds Posts on Testing</strong></p>
<p><a target="_blank" href="https://kentcdodds.com/blog/introducing-the-react-testing-library">https://kentcdodds.com/blog/introducing-the-react-testing-library</a></p>
<p><a target="_blank" href="https://kentcdodds.com/blog/unit-vs-integration-vs-e2e-tests">https://kentcdodds.com/blog/unit-vs-integration-vs-e2e-tests</a></p>
<p><a target="_blank" href="https://kentcdodds.com/blog/why-i-never-use-shallow-rendering">https://kentcdodds.com/blog/why-i-never-use-shallow-rendering</a></p>
<p><a target="_blank" href="https://kentcdodds.com/blog/demystifying-testing">https://kentcdodds.com/blog/demystifying-testing</a></p>
<p><a target="_blank" href="https://kentcdodds.com/blog/effective-snapshot-testing">https://kentcdodds.com/blog/effective-snapshot-testing</a></p>
<p><a target="_blank" href="https://kentcdodds.com/blog/testing-implementation-details">https://kentcdodds.com/blog/testing-implementation-details</a></p>
<p><a target="_blank" href="https://kentcdodds.com/blog/common-testing-mistakes">https://kentcdodds.com/blog/common-testing-mistakes</a></p>
<p><a target="_blank" href="https://kentcdodds.com/blog/ui-testing-myths">https://kentcdodds.com/blog/ui-testing-myths</a></p>
<p><a target="_blank" href="https://kentcdodds.com/blog/why-youve-been-bad-about-testing">https://kentcdodds.com/blog/why-youve-been-bad-about-testing</a></p>
<p><a target="_blank" href="https://kentcdodds.com/blog/the-merits-of-mocking">https://kentcdodds.com/blog/the-merits-of-mocking</a></p>
<p><a target="_blank" href="https://kentcdodds.com/blog/how-to-know-what-to-test">https://kentcdodds.com/blog/how-to-know-what-to-test</a></p>
<p><a target="_blank" href="https://kentcdodds.com/blog/avoid-the-test-user">https://kentcdodds.com/blog/avoid-the-test-user</a>  </p>
<p><strong>Cheat Sheets / github threads</strong></p>
<p><a target="_blank" href="https://devhints.io/enzyme">https://devhints.io/enzyme</a></p>
<p><a target="_blank" href="https://devhints.io/enzyme">https://devhints.io</a>/jest </p>
<p><a target="_blank" href="https://github.com/ReactTraining/react-router/tree/master/packages/react-router/modules/__tests__">https://github.com/ReactTraining/react-router/tree/master/packages/react-router/modules/<strong>tests</strong></a></p>
<p><a target="_blank" href="https://github.com/airbnb/enzyme/issues/1938">https://github.com/airbnb/enzyme/issues/1938</a> </p>
<p><a target="_blank" href="https://gist.github.com/fokusferit/e4558d384e4e9cab95d04e5f35d4f913">https://gist.github.com/fokusferit/e4558d384e4e9cab95d04e5f35d4f913</a></p>
<p><a target="_blank" href="https://airbnb.io/enzyme/docs/api/selector.html">https://airbnb.io/enzyme/docs/api/selector.html</a>  </p>
<p><strong>Docs</strong></p>
<p><a target="_blank" href="https://docs.cypress.io/">https://docs.cypress.io</a></p>
<p><a target="_blank" href="https://airbnb.io/enzyme/">https://airbnb.io/enzyme/</a></p>
<p><a target="_blank" href="https://github.com/dmitry-zaets/redux-mock-store">https://github.com/dmitry-zaets/redux-mock-store</a></p>
<p><a target="_blank" href="https://jestjs.io/docs/en">https://jestjs.io/docs/en</a></p>
<p><a target="_blank" href="https://testing-library.com/docs/learning">https://testing-library.com/docs/learning</a></p>
<p><a target="_blank" href="https://sinonjs.org/releases/v7.3.2/">https://sinonjs.org/releases/v7.3.2/</a></p>
<p><a target="_blank" href="https://redux.js.org/recipes/writing-tests">https://redux.js.org/recipes/writing-tests</a></p>
<p><a target="_blank" href="https://jestjs.io/docs/en/using-matchers">https://jestjs.io/docs/en/using-matchers</a></p>
<p><a target="_blank" href="https://jestjs.io/docs/en/api">https://jestjs.io/docs/en/api</a>  </p>
 ]]>
                </content:encoded>
            </item>
        
    </channel>
</rss>
