<?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[ Software Testing - 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[ Software Testing - freeCodeCamp.org ]]>
            </title>
            <link>https://www.freecodecamp.org/news/</link>
        </image>
        <generator>Eleventy</generator>
        <lastBuildDate>Wed, 27 May 2026 16:21:32 +0000</lastBuildDate>
        <atom:link href="https://www.freecodecamp.org/news/tag/software-testing/rss.xml" rel="self" type="application/rss+xml" />
        <ttl>60</ttl>
        
            <item>
                <title>
                    <![CDATA[ Unit Testing in Go - A Beginner's Guide ]]>
                </title>
                <description>
                    <![CDATA[ If you're learning Go and you’re already familiar with the idea of unit testing, the main challenge is usually not why to test, but how to test in Go. Go takes a deliberately minimal approach to testing. There are no built-in assertions, no annotatio... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/unit-testing-in-go-a-beginners-guide/</link>
                <guid isPermaLink="false">696535ad7a48c374647910f2</guid>
                
                    <category>
                        <![CDATA[ Go Language ]]>
                    </category>
                
                    <category>
                        <![CDATA[ golang ]]>
                    </category>
                
                    <category>
                        <![CDATA[ unit testing ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Testing ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Software Testing ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Gabor Koos ]]>
                </dc:creator>
                <pubDate>Mon, 12 Jan 2026 17:55:57 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/res/hashnode/image/upload/v1768240528981/73c9c9f6-4942-4c39-9e62-87f540fd2233.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>If you're learning Go and you’re already familiar with the idea of <strong>unit testing</strong>, the main challenge is usually not <em>why</em> to test, but <em>how</em> to test in Go.</p>
<p>Go takes a deliberately minimal approach to testing. There are no built-in assertions, no annotations, and no special syntax. Instead, tests are written as regular Go code using a small standard library package, and run with a single command. This can feel unusual at first if you're coming from ecosystems with richer testing frameworks, but it quickly becomes predictable and easy to reason about.</p>
<p>In this article, we'll look at how unit testing works in Go in practice. We'll write a few small tests, run them from the command line, and cover the most common patterns you'll see in real Go codebases, such as table-driven tests and testing functions that return errors. We'll focus on the essentials and won't cover more advanced topics like mocks or external frameworks.</p>
<p>The goal is to show how familiar testing concepts translate into idiomatic Go. By the end, you should feel comfortable reading and writing basic unit tests and integrating them into your regular Go workflow.</p>
<h2 id="heading-what-well-cover">What We'll Cover:</h2>
<ol>
<li><p><a class="post-section-overview" href="#heading-prerequisites">Prerequisites</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-writing-your-first-test">Writing Your First Test</a></p>
<ul>
<li><p><a class="post-section-overview" href="#heading-running-your-test">Running Your Test</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-divide-by-zero">Divide by Zero</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-terrorf-vs-tfatalf">t.Errorf vs t.Fatalf</a></p>
</li>
</ul>
</li>
<li><p><a class="post-section-overview" href="#heading-table-driven-tests">Table-Driven Tests</a></p>
<ul>
<li><p><a class="post-section-overview" href="#heading-table-driven-add-test">Table-Driven Add Test</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-table-driven-divide-test">Table-Driven Divide Test</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-exercise">Exercise</a></p>
</li>
</ul>
</li>
<li><p><a class="post-section-overview" href="#heading-testing-functions-that-return-errors">Testing Functions That Return Errors</a></p>
<ul>
<li><p><a class="post-section-overview" href="#heading-safe-divide-function">Safe Divide Function</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-writing-tests-for-safedivide">Writing Tests for SafeDivide()</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-exercise-1">Exercise</a></p>
</li>
</ul>
</li>
<li><p><a class="post-section-overview" href="#heading-best-practices-and-tips">Best Practices and Tips</a></p>
<ul>
<li><p><a class="post-section-overview" href="#heading-name-tests-clearly">Name Tests Clearly</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-keep-tests-small-and-focused">Keep Tests Small and Focused</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-use-table-driven-tests-for-repetitive-cases">Use Table-Driven Tests for Repetitive Cases</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-check-errors-explicitly">Check Errors Explicitly</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-avoid-panics-when-possible">Avoid Panics When Possible</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-run-tests-frequently">Run Tests Frequently</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-keep-tests-in-the-same-package">Keep Tests in the Same Package</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-use-tfatalf-vs-terrorf-appropriately">Use t.Fatalf vs t.Errorf Appropriately</a></p>
</li>
</ul>
</li>
<li><p><a class="post-section-overview" href="#heading-conclusion">Conclusion</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-solutions-to-exercises">Solutions to Exercises</a></p>
<ul>
<li><p><a class="post-section-overview" href="#heading-subtract-function-and-tests">Subtract Function and Tests</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-safesubtract-function-and-tests">SafeSubtract Function and Tests</a></p>
</li>
</ul>
</li>
</ol>
<h2 id="heading-prerequisites">Prerequisites</h2>
<p>Before you start, you should be comfortable with:</p>
<ul>
<li><p>Writing and running basic Go programs</p>
</li>
<li><p>Defining and calling functions in Go</p>
</li>
<li><p>Understanding basic Go types (int, string, bool, and so on)</p>
</li>
<li><p>Using the Go command-line tool (go run, go build)</p>
</li>
<li><p>Basic understanding of unit tests: what a test is and why it's useful</p>
</li>
<li><p>Familiarity with Test-Driven Development concepts like testing before or alongside writing code</p>
</li>
<li><p>Awareness of common testing ideas such as assertions, test coverage, and checking error conditions</p>
</li>
</ul>
<p>You don't need prior experience with Go's <code>testing</code> package or Go-specific test patterns, as this guide will cover all of that.</p>
<h2 id="heading-writing-your-first-test">Writing Your First Test</h2>
<p>Let's start with a simple function to test. Imagine you have a small <code>calc</code> package with an <code>Add</code> function:</p>
<pre><code class="lang-go"><span class="hljs-comment">// calc.go</span>
<span class="hljs-keyword">package</span> calc

<span class="hljs-comment">// Add returns the sum of two integers</span>
<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">Add</span><span class="hljs-params">(a, b <span class="hljs-keyword">int</span>)</span> <span class="hljs-title">int</span></span> {
    <span class="hljs-keyword">return</span> a + b
}
</code></pre>
<p>To test this function, create a new file named <code>calc_test.go</code> in the same package. In Go, test files must end with <code>_test.go</code> to be recognized by the testing tool.</p>
<p>Inside <code>calc_test.go</code>, you write a test function:</p>
<pre><code class="lang-go"><span class="hljs-comment">// calc_test.go</span>
<span class="hljs-keyword">package</span> calc

<span class="hljs-keyword">import</span> <span class="hljs-string">"testing"</span>

<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">TestAdd</span><span class="hljs-params">(t *testing.T)</span></span> {
    got := Add(<span class="hljs-number">2</span>, <span class="hljs-number">3</span>)
    want := <span class="hljs-number">5</span>
    <span class="hljs-keyword">if</span> got != want {
        t.Errorf(<span class="hljs-string">"Add(2, 3) = %d; want %d"</span>, got, want)
    }
}
</code></pre>
<p>Here's what's happening:</p>
<ul>
<li><p>The function name starts with <code>Test</code> and takes a single <code>*testing.T</code> parameter. Go automatically discovers and runs any function that follows this convention.</p>
</li>
<li><p>The <code>t.Errorf</code> call reports a test failure. Unlike some frameworks, Go doesn't provide special assertions – you simply check a condition and call <code>t.Errorf</code> or <code>t.Fatalf</code> if it fails.</p>
</li>
<li><p>Each test is a standalone function. You can write as many as you like, and Go will run them all.</p>
</li>
</ul>
<h3 id="heading-running-your-test">Running Your Test</h3>
<p>Once the file is saved, you can run your test with:</p>
<pre><code class="lang-bash">go <span class="hljs-built_in">test</span>
</code></pre>
<p>This runs tests for the current package (files ending with <code>_test.go</code>). If you want to run tests recursively in all subdirectories of your project, use:</p>
<pre><code class="lang-bash">go <span class="hljs-built_in">test</span> ./...
</code></pre>
<p>The <code>./...</code> pattern is shorthand for "run tests in this directory and all subdirectories". This is especially useful in larger projects where your code is spread across multiple packages.</p>
<p>If everything is working, you should see output indicating that the test passed:</p>
<pre><code class="lang-bash">$ go <span class="hljs-built_in">test</span>
PASS
ok      _/C_/projects/Articles/Go_Testing       0.334s
</code></pre>
<p>You can add the <code>-v</code> flag for verbose output:</p>
<pre><code class="lang-bash">go <span class="hljs-built_in">test</span> -v
</code></pre>
<p>This will show you the names of the tests as they run:</p>
<pre><code class="lang-bash">$ go <span class="hljs-built_in">test</span> -v
=== RUN   TestAdd
--- PASS: TestAdd (0.00s)
PASS
ok      _/C_/projects/Articles/Go_Testing       0.356s
</code></pre>
<p>Not much difference for a single test, but it becomes useful as you add more tests.</p>
<p>Now let's see what happens if the test fails. Change the expected value in <code>calc_test.go</code> to an incorrect one:</p>
<pre><code class="lang-go">  ...
    want := <span class="hljs-number">6</span> <span class="hljs-comment">// Incorrect expected value</span>
  ...
</code></pre>
<p>Run the tests again:</p>
<pre><code class="lang-bash">$ go <span class="hljs-built_in">test</span>
--- FAIL: TestAdd (0.00s)
    calc_test.go:9: Add(2, 3) = 5; want 6
FAIL
<span class="hljs-built_in">exit</span> status 1
FAIL    _/C_/projects/Articles/Go_Testing       0.340s
</code></pre>
<p>or with verbose output:</p>
<pre><code class="lang-bash">$ go <span class="hljs-built_in">test</span> -v
=== RUN   TestAdd
    calc_test.go:9: Add(2, 3) = 5; want 6
--- FAIL: TestAdd (0.00s)
FAIL
<span class="hljs-built_in">exit</span> status 1
FAIL    _/C_/projects/Articles/Go_Testing       0.337s
</code></pre>
<p>Of course, your tests should always check for the correct expected values! A failing (but correct) test is a sign that your code needs to be fixed.</p>
<p>We only created one test file and one test function with one assertion here, but Go's testing tool can handle many files and functions at once. Behind the scenes, Go will automatically:</p>
<ul>
<li><p>Find <strong>all</strong> <code>_test.go</code> files in the specified packages (for example, current directory for <code>go test</code>, or recursively in all subdirectories with <code>go test ./...</code>).</p>
</li>
<li><p>Identify functions that start with <code>Test</code> and have the correct signature.</p>
</li>
<li><p>Compile them together with your package into a temporary test binary.</p>
</li>
<li><p>Execute each test function and report the results.</p>
</li>
</ul>
<p>To prove this, let's quickly add a <code>Divide</code> function to our package:</p>
<pre><code class="lang-go"><span class="hljs-comment">// calc.go</span>
...
<span class="hljs-comment">// Divide returns the result of dividing a by b</span>
<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">Divide</span><span class="hljs-params">(a, b <span class="hljs-keyword">int</span>)</span> <span class="hljs-title">int</span></span> {
    <span class="hljs-keyword">return</span> a / b
}
</code></pre>
<p>(Note that this is an <strong>integer division</strong>, so fractional parts are discarded. <code>Divide(5, 2)</code> would return <code>2</code>.)</p>
<p>And another test file with a corresponding test:</p>
<pre><code class="lang-go"><span class="hljs-comment">// calc_2_test.go</span>
<span class="hljs-keyword">package</span> calc

<span class="hljs-keyword">import</span> <span class="hljs-string">"testing"</span>

<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">TestDivide</span><span class="hljs-params">(t *testing.T)</span></span> {
    got := Divide(<span class="hljs-number">10</span>, <span class="hljs-number">2</span>)
    want := <span class="hljs-number">5</span>    
    <span class="hljs-keyword">if</span> got != want {
        t.Errorf(<span class="hljs-string">"Divide(10, 2) = %d; want %d"</span>, got, want)
    }    
}
</code></pre>
<p>Now when you run <code>go test</code>, both <code>TestAdd</code> and <code>TestDivide</code> will be executed:</p>
<pre><code class="lang-bash">$ go <span class="hljs-built_in">test</span>
PASS
ok      _/C_/projects/Articles/Go_Testing       0.325s
</code></pre>
<p>Or:</p>
<pre><code class="lang-bash">$ go <span class="hljs-built_in">test</span> -v
=== RUN   TestAdd
--- PASS: TestAdd (0.00s)
=== RUN   TestDivide
--- PASS: TestDivide (0.00s)
PASS
ok      _/C_/projects/Articles/Go_Testing       0.323s
</code></pre>
<h3 id="heading-divide-by-zero">Divide by Zero</h3>
<p>What happens if we try to <code>Divide</code> by zero? Let's add another test case for that:</p>
<pre><code class="lang-go"><span class="hljs-comment">// calc_test.go</span>
...
<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">TestDivideByZero</span><span class="hljs-params">(t *testing.T)</span></span> {
    <span class="hljs-keyword">defer</span> <span class="hljs-function"><span class="hljs-keyword">func</span><span class="hljs-params">()</span></span> {
        <span class="hljs-keyword">if</span> r := <span class="hljs-built_in">recover</span>(); r == <span class="hljs-literal">nil</span> { <span class="hljs-comment">// Check if a panic occurred</span>
            t.Errorf(<span class="hljs-string">"Divide did not panic on division by zero"</span>)
        }
    }()
    Divide(<span class="hljs-number">10</span>, <span class="hljs-number">0</span>) <span class="hljs-comment">// This should cause a panic</span>
}
</code></pre>
<p>This test checks that the <code>Divide</code> function panics when dividing by zero. When you run the tests again, you'll see that this new test also passes:</p>
<pre><code class="lang-bash">$ go <span class="hljs-built_in">test</span> -v
=== RUN   TestAdd
--- PASS: TestAdd (0.00s)
=== RUN   TestDivide
--- PASS: TestDivide (0.00s)
=== RUN   TestDivideByZero
--- PASS: TestDivideByZero (0.00s)
PASS
ok      _/C_/projects/Articles/Go_Testing       0.312s
</code></pre>
<p>(Note that in real-world Go code, it's better to return <code>(int, error)</code> for unsafe operations instead of panicking.)</p>
<p>Feel free to experiment by adding more test cases, changing expected values, and exploring how Go's testing framework handles different scenarios.</p>
<h3 id="heading-terrorf-vs-tfatalf"><code>t.Errorf</code> vs <code>t.Fatalf</code></h3>
<p>In the examples above, we used <code>t.Errorf</code> to report test failures. This function logs the error but allows the test to continue running. This is useful when you want to check multiple conditions in a single test function.</p>
<p>In contrast, <code>t.Fatalf</code> logs the error and immediately stops the execution of the current test. Use <code>t.Fatalf</code> when continuing the test after a failure doesn't make sense or could cause misleading results.</p>
<p>For example, in the <code>TestDivideByZero</code> test, if the <code>Divide</code> function does not panic, we use <code>t.Errorf</code> to report the failure but continue to the end of the test. But if we had additional checks after the division, we might want to use <code>t.Fatalf</code> to stop execution immediately upon failure.</p>
<p>While <code>t.Errorf</code> and <code>t.Fatalf</code> use <code>fmt</code>-style formatting, for simple messages without formatting, you can also use <code>t.Error</code> and <code>t.Fatal</code>, respectively.</p>
<p>In the next section, we'll look at <em>table-driven tests</em>, a common Go pattern for testing multiple cases efficiently.</p>
<h2 id="heading-table-driven-tests">Table-Driven Tests</h2>
<p>In Go, it's common to want to run the same test logic for multiple inputs and expected outputs. Rather than writing a separate test function for each case, Go developers often use <strong>table-driven tests</strong>. This pattern keeps your tests concise, readable, and easy to extend.</p>
<h3 id="heading-table-driven-add-test">Table-Driven <code>Add</code> Test</h3>
<p>Let's rewrite our Add test using a table-driven approach (and delete <code>calc_2_test.go</code> for clarity):</p>
<pre><code class="lang-go"><span class="hljs-comment">// calc_test.go</span>
<span class="hljs-keyword">package</span> calc

<span class="hljs-keyword">import</span> <span class="hljs-string">"testing"</span>

<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">TestAddTableDriven</span><span class="hljs-params">(t *testing.T)</span></span> {
    tests := []<span class="hljs-keyword">struct</span> {<span class="hljs-comment">// Define a struct for each test case and create a slice of them</span>
        name <span class="hljs-keyword">string</span>
        a, b <span class="hljs-keyword">int</span>
        want <span class="hljs-keyword">int</span>
    }{
        {<span class="hljs-string">"both positive"</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>, <span class="hljs-number">5</span>},
        {<span class="hljs-string">"positive + zero"</span>, <span class="hljs-number">5</span>, <span class="hljs-number">0</span>, <span class="hljs-number">5</span>},
        {<span class="hljs-string">"negative + positive"</span>, <span class="hljs-number">-1</span>, <span class="hljs-number">4</span>, <span class="hljs-number">3</span>},
        {<span class="hljs-string">"both negative"</span>, <span class="hljs-number">-2</span>, <span class="hljs-number">-3</span>, <span class="hljs-number">-5</span>},
    }

    <span class="hljs-keyword">for</span> _, tt := <span class="hljs-keyword">range</span> tests {<span class="hljs-comment">// Loop over each test case</span>
        t.Run(tt.name, <span class="hljs-function"><span class="hljs-keyword">func</span><span class="hljs-params">(t *testing.T)</span></span> {<span class="hljs-comment">// Run each case as a subtest</span>
            got := Add(tt.a, tt.b)
            <span class="hljs-keyword">if</span> got != tt.want {<span class="hljs-comment">// Check the result</span>
                t.Errorf(<span class="hljs-string">"Add(%d, %d) = %d; want %d"</span>, tt.a, tt.b, got, tt.want) <span class="hljs-comment">// Report failure if it doesn't match</span>
            }
        })
    }
}
</code></pre>
<p>Here's how it works:</p>
<ul>
<li><p>We define a <strong>slice of structs</strong>, each representing a test case.</p>
</li>
<li><p>Each struct contains the test name, input values, and the expected result.</p>
</li>
<li><p>We loop over the slice and call <code>t.Run(tt.name, func(t *testing.T) { ... })</code> to run each test as a <strong>subtest</strong>.</p>
</li>
<li><p>If a subtest fails, you can see which one by its name in the output.</p>
</li>
</ul>
<pre><code class="lang-bash">$ go <span class="hljs-built_in">test</span>
PASS
ok      _/C_/projects/Articles/Go_Testing       0.452s
</code></pre>
<p>Or to see detailed output:</p>
<pre><code class="lang-bash">$ go <span class="hljs-built_in">test</span> -v
=== RUN   TestAddTableDriven
=== RUN   TestAddTableDriven/both_positive
=== RUN   TestAddTableDriven/positive_+_zero
=== RUN   TestAddTableDriven/negative_+_positive
=== RUN   TestAddTableDriven/both_negative
--- PASS: TestAddTableDriven (0.00s)
    --- PASS: TestAddTableDriven/both_positive (0.00s)
    --- PASS: TestAddTableDriven/positive_+_zero (0.00s)
    --- PASS: TestAddTableDriven/negative_+_positive (0.00s)
    --- PASS: TestAddTableDriven/both_negative (0.00s)
PASS
ok      _/C_/projects/Articles/Go_Testing       0.385s
</code></pre>
<h3 id="heading-table-driven-divide-test">Table-Driven Divide Test</h3>
<p>We can apply the same pattern to <code>Divide</code>, including checking for divide-by-zero:</p>
<pre><code class="lang-go"><span class="hljs-comment">// calc_test.go</span>
...
<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">TestDivideTableDriven</span><span class="hljs-params">(t *testing.T)</span></span> {
    tests := []<span class="hljs-keyword">struct</span> { <span class="hljs-comment">// Define test cases</span>
        name     <span class="hljs-keyword">string</span>
        a, b     <span class="hljs-keyword">int</span>
        want     <span class="hljs-keyword">int</span>
        wantPanic <span class="hljs-keyword">bool</span>
    }{
        {<span class="hljs-string">"normal division"</span>, <span class="hljs-number">10</span>, <span class="hljs-number">2</span>, <span class="hljs-number">5</span>, <span class="hljs-literal">false</span>},
        {<span class="hljs-string">"division by zero"</span>, <span class="hljs-number">10</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-literal">true</span>},
    }

    <span class="hljs-keyword">for</span> _, tt := <span class="hljs-keyword">range</span> tests { <span class="hljs-comment">// Loop over</span>
        t.Run(tt.name, <span class="hljs-function"><span class="hljs-keyword">func</span><span class="hljs-params">(t *testing.T)</span></span> { <span class="hljs-comment">// Run subtest</span>
            <span class="hljs-keyword">if</span> tt.wantPanic { <span class="hljs-comment">// Check for expected panic</span>
                <span class="hljs-keyword">defer</span> <span class="hljs-function"><span class="hljs-keyword">func</span><span class="hljs-params">()</span></span> { <span class="hljs-comment">// Recover from panic</span>
                    <span class="hljs-keyword">if</span> r := <span class="hljs-built_in">recover</span>(); r == <span class="hljs-literal">nil</span> {
                        t.Errorf(<span class="hljs-string">"Divide(%d, %d) did not panic"</span>, tt.a, tt.b)
                    }
                }()
            }
            got := Divide(tt.a, tt.b) <span class="hljs-comment">// Tests that do not panic</span>
            <span class="hljs-keyword">if</span> !tt.wantPanic &amp;&amp; got != tt.want {
                t.Errorf(<span class="hljs-string">"Divide(%d, %d) = %d; want %d"</span>, tt.a, tt.b, got, tt.want)
            }
        })
    }
}
</code></pre>
<p>This example shows how to handle both normal and panic cases in a single table-driven test:</p>
<ul>
<li><p>The <code>wantPanic</code> field tells the test whether we expect a panic.</p>
</li>
<li><p>We use <code>defer</code> and <code>recover</code> to check for a panic when needed.</p>
</li>
<li><p>Normal test cases still check the result as usual.</p>
</li>
</ul>
<p>Run all tests as before:</p>
<pre><code class="lang-bash">$ go <span class="hljs-built_in">test</span> -v
=== RUN   TestAddTableDriven
=== RUN   TestAddTableDriven/both_positive
=== RUN   TestAddTableDriven/positive_+_zero
=== RUN   TestAddTableDriven/negative_+_positive
=== RUN   TestAddTableDriven/both_negative
--- PASS: TestAddTableDriven (0.00s)
    --- PASS: TestAddTableDriven/both_positive (0.00s)
    --- PASS: TestAddTableDriven/positive_+_zero (0.00s)
    --- PASS: TestAddTableDriven/negative_+_positive (0.00s)
    --- PASS: TestAddTableDriven/both_negative (0.00s)
=== RUN   TestDivideTableDriven
=== RUN   TestDivideTableDriven/normal_division
=== RUN   TestDivideTableDriven/division_by_zero
--- PASS: TestDivideTableDriven (0.00s)
    --- PASS: TestDivideTableDriven/normal_division (0.00s)
    --- PASS: TestDivideTableDriven/division_by_zero (0.00s)
PASS
ok      _/C_/projects/Articles/Go_Testing       0.321s
</code></pre>
<p>Subtest names make it easy to see which case passed or failed.</p>
<h3 id="heading-exercise">Exercise</h3>
<p>Try creating your own table-driven test for a new function, <code>Subtract(a, b int) int</code>. Include at least four test cases:</p>
<ul>
<li><p>Both positive numbers</p>
</li>
<li><p>Positive minus zero</p>
</li>
<li><p>Negative minus positive</p>
</li>
<li><p>Both negative</p>
</li>
</ul>
<p>Then run your tests and verify the output.</p>
<h2 id="heading-testing-functions-that-return-errors">Testing Functions That Return Errors</h2>
<p>Many Go functions return an error as the last return value. Writing tests for these functions is slightly different from testing pure functions like our <code>Add</code> or <code>Divide</code>, because you need to check both the result and whether an error occurred.</p>
<h3 id="heading-safe-divide-function">Safe Divide Function</h3>
<p>Let's add a <code>SafeDivide</code> function to return an error instead of panicking:</p>
<pre><code class="lang-go"><span class="hljs-comment">// calc.go</span>
...
<span class="hljs-keyword">import</span> <span class="hljs-string">"fmt"</span>
...
<span class="hljs-comment">// SafeDivide returns the result of dividing a by b.</span>
<span class="hljs-comment">// It returns an error if b is zero.</span>
<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">SafeDivide</span><span class="hljs-params">(a, b <span class="hljs-keyword">int</span>)</span> <span class="hljs-params">(<span class="hljs-keyword">int</span>, error)</span></span> {
    <span class="hljs-keyword">if</span> b == <span class="hljs-number">0</span> {
        <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>, fmt.Errorf(<span class="hljs-string">"cannot divide by zero"</span>)
    }
    <span class="hljs-keyword">return</span> a / b, <span class="hljs-literal">nil</span>
}
</code></pre>
<h3 id="heading-writing-tests-for-safedivide">Writing Tests for <code>SafeDivide()</code></h3>
<p>We can use a table-driven test again:</p>
<pre><code class="lang-go"><span class="hljs-comment">// calc_test.go</span>
<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">TestSafeDivide</span><span class="hljs-params">(t *testing.T)</span></span> {
    tests := []<span class="hljs-keyword">struct</span> {
        name      <span class="hljs-keyword">string</span>
        a, b      <span class="hljs-keyword">int</span>
        want      <span class="hljs-keyword">int</span>
        wantError <span class="hljs-keyword">bool</span>
    }{
        {<span class="hljs-string">"normal division"</span>, <span class="hljs-number">10</span>, <span class="hljs-number">2</span>, <span class="hljs-number">5</span>, <span class="hljs-literal">false</span>},
        {<span class="hljs-string">"division by zero"</span>, <span class="hljs-number">10</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-literal">true</span>},
    }

    <span class="hljs-keyword">for</span> _, tt := <span class="hljs-keyword">range</span> tests {
        t.Run(tt.name, <span class="hljs-function"><span class="hljs-keyword">func</span><span class="hljs-params">(t *testing.T)</span></span> {
            got, err := SafeDivide(tt.a, tt.b)
            <span class="hljs-keyword">if</span> tt.wantError {
                <span class="hljs-keyword">if</span> err == <span class="hljs-literal">nil</span> {
                    t.Errorf(<span class="hljs-string">"SafeDivide(%d, %d) expected error, got nil"</span>, tt.a, tt.b)
                }
                <span class="hljs-keyword">return</span> <span class="hljs-comment">// stop here, no need to check `got`</span>
            }
            <span class="hljs-keyword">if</span> err != <span class="hljs-literal">nil</span> {
                t.Errorf(<span class="hljs-string">"SafeDivide(%d, %d) unexpected error: %v"</span>, tt.a, tt.b, err)
            }
            <span class="hljs-keyword">if</span> got != tt.want {
                t.Errorf(<span class="hljs-string">"SafeDivide(%d, %d) = %d; want %d"</span>, tt.a, tt.b, got, tt.want)
            }
        })
    }
}
</code></pre>
<p>What's happening here:</p>
<ul>
<li><p>We added a <code>wantError</code> field to indicate whether the test expects an error.</p>
</li>
<li><p>If an error is expected, we check that <code>err != nil</code>. If not (that is, <code>err == nil</code>), we fail the test.</p>
</li>
<li><p>If no error is expected, we check both the returned value (<code>got</code>) and that <code>err == nil</code>.</p>
</li>
<li><p>Using <code>t.Run</code> subtests keeps everything organized and readable.</p>
</li>
</ul>
<p>Running the tests again:</p>
<pre><code class="lang-bash">$ go <span class="hljs-built_in">test</span> -v
...
=== RUN   TestSafeDivide
=== RUN   TestSafeDivide/normal_division
=== RUN   TestSafeDivide/division_by_zero
--- PASS: TestSafeDivide (0.00s)
    --- PASS: TestSafeDivide/normal_division (0.00s)
    --- PASS: TestSafeDivide/division_by_zero (0.00s)
PASS
ok      _/C_/projects/Articles/Go_Testing       0.323s
</code></pre>
<p>Showing that both normal and error cases are handled correctly.</p>
<h3 id="heading-exercise-1">Exercise</h3>
<p>Update your <code>Subtract(a, b int) int</code> function to a <code>SafeSubtract(a, b int) (int, error)</code> variant that returns an error if the result would be negative. Then write a table-driven test that covers:</p>
<ul>
<li><p>A positive result</p>
</li>
<li><p>Zero result</p>
</li>
<li><p>A negative result (should return an error)</p>
</li>
</ul>
<h2 id="heading-best-practices-and-tips">Best Practices and Tips</h2>
<p>Writing tests in Go is straightforward, but there are a few conventions and tips that make your tests more readable, maintainable, and idiomatic:</p>
<h3 id="heading-name-tests-clearly">Name Tests Clearly</h3>
<p>First, make sure you use descriptive names for test functions and subtests. A good name explains what you're testing and under what conditions.</p>
<p>Here’s an example:</p>
<pre><code class="lang-go">t.Run(<span class="hljs-string">"Divide positive numbers"</span>, <span class="hljs-function"><span class="hljs-keyword">func</span><span class="hljs-params">(t *testing.T)</span></span> { ... })
t.Run(<span class="hljs-string">"Divide by zero returns error"</span>, <span class="hljs-function"><span class="hljs-keyword">func</span><span class="hljs-params">(t *testing.T)</span></span> { ... })
</code></pre>
<h3 id="heading-keep-tests-small-and-focused">Keep Tests Small and Focused</h3>
<p>Each subtest should verify one thing, and each test function should cover a single function or method.</p>
<p>Try to avoid combining multiple unrelated checks in the same test function, and use table-driven tests help keep multiple similar checks concise without losing clarity.</p>
<h3 id="heading-use-table-driven-tests-for-repetitive-cases">Use Table-Driven Tests for Repetitive Cases</h3>
<p>If you find yourself writing multiple similar test functions, switch to a table-driven pattern. It makes it easier to add new cases, reduces duplicated code, and keeps output organized with <code>t.Run</code>.</p>
<h3 id="heading-check-errors-explicitly">Check Errors Explicitly</h3>
<p>In Go, functions often return <code>error</code>. So make sure you always check for errors in tests, even if you expect <code>nil</code>.</p>
<p>You can use the <code>wantError</code> pattern in table-driven tests for clarity.</p>
<pre><code class="lang-go"><span class="hljs-keyword">if</span> tt.wantError {
    <span class="hljs-keyword">if</span> err == <span class="hljs-literal">nil</span> {
        t.Errorf(<span class="hljs-string">"expected error, got nil"</span>)
    }
}
</code></pre>
<h3 id="heading-avoid-panics-when-possible">Avoid Panics When Possible</h3>
<p>Panics are fine for some internal checks, but in production code, prefer returning an error.</p>
<p>Your tests can check for panics using <code>defer</code> and <code>recover</code>, but this should be the exception rather than the norm.</p>
<h3 id="heading-run-tests-frequently">Run Tests Frequently</h3>
<p>Try to make running tests a habit: <code>go test -v ./...</code>. Frequent testing helps catch mistakes early and reinforces TDD practices.</p>
<h3 id="heading-keep-tests-in-the-same-package">Keep Tests in the Same Package</h3>
<p>By convention, tests live in the same package as the code they test. You can create <code>_test.go</code> files for testing, and Go automatically recognizes them.</p>
<p>Only use a separate <code>package calc_test</code> if you want to test your code from the outside, like a consumer. External test packages (just like every other external package) cannot access unexported identifiers.</p>
<h3 id="heading-use-tfatalf-vs-terrorf-appropriately">Use t.Fatalf vs t.Errorf Appropriately</h3>
<ul>
<li><p><code>t.Errorf</code> reports a failure but continues running the test.</p>
</li>
<li><p><code>t.Fatalf</code> stops the test immediately, which is useful if subsequent code depends on successful setup.</p>
</li>
</ul>
<p>These tips will help you write clean, maintainable, and idiomatic Go tests that are easy to read and extend. Following these practices early in your Go journey will make testing less intimidating and more effective.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>Unit testing in Go may feel different at first, especially if you're coming from ecosystems with heavy frameworks and assertions. But the simplicity of Go's testing tools is one of its strengths: once you understand the conventions, writing, running, and organizing tests becomes predictable and intuitive.</p>
<p>In this guide, you've seen how to:</p>
<ul>
<li><p>Write basic test functions with the testing package</p>
</li>
<li><p>Run tests from the command line and interpret the results</p>
</li>
<li><p>Use table-driven tests to cover multiple cases efficiently</p>
</li>
<li><p>Handle functions that return errors and check for expected failures</p>
</li>
</ul>
<p>Beyond these fundamentals, testing is not just about verifying correctness, it's also about confidence. Well-tested code allows you to refactor, experiment, and add new features with less fear of breaking existing functionality.</p>
<p>As you continue writing Go code, try to integrate testing early, follow the idiomatic patterns you've learned, and explore more advanced topics such as:</p>
<ul>
<li><p>Using <em>mocks</em> or <em>interfaces</em> to isolate dependencies</p>
</li>
<li><p>Benchmark tests with <code>testing.B</code></p>
</li>
<li><p>Coverage analysis with <code>go test -cover</code></p>
</li>
</ul>
<p>The key takeaway is that testing in Go is accessible, flexible, and powerful, even without fancy frameworks. By building these habits now, you'll write code that's more reliable, maintainable, and enjoyable to work with.</p>
<h2 id="heading-solutions-to-exercises">Solutions to Exercises</h2>
<h3 id="heading-subtract-function-and-tests">Subtract Function and Tests</h3>
<pre><code class="lang-go"><span class="hljs-comment">// calc.go</span>
<span class="hljs-keyword">package</span> calc

<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">Subtract</span><span class="hljs-params">(a, b <span class="hljs-keyword">int</span>)</span> <span class="hljs-title">int</span></span> {
    <span class="hljs-keyword">return</span> a - b
}
</code></pre>
<pre><code class="lang-go"><span class="hljs-comment">// calc_test.go</span>
<span class="hljs-keyword">package</span> calc

<span class="hljs-keyword">import</span> <span class="hljs-string">"testing"</span>

<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">TestSubtractTableDriven</span><span class="hljs-params">(t *testing.T)</span></span> {
    tests := []<span class="hljs-keyword">struct</span> {
        name <span class="hljs-keyword">string</span>
        a, b <span class="hljs-keyword">int</span>
        want <span class="hljs-keyword">int</span>
    }{
        {<span class="hljs-string">"both positive"</span>, <span class="hljs-number">5</span>, <span class="hljs-number">3</span>, <span class="hljs-number">2</span>},
        {<span class="hljs-string">"positive minus zero"</span>, <span class="hljs-number">5</span>, <span class="hljs-number">0</span>, <span class="hljs-number">5</span>},
        {<span class="hljs-string">"negative minus positive"</span>, <span class="hljs-number">-1</span>, <span class="hljs-number">4</span>, <span class="hljs-number">-5</span>},
        {<span class="hljs-string">"both negative"</span>, <span class="hljs-number">-3</span>, <span class="hljs-number">-2</span>, <span class="hljs-number">-1</span>},
    }

    <span class="hljs-keyword">for</span> _, tt := <span class="hljs-keyword">range</span> tests {
        t.Run(tt.name, <span class="hljs-function"><span class="hljs-keyword">func</span><span class="hljs-params">(t *testing.T)</span></span> {
            got := Subtract(tt.a, tt.b)
            <span class="hljs-keyword">if</span> got != tt.want {
                t.Errorf(<span class="hljs-string">"Subtract(%d, %d) = %d; want %d"</span>, tt.a, tt.b, got, tt.want)
            }
        })
    }
}
</code></pre>
<h3 id="heading-safesubtract-function-and-tests">SafeSubtract Function and Tests</h3>
<pre><code class="lang-go"><span class="hljs-comment">// calc.go</span>
<span class="hljs-keyword">package</span> calc

<span class="hljs-keyword">import</span> <span class="hljs-string">"fmt"</span>

<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">SafeSubtract</span><span class="hljs-params">(a, b <span class="hljs-keyword">int</span>)</span> <span class="hljs-params">(<span class="hljs-keyword">int</span>, error)</span></span> {
    result := a - b
    <span class="hljs-keyword">if</span> result &lt; <span class="hljs-number">0</span> {
        <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>, fmt.Errorf(<span class="hljs-string">"result would be negative"</span>)
    }
    <span class="hljs-keyword">return</span> result, <span class="hljs-literal">nil</span>
}
</code></pre>
<pre><code class="lang-go"><span class="hljs-comment">// calc_test.go</span>
<span class="hljs-keyword">package</span> calc

<span class="hljs-keyword">import</span> <span class="hljs-string">"testing"</span>

<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">TestSafeSubtract</span><span class="hljs-params">(t *testing.T)</span></span> {
    tests := []<span class="hljs-keyword">struct</span> {
        name      <span class="hljs-keyword">string</span>
        a, b      <span class="hljs-keyword">int</span>
        want      <span class="hljs-keyword">int</span>
        wantError <span class="hljs-keyword">bool</span>
    }{
        {<span class="hljs-string">"positive result"</span>, <span class="hljs-number">5</span>, <span class="hljs-number">3</span>, <span class="hljs-number">2</span>, <span class="hljs-literal">false</span>},
        {<span class="hljs-string">"zero result"</span>, <span class="hljs-number">3</span>, <span class="hljs-number">3</span>, <span class="hljs-number">0</span>, <span class="hljs-literal">false</span>},
        {<span class="hljs-string">"negative result"</span>, <span class="hljs-number">2</span>, <span class="hljs-number">5</span>, <span class="hljs-number">0</span>, <span class="hljs-literal">true</span>},
    }

    <span class="hljs-keyword">for</span> _, tt := <span class="hljs-keyword">range</span> tests {
        t.Run(tt.name, <span class="hljs-function"><span class="hljs-keyword">func</span><span class="hljs-params">(t *testing.T)</span></span> {
            got, err := SafeSubtract(tt.a, tt.b)
            <span class="hljs-keyword">if</span> tt.wantError {
                <span class="hljs-keyword">if</span> err == <span class="hljs-literal">nil</span> {
                    t.Errorf(<span class="hljs-string">"SafeSubtract(%d, %d) expected error, got nil"</span>, tt.a, tt.b)
                }
                <span class="hljs-keyword">return</span>
            }
            <span class="hljs-keyword">if</span> err != <span class="hljs-literal">nil</span> {
                t.Errorf(<span class="hljs-string">"SafeSubtract(%d, %d) unexpected error: %v"</span>, tt.a, tt.b, err)
            }
            <span class="hljs-keyword">if</span> got != tt.want {
                t.Errorf(<span class="hljs-string">"SafeSubtract(%d, %d) = %d; want %d"</span>, tt.a, tt.b, got, tt.want)
            }
        })
    }
}
</code></pre>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Scale TestOps for Global Software Development Teams ]]>
                </title>
                <description>
                    <![CDATA[ Imagine that your software team is spread across the globe—developers in the US, testers in Asia, and managers in Europe. Exciting, right? But managing this setup is no walk in the park. Coordinating testing across time zones, tools, and workflows ca... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/scale-testops-for-global-software-development-teams/</link>
                <guid isPermaLink="false">6801211371255f2b14ea901b</guid>
                
                    <category>
                        <![CDATA[ Testing ]]>
                    </category>
                
                    <category>
                        <![CDATA[ testops ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Software Testing ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Nazneen Ahmad ]]>
                </dc:creator>
                <pubDate>Thu, 17 Apr 2025 15:41:07 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/res/hashnode/image/upload/v1744904445449/18f469d0-b066-4709-a463-4f378802615d.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Imagine that your software team is spread across the globe—developers in the US, testers in Asia, and managers in Europe. Exciting, right? But managing this setup is no walk in the park. Coordinating testing across time zones, tools, and workflows can be challenging.</p>
<p>That is where TestOps comes in. It blends testing with operational efficiency, creating a streamlined approach to quality assurance. Scaling TestOps for global teams means setting up processes that work smoothly across continents, delivering speed and consistency without compromising on quality.</p>
<p>The challenges are real: communication gaps, tool compatibility issues, and cultural differences. But the payoff is worth it. A well-structured TestOps framework helps teams collaborate easily, automate testing, and produce software that meets global expectations.</p>
<p>This guide will walk you through overcoming these challenges, adopting practical strategies, and turning your global TestOps into a hub for innovation and quality.</p>
<h3 id="heading-heres-what-well-cover">Here’s what we’ll cover:</h3>
<ol>
<li><p><a class="post-section-overview" href="#heading-understanding-testops">Understanding TestOps</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-limitations-of-scaling-testops">Limitations of Scaling TestOps</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-strategies-for-scaling-testops">Strategies for Scaling TestOps</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-integrate-testops-into-global-devops-pipelines">How to Integrate TestOps into Global DevOps Pipelines</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-use-ai-and-analytics-in-testops">How to Use AI and Analytics in TestOps</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-future-of-testops-in-global-development">Future of TestOps in Global Development</a></p>
</li>
</ol>
<h2 id="heading-understanding-testops">Understanding TestOps</h2>
<p>TestOps is all about using automation to make software testing smoother and more efficient. It brings together scattered teams and processes into a unified system, helping you deliver better software faster and with fewer bugs. But what does it actually do?</p>
<p>TestOps makes testing easier to manage, run, and review. It keeps the testing process organized, consistent, and team-friendly. By using automation and central tools, TestOps helps you avoid mistakes, save time, and deliver better-quality software.</p>
<p>Here are the four central components of TestOps:</p>
<ul>
<li><p><strong>Planning</strong>: This step focuses on deciding what needs to be tested, how it will be tested (including the test environment), when testing will happen, and who will handle it.</p>
</li>
<li><p><strong>Management</strong>: This ensures testing is efficient and scalable by using tools that improve teamwork and visibility.</p>
</li>
<li><p><strong>Execution</strong>: This is the actual process of running tests on the software.</p>
</li>
<li><p><strong>Analysis</strong>: This step involves reviewing test performance, diagnosing issues, and finding ways to improve the overall testing process.</p>
</li>
</ul>
<p>At scale, TestOps focuses on:</p>
<ul>
<li><p><strong>Standardization</strong>: Setting up consistent testing methods and tools that everyone can use across teams and projects.</p>
</li>
<li><p><strong>Automation</strong>: Increasing the use of automated tests to handle more tasks quickly and accurately.</p>
</li>
<li><p><strong>Collaboration</strong>: Improving how teams work together, even if they are spread out in different locations.</p>
</li>
<li><p><strong>Scalability</strong>: Making sure testing systems and processes can grow as needs increase.</p>
</li>
<li><p><strong>Insights</strong>: Using data from large-scale testing to make better decisions and improve how things work.</p>
</li>
</ul>
<h2 id="heading-limitations-of-scaling-testops">Limitations of Scaling TestOps</h2>
<p>Scaling TestOps for global software teams comes with its fair share of challenges. While the advantages of smooth, integrated testing are clear, getting there requires careful planning.</p>
<p>Here are some key obstacles:</p>
<ul>
<li><p><strong>Communication barriers</strong>: With teams spread across different time zones, keeping communication clear and timely can be tough. Delays or misunderstandings can slow progress and affect the quality of testing.</p>
</li>
<li><p><strong>Tool compatibility</strong>: Teams may use different testing tools, leading to inefficiencies and fragmentation. It's important to make sure all tools can work together and are compatible across different environments.</p>
</li>
<li><p><strong>Cultural and organizational differences</strong>: Teams from various regions may have different work cultures, priorities, and expectations. Finding common ground without creating friction is essential for smooth collaboration.</p>
</li>
<li><p><strong>Time zone management</strong>: Coordinating meetings or ensuring real-time review of test results becomes difficult with global teams in different time zones.</p>
</li>
<li><p><strong>Quality consistency</strong>: Ensuring consistent testing standards across multiple locations can be tricky. Without centralized control, practices can vary, which may lead to missed defects and unreliable releases.</p>
</li>
</ul>
<p>Overcoming these challenges requires a well-thought-out strategy, effective communication, and the right tools to align teams and processes across the globe.</p>
<h2 id="heading-strategies-for-scaling-testops">Strategies for Scaling TestOps</h2>
<p>Scaling TestOps for global teams requires smart strategies to address communication issues, tool mismatches, and operational challenges. Here are some key approaches to make scaling work:</p>
<h3 id="heading-standardize-testing-processes"><strong>Standardize Testing Processes</strong></h3>
<p>Set up clear, consistent testing protocols and tools across all teams to ensure everyone is on the same page.</p>
<p>For example, you can standardize testing using frameworks like <strong>Jest</strong> to ensure consistency across teams.</p>
<pre><code class="lang-bash">bashCopy codenpm install --save-dev jest
</code></pre>
<p>In your <strong>package.json</strong>:</p>
<pre><code class="lang-json">jsonCopy code{
  <span class="hljs-attr">"scripts"</span>: {
    <span class="hljs-attr">"test"</span>: <span class="hljs-string">"jest"</span>
  }
}
</code></pre>
<h3 id="heading-use-cloud-based-tools"><strong>Use Cloud-Based Tools</strong></h3>
<p>Choose cloud tools that allow teams to collaborate smoothly, provide real-time feedback, and access testing environments from anywhere.</p>
<p>For example, cloud tools like <strong>LambdaTest</strong> enable remote testing across browsers and devices.</p>
<pre><code class="lang-javascript">javascriptCopy codeconst { remote } = <span class="hljs-built_in">require</span>(<span class="hljs-string">'webdriverio'</span>);

<span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">runTest</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> browser = <span class="hljs-keyword">await</span> remote({
    <span class="hljs-attr">capabilities</span>: {
      <span class="hljs-attr">browserName</span>: <span class="hljs-string">'chrome'</span>,
      <span class="hljs-attr">platform</span>: <span class="hljs-string">'Windows 10'</span>,
      <span class="hljs-attr">version</span>: <span class="hljs-string">'latest'</span>,
      <span class="hljs-string">'build'</span>: <span class="hljs-string">'TestOps Scaling Build'</span>,
      <span class="hljs-string">'name'</span>: <span class="hljs-string">'Test Parallel Execution'</span>,
    },
    <span class="hljs-attr">host</span>: <span class="hljs-string">'hub.lambdatest.com'</span>,
    <span class="hljs-attr">port</span>: <span class="hljs-number">80</span>,
    <span class="hljs-attr">user</span>: <span class="hljs-string">'your_username'</span>,
    <span class="hljs-attr">key</span>: <span class="hljs-string">'your_access_key'</span>
  });

  <span class="hljs-keyword">await</span> browser.url(<span class="hljs-string">'https://www.yoursite.com'</span>);
  <span class="hljs-built_in">console</span>.log(<span class="hljs-keyword">await</span> browser.getTitle());
  <span class="hljs-keyword">await</span> browser.deleteSession();
}

runTest();
</code></pre>
<h3 id="heading-automate-testing"><strong>Automate Testing</strong></h3>
<p>Integrate automated tests into CI/CD pipelines to reduce manual work, speed up feedback, and improve test coverage.</p>
<p>For example, you can use <strong>GitHub Actions</strong> for CI/CD test automation.</p>
<pre><code class="lang-yaml"><span class="hljs-attr">yamlCopy codename:</span> <span class="hljs-string">Run</span> <span class="hljs-string">Tests</span>

<span class="hljs-attr">on:</span> [<span class="hljs-string">push</span>]

<span class="hljs-attr">jobs:</span>
  <span class="hljs-attr">test:</span>
    <span class="hljs-attr">runs-on:</span> <span class="hljs-string">ubuntu-latest</span>
    <span class="hljs-attr">steps:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Checkout</span> <span class="hljs-string">code</span>
        <span class="hljs-attr">uses:</span> <span class="hljs-string">actions/checkout@v2</span>
      <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Run</span> <span class="hljs-string">tests</span>
        <span class="hljs-attr">run:</span> <span class="hljs-string">npm</span> <span class="hljs-string">test</span>
</code></pre>
<h3 id="heading-use-centralized-reporting-tools"><strong>Use Centralized Reporting Tools</strong></h3>
<p>Use dashboards to give everyone real-time updates on testing progress, keeping all teams and stakeholders in the loop.</p>
<p>Here’s an example of integrating with <strong>TestRail</strong> for centralized reporting.</p>
<pre><code class="lang-javascript">javascriptCopy codeconst axios = <span class="hljs-built_in">require</span>(<span class="hljs-string">'axios'</span>);

<span class="hljs-keyword">const</span> result = {
  <span class="hljs-string">"status"</span>: <span class="hljs-string">"passed"</span>, 
  <span class="hljs-string">"test_case_id"</span>: <span class="hljs-number">123</span>,
  <span class="hljs-string">"run_id"</span>: <span class="hljs-number">456</span>
};

axios.post(<span class="hljs-string">'https://your-testrail-instance/api/v2/add_result_for_case/1/123'</span>, result, {
  <span class="hljs-attr">auth</span>: { <span class="hljs-attr">username</span>: <span class="hljs-string">'your_email'</span>, <span class="hljs-attr">password</span>: <span class="hljs-string">'your_password'</span> }
})
.then(<span class="hljs-function"><span class="hljs-params">response</span> =&gt;</span> <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Test result posted successfully'</span>))
.catch(<span class="hljs-function"><span class="hljs-params">error</span> =&gt;</span> <span class="hljs-built_in">console</span>.error(<span class="hljs-string">'Error:'</span>, error));
</code></pre>
<h3 id="heading-encourage-cross-regional-collaboration"><strong>Encourage Cross-Regional Collaboration</strong></h3>
<p>Use collaboration tools and hold regular meetings to bridge time zone and cultural differences between teams.</p>
<p>You can use <strong>Slack</strong> or similar tools for real-time communication and alerts.</p>
<pre><code class="lang-javascript">javascriptCopy codeconst slackMessage = { <span class="hljs-attr">text</span>: <span class="hljs-string">"Test Execution Completed: All tests have passed successfully!"</span> };

axios.post(<span class="hljs-string">'https://hooks.slack.com/services/your-webhook-url'</span>, slackMessage)
  .then(<span class="hljs-function"><span class="hljs-params">response</span> =&gt;</span> <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Slack message sent'</span>))
  .catch(<span class="hljs-function"><span class="hljs-params">error</span> =&gt;</span> <span class="hljs-built_in">console</span>.error(<span class="hljs-string">'Error:'</span>, error));
</code></pre>
<h3 id="heading-create-a-continuous-feedback-loop"><strong>Create a Continuous Feedback Loop</strong></h3>
<p>Set up systems that provide immediate feedback and allow for quick action, ensuring quality isn’t delayed.</p>
<p>For example, you can trigger feedback loops with <strong>Slack</strong> for an immediate response.</p>
<pre><code class="lang-javascript">javascriptCopy codeconst slackMessage = { <span class="hljs-attr">text</span>: <span class="hljs-string">"Alert: Test failure detected!"</span> };

axios.post(<span class="hljs-string">'https://hooks.slack.com/services/your-webhook-url'</span>, slackMessage)
  .then(<span class="hljs-function"><span class="hljs-params">response</span> =&gt;</span> <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Alert sent to Slack'</span>))
  .catch(<span class="hljs-function"><span class="hljs-params">error</span> =&gt;</span> <span class="hljs-built_in">console</span>.error(<span class="hljs-string">'Error:'</span>, error));
</code></pre>
<h3 id="heading-upskill-teams"><strong>Upskill Teams</strong></h3>
<p>Offer training so all team members know how to use TestOps tools effectively.</p>
<p>Try providing training through GitHub repositories with testing best practices.</p>
<pre><code class="lang-plaintext">markdownCopy code# Automated Testing Guide

## Steps:
1. Clone repo
2. Install dependencies: `npm install`
3. Run tests: `npm test`
4. Review TestRail dashboard
</code></pre>
<h3 id="heading-adapt-to-time-zones"><strong>Adapt to Time Zones</strong></h3>
<p>Organize workflows and shifts that allow for continuous testing, helping teams overcome time zone challenges.</p>
<p>You can schedule tests using <strong>Jenkins</strong>, for example, to accommodate global teams.</p>
<pre><code class="lang-plaintext">groovyCopy codepipeline {
    agent any
    triggers {
        cron('H 0 * * *')
    }
    stages {
        stage('Run Tests') {
            steps {
                sh 'npm test'
            }
        }
    }
}
</code></pre>
<h2 id="heading-how-to-integrate-testops-into-global-devops-pipelines">How to Integrate TestOps into Global DevOps Pipelines</h2>
<p>Integrating TestOps into global DevOps pipelines is crucial for maintaining software quality across distributed teams. This integration makes testing a seamless and automated part of the software delivery process, helping improve and release software quickly.</p>
<p>Tools like containerization and orchestration platforms play a big role in scaling TestOps across global pipelines. Here’s how to do it effectively:</p>
<h3 id="heading-test-early-and-continuously"><strong>Test Early and Continuously</strong></h3>
<p>When you start testing early in the development cycle, you catch issues before they reach production. This early approach allows developers to fix bugs while the changes are still fresh. It also prevents those issues from becoming bigger later.</p>
<p>Continuous testing means tests run automatically whenever code changes. These are usually triggered during the Continuous Integration (CI) process. Since the tests run right after a change is made, feedback is quick.</p>
<p>This quick feedback helps reduce debugging time. It also supports teams working from different regions, since they can move ahead without waiting on others. And because tests fail fast, blockers are identified early and resolved quickly.</p>
<p><strong>Example:</strong><br>A global logistics company uses GitHub Actions to run unit and integration tests whenever a developer submits a pull request. The setup alerts developers immediately if any test fails. Since the teams are based in India, the US, and Germany, this system helps them work independently. It also avoids delays that often happen due to time zone differences.</p>
<h3 id="heading-automate-test-execution"><strong>Automate Test Execution</strong></h3>
<p>Using test automation frameworks lets you run tests automatically across different stages of development. Tools like TestNG, Playwright, and Cypress can help you do this easily. These tools are great for saving time and reducing human error.</p>
<p>By automating the test process, you avoid the need for manual execution. This also makes regression testing more manageable, especially in large applications. It gives your team more confidence to release code frequently.</p>
<p>As tests run on every code change, any new issues are quickly caught. And because automation supports repeatability, it keeps testing consistent across teams.</p>
<p><strong>Example:</strong><br>A healthcare software company uses Cypress for automating UI tests. These tests are connected with GitLab CI and run whenever someone updates a feature branch. The tests run in parallel containers, which helps speed up the process. This setup ensures key features are always verified before merging code. Even when several features are being developed at once, their system keeps everything on track.</p>
<p><strong>Sample Cypress Test:</strong></p>
<pre><code class="lang-javascript">javascriptCopy codedescribe(<span class="hljs-string">'Login Functionality'</span>, <span class="hljs-function">() =&gt;</span> {
  it(<span class="hljs-string">'should log in with valid credentials'</span>, <span class="hljs-function">() =&gt;</span> {
    cy.visit(<span class="hljs-string">'https://app.healthcare-demo.com/login'</span>)
    cy.get(<span class="hljs-string">'input[name=email]'</span>).type(<span class="hljs-string">'testuser@demo.com'</span>)
    cy.get(<span class="hljs-string">'input[name=password]'</span>).type(<span class="hljs-string">'securePassword123'</span>)
    cy.get(<span class="hljs-string">'button[type=submit]'</span>).click()
    cy.url().should(<span class="hljs-string">'include'</span>, <span class="hljs-string">'/dashboard'</span>)
    cy.contains(<span class="hljs-string">'Welcome back'</span>)
  })
})
</code></pre>
<p><strong>GitLab CI Configuration (gitlab-ci.yml):</strong></p>
<pre><code class="lang-yaml"><span class="hljs-attr">yamlCopy codestages:</span>
  <span class="hljs-bullet">-</span> <span class="hljs-string">test</span>

<span class="hljs-attr">cypress_tests:</span>
  <span class="hljs-attr">stage:</span> <span class="hljs-string">test</span>
  <span class="hljs-attr">image:</span> <span class="hljs-string">cypress/browsers:node-18.12.0-chrome-106</span>
  <span class="hljs-attr">script:</span>
    <span class="hljs-bullet">-</span> <span class="hljs-string">npm</span> <span class="hljs-string">ci</span>
    <span class="hljs-bullet">-</span> <span class="hljs-string">npx</span> <span class="hljs-string">cypress</span> <span class="hljs-string">run</span>
  <span class="hljs-attr">artifacts:</span>
    <span class="hljs-attr">when:</span> <span class="hljs-string">always</span>
    <span class="hljs-attr">paths:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">cypress/videos/</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">cypress/screenshots/</span>
  <span class="hljs-attr">only:</span>
    <span class="hljs-bullet">-</span> <span class="hljs-string">merge_requests</span>
    <span class="hljs-bullet">-</span> <span class="hljs-string">branches</span>
</code></pre>
<p>This code demonstrates how Cypress runs UI tests, and how GitLab CI automatically triggers those tests when a new branch is pushed or a merge request is created. It reflects the kind of scalable, repeatable test execution process that supports global software teams.</p>
<h3 id="heading-use-containerization-for-environment-consistency"><strong>Use Containerization for Environment Consistency</strong></h3>
<p>When you use Docker, you create containers that include your application and everything it needs to run. These containers can be shared and used anywhere. That means every developer and tester uses the same environment.</p>
<p>This removes the “it works on my machine” issue. It also helps create identical setups across development, staging, QA, and production. Since everyone works with the same tools and settings, there are fewer environment-related bugs.</p>
<p>With containerization, it becomes easier to test on different systems without needing to reconfigure anything. And it helps teams in different locations stay in sync.</p>
<p><strong>Example:</strong><br>A fintech startup packages its API and testing framework using Docker. These containers are then used inside Azure DevOps pipelines. The same tests run across staging, QA, and production environments. Since the containers do not change, the results are always reliable and consistent.</p>
<p><strong>Sample Dockerfile for API Testing:</strong></p>
<pre><code class="lang-dockerfile">DockerfileCopy code<span class="hljs-comment"># Use official Node.js image</span>
<span class="hljs-keyword">FROM</span> node:<span class="hljs-number">18</span>

<span class="hljs-comment"># Set working directory</span>
<span class="hljs-keyword">WORKDIR</span><span class="bash"> /usr/src/app</span>

<span class="hljs-comment"># Copy package files</span>
<span class="hljs-keyword">COPY</span><span class="bash"> package*.json ./</span>

<span class="hljs-comment"># Install dependencies</span>
<span class="hljs-keyword">RUN</span><span class="bash"> npm install</span>

<span class="hljs-comment"># Copy test files and configuration</span>
<span class="hljs-keyword">COPY</span><span class="bash"> . .</span>

<span class="hljs-comment"># Run tests (can be overridden in CI/CD)</span>
<span class="hljs-keyword">CMD</span><span class="bash"> [<span class="hljs-string">"npm"</span>, <span class="hljs-string">"test"</span>]</span>
</code></pre>
<p><strong>Example docker-compose.yml:</strong></p>
<pre><code class="lang-yaml"><span class="hljs-attr">yamlCopy codeversion:</span> <span class="hljs-string">'3.8'</span>

<span class="hljs-attr">services:</span>
  <span class="hljs-attr">api:</span>
    <span class="hljs-attr">image:</span> <span class="hljs-string">fintech-api:latest</span>
    <span class="hljs-attr">build:</span>
      <span class="hljs-attr">context:</span> <span class="hljs-string">./api</span>
    <span class="hljs-attr">ports:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">"3000:3000"</span>
    <span class="hljs-attr">environment:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">NODE_ENV=test</span>

  <span class="hljs-attr">tests:</span>
    <span class="hljs-attr">build:</span>
      <span class="hljs-attr">context:</span> <span class="hljs-string">./tests</span>
    <span class="hljs-attr">depends_on:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">api</span>
    <span class="hljs-attr">command:</span> <span class="hljs-string">npm</span> <span class="hljs-string">run</span> <span class="hljs-string">test</span>
</code></pre>
<p>This setup builds two containers – one for the API and one for the test runner. It mirrors how the startup runs its tests inside Azure DevOps pipelines. Developers, QA, and staging environments all use the same containers, reducing variability and giving more predictable test results.</p>
<h3 id="heading-enable-scalable-test-orchestration"><strong>Enable Scalable Test Orchestration</strong></h3>
<p>When tests are run in parallel across different environments, they finish faster. Tools like Selenium Grid, and LambdaTest help you do this. These platforms allow you to test across various browsers, operating systems, and devices.</p>
<p>By running tests this way, you save time and cover more scenarios at once. This is especially useful when your product needs to work globally. It ensures users across different regions have the same experience.</p>
<p>Parallel testing also helps teams working in different time zones. While one team sleeps, another team can pick up where they left off.</p>
<p><strong>Example:</strong><br>A retail company uses LambdaTest to run regression tests every night. These tests cover Chrome, Firefox, and Safari, both on desktop and mobile. Since the tests run in parallel, the UK team finishes validation before the US team starts their workday. This keeps their pipeline flowing without delays.</p>
<p><strong>Sample Setup for Parallel Execution with Selenium Grid (Docker-based):</strong></p>
<pre><code class="lang-yaml"><span class="hljs-string">yamlCopy</span> <span class="hljs-string">code#</span> <span class="hljs-string">docker-compose.yml</span>
<span class="hljs-attr">version:</span> <span class="hljs-string">"3"</span>
<span class="hljs-attr">services:</span>
  <span class="hljs-attr">selenium-hub:</span>
    <span class="hljs-attr">image:</span> <span class="hljs-string">selenium/hub:4.18.1</span>
    <span class="hljs-attr">ports:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">"4442:4442"</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">"4443:4443"</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">"4444:4444"</span>

  <span class="hljs-attr">chrome:</span>
    <span class="hljs-attr">image:</span> <span class="hljs-string">selenium/node-chrome:4.18.1</span>
    <span class="hljs-attr">depends_on:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">selenium-hub</span>
    <span class="hljs-attr">environment:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">SE_EVENT_BUS_HOST=selenium-hub</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">SE_EVENT_BUS_PUBLISH_PORT=4442</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">SE_EVENT_BUS_SUBSCRIBE_PORT=4443</span>

  <span class="hljs-attr">firefox:</span>
    <span class="hljs-attr">image:</span> <span class="hljs-string">selenium/node-firefox:4.18.1</span>
    <span class="hljs-attr">depends_on:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">selenium-hub</span>
    <span class="hljs-attr">environment:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">SE_EVENT_BUS_HOST=selenium-hub</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">SE_EVENT_BUS_PUBLISH_PORT=4442</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">SE_EVENT_BUS_SUBSCRIBE_PORT=4443</span>
</code></pre>
<p>This creates a Selenium Grid with Chrome and Firefox nodes that connect to the central hub. It allows you to distribute your tests in parallel across browsers.</p>
<p><strong>Sample Java Test (TestNG) for Running in Parallel:</strong></p>
<pre><code class="lang-java">javaCopy codepublic <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ParallelTest</span> </span>{
    WebDriver driver;

    <span class="hljs-meta">@Parameters("browser")</span>
    <span class="hljs-meta">@BeforeMethod</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">setup</span><span class="hljs-params">(String browser)</span> <span class="hljs-keyword">throws</span> MalformedURLException </span>{
        DesiredCapabilities capabilities = <span class="hljs-keyword">new</span> DesiredCapabilities();

        <span class="hljs-keyword">if</span> (browser.equalsIgnoreCase(<span class="hljs-string">"chrome"</span>)) {
            capabilities.setBrowserName(<span class="hljs-string">"chrome"</span>);
        } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (browser.equalsIgnoreCase(<span class="hljs-string">"firefox"</span>)) {
            capabilities.setBrowserName(<span class="hljs-string">"firefox"</span>);
        }

        driver = <span class="hljs-keyword">new</span> RemoteWebDriver(<span class="hljs-keyword">new</span> URL(<span class="hljs-string">"http://localhost:4444/wd/hub"</span>), capabilities);
    }

    <span class="hljs-meta">@Test</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">runTest</span><span class="hljs-params">()</span> </span>{
        driver.get(<span class="hljs-string">"https://retail-demo.com"</span>);
        Assert.assertTrue(driver.getTitle().contains(<span class="hljs-string">"Retail"</span>));
    }

    <span class="hljs-meta">@AfterMethod</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">tearDown</span><span class="hljs-params">()</span> </span>{
        <span class="hljs-keyword">if</span> (driver != <span class="hljs-keyword">null</span>) {
            driver.quit();
        }
    }
}
</code></pre>
<p><strong>TestNG Parallel Configuration (testng.xml):</strong></p>
<pre><code class="lang-xml">xmlCopy code<span class="hljs-tag">&lt;<span class="hljs-name">suite</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"ParallelTests"</span> <span class="hljs-attr">parallel</span>=<span class="hljs-string">"tests"</span> <span class="hljs-attr">thread-count</span>=<span class="hljs-string">"2"</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">test</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"ChromeTest"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">parameter</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"browser"</span> <span class="hljs-attr">value</span>=<span class="hljs-string">"chrome"</span>/&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">classes</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">class</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"ParallelTest"</span>/&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">classes</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">test</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">test</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"FirefoxTest"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">parameter</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"browser"</span> <span class="hljs-attr">value</span>=<span class="hljs-string">"firefox"</span>/&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">classes</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">class</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"ParallelTest"</span>/&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">classes</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">test</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">suite</span>&gt;</span>
</code></pre>
<p>This setup allows tests to run in parallel on both Chrome and Firefox, using Selenium Grid hosted locally with Docker. It mirrors how global teams can scale their test execution and speed up feedback loops.</p>
<h3 id="heading-role-of-containerization-and-orchestration-tools"><strong>Role of Containerization and Orchestration Tools</strong></h3>
<p>Tools like Docker and Kubernetes are essential for integrating TestOps into global DevOps pipelines.</p>
<ul>
<li><p><strong>Docker</strong> creates lightweight, repeatable test environments that can be quickly set up or shut down. By packaging apps and their dependencies into containers, Docker ensures tests run consistently, whether on local machines or in the cloud.</p>
</li>
<li><p><strong>Kubernetes</strong> manages the deployment and scaling of containerized apps. In TestOps, Kubernetes automates test execution across multiple containers, speeding up testing in global pipelines. It helps scale testing to handle large volumes of tests in different environments and locations.</p>
</li>
</ul>
<p>Containerization with Docker and orchestration with Kubernetes can streamline the testing process, especially for global DevOps pipelines.</p>
<h4 id="heading-step-1-docker-for-repeatable-test-environments">Step 1: Docker for Repeatable Test Environments</h4>
<p>You can use Docker to package your application along with its dependencies into a container, making it easy to run tests consistently across various environments.</p>
<h5 id="heading-example-dockerfile-for-test-environment"><strong>Example Dockerfile for Test Environment:</strong></h5>
<pre><code class="lang-dockerfile">dockerfileCopy codeFROM node:<span class="hljs-number">14</span>

<span class="hljs-keyword">WORKDIR</span><span class="bash"> /app</span>

<span class="hljs-comment"># Install dependencies</span>
<span class="hljs-keyword">COPY</span><span class="bash"> package*.json ./</span>
<span class="hljs-keyword">RUN</span><span class="bash"> npm install</span>

<span class="hljs-comment"># Copy application code</span>
<span class="hljs-keyword">COPY</span><span class="bash"> . .</span>

<span class="hljs-comment"># Run tests</span>
<span class="hljs-keyword">CMD</span><span class="bash"> [<span class="hljs-string">"npm"</span>, <span class="hljs-string">"test"</span>]</span>
</code></pre>
<p>This Dockerfile sets up a container to install dependencies and run the tests using <code>npm test</code>.</p>
<h4 id="heading-step-2-kubernetes-for-orchestration">Step 2: Kubernetes for Orchestration</h4>
<p>You can use Kubernetes to scale the test execution across multiple containers. Kubernetes can manage the deployment of containers and automatically distribute them across nodes, enabling parallel testing.</p>
<h5 id="heading-example-kubernetes-deployment-yaml"><strong>Example Kubernetes Deployment YAML:</strong></h5>
<pre><code class="lang-yaml"><span class="hljs-attr">yamlCopy codeapiVersion:</span> <span class="hljs-string">apps/v1</span>
<span class="hljs-attr">kind:</span> <span class="hljs-string">Deployment</span>
<span class="hljs-attr">metadata:</span>
  <span class="hljs-attr">name:</span> <span class="hljs-string">test-deployment</span>
<span class="hljs-attr">spec:</span>
  <span class="hljs-attr">replicas:</span> <span class="hljs-number">3</span>  <span class="hljs-comment"># Number of containers to run in parallel</span>
  <span class="hljs-attr">selector:</span>
    <span class="hljs-attr">matchLabels:</span>
      <span class="hljs-attr">app:</span> <span class="hljs-string">test-app</span>
  <span class="hljs-attr">template:</span>
    <span class="hljs-attr">metadata:</span>
      <span class="hljs-attr">labels:</span>
        <span class="hljs-attr">app:</span> <span class="hljs-string">test-app</span>
    <span class="hljs-attr">spec:</span>
      <span class="hljs-attr">containers:</span>
        <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">test-container</span>
          <span class="hljs-attr">image:</span> <span class="hljs-string">my-app-test-env:latest</span>  <span class="hljs-comment"># Docker image built earlier</span>
          <span class="hljs-attr">ports:</span>
            <span class="hljs-bullet">-</span> <span class="hljs-attr">containerPort:</span> <span class="hljs-number">80</span>
</code></pre>
<p>This Kubernetes deployment configuration specifies that 3 replicas (containers) of the test environment will be created and run in parallel. This helps speed up the testing process by distributing the workload.</p>
<h4 id="heading-step-3-running-tests-in-kubernetes">Step 3: Running Tests in Kubernetes</h4>
<p>Once you have the containers and Kubernetes deployment configured, you can integrate this setup into your CI/CD pipeline. Kubernetes can handle scaling the test execution, making it ideal for global pipelines where tests need to run across different environments.</p>
<h5 id="heading-example-kubernetes-command-to-deploy"><strong>Example Kubernetes Command to Deploy:</strong></h5>
<pre><code class="lang-bash">bashCopy codekubectl apply -f test-deployment.yaml
</code></pre>
<p>This command deploys the test containers to the Kubernetes cluster, ensuring that your tests run across multiple containers, in parallel, at scale.</p>
<h3 id="heading-continuous-monitoring-and-feedback"><strong>Continuous Monitoring and Feedback</strong></h3>
<p>TestOps relies on continuous monitoring to provide real-time insights into test results, performance, and system health.</p>
<p>Kubernetes helps manage testing resources and spot problems quickly. Real-time feedback from automated tests lets developers fix issues immediately, improving software quality.</p>
<h3 id="heading-cross-tool-integration"><strong>Cross-Tool Integration</strong></h3>
<p>TestOps works well with different DevOps tools, creating a smooth feedback loop. It connects test management platforms (like TestRail) with CI/CD tools (like Jenkins or GitLab CI) and uses containerized environments to run tests consistently. Kubernetes ensures testing resources scale automatically to meet the needs of global teams.</p>
<h3 id="heading-shift-left-testing"><strong>Shift-Left Testing</strong></h3>
<p>TestOps follows a <a target="_blank" href="https://www.freecodecamp.org/news/what-is-shift-left-in-software/">shift-left approach</a>, which means integrating testing earlier in the pipeline to catch issues right away. Running tests in containerized environments speeds up testing and allows teams to find problems earlier in the development process, reducing risks and improving quality.</p>
<h4 id="heading-shift-left-testing-with-docker-and-ci">Shift-Left Testing with Docker and CI</h4>
<p>Shift-left testing integrates tests early in the development pipeline to catch issues sooner. Using Docker in a CI pipeline automates test execution in a consistent environment.</p>
<h4 id="heading-dockerfile-example"><strong>Dockerfile Example:</strong></h4>
<pre><code class="lang-dockerfile">dockerfileCopy codeFROM node:<span class="hljs-number">14</span>
<span class="hljs-keyword">WORKDIR</span><span class="bash"> /app</span>
<span class="hljs-keyword">COPY</span><span class="bash"> package*.json ./</span>
<span class="hljs-keyword">RUN</span><span class="bash"> npm install</span>
<span class="hljs-keyword">COPY</span><span class="bash"> . .</span>
<span class="hljs-keyword">CMD</span><span class="bash"> [<span class="hljs-string">"npm"</span>, <span class="hljs-string">"test"</span>]</span>
</code></pre>
<h4 id="heading-jenkinsfile-example"><strong>Jenkinsfile Example:</strong></h4>
<pre><code class="lang-plaintext">groovyCopy codepipeline {
    agent any
    environment {
        DOCKER_IMAGE = 'my-app-test-env'
    }
    stages {
        stage('Checkout') {
            steps {
                git 'https://github.com/your-repository/my-app.git'
            }
        }
        stage('Build Docker Image') {
            steps {
                script {
                    sh 'docker build -t $DOCKER_IMAGE .'
                }
            }
        }
        stage('Run Tests') {
            steps {
                script {
                    sh 'docker run --rm $DOCKER_IMAGE'
                }
            }
        }
    }
    post {
        always {
            sh 'docker rmi $DOCKER_IMAGE'
        }
    }
}
</code></pre>
<h3 id="heading-scalability-and-flexibility"><strong>Scalability and Flexibility</strong></h3>
<p>Global teams need to manage large test environments. Containerization and Kubernetes provide the scalability needed to run thousands of tests across different regions at once. Containers package tests into small, isolated environments, while Kubernetes automates their scaling and management, keeping testing efficient as the pipeline grows.</p>
<h2 id="heading-how-to-use-ai-and-analytics-in-testops">How to Use AI and Analytics in TestOps</h2>
<p>When you bring AI and analytics into TestOps, it helps simplify complex testing tasks. It reduces manual work, improves accuracy, and supports better decision-making. Since DevOps teams often work across regions, this becomes even more important.</p>
<p>AI helps reduce repetitive testing tasks, while analytics turns test data into clear insights. Together, they create smarter and faster testing pipelines. And because these pipelines are shared globally, consistency is key.</p>
<h3 id="heading-what-tools-can-you-use">What Tools Can You Use?</h3>
<p>There are different tools that support AI and analytics in TestOps. Some focus on automation with intelligence, while others give you clear visibility into your test data.</p>
<p>AI-powered testing tools like Mabl, Testim, and Functionize use machine learning. These tools help create, run, and even repair test cases when the app changes. Since applications change frequently, these tools help keep your tests up to date.</p>
<p>They also save time on maintenance, since the tests adjust themselves when needed. And because the tools learn from patterns, they help teams catch issues faster.</p>
<p>Analytics and observability platforms such as TestRail Analytics, Xray, Grafana, and Kibana focus on trends. They turn raw test results into visual dashboards and alerts.</p>
<p>These platforms connect with CI/CD tools, so you get real-time updates on test quality. This makes it easier for teams to stay on top of what matters, even when they are spread across locations.</p>
<h4 id="heading-example-running-a-working-test-on-lambdatest">Example – Running a Working Test on LambdaTest</h4>
<p>LambdaTest lets you execute real browser tests in the cloud, making it easy to scale your testing across browsers and OS combinations. Here is a working example using Python and Selenium, which opens a page, checks the title, and closes the browser:</p>
<pre><code class="lang-python">pythonCopy codefrom selenium <span class="hljs-keyword">import</span> webdriver
<span class="hljs-keyword">from</span> selenium.webdriver.common.by <span class="hljs-keyword">import</span> By

<span class="hljs-comment"># Define LambdaTest capabilities</span>
capabilities = {
  <span class="hljs-string">"browserName"</span>: <span class="hljs-string">"Chrome"</span>,
  <span class="hljs-string">"browserVersion"</span>: <span class="hljs-string">"latest"</span>,
  <span class="hljs-string">"LT:Options"</span>: {
    <span class="hljs-string">"platformName"</span>: <span class="hljs-string">"Windows 11"</span>,
    <span class="hljs-string">"build"</span>: <span class="hljs-string">"TestOps Working Demo"</span>,
    <span class="hljs-string">"name"</span>: <span class="hljs-string">"Title Verification Test"</span>,
    <span class="hljs-string">"selenium_version"</span>: <span class="hljs-string">"4.8.0"</span>,
    <span class="hljs-string">"w3c"</span>: <span class="hljs-literal">True</span>
  }
}

<span class="hljs-comment"># Replace with your LambdaTest username and access key</span>
USERNAME = <span class="hljs-string">"your_username"</span>
ACCESS_KEY = <span class="hljs-string">"your_access_key"</span>

<span class="hljs-comment"># Connect to LambdaTest cloud grid</span>
driver = webdriver.Remote(
    command_executor=<span class="hljs-string">f"https://<span class="hljs-subst">{USERNAME}</span>:<span class="hljs-subst">{ACCESS_KEY}</span>@hub.lambdatest.com/wd/hub"</span>,
    desired_capabilities=capabilities
)

<span class="hljs-keyword">try</span>:
    <span class="hljs-comment"># Step 1: Navigate to the app under test</span>
    driver.get(<span class="hljs-string">"https://www.lambdatest.com/selenium-playground/"</span>)

    <span class="hljs-comment"># Step 2: Interact with the page (click a link)</span>
    driver.find_element(By.LINK_TEXT, <span class="hljs-string">"Simple Form Demo"</span>).click()

    <span class="hljs-comment"># Step 3: Enter message and verify output</span>
    message_box = driver.find_element(By.ID, <span class="hljs-string">"user-message"</span>)
    message_box.send_keys(<span class="hljs-string">"TestOps in action!"</span>)
    driver.find_element(By.ID, <span class="hljs-string">"showInput"</span>).click()

    output = driver.find_element(By.ID, <span class="hljs-string">"message"</span>).text
    <span class="hljs-keyword">assert</span> output == <span class="hljs-string">"TestOps in action!"</span>, <span class="hljs-string">"Message output did not match input."</span>

    print(<span class="hljs-string">"✅ Test Passed: Message displayed correctly."</span>)
<span class="hljs-keyword">except</span> Exception <span class="hljs-keyword">as</span> e:
    print(<span class="hljs-string">"❌ Test Failed:"</span>, e)
<span class="hljs-keyword">finally</span>:
    driver.quit()
</code></pre>
<p>What this test does:</p>
<ul>
<li><p>Launches a browser on LambdaTest cloud</p>
</li>
<li><p>Navigates to their Selenium Playground</p>
</li>
<li><p>Fills out a form and clicks a button</p>
</li>
<li><p>Verifies that the output matches the input</p>
</li>
<li><p>Logs the result and closes the session</p>
</li>
</ul>
<p>Once the test finishes, you can view detailed logs, screenshots, and video recordings on the LambdaTest Automation Dashboard, which also includes AI-based debugging info.</p>
<h3 id="heading-what-types-of-problems-can-ml-help-solve-and-how">What Types of Problems Can ML Help Solve — and How?</h3>
<p>Machine learning can solve several pain points in testing. It looks at patterns in your data and helps identify things that manual checks might miss.</p>
<h4 id="heading-flaky-tests"><strong>Flaky Tests:</strong></h4>
<p>ML helps detect tests that pass and fail randomly across different builds. It finds patterns in those failures and flags the ones that are unstable. And by doing this early, it prevents teams from wasting time chasing false bugs.</p>
<h4 id="heading-test-prioritization"><strong>Test Prioritization:</strong></h4>
<p>ML studies your past test results and recent code changes. It then ranks your tests based on risk and importance. So, the most critical ones run first. This way, your pipeline moves faster without skipping key checks.</p>
<h4 id="heading-failure-prediction"><strong>Failure Prediction:</strong></h4>
<p>ML uses logs, crash reports, and previous outcomes to predict where failures may happen. If it finds something risky, it warns the team in advance. This gives them time to fix problems before they grow bigger.</p>
<h4 id="heading-root-cause-clustering"><strong>Root Cause Clustering:</strong></h4>
<p>When many tests fail at once, ML groups them by shared failure reasons. It helps you understand whether the issue is with one module or across several. That means your team can solve the actual root problem quicker.</p>
<h4 id="heading-anomaly-detection"><strong>Anomaly Detection:</strong></h4>
<p>ML tracks things like test duration and system behavior. If something suddenly changes, like a test taking too long or using too much memory, it flags it. These alerts help teams spot performance dips early.</p>
<h3 id="heading-what-types-of-analytics-tools-can-you-use">What Types of Analytics Tools Can You Use?</h3>
<p>Analytics tools help you turn your test results into useful information. They highlight patterns, gaps, and areas that need your attention. And because these insights are visual, they are easier to act on.</p>
<p>These tools can show how your pass/fail rates have changed over time. They also help you check which parts of your app are not covered by tests. If some tests are being skipped or are too flaky, the tools will highlight that too.</p>
<p>They also measure how long tests take to run and where your pipeline slows down. This helps teams reduce bottlenecks and improve efficiency.</p>
<p>Some platforms include dashboards that link test quality to deployment status. This gives you a clear picture of whether your product is ready for release.</p>
<p>They also track failures by environment—like which browsers or regions face more issues. This helps teams debug faster and improve global reliability.</p>
<p>All of these insights help QA and DevOps teams improve their strategies. They let you remove unnecessary tests, fix flaky ones, and focus where testing matters the most.</p>
<h3 id="heading-example-using-grafana-and-kibana-for-test-analytics"><strong>Example – Using Grafana and Kibana for Test Analytics</strong></h3>
<p>Analytics tools help your teams understand test trends, flakiness, coverage gaps, and slowdowns in the CI/CD pipeline. Here is how you can set them up to actually <em>work</em> with your test data.</p>
<h4 id="heading-example-1-visualizing-test-results-in-grafana-using-influxdb">Example 1: Visualizing Test Results in Grafana using InfluxDB</h4>
<p>Grafana is commonly paired with InfluxDB to display metrics such as pass/fail rates, test durations, and failure frequencies. Here’s how you can push your test results into InfluxDB and visualize them in Grafana.</p>
<h5 id="heading-step-by-step-setup"><strong>Step-by-step setup:</strong></h5>
<ol>
<li><p>Push test results to InfluxDB after each test run. This can be done from Jenkins, GitHub Actions, or any test automation framework that generates test results.</p>
</li>
<li><p>Query and visualize data in Grafana using InfluxDB as the data source.</p>
</li>
</ol>
<h5 id="heading-python-script-to-send-test-metrics-to-influxdb"><strong>Python script to send test metrics to InfluxDB:</strong></h5>
<pre><code class="lang-python">pythonCopy codefrom influxdb <span class="hljs-keyword">import</span> InfluxDBClient
<span class="hljs-keyword">import</span> time

<span class="hljs-comment"># Create an InfluxDB client to send data</span>
client = InfluxDBClient(host=<span class="hljs-string">'localhost'</span>, port=<span class="hljs-number">8086</span>)
client.switch_database(<span class="hljs-string">'test_metrics'</span>)  <span class="hljs-comment"># Switch to your specific database</span>

<span class="hljs-comment"># Example test result data</span>
json_body = [
    {
        <span class="hljs-string">"measurement"</span>: <span class="hljs-string">"test_results"</span>,
        <span class="hljs-string">"tags"</span>: {
            <span class="hljs-string">"test_suite"</span>: <span class="hljs-string">"login_tests"</span>,  <span class="hljs-comment"># Name of the test suite</span>
            <span class="hljs-string">"environment"</span>: <span class="hljs-string">"staging"</span>  <span class="hljs-comment"># Environment like 'production', 'staging', etc.</span>
        },
        <span class="hljs-string">"time"</span>: time.strftime(<span class="hljs-string">'%Y-%m-%dT%H:%M:%SZ'</span>),  <span class="hljs-comment"># Timestamp for the test execution</span>
        <span class="hljs-string">"fields"</span>: {
            <span class="hljs-string">"pass"</span>: <span class="hljs-number">10</span>,        <span class="hljs-comment"># Number of tests that passed</span>
            <span class="hljs-string">"fail"</span>: <span class="hljs-number">2</span>,         <span class="hljs-comment"># Number of tests that failed</span>
            <span class="hljs-string">"skipped"</span>: <span class="hljs-number">1</span>,      <span class="hljs-comment"># Number of tests that were skipped</span>
            <span class="hljs-string">"duration"</span>: <span class="hljs-number">12.5</span>   <span class="hljs-comment"># Duration of the test run in seconds</span>
        }
    }
]

<span class="hljs-comment"># Write the data points to InfluxDB</span>
client.write_points(json_body)
</code></pre>
<h5 id="heading-grafana-setup">Grafana setup:</h5>
<ul>
<li><p><strong>Data Source</strong>: In Grafana, connect to your InfluxDB instance.</p>
</li>
<li><p><strong>Dashboard</strong>: Create a dashboard that queries the <code>test_results</code> measurement and display:</p>
<ul>
<li><p>Line charts for pass/fail trends over time.</p>
</li>
<li><p>Pie charts for distribution of test results.</p>
</li>
<li><p>Table showing tests and their durations.</p>
</li>
</ul>
</li>
</ul>
<p>This approach helps you track key metrics and trends for each test suite and environment.</p>
<h4 id="heading-example-2-debugging-failures-by-environment-with-kibana-and-elasticsearch">Example 2: Debugging Failures by Environment with Kibana and Elasticsearch</h4>
<p>If your testing framework logs results into Elasticsearch, you can use Kibana to analyze and visualize those logs. For example, you can track which browsers or regions are facing more issues and display the results in Kibana.</p>
<h5 id="heading-elasticsearch-data-model"><strong>Elasticsearch Data Model:</strong></h5>
<p>First, let’s assume that test results are logged in Elasticsearch with the following format:</p>
<pre><code class="lang-json">jsonCopy code{
  <span class="hljs-attr">"timestamp"</span>: <span class="hljs-string">"2025-04-16T14:00:00Z"</span>,
  <span class="hljs-attr">"test_name"</span>: <span class="hljs-string">"checkout_flow_mobile"</span>,  # Name of the test
  <span class="hljs-attr">"status"</span>: <span class="hljs-string">"fail"</span>,  # Pass or fail status
  <span class="hljs-attr">"browser"</span>: <span class="hljs-string">"Safari"</span>,  # Browser used for the test
  <span class="hljs-attr">"region"</span>: <span class="hljs-string">"EU-West"</span>,  # Region where the test was run
  <span class="hljs-attr">"error"</span>: <span class="hljs-string">"Element not visible"</span>,  # Error message in case of failure
  <span class="hljs-attr">"duration"</span>: <span class="hljs-number">9.8</span>,  # Duration of the test in seconds
  <span class="hljs-attr">"env"</span>: <span class="hljs-string">"QA"</span>  # Environment where the test ran
}
</code></pre>
<h5 id="heading-kibana-setup"><strong>Kibana setup:</strong></h5>
<ol>
<li><p><strong>Data Ingestion</strong>: Your CI pipeline or test scripts push results to Elasticsearch after each run.</p>
</li>
<li><p><strong>Create Visualizations</strong>: In Kibana, create visualizations like:</p>
<ul>
<li><p><strong>Pie Chart</strong>: Show failure rates by browser type (e.g., Chrome, Firefox, Safari).</p>
</li>
<li><p><strong>Line Chart</strong>: Track test durations over time for a specific test suite.</p>
</li>
<li><p><strong>Table</strong>: Display flaky tests that fail repeatedly by region or environment.</p>
</li>
</ul>
</li>
</ol>
<p>Example of a Kibana query that you might use to filter failures by browser:</p>
<pre><code class="lang-json">jsonCopy code{
  <span class="hljs-attr">"query"</span>: {
    <span class="hljs-attr">"bool"</span>: {
      <span class="hljs-attr">"must"</span>: [
        { <span class="hljs-attr">"match"</span>: { <span class="hljs-attr">"status"</span>: <span class="hljs-string">"fail"</span> }},
        { <span class="hljs-attr">"match"</span>: { <span class="hljs-attr">"browser"</span>: <span class="hljs-string">"Safari"</span> }}
      ]
    }
  }
}
</code></pre>
<p>This will show all test failures in Safari, helping you identify browser-specific issues.</p>
<h3 id="heading-why-this-matters"><strong>Why This Matters</strong></h3>
<p>Using Grafana and Kibana with your test results helps your team gain valuable insights:</p>
<ul>
<li><p>Identify flaky tests and prioritize them for maintenance.</p>
</li>
<li><p>Track performance trends, including test duration and failure rates.</p>
</li>
<li><p>Debug faster by identifying failure patterns tied to specific browsers, environments, or regions.</p>
</li>
</ul>
<p>With these analytics in place, teams can make data-driven decisions to improve test coverage, reduce bottlenecks, and ensure better product quality.</p>
<h2 id="heading-future-of-testops-in-global-development">Future of TestOps in Global Development</h2>
<p>As global software delivery keeps growing more complex, TestOps is changing fast. It is no longer just a supporting function. Instead, it is becoming a central part of DevOps strategies. And as development moves faster, this shift is only expected to continue.</p>
<p>Here are some of the key changes that are shaping the future of TestOps. You will need to watch for them and prepare ahead.</p>
<h3 id="heading-ai-driven-decision-making-in-testops">AI-Driven Decision-Making in TestOps</h3>
<p>AI in TestOps is moving beyond just automating test cases or running scripts. It is starting to take on decision-making roles within the testing process. For instance, orchestration tools powered by AI will soon go further.</p>
<p>They will decide which tests should run, based on recent code changes and how those changes affect the business. They will also predict which parts of the system are more likely to break in the next release.</p>
<p>And as these tools learn from real-time usage patterns, they will suggest ways to improve your test strategy. That means TestOps professionals will not only need to know how to use these tools. They will also need to understand how to read the insights and make smart choices with them.</p>
<h3 id="heading-cloud-native-and-edge-testing">Cloud-Native and Edge Testing</h3>
<p>While teams are already embracing cloud-based testing, the next step is even more distributed. This is where edge-aware TestOps comes in. It focuses on testing software where it is used, not just where it is built.</p>
<p>That means tests will run closer to the user, in specific networks or regional setups. It will also mean checking how systems perform in places with different latency or unreliable connectivity.</p>
<p>And as data laws vary across regions, teams will need to manage test data carefully and securely. Because TestOps now stretches across countries and cloud platforms, it must adapt to decentralized architectures.</p>
<h3 id="heading-testops-as-a-unifier-of-observability-and-automation">TestOps as a Unifier of Observability and Automation</h3>
<p>TestOps will not only be about running tests anymore. It will play a larger role in bringing together testing, monitoring, and automation across the pipeline. This will create a more complete view of system health and product quality.</p>
<p>Tools under TestOps will start using production monitoring data to improve test design. If something fails in production, it can guide what should be tested next.</p>
<p>Real-time behavior from users can even trigger specific regression tests. This helps teams fix issues faster and smarter. As a result, TestOps will create a feedback loop between pre-release and post-release stages.</p>
<p>That means teams will not only rely on TestOps for test automation. They will also use it to see how everything connects—from development to operations.</p>
<h3 id="heading-skill-shifts-in-testops-teams">Skill Shifts in TestOps Teams</h3>
<p>As testing tools become more advanced, the skills that TestOps teams need will change too. There will be less demand for manual testing roles. But there will be more need for engineers who think strategically about quality.</p>
<p>You will see more roles focused on site reliability, automation frameworks, and test strategy. These roles will require knowledge of cloud infrastructure and continuous delivery.</p>
<p>And instead of working in silos, testers will work closely with developers and ops teams. This shift will require people who can think across functions and understand how everything fits together.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>Scaling TestOps for global software development teams is essential in today’s fast-moving, distributed work environment. By using best practices like standardizing tools, automating tests, promoting collaboration, and taking advantage of cloud and AI solutions, teams can ensure smooth, high-quality software delivery across different regions and time zones.</p>
<p>As TestOps evolves with advances in automation, AI, and cloud technology, it will make the testing process even more efficient. Teams will be able to respond faster, predict problems before they happen, and maintain high-quality standards.</p>
<p>The future of TestOps looks even more promising with smarter tools, better collaboration, and more automation, driving success for global development teams and improving the entire software development process.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Use AI to Automate Unit Testing with TestGen-LLM and Cover-Agent ]]>
                </title>
                <description>
                    <![CDATA[ It's important to write clear and efficient unit tests that actually work during the software development process. Unit tests separate out individual code elements and confirm that they work as intended. Effective unit tests not only catch errors but... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/automated-unit-testing-with-testgen-llm-and-cover-agent/</link>
                <guid isPermaLink="false">66d4608a246e57ac83a2c7bb</guid>
                
                    <category>
                        <![CDATA[ Artificial Intelligence ]]>
                    </category>
                
                    <category>
                        <![CDATA[ LLM&#39;s  ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Software Testing ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Testing ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Oluwadamisi Samuel ]]>
                </dc:creator>
                <pubDate>Mon, 03 Jun 2024 14:45:24 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2024/06/Final-X3-Cover-FFC-Cover-Agent.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>It's important to write clear and efficient unit tests that actually work during the software development process. Unit tests separate out individual code elements and confirm that they work as intended.</p>
<p>Effective unit tests not only catch errors but also help you be confident that your code can be maintained and is dependable. But it takes time and resources to manually create an extensive suite of unit tests.</p>
<p>There have been some recent developments in artificial intelligence that promise to help automate the unit test development processes. In February, researchers at Meta released a paper on <a target="_blank" href="https://arxiv.org/abs/2402.09171">Automated Unit Test Improvement using Large Language Models</a>. This introduced an innovative method for automating unit testing.</p>
<p>Their research focuses on a new tool called <code>TestGen-LLM</code>, which explores the possibilities of using LLMs to analyze already-existing unit tests and improving on them to increase code coverage.</p>
<p>Although the code for the TestGen-LLM was not released, I will introduce an open-source alternative inspired by their research in this article. You'll learn how it generates test suites, why it's better than most LLMs, and where to get your hands on this technology and start trying it out.</p>
<h2 id="heading-table-of-contents">Table of Contents</h2>
<ul>
<li><p><a class="post-section-overview" href="#heading-metas-testgen-llm">Meta’s TestGen-LLM</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-does-testgen-llm-work">How does TestGen-LLM work?</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-open-source-implementation-cover-agent">Open-Source Implementation (Cover-Agent)</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-does-cover-agent-work">How does Cover-Agent work?</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-use-cover-agent">How to Use Cover-Agent</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-benefits-of-the-open-source-cover-agent">Benefits of the Open-Source Cover-Agent</a></p>
</li>
<li><p><a class="post-section-overview" href="#how-can-you-contribute-to-this-technology">How can you Contribute to this Technology?</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-conclusion">Conclusion</a></p>
</li>
</ul>
<h2 id="heading-metas-testgen-llm">Meta’s TestGen-LLM</h2>
<p>Meta's TestGen-LLM tackles the time-consuming task of unit test writing by leveraging the power of Large Language Models (LLMs). General-purpose LLMs like Gemini or ChatGPT might struggle with the specific domain of unit test code, testing syntax, and generating tests that don't add value. But TestGen-LLM is specifically tailored for unit testing.</p>
<p>This specialization allows it to understand the intricacies of code structure and test logic, leading to more targeted test suites and generate tests that actually add value and increase code coverage.</p>
<p>TestGen-LLM is able to evaluate unit tests and identify areas for improvements. It achieves this through its understanding of common testing patterns which it has been trained with. But generating tests alone is insufficient for proper code coverage.</p>
<p>Meta's researchers implemented safeguards within TestGen-LLM to ensure the effectiveness of the tests it writes. These safeguards, referred to as <code>filters</code>, act as a quality control mechanism. They eliminate suggestions that:</p>
<ul>
<li><p>wouldn't compile</p>
</li>
<li><p>fail consistently, or</p>
</li>
<li><p>fail to actually improve code coverage (suggestions that are already covered by other tests).</p>
</li>
</ul>
<h2 id="heading-how-does-testgen-llm-work">How Does TestGen-LLM Work?</h2>
<p>TestGen-LLM uses an approach called "Assured LLM-based Software Engineering" (Assured LLMSE). TestGen-LLM simply augments an existing test class with additional test cases, retaining all existing test cases and thereby guaranteeing that there will be no regression.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/05/img-testgen-llm-paper.jpg" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Test generation workflow(</em><a target="_blank" href="https://arxiv.org/abs/2402.09171"><em>From TestGen_LLM paper</em></a><em>)</em></p>
<p>The TestGen-LLM generates a bunch of tests, then filters out the tests that don’t run and drops any that don’t pass. Finally, it discards those that don't increase the code coverage.</p>
<p>After using the TestGen-LLM to automate a test suite, Meta used a human reviewer to accept or reject tests where the generated tests had an acceptance rate of 73% in their best reported cases.</p>
<p>According to the paper, TestGen-LLM generates a single test on each run that is then added to an existing test suite which was written previously by a developer. But it doesn’t necessarily generate tests for any given test suite.</p>
<p>The effectiveness of TestGen-LLM was demonstrated at Meta's internal test-a-thons. Here, the tool was used to analyze existing test suites and suggest improvements. The results were promising:</p>
<blockquote>
<p><em>“75% of TestGen-LLM's test cases built correctly, 57% passed reliably, and 25% increased coverage. During Meta's Instagram and Facebook test-a-thons, it improved 11.5% of all classes to which it was applied, with 73% of its recommendations being accepted for production deployment by Meta software engineers”</em>.</p>
</blockquote>
<p>Also, the recommendations from TestGen-LLM were deemed useful and relevant by the developers who took part in the test-a-thons.</p>
<h2 id="heading-open-source-implementation-cover-agent">Open-Source Implementation (Cover-Agent)</h2>
<p>The TestGen-LLM research from Meta has a lot of potential to change unit testing and automated test generation. The tool will likely help improve code coverage and speed up test creation by utilizing LLMs particularly trained on code. But this technology is not available for use by just anyone, since the code for the TestGen-LLM was not released.</p>
<p>Developers who have taken an interest in this technology are probably frustrated by the lack of publicly available code. After all, Meta's TestGen-LLM study provides a glimpse into the future of what automated testing can be.</p>
<p>It's quite appealing to be able to dive into the newest technology’s internal workings, comprehend its decision-making procedures, and maybe even help shape its evolution. But while the absence of Meta's code is a hindrance, there's an open-source implementation called <code>Cover-Agent</code> which can serve as a helpful alternative.</p>
<p><code>CodiumAI's Cover-Agent</code> is the first open-source implementation of an automated testing tool based on TestGen-LLM. Inspired by Meta's research, Cover-Agent is now at the forefront of developments in open-source AI-driven unit testing as a result.</p>
<h3 id="heading-why-are-specific-testing-focused-llms-necessary">Why are specific testing-focused LLMs necessary?</h3>
<p>Since most LLMs (like ChatGPT and Gemini) are capable of generating tests, then why bother with a new technology?</p>
<p>Well, Cover-Agent and TestGen-LLM were created to be the next step in the evolution of efficient unit testing. Their aim is to avoid common pitfalls that developers run into when generating tests with LLMs such as:</p>
<ul>
<li><p>LLM Hallucination</p>
</li>
<li><p>Generating tests that do not add value</p>
</li>
<li><p>Generating tests that omit some parts of the code, resulting in low code coverage</p>
</li>
</ul>
<p>To overcome such challenges (specifically for regression unit tests) the TestGen-LLM researchers came up with the following criteria which the generated tests must meet before the test can be accepted:</p>
<ul>
<li><p>Does the generated test compile and run properly?</p>
</li>
<li><p>Does the test increase code coverage?</p>
</li>
<li><p>Does it add value?</p>
</li>
<li><p>Does it meet any additional requirements that we may have?</p>
</li>
</ul>
<p>These are fundamental questions and issues that the generated test must solve before it is deemed an upgrade on the existing technology. Cover-Agent provides tests that answer these questions to an amazingly high degree.</p>
<h2 id="heading-how-does-cover-agent-work">How Does Cover-Agent Work?</h2>
<p>Cover-Agent is part of a broader suite of utilities designed to automate the creation of unit tests for software projects. Utilizing the TestGen-LLM Generative AI model, it aims to simplify and expedite the testing process, ensuring high-quality software development.</p>
<p>The system is made up of several components:</p>
<ul>
<li><p><strong>Test Runner</strong>: Executes the command or scripts to run the test suite and generate code coverage reports.</p>
</li>
<li><p><strong>Coverage Parser:</strong> Validates that code coverage increases as tests are added, ensuring that new tests contribute to the overall test effectiveness.</p>
</li>
<li><p><strong>Prompt Builder:</strong> Gathers necessary data from the codebase and constructs the prompt to be passed to the Large Language Model (LLM).</p>
</li>
<li><p><strong>AI Caller:</strong> Interacts with the LLM to generate tests based on the prompt provided.</p>
</li>
</ul>
<p>These components work together with TestGen-LLM to generate only tests that are guaranteed to improve the existing code base.</p>
<h2 id="heading-how-to-use-cover-agent">How to Use Cover-Agent</h2>
<h3 id="heading-requirements">Requirements</h3>
<p>You need to have the following requirements before you can begin using Cover-Agent:</p>
<ul>
<li><p><code>OPENAI_API_KEY</code> set in your environment variables, which is required for calling the <code>OpenAI API</code>.</p>
</li>
<li><p>Code Coverage tool: A Cobertura XML code coverage report is required for the tool to function correctly. For example, in Python you could use <code>pytest-cov.</code> Add the <code>--cov-report=xml</code> option when running Pytest.</p>
</li>
</ul>
<h3 id="heading-installation">Installation</h3>
<p>If you're running Cover-Agent directly from the repository, you will also need:</p>
<ul>
<li><p>Python installed on your system.</p>
</li>
<li><p>Poetry installed for managing Python package dependencies. You can find installation instructions for Poetry <a target="_blank" href="https://python-poetry.org/docs/">here</a>.</p>
</li>
</ul>
<h4 id="heading-standalone-runtime">Standalone Runtime</h4>
<p>You can install Cover-Agent as a Python Pip package or run it as a standalone executable.</p>
<h4 id="heading-python-pip">Python Pip</h4>
<p>To install the Python Pip package directly via GitHub, run the following command:</p>
<pre><code class="lang-py">pip install git+https://github.com/Codium-ai/cover-agent.git
</code></pre>
<h4 id="heading-binary">Binary</h4>
<p>You can run the binary without any Python environment installed on your system (for example, within a Docker container that does not contain Python). You can download the release for your system by navigating to the project's <a target="_blank" href="https://github.com/Codium-ai/cover-agent/releases">release page</a>.</p>
<h4 id="heading-repository-setup">Repository Setup</h4>
<p>Run the following command to install all the dependencies and run the project from source:</p>
<pre><code class="lang-py">poetry install
</code></pre>
<h4 id="heading-running-the-code">Running the Code</h4>
<p>After downloading the executable or installing the Pip package, you can now run Cover-Agent to generate and validate unit tests.</p>
<p>Execute it from the command line by using the following command:</p>
<pre><code class="lang-py">cover-agent \
--source-file-path <span class="hljs-string">"path_to_source_file"</span> \
--test-file-path <span class="hljs-string">"path_to_test_file"</span> \
--code-coverage-report-path <span class="hljs-string">"path_to_coverage_report.xml"</span> \
--test-command <span class="hljs-string">"test_command_to_run"</span> \
--test-command-dir <span class="hljs-string">"directory_to_run_test_command/"</span> \
--coverage-type <span class="hljs-string">"type_of_coverage_report"</span> \
--desired-coverage <span class="hljs-string">"desired_coverage_between_0_and_100"</span> \
--max-iterations <span class="hljs-string">"max_number_of_llm_iterations"</span> \
 --included-files <span class="hljs-string">"&lt;optional_list_of_files_to_include&gt;"</span>
</code></pre>
<p>You can use the example projects within this repository to run this code as a test.</p>
<h4 id="heading-command-arguments">Command Arguments</h4>
<ul>
<li><p><strong>source-file-path:</strong> Path of the file containing the functions or block of code we want to test for.</p>
</li>
<li><p><strong>test-file-path:</strong> Path of the file where the tests will be written by the agent. It’s best to create a skeleton of this file with at least one test and the necessary import statements.</p>
</li>
<li><p><strong>code-coverage-report-path:</strong> Path where the code coverage report is saved.</p>
</li>
<li><p><strong>test-command:</strong> Command to run the tests (for example pytest).</p>
</li>
<li><p><strong>test-command-dir</strong>: Directory where the test command should run. Set this to the root or the location of your main file to avoid issues with relative imports.</p>
</li>
<li><p><strong>coverage-type:</strong> Type of coverage to use. Cobertura is a good default.</p>
</li>
<li><p><strong>desired-coverage:</strong> Coverage goal. Higher is better, though 100% is often impractical.</p>
</li>
<li><p><strong>max-iterations:</strong> Number of times the agent should retry to generate test code. More iterations may lead to higher OpenAI token usage.</p>
</li>
<li><p><strong>additional-instructions:</strong> Prompts to ensure the code is written in a specific way. For example, here we specify that the code should be formatted to work within a test class.</p>
</li>
</ul>
<p>On running the command, the agent starts writing and iterating on the tests.</p>
<h3 id="heading-how-to-use-cover-agent-1">How to Use Cover-Agent</h3>
<p>It's time test out Cover-Agent. We will use a simple calculator.py app to compare the code coverage for manual and automated testing.</p>
<h4 id="heading-manual-testing">Manual Testing</h4>
<pre><code class="lang-py"><span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">add</span>(<span class="hljs-params">a, b</span>):</span>
    <span class="hljs-keyword">return</span> a + b

<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">subtract</span>(<span class="hljs-params">a, b</span>):</span>
    <span class="hljs-keyword">return</span> a - b

<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">multiply</span>(<span class="hljs-params">a, b</span>):</span>
    <span class="hljs-keyword">return</span> a * b

<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">divide</span>(<span class="hljs-params">a, b</span>):</span>
    <span class="hljs-keyword">if</span> b == <span class="hljs-number">0</span>:
        <span class="hljs-keyword">raise</span> ValueError(<span class="hljs-string">"Cannot divide by zero"</span>)
    <span class="hljs-keyword">return</span> a / b
</code></pre>
<p>This is the test_calculator.py placed in the test folder.</p>
<pre><code class="lang-py"><span class="hljs-comment"># tests/test_calculator.py</span>
<span class="hljs-keyword">from</span> calculator <span class="hljs-keyword">import</span> add, subtract, multiply, divide

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">TestCalculator</span>:</span>

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">test_add</span>(<span class="hljs-params">self</span>):</span>
        <span class="hljs-keyword">assert</span> add(<span class="hljs-number">2</span>, <span class="hljs-number">3</span>) == <span class="hljs-number">5</span>
</code></pre>
<p>To see the test coverage, we need to install <code>pytest-cov</code>, a pytest extension for coverage reporting stated earlier.</p>
<pre><code class="lang-py">pip install pytest-cov
</code></pre>
<p>Run the coverage analysis with:</p>
<pre><code class="lang-py">pytest --cov=calculator
</code></pre>
<p>The output shows:</p>
<pre><code class="lang-py">Name            Stmts   Miss  Cover
-----------------------------------
calculator.py      <span class="hljs-number">10</span>      <span class="hljs-number">5</span>    <span class="hljs-number">50</span>%
-----------------------------------
TOTAL              <span class="hljs-number">10</span>      <span class="hljs-number">5</span>    <span class="hljs-number">50</span>%
</code></pre>
<p>The output above shows that 5 of the 10 statements in calculator.py are not executed, resulting in just 50% code coverage. For a larger code base, this will become a serious issue and lead to setbacks.</p>
<p>Now let's see if cover-agent can do better.</p>
<h4 id="heading-automated-testing-with-cover-agent">Automated Testing with Cover-Agent</h4>
<p>To set up Codium's Cover-Agent, follow these steps:</p>
<p>First, install Cover-Agent:</p>
<pre><code class="lang-py">pip install git+https://github.com/Codium-ai/cover-agent.git
</code></pre>
<p>Make sure that your OPENAI_API_KEY is set in your environment variables, as it is required for the OpenAI API.</p>
<p>Next, write the commands to start generating tests in the terminal:</p>
<pre><code class="lang-py">cover-agent \
--source-file-path <span class="hljs-string">"calculator.py"</span> \
--test-file-path <span class="hljs-string">"tests/test_calculator.py"</span> \
--code-coverage-report-path <span class="hljs-string">"coverage.xml"</span> \
--test-command <span class="hljs-string">"pytest --cov=. --cov-report=xml --cov-report=term"</span> \
--test-command-dir <span class="hljs-string">"./"</span> \
--coverage-type <span class="hljs-string">"cobertura"</span> \
--desired-coverage <span class="hljs-number">80</span> \
--max-iterations <span class="hljs-number">3</span> \
--openai-model <span class="hljs-string">"gpt-4o"</span> \
--additional-instructions <span class="hljs-string">"Since I am using a test class, each line of code (including the first line) needs to be prepended with 4 whitespaces. This is extremely important to ensure that every line returned contains that 4 whitespace indent; otherwise, my code will not run."</span>
</code></pre>
<p>This generates the following code:</p>
<pre><code class="lang-py"><span class="hljs-keyword">import</span> pytest
<span class="hljs-keyword">from</span> calculator <span class="hljs-keyword">import</span> add, subtract, multiply, divide

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">TestCalculator</span>:</span>

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">test_add</span>(<span class="hljs-params">self</span>):</span>
        <span class="hljs-keyword">assert</span>(add(<span class="hljs-number">2</span>, <span class="hljs-number">3</span>), <span class="hljs-number">5</span>

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">test_subtract</span>(<span class="hljs-params">self</span>):</span>
        <span class="hljs-string">"""
        Test subtracting two numbers.
        """</span>
        <span class="hljs-keyword">assert</span> subtract(<span class="hljs-number">5</span>, <span class="hljs-number">3</span>) == <span class="hljs-number">2</span>
        <span class="hljs-keyword">assert</span> subtract(<span class="hljs-number">3</span>, <span class="hljs-number">5</span>) == <span class="hljs-number">-2</span>

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">test_multiply</span>(<span class="hljs-params">self</span>):</span>
        <span class="hljs-string">"""
        Test multiplying two numbers.
        """</span>
        <span class="hljs-keyword">assert</span> multiply(<span class="hljs-number">2</span>, <span class="hljs-number">3</span>) == <span class="hljs-number">6</span>
        <span class="hljs-keyword">assert</span> multiply(<span class="hljs-number">-2</span>, <span class="hljs-number">3</span>) == <span class="hljs-number">-6</span>
        <span class="hljs-keyword">assert</span> multiply(<span class="hljs-number">2</span>, <span class="hljs-number">-3</span>) == <span class="hljs-number">-6</span>
        <span class="hljs-keyword">assert</span> multiply(<span class="hljs-number">-2</span>, <span class="hljs-number">-3</span>) == <span class="hljs-number">6</span>

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">test_divide</span>(<span class="hljs-params">self</span>):</span>
        <span class="hljs-string">"""
        Test dividing two numbers.
        """</span>
        <span class="hljs-keyword">assert</span> divide(<span class="hljs-number">6</span>, <span class="hljs-number">3</span>) == <span class="hljs-number">2</span>
        <span class="hljs-keyword">assert</span> divide(<span class="hljs-number">-6</span>, <span class="hljs-number">3</span>) == <span class="hljs-number">-2</span>
        <span class="hljs-keyword">assert</span> divide(<span class="hljs-number">6</span>, <span class="hljs-number">-3</span>) == <span class="hljs-number">-2</span>
        <span class="hljs-keyword">assert</span> divide(<span class="hljs-number">-6</span>, <span class="hljs-number">-3</span>) == <span class="hljs-number">2</span>

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">test_divide_by_zero</span>(<span class="hljs-params">self</span>):</span>
        <span class="hljs-string">"""
        Test dividing by zero, should raise ValueError.
        """</span>
        <span class="hljs-keyword">with</span> pytest.raises(ValueError, match=<span class="hljs-string">"Cannot divide by zero"</span>):
            divide(<span class="hljs-number">5</span>, <span class="hljs-number">0</span>)
</code></pre>
<p>You can see that the agent also wrote tests that check for errors for any edge cases.</p>
<p>Now it's time to test the coverage again:</p>
<pre><code class="lang-py">pytest --cov=calculator
</code></pre>
<p>Output:</p>
<pre><code class="lang-py">Name            Stmts   Miss  Cover
-----------------------------------
calculator.py      <span class="hljs-number">10</span>      <span class="hljs-number">0</span>   <span class="hljs-number">100</span>%
-----------------------------------
TOTAL              <span class="hljs-number">10</span>      <span class="hljs-number">0</span>   <span class="hljs-number">100</span>%
</code></pre>
<p>In this example we reached 100% code coverage. For larger code bases, the procedure is relatively the same. You can read through <a target="_blank" href="https://dev.to/oluwadamisisamuel1/how-to-automate-test-generation-with-ai-using-codiumai-cover-agent-1kep">this guide</a> for a walkthrough on a larger code base.</p>
<p>While Cover-Agent represents a significant step forward, it's important to note that this technology is still in its early stages. Continued research and development are crucial for further refinement and broader adoption and codiumAI invites you to make your contributions to this open source tool.</p>
<h2 id="heading-benefits-of-the-open-source-cover-agent">Benefits of the Open Source Cover-Agent</h2>
<p>The open source nature of Cover-Agent offers several advantages that should help propel the technology forward. Among them are:</p>
<ul>
<li><p><strong>Accessibility:</strong> Its open source nature enables LLM-based testing experimentation and it is accessible to developers with varying backgroundsThis will increase the number of users and lead to the development of a better technology and more applications..</p>
</li>
<li><p><strong>Cooperation:</strong> Developers are able to make contributions, suggest enhancements, propose new features and report issues. Cover-Agent will grow and develop quickly into a project perfect for developers..</p>
</li>
<li><p><strong>Transparency:</strong> Information about the internal operations are available and this promotes trust and will ultimately increase the potential for the technology.</p>
</li>
</ul>
<p>In addition to it’s open-source advantages, Cover-Agent provides developers with a strong set of benefits of its own:</p>
<ul>
<li><p><strong>Simple Access:</strong> Developers can easily install and experiment with LLM-based testing. This allows for firsthand and immediate exploration of the technology's capabilities and with little to no disruption in their workflow.</p>
</li>
<li><p><strong>Customization for Specific Needs:</strong> Cover-Agent's open-source nature allows developers to adapt the tool to their specific project requirements. This could involve modifying the LLM model used, adjusting training data to better reflect their codebase, or integrating Cover-Agent with existing testing frameworks. This level of customization empowers developers to leverage the power of LLM-based testing in a way that aligns with their project needs.</p>
</li>
<li><p><strong>Easy Integration:</strong> It is easily integrated with VSCode (a popular code editor) which makes integration with existing workflows a breeze. You can also easily integrate it with existing human-written tests.</p>
</li>
</ul>
<h2 id="heading-how-can-you-contribute-to-cover-agent">How Can You Contribute to Cover-Agent?</h2>
<p>Cover-Agent source code is publicly available through <a target="_blank" href="https://github.com/Codium-ai/cover-agent">this GitHub repo</a>. They encourage developers of all backgrounds to test their product and make contributions to further improve and grow this new technology.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>LLM-based test improvement tools hold immense potential for revolutionizing the way developers approach unit testing. By leveraging the power of large language models specifically trained on code, these tools can streamline test creation, improve code coverage, and ultimately enhance software quality.</p>
<p>While Meta's research with TestGen-LLM offers valuable insights, the lack of publicly available code hinders wider adoption and ongoing development. Fortunately, Cover-Agent has provided a readily accessible and customizable solution. It empowers developers to experiment with LLM-based testing and contribute to its evolution.</p>
<p>The potential for the TestGen-LLM and Cover-Agent is immense, and further development through contributions by developers will lead to a revolutionary tool that will transform automated test generation forever.</p>
<ul>
<li><p><a target="_blank" href="https://arxiv.org/abs/2402.09171">Meta’s Research Paper</a></p>
</li>
<li><p><a target="_blank" href="https://www.codium.ai/blog/we-created-the-first-open-source-implementation-of-metas-testgen-llm/">Cover-Agent Blog for further study</a></p>
</li>
<li><p><a target="_blank" href="https://dev.to/oluwadamisisamuel1/how-to-automate-test-generation-with-ai-using-codiumai-cover-agent-1kep">Article for installation process and use cases</a></p>
</li>
</ul>
<p>Connect with me on <a target="_blank" href="http://www.linkedin.com/in/samuel-oluwadamisi-01b3a4236">LinkedIn</a> and <a target="_blank" href="https://twitter.com/Data_Steve_">Twitter</a> if you found this helpful.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Use Cypress for End-to-End Testing Your React Apps ]]>
                </title>
                <description>
                    <![CDATA[ React is a popular framework for building web applications. It's is one of the best options for frontend engineering because of its declarative approach to user interface design and component-based architecture. But it can be difficult to make sure y... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/cypress-for-end-to-end-testing-react-apps/</link>
                <guid isPermaLink="false">66d4608affe6b1f641b5fa4f</guid>
                
                    <category>
                        <![CDATA[ React ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Software Testing ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Okosa Leonard ]]>
                </dc:creator>
                <pubDate>Wed, 01 Nov 2023 22:45:46 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2023/10/1_PfsGOHgjLPh3EFOkxCRmjw.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>React is a popular framework for building web applications. It's is one of the best options for frontend engineering because of its declarative approach to user interface design and component-based architecture.</p>
<p>But it can be difficult to make sure your React application functions as intended in various different scenarios.</p>
<p>Cypress is an end-to-end testing framework that you can use to test your React apps. And in this tutorial, I'll explain how to create efficient end-to-end tests for your web application using Cypress and React.</p>
<h2 id="heading-table-of-contents">Table of Contents</h2>
<ol>
<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-how-to-set-up-your-environment">How to Set Up Your Environment</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-write-your-first-cypress-test">How to Write Your First Cypress Test</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-interact-with-react-components">How to Interact with React Components</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-cypress-queries">Cypress Queries</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-cypress-assertions">Cypress Assertions</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-cypress-actions">Cypress Actions</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-organize-and-run-your-cypress-tests">How to Organize and Run Your Cypress Tests</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-plugins">Plugins</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-describe-blocks">Describe Blocks</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-custom-commands">Custom Commands</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-cypress-dashboard">Cypress Dashboard</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-debug-your-code-with-cypress">How to Debug Your Code with Cypress</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-continuous-integration">Continuous Integration</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-conclusion">Conclusion</a></p>
</li>
</ol>
<h2 id="heading-what-is-cypress">What is Cypress?</h2>
<p>Cypress is a straightforward open-source end-to-end testing framework designed for modern web development. It's based on JavaScript.</p>
<p>The tool operates within the browser, which sets it apart from other testing tools like Selenium. The concise, uncomplicated API that Cypress provides for interacting with your application makes it easy to create and manage tests.</p>
<p>You can create and manage tests that mimic user interactions with Cypress. You can also examine your web application for expected behavior and troubleshoot any concerns that arise.</p>
<h2 id="heading-how-to-set-up-your-environment">How to Set Up Your Environment</h2>
<p>Before we begin writing tests, you'll want to set up your environment. You must have Node.js and npm (Node Package Manager) installed in order to use Cypress with your React application.</p>
<p>You can visit <a target="_blank" href="https://nodejs.org/en/">https://nodejs.org/en/</a> to download to install Node.js on your computer if it isn't already installed. To get started using Cyprus after installing Node, you can follow these steps:</p>
<h3 id="heading-1-create-a-react-application">1) Create a React Application</h3>
<p>We'll utilize Vite to develop our React application, as it helps us quickly and efficiently create web apps.</p>
<p>To get started, create a React app on Vite by entering the following code in your console:</p>
<pre><code class="lang-js">npm create vite@latest
</code></pre>
<p>Vite will ask you to give your project a name. Choose whatever name you like.</p>
<p>Following that, Vite will give you the choice of framework. Just make sure you select React for this lesson.</p>
<p>It'll then ask you to select between TypeScript and JavaScript when you select React. Pick JavaScript.</p>
<p>Then go to your project directory and choose your project.</p>
<p>Finally, type <code>npm install</code> after that, and then <code>npm start dev</code> to launch your project.</p>
<p>Your project will be hosted by Vite at <code>http://localhost:5173/</code>. To view your project in a browser, click the link that's provided.</p>
<h3 id="heading-2-install-cypress">2) Install cypress</h3>
<p>You can install Cypress in your project by using this code <code>install cypress –-save-dev</code> in your terminal. This code installs Cypress in your React application.</p>
<h3 id="heading-3-initialize-cypress">3) Initialize Cypress</h3>
<p>Run <code>npx Cypress open</code> from the directory of your React project. This command should launch Cypress Test Runner, a graphical tool for creating and managing tests. You will now have two alternatives for automated testing:</p>
<ul>
<li><p>End-to-End Testing: End-to-end testing involves a browser using an automated tool like Cypress, so you can make tests consisting of functions like pressing buttons, typing in inputs, and so on. This helps make sure everything’s working perfectly.</p>
</li>
<li><p>Component Testing: This involves testing individual components instead of the entire React application.</p>
</li>
</ul>
<h4 id="heading-what-is-the-cypress-test-runner">What is the Cypress Test Runner?</h4>
<p>The test runner opens up once you pass in <code>npx cypress open</code>. It is a graphical tool for creating and managing tests, it also allows you to write and execute your test cases in Cypress.</p>
<p>After selecting what type of testing you want to do, the next section of the test runner helps you specify what script you want to execute, and gives you the option to select the browser you want to use and validate your tests as expected.</p>
<h3 id="heading-4-folder-structure">4) Folder Structure</h3>
<p>Cypress will automatically save its test files and configurations inside of your project in a subfolder named <code>cypress</code>.</p>
<h2 id="heading-how-to-write-your-first-cypress-test">How to Write Your First Cypress Test</h2>
<p>We'll use JavaScript to write our Cypress tests which are executed within the browser. Here's how to create your React application's first test.</p>
<p>Suppose we wish to check to see if the Document Object Model (DOM) displays our h2 element. To accomplish this using Cypress, take the following actions:</p>
<p><strong>Step 1</strong>: In your Cypress folder, go to the e2e file and there you’ll see a line of code similar to this:</p>
<pre><code class="lang-javascript">describe(<span class="hljs-string">'template spec'</span>, <span class="hljs-function">() =&gt;</span> {
    it(<span class="hljs-string">'passes'</span>, <span class="hljs-function">() =&gt;</span> {
        cy.visit(<span class="hljs-string">'https://example.cypress.io'</span>)
    })
    })
</code></pre>
<p><strong>Step 2</strong>: Now, in <code>cy.visit</code>, update the default http address to your React app's address (<a target="_blank" href="http://localhost:5173/">http://localhost:5173/</a>, if you recall).</p>
<p><strong>Step 3</strong>: We wish to check to see if the DOM has our h2 element. Navigate to the element you wish to test and add <code>data-testid</code> as an attribute to accomplish this. Next, assign a name to the attribute. Example: <code>&lt;h2 data-testid="cypress-h1"&gt; Leo Website &lt;/h2&gt;</code>.</p>
<p><strong>Step 4</strong>: Make a space and add this piece of code to your cypress folder to see if the attribute exists.</p>
<pre><code class="lang-js">cy.get(‘[data-testid=”cypress-header”]’).should(“exists”):
</code></pre>
<p>Since Cypress is configured to execute tests upon save, as soon as you save anything in your code editor, the test ought to instantly start in Cypress.</p>
<h2 id="heading-how-to-interact-with-react-components">How to Interact With React Components</h2>
<p>You'll want to be familiar with the vast array of commands used to imitate user interactions in order to write more insightful tests.</p>
<p>With its extensive command set for interacting with and testing online elements, Cypress is designed specifically for webpages and web applications.</p>
<p>To imitate user interactions and assert certain behaviors of the application, test scripts employ these instructions. Because Cypress maintains a promise chain on your behalf, you can chain commands together. Until the chain breaks and an error occurs, each command yields a "subject" to the following command.</p>
<p>Cypress commands can be classified into the following groups: queries, assertions, actions, and others.</p>
<h3 id="heading-cypress-queries">Cypress Queries</h3>
<p>These are Cypress commands that retrieve your application's current status. They retry as necessary to ensure that the DOM element or other data they offer is constantly current. They return a subject for additional commands to act upon or assert.</p>
<p>Here are some ways you can organize and run tests:</p>
<h4 id="heading-using-the-children-method">Using the <code>.children()</code> method</h4>
<p>To choose and work with a parent element's direct child elements in Cypress, use the <code>.children()</code> method. It enables you to access particular child elements of a given parent element by navigating the DOM tree.</p>
<p>Here are some examples of how to use <code>.children()</code> in Cypress:</p>
<p>Example 1: Assuming you have this sort HTML structure in your <code>jsx</code> file:</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"parent-element"</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"child"</span>&gt;</span>Child 1<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"child"</span>&gt;</span>Child 2<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"child"</span>&gt;</span>Child 3<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>
</code></pre>
<p>To choose and work with the child elements inside the <code>.parent</code> element, use the <code>.children()</code> function like this:</p>
<pre><code class="lang-javascript">cy.get(<span class="hljs-string">'.parent'</span>).children(<span class="hljs-string">'.child'</span>).should(<span class="hljs-string">'have.length'</span>, <span class="hljs-number">3</span>);

<span class="hljs-comment">// Click on the second child element</span>
cy.get(<span class="hljs-string">'.parent'</span>).children(<span class="hljs-string">'.child'</span>).eq(<span class="hljs-number">1</span>).click();
</code></pre>
<p>Example 2: you can perform a whole range of tasks using <code>.children()</code> combined with other Cypress functions. You can, for instance, recognize certain child objects and define their properties:</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// Ensure that the first child element contains the text "Child 1"</span>
cy.get(<span class="hljs-string">'.parent'</span>).children(<span class="hljs-string">'.child'</span>).first().should(<span class="hljs-string">'contain'</span>, <span class="hljs-string">'Child 1'</span>);

<span class="hljs-comment">// Verify that all child elements have a specific class</span>
cy.get(<span class="hljs-string">'.parent'</span>).children(<span class="hljs-string">'.child'</span>).each(<span class="hljs-function">(<span class="hljs-params">$child</span>) =&gt;</span> {
  cy.wrap($child).should(<span class="hljs-string">'have.class'</span>, <span class="hljs-string">'child'</span>);
});
</code></pre>
<p>Example 3: Many Cypress instructions may be chained together to perform more complex interactions. Using <code>.children()</code>, you can select the parent element, select its child elements, and then operate with the child elements as demonstrated by this example:</p>
<pre><code class="lang-javascript">cy.get(<span class="hljs-string">'.parent'</span>)
  .children(<span class="hljs-string">'.child'</span>)
  .first()
  .click()
  .next()
  .type(<span class="hljs-string">'I'</span>m Leo<span class="hljs-string">');</span>
</code></pre>
<p>To interact with the next child element in this example, we first pick the <code>.parent</code> element, then use <code>.children('.child')</code> to select its child elements, click on the first child element, and then chain more instructions to type "I'm Leo."</p>
<p>These examples show you how to pick and work with child items inside of a parent element in Cypress using the <code>.children()</code> function. Depending on your unique HTML structure, you can modify the CSS selector inside <code>.children()</code> to match the child elements you wish to target.</p>
<p>Now you should have an have an idea of how <code>.children()</code> works and how you can use queries as a type of Cypress command. There are more query commands but you can always refer to the documentation on <a target="_blank" href="https://www.freecodecamp.org/news/p/ee697448-b73d-43dd-85de-d31f1e1005c6/cypress.io">cypress.io</a> to learn more on them.</p>
<h4 id="heading-using-the-cyget-command">Using the cy.get() command</h4>
<p><code>cy.get()</code> is a fundamental command in the Cypress framework. You use it to choose and perform actions on DOM elements inside a web application, including those created using React.</p>
<p>To choose one or more DOM elements from your React application for testing, use the <code>cy.get()</code> command. It lets you pick elements with CSS selectors or other Cypress-compatible methods.</p>
<p>The fundamental syntax of <code>cy.get()</code> is <code>cy.get(selector)</code>.</p>
<p><code>selector</code> is an instance of a CSS selector. There are alternative ways for choosing components based on attributes like ID, class name, or data.</p>
<p>Suppose you have a React component like this:</p>
<pre><code class="lang-javascript">&lt;button data-testid=<span class="hljs-string">"Leo-button"</span>&gt;Click&lt;/button&gt;
</code></pre>
<p>You can use <code>cy.get()</code> to select the button element:</p>
<pre><code class="lang-javascript">cy.get(‘[data-testid=”Leo-button”]’);
</code></pre>
<p><code>cy.get('#Leo-button')</code> in this case chooses the button element with ID "Leo-button."</p>
<h3 id="heading-cypress-assertions">Cypress Assertions</h3>
<p>These are Cypress commands that make assertions about the state of your application. They stop your test when they reach the time limit or the specified condition is fulfilled.</p>
<p>There are only two types of assertion commands: <code>.and()</code> and <code>.should()</code>. I'll discuss <code>.should()</code> here.</p>
<p>In Cypress, statements concerning the states of particular elements are made using the <code>.should()</code> command. It enables you to specify requirements that components must fulfill. In the event that the requirements are not satisfied, the test will fail.</p>
<h4 id="heading-fundamental-use-of-should">Fundamental Use of <code>.should()</code></h4>
<p>The basic syntax of <code>.should()</code> is as follows:</p>
<pre><code class="lang-javascript">cy.get(<span class="hljs-string">'selector'</span>).should(<span class="hljs-string">'condition'</span>, expectedValue);
</code></pre>
<ul>
<li><p>The DOM element(s) that you wish to make assertions against are chosen by <code>cy.get('selector')</code>.</p>
</li>
<li><p><code>.should('condition', expectedValue)</code> indicates what conditions and values the chosen element(s) must satisfy.</p>
</li>
</ul>
<p>You can also chain <code>.should()</code> assertions. Chained <code>.should()</code> statements are used to verify different conditions on the same element:</p>
<pre><code class="lang-javascript">cy.get(<span class="hljs-string">'input#username'</span>)
  .should(<span class="hljs-string">'be.visible'</span>)
  .should(<span class="hljs-string">'have.attr'</span>, <span class="hljs-string">'placeholder'</span>, <span class="hljs-string">'Enter your username'</span>)
</code></pre>
<p>In this example, we verify that the username input element is there and that the placeholder content is appropriate.</p>
<p><code>.should()</code> also allows you to use custom assertions by passing a callback function as the expected value:</p>
<pre><code class="lang-javascript">cy.get(<span class="hljs-string">'.my-element'</span>).should(<span class="hljs-function">(<span class="hljs-params">$element</span>) =&gt;</span> {
  expect($element).to.have.class(<span class="hljs-string">'active'</span>);
  expect($element).to.have.css(<span class="hljs-string">'color'</span>, <span class="hljs-string">'rgb(255, 0, 0)'</span>);
});
</code></pre>
<p>In this code, we're using custom assertions within <code>.should()</code> to check if the element has the class "active" and if its text color is red.</p>
<h4 id="heading-negating-assertions-with-should">Negating assertions with .should()</h4>
<p><code>.should('not.condition', expectedValue)</code> can be used to refute the following claims:</p>
<pre><code class="lang-javascript">cy.get(<span class="hljs-string">'#error-message'</span>).should(<span class="hljs-string">'not.exist'</span>);
</code></pre>
<p>This code verifies that there isn't an element with the ID "error-message".</p>
<h4 id="heading-combining-should-with-other-commands">Combining .should() with Other Commands</h4>
<p>To create testing scenarios with greater complexity, you can combine <code>.should()</code> with other Cypress commands. For instance, you can use it to assert the element's final state following a <code>.click()</code> or <code>.type()</code> command.</p>
<pre><code class="lang-javascript">cy.get(<span class="hljs-string">'button'</span>).click().should(<span class="hljs-string">'be.disabled'</span>);
cy.get(‘[data-testid=”search-input”]’).type(<span class="hljs-string">'Leonard'</span>).should(<span class="hljs-string">'have.value'</span>, <span class="hljs-string">'Leonard'</span>);
</code></pre>
<p>In these instances, we interact with the elements first (by clicking a button or entering text into an input box), and then we use the resultant states of the elements' states as determined by using <code>.should()</code>.</p>
<p>When constructing relevant assertions to confirm the behavior and state of items in your web application during end-to-end testing, Cypress's <code>.should()</code> command is a potent tool.</p>
<h3 id="heading-cypress-actions">Cypress Actions</h3>
<p>Cypress commands that interact with your program like a user would are called actions. They do not interact with the page until components or elements are actionable. There are numerous examples, but for now I'll use the <code>.click()</code> command.</p>
<p>To mimic a click on a DOM element in Cypress, use the <code>.click()</code> command. It's among the most typical and basic things you'll do in your end-to-end tests.</p>
<p>Let's look at an example of some code to demonstrate how to use <code>.click()</code>:</p>
<h4 id="heading-basic-click-usage">Basic <code>.Click()</code> Usage</h4>
<p>The following is the syntax of <code>.click()</code>:</p>
<pre><code class="lang-javascript">cy.get(<span class="hljs-string">'selector'</span>).click();
</code></pre>
<p>To choose the DOM element you want to click, use <code>cy.get('selector')</code>. <code>.click()</code> replicates a click event on the element that is chosen.</p>
<h4 id="heading-managing-clicks-during-user-interaction">Managing Clicks During User Interaction</h4>
<p>Sometimes, you may need to interact with things before clicking. For instance, you may want to complete a form field and press the submit button afterward. You can use <code>.type()</code> to communicate with input fields before continuing on to the submit button, <code>.click()</code>:</p>
<pre><code class="lang-javascript">cy.get(‘[data-testid=”username”]’).type(<span class="hljs-string">'okosaleo'</span>);
cy.get(‘[data-testid=”password”]’).type(<span class="hljs-string">'password'</span>);
cy.get(‘[data-testid=”Leo-button”]’).click();
</code></pre>
<p>First, in this case we employ <code>.type()</code> to input values in the password and username fields, and then click <code>.click()</code> to click the login button and submit the form.</p>
<h4 id="heading-managing-dynamic-elements">Managing Dynamic Elements</h4>
<p>You can utilize <code>.click()</code> while working with dynamic elements, or elements that emerge following an action. In order to make sure the element is there and prepared for interaction, you can use <code>.click()</code> in conjunction with other commands.</p>
<p>For instance, clicking a dynamic element. Assume you have a list of items and that you wish to click on a certain item that pops up following a certain amount of user interaction:</p>
<pre><code class="lang-javascript">cy.get(‘[data-testid=”Leo-button”]’).click();
cy.get(<span class="hljs-string">'.dynamic-item'</span>).should(<span class="hljs-string">'have.length.gt'</span>, <span class="hljs-number">5</span>);
cy.get(<span class="hljs-string">'.dynamic-item'</span>).eq(<span class="hljs-number">4</span>).click();
</code></pre>
<p>In this example, to load new things dynamically, we first click the <code>"Leo-button"</code> button. After making sure that at least six things are shown using <code>.should('have.length.gt', 5)</code>, we click the fifth item using <code>.eq(4)</code>.</p>
<h3 id="heading-other-commands">Other commands</h3>
<p>Cypress has many other commands which we haven't discussed here but that you can use to write other tests. You can check them out in the <a target="_blank" href="https://docs.cypress.io/api/table-of-contents">Cypress docs here</a>.</p>
<h2 id="heading-how-to-organize-and-run-your-cypress-tests">How to Organize and Run Your Cypress Tests</h2>
<p>Your application may accumulate a number of tests over time. Cypress offers several methods for setting them up and managing them effectively.</p>
<h3 id="heading-plugins">Plugins</h3>
<p>To assist with tasks such as creating code coverage reports and simulating APIs, Cypress offers a number of extensions and plugins.</p>
<p>Plugins are specially designed JavaScript modules that let you modify and add new features to the Cypress testing framework. With the use of plugins, you can increase Cypress's capabilities and customize it to suit your unique requirements.</p>
<p>Cypress plugins include:</p>
<ol>
<li><p>Integrations: Cypress may be integrated with other programs, services, and systems by the creation of plugins. Examples of these include deployment pipelines, version control systems, and platforms for continuous integration (CI).</p>
</li>
<li><p>Custom Commands: To encapsulate and reuse routine test procedures or user interactions with your application, you may define custom commands using plugins. This improves the organization and maintainability of your test code.</p>
</li>
</ol>
<p>There are many more plugin features that Cypress offers. Plugins are a flexible way to customize your testing framework to the specific needs of your project, increase the power of your testing, and organize and maintain your test code better.</p>
<h3 id="heading-describe-blocks">Describe Blocks</h3>
<p>The Mocha testing framework, which is integrated with Cypress to help you organize and structure your test suites, includes describe blocks. These describe blocks provide your tests a clear structure and help you group related test cases.</p>
<p>You can use describe blocks to categorize and explain the functionality and behavior of the program you are evaluating.</p>
<h4 id="heading-purpose-of-describe-blocks-in-cypress">Purpose of Describe Blocks in Cypress</h4>
<ul>
<li><p>Organize Test Cases: You can organize relevant test cases together by using the describe blocks. A description block can be made for a particular application feature, part, or functionality.</p>
</li>
<li><p>Enhance Test framework: They give your tests a hierarchical framework that makes the test suite easier to explore and comprehend. Developers and testers can find certain tests more quickly with the aid of this structure.</p>
</li>
<li><p>Clarity and Documentation: You can give titles for your tests that are both human-readable and descriptive by using describe blocks. This functions as a type of test documentation.</p>
</li>
</ul>
<p>A <code>describe</code> block is structured like this:</p>
<pre><code class="lang-javascript">describe(<span class="hljs-string">'Description of the Test Suite or Feature'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{
  <span class="hljs-comment">// Your test cases (it blocks) go here</span>
});
</code></pre>
<ul>
<li><p><code>"Description of the Test Suite or Feature"</code>: This is a string that contains a description of the test suite or feature. It acts as the group of test cases title.</p>
</li>
<li><p><code>function () { /*... */ }</code>: This function holds the various test cases that are related to this <code>describe</code> block and are written within <code>it</code> blocks.</p>
</li>
</ul>
<h4 id="heading-how-to-use-describe-blocks-custom-commands">How to Use Describe Blocks Custom Commands</h4>
<p>Let's say you are evaluating a web application's login functionality. The following is how you could structure your tests using describe blocks:</p>
<pre><code class="lang-javascript">describe(<span class="hljs-string">'Login Feature'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{
  <span class="hljs-comment">// This is the outermost describe block for the Login Feature</span>

  it(<span class="hljs-string">'should display the login form'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{
    <span class="hljs-comment">// Test case logic to check if the login form is displayed</span>
  });

  it(<span class="hljs-string">'should show an error message on invalid login'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{
    <span class="hljs-comment">// Test case logic to check error message display</span>
  });

  it(<span class="hljs-string">'should log in successfully with valid credentials'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{
    <span class="hljs-comment">// Test case logic to check successful login</span>
  });

  describe(<span class="hljs-string">'Password Reset'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{
    <span class="hljs-comment">// Nested describe block for Password Reset functionality</span>

    it(<span class="hljs-string">'should allow users to request a password reset'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{
      <span class="hljs-comment">// Test case logic for password reset request</span>
    });

    it(<span class="hljs-string">'should reset the password with a valid reset token'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{
      <span class="hljs-comment">// Test case logic for password reset with a valid token</span>
    });
  });
});
</code></pre>
<p>In this instance:</p>
<ol>
<li><p>All of the test cases for the login feature are grouped together in the outermost describe block.</p>
</li>
<li><p>Tests pertaining to the password reset feature are grouped together in a describe block nestled within it.</p>
</li>
</ol>
<p>You can easily identify related tests thanks to this hierarchical structure, which also aids in clarifying the goals of each set of test cases.</p>
<p>Effective use of <code>describe</code> blocks in Cypress allows you to write well-structured and easily accessible test suites, which will facilitate test management and maintenance as your project expands.</p>
<h3 id="heading-custom-commands">Custom Commands</h3>
<p>To simplify repetitive tasks and improve the readability of your tests, you can create custom Cypress commands.</p>
<p>To encapsulate and reuse common test processes or interactions with the application being tested, you may develop and add custom commands—user-defined JavaScript functions—to your Cypress test suite. These can help augment the built-in Cypress commands and improve the readability, organization, and maintainability of your test code.</p>
<p>You need to define your custom command in one of your test files, usually the <code>commands.js</code> file. Often, you may find this file in the <code>cypress/support</code> directory.</p>
<p>On the other hand, you can arrange your customized commands in different files or folders according to the features of your program.</p>
<p>Here's an example:</p>
<pre><code class="lang-javascript">Cypress.Commands.add(<span class="hljs-string">'customCommandName'</span>, <span class="hljs-function">(<span class="hljs-params">arg0, arg1, ...</span>) =&gt;</span> {
  <span class="hljs-comment">// Define the custom command logic here</span>
});
</code></pre>
<ul>
<li><p><code>customCommandName</code>: This is the name that you'll use in your test scripts to identify your custom command.</p>
</li>
<li><p><code>(arg0, arg1,...)</code>: These are the parameters or arguments that you can give to the custom command in order to alter how the program behaves.</p>
</li>
<li><p><code>// Custom command logic }</code>: Here you provide the precise operations you wish to be carried out by your custom command.</p>
</li>
</ul>
<h4 id="heading-how-to-use-custom-commands">How to Use Custom Commands</h4>
<p>Once your custom command is defined, you can use it in your test scripts in the same way as any other Cypress command that is built-in.</p>
<p>Using the following syntax, you can invoke a custom command:</p>
<pre><code class="lang-javascript">cy.customCommandName(arg0, arg1, ...);
</code></pre>
<h4 id="heading-advantages-of-custom-commands">Advantages of Custom Commands</h4>
<p>Cypress custom commands have a number of advantages:</p>
<ol>
<li><p>Reusability: You can encapsulate intricate or commonly used interactions with your application using custom commands. This lessens redundancy in your test scripts and encourages the reuse of code.</p>
</li>
<li><p>Readability: Your test scripts become more accessible and understandable when typical tasks are abstracted into custom commands. Your test code will be more self-explanatory with custom commands.</p>
</li>
<li><p>Maintenance: Rather than having to look for and update each instance of an action in several test scripts, you just need to change the custom command once when you need to update a common action or interaction.</p>
</li>
<li><p>Consistency: Using custom commands guarantees that your test suite's common interactions are carried out in a consistent manner. This keeps the testing process consistent.</p>
</li>
</ol>
<p>This is a basic illustration of a custom command that allows a user to log in by filling out a login form with their username and password:</p>
<pre><code class="lang-javascript">Cypress.Commands.add(<span class="hljs-string">'login'</span>, <span class="hljs-function">(<span class="hljs-params">username, password</span>) =&gt;</span> {
  cy.get(‘[username-input”]’).type(username);
  cy.get(‘[data-testid=”password-input”]’).type(password);
  cy.get(‘[data-testid=”Leo-button”]’).click();
});
</code></pre>
<h3 id="heading-cypress-dashboard">Cypress Dashboard</h3>
<p>This tool lets you monitor films of text executors, organize test runs, and discuss outcomes with your team. You can find the Cypress dashboard in the test runner window.</p>
<p>To see the history of your test runs, click the "Runs" tab. The Runs tab will include a "View Dashboard" link at the top. When you click the "View Dashboard" link, your web browser will launch the Cypress Dashboard.</p>
<p>Cypress offers the dashboard as a web-based service. The goal of the Cypress Dashboard is to improve and streamline the web application testing and test management process. It provides a single platform to monitor, analyze, and manage your test runs using Cypress.</p>
<p>The Cypress Dashboard's main attributes and capabilities are as follows:</p>
<ol>
<li><p>Real-Time Test Execution: You can watch the test execution process in real time when you use the Cypress Dashboard service to execute Cypress tests. It offers a real-time view of your testing, including with videos and live browser screenshots. This tool is useful for tracking test progress and troubleshooting problems.</p>
</li>
<li><p>Collaboration and Sharing: The development and QA teams can work together thanks to the dashboard. Test results may be accessed and reviewed by developers, testers, and other stakeholders with ease when test runs are shared with team members.</p>
</li>
<li><p>Centralized Test Management: You can store and manage your Cypress test results centrally using the Cypress Dashboard. Test runs can be accessed and arranged from a single location.</p>
</li>
<li><p>The Cypress Dashboard facilitates the concurrent running of tests across many computers and web browsers. This can speed up the test execution process considerably and provide you the results you need more quickly.</p>
</li>
<li><p>Test Insights and Analytics: By tracking test results over time, you can learn more about your test runs. Comprehensive analytics, including execution times, pass/fail statuses, and more, are available in the Cypress Dashboard. You can use this data to find trends and patterns in your test results.</p>
</li>
<li><p>Test Automation and Scheduling: You can automate the testing process by scheduling tests to run at predetermined times or intervals. Running regression tests and maintaining ongoing test coverage can both benefit from this.</p>
</li>
</ol>
<p>These are some of the functions and attributes the Cypress dashboard offers.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/11/dashboard-analytics-overview.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Here's an example of what the cypress dashboard looks like</em></p>
<h2 id="heading-how-to-debug-your-code-with-cypress">How to Debug Your Code With Cypress</h2>
<p>It's simple to debug your tests with Cypress. To halt test execution and view an application's status in the browser, add <code>cy.debug()</code>. Let's look at an example of how to use <code>cy.debug</code> in Cypress:</p>
<pre><code class="lang-javascript">describe(<span class="hljs-string">'Cypress Debug Example'</span>, <span class="hljs-function">() =&gt;</span> {
  it(<span class="hljs-string">'performs a login and checks the user profile'</span>, <span class="hljs-function">() =&gt;</span> {
    cy.visit(<span class="hljs-string">'/login'</span>);
    cy.get(<span class="hljs-string">'#username-input'</span>).type(<span class="hljs-string">'testuser'</span>);

    <span class="hljs-comment">// Pause the test execution to inspect the application state</span>
    cy.pause();

    cy.get(<span class="hljs-string">'#password-input'</span>).type(<span class="hljs-string">'password123'</span>);
    cy.get(<span class="hljs-string">'#login-button'</span>).click();

    <span class="hljs-comment">// Continue with assertions</span>
    cy.url().should(<span class="hljs-string">'include'</span>, <span class="hljs-string">'/profile'</span>);
    cy.get(<span class="hljs-string">'.user-info'</span>).should(<span class="hljs-string">'contain'</span>, <span class="hljs-string">'Welcome, testuser'</span>);
  });
});
</code></pre>
<p>In this example, the test will halt when it reaches the <code>cy.pause()</code> command, and the Cypress Test Runner will prompt you to view the DevTools console.</p>
<p>After that, you may interact with the program, examine the DOM, verify variables, and execute more Cypress commands interactively for debugging reasons via the console.</p>
<h4 id="heading-time-travel-debugging">Time Travel Debugging</h4>
<p>Cypress also has a powerful capability known as "Time Travel Debugging." This feature allows you to see the current state of your application at any time while it is being tested. This greatly simplifies the diagnosis process.</p>
<p>Using this feature, you can record and replay test execution stages to troubleshoot your Cypress tests. By giving you a visual depiction of the test execution process step-by-step, it assists you in identifying and resolving problems with your tests and application. Using Test Driven Development (TTD), you may see your application's state interactively at various stages of the test run.</p>
<p>This is how Cypress's Time Travel Debugging works:</p>
<p>You must first record a test run in order to use TTD. You may do this using the Cypress Dashboard service or by running your tests locally with the <code>--record</code> parameter.</p>
<p>This is an example of how to conduct testing while recording:</p>
<pre><code class="lang-bash">npx cypress run --record
</code></pre>
<p>The test is launched in the Electron browser by default.</p>
<p>Then you can use the Cypress Dashboard web interface once the test run is finished and the results are submitted to the Cypress Dashboard.</p>
<p>Next, find the test run you wish to debug in the Cypress Dashboard and click on it. This will direct you to the page with test specifics.</p>
<p>You may see a timeline representation of your application's state at each Cypress command execution on the test details page.</p>
<p>To see the state of the application at a certain moment in time, click on a snapshot on the timeline. You may browse console logs, work with the DOM, and even run Cypress commands in the context of that snapshot.</p>
<p>To examine the condition of the application at various test phases, you can either go to particular points in the timeline or walk through each command in the timeline one at a time.</p>
<p>This is an illustration of how to apply TTD in a Cypress test:</p>
<pre><code class="lang-javascript">describe(<span class="hljs-string">'Time Travel Debugging Example'</span>, <span class="hljs-function">() =&gt;</span> {
  it(<span class="hljs-string">'performs a login and checks the user profile'</span>, <span class="hljs-function">() =&gt;</span> {
    cy.visit(<span class="hljs-string">'/login'</span>);
    cy.get(‘[username-input”]’).type(<span class="hljs-string">'testuser'</span>);
    cy.get(‘[password-input”]’).type(<span class="hljs-string">'password'</span>);
    cy.get(‘[login-input”]’).click();

    <span class="hljs-comment">// At this point, we may want to perform TTD to inspect the application's state</span>
    <span class="hljs-comment">// and ensure the user is returned to the profile page.</span>

    cy.url().should(<span class="hljs-string">'include'</span>, <span class="hljs-string">'/profile'</span>);
    cy.get(<span class="hljs-string">'.user-info'</span>).should(<span class="hljs-string">'contain'</span>, <span class="hljs-string">'Welcome, testuser'</span>);
  });
});
</code></pre>
<p>In this scenario, you may run into a problem that you wish to diagnose after entering your login information and hitting the login button.</p>
<p>To make sure the user is on the profile page and that their name is shown appropriately, you may use TTD to halt at the <code>cy.url()</code> assertion and verify the status of the application.</p>
<p>With TTD, you can examine the status of the application at different times to interactively debug and troubleshoot your Cypress tests, which will help you find and address problems more efficiently.</p>
<h2 id="heading-continuous-integration">Continuous Integration</h2>
<p>Cypress tests can be integrated into your continuous integration (CI) workflow using solutions like as Travis CI, GitHub actions, Jenkins, or CircleCI. Let's talk about continuous integration using Github actions:</p>
<h3 id="heading-cypress-continuous-integration-using-github-actions">Cypress Continuous Integration Using GitHub Actions</h3>
<p>You can automate the testing of your web apps with Cypress as part of your development workflow with Continuous Integration (CI) using GitHub Actions.</p>
<p>You can create workflows using GitHub Actions that automate a variety of processes, such as Cypress test runs, whenever changes are made to your source. Let's walk through how to get it set up.</p>
<p><strong>Prerequisites:</strong></p>
<ol>
<li><p>GitHub Repository: The Cypress tests and application code should be located in a GitHub repository.</p>
</li>
<li><p>Cypress Setup: Verify that Cypress is installed in your project and that your Cypress test configurations are accurate. Cypress Open may be used to set up and execute your tests locally.</p>
</li>
</ol>
<h4 id="heading-step-1-establish-a-workflow-configuration">Step 1: Establish a Workflow Configuration:</h4>
<p>Create a file in your GitHub repository called workflow configuration. The CI workflow is defined in this file, which is usually named <code>.github/workflows/cypress.yml</code>. It also provides instructions on when and how to execute Cypress tests.</p>
<p>This is an example of a simple configuration file:</p>
<pre><code class="lang-javascript">name: Cypress Tests

<span class="hljs-attr">on</span>:
  push:
    branches:
      - main # Align to your repository<span class="hljs-string">'s default branch

jobs:
  cypress:
    runs-on: ubuntu-latest

    steps:
    - name: Checkout code
      uses: actions/checkout@v2

    - name: Install dependencies
      run: npm install

    - name: Run Cypress tests
      run: npm run cypress:run</span>
</code></pre>
<p>Every time a push is made to the <code>main</code> branch, a process to execute Cypress tests is established by this configuration file. This may be altered to meet your needs.</p>
<h4 id="heading-step-2-describe-the-npm-scripts">Step 2: Describe the <code>npm</code> Scripts:</h4>
<p>Define <code>npm</code> scripts in your <code>package.json</code> file so that Cypress tests may be executed. For instance:</p>
<pre><code class="lang-javascript"><span class="hljs-string">"scripts"</span>: {
  <span class="hljs-string">"cypress:run"</span>: <span class="hljs-string">"cypress run"</span>,
  <span class="hljs-string">"cypress:open"</span>: <span class="hljs-string">"cypress open"</span>
}
</code></pre>
<p>While <code>cypress:open</code> is used to run tests interactively during development, <code>cypress:run</code> is used to execute Cypress tests in headless mode.</p>
<h4 id="heading-step-3-add-to-github-repo">Step 3: Add to GitHub Repo</h4>
<p>Add your application code and the GitHub Actions configuration file (cypress.yml) to your GitHub repository. Send the modifications to GitHub.</p>
<h4 id="heading-step-4-switch-on-github-actions">Step 4: Switch on GitHub Actions:</h4>
<p>If you haven't already, go to your GitHub repository, choose the "Actions" tab, and activate GitHub Actions for your repository.</p>
<h4 id="heading-step-5-manage-your-process">Step 5: Manage Your Process:</h4>
<p>GitHub Actions will launch the specified process, which includes your Cypress tests, automatically each time you post changes to your repository.</p>
<h4 id="heading-step-6-examine-the-results">Step 6: Examine the Results:</h4>
<p>The "Actions" page on your GitHub repository is where you can view the status and outcomes of your Cypress tests. Test results and logs will be displayed to you, allowing you to diagnose and look for any issues.</p>
<h3 id="heading-headless-option">Headless Option</h3>
<p>Cypress offers a headless option for continuous integration (CI) testing. Without the Cypress test runner, you can still run Cypress headlessly. By using the command <code>npx cypress run</code> this simply means there is no graphical user interface involved so the test runner isn't being deployed, here we mostly write scripts to use Cypress.</p>
<p>Web browsers that function without a graphical user interface, or headless browsers, are appropriate for automated testing in server contexts such as continuous integration/continuous delivery systems.</p>
<p>When you run Cypress tests in headless mode, no visible browser window is displayed during test execution. This is very helpful when testing without a user interface in an automated continuous integration and delivery pipeline.</p>
<p>To use this put the command <code>npx cypress run</code> in your terminal.</p>
<ol>
<li><p>Cypress will launch your test in an electron browser when you execute this command.</p>
</li>
<li><p>Upon completion, Cypress will automatically provide a video clip of the test run and screenshots in the event that a test fails, facilitating easy debugging.</p>
</li>
<li><p>The user can adjust screenshots and videos. The folder labeled "screenshots and videos" contains both screenshots and videos cypress produces.</p>
</li>
</ol>
<p>Another way of running tests is through adding scripts to your <code>package.json</code> file. You can add scripts which consist of the <code>key</code> and <code>value</code> pair that work as objects. with <code>key</code> being the name of the command and <code>value</code> being the command that's being run.</p>
<p>Let's run a test headlessly using a key value pair:</p>
<pre><code class="lang-javascript"><span class="hljs-string">"script"</span>: {
    <span class="hljs-string">"cypress:run"</span>: <span class="hljs-string">"cypress run"</span>,
    <span class="hljs-string">"cypress:open"</span>: <span class="hljs-string">"cypress open"</span>
},
</code></pre>
<p>In this code <code>"cypress:run"</code> and <code>"cypress:open"</code> are the <code>keys</code> and <code>"cypress open"</code> and <code>"cypress open"</code> are the commands. To run the command we need the <code>npm run</code> followed by the key used example: <code>npm cypress:run</code>.</p>
<p>Hopefully you now understand how to run tests headlessly in Cypress.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>Cypress is an effective tool you can use to test your web apps. You can use it to write end-to-end tests that make sure your React projects function as intended and identify any issues.</p>
<p>Cypress is a useful addition to your testing toolkit because of its interactive Test Runner, easy-to-use API, and robust debugging features. Now go ahead and use Cypress to test your React applications to make sure the user experience is seamless and error-free.</p>
<p>If you want to learn about Cypress in more detail, you can check out their documentation at <a target="_blank" href="https://www.freecodecamp.org/news/p/ee697448-b73d-43dd-85de-d31f1e1005c6/CYPRESS.IO">cypress.io</a>. Cheers to your testing!</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Test User Interactions Using the React Testing Library ]]>
                </title>
                <description>
                    <![CDATA[ When you're testing different components in React, you’ll need to simulate user interactions with various parts of each component. In this tutorial, I am going to show you some methods to simulate user interactions with different interactive elements... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-test-user-interactions-in-react/</link>
                <guid isPermaLink="false">66d8515139c4dccc43d4d4bf</guid>
                
                    <category>
                        <![CDATA[ React ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Software Testing ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Testing ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Kunal Nalawade ]]>
                </dc:creator>
                <pubDate>Mon, 20 Feb 2023 19:12:24 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2023/02/0_cba5BsaMWpgBXzGK.jpeg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>When you're testing different components in React, you’ll need to simulate user interactions with various parts of each component.</p>
<p>In this tutorial, I am going to show you some methods to simulate user interactions with different interactive elements.</p>
<p>Before getting started, make sure you know how to structure a test in React and how to write simple tests. You can brush up on that knowledge by reading my <a target="_blank" href="https://www.freecodecamp.org/news/how-to-write-unit-tests-in-react/">previous post</a> about how to write unit tests in React.</p>
<p>I also have a challenge for you, so make sure you read the complete article.</p>
<h2 id="heading-how-to-set-up-the-project">How to Set Up the Project</h2>
<p>Create your React app using the command <code>create-react-app testing-user-interactions</code>. Next, install the library <code>user-event</code>.</p>
<pre><code class="lang-python">npm i user-event
</code></pre>
<p>I am assuming you know how to use this library. If not, I explained how it works in my previous <a target="_blank" href="https://www.freecodecamp.org/news/how-to-write-unit-tests-in-react/">tutorial</a>.</p>
<p>Basically, this library has a few functions you can use to simulate a user. We’ll go through all these functions with examples.</p>
<p>Before writing your tests, you'll need to make the following imports at the start of your test suite (the file in which you write all your tests).</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> {render, screen} <span class="hljs-keyword">from</span> <span class="hljs-string">'@testing-library/react'</span>
<span class="hljs-keyword">import</span> userEvent <span class="hljs-keyword">from</span> <span class="hljs-string">'@testing-library/user-event'</span>
</code></pre>
<p>You'll also need to import the component you’ll be testing.</p>
<p>For every test, we'll be simulating user interactions and test how our component behaves.</p>
<h2 id="heading-how-to-test-select-element-interactions">How to Test <code>select</code> Element Interactions</h2>
<p>In your application, you may have <code>select</code> elements that allow a user to select something from a list of options. Let’s take an example:</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">select</span> <span class="hljs-attr">id</span>=<span class="hljs-string">'selectCity'</span>&gt;</span>    
    <span class="hljs-tag">&lt;<span class="hljs-name">option</span>&gt;</span> Mumbai<span class="hljs-tag">&lt;/<span class="hljs-name">option</span>&gt;</span>    
    <span class="hljs-tag">&lt;<span class="hljs-name">option</span>&gt;</span> Bangalore<span class="hljs-tag">&lt;/<span class="hljs-name">option</span>&gt;</span>    
    <span class="hljs-tag">&lt;<span class="hljs-name">option</span>&gt;</span> Chennai<span class="hljs-tag">&lt;/<span class="hljs-name">option</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">select</span>&gt;</span>
</code></pre>
<p>Normally, when a user sees a <code>select</code> element, they would click it and select an option they want. We are going to simulate the exact same behaviour and test if our component reacts accordingly. For instance, if a user selects <code>Chennai</code>, the value shown must be the same.</p>
<p>First, let’s see how to query the element. Let's use <code>getByRole</code> to query the element. You can use the role <code>combobox</code> for the above element.</p>
<pre><code class="lang-javascript">screen.getByRole(<span class="hljs-string">'combobox'</span>)
</code></pre>
<p>What is a role? How do you know which role to use for an element? In React, for testing purposes, there's an attribute called <code>role</code> defined for every HTML element. This makes it easier for you to query an element while testing.</p>
<p>Now, in order to know the value of the role attribute for each element, you can refer to the list of roles <a target="_blank" href="https://www.w3.org/TR/html-aria/#docconformance">here</a>.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/02/Screenshot-2023-02-18-at-12.37.44-PM.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>A Snapshot of the List of Roles</em></p>
<p>If you want to query an anchor element containing an <code>href</code> attribute, you can use the role <code>link</code>. Same is true for other elements in the list.</p>
<p>However, do not define an explicit role attribute for your HTML element, as it's already defined for you.</p>
<p>Let's see another method of querying the element. If there are is more than one <code>select</code> element, you can use <code>getByLabelText()</code>. For this, add a label, <code>&lt;label htmlFor=”selectCity”&gt;Select City&lt;/label&gt;</code> for the element and do <code>screen.getByLabelText(/select city/i)</code>. You’ll get the element.</p>
<p>Now, use the <code>[selectOptions()](https://testing-library.com/docs/ecosystem-user-event/#selectoptionselement-values-options)</code> method of the library to simulate a user selecting an option. It takes three arguments: the element, the value, and any options.</p>
<pre><code class="lang-javascript">userEvent.selectOptions(    
    screen.getByRole(<span class="hljs-string">'combobox'</span>),    
    <span class="hljs-string">'Chennai'</span>
)
</code></pre>
<p>Then, add an assertion at the end of your test to check if the element has the same value that the user selected.</p>
<pre><code class="lang-javascript">expect(screen.getByRole(<span class="hljs-string">'combobox'</span>)).toHaveValue(<span class="hljs-string">'Chennai'</span>)
</code></pre>
<p>The user selected <code>Chennai</code> and our <code>select</code> element has the same value, so the test passes.</p>
<h2 id="heading-how-to-test-state-change">How to Test State Change</h2>
<p>Now, I’ll make a state update on changing the <code>select</code> element’s value. First, I’ll have a state called <code>cityName</code> to display the option selected.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> [cityName, setCityName] = useState(<span class="hljs-string">'Mumbai'</span>);
</code></pre>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">h2</span>&gt;</span> City Name:  {cityName} <span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span>
</code></pre>
<p>Then, I’ll add an <code>onChange</code> attribute with a method that updates the state.</p>
<pre><code class="lang-javascript">onChange={<span class="hljs-function">(<span class="hljs-params">e</span>) =&gt;</span> { setCityName(e.target.value)}}
</code></pre>
<p>To write the test for this, follow the same process:</p>
<pre><code class="lang-javascript">test(<span class="hljs-string">"City Name header rendering"</span>, <span class="hljs-function">() =&gt;</span> {    
    render(<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">SelectElement</span>/&gt;</span></span>)    
    userEvent.selectOptions(        
        screen.getByRole(<span class="hljs-string">'combobox'</span>),        
        <span class="hljs-string">'Bangalore'</span>    )    
    expect(screen.getByRole(<span class="hljs-string">'heading'</span>,               
                     { <span class="hljs-attr">name</span>: <span class="hljs-regexp">/bangalore/i</span>})).toBeInTheDocument();
})
</code></pre>
<p>To query the <code>h2</code> element, use <code>[getByRole()](https://testing-library.com/docs/queries/byrole/)</code> with the <code>name</code> option. The <code>name</code> option adds another filter to the query – in case there are multiple <code>h2</code> elements.</p>
<h2 id="heading-how-to-test-a-hover-event">How to Test a Hover Event</h2>
<p>Your application may have functionalities where a user can hover over an element to see some information as a tooltip. So, to learn how to test this, let’s implement a basic tooltip functionality.</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"tooltip"</span>&gt;</span>    
    <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span> Hover over me<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>    
    <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"tooltiptext"</span>&gt;</span>Tooltip text<span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
</code></pre>
<p>There’s also some CSS styles for the classes defined above, but I won’t show them here. Basically, when a user hovers over the text <em>Hover over me,</em> the tooltip text is visible.</p>
<p>To simulate a user hovering over the text element, use the <code>hover()</code> method. Add an assertion at the end to test if the tooltip is visible.</p>
<pre><code class="lang-javascript">test(<span class="hljs-string">"Tooltip visible"</span>, <span class="hljs-function">() =&gt;</span> {    
    render(<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">HoverEvent</span>/&gt;</span></span>)
    userEvent.hover(screen.getByText(<span class="hljs-regexp">/hover over me/i</span>))          
    expect(screen.getByText(<span class="hljs-regexp">/tooltip text/i</span>)).toBeInTheDocument()
})
</code></pre>
<p>The test will pass if the tooltip is visible on hover. If it doesn't, you'll need to refactor your code.</p>
<h2 id="heading-how-to-test-a-file-upload-event">How to Test a File Upload Event</h2>
<p>Another important event is a user uploading files to your website. This is a pretty common functionality in any UI application.</p>
<p>Let’s have an <code>input</code> of type <code>file</code>.</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">label</span> <span class="hljs-attr">htmlFor</span>=<span class="hljs-string">"singleFile"</span>&gt;</span>Upload File<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">type</span>=<span class="hljs-string">'file'</span> <span class="hljs-attr">id</span>=<span class="hljs-string">'singleFile'</span> /&gt;</span>
</code></pre>
<p>In the test, you’ll need to simulate the user uploading a file. Use the <code>upload()</code> method to do that:</p>
<pre><code class="lang-javascript">test(<span class="hljs-string">"Test single file upload"</span>, <span class="hljs-function">() =&gt;</span> {    
    render(<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">FileUpload</span>/&gt;</span></span>)    
    <span class="hljs-keyword">const</span> file = <span class="hljs-keyword">new</span> File([<span class="hljs-string">'hello'</span>], <span class="hljs-string">'hello.png'</span>, {<span class="hljs-attr">type</span>: <span class="hljs-string">'image/png'</span>})   
    userEvent.upload(screen.getByLabelText(<span class="hljs-regexp">/upload file/i</span>), file)  
    expect(screen.getByLabelText(<span class="hljs-regexp">/upload file/i</span>).files[<span class="hljs-number">0</span>]).toEqual(file)
})
</code></pre>
<p>First, create a mock file and upload the same. Then, make an assertion that the file present in the input matches our uploaded file. It does, so the test passes.</p>
<p>Now, let’s take an example of multiple file uploads.</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">label</span> <span class="hljs-attr">htmlFor</span>=<span class="hljs-string">'multipleFiles'</span>&gt;</span>Upload multiple files<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">type</span>=<span class="hljs-string">'file'</span> <span class="hljs-attr">id</span>=<span class="hljs-string">'multipleFiles'</span> <span class="hljs-attr">multiple</span> /&gt;</span>
</code></pre>
<p>In our test, upload multiple files.</p>
<pre><code class="lang-javascript">test(<span class="hljs-string">"Test multiple file uploads"</span>, <span class="hljs-function">() =&gt;</span> {    
    render(<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">FileUpload</span>/&gt;</span></span>)    
    <span class="hljs-keyword">const</span> files = [        
           <span class="hljs-keyword">new</span> File([<span class="hljs-string">'file1'</span>], <span class="hljs-string">'file1.png'</span>, {<span class="hljs-attr">type</span>: <span class="hljs-string">'image/png'</span>}),       
           <span class="hljs-keyword">new</span> File([<span class="hljs-string">'file2'</span>], <span class="hljs-string">'file2.png'</span>, {<span class="hljs-attr">type</span>: <span class="hljs-string">'application/pdf'</span>})   
    ]    
    userEvent.upload(screen.getByLabelText(<span class="hljs-regexp">/upload multiple files/i</span>), 
                        files)    
    <span class="hljs-keyword">const</span> fileInput = screen.getByLabelText(<span class="hljs-regexp">/upload multiple files/i</span>)  

    expect(fileInput.files.length).toBe(<span class="hljs-number">2</span>);   
    expect(fileInput.files[<span class="hljs-number">0</span>]).toEqual(files[<span class="hljs-number">0</span>]);   
    expect(fileInput.files[<span class="hljs-number">1</span>]).toEqual(files[<span class="hljs-number">1</span>]);
})
</code></pre>
<p>In the assertions, check the number of files and whether both the files match the uploaded ones. Thus, all our tests pass with 100% coverage.</p>
<p>Now, time for the challenge. Go through my posts on <a target="_blank" href="https://medium.com/gitconnected/how-to-implement-multiple-file-uploads-in-react-4cdcaadd0f6e">Muliple File Uploads</a> and <a target="_blank" href="https://medium.com/gitconnected/4-different-examples-of-the-usestate-hook-in-react-5504ce011a20">Different Examples of the useState Hook</a> and write unit tests for all the functionalities. Upload your code on GitHub and share it with me.</p>
<h2 id="heading-how-to-test-form-behaviour">How to Test Form Behaviour</h2>
<p>An important feature of most web apps is form handling. When writing tests for a React app, it’s highly likely you will need to test your component’s behaviour with forms.</p>
<p>In our example, let’s have a form with two <code>input</code> fields, one <code>select</code> field and a submit button.</p>
<p>First, let’s define the states for the respective fields and an additional state for indicating whether the form is submitted.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> [name, setName] = useState(<span class="hljs-string">''</span>)
<span class="hljs-keyword">const</span> [password, setPassword] = useState(<span class="hljs-string">''</span>)
<span class="hljs-keyword">const</span> [country, setCountry] = useState(<span class="hljs-string">''</span>)
<span class="hljs-keyword">const</span> [formSubmitted, setFormSubmitted] = useState(<span class="hljs-literal">false</span>)
</code></pre>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">form</span>&gt;</span>    
    <span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">onChange</span>=<span class="hljs-string">{(e)</span> =&gt;</span> {setName(e.target.value)}}             
           placeholder='Enter name'/&gt;    
    <span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">onChange</span>=<span class="hljs-string">{(e)</span> =&gt;</span> {setPassword(e.target.value)}}                          placeholder='Enter password'/&gt;    
    <span class="hljs-tag">&lt;<span class="hljs-name">label</span> <span class="hljs-attr">htmlFor</span>=<span class="hljs-string">'selectCountry'</span>&gt;</span> Select Country <span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span>    
    <span class="hljs-tag">&lt;<span class="hljs-name">select</span> <span class="hljs-attr">id</span>=<span class="hljs-string">'selectCountry'</span>             
            <span class="hljs-attr">onChange</span>=<span class="hljs-string">{(e)</span> =&gt;</span> {setCountry(e.target.value)}}&gt;       
        <span class="hljs-tag">&lt;<span class="hljs-name">option</span>&gt;</span>India<span class="hljs-tag">&lt;/<span class="hljs-name">option</span>&gt;</span>        <span class="hljs-tag">&lt;<span class="hljs-name">option</span>&gt;</span>Japan<span class="hljs-tag">&lt;/<span class="hljs-name">option</span>&gt;</span>       
        <span class="hljs-tag">&lt;<span class="hljs-name">option</span>&gt;</span>China<span class="hljs-tag">&lt;/<span class="hljs-name">option</span>&gt;</span>        <span class="hljs-tag">&lt;<span class="hljs-name">option</span>&gt;</span>USA<span class="hljs-tag">&lt;/<span class="hljs-name">option</span>&gt;</span>       
        <span class="hljs-tag">&lt;<span class="hljs-name">option</span>&gt;</span>England<span class="hljs-tag">&lt;/<span class="hljs-name">option</span>&gt;</span>    
    <span class="hljs-tag">&lt;/<span class="hljs-name">select</span>&gt;</span>    
    <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{handleSubmit}</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>
</code></pre>
<p>In the <code>onChange</code> attribute, make the state updates. In the end, display a text on successful submission of the form.</p>
<pre><code class="lang-html">{formSubmitted &amp;&amp; 'Form Submitted'}
</code></pre>
<p>Also, let’s add some validation in the <code>handleSubmit</code> method. When a validation fails, a list of errors will be shown. Create another state to hold errors.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> [errors, setErrors] = useState([])
</code></pre>
<p>Now, implement the <code>handleSubmit</code> method.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> handleSubmit = <span class="hljs-function">(<span class="hljs-params">event</span>) =&gt;</span> {    
    event.preventDefault();    
    <span class="hljs-keyword">const</span> errorList=[];    
    <span class="hljs-keyword">if</span>(name == <span class="hljs-string">''</span> || password == <span class="hljs-string">''</span> || country == <span class="hljs-string">''</span>) {        
        errorList.push(<span class="hljs-string">'Please fill all the details'</span>)    
    }        
    <span class="hljs-keyword">const</span> regex = <span class="hljs-regexp">/^[a-z]*$/i</span>;    
    <span class="hljs-keyword">if</span>(!name.match(regex)) {        
        errorList.push(<span class="hljs-string">'Please enter a valid name'</span>)    
    }    
    <span class="hljs-keyword">if</span>(errorList.length != <span class="hljs-number">0</span>) {        
        setErrors(errorList);        
        setFormSubmitted(<span class="hljs-literal">false</span>);        
        <span class="hljs-keyword">return</span>;      
    }     
    setErrors([]);    
    setFormSubmitted(<span class="hljs-literal">true</span>)
}
</code></pre>
<p>First, we’ll do <code>event.preventDefault()</code> which cancels out any events that prevent submitting the form. Then, we’ll add few error checks and add any errors to the state <code>errors</code>. In the end, if there are no errors then set <code>errors</code> to an empty array and set <code>formSubmitted</code> as <code>true</code>.</p>
<p>We’ll also display the list of all the errors which will be visible on clicking the submit button.</p>
<pre><code class="lang-javascript">errors.map(<span class="hljs-function"><span class="hljs-params">err</span> =&gt;</span> (    
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>        
        {err}   
    <span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span></span>
))
</code></pre>
<p>Let’s write the tests for this example. There are a few different things you should test. First, write a test simulating a user interacting with the form and submitting it with correct values.</p>
<pre><code class="lang-javascript">test(<span class="hljs-string">"Form getting submitted with correct input values"</span>, <span class="hljs-function">() =&gt;</span> {
    render(<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">FormBehaviour</span>/&gt;</span></span>)

    userEvent.type(screen.getByPlaceholderText(<span class="hljs-regexp">/enter name/i</span>), <span class="hljs-string">'kunal'</span>)
    userEvent.type(screen.getByPlaceholderText(<span class="hljs-regexp">/enter password/i</span>),                                   <span class="hljs-string">'pass'</span>)
    userEvent.selectOptions(screen.getByLabelText(<span class="hljs-regexp">/select country/i</span>),                               <span class="hljs-string">'India'</span>)
    userEvent.click(screen.getByText(<span class="hljs-regexp">/submit/i</span>))

    expect(screen.getByText(<span class="hljs-regexp">/form submitted/i</span>)).toBeInTheDocument();
})
</code></pre>
<p>Use the <code>type</code> and <code>click</code> methods of the <code>userEvent</code> library to simulate the respective actions. In the end, add an assertion to see if the text matching the regex <code>/form submitted/i</code> is visible in the document since our logic displays the text as soon as the form is submitted.</p>
<p><img src="https://miro.medium.com/max/1400/1*Tb0jZPtQRAJwlrlWpEhUiw.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Test Coverage for the Form Behaviour Component</em></p>
<p>Our test passes, but there are still some uncovered lines. We have tested regular form behaviour. However, we also have error handling mechanisms in place. So, you also need to write tests that cover different error scenarios.</p>
<p>First, simulate a user clicking the submit button without entering anything.</p>
<pre><code class="lang-javascript">test(<span class="hljs-string">"Empty fields error shown"</span>, <span class="hljs-function">() =&gt;</span> {    
    render(<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">FormBehaviour</span>/&gt;</span></span>)    
    userEvent.click(screen.getByText(<span class="hljs-regexp">/submit/i</span>))    
    expect(screen.getByText(<span class="hljs-regexp">/please fill all the details/i</span>))                         .toBeInTheDocument()
})
</code></pre>
<p>On clicking the submit button, an error message should be visible prompting the user to fill all the details. Make an assertion for the same.</p>
<p>Not all lines are covered yet. We still have one more error scenario. What if the user enters an invalid name?</p>
<pre><code class="lang-javascript">test(<span class="hljs-string">"Invalid name error shown"</span>, <span class="hljs-function">() =&gt;</span> {    
    render(<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">FormBehaviour</span>/&gt;</span></span>)    
    userEvent.type(screen.getByPlaceholderText(<span class="hljs-regexp">/enter name/i</span>), <span class="hljs-string">'@###'</span>)       userEvent.type(screen.getByPlaceholderText(<span class="hljs-regexp">/enter password/i</span>),                                    <span class="hljs-string">'pass'</span>)    
    userEvent.selectOptions(screen.getByLabelText(<span class="hljs-regexp">/select country/i</span>),                                  <span class="hljs-string">'India'</span>)    
    userEvent.click(screen.getByText(<span class="hljs-regexp">/submit/i</span>))    
    expect(screen.getByText(<span class="hljs-regexp">/Please enter a valid name/i</span>))
          .toBeInTheDocument();
})
</code></pre>
<p>This test is similar to the first test, except here, the user enters an invalid name. So, assert whether the corresponding error is shown.</p>
<p><img src="https://miro.medium.com/max/1400/1*QEBA48iEtB15EmuQrs-DTQ.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>100% Coverage for the Form Behaviour Component</em></p>
<p>Now, all our tests pass with 100% coverage.</p>
<p>You can find the complete code on <a target="_blank" href="https://github.com/KunalN25/testing-user-interactions">GitHub</a>.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>Testing user interactions helps you make sure that users can interact efficiently and effectively with your application. You need to cover all possible scenarios a user may encounter. In this article, I have shown you how you can simulate user interactions with different elements.</p>
<p>I have also demonstrated testing form behaviour covering many scenarios. I hope you now know how to use the <code>userEvent</code> library to test your component’s behaviour with user events.</p>
<p>If you are unable to understand the content or find the explanation unsatisfactory, get in touch with me and let me know. New ideas are always appreciated! Feel free to connect with me on Twitter. Till then, Goodbye!</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Write Unit Tests in React ]]>
                </title>
                <description>
                    <![CDATA[ When you're building a website and coding all the cool features you had planned, you'll want to test if everything works as expected. Now, you can’t do that just by going through the website yourself – you need to check if each unit of your code is w... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-write-unit-tests-in-react/</link>
                <guid isPermaLink="false">66d8515392b237d9f6a7c528</guid>
                
                    <category>
                        <![CDATA[ React ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Software Testing ]]>
                    </category>
                
                    <category>
                        <![CDATA[ unit testing ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Kunal Nalawade ]]>
                </dc:creator>
                <pubDate>Mon, 23 Jan 2023 15:35:25 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2023/01/unit-testing-in-react-image.jpeg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>When you're building a website and coding all the cool features you had planned, you'll want to test if everything works as expected.</p>
<p>Now, you can’t do that just by going through the website yourself – you need to check if each unit of your code is working as you want. For that, you need to write unit tests. And they can be quite a hassle when you actually get down to writing them.</p>
<p>So, in this post, I am going to show you how you can get started with writing unit tests in React. I will explain the process through several examples to help you understand better.</p>
<p>For this post, I assume you have a basic knowledge of React. If not, then head over to the <a target="_blank" href="https://reactjs.org/docs/getting-started.html">docs</a> to get started.</p>
<h2 id="heading-how-is-a-test-structured">How Is a Test Structured?</h2>
<p>Testing involves checking if your code is functioning as it's supposed to by comparing the expected output with the actual output.</p>
<h3 id="heading-what-to-test">What to Test</h3>
<p>In general, your tests should cover the following aspects of your code:</p>
<ol>
<li><p>If a component renders with or without props</p>
</li>
<li><p>How a component renders with state changes</p>
</li>
<li><p>How a component reacts to user interactions</p>
</li>
</ol>
<h3 id="heading-what-not-to-test">What Not to Test</h3>
<p>Testing most of your code is important, but here are some things you do not need to test:</p>
<ol>
<li><p><strong>Actual Implementation:</strong> You do not need to test the actual implementation of a functionality. Just test if the component is behaving correctly.<br> Let’s say you want to sort an array on the click of a button. There’s no need to test the actual sorting logic. You only test if the function was called and if the state changes are rendering correctly.</p>
</li>
<li><p><strong>Third Party libraries:</strong> If you are using any third party libraries like Material UI, no need to test those – they should already be tried and tested.</p>
</li>
</ol>
<p>This might seem a little complicated at the moment, but you should understand better through examples.</p>
<p>Any test in React, no matter how complicated, follows this structure:</p>
<ol>
<li><p>Render the component</p>
</li>
<li><p>Get an element from the component and simulate any user interactions</p>
</li>
<li><p>Write an assertion.</p>
</li>
</ol>
<h2 id="heading-how-to-set-up-our-project">How to Set Up Our Project</h2>
<p>First, create the app with <code>create-react-app</code>. We’ll be using <a target="_blank" href="https://jestjs.io/docs/getting-started">Jest</a> and <a target="_blank" href="https://testing-library.com/docs/react-testing-library/intro/">React Testing Library</a>. Both of them come pre - installed with <code>create-react-app</code>. You can see what it looks like here:</p>
<pre><code class="lang-javascript"><span class="hljs-string">"dependencies"</span>: {
    <span class="hljs-string">"@testing-library/jest-dom"</span>: <span class="hljs-string">"^5.16.5"</span>,
    <span class="hljs-string">"@testing-library/react"</span>: <span class="hljs-string">"^13.4.0"</span>,
    <span class="hljs-string">"react"</span>: <span class="hljs-string">"^18.2.0"</span>,
    <span class="hljs-string">"react-dom"</span>: <span class="hljs-string">"^18.2.0"</span>,
    <span class="hljs-string">"react-scripts"</span>: <span class="hljs-string">"5.0.1"</span>,
    <span class="hljs-string">"web-vitals"</span>: <span class="hljs-string">"^2.1.4"</span>
},
</code></pre>
<p>As you can see, Jest is not visible here. But, if you go to the <code>node_modules</code> folder, you will see Jest there. So, no need to install it separately.</p>
<p>Also, make sure you have the following lines in your <code>setupTests.js</code> file:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> <span class="hljs-string">'@testing-library/jest-dom'</span>;
<span class="hljs-keyword">import</span> <span class="hljs-string">'@testing-library/jest-dom/extend-expect'</span>;
</code></pre>
<p>Also, in your <code>package.json</code> file, modify your scripts like this:</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 --watchAll --coverage"</span>,
    <span class="hljs-string">"eject"</span>: <span class="hljs-string">"react-scripts eject"</span>
},
</code></pre>
<p>This will run your tests in watch mode and also show you the coverage (that is, the portion of the code covered by your tests). You can also define the coverage threshold by adding another property <code>jest</code>. For now, keep the threshold at 80%.</p>
<pre><code class="lang-javascript"><span class="hljs-string">"jest"</span>: {
    <span class="hljs-string">"coverageThreshold"</span>: {
        <span class="hljs-string">"global"</span>: {
            <span class="hljs-string">"lines"</span>: <span class="hljs-number">80</span>
        }
    }
}
</code></pre>
<p>That’s it, now you are ready to start testing. Let’s first start with a basic test.</p>
<h2 id="heading-how-to-write-your-first-test-for-a-react-app">How to Write Your First Test for a React App</h2>
<p>Let’s write a test for the following component:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> FirstTest = <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">h2</span>&gt;</span> First test <span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  )
}
</code></pre>
<p>Here, we just need to test if the <code>h2</code> element renders. Now, where should we write the tests? We can write them inside a <code>__tests__</code> folder anywhere in the <code>src</code> folder. The test file just needs to have a <code>.test.js/jsx</code> extension and the test runner will pick it up.</p>
<p>This is how the test looks in our <code>FirstTest.test.jsx</code> file:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> { render, screen } <span class="hljs-keyword">from</span> <span class="hljs-string">'@testing-library/react'</span>
<span class="hljs-keyword">import</span> FirstTest <span class="hljs-keyword">from</span> <span class="hljs-string">'../components/FirstTest'</span>;

test(<span class="hljs-string">"Example 1 renders successfully"</span>, <span class="hljs-function">() =&gt;</span> {
    render(<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">FirstTest</span>/&gt;</span></span>);

    <span class="hljs-keyword">const</span> element = screen.getByText(<span class="hljs-regexp">/first test/i</span>);

    expect(element).toBeInTheDocument();
})
</code></pre>
<p>First, import the required methods. The <code>test()</code> method contains an individual test. It takes the name of the test and a callback function as the two arguments.</p>
<p>Now, following the structure mentioned above, render the component you're testing using the <a target="_blank" href="https://testing-library.com/docs/react-testing-library/api/#render">render</a> method. Then, use the <code>screen</code> object to make a query for an element. In this case, it’s the <code>h2</code> element. Our query gets an element containing text that matches the regex <code>/first test/i</code> (<em>i</em> means ignore case).</p>
<p>Lastly, make the assertion using the <code>expect</code> method. We expect the element to be in the document and it is, so the test passes.</p>
<p>There are lots of other assertions you can make in your tests. You can read more about them <a target="_blank" href="https://jestjs.io/docs/using-matchers">here</a>. Also, you can find a list of ways to query an element <a target="_blank" href="https://testing-library.com/docs/queries/about">here</a>. We’ll use some of them in our further examples.</p>
<h2 id="heading-how-to-test-with-mock-data-in-react">How to Test With Mock Data in React</h2>
<p>Here, we have a component with a prop <code>data</code> that displays a list of items. Let’s assume this data comes from the backend and your component is displaying this data.</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> TestWithMockData = <span class="hljs-function">(<span class="hljs-params">{data}</span>) =&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">ul</span>&gt;</span>
            {data.map(item =&gt; (
                <span class="hljs-tag">&lt;<span class="hljs-name">li</span> <span class="hljs-attr">key</span>=<span class="hljs-string">{item.id}</span>&gt;</span>
                    {item.id}
                    {item.first_name},
                    {item.last_name},
                    {item.email}

                <span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
            ))}
        <span class="hljs-tag">&lt;/<span class="hljs-name">ul</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> TestWithMockData
</code></pre>
<p>While writing tests for a component with props, you need to pass some mock data while rendering this component that pertains to your functionality. Here, one object in our data contains four fields, so we pass some mock data here.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> mockData = [
    {
        <span class="hljs-string">"id"</span>: <span class="hljs-number">1</span>,
        <span class="hljs-string">"first_name"</span>: <span class="hljs-string">"Fletcher"</span>,
        <span class="hljs-string">"last_name"</span>: <span class="hljs-string">"McVanamy"</span>,
        <span class="hljs-string">"email"</span>: <span class="hljs-string">"mmcvanamy0@e-recht24.de"</span>,
        <span class="hljs-string">"age"</span>: <span class="hljs-number">30</span>
      }, {
        <span class="hljs-string">"id"</span>: <span class="hljs-number">2</span>,
        <span class="hljs-string">"first_name"</span>: <span class="hljs-string">"Clarice"</span>,
        <span class="hljs-string">"last_name"</span>: <span class="hljs-string">"Harrild"</span>,
        <span class="hljs-string">"email"</span>: <span class="hljs-string">"charrild1@dion.ne.jp"</span>,
        <span class="hljs-string">"age"</span>: <span class="hljs-number">35</span>
      }, 
]
</code></pre>
<p>Note that the actual data could contain thousands of records, but the mock data only needs to be relevant to what you want to test. Now, let’s write the test and check if the list renders.</p>
<pre><code class="lang-javascript">test(<span class="hljs-string">"List renders successfully"</span>, <span class="hljs-function">() =&gt;</span> {
    render(<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">TestWithMockData</span> <span class="hljs-attr">data</span>=<span class="hljs-string">{mockData}</span> /&gt;</span></span>)
    expect(screen.getByText(<span class="hljs-regexp">/fletcher/i</span>)).toBeInTheDocument();
})
</code></pre>
<h2 id="heading-how-to-test-with-mock-data-covering-all-branches-in-react">How to Test With Mock Data Covering All Branches in React</h2>
<p>Let’s introduce some branching in the above component. We’ll have another prop, <code>displayUnorderedList</code>, that determines whether to display an ordered or unordered list. We’ll also render <code>Senior</code> for <code>age &gt; 50</code> and <code>Not Senior</code> otherwise.</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> TestWithMockData = <span class="hljs-function">(<span class="hljs-params">{data, displayUnorderedList, handleClick}</span>) =&gt;</span> {
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
        {displayUnorderedList ? 
            <span class="hljs-tag">&lt;<span class="hljs-name">ul</span>&gt;</span>
                {data.map(item =&gt; (
                    <span class="hljs-tag">&lt;<span class="hljs-name">li</span> <span class="hljs-attr">key</span>=<span class="hljs-string">{item.id}</span>&gt;</span>
                        {item.id}
                        {item.first_name},
                        {item.last_name},
                        <span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span> {
                            console.log("email link clicked")
                            handleClick()
                        }}&gt;{item.email}<span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span>

                        {item.age &gt; 50 ? 'Senior' : 'Not senior'}

                    <span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
                ))}
            <span class="hljs-tag">&lt;/<span class="hljs-name">ul</span>&gt;</span>
        : 
            <span class="hljs-tag">&lt;<span class="hljs-name">ol</span>&gt;</span>
                {data.map(item =&gt; (
                    <span class="hljs-tag">&lt;<span class="hljs-name">li</span> <span class="hljs-attr">key</span>=<span class="hljs-string">{item.id}</span>&gt;</span>
                        Last name: {item.last_name}
                    <span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
                ))}
            <span class="hljs-tag">&lt;/<span class="hljs-name">ol</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> TestWithMockData
</code></pre>
<p>Here's the coverage report so far:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/01/image-141.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Failed Test: Unable to find the element</em></p>
<p>You can see that Line 9 (that is, the unordered list part) is not covered by our existing tests. And our previous test has also failed since it is unable to find <code>fletcher</code> in the component.</p>
<p>Why is this so? In our previous test, we have not passed the <code>displayUnorderedList</code> prop to the component so it is <code>null</code>. So, the component renders the ordered list and it does not contain the <code>first_name</code>.</p>
<p>So, let’s write another test covering the ordered list part.</p>
<pre><code class="lang-javascript">test(<span class="hljs-string">"Ordered list renders"</span>, <span class="hljs-function">() =&gt;</span> {
    render(<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">TestWithMockData</span> <span class="hljs-attr">data</span>=<span class="hljs-string">{mockData}</span> <span class="hljs-attr">displayUnorderedList</span>=<span class="hljs-string">{false}</span> /&gt;</span></span>)

    expect(screen.getByText(<span class="hljs-regexp">/McVanamy/i</span>)).toBeInTheDocument()
})
</code></pre>
<p>Here, pass the prop’s value as <code>false</code> to render the ordered list. Also, add the <code>displayUnorderedList</code> prop to the failing test and pass the value <code>true</code>.</p>
<p>Now, all our tests pass with 100% coverage.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/01/image-142.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Uncovered Branch</em></p>
<p>One line is still not covered by the test cases, which is the branching logic for <code>age</code>. So, add another record to the mock data that has an age greater than 50.</p>
<pre><code class="lang-javascript">{
    <span class="hljs-string">"id"</span>: <span class="hljs-number">3</span>,
    <span class="hljs-string">"first_name"</span>: <span class="hljs-string">"Amby"</span>,
    <span class="hljs-string">"last_name"</span>: <span class="hljs-string">"Emmer"</span>,
    <span class="hljs-string">"email"</span>: <span class="hljs-string">"aemmer2@buzzfeed.com"</span>,
    <span class="hljs-string">"age"</span>: <span class="hljs-number">67</span>
}
</code></pre>
<p>Now, all our tests should pass with 100% coverage.</p>
<h2 id="heading-how-to-test-user-interactions-in-react">How to Test User Interactions in React</h2>
<p>The most important part of testing any UI app is testing its behaviour with various user interactions. Almost every functionality in a UI app involves user interactions.</p>
<p>You can use the <code>user-event</code> library to simulate user interactions. It has methods for simulating various user events such as <em>click</em>, <em>type</em>, <em>hover</em>, and so on.</p>
<p>First, we need to install the library:</p>
<pre><code class="lang-python">npm install --save-dev @testing-library/user-event
</code></pre>
<p>We can use this library to simulate user events. In our examples, we’ll interact with different elements, mostly <code>input</code> and <code>button</code> elements.</p>
<h3 id="heading-how-to-test-a-function-call-on-click-of-an-element">How to Test a Function Call on Click of an Element</h3>
<p>In our above component, we need to<code>TestWithMockData</code>, make the <code>email</code> field clickable and call a function <code>handleClick</code> on it. This will be passed as props to the component. There, replace <code>{item.email}</code> with:</p>
<pre><code class="lang-javascript">&lt;a onClick={<span class="hljs-function">() =&gt;</span> {
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"email link clicked"</span>)
    handleClick()
}}&gt;{item.email}&lt;/a&gt;
</code></pre>
<p>Now, our test coverage takes a hit. To cover this scenario, write the following test:</p>
<pre><code class="lang-javascript">test(<span class="hljs-string">"Email link click handler called"</span>, <span class="hljs-keyword">async</span> () =&gt; {
    <span class="hljs-keyword">const</span> mockHandleClick = jest.fn();
    render(<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">TestWithMockData</span> 
                <span class="hljs-attr">data</span>=<span class="hljs-string">{mockData}</span> 
                <span class="hljs-attr">displayUnorderedList</span>=<span class="hljs-string">{true}</span>
                <span class="hljs-attr">handleClick</span> = <span class="hljs-string">{mockHandleClick}</span>
          /&gt;</span></span>)
    <span class="hljs-keyword">await</span> userEvent.click(screen.getByText(<span class="hljs-regexp">/mmcvanamy0@e-recht24.de/i</span>));
    expect(mockHandleClick).toHaveBeenCalled();
})
</code></pre>
<p>First, create the mock of the <code>handleClick</code> function using <code>jest.fn()</code>. We do not need the actual implementation of the method, as we only want to test the behaviour of the component. So, we create an empty mock and pass the same as props. Read more about mocking functions <a target="_blank" href="https://jestjs.io/docs/mock-functions">here</a>.</p>
<p>Now, query the <code>&lt;a&gt;</code> element by text (any <code>email</code> from the mock data). Use the <code>click()</code> method to simulate a click event. Use <code>await</code> as simulating a user event is an asynchronous operation.</p>
<p>Write an assertion in the end to check if the method was called. The method was called, so our test passes with 100% coverage.</p>
<h3 id="heading-how-to-query-input-fields-and-buttons">How to Query Input Fields and Buttons</h3>
<p>So far, we have used only one method of querying elements – <code>getByText()</code>. Now, let’s see how you can query input fields and buttons.</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">placeholder</span>=<span class="hljs-string">'Enter name'</span>/&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">button</span>&gt;</span> Submit <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
</code></pre>
<p>To query these elements, you can do the following:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> inputElement = screen.getByRole(<span class="hljs-string">'textbox'</span>)
</code></pre>
<p><code>getByRole</code> finds an element by the given role. In this case, the <code>textbox</code> role means the <code>input</code> element.</p>
<p>How is role determined? Each element has a defined role, so you do not need to specify an explicit role attribute. You can see a list of roles for different elements <a target="_blank" href="https://www.w3.org/TR/html-aria/#docconformance">here</a>. Whatever element you want, just do <code>getByRole</code> and refer to the list.</p>
<p>For <code>button</code>, the default role is ‘button’ as you can see here:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> button = screen.getByRole(<span class="hljs-string">'button'</span>)
</code></pre>
<p>What if we add another <code>input</code> element, <code>&lt;input placeholder=’Enter description’/&gt;</code>? The test runner will now throw an error saying that there are two elements with the same role. What should we do in such a scenario? Use another query <code>getByPlaceholderText()</code>.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> nameInput = screen.getByPlaceholderText(<span class="hljs-regexp">/enter name/i</span>);
<span class="hljs-keyword">const</span> descrInput = screen.getByPlaceholderText(<span class="hljs-regexp">/enter description/i</span>);
</code></pre>
<p>You can also use <code>getByLabelText()</code> if your <code>input</code> has a <code>label</code>.</p>
<pre><code class="lang-javascript">&lt;label htmlFor=<span class="hljs-string">'password'</span>&gt; Enter password&lt;/label&gt;
<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">type</span>=<span class="hljs-string">'password'</span> <span class="hljs-attr">id</span>=<span class="hljs-string">'password'</span>/&gt;</span></span>
</code></pre>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> passwordInput = screen.getByLabelText(<span class="hljs-regexp">/enter password/i</span>);
</code></pre>
<p>For querying buttons, we can do <code>screen.getByRole('button')</code>.</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">button</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">button</span>&gt;</span> Apply<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
</code></pre>
<p>Since we have two buttons here, just doing <code>getByRole</code> will throw an error. So, we use a <code>name</code> option.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> submitButton = screen.getByRole(<span class="hljs-string">'button'</span>, { <span class="hljs-attr">name</span>: <span class="hljs-regexp">/submit/i</span> });
<span class="hljs-keyword">const</span> applyButton = screen.getByRole(<span class="hljs-string">'button'</span>, { <span class="hljs-attr">name</span>: <span class="hljs-regexp">/apply/i</span> });
</code></pre>
<p>The <code>name</code> option can contain the label of a form element, text of a button, or the value of the <code>aria-label</code> attribute of any element. We can also do <code>getByText()</code> for a button.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> submitButton = screen.getByText(<span class="hljs-regexp">/submit/i</span>);
</code></pre>
<h2 id="heading-how-to-test-state-updates-in-react">How to Test State Updates in React</h2>
<p>We have seen how to query form elements like <code>input</code> and <code>button</code>. Now, let’s simulate some user interactions and test state updates. What do I mean by testing state updates?</p>
<p>State updates cause a component to re-render. So, when your functionality performs a state update, you should test how the component is behaving due to the state change.</p>
<p>First, let’s take a simple example where we set the state as soon as the component is loaded – that is, in the <code>useEffect</code> block.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> TestingStateChange = <span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">const</span> [loaded, setLoaded] = useState(<span class="hljs-literal">false</span>)
    useEffect(<span class="hljs-function">() =&gt;</span> {
        setLoaded(<span class="hljs-literal">true</span>)
    }, [])
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
        {loaded &amp;&amp; <span class="hljs-tag">&lt;<span class="hljs-name">h3</span>&gt;</span> Page Loaded <span class="hljs-tag">&lt;/<span class="hljs-name">h3</span>&gt;</span>}
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  )
}
</code></pre>
<p>Here, your entire component, starting from the <code>useEffect</code> statement to the end, is uncovered. When you write the following test, not only does the HTML part get covered but also the <code>useEffect</code> part where you set the state.</p>
<pre><code class="lang-javascript">test(<span class="hljs-string">"Testing page load"</span>, <span class="hljs-function">() =&gt;</span> {
    render(<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">TestingStateChange</span>/&gt;</span></span>)
    expect(screen.getByText(<span class="hljs-regexp">/page loaded/i</span>)).toBeInTheDocument();
})
</code></pre>
<p>This is how you test state updates. You test whether the component behaves as you expect with a state change.</p>
<h3 id="heading-how-to-test-a-state-change-on-click-of-a-button">How to Test a State Change on Click of a Button</h3>
<p>Let’s have a button and a text that toggles on the click of the button.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> [toggleTextVisible, setToggleTextVisible] = useState(<span class="hljs-literal">false</span>)<span class="hljs-string">`</span>
</code></pre>
<pre><code class="lang-html">{toggleTextVisible &amp;&amp; <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span> Text visible <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">{()</span> =&gt;</span> { setToggleTextVisible(!toggleTextVisible) }}&gt; 
    Toggle text 
<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
</code></pre>
<p>We’ll write the test for this:</p>
<pre><code class="lang-javascript">test(<span class="hljs-string">"Toggle text visible"</span>, <span class="hljs-keyword">async</span> () =&gt; {
    render(<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">TestingStateChange</span>/&gt;</span></span>);
    <span class="hljs-keyword">await</span> userEvent.click(screen.getByText(<span class="hljs-regexp">/toggle text/i</span>));
    expect(screen.getByText(<span class="hljs-regexp">/text visible/i</span>)).toBeInTheDocument();
})
</code></pre>
<p>With <code>userEvent</code>, we have simulated the click of a button and asserted if the text is visible.</p>
<p>Now, let’s test another scenario where we check if the above button is disabled on the click of another button.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> [btnDisabled, setBtnDisabled] = useState(<span class="hljs-literal">false</span>);
</code></pre>
<p>Add a <code>disabled={btnDisabled}</code> attribute to the above button and create another button that controls its value.</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span> { setBtnDisabled(!btnDisabled) }}&gt; 
      Toggle button disabled 
<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
</code></pre>
<p>Use the <code>toBeDisabled()</code> method to test if the button is disabled.</p>
<pre><code class="lang-javascript">test(<span class="hljs-string">"Button disabled on click"</span>, <span class="hljs-keyword">async</span> () =&gt; {
    render(<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">TestingStateChange</span>/&gt;</span></span>)
    <span class="hljs-keyword">await</span> userEvent.click(screen.getByText(<span class="hljs-regexp">/toggle button disabled/i</span>));
    expect(screen.getByText(<span class="hljs-regexp">/toggle text/i</span>)).toBeDisabled();
})
</code></pre>
<h3 id="heading-how-to-test-if-an-element-was-added-to-a-list">How to Test if an Element Was Added to a List</h3>
<p>Let’s perform another assertion. Here, we’ll check if an element was added to a list. We’ll have some data and create a state with the data as the initial value. We'll display it while also having a button to add an element to it.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> [elements, setElements] = useState(data);
</code></pre>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">h3</span>&gt;</span> List <span class="hljs-tag">&lt;/<span class="hljs-name">h3</span>&gt;</span>
{elements.map(item =&gt; (
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">key</span>= <span class="hljs-string">{item.id}</span>&gt;</span>
       {item.id}: { item.name }
    <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">{()</span> =&gt;</span> {
    setElements([...elements, {
        id: 4,
        name: 'abhinav'
    }])
}}&gt; Add to list <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
</code></pre>
<p>Add an attribute <code>data-testid='record'</code> to each record to help query the element. Let’s write the test for this:</p>
<pre><code class="lang-javascript">test(<span class="hljs-string">"Element added to the list"</span>, <span class="hljs-keyword">async</span> () =&gt; {
    render(<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">TestingStateChange</span>/&gt;</span></span>)
    expect(screen.getAllByTestId(<span class="hljs-string">'record'</span>).length).toBe(<span class="hljs-number">3</span>);

    <span class="hljs-keyword">await</span> userEvent.click(screen.getByText(<span class="hljs-regexp">/add to list/i</span>));
    expect(screen.getAllByTestId(<span class="hljs-string">'record'</span>).length).toBe(<span class="hljs-number">4</span>);
})
</code></pre>
<p>To get multiple elements with the same query, use the <code>getAllBy…</code> method. In this case, there are multiple elements with the test-id <code>record</code>, so using the <code>getAllByTestId()</code> method gets a list of all such elements.</p>
<p>Here, we have checked the length of the list. We can add another assertion to check if the new element is visible.</p>
<pre><code class="lang-javascript">expect(screen.getByText(<span class="hljs-regexp">/abhinav/i</span>)).toBeInTheDocument();
</code></pre>
<h3 id="heading-how-to-test-if-an-element-was-removed-from-a-list">How to Test if an Element Was Removed From a List</h3>
<p>Now, let’s add another button that removes an element from the list.</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span> {
    setElements(elements.filter(item =&gt; item.id != 2))
}}&gt; Remove from list <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
</code></pre>
<p>The test for this:</p>
<pre><code class="lang-javascript">test(<span class="hljs-string">"Element removed from list"</span>, <span class="hljs-keyword">async</span> () =&gt; {
    render(<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">TestingStateChange</span>/&gt;</span></span>)
    <span class="hljs-keyword">await</span> userEvent.click(screen.getByText(<span class="hljs-regexp">/remove from list/i</span>));
    expect(screen.getAllByTestId(<span class="hljs-string">'record'</span>).length).toBe(<span class="hljs-number">2</span>);
})
</code></pre>
<p>Here, we test whether the length of the list was reduced. All our tests pass with 100% coverage.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/01/image-143.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Coverage Report for Testing State Change: Tests Passed</em></p>
<h2 id="heading-how-to-test-api-calls-in-react">How to Test API Calls in React</h2>
<p>API calls are an important part of any UI application. Let’s understand how to test an API call.</p>
<p>In this example, we have a file <code>data.json</code> that has some data. We’ll make an API call to fetch this data.</p>
<p>For demonstration, we’ll save this file on the local server only (inside the <code>public</code> folder), but the procedure remains the same when fetching a file from a remote server.</p>
<p>We’ll use <code>fetch</code> to make the API call.</p>
<pre><code class="lang-javascript">fetch(<span class="hljs-string">"http://localhost:3000/data.json"</span>)
  .then(<span class="hljs-function"><span class="hljs-params">res</span> =&gt;</span> {
      <span class="hljs-keyword">return</span> res.json();
  })
  .then(<span class="hljs-function"><span class="hljs-params">data</span> =&gt;</span> {
      <span class="hljs-comment">// Store the data in state</span>
  })
</code></pre>
<p>Now, let’s have a state to store the data and render it.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> [data, setData] = useState([])
</code></pre>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
    {data.map(item =&gt; (
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
            {item.name}
        <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>
</code></pre>
<p>How do we write the test for this? One way is to mock the <code>fetch</code> method and provide our own mock implementation. But what if there are multiple Fetch API calls in the component? You cannot have the same mock implementation for everyone.</p>
<p>So, we put the <code>fetch</code> call in a separate function and have a mock implementation of that function. We put our API call in a <code>FetchData</code> method that returns the promise returned by <code>fetch</code>.</p>
<p>We put the method in a separate <code>Services.js</code> file and export it from there.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> FetchData = <span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">return</span> fetch(<span class="hljs-string">"http://localhost:3000/data.json"</span>)
        .then(<span class="hljs-function"><span class="hljs-params">res</span> =&gt;</span> {
            <span class="hljs-keyword">return</span> res.json();
        }) 
}
</code></pre>
<p>Now, when we call this method inside our component, it looks like this:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> [data, setData] = useState([])

useEffect(<span class="hljs-function">() =&gt;</span> {
    FetchData().then(<span class="hljs-function"><span class="hljs-params">data</span> =&gt;</span> {
        setData(data);
    })
})

<span class="hljs-keyword">return</span> (
  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
      {data.map(item =&gt; (
          <span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
              {item.name}
          <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></span>
)
</code></pre>
<p>Now, let’s write the test for this. The main thing is to mock the FetchData method. First, import all methods from <code>Services.js</code> as a module.</p>
<pre><code class="lang-python"><span class="hljs-keyword">import</span> * <span class="hljs-keyword">as</span> services <span class="hljs-keyword">from</span> <span class="hljs-string">'../utils/Services'</span>
</code></pre>
<p>Let’s mock our function using <code>jest.spyOn()</code>. The method takes two arguments, the object and the method name as a string.</p>
<pre><code class="lang-python">const mockFetchData = jest.spyOn(services, <span class="hljs-string">'FetchData'</span>)
        .mockImplementation(<span class="hljs-keyword">async</span> () =&gt; {
            <span class="hljs-keyword">return</span> [{
                name: <span class="hljs-string">'kunal'</span>
            }];
        })
</code></pre>
<p><code>spyOn</code> creates an empty mock of the method. Now, we provide our mock implementation where we return some mock data. This will be called when our component renders.</p>
<pre><code class="lang-python">render(&lt;TestingAPICalls/&gt;)
expect(mockFetchData).toHaveBeenCalled();
</code></pre>
<p>We use <code>toHaveBeenCalled()</code> to test if the method was called. It was – so the test passes. Now, to test the behaviour of our component, let’s test if the name was rendered.</p>
<pre><code class="lang-javascript">expect(screen.getByText(<span class="hljs-regexp">/kunal/i</span>)).toBeInTheDocument();
</code></pre>
<p>In this case, the test fails as it is unable to find the element. Why is this so?</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/01/image-144.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Failed Test: Unable to find the element</em></p>
<p>Since API calls and state updates are asynchronous, the text hasn’t been rendered yet. To test asynchronous behaviour, wrap the query in a <code>waitFor()</code> block.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">await</span> waitFor(<span class="hljs-function">() =&gt;</span> {
    expect(screen.getByText(<span class="hljs-regexp">/kunal/i</span>)).toBeInTheDocument();
})
</code></pre>
<p><code>waitFor</code> does exactly what the name suggests. It waits for the asynchronous behaviour to finish before making the query. Now, our test passes with 100% coverage.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/01/image-145.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>100% Coverage for Testing API Calls</em></p>
<p>You can find the complete code on <a target="_blank" href="https://github.com/KunalN25/react-testing-basics">GitHub</a>.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>Phew! That was a long one. But it needed to be. I have explained, through basic examples, how you can start writing tests in React.</p>
<p>This article started from a basic test with a simple assertion and explained how to use mock data to serve the purpose of your test.</p>
<p>I also explained how to simulate user interactions, how to test a component’s behaviour on state updates, and lastly how to test API calls. Hopefully, all these examples help you write tests for your upcoming project.</p>
<p>If you are unable to understand the content or find the explanation unsatisfactory, please let me know. New ideas are always appreciated! Feel free to DM me on <a target="_blank" href="https://www.linkedin.com/in/kunalnk25/">LinkedIn</a> if you want to discuss anything. Until then, Goodbye!</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ API Testing Best Practices – How to Test APIs for Beginners ]]>
                </title>
                <description>
                    <![CDATA[ In this digital age, APIs have become the cornerstone of how data is shared and processed.  But many users are often unaware of the fact that they are putting their trust in an API and not a person. This is why it's important to leverage API testing ... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/rules-of-api-testing-for-beginners/</link>
                <guid isPermaLink="false">66b8dbfb1ce2b93cb4142f0c</guid>
                
                    <category>
                        <![CDATA[ api ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Software Testing ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Testing ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Hillary Nyakundi ]]>
                </dc:creator>
                <pubDate>Fri, 16 Dec 2022 21:25:46 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2022/12/OOP--2-.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>In this digital age, APIs have become the cornerstone of how data is shared and processed. </p>
<p>But many users are often unaware of the fact that they are putting their trust in an API and not a person.</p>
<p>This is why it's important to leverage API testing techniques to ensure that every aspect of your website or application works as expected.</p>
<h2 id="heading-why-api-testing-is-important">Why API Testing is Important</h2>
<p>My first interaction with APIs was while working on a personal project, a <a target="_blank" href="https://github.com/larymak/VirtualAssistant">VirtualAssistant</a>. It required me to fetch real data from third party apps. </p>
<p>As a beginner, the knowledge I acquired was mainly from tutorials I had watched which basically covered how to <code>GET</code>, <code>POST</code> and <code>DELETE</code> data. I didn't know that there were rules that I should follow while working with APIs. </p>
<p>But as time progressed I came to understand the importance of APIs and the major role they play in the daily applications of a developer's job.</p>
<p>Mastering the rules is an essential step in learning about APIs. Most applications today are made up of pieces of software, each of which needs to be tested in its own way. </p>
<p>There are always new and exciting ways to test an application – and we're not just talking about checking for bugs here. It's more about the app functionality.</p>
<p>As technology continues to advance, the trends related to how to test these applications will also change. </p>
<p>In this guide, we will be discussing the trends that apply to the testing of APIs, how they differ from other types of testing, tools we can leverage when it comes to testing APIs, and how you can stay on top of your game when it comes to API testing.</p>
<p>First, let's get an understanding of what we mean by APIs.</p>
<h2 id="heading-what-is-an-api">What is an API?</h2>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/12/i50d3cqyx3ijgcla2tc4.png" alt="APIs" width="600" height="400" loading="lazy"></p>
<p>APIs are designed for developers to use. They are, in essence, a coding tool that allows your application to communicate with other applications. APIs allow you to integrate third-party applications into your work or use your own data and processes in the cloud.</p>
<p>The functionality of any application is defined by the connection it has with the outside world. For this reason, connecting your application with APIs becomes very helpful. </p>
<p>In today's development process, APIs have become an essential part in web and mobile applications. They enable communication of different components of these systems and help you access data and services.</p>
<p>A very important thing to keep in mind is that when dealing with APIs, you need to be sure everything works properly and that you get the correct feedback before integrating them into your applications. That's why testing them is essential.</p>
<p>For this reason, a vital part of testing any type of software requires evaluating whether or not there's a way the app can be broken. In order to ensure a certain level of continuity when using an API in multiple ways simultaneously, you need to conduct API testing.</p>
<p>Now that you have an understanding of what an API and why testing it is important, let's clarify what exactly might we mean by this – is there more to the term testing?</p>
<h2 id="heading-what-is-api-testing">What is API Testing?</h2>
<p>API Testing is a process that checks that an API adheres to the given 
requirements. Achieving this goal is not an easy task and there are many ways in which a tester can go about doing it effectively. </p>
<p>You can conduct API testing manually or automatically, and it is often considered a part of integration testing. </p>
<ul>
<li>Manual API testing involves directly interacting with the API using tools like <a target="_blank" href="https://www.postman.com/">Postman</a>, <a target="_blank" href="https://apitester.org/">API Tester</a> or any other available online tools. </li>
<li>Automated API testing uses specialized software to send requests to the API and then compares the results to the expected behavior.</li>
</ul>
<p>API testing is important because it helps ensure that the various components of a system are working together as expected. By verifying the functionality of the API, you can be confident that the system as a whole will function as intended.</p>
<h2 id="heading-api-testing-tools">API Testing Tools</h2>
<p>You can use API testing tools to test the functionality of an API. They can help you test the performance of an API, as well as to check for security vulnerabilities. </p>
<p>There are a number of different API testing tools available, each with its own advantages and disadvantages. Some of the most popular API testing tools include SoapUI, Postman, Runscope, and API Tester. </p>
<h2 id="heading-api-testing-principles">API Testing Principles</h2>
<p>Having a set of standard rules is the best way to ensure the quality of your APIs and their implementations. You can apply these rules during testing, coding, and development, as well as in production. </p>
<p>Here are some principles that you should keep in mind:</p>
<ol>
<li>API testing should be a part of your continuous integration and delivery pipeline.</li>
<li>API tests should be easy to maintain and write.</li>
<li>A well-designed API will make your tests easier to write.</li>
<li>You should test at the boundary of your system.</li>
<li>Keep your tests small and focused.</li>
<li>Make sure your tests are deterministic.</li>
<li>Run your tests in parallel for speed.</li>
<li>Use the available and freely accessible tools to simplify API testing. </li>
</ol>
<h2 id="heading-how-to-start-api-testing">How to Start API Testing</h2>
<p>There are many different types of tests you can perform on your APIs:</p>
<ul>
<li>Functionality tests focus on ensuring that the API is able to perform its intended functions. </li>
<li>Performance tests measure the response times of the API and check for bottlenecks. </li>
<li>Security tests assess the vulnerability of the API to attack vectors such as SQL injection and cross-site scripting (XSS). </li>
</ul>
<p>To get started with API testing, you will need to have access to an application with an exposed API. You will also need to choose a method for sending requests to the API (manual or automated), and select a tool or framework for writing your tests (if using automated testing).</p>
<p>Once you have these things set up, you can begin writing your test cases and running them against the API.</p>
<h2 id="heading-api-testing-tips">API Testing Tips</h2>
<p>API testing can be a challenge, but regardless of the tools you decide to use here are some tips that can help:</p>
<ol>
<li>Make sure you have a clear understanding of the API before you start testing. Read the documentation and any other available materials. This will help you know what to expect and how the API should work. </li>
<li>Use API testing tools: This will give you a better understanding of how the API works and make it easier to find any issues. </li>
<li>Test all aspects of the API, including input validation, error handling, and security. These are all important factors in ensuring that your API is working correctly.</li>
<li>Keep your tests up-to-date as the API changes. This will help ensure that you catch any new issues that may arise. </li>
<li>Use mobile apps for API testing. Things are changing all the time these days, where many people are working remotely, and from their phones too. By using mobile apps you can increase your productivity, become more mobile, and work from anywhere in the world. A good example of such a tool is the <a target="_blank" href="https://apitester.org/">API Tester</a>. </li>
</ol>
<p>By following these tips, you can help make sure that your API testing is effective and efficient. </p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>API testing is a key part of ensuring the quality of your software. By following these highlighted rules you will be able to ensure your tests are functional, secure and have a reliable performance. </p>
<p>This will in turn help you improve the overall quality of your software applications and provide a better user experience.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ React Unit Test Handbook + Redux Testing Toolkit ]]>
                </title>
                <description>
                    <![CDATA[ In this step-by-step tutorial, you'll learn how to easily start with Unit Tests in React. You'll learn how to write tests for Redux states as well as fundamental Redux slice tests using the React Testing Library and Jest. 🔐 Here's What We'll Cover ... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-write-unit-tests-in-react-redux/</link>
                <guid isPermaLink="false">66bb8f42fce17a7d998852db</guid>
                
                    <category>
                        <![CDATA[ React ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Redux ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Software Testing ]]>
                    </category>
                
                    <category>
                        <![CDATA[ unit testing ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Matthes B. ]]>
                </dc:creator>
                <pubDate>Wed, 09 Nov 2022 15:32:10 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2022/11/pexels-scott-webb-1527893.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>In this step-by-step tutorial, you'll learn how to easily start with Unit Tests in React. You'll learn how to write tests for Redux states as well as fundamental Redux slice tests using the React Testing Library and Jest.</p>
<h2 id="heading-heres-what-well-cover"><strong>🔐 Here's What We'll Cover</strong></h2>
<ul>
<li>You'll see how easy it is to set up your first unit tests in React.</li>
<li>You'll improve your general React knowledge.</li>
<li>You'll get the hang of why Test Driven Development (TDD) is helpful for your coding workflow.</li>
</ul>
<h2 id="heading-prerequisites"><strong>📝</strong> Prerequisites</h2>
<ul>
<li>You should be familiar with the basic React workflow structure (including functional components and hooks).</li>
<li>You should have a basic knowledge of Redux (I'm using Redux Toolkit for this guide).</li>
<li>You don't need any prior knowledge about testing.</li>
<li>I'm using the <code>npm</code> installation approach, not the <code>yarn</code> one.</li>
</ul>
<h2 id="heading-the-objective"><strong>🎯</strong> The Objective</h2>
<p>While learning advanced concepts of React, you'll probably stumble across the topic of testing. Being able to work with automatic tests is also quite handy for any upcoming frontend developers. </p>
<p>However, as I myself was learning React, I had a hard time finding information about how to implement tests for libraries like Redux (even though it's a library I work with all the time). </p>
<p>Beyond that, I found that doing any component testing in React is basically unfeasible when you don't know how to work with the Redux library.</p>
<p>So I took some time to read the Redux documentation and went back and forth with it a bit. Then I decided to write a practical starter guide for unit testing in React, including Redux, to share what I learned. </p>
<p>Since I would like to take a modern approach, I'm also going to use the Redux Toolkit. We'll cover the Redux implementation in this guide.</p>
<h3 id="heading-what-well-cover">What we'll cover:</h3>
<p>To start off, I will provide some general information about tests before I directly go into creating the first general unit tests. </p>
<p>Next I'll give a quick overview of how to implement some Redux Toolkit logic. </p>
<p>Then we will work on some unit tests within an application which uses Redux Toolkit. For this step we will adjust our previously created tests to the new Redux environment.</p>
<p>This is a step-by-step guide. If you are new to tests, I recommend following this guide in order from top to bottom.</p>
<p>I have also created a <a target="_blank" href="https://github.com/Matthes-Baer/unit-test-redux-article-app">public GitHub repository</a> for this guide with some commentary. You can use that if you want to look something up without scrolling through this guide in its full length again.</p>
<h2 id="heading-table-of-contents">Table of Contents</h2>
<ol>
<li><a class="post-section-overview" href="#what-different-kinds-of-tests-are-there">What Different Kinds of Tests Are There?</a></li>
<li><a class="post-section-overview" href="#how-to-set-up-your-react-testing-environment">How to Set Up Your React Testing Environment</a></li>
<li><a class="post-section-overview" href="#heading-check-out-your-created-react-application">Check Out Your Created React Application</a></li>
<li><a class="post-section-overview" href="#how-to-create-your-first-unit-test">How to Create Your First Unit Test</a></li>
<li><a class="post-section-overview" href="#how-to-create-a-failing-test-on-purpose">How to Create a Failing Test on Purpose</a></li>
<li><a class="post-section-overview" href="#heading-how-to-create-some-additional-tests">How to Create Some Additional Tests</a></li>
<li><a class="post-section-overview" href="#heading-how-to-perform-testing-with-the-react-redux-toolkit">How to Perform Testing with the React Redux Toolkit</a></li>
<li><a class="post-section-overview" href="#heading-outlook-for-advanced-testing">Outlook for Advanced Testing</a></li>
</ol>
<h2 id="heading-what-different-kinds-of-tests-are-there">📋 What Different Kinds of Tests Are There?</h2>
<p>This quick guide won't provide you with detailed theoretical knowledge about all the <a target="_blank" href="https://www.freecodecamp.org/news/types-of-software-testing/">different kinds of testing out there</a>. At this point, you should just understand that there are generally three kinds of tests:</p>
<ul>
<li>Unit Tests</li>
<li>Integration Tests</li>
<li>End-To-End Tests</li>
</ul>
<p>To put it in simple words: You can see these three types of tests as generally increasing in their complexity. </p>
<p>While <a target="_blank" href="https://www.freecodecamp.org/news/unit-tests-explained/">unit tests</a> cover single functions and components, integration tests typically focus on multiple functions and their connections to each other. <a target="_blank" href="https://www.freecodecamp.org/news/end-to-end-testing-tutorial/">End-to-end tests</a> are even more complex and give insights about multiple function and component structures. </p>
<p>There are other test concepts, but these three are the most important ones for web developers, for example.</p>
<p>Again, this is really put in simple words. But in this case it's sufficient to know that unit tests are basically the least complex tests out of these three. </p>
<p>It's also quite easy to work with unit tests as soon as you have a basic understanding of how testing in general works.</p>
<p>I would also like to quickly emphasize that there are mainly two ways of testing your application.</p>
<ul>
<li>Manual Testing</li>
<li>Automatic Testing</li>
</ul>
<p>Manual Testing is pretty much what you probably already do for all of your application which you create. When manually testing your application, you basically start your React application with <code>npm run start</code> and actually click on buttons to check if the corresponding function works.</p>
<p>Automatic Tests, on the other hand, are pretty much functions you create which automatically check your application to see if the respective steps work that you defined within these tests. This automatic kind of testing is extremely important for larger projects. </p>
<p>With this automatic approach, it's also way easier to scale your tests. In the end, you have a lot of tests which automatically test your whole application in a relatively short amount of time. These test can help you spot any potential errors which might have occurred during development. This would take much more time if you were to go back constantly to manually test your application.</p>
<p>Being able to work with automatic tests is also typically a big plus for your résumé as a frontend developer.</p>
<h2 id="heading-how-to-set-up-your-react-testing-environment">🔧 How to Set Up Your React Testing Environment</h2>
<p>In order to get a practical start, we are going to directly dive into our React application. </p>
<p>You will see that the setup of a testing environment is relatively easy in React – or, to be more precise, React does it all for you during the regular install setup.</p>
<p>Therefore, I'm creating a React application with the following line:</p>
<p><code>npx create-react-app &lt;name of your application&gt;</code></p>
<p>After this step, we need everything that should be added for using Redux in our React application:</p>
<ul>
<li><strong>React Redux:</strong> <code>npm install react-redux</code> (provides some mandatory hooks, for example)</li>
<li><strong>React Redux Toolkit:</strong> <code>npm install @reduxjs/toolkit</code> (provides logic for creating a store or slices, for example)</li>
</ul>
<p>It's worth mentioning that there also is the <strong>Redux core</strong> (<code>npm install redux</code>). But this is already part of the React Redux Toolkit installation, so we don't have to install it here too. </p>
<p>If you wanted to use React without the React Redux Toolkit, then you would have to separately reach out to the Redux core installation.</p>
<p>You can also create a new React application from scratch with <code>npx create-react-app my-app --template redux</code> which includes the React Redux Toolkit, the React core, React Redux, as well as a template from the React Redux Toolkit. </p>
<p>Choose this approach if you don't have any existing React applications, since it's probably more convenient.</p>
<p>Under the hood, you now have an application that uses the <strong>React Testing library</strong> combined with <strong>Jest</strong> (a testing framework). Together, they have pretty much everything that you will need for testing your React application. </p>
<p>You don't have to install anything else for this purpose. These tools come out of the box with a standard React installation.</p>
<h2 id="heading-check-out-your-created-react-application">🔎 Check Out Your Created React Application</h2>
<p>As you go into your newly created React application, you will find the folder and file structure you are likely familiar with. Besides others, there is the <code>App.js</code> file, which is created like this:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> logo <span class="hljs-keyword">from</span> <span class="hljs-string">'./logo.svg'</span>;
<span class="hljs-keyword">import</span> <span class="hljs-string">'./App.css'</span>;

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">App</span>(<span class="hljs-params"></span>) </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">header</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"App-header"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">src</span>=<span class="hljs-string">{logo}</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"App-logo"</span> <span class="hljs-attr">alt</span>=<span class="hljs-string">"logo"</span> /&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>
          Edit <span class="hljs-tag">&lt;<span class="hljs-name">code</span>&gt;</span>src/App.js<span class="hljs-tag">&lt;/<span class="hljs-name">code</span>&gt;</span> and save to reload.
        <span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">a</span>
          <span class="hljs-attr">className</span>=<span class="hljs-string">"App-link"</span>
          <span class="hljs-attr">href</span>=<span class="hljs-string">"https://reactjs.org"</span>
          <span class="hljs-attr">target</span>=<span class="hljs-string">"_blank"</span>
          <span class="hljs-attr">rel</span>=<span class="hljs-string">"noopener noreferrer"</span>
        &gt;</span>
          Learn React
        <span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">header</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>Within the <code>src</code> folder, you also have the file <code>App.test.js</code>. This file is actually a first test that came out of the box with React installation. This file is structured like this:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> { render, screen } <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>;

test(<span class="hljs-string">'renders learn react link'</span>, <span class="hljs-function">() =&gt;</span> {
  render(<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">App</span> /&gt;</span></span>);
  <span class="hljs-keyword">const</span> linkElement = screen.getByText(<span class="hljs-regexp">/learn react/i</span>);
  expect(linkElement).toBeInTheDocument();
});
</code></pre>
<p>Even without fully understanding what <code>render</code> or <code>screen</code> is, for example, we can see that something is going on with our <code>App</code> component in there. In fact, this is a unit test that is focusing on a specific part of the <code>App</code> component.</p>
<p>While this first template for a test is a handy representation of what a test looks like, I would like to create a test file from scratch.</p>
<p>Generally speaking, tests are separated into different test suites. These test suites are typically a group of tests that focus on the same component, for example. Tests within the same test suite basically have the same superordinate topic.</p>
<p>To check this, try to enter <code>npm run test</code> in your terminal when you are within your React application. </p>
<p>It could say something like "There are no new tests or changes since the last commit" – in this case, just enter <code>a</code> in the terminal to run all tests regardless.</p>
<p>In the end, you should be able to see this within the terminal:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/10/image-124.png" alt="Image" width="600" height="400" loading="lazy">
<em>Result of <code>npm run test</code></em></p>
<p>At the top, you can see that the <code>App.test.js</code> file passed. Basically, all tests within this file were successful. </p>
<p>Below that, you can see <code>renders learn react link</code>: This is the description for this particular test, which we can define individually. We will get back to this later.</p>
<p>Further down, we can finally see the test suites and tests. As you can see, we have one test suite and one test. To be more precise, we have one test suite that includes this one test. </p>
<p>Later on, you will recognize that we will use like 1-3 test suites while there will be around 5+ tests, for example. Again, test suites basically provide a structure that groups single tests together.</p>
<p>The stuff with the snapshots is not important for your specific case.</p>
<p><a target="_blank" href="https://jestjs.io/docs/snapshot-testing">Snapshots</a> are an advanced concept for testing. So a reference snapshot (like an image that was taken) is being compared with the version after some actions took place. This can help to check whether the UI stays the same after some actions or if some changes happened all of a sudden.</p>
<p>I won't focus on testing with snapshots in this article. This is a topic that you might want to look up after understanding some unit testing basics.</p>
<h2 id="heading-how-to-create-your-first-unit-test">🔨 How to Create Your First Unit Test</h2>
<p>Now that we've looked at a unit test, lets dive into the first test which we'll build from scratch on our own.</p>
<p>For that, I would like to create a new folder called <code>__tests__</code>. This is common when you are working with tests or checking out other applications. </p>
<p>I'm also dragging the already-available <code>App.test.js</code> file into this folder. This doesn't change anything about the result.</p>
<p>Our folder structure now looks like this:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/10/image-125.png" alt="Image" width="600" height="400" loading="lazy">
<em>general folder structure with <code>__tests__</code></em></p>
<p>Within <code>__tests__</code>, we create the file <code>myFirstTesting.test.js</code>. We need this file structure of <code>&lt;test name&gt;.test.js</code>. You can also create a test file with <code>&lt;test name&gt;.spec.js</code> – both approaches will work the same.</p>
<p>Our first step is to import the <code>App.js</code> component: <code>import App from "../App";</code>.</p>
<p>To create our first test, we have to make use of the <code>test()</code> function. You could also use <code>it()</code>. Both will achieve the same result. </p>
<p>The first parameter of this function has to be a string, which describes what we are going to test (remember the stuff with "renders learn react link" within the test file we viewed?). This is going to help you have a more precise overview after running all the tests. </p>
<p>In this case, I will use the description <code>"renders logo in App component"</code>. The second parameter is another function for which we are using an anonymous arrow function. Our <code>myFirstTesting.test.js</code> file now looks like this:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> App <span class="hljs-keyword">from</span> <span class="hljs-string">"../App"</span>;

test(<span class="hljs-string">"renders logo in App component"</span>, <span class="hljs-function">() =&gt;</span> {

})
</code></pre>
<p>Even though there is not much going on, let's try entering <code>npm run test</code> again. We will find the following result in our terminal:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/10/image-126.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Therefore, we now have two test files, resulting in two test suites and two tests.</p>
<p>Now we would actually like to test something. Since we added the description <code>"renders logo in App component"</code>, we are going to test exactly that. </p>
<p>In order to do that, we need the <code>render()</code> function, which we'll use whenever we actually want to render a component from our application.</p>
<p>In order to add the <code>render()</code> function, we have to import it from the React Testing library, which is already part of our React application without any other installations. </p>
<p>While we're at this step of importing, let's also import <code>screen</code> (also part of the React Testing library). It provides access to different functions that will look through the current screen after something gets rendered and find specific elements, for example.</p>
<p>After adding these two imports, our <code>myFirstTesting.test.js</code> file now looks like this:</p>
<pre><code class="lang-javascript"><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> { render, screen } <span class="hljs-keyword">from</span> <span class="hljs-string">"@testing-library/react"</span>;

test(<span class="hljs-string">"renders logo in App component"</span>, <span class="hljs-function">() =&gt;</span> {

})
</code></pre>
<p>Now that we have all that, let's actually start working on our test.</p>
<p>First of all, we need to render our component. Remember that tests are self-contained and don't know that we have an <code>App.js</code> with the corresponding content in our React application. We have to individually tell the specific test that a component exists by rendering it with <code>render()</code> at the top of the test. This is going to look like this: <code>render(&lt;App /&gt;);</code>.</p>
<p>Now that we have rendered the <code>App.js</code> component in this test, we should try to check if a specific content part can be found by the test. This way, we can actually test if <code>App.js</code> was rendered like it was supposed to be. </p>
<p>Assuming something went wrong, we would not be able to find the React logo, for example, which is currently part of the <code>App.js</code> component.</p>
<p>So we will try to find this logo, which is an <code>img</code> element. To do this, we can make use of the <code>getByAltText()</code> function that finds an element by its specific <code>alt</code> attribute, which is commonly utilized for images. We have access to this function with <code>screen</code> that we imported earlier. </p>
<p>We now have this expression: <code>screen.getByAltText("logo")</code>. So the test looks at the screen where we rendered the <code>App.js</code> component beforehand, and then gets an element, which has an <code>alt</code> attribute of <code>"logo"</code>. We will connect all this to a variable. </p>
<p>Our test file now looks like this:</p>
<pre><code class="lang-javascript"><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> { render, screen } <span class="hljs-keyword">from</span> <span class="hljs-string">"@testing-library/react"</span>;

test(<span class="hljs-string">"renders logo in App component"</span>, <span class="hljs-function">() =&gt;</span> {
  render(<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">App</span> /&gt;</span></span>);
  <span class="hljs-keyword">const</span> image = screen.getByAltText(<span class="hljs-string">"logo"</span>);
})
</code></pre>
<p>There are a bunch of different functions like <code>getByAltText()</code> that you can use to look for elements with a specific text content, a specific role like a button, or even with a test id that you can add to the actual element.</p>
<p>You also have the opportunity to look for multiple elements. Besides that, you don't have to use a string as parameter. A regular expression with <code>/logo/i</code> is also feasible, for example. We will use different ways to find elements throughout this starter guide.</p>
<p>For the last step, we have to utilize <code>expect()</code>, which we use to see what behavior we can expect. In this case, we expect that our <code>image</code> variable is part of the component and therefore exists. </p>
<p>For this approach, our file would look like this:</p>
<pre><code class="lang-javascript"><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> { render, screen } <span class="hljs-keyword">from</span> <span class="hljs-string">"@testing-library/react"</span>;

test(<span class="hljs-string">"renders logo in App component"</span>, <span class="hljs-function">() =&gt;</span> {
  render(<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">App</span> /&gt;</span></span>);
  <span class="hljs-keyword">const</span> image = screen.getByAltText(<span class="hljs-string">"logo"</span>);
  expect(image).toBeInTheDocument();
})
</code></pre>
<h2 id="heading-how-to-create-a-failing-test-on-purpose">❗ How to Create a Failing Test on Purpose</h2>
<p>If we now run our tests with <code>npm run test</code>, everything will pass. Now, let's try to reverse this logic so that we actually create a failing test. This way, we can check if this test actually has some impact or not. </p>
<p>To do this, we can go into our <code>App.js</code> file and change the <code>alt</code> attribute for the logo image. If you change it to <code>alt="loo"</code>, the test will fail and it'll give you some information.</p>
<p>In our case, though, I would like to change something on the test itself to make it fail and show you another expression that is handy to know. Instead of <code>expect(image).toBeInTheDocument();</code> we can also type <code>expect(image).not.toBeInTheDocument();</code>. So here we added a <code>not</code>. This basically reversed the logic, and now the test expects that no such image element exists.</p>
<p>If we now try to run the test, we will find the following error message in our terminal:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/10/image-127.png" alt="Image" width="600" height="400" loading="lazy">
<em>The error message we get</em></p>
<p>You can see that the test expected that there was no such element as <code>image</code>. However, it found something and therefore answered with an error message.</p>
<p>You don't have to make all your tests purposely fail to check if they work or not. I just wanted to show you what an actual failing test would look like.</p>
<h2 id="heading-how-to-create-some-additional-tests">✏️ How to Create Some Additional Tests</h2>
<p>Now we have finished with our first test and have some basic knowledge about what to expect when working with unit tests. Next, we will check out some other test examples.</p>
<p>In order to create a more realistic scenario, I will add one additional component, which we'll insert into the <code>App.js</code> component.</p>
<p>For this step, first we create a folder called <code>components</code> in our <code>src</code> folder. This is not a must, but it is common to structure your files like that.</p>
<p>Within the <code>components</code> folder, we create <code>List.js</code>. Our folder structure now looks like this:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/10/image-155.png" alt="Image" width="600" height="400" loading="lazy">
<em>current folder structure</em></p>
<p>Now, let's try to follow more of a test driven development (TDD) workflow, which is quite modern. I'm not necessarily sayint that this is always recommended. But a TDD approach is considered best practice by more and more people nowadays. </p>
<p>Of course, in this tutorial we'lre "only" talking about unit tests and not integration or end-to-end tests, but the general TDD workflow is similar for all three test categories.</p>
<p>So using this test driven development approach, we basically add tests and work on our application simultaneously. </p>
<p>To be more precise, we even create tests for single components and function parts before you even implement this tested logic in your application. </p>
<p>So there is a lot of going back and forth instead of creating all the tests at once at the end.</p>
<h3 id="heading-how-to-start-the-setup-for-listjs">How to Start the Setup for <code>List.js</code></h3>
<p>In our example, we have added the <code>List.js</code> component. Within this component, I would like to add a list with a button. When a user clicks on the button, it adds something to the list (an object with multiple keys and values).</p>
<p>In order to have some sort of frame, I will first add some <code>div</code> elements and similar stuff to our <code>List.js</code> component before we dive into the actual logic.</p>
<p>The <code>List.js</code> component now looks like this:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> List = <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>
      <span class="hljs-attr">style</span>=<span class="hljs-string">{{</span> <span class="hljs-attr">marginLeft:</span> "<span class="hljs-attr">auto</span>", <span class="hljs-attr">marginTop:</span> "<span class="hljs-attr">500px</span>", <span class="hljs-attr">marginBottom:</span> "<span class="hljs-attr">500px</span>" }}
    &gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>This is a list<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">ul</span> <span class="hljs-attr">style</span>=<span class="hljs-string">{{</span> <span class="hljs-attr">listStyleType:</span> "<span class="hljs-attr">none</span>" }}&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">li</span>&gt;</span>This is the first list entry<span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">ul</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">button</span>&gt;</span>This button can add a new entry to the list<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> List;
</code></pre>
<p>I also added the <code>List.js</code> component as a child to <code>App.js</code> (below all the other stuff in <code>App.js</code>) so it will be visible without changing anything else.</p>
<p>The result looks like this:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/10/image-156.png" alt="Image" width="600" height="400" loading="lazy">
<em>How it looks</em></p>
<p>This won't win you any style competitions but it's sufficient for our case.</p>
<h3 id="heading-setup-for-the-test-for-listjs">Setup for the test for <code>List.js</code></h3>
<p>Since we want to test while we are working on our component, I will now jump directly to the testing part even if nothing really happened in our <code>List.js</code> component in terms of click functions, for example.</p>
<p>We could create a new test file, but I would like to show you a new function we can use for our test suites specifically. This function is called <code>describe()</code> and can be handy for further structuring our tests.</p>
<p>To use <code>describe()</code>, we jump to <code>myFirstTesting.test.js</code> within <code>__tests__</code>. Right now, this file basically serves as one test suite for the test we specifically created for the <code>App.js</code> component. But I would like to have two test suites within this test file: one for the <code>App.js</code> tests and one for the <code>List.js</code> tests.</p>
<p>For this step, I'm using the <code>describe()</code> function, which basically works like the <code>test()</code> function in terms of parameters. </p>
<p>The first parameter will be a string, describing the respective test suite. The second parameter is a function, which then includes our <code>test()</code> functions with their stuff.</p>
<p>It will look like this in our case:</p>
<pre><code class="lang-javascript"><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> { render, screen } <span class="hljs-keyword">from</span> <span class="hljs-string">"@testing-library/react"</span>;

describe(<span class="hljs-string">"App.js component"</span>, <span class="hljs-function">() =&gt;</span> {
  test(<span class="hljs-string">"renders logo in App component"</span>, <span class="hljs-function">() =&gt;</span> {
    render(<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">App</span> /&gt;</span></span>);
    <span class="hljs-keyword">const</span> image = screen.getByAltText(<span class="hljs-string">"logo"</span>);
    expect(image).toBeInTheDocument();
  });
});

describe(<span class="hljs-string">"List.js component"</span>, <span class="hljs-function">() =&gt;</span> {
  test(<span class="hljs-string">"example"</span>, <span class="hljs-function">() =&gt;</span> {});
});
</code></pre>
<p>Before we jump into this new test, I would actually like to add something for the <code>App.js</code> testing. Since we have this <code>describe()</code> block, we could just add a new <code>test()</code> function – and this is what I'm going to do.</p>
<p>See the following newly added test described with <code>"renders List.js component in App.js"</code>:</p>
<pre><code class="lang-javascript"><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> { render, screen } <span class="hljs-keyword">from</span> <span class="hljs-string">"@testing-library/react"</span>;

describe(<span class="hljs-string">"App.js component"</span>, <span class="hljs-function">() =&gt;</span> {
  test(<span class="hljs-string">"renders logo in App component"</span>, <span class="hljs-function">() =&gt;</span> {
    render(<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">App</span> /&gt;</span></span>);
    <span class="hljs-keyword">const</span> image = screen.getByAltText(<span class="hljs-string">"logo"</span>);
    expect(image).toBeInTheDocument();
  });

   test(<span class="hljs-string">"renders List.js component in App.js"</span>, <span class="hljs-function">() =&gt;</span> {
    render(<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">App</span> /&gt;</span></span>);
    <span class="hljs-keyword">const</span> textInListJS = screen.getByText(<span class="hljs-regexp">/This is a list/i</span>);
    expect(textInListJS).toBeInTheDocument();
  });
});

describe(<span class="hljs-string">"List.js component"</span>, <span class="hljs-function">() =&gt;</span> {
  test(<span class="hljs-string">"example"</span>, <span class="hljs-function">() =&gt;</span> {});
});
</code></pre>
<p>So I'm rendering the <code>App.js</code> component and looking for text via a regular expression, which is part of the <code>List.js</code> component. This test can basically be understood as a render test for <code>List.js</code>. If <code>List.js</code> had not been able to be rendered within <code>App.js</code>, this test would not pass.</p>
<p>If you are confused that this works without separately using <code>render()</code> on the <code>List.js</code> component, remember that <code>List.js</code> is part of <code>App.js</code> and everything inside <code>App.js</code> will be rendered under typical conditions. If you tried to look for a text phrase that doesn't exist in <code>List.js</code>, this new test would fail. Right now, in our case, it passes.</p>
<p>I would also like to emphasize that you can have multiple <code>expect()</code> functions within the same test. Therefore, we also could have structured this new test like this:</p>
<pre><code class="lang-javascript"><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> { render, screen } <span class="hljs-keyword">from</span> <span class="hljs-string">"@testing-library/react"</span>;

describe(<span class="hljs-string">"App.js component"</span>, <span class="hljs-function">() =&gt;</span> {
  test(<span class="hljs-string">"renders logo in App component"</span>, <span class="hljs-function">() =&gt;</span> {
    render(<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">App</span> /&gt;</span></span>);
    <span class="hljs-keyword">const</span> image = screen.getByAltText(<span class="hljs-string">"logo"</span>);
    <span class="hljs-keyword">const</span> textInListJS = screen.getByText(<span class="hljs-regexp">/This is a list/i</span>);

    expect(image).toBeInTheDocument();
    expect(textInListJS).toBeInTheDocument();
  });
});

describe(<span class="hljs-string">"List.js component"</span>, <span class="hljs-function">() =&gt;</span> {
  test(<span class="hljs-string">"example"</span>, <span class="hljs-function">() =&gt;</span> {});
});
</code></pre>
<p>This would also work perfectly fine in our case. And this can be handy in situations where you test for some small elements which are directly connected to each other and have the same requirements to be rendered. </p>
<p>But keep in mind that in our case, we should have adjusted the description for this test. That's because <code>"renders logo in App component"</code> is not correct anymore if we are testing more than that in this test. So let's head back to the structure with two separate tests for now. But have in mind that you are able to work like this.</p>
<h3 id="heading-back-to-the-test-for-listjs">Back to the test for <code>List.js</code></h3>
<p>Now I would like to work with the second <code>describe()</code> block that we created a few moments ago, where we want to work with tests specifically for the <code>List.js</code> component.</p>
<p>Since we are aiming for a test-driven development approach, we should think about what we are going to build, write a test, and then implement that logic in our component.</p>
<p>We want to create a simple list in our <code>List.js</code> component. So there will be an array, which we will go through with <code>map()</code>. </p>
<p>For this approach, we will utilize the <code>useState()</code> hook so we have a state that can dynamically adjust (the array of list items). Our first test will be to check if the length of this array in its initial state is equal to <code>1</code>.</p>
<p>To find the items within this state, we will make use of the <code>getAllByTestId()</code> method, which allows us to search for specific elements we marked with a <code>data-testid</code> in the frontend. </p>
<p>The test with the description <code>"renders initial state of listData state"</code> that I created is now included:</p>
<pre><code class="lang-javascript"><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> { render, screen } <span class="hljs-keyword">from</span> <span class="hljs-string">"@testing-library/react"</span>;

describe(<span class="hljs-string">"App.js component"</span>, <span class="hljs-function">() =&gt;</span> {
  test(<span class="hljs-string">"renders logo in App component"</span>, <span class="hljs-function">() =&gt;</span> {
    render(<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">App</span> /&gt;</span></span>);
    <span class="hljs-keyword">const</span> image = screen.getByAltText(<span class="hljs-string">"logo"</span>);
    <span class="hljs-keyword">const</span> textInListJS = screen.getByText(<span class="hljs-regexp">/This is a list/i</span>);

    expect(image).toBeInTheDocument();
    expect(textInListJS).toBeInTheDocument();
  });
});

describe(<span class="hljs-string">"List.js component"</span>, <span class="hljs-function">() =&gt;</span> {
   test(<span class="hljs-string">"renders initial state of listData state"</span>, <span class="hljs-function">() =&gt;</span> {
    render(<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">List</span> /&gt;</span></span>);
    <span class="hljs-keyword">const</span> list = screen.getAllByTestId(<span class="hljs-string">"list-item"</span>);
    expect(list.length).toEqual(<span class="hljs-number">1</span>);
  });
});
</code></pre>
<p>Right now this test will fail, of course, because we haven't added any of this logic to the component yet.</p>
<p>So I adjusted the <code>List.js</code> component. It now looks like this:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> { useState } <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;

<span class="hljs-keyword">const</span> List = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">const</span> initialState = [
    {
      <span class="hljs-attr">id</span>: <span class="hljs-string">`<span class="hljs-subst">${<span class="hljs-keyword">new</span> <span class="hljs-built_in">Date</span>().getSeconds()}</span>`</span>,
      <span class="hljs-attr">description</span>: <span class="hljs-string">"This is something"</span>,
      <span class="hljs-attr">significance</span>: <span class="hljs-number">7</span>,
    },
  ];
  <span class="hljs-keyword">const</span> [listData, setListData] = useState(initialState);

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>
      <span class="hljs-attr">style</span>=<span class="hljs-string">{{</span> <span class="hljs-attr">marginLeft:</span> "<span class="hljs-attr">auto</span>", <span class="hljs-attr">marginTop:</span> "<span class="hljs-attr">500px</span>", <span class="hljs-attr">marginBottom:</span> "<span class="hljs-attr">500px</span>" }}
    &gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>This is a list<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">ul</span> <span class="hljs-attr">style</span>=<span class="hljs-string">{{</span> <span class="hljs-attr">listStyleType:</span> "<span class="hljs-attr">none</span>" }}&gt;</span>
        {listData.map((listItem) =&gt; {
          return (
            <span class="hljs-tag">&lt;<span class="hljs-name">li</span> <span class="hljs-attr">key</span>=<span class="hljs-string">{listItem.id}</span> <span class="hljs-attr">data-testid</span>=<span class="hljs-string">"list-item"</span>&gt;</span>
              {listItem.description}
            <span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
          );
        })}
      <span class="hljs-tag">&lt;/<span class="hljs-name">ul</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">button</span>&gt;</span>This button can add a new entry to the list<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> List;
</code></pre>
<p>Newly added was the <code>listData</code> state array via a <code>useState()</code> hook as well as an initialState, which I initialized with one object at the very top. I also made use of the <code>map()</code> function to go through this <code>listData</code> to create a list. </p>
<p>For each <code>&lt;li&gt;</code> element, I'm adding a key and a <code>data-testid</code>. This <code>data-testid</code> is the id we need for our test to find the respective elements.</p>
<p>On our actual application, we can see the <code>listItem.description</code> for this initial state:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/10/image-165.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>So by manually testing (actually looking at our application in the browser), we can see that this should work. If we now run our tests, we will also see that the test we created passed.</p>
<h3 id="heading-how-to-add-an-object-to-the-state">How to add an object to the state</h3>
<p>Now let's test something more exciting: the logic to add a new object to this <code>listData</code> state. Again, we will start by working on our test first before actually implementing the required logic within the React component.</p>
<p>With this newly added test described by <code>"adds a new data entry to listData after button click"</code>, our test file now looks like this:</p>
<pre><code class="lang-javascript"><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> List <span class="hljs-keyword">from</span> <span class="hljs-string">"../components/List"</span>;
<span class="hljs-keyword">import</span> { render, screen } <span class="hljs-keyword">from</span> <span class="hljs-string">"@testing-library/react"</span>;

<span class="hljs-keyword">import</span> userEvent <span class="hljs-keyword">from</span> <span class="hljs-string">"@testing-library/user-event"</span>;

describe(<span class="hljs-string">"App.js component"</span>, <span class="hljs-function">() =&gt;</span> {
  test(<span class="hljs-string">"renders logo in App component"</span>, <span class="hljs-function">() =&gt;</span> {
    render(<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">App</span> /&gt;</span></span>);
    <span class="hljs-keyword">const</span> image = screen.getByAltText(<span class="hljs-string">"logo"</span>);
    expect(image).toBeInTheDocument();
  });

  test(<span class="hljs-string">"renders List.js component in App.js"</span>, <span class="hljs-function">() =&gt;</span> {
    render(<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">App</span> /&gt;</span></span>);
    <span class="hljs-keyword">const</span> textInListJS = screen.getByText(<span class="hljs-regexp">/This is a list/i</span>);
    expect(textInListJS).toBeInTheDocument();
  });
});

describe(<span class="hljs-string">"List.js component"</span>, <span class="hljs-function">() =&gt;</span> {
  test(<span class="hljs-string">"renders initial state of listData state"</span>, <span class="hljs-function">() =&gt;</span> {
    render(<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">List</span> /&gt;</span></span>);
    <span class="hljs-keyword">const</span> list = screen.getAllByTestId(<span class="hljs-string">"list-item"</span>);
    expect(list.length).toEqual(<span class="hljs-number">1</span>);
  });

  test(<span class="hljs-string">"adds a new data entry to listData after button click"</span>, <span class="hljs-function">() =&gt;</span> {
    render(<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">List</span> /&gt;</span></span>);
    <span class="hljs-keyword">let</span> listItems = screen.getAllByTestId(<span class="hljs-string">"list-item"</span>);
    <span class="hljs-keyword">const</span> button = screen.getByRole(<span class="hljs-string">"button"</span>, {
      <span class="hljs-attr">name</span>: <span class="hljs-regexp">/This button can add a new entry to the list/i</span>,
    });

    expect(list.length).toEqual(<span class="hljs-number">1</span>);
    userEvent.click(button);
    list = screen.getAllByTestId(<span class="hljs-string">"list-item"</span>);
    expect(list.length).toEqual(<span class="hljs-number">2</span>);
  });
});
</code></pre>
<p>At the bottom, you can see this test. Therefore, we are first rendering the <code>List.js</code> component before looking for all available list items we assigned a test id to. You will see exactly where we put the test id in a few moments.</p>
<p>We also have to look for the button that we want to test to see if clicking on it adds something to the list. We do this with <code>getByRole()</code> which expects a role like <code>"button"</code> or <code>"table"</code> as a first parameter, for example (there are a bunch of different roles you can target). The second parameter is optional and is an object that can receive a value for the <code>name</code> key.</p>
<p><code>name</code> is pretty much the text content we have specifically for the button in this case. This optional second parameter is handy when you have multiple elements of type <code>"button"</code> in your component and want to get a specific button out of these.</p>
<p>After getting the <code>listItems</code> as well as the <code>button</code>, we start off with a first <code>expect()</code> to basically test the initial state. In this initial state, we expect to have only one list item.</p>
<p>Then, with the help of <code>userEvent</code>, we are going to click on the button. You could also use <code>fireEvent</code> for this situation (<code>userEvent</code> is still pretty new compared to the <code>fireEvent</code> approach). Both will work, and both are helpful for any action where you want to interact with specific elements. In this case, I want to simulate clicking on a button.</p>
<p>Tests generally follow a "arrange -&gt; act -&gt; assert" pattern that you can follow to structure them. Within the "arrange" part, you initialize and get all required elements. With the "act" part, you would simulate a mouse click (as in our case), for example. With "assert," you are checking if it all behaves like you expected it to.</p>
<p>In another case, you could simulate changing the value of an input field with <code>fireEvent.change(inputField, { target: { value: someValueVariable } })</code>, for example. Maybe you want to focus an input field or even drag an element - such actions can be simulated via <code>fireEvent</code> and <code>userEvent</code>.</p>
<p>After the button click, it again looked for all <code>listItems</code> since the current value of this variable would still be <code>1</code> from the previous initialization. As soon as this step is completed, it uses another <code>expect()</code> function to check if the length of the <code>listItems</code> array is now equal to <code>2</code> and not <code>1</code>.</p>
<p>Now that we have our test logic, let's jump back to the <code>List.js</code> component and implement the corresponding logic:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> { useState } <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;

<span class="hljs-keyword">const</span> List = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">const</span> initialState = [
    {
      <span class="hljs-attr">id</span>: <span class="hljs-string">`<span class="hljs-subst">${<span class="hljs-keyword">new</span> <span class="hljs-built_in">Date</span>().getSeconds()}</span>`</span>,
      <span class="hljs-attr">description</span>: <span class="hljs-string">"This is something"</span>,
      <span class="hljs-attr">significance</span>: <span class="hljs-number">7</span>,
    },
  ];
  <span class="hljs-keyword">const</span> [listData, setListData] = useState(initialState);

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>
      <span class="hljs-attr">style</span>=<span class="hljs-string">{{</span> <span class="hljs-attr">marginLeft:</span> "<span class="hljs-attr">auto</span>", <span class="hljs-attr">marginTop:</span> "<span class="hljs-attr">500px</span>", <span class="hljs-attr">marginBottom:</span> "<span class="hljs-attr">500px</span>" }}
    &gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>This is a list<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">ul</span> <span class="hljs-attr">style</span>=<span class="hljs-string">{{</span> <span class="hljs-attr">listStyleType:</span> "<span class="hljs-attr">none</span>" }}&gt;</span>
        {listData.map((listItem) =&gt; {
          return (
            <span class="hljs-tag">&lt;<span class="hljs-name">li</span> <span class="hljs-attr">key</span>=<span class="hljs-string">{listItem.id}</span> <span class="hljs-attr">data-testid</span>=<span class="hljs-string">"list-item"</span>&gt;</span>
              {listItem.description}
            <span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
          );
        })}
      <span class="hljs-tag">&lt;/<span class="hljs-name">ul</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">button</span>
        <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span>
          setListData([
            ...listData,
            { id: 999, description: "999", significance: 100 },
          ])
        }
      &gt;
        This button can add a new entry to the list
      <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> List;
</code></pre>
<p>The only part that changed is the button at the bottom of this file. So I added a function that gets invoked when clicking on this button. The function then adjusts the current state of <code>listData</code> which is responsible for rendering our list. I copied the current state with a spread operator and then added another hard-coded object as the new entry for this list. </p>
<p>Of course, there are more creative ways to fill in the values for the <code>id</code>, <code>description</code>, and <code>significance</code> keys.</p>
<p>I would also like to emphasize that you have the opportunity to create a separate function outside of the <code>return()</code> and access this function like this: <code>onClick={separateFunctionToAddObjectToState}</code> on the same button element. This would also work without having to render something additional within the test.</p>
<p>If we now run our test, we will see that it passes. If you try to still expect a length of <code>1</code> after clicking on the button, the test will fail like this:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/10/image-192.png" alt="Image" width="600" height="400" loading="lazy">
<em>error alert for length of 1</em></p>
<p>So it actually does what it is supposed to do.</p>
<h2 id="heading-setup-for-redux">🔧 Setup for Redux</h2>
<p>After working with local states via the <code>useState()</code> hook, I would like to work on the same files and adjust them for Redux (or the Redux Toolkit, to be precise). </p>
<p>I'm not going to dive deep into what Redux actually is and what every term like <code>action</code>, <code>store</code>, or <code>reducer</code> means in detail – since this would be worthy of a whole new guide. If you want that, you can <a target="_blank" href="https://www.freecodecamp.org/news/redux-for-beginners/">read this guide to Redux basics</a>.</p>
<p>Instead, I will give just a quick rundown and show which files I'm adding and editing. Then I'll talk about how to handle the <code>render()</code> method, including the Redux store provider, which can cause a lot of frustration when testing if you don't know about it.</p>
<h3 id="heading-overall-folder-structure">Overall folder structure:</h3>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/11/image-14.png" alt="Image" width="600" height="400" loading="lazy">
<em>current overall folder structure with the React Redux Toolkit</em></p>
<p>You can see that I added an <code>app</code> (for the store) as well as a <code>features</code> (for the slice) folder.</p>
<h3 id="heading-updated-indexjs-file">Updated <code>index.js</code> file:</h3>
<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/client"</span>;
<span class="hljs-keyword">import</span> <span class="hljs-string">"./index.css"</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> reportWebVitals <span class="hljs-keyword">from</span> <span class="hljs-string">"./reportWebVitals"</span>;
<span class="hljs-keyword">import</span> { Provider } <span class="hljs-keyword">from</span> <span class="hljs-string">"react-redux"</span>;
<span class="hljs-keyword">import</span> store <span class="hljs-keyword">from</span> <span class="hljs-string">"./app/store"</span>;

<span class="hljs-keyword">const</span> root = ReactDOM.createRoot(<span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">"root"</span>));
root.render(
  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">React.StrictMode</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">Provider</span> <span class="hljs-attr">store</span>=<span class="hljs-string">{store}</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">App</span> /&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">Provider</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">React.StrictMode</span>&gt;</span></span>
);
</code></pre>
<p>You can see that I added a <code>provider</code> and wrapped it around the application so we have access to the store from anywhere.</p>
<h3 id="heading-created-storejs-file">Created <code>store.js</code> file:</h3>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> { configureStore } <span class="hljs-keyword">from</span> <span class="hljs-string">"@reduxjs/toolkit"</span>;
<span class="hljs-keyword">import</span> { ListSlice } <span class="hljs-keyword">from</span> <span class="hljs-string">"../features/ListSlice"</span>;

<span class="hljs-keyword">const</span> store = configureStore({
  <span class="hljs-attr">reducer</span>: {
    <span class="hljs-attr">listReducers</span>: listSlice.reducer,
  },
});

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> store;
</code></pre>
<p>In this file, we have created the required store for the Redux implementation.</p>
<h3 id="heading-created-listslicejs-file-in-features-folder">Created <code>ListSlice.js</code> file in <code>features</code> folder:</h3>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> { createSlice } <span class="hljs-keyword">from</span> <span class="hljs-string">"@reduxjs/toolkit"</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> initialState = {
  <span class="hljs-attr">value</span>: [
    {
      <span class="hljs-attr">id</span>: <span class="hljs-string">`<span class="hljs-subst">${<span class="hljs-keyword">new</span> <span class="hljs-built_in">Date</span>().getSeconds()}</span>`</span>,
      <span class="hljs-attr">description</span>: <span class="hljs-string">"This is something"</span>,
      <span class="hljs-attr">significance</span>: <span class="hljs-number">7</span>,
    },
  ],
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> ListSlice = createSlice({
  <span class="hljs-attr">name</span>: <span class="hljs-string">"listReducers"</span>,
  initialState,
  <span class="hljs-attr">reducers</span>: {},
});

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> { } = ListSlice.actions;
<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> ListSlice.reducer;
</code></pre>
<p>Here we have created the slice that we added to the store. Notice that I haven't added any reducer yet. This slice just contains the current corresponding state.</p>
<h3 id="heading-updated-listjs-file-in-components-folder">Updated <code>List.js</code> file in <code>components</code> folder:</h3>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> { useSelector, useDispatch } <span class="hljs-keyword">from</span> <span class="hljs-string">"react-redux"</span>;

<span class="hljs-keyword">const</span> List = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">const</span> listState = useSelector(<span class="hljs-function">(<span class="hljs-params">state</span>) =&gt;</span> state.listReducers.value);
  <span class="hljs-keyword">const</span> dispatch = useDispatch(); <span class="hljs-comment">// not used right now</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">style</span>=<span class="hljs-string">{{</span> <span class="hljs-attr">marginLeft:</span> "<span class="hljs-attr">auto</span>", <span class="hljs-attr">marginTop:</span> "<span class="hljs-attr">500px</span>", <span class="hljs-attr">marginBottom:</span> "<span class="hljs-attr">500px</span>" }}
    &gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>This is a list<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">ul</span> <span class="hljs-attr">style</span>=<span class="hljs-string">{{</span> <span class="hljs-attr">listStyleType:</span> "<span class="hljs-attr">none</span>" }}&gt;</span>
        {listState.map((listItem) =&gt; {
          return (
            <span class="hljs-tag">&lt;<span class="hljs-name">li</span> <span class="hljs-attr">key</span>=<span class="hljs-string">{listItem.id}</span> <span class="hljs-attr">data-testid</span>=<span class="hljs-string">"list-item"</span>&gt;</span>
              {listItem.description}
            <span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
          );
        })}
      <span class="hljs-tag">&lt;/<span class="hljs-name">ul</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">button</span>&gt;</span>This button can add a new entry to the list<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> List;
</code></pre>
<p>On the frontend, we swapped the local state (using the useState hook) with the Redux state (using the useSelctor hook). You'll also see that I adjusted the button. There is no click function anymore (we will get back to that later on).</p>
<h2 id="heading-how-to-perform-testing-with-the-react-redux-toolkit">🔎 How to Perform Testing with the React Redux Toolkit</h2>
<p>Now that we have updated and created all the necessary files for the React Redux Toolkit logic, I would like to run a quick test of all the tests we previously created.</p>
<p>The result is that all tests have failed:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/11/image-15.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Keep in mind that I adjusted the button in <code>List.js</code>, for example, so the corresponding test was expected to fail. However, not all tests should have failed.</p>
<p>The test environments are working in their own world. They don't know if you wrap a provider somewhere in <code>index.js</code> and enable Redux logic. So the tests are still trying to make the rendering work without Redux. But our application now depends on Redux to manage our main state.</p>
<p>This means that we have to adjust the <code>render()</code> function so that this function is actually aligned with the Redux logic.</p>
<p>A method to make this work is to introduce a helper function, which we will store in a new folder called <code>utils</code>. The file will be called <code>utils-for-tests.jsx</code>. The content will look like this:</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> { render } <span class="hljs-keyword">from</span> <span class="hljs-string">"@testing-library/react"</span>;
<span class="hljs-keyword">import</span> { configureStore } <span class="hljs-keyword">from</span> <span class="hljs-string">"@reduxjs/toolkit"</span>;
<span class="hljs-keyword">import</span> { Provider } <span class="hljs-keyword">from</span> <span class="hljs-string">"react-redux"</span>;
<span class="hljs-comment">// As a basic setup, import your same slice reducers</span>
<span class="hljs-keyword">import</span> { ListSlice } <span class="hljs-keyword">from</span> <span class="hljs-string">"../features/ListSlice"</span>;

<span class="hljs-keyword">export</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">renderWithProviders</span>(<span class="hljs-params">
  ui,
  {
    preloadedState = {},
    <span class="hljs-regexp">//</span> Automatically create a store instance if no store was passed in
    store = configureStore({
      reducer: { listReducers: ListSlice.reducer },
      preloadedState,
    }),
    ...renderOptions
  } = {}
</span>) </span>{
  <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Wrapper</span>(<span class="hljs-params">{ children }</span>) </span>{
    <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">Provider</span> <span class="hljs-attr">store</span>=<span class="hljs-string">{store}</span>&gt;</span>{children}<span class="hljs-tag">&lt;/<span class="hljs-name">Provider</span>&gt;</span></span>;
  }

  <span class="hljs-comment">// Return an object with the store and all of RTL's query functions</span>
  <span class="hljs-keyword">return</span> { store, ...render(ui, { <span class="hljs-attr">wrapper</span>: Wrapper, ...renderOptions }) };
}
</code></pre>
<p>This code information can be found in the <a target="_blank" href="https://redux.js.org/usage/writing-tests">Redux documentation</a>. You can almost copy and paste it all for your application.</p>
<p>But you have to adjust the slices that are used in there. Since in our application there is only the <code>ListSlice</code> we don't have much to add. Just import that and update the content of the <code>configureStore()</code> function, like we managed it in our <code>store.js</code> file.</p>
<p>This step is necessary to basically mock the entire Redux logic and put it together into one new <code>render()</code> function.</p>
<p>With that, we can import this new function into our test files (<code>App.test.js</code> and <code>myFirstTesting.test.js</code>) and then replace all <code>render()</code> functions with <code>renderWithProviders()</code>. The <code>App.test.js</code> file, for example, now looks like this:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> { screen } <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> { renderWithProviders } <span class="hljs-keyword">from</span> <span class="hljs-string">"../utils/utils-for-tests"</span>;

test(<span class="hljs-string">"renders learn react link"</span>, <span class="hljs-function">() =&gt;</span> {
  renderWithProviders(<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">App</span> /&gt;</span></span>);
  <span class="hljs-keyword">const</span> linkElement = screen.getByText(<span class="hljs-regexp">/learn react/i</span>);
  expect(linkElement).toBeInTheDocument();
});
</code></pre>
<p>There is not much more to do! If we now run our tests again (and comment out this one test, which is going to fail regardless because the button logic is not active anymore), it will work again.</p>
<h3 id="heading-slice-testing">Slice testing</h3>
<p>Another exciting part about testing with Redux is testing the slices. If you created your application with the React Redux Toolkit template, then you will be provided with some corresponding tests.</p>
<p>For our case, I also want to implement a new test file where we will specifically test <code>ListSlice.js</code> and its corresponding Redux logic.</p>
<p>For this slice, we have to import the slice and the corresponding reducers we want to test. To start, I will import the slice and test if it gets initialized with the initialState.</p>
<p>This is actually not the TDD approach since we already manually tested this part. Netherless, I would like to implement an automatic test as well:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> ListSlice, { initialState } <span class="hljs-keyword">from</span> <span class="hljs-string">"../features/ListSlice"</span>;

describe(<span class="hljs-string">"tests for ListSlice"</span>, <span class="hljs-function">() =&gt;</span> {
  test(<span class="hljs-string">"initialize slice with initialValue"</span>, <span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">const</span> listSliceInit = ListSlice(initialState, { <span class="hljs-attr">type</span>: <span class="hljs-string">"unknown"</span> });
    expect(listSliceInit).toBe(initialState);
  });
});
</code></pre>
<p>Notice that I'm using <code>.spec</code> instead of <code>.test</code>. This doesn't matter. You can choose either. In this case, I'm going with <code>.spec</code> to remind you that this is also a viable option.</p>
<p>Also remember that we exported the initialState within our slice (see above). So we are able to import it here.</p>
<p>Other than that, we are already familiar with the <code>describe()</code> environment, which includes one <code>test()</code>. Within this test, I'm initializing a variable <code>listSliceInit</code>, which will hold the value we are receiving after the slice operation took place.</p>
<p>For this operation, we use <code>ListSlice</code> as a function and include the initial state as the first argument (in this case <code>initialState</code>). The second argument will be a reducer in most cases. </p>
<p>But in this case, we don't need to enter a reducer. Instead, we are using an object with <code>type: "unknown"</code>. This is basically telling the function that we don't want to perform any additional operations.</p>
<p>Therefore, <code>listSliceInit</code> should now include our state value, which includes an array with one entry. The corresponding test will pass.</p>
<p>To force a failure, I'm entering <code>expect(listSliceInit).toBe({ value: [] });</code> instead of the previous <code>expect()</code> function. So instead of our <code>initialState</code> we are expecting it to have an empty array. Now our test environment will tell us the following:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/11/image-24.png" alt="Image" width="600" height="400" loading="lazy">
<em>failing test</em></p>
<p>So it actually tells us what exactly it expected – in this case, it expected the <code>initialState</code>.</p>
<p>Next, I would like to test a reducer. However, we haven't added one yet. So I will adjust <code>ListSlice</code> in the <code>ListSlice.js</code> file like this:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> ListSlice = createSlice({
  <span class="hljs-attr">name</span>: <span class="hljs-string">"listReducers"</span>,
  initialState,
  <span class="hljs-attr">reducers</span>: {
    <span class="hljs-attr">testAddReducer</span>: <span class="hljs-function">(<span class="hljs-params">state, action</span>) =&gt;</span> {
      state.value.push(action.payload);
    },
  },
});
</code></pre>
<p>Thus, I added <code>testAddReducer()</code>, which is responsible for pushing one additional element to the current state value, which it receives via an input from the dispatch (through <code>action.payload</code>).</p>
<p>If we now jump back to the <code>listSlice.spec.js</code> file, I'm adding another unit test:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> ListSlice, { initialState, testAddReducer } <span class="hljs-keyword">from</span> <span class="hljs-string">"../features/ListSlice"</span>;

describe(<span class="hljs-string">"tests for ListSlice"</span>, <span class="hljs-function">() =&gt;</span> {
  test(<span class="hljs-string">"initialize slice with initialValue"</span>, <span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">const</span> listSliceInit = ListSlice(initialState, { <span class="hljs-attr">type</span>: <span class="hljs-string">"unknown"</span> });
    expect(listSliceInit).toBe(initialState);
  });

  test(<span class="hljs-string">"testAddReducer"</span>, <span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">const</span> testData = {
      <span class="hljs-attr">id</span>: <span class="hljs-string">`<span class="hljs-subst">${<span class="hljs-keyword">new</span> <span class="hljs-built_in">Date</span>().getSeconds()}</span>`</span>,
      <span class="hljs-attr">description</span>: <span class="hljs-string">"This is for the test section"</span>,
      <span class="hljs-attr">significance</span>: <span class="hljs-number">5</span>,
    };

    <span class="hljs-keyword">const</span> afterReducerOperation = ListSlice(
      initialState,
      testAddReducer(testData)
    );

    expect(afterReducerOperation).toStrictEqual({
      <span class="hljs-attr">value</span>: [initialState.value.at(<span class="hljs-number">0</span>), testData],
    });
  });
});
</code></pre>
<p>I added the test for <code>testAddReducer</code>. You can see that I imported the reducer as well.</p>
<p>Firstly, I'm initializing a new variable, <code>testData</code>, which contains the data I would like to push to the current state.</p>
<p>After that, we follow the same structure as before with <code>afterReducerOperation</code>. But instead of this <code>type: "unknown"</code> stuff, we add the reducer as the second argument. This receives the <code>testData</code> as a parameter – basically like you would see it in a dispatch.</p>
<p>Then, we expect this <code>afterReducerOperation</code> variable to be strictly equal to the value of an array, which has two entries: <code>initialState.value.at(0)</code> (the first entry of our <code>initialState</code>) and <code>testData</code>. And this test will pass like we actually expected it.</p>
<p>If we are trying to enter some other entries or change the current ones, you would be able to see this test failing:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/11/image-25.png" alt="Image" width="600" height="400" loading="lazy">
<em>forced error: I added a third entry to the array</em></p>
<h3 id="heading-how-to-make-the-button-click-function-work-again">How to make the button click function work again</h3>
<p>Remember the button click within the <code>List.js</code> component (for adding something to the <code>listData</code> state) that wasn't working anymore after we changed to the Redux setup? Let's quickly update that to make that logic work within a Redux environment for the sake of completeness. Since we have the required reducer now, this will be an easy step.</p>
<p>To make the test work again, which added a new element to the state, we have to adjust it a little on the frontend to implement the Redux logic. (Previously we used the useState hook for a local state.)</p>
<p>For this step, we are making use of the <code>dispatch()</code> function in order to reach out to the <code>testAddReducer</code>:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> { useSelector, useDispatch } <span class="hljs-keyword">from</span> <span class="hljs-string">"react-redux"</span>;
<span class="hljs-keyword">import</span> { testAddReducer } <span class="hljs-keyword">from</span> <span class="hljs-string">"../features/ListSlice"</span>;

<span class="hljs-keyword">const</span> List = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">const</span> listState = useSelector(<span class="hljs-function">(<span class="hljs-params">state</span>) =&gt;</span> state.listReducers.value);
  <span class="hljs-keyword">const</span> dispatch = useDispatch();

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>
      <span class="hljs-attr">style</span>=<span class="hljs-string">{{</span> <span class="hljs-attr">marginLeft:</span> "<span class="hljs-attr">auto</span>", <span class="hljs-attr">marginTop:</span> "<span class="hljs-attr">500px</span>", <span class="hljs-attr">marginBottom:</span> "<span class="hljs-attr">500px</span>" }}
    &gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>This is a list<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">ul</span> <span class="hljs-attr">style</span>=<span class="hljs-string">{{</span> <span class="hljs-attr">listStyleType:</span> "<span class="hljs-attr">none</span>" }}&gt;</span>
        {listState.map((listItem) =&gt; {
          return (
            <span class="hljs-tag">&lt;<span class="hljs-name">li</span> <span class="hljs-attr">key</span>=<span class="hljs-string">{listItem.id}</span> <span class="hljs-attr">data-testid</span>=<span class="hljs-string">"list-item"</span>&gt;</span>
              {listItem.description}
            <span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
          );
        })}
      <span class="hljs-tag">&lt;/<span class="hljs-name">ul</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">button</span>
        <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span>
          dispatch(
            testAddReducer({
              id: `${new Date().getSeconds()}1`,
              description: "This is added",
              significance: 5,
            })
          )
        }
      &gt;
        This button can add a new entry to the list
      <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> List;
</code></pre>
<p>Besides the button logic, nothing else has changed in this file.</p>
<p>In the corresponding test (within <code>myFirstTesting.test.js</code> nothing has changed), if we now test everything – including this updated test – we will see that everything works fine:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/11/image-34.png" alt="Image" width="600" height="400" loading="lazy">
<em>final test run</em></p>
<p>And that's pretty much it for fundamental slice and general Redux unit testing!</p>
<h2 id="heading-outlook-for-advanced-testing">🔭 Outlook for Advanced Testing</h2>
<p>There are different topics like <a target="_blank" href="https://redux-toolkit.js.org/api/createAsyncThunk">thunks</a> (or <a target="_blank" href="https://redux-toolkit.js.org/rtk-query/overview">RTK Query</a> as an alternative) which could also be tested. But I'm considering this as an advanced topic, and it would take some more time to explain these processes.</p>
<p>If you are not aiming to be an expert in testing at this point, the topics we discussed for unit tests in Redux in this tutorial should be sufficient for you.</p>
<p>Generally speaking, I would recommend diving deeper into so-called mocks, spies, and also snapshots. These will be helpful if you are working on some other more advanced tests. </p>
<p>The stuff with <code>renderWithProvider()</code> is basically based on such a mock – there, we artificially created a store with reducers and a provider to create this new <code>render()</code> function. So mocks are especially helpful for any third-party libraries, for example. </p>
<p>As I said, though, mocks, spies, and snapshots are more of an advanced topic to wrap your head around.</p>
<h2 id="heading-further-learning-opportunities">📣 Further Learning Opportunities</h2>
<p>I recently started to work on my first <a target="_blank" href="https://www.udemy.com/user/matthes-bar/">free Udemy course</a>. While this first free course covers the basics of the React Redux Toolkit with German audio and manually added English subtitles, I'm also planning to publish other Udemy courses completely in English in the future. </p>
<p>I would really appreciate it if you would check out this cost-free course in order to provide me with some feedback.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Test Your Express.js and Mongoose Apps with Jest and SuperTest ]]>
                </title>
                <description>
                    <![CDATA[ By Rakesh Potnuru Testing is a vital part of software development. The sooner you start testing, the better.  In this article, I'll show you how to write tests for your NodeJs/ExpressJS and MongoDB/Mongoose applications with Jest and Supertest. Let's... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-test-in-express-and-mongoose-apps/</link>
                <guid isPermaLink="false">66d460c9787a2a3b05af43f6</guid>
                
                    <category>
                        <![CDATA[ Express JS ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Jest ]]>
                    </category>
                
                    <category>
                        <![CDATA[ mongoose ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Software Testing ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Testing ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Tue, 27 Sep 2022 23:26:16 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2022/09/how-to-write-tests.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Rakesh Potnuru</p>
<p>Testing is a vital part of software development. The sooner you start testing, the better. </p>
<p>In this article, I'll show you how to write tests for your NodeJs/ExpressJS and MongoDB/Mongoose applications with <strong>Jest</strong> and <strong>Supertest</strong>.</p>
<h2 id="heading-lets-get-started">Let's get started</h2>
<p>First let's set up a demo Express.js app.</p>
<p>Let's say we are building a backend REST API for an eCommerce application.</p>
<p>This app should:</p>
<ul>
<li>Get all the products</li>
<li>Get a product by id</li>
<li>Add product(s) to the database</li>
<li>Delete product(s) from the database</li>
<li>Update product information</li>
</ul>
<h2 id="heading-expressjs-app-set-up">Express.js App Set Up</h2>
<h3 id="heading-step-1-project-set-up">Step 1: Project set up</h3>
<p>First, create a folder and start a blank application with <code>npm</code>.</p>
<pre><code class="lang-bash">npm init
</code></pre>
<p>Fill all the details it asks for.</p>
<p>Then, install <code>express</code>, <code>mongoose</code>, <code>axios</code> and <code>dotenv</code> with the following command:</p>
<pre><code class="lang-bash">npm i express mongoose axios dotenv
</code></pre>
<p>Here's a link to the <a target="_blank" href="https://github.com/itsrakeshhq/jest-tests-demo/blob/a1725cb3379f78a03cf8d3d4cfa22127469e8b50/package.json">package.json</a> on my GitHub.</p>
<h3 id="heading-step-2-create-the-boilerplate">Step 2: Create the boilerplate</h3>
<p>Let's create all the folders and files and then fill them with some boilerplate code.</p>
<p>This is how your folder hierarchy should look:</p>
<pre><code class="lang-bash">.
├── controllers
│   └── product.controller.js
├── models
│   └── product.model.js
├── routes
│   └── product.route.js
├── package-lock.json
├── package.json
├── .env
├── app.js
└── server.js
</code></pre>
<p>Use these files' code by copying and pasting. Analyze the code and flow as best you can.</p>
<ul>
<li><code>[product.controller.js](https://github.com/itsrakeshhq/jest-tests-demo/blob/main/controllers/product.controller.js)</code></li>
<li><code>[product.model.js](https://github.com/itsrakeshhq/jest-tests-demo/blob/main/models/product.model.js)</code></li>
<li><code>[product.route.js](https://github.com/itsrakeshhq/jest-tests-demo/blob/main/routes/product.route.js)</code></li>
<li><code>[app.js](https://github.com/itsrakeshhq/jest-tests-demo/blob/main/app.js)</code> </li>
<li><code>[server.js](https://github.com/itsrakeshhq/jest-tests-demo/blob/main/server.js)</code></li>
</ul>
<h3 id="heading-step-3-database-setup">Step 3: Database setup</h3>
<p>I advise using two databases for a project—one for testing, the other for development. But just one database will be sufficient for learning purposes.</p>
<p>First, create a <a target="_blank" href="https://mongodb.com">MongoDB</a> account or log in.</p>
<p>Then create a new project. Give it a name and press the <strong>Next</strong> button.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/09/Screenshot-2022-09-26-205148.png" alt="Naming the project" width="600" height="400" loading="lazy">
<em>Naming the project</em></p>
<p>Then click <strong>Create Project</strong> after that.</p>
<p>We must create a database in the following window by selecting a cloud provider, a location, and specs. So press <strong>Build a Database</strong> to get going.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/09/Screenshot-2022-09-26-205911.png" alt="Build a database" width="600" height="400" loading="lazy">
<em>Build a database</em></p>
<p>Choose "Shared" because it is sufficient for learning purposes. And then click <strong>Create</strong>.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/09/Screenshot-2022-09-26-211701.png" alt="Choose a deployment option" width="600" height="400" loading="lazy">
<em>Choose a deployment option</em></p>
<p>Next, select "aws" as your cloud provider and the region that is closest to you. Following your selection, click <strong>Create Cluster</strong>.</p>
<p>The cluster's formation will take some time. Create a user to access your database in the meanwhile.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/09/Screenshot-2022-09-26-212537.png" alt="Create Superuser" width="600" height="400" loading="lazy">
<em>Create Superuser</em></p>
<p>Choose "My Local Environment" because we are developing our application. You can then add an IP addresses. To conclude, click <strong>Close</strong>.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/09/Screenshot-2022-09-26-213347.png" alt="Add IP addresses" width="600" height="400" loading="lazy">
<em>Add IP addresses</em></p>
<p>You will receive a URI string after the database is set up, which we'll use to connect to the database. The string appears as follows:</p>
<pre><code class="lang-bash">mongodb+srv://&lt;YOUR_USERNAME&gt;:&lt;YOUR_PASSWORD&gt;@&lt;YOUR_CLUSTER_URL&gt;/&lt;DATABASE_NAME&gt;?retryWrites=<span class="hljs-literal">true</span>&amp;w=majority
</code></pre>
<p>Put this string in the <code>.env</code> file.</p>
<pre><code class="lang-bash">MONGODB_URI=your database string
</code></pre>
<p>Now we're ready to start testing our app.</p>
<h2 id="heading-how-to-write-tests-with-jest-and-supertest">How to Write Tests with Jest and SuperTest</h2>
<h3 id="heading-step-1-install-packages">Step 1: Install packages</h3>
<p>You need three npm packages to begin writing tests: <code>jest</code>, <code>supertest</code>, and <code>cross-env</code>. You can install them like this:</p>
<pre><code class="lang-bash">npm i jest supertest cross-env
</code></pre>
<ul>
<li><code>jest</code>: Jest is a framework for testing JavaScript code. Unit testing is the main usage of it.</li>
<li><code>supertest</code>: Using Supertest, we can test endpoints and routes on HTTP servers.</li>
<li><code>cross-env</code>: You can set environmental variables inline within a command using cross-env.</li>
</ul>
<h3 id="heading-step-2-add-test-script">Step 2: Add test script</h3>
<p>Open your <code>package.json</code> file and add the test script to the scripts.</p>
<pre><code class="lang-json"><span class="hljs-string">"scripts"</span>: {
    <span class="hljs-attr">"test"</span>: <span class="hljs-string">"cross-env NODE_ENV=test jest --testTimeout=5000"</span>,
    <span class="hljs-attr">"start"</span>: <span class="hljs-string">"node server.js"</span>,
    <span class="hljs-attr">"dev"</span>: <span class="hljs-string">"nodemon server.js"</span>
},
</code></pre>
<p>In this case, we're using <code>cross-env</code> to set environment variables, <code>jest</code> to execute test suites, and <code>testTimeout</code> is set to <code>5000</code> because certain requests might take a while to finish.</p>
<h3 id="heading-step-3-start-writing-tests">Step 3: Start writing tests</h3>
<p>First, create a folder called <code>tests</code> at the application's root, and then create a file there called <code>product.test.js</code>. Jest searches for the folder <code>tests</code> at the project's root when you do <code>npm run test</code>. As a result, you must place your test files in the <code>tests</code> folder.</p>
<p>Next, import the <code>supertest</code> and <code>mongoose</code> packages into the test file.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> mongoose = <span class="hljs-built_in">require</span>(<span class="hljs-string">"mongoose"</span>);
<span class="hljs-keyword">const</span> request = <span class="hljs-built_in">require</span>(<span class="hljs-string">"supertest"</span>);
</code></pre>
<p>Import <code>dotenv</code> to load environment variables, and import <code>app.js</code> as that is where our application starts.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> mongoose = <span class="hljs-built_in">require</span>(<span class="hljs-string">"mongoose"</span>);
<span class="hljs-keyword">const</span> request = <span class="hljs-built_in">require</span>(<span class="hljs-string">"supertest"</span>);
<span class="hljs-keyword">const</span> app = <span class="hljs-built_in">require</span>(<span class="hljs-string">"../app"</span>);

<span class="hljs-built_in">require</span>(<span class="hljs-string">"dotenv"</span>).config();
</code></pre>
<p>You'll need to connect and disconnect the database before and after each test (because we don't require the database once testing is complete).</p>
<pre><code class="lang-javascript"><span class="hljs-comment">/* Connecting to the database before each test. */</span>
beforeEach(<span class="hljs-keyword">async</span> () =&gt; {
  <span class="hljs-keyword">await</span> mongoose.connect(process.env.MONGODB_URI);
});

<span class="hljs-comment">/* Closing database connection after each test. */</span>
afterEach(<span class="hljs-keyword">async</span> () =&gt; {
  <span class="hljs-keyword">await</span> mongoose.connection.close();
});
</code></pre>
<p>Now you can write your first unit test.</p>
<pre><code class="lang-javascript">describe(<span class="hljs-string">"GET /api/products"</span>, <span class="hljs-function">() =&gt;</span> {
  it(<span class="hljs-string">"should return all products"</span>, <span class="hljs-keyword">async</span> () =&gt; {
    <span class="hljs-keyword">const</span> res = <span class="hljs-keyword">await</span> request(app).get(<span class="hljs-string">"/api/products"</span>);
    expect(res.statusCode).toBe(<span class="hljs-number">200</span>);
    expect(res.body.length).toBeGreaterThan(<span class="hljs-number">0</span>);
  });
});
</code></pre>
<p>In the above code, </p>
<ul>
<li>We use <code>describe</code> to describe the unit test. Even though it is not required, it will be useful to identify tests in test results.</li>
<li>In <code>it</code>, we write the actual test code. Tell what the test performs in the first argument, and then in the second argument, write a callback function that contains the test code.</li>
<li>In the callback function, the request is sent to the endpoint first, and the expected and actual responses are then compared. The test passes if both answers match, else, it fails. ✨ As simple as that ✨.</li>
</ul>
<p>You can write tests for all the endpoints in the same manner.</p>
<pre><code class="lang-javascript">describe(<span class="hljs-string">"GET /api/products/:id"</span>, <span class="hljs-function">() =&gt;</span> {
  it(<span class="hljs-string">"should return a product"</span>, <span class="hljs-keyword">async</span> () =&gt; {
    <span class="hljs-keyword">const</span> res = <span class="hljs-keyword">await</span> request(app).get(
      <span class="hljs-string">"/api/products/6331abc9e9ececcc2d449e44"</span>
    );
    expect(res.statusCode).toBe(<span class="hljs-number">200</span>);
    expect(res.body.name).toBe(<span class="hljs-string">"Product 1"</span>);
  });
});

describe(<span class="hljs-string">"POST /api/products"</span>, <span class="hljs-function">() =&gt;</span> {
  it(<span class="hljs-string">"should create a product"</span>, <span class="hljs-keyword">async</span> () =&gt; {
    <span class="hljs-keyword">const</span> res = <span class="hljs-keyword">await</span> request(app).post(<span class="hljs-string">"/api/products"</span>).send({
      <span class="hljs-attr">name</span>: <span class="hljs-string">"Product 2"</span>,
      <span class="hljs-attr">price</span>: <span class="hljs-number">1009</span>,
      <span class="hljs-attr">description</span>: <span class="hljs-string">"Description 2"</span>,
    });
    expect(res.statusCode).toBe(<span class="hljs-number">201</span>);
    expect(res.body.name).toBe(<span class="hljs-string">"Product 2"</span>);
  });
});

describe(<span class="hljs-string">"PUT /api/products/:id"</span>, <span class="hljs-function">() =&gt;</span> {
  it(<span class="hljs-string">"should update a product"</span>, <span class="hljs-keyword">async</span> () =&gt; {
    <span class="hljs-keyword">const</span> res = <span class="hljs-keyword">await</span> request(app)
      .patch(<span class="hljs-string">"/api/products/6331abc9e9ececcc2d449e44"</span>)
      .send({
        <span class="hljs-attr">name</span>: <span class="hljs-string">"Product 4"</span>,
        <span class="hljs-attr">price</span>: <span class="hljs-number">104</span>,
        <span class="hljs-attr">description</span>: <span class="hljs-string">"Description 4"</span>,
      });
    expect(res.statusCode).toBe(<span class="hljs-number">200</span>);
    expect(res.body.price).toBe(<span class="hljs-number">104</span>);
  });
});

describe(<span class="hljs-string">"DELETE /api/products/:id"</span>, <span class="hljs-function">() =&gt;</span> {
  it(<span class="hljs-string">"should delete a product"</span>, <span class="hljs-keyword">async</span> () =&gt; {
    <span class="hljs-keyword">const</span> res = <span class="hljs-keyword">await</span> request(app).delete(
      <span class="hljs-string">"/api/products/6331abc9e9ececcc2d449e44"</span>
    );
    expect(res.statusCode).toBe(<span class="hljs-number">200</span>);
  });
});
</code></pre>
<p>Then run <code>npm run test</code> to run the test suites (suite - test file).</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/09/image-428.png" alt="Image" width="600" height="400" loading="lazy">
<em>Test results</em></p>
<p>And that's it! You now know how to test your Express/Mongoose apps with Jest and SuperTest.</p>
<p>Now go forth and create new tests for your apps. :)</p>
<p>If you have any questions, feel free to message me on <a target="_blank" href="https://twitter.com/rakesh_at_tweet">Twitter</a>.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ What is Software Testing? A Beginner's Guide ]]>
                </title>
                <description>
                    <![CDATA[ Software testing is essential to development. It saves you time and money in production mode.  But software testing is a complex topic and can be a bit difficult to understand. In this article, I'll explain the major topics in software testing and ho... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/software-testing-beginners-guide/</link>
                <guid isPermaLink="false">66c4c6501b22d2d8d9040ec8</guid>
                
                    <category>
                        <![CDATA[ beginner ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Software Testing ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Testing ]]>
                    </category>
                
                    <category>
                        <![CDATA[ unit testing ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Sophia Iroegbu ]]>
                </dc:creator>
                <pubDate>Wed, 21 Sep 2022 16:03:49 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2022/09/Tech-Blog-Cover--4-.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Software testing is essential to development. It saves you time and money in production mode. </p>
<p>But software testing is a complex topic and can be a bit difficult to understand.</p>
<p>In this article, I'll explain the major topics in software testing and how this practice can help you. </p>
<h3 id="heading-table-of-contents">Table of Contents:</h3>
<ul>
<li><a class="post-section-overview" href="#heading-what-is-software-testing">What is Software Testing?</a></li>
<li><a class="post-section-overview" href="#heading-types-of-software-testing">Types of Software Testing</a></li>
<li><a class="post-section-overview" href="#heading-different-types-of-functional-software-testing">Different Types of Functional Software Testing</a></li>
<li><a class="post-section-overview" href="#heading-software-testing-principles">Software Testing Principles</a></li>
<li><a class="post-section-overview" href="#heading-why-is-software-testing-needed">Why is Software Testing needed?</a></li>
<li><a class="post-section-overview" href="#heading-conclusion">Conclusion</a></li>
</ul>
<h2 id="heading-what-is-software-testing">What is Software Testing?</h2>
<p>Software testing is the process of making sure your software/app works as it should. There are various methods you can use to test your code, and each testing method has different requirements. </p>
<p>For instance, unit testing involves writing test cases to ensure the code works as it should, and Beta testing consists of testing the preview version of the software or app to make sure users can use the product.</p>
<p>Software testing is integral to the process of building good software that works as it should. It also helps improve productivity and performance. Testing is an important part of the <em>Software Development Life Cycle</em> (SDLC). </p>
<p>Other benefits of testing your code include preventing bugs, reducing cost, and reducing time of development.</p>
<h2 id="heading-types-of-software-testing">Types of Software Testing</h2>
<p>There are two general types of software testing:</p>
<h3 id="heading-functional-testing">Functional Testing:</h3>
<p>Functional Testing is a software testing method that validates the system against the customer's requirements or specifications. </p>
<p>This type of testing aims to test each function of the software by providing the correct input and ensuring the output is right. </p>
<p>For examples, let's say you write a test case to test creating a user. The test case provides the correct input (email, first name, last name and password) and ensures the output (success message) is accurate, as well.</p>
<p>Functional testing checks that everything is functioning properly by emulating business scenarios based on applicable requirements.</p>
<h3 id="heading-non-functional-testing">Non-functional Testing:</h3>
<p>Non-functional testing is a software testing method that tests for end-user experiences, such as performance and reliability under load. This could either make or break a user experience. </p>
<p>When your code fails at non-functional testing, it may not cause an issue that user would note but it can flag a problem in the system.</p>
<p>Non-functional testing is just about testing the software to know how it responds to load on the system.</p>
<p>In this guide, we will focus on Functional Software Testing.</p>
<h2 id="heading-different-types-of-functional-software-testing">Different Types of Functional Software Testing</h2>
<p>There are different types of software testing, and each has a specific aim. We'll look at each one quickly now. </p>
<h3 id="heading-unit-testing">Unit Testing:</h3>
<p>Unit testing is a type of software testing that validates how each software unit performs and whether that specific piece of code does what it should. A unit is the smallest testable component of an application.</p>
<p>The aim is to confirm that each unit of software code works as expected. You do unit testing during the coding (development) stage or phase. Developers write these tests as they go. </p>
<p>Unit tests isolate possible bugs in your code and help you correct them. A unit could be a single function, method, procedure, module, or object.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/09/image-404.png" alt="Image" width="600" height="400" loading="lazy">
<em>Code Snippet of a unit test case in Python</em></p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/09/image-403.png" alt="Image" width="600" height="400" loading="lazy">
<em>Code Snippet of a unit test case in Java</em></p>
<h3 id="heading-integration-testing">Integration Testing:</h3>
<p>Integration Testing is software testing which helps ensure that software components or functions work together properly. This is the second phase of the software testing process that comes after unit testing.</p>
<p>In this type of testing, units or individual software components are tested in groups. This testing method mainly focuses on exposing defects in interactions between integrated components and units.</p>
<h3 id="heading-system-testing">System Testing:</h3>
<p>System testing involves the process of testing integrated software. The aim is to evaluate the system's compliance with specify requirements. </p>
<p>In system testing, the quality assurance team evaluates how each component of the application or software work together in a full, integrated environment.</p>
<h3 id="heading-acceptance-testing">Acceptance Testing:</h3>
<p>Acceptance testing is a software testing method where a system is tested or checked for acceptability. It evaluates the system's compatibility with the business requirements and assesses whether it is acceptable for delivery.</p>
<p>It is also known as formal testing performed to fit user needs, requirements, and business processes. It determines if a system satisfies the standard business criteria and if users or customers will be able to accept it. </p>
<p>Acceptance testing is the last stage of software testing done after system testing and before making the system available for public use.</p>
<h3 id="heading-regression-testing">Regression Testing:</h3>
<p>Regression testing ensures that a component continues working as it should, after including additional components in the program. You perform regression testing when something changes, such as adding a new module to the program.</p>
<p>This type of testing represents the complete testing of executed test cases that are re-executed to ensure the current functionalities still work just fine.</p>
<h3 id="heading-alpha-testing-and-beta-testing">Alpha Testing and Beta Testing:</h3>
<p>Alpha testing is also known as initial validation testing. It is an aspect of acceptance testing done before the product is given to the consumers or users. QA (Quality Assurance) testers usually do this. Alpha testing is done internally by the QA team.</p>
<p>Beta testing is also known as second phase of validation testing. But this type of testing is done externally, which means the public does it. </p>
<p>The version of the code/software for this phase of testing is released to a limited number of users for testing in a real-time scenario. For instance, freeCodeCamp's math curriculum is available for beta testing <a target="_blank" href="https://www.freecodecamp.org/news/freecodecamp-foundational-math-curriculum/">here</a>.</p>
<h2 id="heading-software-testing-principles">Software Testing Principles</h2>
<p>Everything in tech has principles. These are guidelines to help you build better software and avoid errors.</p>
<p>Here are some software testing principles you should follow when writing tests for your code:</p>
<h3 id="heading-testing-aims-to-show-the-presence-of-defects-not-the-absence">Testing aims to show the presence of defects, not the absence:</h3>
<p>Software testing aims to spot software failures. This reduces the presence of faults and errors. </p>
<p>Software testing ensures defects are visible to the developer but doesn't guarantee defect-free software. Multiple types of testing can't even ensure error-free software. Testing can only decrease the number of errors.</p>
<h3 id="heading-exhaustive-testing-is-not-possible">Exhaustive testing is not possible:</h3>
<p>Exhaustive Testing is the process of testing software for all valid and invalid inputs and pre-conditions. </p>
<p>This method of testing is not realistic because test cases presume that the software is correct and it produces the correct output in every test case. If you truly try to test every aspect and test case in your software, it will take too much time and effort, and it's not practical.</p>
<h3 id="heading-perform-early-testing">Perform early testing:</h3>
<p>Testing your software at an early phase helps avoid minor bugs or errors. When you can spot errors at an early stage of the Software Development Life Cycle(SDLC), it's always less expensive. It is best to start software testing from the beginning of the project.</p>
<h3 id="heading-defect-clustering">Defect clustering:</h3>
<p>Defect clustering refers to when most of the problems you find occur in just a few parts of the application or software. If you can identify the modules or areas where these defects occur, you can focus most of your testing efforts on them. </p>
<p>Keep the Pareto Principle in mind when testing your code: 80% of software defects tend to come from 20% of the modules.</p>
<h3 id="heading-beware-of-the-pesticide-paradox">Beware of the Pesticide paradox:</h3>
<p>This principle is based on a theory – "the more you use pesticide on a crop, the more immune the crop will eventually grow, and the pesticide will not be effective." </p>
<p>When you repeat particular test cases over and over, you will see fewer and fewer new bugs. So to find new bugs, update your test cases and run them once you add new test cases.</p>
<h3 id="heading-testing-is-context-dependent">Testing is context-dependent:</h3>
<p>Testing is context-dependent, which means that you should test your software based on its needs, functionalities, and requirements.</p>
<p>Your test approach should depend on what your software does. Not every software needs the same type/method of testing because every application has its unique functionalities.</p>
<p>For instance, when testing an eCommerce web app, you will focus on its functionality to display products, so you will test how it shows products to end-users. When dealing with an API, you will focus on the response the API returns when an endpoint is called. </p>
<p>You wouldn't necessarily use the same test cases for both – that is what it means that testing is context-dependent.</p>
<h3 id="heading-the-absence-of-errors-is-a-fallacy">The absence of errors is a fallacy:</h3>
<p>If you build software that is 99% bug-free, but it doesn't follow user requirements, it is not usable for end-users. </p>
<p>Know that it is very much necessary that your 99% bug-free software still meets or fulfills your user requirements. It is important to write test cases to find errors in the code, but you also need to test your software for your end-users (with them and how they'll use it in mind). The best way to do this is to carry out beta testing.</p>
<h2 id="heading-why-is-software-testing-needed">Why is Software Testing Needed?</h2>
<p>Besides making sure your software is bug-free and meets user requirements, software testing has other advantages. </p>
<h3 id="heading-software-testing-improves-security">Software testing improves security:</h3>
<p>When building software, security is a crucial part of your planning. This is because vulnerable software could jeopardize you users and their information, as hackers can use stolen info for malicious purposes.</p>
<p>As a product undergoes testing, the end-user can count on the fact that they will be getting a reliable product and their details will be secured and safe. So users are more likely to get a product that is free from vulnerabilities with the help of software testing.</p>
<h3 id="heading-software-testing-improves-product-quality">Software testing improves product quality:</h3>
<p>You want your software or product to be bug-free, low-risk, and effective at what it should do. And you can achieve this by including test cases and other testing methods when building out the code.</p>
<p>In addition, you won't know how good your product is until you test it. This helps you provide the best product version before it gets released (and discover any inconsistencies or pain points along the way – so you can improve them).</p>
<h3 id="heading-software-testing-improves-customer-satisfaction">Software testing improves customer satisfaction:</h3>
<p>For instance, let's say you download a new app and try to use some of its functionality – but it shows an error. This will probably frustrate you, and you might not want to use the app again, right?</p>
<p>This is exactly why software testing is important. It can help you discover such errors and detect them before you release the product to the user, and gives the developers a chance to prevent the error. </p>
<p>By investing in software testing early in the development stage, you are letting the users know that you care about their experience. It could also help you create a solid long-term customer relationship.</p>
<h3 id="heading-software-testing-saves-money">Software testing saves money:</h3>
<p>Software testing can save you a lot of money – but how?</p>
<p>Each stage of development involves many things, such as clear communication and coordination between multiple teams, and each step has a laundry list of things that could go awry.</p>
<p>Catching those errors when the product is live is a horrible experience because you may have to handle PR, retasking fixes, and trying to sort the problem in real time.</p>
<p>In addition, your users won't be able to access the app while you're fixing it, which defeats the app's purpose and provides a bad user experience in the meantime. Software testing helps resolve this stress, and once live, your user can enjoy your app/product to the fullest.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>In conclusion, software testing is a crucial part of development. It can help save your team a lot of trouble, and it feels great to create a usable, bug-free product that users enjoy and recommend.</p>
<p>If software testing interests you, you can check freeCodeCamp's QA certificate course <a target="_blank" href="https://www.freecodecamp.org/learn/quality-assurance/#quality-assurance-and-testing-with-chai">here</a> to learn more about QA testing. QA testers are techies that focus on testing softwares and apps for errors. </p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Perform Integration Testing using JUnit 5 and TestContainers with SpringBoot ]]>
                </title>
                <description>
                    <![CDATA[ TestContainers is a library that helps you run module-specific Docker containers to simplify Integration Testing. These Docker containers are lightweight, and once the tests are finished the containers get destroyed. In the article we are going to un... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/integration-testing-using-junit-5-testcontainers-with-springboot-example/</link>
                <guid isPermaLink="false">66d460f437bd2215d1e245c9</guid>
                
                    <category>
                        <![CDATA[ Docker ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Software Testing ]]>
                    </category>
                
                    <category>
                        <![CDATA[ spring-boot ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Testing ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Sameer Shukla ]]>
                </dc:creator>
                <pubDate>Fri, 26 Aug 2022 15:46:39 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2022/08/testcontainers-logo.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>TestContainers is a library that helps you run module-specific Docker containers to simplify Integration Testing.</p>
<p>These Docker containers are lightweight, and once the tests are finished the containers get destroyed.</p>
<p>In the article we are going to understand what the TestContainers is and how it helps you write more reliable Tests.</p>
<p>We are also going to understand the important components (Annotations and Methods) of the library which help you write the Tests.</p>
<p>Finally, we will also learn to write a proper Integration Test in SpringBoot using the TestContainers library and its components.</p>
<h2 id="heading-limitations-of-testing-with-an-h2-in-memory-database">Limitations of Testing with an H2 In-Memory Database</h2>
<p>The most common approach to Integration Testing today is to use an H2 in-memory database. But there are certain limitations to this method.</p>
<p>First of all, say we are using version 8.0 of MySQL in production, but our integration tests are using H2. We can never execute our tests for the database version running on Production.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/08/image-303.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>SpringBoot app with MySQL DB and H2</em></p>
<p>‌Secondly, the test cases are less reliable because in production we are using an altogether different database and the tests are pointing to H2. The application may run into issues in production, but the integration tests may succeed.</p>
<p>I was trying to access my RESTful service on local and faced this error:</p>
<p>“<strong>Caused by: org.postgresql.util.PSQLException: FATAL: database "example_db" does not exist</strong>”.</p>
<p>It happened because of a permission issue, but the tests on local worked fine.</p>
<p>And finally, as documented <a target="_blank" href="http://h2database.com/html/features.html#compatibility">here</a>, H2 is compatible with other databases only up to a certain point. There are few areas where H2 is incompatible. If you need to use “nativeQueries” in a SpringBoot application, for example, then using H2 may cause problems.</p>
<h2 id="heading-enter-the-testcontainers-library">Enter the TestContainers Library</h2>
<p>By using TestContainers we can overcome the limitations of H2.</p>
<ul>
<li><p>Integration tests will point to the same version of the database as it’s in production. So we can tie our TestContainer Database Image to the same version running on production.</p>
</li>
<li><p>Integration tests are lot more reliable because both application and tests are using the same database type and version and there won't be any compatibility issues in Testcases.</p>
</li>
</ul>
<h2 id="heading-what-is-testcontainers">What is TestContainers?</h2>
<p>The TestContainers library is a wrapper API over Docker. When we write code to create a container behind the scenes it may be translated to some Docker command, for example‌:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/08/image-283.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>MySQLContainer Creation</em></p>
<p>This code may be translated to something like the following:</p>
<pre><code class="lang-docker">docker <span class="hljs-keyword">run</span><span class="bash"> -d --env MYSQL_DATABASE=example_db --env MYSQL_USER=<span class="hljs-built_in">test</span> --env MYSQL_PASSWORD=<span class="hljs-built_in">test</span> ‘mysql:latest’</span>
</code></pre>
<p>TestContainers has a method name “withCommand”. You use it to set the command that should be run inside the Docker container which confirms that TestContainers is a wrapper API over Docker.</p>
<p>TestContainers downloads the MySQL, Postgres, Kafka, Redis images and runs in a container. The MySQLContainer will run a MySQL Database in a container and the Testcases can connect to it on the local machine. Once the execution is over the Database will be gone – it just deletes it from the machine. In the Testcases we can start as many container images as we want.</p>
<p>TestContainers supports JUnit 4, JUnit 5 and Spock. If you go to the TestContainers.org website, just visit the QuickStart section that explains how to use it:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/08/image-284.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>TestContainers.org how to start with Test Framework</em></p>
<p>TestContainers supports almost every Database from MySQL and Postgres to CockroachDB. You can find more info about this on the TestContainers.org website under the Modules section:‌</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/08/image-285.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>TestContainers support for Database Modules</em></p>
<p>‌TestContainers also supports Cloud Modules like GCloud Module and Azure Module as well. If your application is running on Google Cloud, then TestContainers has support for Cloud Spanner, Firestore, Datastore and so on.‌</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/08/image-286.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>TestContainers support for GCloud Module</em></p>
<p>In the article so far, we have discussed only about Databases, but TestContainers supports various other components like Kafka, SOLR, Redis, and more.</p>
<h2 id="heading-how-to-use-the-testcontainers-library">How to Use the TestContainers Library</h2>
<p>In this article we are going to explore TestContainers with JUnit 5. To implement TestContainers we need to understand a few important TestContainers annotations, methods, and the libraries that we need to implement in our project.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/08/image-288.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>TestContainers libraries</em></p>
<h3 id="heading-annotations-in-testcontainers">Annotations in TestContainers</h3>
<p>Two important annotations are required in our Tests for TestContainers to work: @TestContainers and @Container.</p>
<p>@TestContainer is JUnit-Jupiter extension which automatically starts and stops the containers that are used in the tests. This annotation finds the fields that are marked with @Container and calls the specific Container life-cycle methods. Here, MySQLContainer life-cycle methods will be invoked.‌</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/08/image-289.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>MySQLContainer</em></p>
<p>The MySQLContainer is declared as static because if we declare Container as static then a single container is started and it will be shared across all the test methods.</p>
<p>If it’s an instance variable, then a new container is created for each test method.</p>
<h2 id="heading-testcontainers-library-methods">TestContainers Library Methods</h2>
<p>There are few important methods in TestContainers library that you'll use in the tests. They're good to know before using the library.</p>
<ul>
<li><p><strong>withInitScript</strong>: Using ‘withInitScript’ we can execute the .SQL to define the schema, tables, and plus add the data into the database. In short, this method is used to run the .SQL to populate the database.</p>
</li>
<li><p><strong>withReuse</strong> (true): Using “withReuse” method we can enable the reuse of containers. This method works well in conjunction with enabling the “testcontainers.reuse.enable:true” property in the “.testcontainers.properties” file.</p>
</li>
<li><p><strong>start</strong>: we use this to start the container.</p>
</li>
<li><p><strong>withClasspathResourceMapping</strong>: This maps a resource (file or directory) on the classpath to a path inside the container. This will only work if you are running your tests outside a Docker container.</p>
</li>
<li><p><strong>withCommand</strong>: Set the command that should be run inside the Docker container.</p>
</li>
<li><p><strong>withExposedPorts</strong>: Used to set the port that the container listens on.</p>
</li>
<li><p><strong>withFileSystemBind</strong>: Used to map a file / directory from the local filesystem into the container.</p>
</li>
</ul>
<h2 id="heading-testcontainers-use-case">TestContainers Use Case</h2>
<p>In the example we'll look at now, the application will communicate only with the database and write the integration tests for it using TestContainers. Then we'll extend the use-case by implementing Redis in between.</p>
<p>If the data exists in the Redis cache it will be returned, otherwise it'll dip into the database for saving and retrieval based on the Key.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/08/image-308.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Use-Case</em></p>
<p>The service is simple. It has 2 endpoints – the first one is to create a user and the second one is to find a user by email. If the user is found it is returned, otherwise we get a 404. The service class code looks something like this:‌</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/08/image-291.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Service Component</em></p>
<p>We are going to write tests for this class. You can find the entire codebase <a target="_blank" href="https://github.com/sameershukla/testcontainers_demo">here</a>:‌</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/08/image-292.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Test Class</em></p>
<p>The test class is marked with @TestContainers annotation which starts/stops the container. We use the @Container annotation to call the specific container's life-cycle methods.</p>
<p>Also, the “MySQLContainer” is declared as static because then a single container is started. Then it gets shared across all the test methods (we have already discussed the importance of these annotations).</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/08/image-293.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>BeforeAll</em></p>
<p>Next we need to write a setup method marked with @BeforeAll, where we have enabled the “withReuse” method. This helps us reuse the existing containers. We are using the “withInitScript” method to execute the “.sql” file and then starting the container.‌</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/08/image-294.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Overwriting Properties</em></p>
<p>‌@DynamicPropertySource helps us override the properties declared in the properties file. We write this method to allow TestContainers to create the URL, username, and password on its own – otherwise we may face errors.</p>
<p>For example on removing username and password we may face an ‘Access denied’ error which may confuse us. So it’s better to allow TestContainer to assign these properties dynamically on its own.</p>
<p>That’s it – we are ready to run the Testcases:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/08/image-295.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Test Cases</em></p>
<p>Execute @AfterAll to stop the container, otherwise it may keep running on your local machine if you don't explicitly stop it. ‌</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/08/image-296.png" alt="Image" width="600" height="400" loading="lazy"></p>
<h2 id="heading-how-to-use-genericcontainer">How to Use GenericContainer</h2>
<p>‌‌GenericContainer is the most flexible container. It makes it easy to run any container images within GenericContainer.</p>
<p>Now we have Redis in place, all we need to do in our Testcase is to spin up a GenericContainer with the Redis image.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/08/image-297.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>GenericContainer for Redis</em></p>
<p>Then we start the Generic Redis container in @BeforeAll and stop it with the @AfterAll tear down method.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/08/image-298.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Starting Containers</em></p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/08/image-299.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Stopping Containers</em></p>
<h2 id="heading-wrapping-up">Wrapping Up</h2>
<p>It's extremely easy to use TestContainers in our application to write better tests. The learning curve is not too steep and it has support for various different modules from a variety of databases like Kafka, Redis and others.</p>
<p>Writing tests using TestContainers makes our tests lot more reliable. The only flip side is that the tests are slow compared to H2. This is because H2 is in memory and TestContainers takes time to download the image, run the container, and execute the entire setup we have discussed in this article.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Test-Driven Development Tutorial – How to Test Your JavaScript and ReactJS Applications ]]>
                </title>
                <description>
                    <![CDATA[ Understanding test-driven development is an essential part of being a prolific software developer. Testing provides a solid platform for building reliable programs. This tutorial will show you all you need to implement test-driven development in your... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/test-driven-development-tutorial-how-to-test-javascript-and-reactjs-app/</link>
                <guid isPermaLink="false">66ba0e0ed14c87384322b685</guid>
                
                    <category>
                        <![CDATA[ JavaScript ]]>
                    </category>
                
                    <category>
                        <![CDATA[ React ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Software Testing ]]>
                    </category>
                
                    <category>
                        <![CDATA[ test driven development ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Testing ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Oluwatobi Sofela ]]>
                </dc:creator>
                <pubDate>Tue, 26 Jul 2022 17:51:22 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2022/07/test-driven-development-tutorial-how-to-test-javascript-and-reactjs-app-codesweetly-battlecreek-coffee-roasters-i22gbC3gFm4-unsplash.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Understanding test-driven development is an essential part of being a prolific software developer. Testing provides a solid platform for building reliable programs.</p>
<p>This tutorial will show you all you need to implement test-driven development in your JavaScript and React applications.</p>
<h2 id="heading-table-of-contents">Table of Contents</h2>
<ol>
<li><a class="post-section-overview" href="#heading-what-is-test-driven-development">What Is Test-Driven Development?</a></li>
<li><a class="post-section-overview" href="#heading-javascript-example-of-a-test-driven-development-workflow">JavaScript Example of a Test-Driven Development Workflow</a></li>
<li><a class="post-section-overview" href="#heading-how-to-use-jest-as-a-test-implementation-tool">How to Use Jest as a Test Implementation Tool</a></li>
<li><a class="post-section-overview" href="#heading-important-stuff-to-know-about-using-es6-modules-with-jest">Important Stuff to Know about Using ES6 Modules with Jest</a></li>
<li><a class="post-section-overview" href="#heading-what-are-the-advantages-of-test-driven-development">What Are the Advantages of Test-Driven Development?</a></li>
<li><a class="post-section-overview" href="#heading-what-is-a-unit-test-in-test-driven-development">What is a Unit Test in Test-Driven Development</a>?</li>
<li><a class="post-section-overview" href="#heading-what-is-an-integration-test-in-test-driven-development">What is an Integration Test in Test-Driven Development</a>?</li>
<li><a class="post-section-overview" href="#heading-what-is-an-end-to-end-test-in-test-driven-development">What is an End-to-End Test in Test-Driven Development</a>?</li>
<li><a class="post-section-overview" href="#heading-what-are-test-doubles-in-test-driven-development">What are Test Doubles in Test-Driven Development</a>?</li>
<li><a class="post-section-overview" href="#heading-quick-overview-of-test-driven-development-so-far">Quick Overview of Test-Driven Development So Far</a></li>
<li><a class="post-section-overview" href="#heading-how-to-test-react-components">How to Test React Components</a></li>
<li><a class="post-section-overview" href="#heading-test-runner-vs-react-component-testing-tool-whats-the-difference">Test Runner vs. React Component Testing Tool: What's the Difference?</a></li>
<li><a class="post-section-overview" href="#heading-project-how-react-testing-works">Project: How React Testing Works</a></li>
<li><a class="post-section-overview" href="#heading-overview">Overview</a></li>
</ol>
<p>So, without any further ado, let's get started by discussing what test-driven development means.</p>
<h2 id="heading-what-is-test-driven-development">What Is Test-Driven Development?</h2>
<p><strong>Test-driven development (TDD)</strong> is a coding practice where you write the result you want your program to produce before creating the program.</p>
<p>In other words, TDD requires you to pre-specify the output your intended program must produce to pass the test of functioning the way you envisioned.</p>
<p>So, in an effective test-driven development practice, you would first write tests that express the result you expect from your intended program.</p>
<p>Afterward, you would develop the program to pass the prewritten test.</p>
<p>For instance, suppose you wish to create an addition calculator. In such a case, the TDD approach will be like so:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/07/test-driven-development-tdd-workflow-diagram-codesweetly.png" alt="Test-driven development workflow diagram" width="600" height="400" loading="lazy">
<em>Test-driven development workflow diagram</em></p>
<ol>
<li>Write a test specifying the result you expect the calculator to produce to pass the test of being the program you had in mind.</li>
<li>Develop the calculator to pass the prewritten test.</li>
<li>Run the test to check whether the calculator passes or fails the test.</li>
<li>Refactor your test code (if necessary).</li>
<li>Refactor your program (if necessary).</li>
<li>Continue the cycle until the calculator matches your vision.</li>
</ol>
<p>Let's now see a JavaScript example of a TDD workflow.</p>
<h2 id="heading-javascript-example-of-a-test-driven-development-workflow">JavaScript Example of a Test-Driven Development Workflow</h2>
<p>The steps below will use a simple JavaScript program to show you how to approach TDD.</p>
<h3 id="heading-1-write-your-test">1. Write your test</h3>
<p>Write a test that specifies the result you expect your calculator program to produce:</p>
<pre><code class="lang-js"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">additionCalculatorTester</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">if</span> (additionCalculator(<span class="hljs-number">4</span>, <span class="hljs-number">6</span>) === <span class="hljs-number">10</span>) {
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"✔ Test Passed"</span>);
  } <span class="hljs-keyword">else</span> {
    <span class="hljs-built_in">console</span>.error(<span class="hljs-string">"❌ Test Failed"</span>);
  }
}
</code></pre>
<h3 id="heading-2-develop-your-program">2. Develop your program</h3>
<p>Develop the calculator program to pass the prewritten test:</p>
<pre><code class="lang-js"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">additionCalculator</span>(<span class="hljs-params">a, b</span>) </span>{
  <span class="hljs-keyword">return</span> a + b;
}
</code></pre>
<h3 id="heading-3-run-the-test">3. Run the test</h3>
<p>Run the test to check whether the calculator passes or fails the test:</p>
<pre><code class="lang-js">additionCalculatorTester();
</code></pre>
<p><a target="_blank" href="https://stackblitz.com/edit/js-ciui1u?devToolsHeight=33&amp;file=index.js"><strong>Try it on StackBlitz</strong></a></p>
<h3 id="heading-4-refactor-the-test">4. Refactor the test</h3>
<p>After you've confirmed that your program passed the prewritten test, it's time to check if there's any need to refactor it.</p>
<p>For instance, you could refactor <code>additionCalculatorTester()</code> to use a <a target="_blank" href="https://codesweetly.com/javascript-statement/#what-is-a-conditional-ternary-operator-in-javascript">conditional operator</a> like so:</p>
<pre><code class="lang-js"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">additionCalculatorTester</span>(<span class="hljs-params"></span>) </span>{
  additionCalculator(<span class="hljs-number">4</span>, <span class="hljs-number">6</span>) === <span class="hljs-number">10</span> 
    ? <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"✔ Test Passed"</span>) 
    : <span class="hljs-built_in">console</span>.error(<span class="hljs-string">"❌ Test Failed"</span>);
}
</code></pre>
<h3 id="heading-5-refactor-the-program">5. Refactor the program</h3>
<p>Let's also refactor the program's code to use an <a target="_blank" href="https://codesweetly.com/javascript-function-object#arrow-function-expression-in-javascript">arrow function</a>.</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> additionCalculator = <span class="hljs-function">(<span class="hljs-params">a, b</span>) =&gt;</span> a + b;
</code></pre>
<h3 id="heading-6-run-the-test">6. Run the test</h3>
<p>Rerun the test to ensure your program still works as intended.</p>
<pre><code class="lang-js">additionCalculatorTester();
</code></pre>
<p><a target="_blank" href="https://stackblitz.com/edit/js-xp732h?devToolsHeight=33&amp;file=index.js"><strong>Try it on StackBlitz</strong></a></p>
<p>Notice that in the examples above, we implemented TDD without using any libraries.</p>
<p>But you can also use powerful test-running tools like <a target="_blank" href="https://jasmine.github.io/">Jasmine</a>, <a target="_blank" href="https://mochajs.org/">Mocha</a>, <a target="_blank" href="https://github.com/substack/tape">Tape</a>, and <a target="_blank" href="https://jestjs.io/">Jest</a>, to make your test implementation faster, simpler, and more fun.</p>
<p>Let's see how to use Jest, for example.</p>
<h2 id="heading-how-to-use-jest-as-a-test-implementation-tool">How to Use Jest as a Test Implementation Tool</h2>
<p>Here are the steps you'll need to follow to get started using Jest as your test implementation tool:</p>
<h3 id="heading-step-1-get-the-right-node-and-npm-version">Step 1: Get the right Node and NPM version</h3>
<p>Make sure you have Node 10.16 (or greater) and NPM 5.6 (or greater) installed on your system.</p>
<p>You can get both by installing the latest LTS from the <a target="_blank" href="https://nodejs.org/en/">Node.js</a> website.</p>
<p>If you prefer to use Yarn, ensure you have <a target="_blank" href="https://yarnpkg.com/">Yarn 0.25 (or greater)</a>.</p>
<h3 id="heading-step-2-create-a-project-directory">Step 2: Create a project directory</h3>
<p>Create a new folder for your project.</p>
<pre><code class="lang-bash">mkdir addition-calculator-jest-project
</code></pre>
<h3 id="heading-step-3-navigate-to-your-project-folder">Step 3: Navigate to your project folder</h3>
<p>Using the command line, navigate to your project directory.</p>
<pre><code class="lang-bash"><span class="hljs-built_in">cd</span> path/to/addition-calculator-jest-project
</code></pre>
<h3 id="heading-step-4-create-a-packagejson-file">Step 4: Create a <code>package.json</code> file</h3>
<p>Initialize a <code>package.json</code> file for your project.</p>
<pre><code class="lang-bash">npm init -y
</code></pre>
<p>Or, if your <a target="_blank" href="https://codesweetly.com/package-manager-explained">package manager</a> is Yarn, run:</p>
<pre><code class="lang-bash">yarn init -y
</code></pre>
<h3 id="heading-step-5-install-jest">Step 5: Install Jest</h3>
<p>Install Jest as a development dependency package like so:</p>
<pre><code class="lang-bash">npm install jest --save-dev
</code></pre>
<p>Alternatively, if your package manager is Yarn, run:</p>
<pre><code class="lang-bash">yarn add jest --dev
</code></pre>
<h3 id="heading-step-6-make-jest-your-projects-test-runner-tool">Step 6: Make Jest your project's test runner tool</h3>
<p>Open your <code>package.json</code> file and add Jest to the <code>test</code> field.</p>
<pre><code class="lang-json">{
  <span class="hljs-attr">"scripts"</span>: {
    <span class="hljs-attr">"test"</span>: <span class="hljs-string">"jest"</span>
  }
}
</code></pre>
<h3 id="heading-step-7-create-your-project-file">Step 7: Create your project file</h3>
<p>Create a file that you will use to develop your program.</p>
<pre><code class="lang-bash">touch additionCalculator.js
</code></pre>
<h3 id="heading-step-8-create-your-test-file">Step 8: Create your test file</h3>
<p>Create a file that you will use to write your test cases.</p>
<pre><code class="lang-bash">touch additionCalculator.test.js
</code></pre>
<p><strong>Note:</strong> Your test file's name must end with <code>.test.js</code>—so that Jest can recognize it as the file containing your test code.</p>
<h3 id="heading-step-9-write-your-test-case">Step 9: Write your test case</h3>
<p>Open your test file and write some test code that specifies the result you expect your program to produce.</p>
<p><strong>Here's an example:</strong></p>
<pre><code class="lang-js"><span class="hljs-comment">// additionCalculator.test.js</span>

<span class="hljs-keyword">const</span> additionCalculator = <span class="hljs-built_in">require</span>(<span class="hljs-string">"./additionCalculator"</span>);

test(<span class="hljs-string">"addition of 4 and 6 to equal 10"</span>, <span class="hljs-function">() =&gt;</span> {
  expect(additionCalculator(<span class="hljs-number">4</span>, <span class="hljs-number">6</span>)).toBe(<span class="hljs-number">10</span>);
});
</code></pre>
<p>Here's what we did in the snippet above:</p>
<ol>
<li>We imported the <code>additionCalculator.js</code> project file into the <code>additionCalculator.test.js</code> test file.</li>
<li>We wrote a test case specifying that we expect the <code>additionCalculator()</code> program to output <code>10</code> whenever users provide <code>4</code> and <code>6</code> as its <a target="_blank" href="https://codesweetly.com/javascript-arguments">argument</a>.</li>
</ol>
<p><strong>Note:</strong></p>
<ul>
<li><a target="_blank" href="https://jestjs.io/docs/api#testname-fn-timeout"><code>test()</code></a> is one of Jest's global methods. It accepts three arguments:<ol>
<li>The name of the test (<code>"addition of 4 and 6 to equal 10"</code>).</li>
<li>A function containing the expectations you wish to test.</li>
<li>An optional timeout argument.</li>
</ol>
</li>
<li><a target="_blank" href="https://jestjs.io/docs/expect#expectvalue"><code>expect()</code></a> is a Jest method that lets you test the output of your code.</li>
<li><a target="_blank" href="https://jestjs.io/docs/expect#tobevalue"><code>toBe()</code></a> is a <a target="_blank" href="https://jestjs.io/docs/using-matchers">Jest matcher</a> function that enables you to compare <code>expect()</code>'s argument to primitive values.</li>
</ul>
<p>Suppose you run the test code now. The test would fail because you've not developed the program for which you created the test. So, let's do that now.</p>
<h3 id="heading-step-10-develop-your-program">Step 10: Develop your program</h3>
<p>Open your project file and develop a program to pass the prewritten test.</p>
<p><strong>Here's an example:</strong></p>
<pre><code class="lang-js"><span class="hljs-comment">// additionCalculator.js</span>

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">additionCalculator</span>(<span class="hljs-params">a, b</span>) </span>{
  <span class="hljs-keyword">return</span> a + b;
}

<span class="hljs-built_in">module</span>.exports = additionCalculator;
</code></pre>
<p>The snippet above created an <code>additionCalculator()</code> program and exported it with the <code>module.exports</code> statement.</p>
<h3 id="heading-step-11-run-the-test">Step 11: Run the test</h3>
<p>Run the prewritten test to check if your program passed or failed.</p>
<pre><code class="lang-bash">npm run <span class="hljs-built_in">test</span>
</code></pre>
<p>Alternatively, you can use Yarn like so:</p>
<pre><code class="lang-bash">yarn <span class="hljs-built_in">test</span>
</code></pre>
<p>Suppose your project contains multiple test files, and you wish to run a specific one. In such a case, specify the test file as follow:</p>
<pre><code class="lang-bash">npm run <span class="hljs-built_in">test</span> additionCalculator.test.js
</code></pre>
<p>Alternatively, you can use Yarn like this:</p>
<pre><code class="lang-bash">yarn <span class="hljs-built_in">test</span> additionCalculator.test.js
</code></pre>
<p>Once you've initiated the test, Jest will print a pass or fail message on your editor's console. The message will look similar to this:</p>
<pre><code class="lang-bash">$ jest
 PASS  ./additionCalculator.test.js
  √ addition of 4 and 6 to equal 10 (2 ms)

Test Suites: 1 passed, 1 total
Tests:       1 passed, 1 total
Snapshots:   0 total
Time:        2.002 s
Ran all <span class="hljs-built_in">test</span> suites.
Done <span class="hljs-keyword">in</span> 7.80s.
</code></pre>
<p>If you prefer Jest to run your test automatically, add the <code>--watchAll</code> option to your <code>package.json</code>'s <code>test</code> field.</p>
<p><strong>Here's an example:</strong></p>
<pre><code class="lang-json">{
  <span class="hljs-attr">"scripts"</span>: {
    <span class="hljs-attr">"test"</span>: <span class="hljs-string">"jest --watchAll"</span>
  }
}
</code></pre>
<p>After adding <code>--watchAll</code>, re-execute the <code>npm run test</code> (or <code>yarn test</code>) command to make Jest automatically begin rerunning your test whenever you save changes.</p>
<p><strong>Note:</strong> You can quit the watch mode by pressing the <strong>Q</strong> key on your keyboard.</p>
<h3 id="heading-step-12-refactor-the-test-code">Step 12: Refactor the test code</h3>
<p>So, now that you've confirmed that your program is working as intended, it's time to check if there's any need to refactor the test code.</p>
<p>For instance, suppose you realized that the <code>additionalCalculator</code> should allow users to add any number of digits. In that case, you can refactor your test code like so:</p>
<pre><code class="lang-js"><span class="hljs-comment">// additionCalculator.test.js</span>

<span class="hljs-keyword">const</span> additionCalculator = <span class="hljs-built_in">require</span>(<span class="hljs-string">"./additionCalculator"</span>);

describe(<span class="hljs-string">"additionCalculator's test cases"</span>, <span class="hljs-function">() =&gt;</span> {
  test(<span class="hljs-string">"addition of 4 and 6 to equal 10"</span>, <span class="hljs-function">() =&gt;</span> {
    expect(additionCalculator(<span class="hljs-number">4</span>, <span class="hljs-number">6</span>)).toBe(<span class="hljs-number">10</span>);
  });

  test(<span class="hljs-string">"addition of 100, 50, 20, 45 and 30 to equal 245"</span>, <span class="hljs-function">() =&gt;</span> {
    expect(additionCalculator(<span class="hljs-number">100</span>, <span class="hljs-number">50</span>, <span class="hljs-number">20</span>, <span class="hljs-number">45</span>, <span class="hljs-number">30</span>)).toBe(<span class="hljs-number">245</span>);
  });

  test(<span class="hljs-string">"addition of 7 to equal 7"</span>, <span class="hljs-function">() =&gt;</span> {
    expect(additionCalculator(<span class="hljs-number">7</span>)).toBe(<span class="hljs-number">7</span>);
  });

  test(<span class="hljs-string">"addition of no argument provided to equal 0"</span>, <span class="hljs-function">() =&gt;</span> {
    expect(additionCalculator()).toBe(<span class="hljs-number">0</span>);
  });
});
</code></pre>
<p>Note that the <a target="_blank" href="https://jestjs.io/docs/api#describename-fn">describe()</a> method we used in the snippet above is optional code—it helps organize related test cases into groups.</p>
<p><code>describe()</code> accepts two arguments:</p>
<ol>
<li>A name you wish to call the test case group—for instance, <code>"additionCalculator's test cases"</code>.</li>
<li>A function containing your test cases.</li>
</ol>
<h3 id="heading-step-13-refactor-the-program">Step 13: Refactor the program</h3>
<p>So, now that you've refactored your test code, let's do the same for the <code>additionalCalculator</code> program.</p>
<pre><code class="lang-js"><span class="hljs-comment">// additionCalculator.js</span>

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">additionCalculator</span>(<span class="hljs-params">...numbers</span>) </span>{
  <span class="hljs-keyword">return</span> numbers.reduce(<span class="hljs-function">(<span class="hljs-params">sum, item</span>) =&gt;</span> sum + item, <span class="hljs-number">0</span>);
}

<span class="hljs-built_in">module</span>.exports = additionCalculator;
</code></pre>
<p>Here's what we did in the snippet above:</p>
<ol>
<li>The <code>...numbers</code> code used JavaScript's <a target="_blank" href="https://codesweetly.com/javascript-rest-operator">rest operator</a> (<code>...</code>) to put the function's arguments into an array.</li>
<li>The <code>numbers.reduce((sum, item) =&gt; sum + item, 0)</code> code used JavaScript's <a target="_blank" href="https://codesweetly.com/javascript-reduce-method">reduce()</a> method to sum up all the items in the <code>numbers</code> array.</li>
</ol>
<h3 id="heading-step-14-rerun-the-test">Step 14: Rerun the test</h3>
<p>Once you've finished refactoring your code, rerun the test to confirm that your program still works as expected.</p>
<h3 id="heading-and-thats-it">And that's it!</h3>
<p>Congratulations! You've successfully used Jest to develop an addition calculator program using a test-driven development approach! 🎉</p>
<h2 id="heading-important-stuff-to-know-about-using-es6-modules-with-jest">Important Stuff to Know about Using ES6 Modules with Jest</h2>
<p>Jest does not currently recognize ES6 modules.</p>
<p>However, suppose you prefer to use ES6's import/export statements. In that case, do the following:</p>
<h3 id="heading-1-install-babel-as-a-development-dependency">1. Install Babel as a development dependency</h3>
<pre><code class="lang-bash">npm install @babel/preset-env --save-dev
</code></pre>
<p>Or, you can use Yarn:</p>
<pre><code class="lang-bash">yarn add @babel/preset-env --dev
</code></pre>
<h3 id="heading-2-create-a-babelrc-file-in-your-projects-root">2. Create a <code>.babelrc</code> file in your project's root</h3>
<pre><code class="lang-bash">touch .babelrc
</code></pre>
<h3 id="heading-3-open-the-babelrc-file-and-replicate-the-code-below">3. Open the <code>.babelrc</code> file and replicate the code below</h3>
<pre><code class="lang-json">{ <span class="hljs-attr">"presets"</span>: [<span class="hljs-string">"@babel/preset-env"</span>] }
</code></pre>
<p>The configuration above will now allow you to change step 9's <code>require()</code> statement from this:</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> additionCalculator = <span class="hljs-built_in">require</span>(<span class="hljs-string">"./additionCalculator"</span>);
</code></pre>
<p>...to this:</p>
<pre><code class="lang-js"><span class="hljs-keyword">import</span> additionCalculator <span class="hljs-keyword">from</span> <span class="hljs-string">"./additionCalculator"</span>;
</code></pre>
<p>Likewise, you can now also substitute step 10's <code>export</code> statement from this:</p>
<pre><code class="lang-js"><span class="hljs-built_in">module</span>.exports = additionCalculator;
</code></pre>
<p>...to this:</p>
<pre><code class="lang-js"><span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> additionCalculator;
</code></pre>
<p><strong>Note:</strong> Jest also specified similar instructions in their <a target="_blank" href="https://jestjs.io/docs/getting-started#using-babel">using Babel</a> documentation.</p>
<h3 id="heading-4-rerun-the-test">4. Rerun the test</h3>
<p>You can now rerun the test to confirm that your program still works!</p>
<p>So, now that we know what test-driven development is, we can discuss its advantages.</p>
<h2 id="heading-what-are-the-advantages-of-test-driven-development">What Are the Advantages of Test-Driven Development?</h2>
<p>Below are two main advantages of adopting test-driven development (TDD) in your programming workflow.</p>
<h3 id="heading-1-understand-your-programs-purpose">1. Understand your program's purpose</h3>
<p>Test-driven development helps you understand the purposes of your program.</p>
<p>In other words, since you write your test before the actual program, TDD makes you think about what you want your program to do.</p>
<p>Then, after you've documented the program's purposes using one or more tests, you can confidently proceed to create the program.</p>
<p>Therefore, TDD is a helpful way to jot down the specific results you expect your intended program to produce.</p>
<h3 id="heading-2-confidence-booster">2. Confidence booster</h3>
<p>TDD is a benchmark for knowing that your program is working as expected. It gives you the confidence that your program is working correctly.</p>
<p>Therefore, irrespective of any future development on your codebase, TDD provides an effective way to test if your program is still working appropriately.</p>
<p>Let's now discuss some popular TDD terms: "unit test," "integration test," "E2E," and "test doubles."</p>
<h2 id="heading-what-is-a-unit-test-in-test-driven-development">What is a Unit Test in Test-Driven Development?</h2>
<p>A <strong>unit test</strong> is a test you write to assess the functionality of an independent piece of a program. In other words, a unit test checks if a fully isolated unit of program is working as intended.</p>
<p>The test we wrote for step 10's <code>additionalCalculator</code> program is an excellent unit test example.</p>
<p>Step 10's <code>additionalCalculator()</code>'s test is a unit test because the program is an independent function that does not depend on any external code.</p>
<p>Note that a unit test's primary purpose is not to check for bugs. Instead, a unit test's core purpose is to check whether an independent piece of program (called unit) behaves as intended under various test cases.</p>
<h2 id="heading-what-is-an-integration-test-in-test-driven-development">What is an Integration Test in Test-Driven Development?</h2>
<p>An <strong>integration test</strong> assesses the functionality of a dependent piece of program. In other words, an integration test checks if a program—which depends on other code—is working as intended.</p>
<p>The test we wrote for step 13's <code>additionalCalculator</code> program is an excellent example of an integration test.</p>
<p>Step 13's <code>additionalCalculator()</code>'s test is an integration test because the program is a dependent function that depends on JavaScript's <a target="_blank" href="https://codesweetly.com/javascript-reduce-method">reduce()</a> method.</p>
<p>In other words, we used the prewritten test case to assess the integration of <code>additionalCalculator()</code> and <code>reduce()</code>.</p>
<p>Therefore, suppose JavaScript makes <code>reduce()</code> an obsolete method. In such a case, <code>additionalCalculator</code> will fail its test because of the <code>reduce()</code> method.</p>
<h2 id="heading-what-is-an-end-to-end-test-in-test-driven-development">What is an End-to-End Test in Test-Driven Development?</h2>
<p>An <strong>End-to-End (E2E) test</strong> assesses the functionality of a user interface. In other words, E2E checks if your user interface is working as intended.</p>
<p>Watch <a target="_blank" href="https://youtu.be/r9HdJ8P6GQI?t=1755">Max's YouTube video</a> for a good illustration of an End-to-End test.</p>
<h2 id="heading-what-are-test-doubles-in-test-driven-development">What are Test Doubles in Test-Driven Development?</h2>
<p><strong>Test doubles</strong> are the imitation objects used to mimic real dependencies like databases, libraries, networks, and APIs.</p>
<p>A test double allows you to bypass the natural objects on which your program depends. They let you test your code independently of any dependencies.</p>
<p>For instance, suppose you need to verify if an error detected in your app originates from an external API or your code.</p>
<p>But suppose the API's service is available only in production—not in the development environment. In that case, you've got two options:</p>
<ol>
<li>Wait until your app goes live—which could take months.</li>
<li>Clone the API so you can continue your test irrespective of the dependency's availability.</li>
</ol>
<p>Test doubles provide a helpful way to clone your program's dependencies so that your testing activities won't encounter any disruptions.</p>
<p>Typical examples of test doubles are dummy objects, mocks, fakes, and stubs. Let's discuss them below.</p>
<h3 id="heading-what-is-a-dummy-in-test-driven-development">What is a dummy in test-driven development?</h3>
<p>A <strong>dummy</strong> is a test double used to mimic the value of a specific dependency.</p>
<p>For instance, suppose your app depends on a third-party method that requires you to provide some arguments. In such a case, a dummy allows you to pass in pretend values to the parameters of that method.</p>
<h3 id="heading-what-is-a-mock-in-test-driven-development">What is a mock in test-driven development?</h3>
<p><strong>Mock</strong> is a test double used to mimic an external dependency without considering the responses the dependency may return.</p>
<p>For instance, suppose your app depends on a third-party API (for example, Facebook)—which you cannot access in the development mode. Mock allows you to bypass the API so that you can focus on testing your code regardless of the Facebook API's availability.</p>
<h3 id="heading-what-is-a-stub-in-test-driven-development">What is a stub in test-driven development?</h3>
<p>A <strong>stub</strong> is a test double used to mimic an external dependency while returning hand-coded values. You can use the returned value to assess your program's behavior with various test case responses from the dependency.</p>
<p>For instance, suppose your app depends on a third-party API (for example, Facebook)—which you cannot access in the development mode. Stub allows you to bypass the API while mimicking the exact values Facebook will return.</p>
<p>Therefore, stub helps you assess your program's behavior with various response scenarios.</p>
<h3 id="heading-what-is-a-fake-in-test-driven-development">What is a fake in test-driven development?</h3>
<p><strong>Fake</strong> is a test double used to create a working test implementation of an external dependency with dynamic values.</p>
<p>For instance, you can use fake to create a local database that allows you to test how a real database will work with your program.</p>
<h2 id="heading-quick-overview-of-test-driven-development-so-far">Quick Overview of Test-Driven Development So Far</h2>
<p>We've learned that test-driven development helps you jot down your program's behavior before creating the program.</p>
<p>We also saw a simple JavaScript test and used Jest as a test implementation tool.</p>
<p>Let's now see how to test React components.</p>
<h2 id="heading-how-to-test-react-components">How to Test React Components</h2>
<p>The two main tools you need to test your React components are:</p>
<ol>
<li>A test runner tool</li>
<li>A React component testing tool</li>
</ol>
<p>But what exactly is the difference between a test runner and a React component testing tool? Let's find out.</p>
<h2 id="heading-test-runner-vs-react-component-testing-tool-whats-the-difference">Test Runner vs. React Component Testing Tool: What's the Difference?</h2>
<p>Below are the differences between a test runner and a React component testing tool.</p>
<h3 id="heading-what-is-a-test-runner">What is a test runner?</h3>
<p>A <strong>test runner</strong> is a tool developers use to run a test script and print the test's results on the command line (CLI).</p>
<p>For instance, suppose you wish to run the test cases in your project's <code>App.test.js</code> test script. In such a case, you will use a test runner.</p>
<p>The test runner will execute <code>App.test.js</code> and print the test's results on the command line.</p>
<p>Typical examples of test runners are <a target="_blank" href="https://jasmine.github.io/">Jasmine</a>, <a target="_blank" href="https://mochajs.org/">Mocha</a>, <a target="_blank" href="https://github.com/substack/tape">Tape</a>, and <a target="_blank" href="https://jestjs.io/">Jest</a>.</p>
<h3 id="heading-what-is-a-react-component-testing-tool">What is a React component testing tool?</h3>
<p>A <strong>React component testing tool</strong> provides helpful APIs for defining a component's test cases.</p>
<p>For instance, suppose you need to test your project's <code>&lt;App /&gt;</code> component. In such a case, you will use a React component testing tool to define the component's test cases.</p>
<p>In other words, a React component testing tool provides the APIs for writing your component's test cases.</p>
<p>Typical examples are <a target="_blank" href="https://enzymejs.github.io/enzyme/">Enzyme</a> and the <a target="_blank" href="https://testing-library.com/docs/react-testing-library/intro">React Testing Library</a>.</p>
<p>So, now that we know what a test runner and React component testing tool are, let's use a mini-project to understand how React testing works.</p>
<h2 id="heading-project-how-react-testing-works">Project: How React Testing Works</h2>
<p>In the following steps, we will use <a target="_blank" href="https://en.wikipedia.org/wiki/Jest_(JavaScript_framework)">Jest</a> and the <a target="_blank" href="https://testing-library.com/docs/react-testing-library/intro">React Testing Library</a> (by Kent C. Dodds) to learn how React testing works.</p>
<p><strong>Note:</strong> The React official docs <a target="_blank" href="https://reactjs.org/docs/testing.html#tools">recommend</a> the Jest and React Testing Library combination for testing React components.</p>
<h3 id="heading-step-1-get-the-right-node-and-npm-version-1">Step 1: Get the right Node and NPM version</h3>
<p>Make sure that you have <a target="_blank" href="https://codesweetly.com/package-manager-explained#how-to-check-the-installed-node-version">Node 10.16</a> (or greater) and NPM 5.6 (or greater) installed on your system.</p>
<p>If you prefer to use Yarn, ensure you have Yarn 0.25 (or greater).</p>
<h3 id="heading-step-2-create-a-new-react-app">Step 2: Create a new React app</h3>
<p>Use NPM's <a target="_blank" href="https://create-react-app.dev/">create-react-app</a> package to create a new React app called <code>react-testing-project</code>.</p>
<pre><code class="lang-bash">npx create-react-app react-testing-project
</code></pre>
<p>Alternatively, you can use Yarn to configure your project like so:</p>
<pre><code class="lang-bash">yarn create react-app react-testing-project
</code></pre>
<h3 id="heading-step-3-go-inside-the-project-directory">Step 3: Go inside the project directory</h3>
<p>After the installation process, navigate into the project directory like so:</p>
<pre><code class="lang-bash"><span class="hljs-built_in">cd</span> react-testing-project
</code></pre>
<h3 id="heading-step-4-set-up-your-test-environment">Step 4: Set up your test environment</h3>
<p>Install the following test packages:</p>
<ul>
<li>jest</li>
<li>@testing-library/react</li>
<li>@testing-library/jest-dom</li>
<li>@testing-library/user-event</li>
</ul>
<p><strong>Note:</strong> If you've initialized your React project with <code>create-react-app</code> (step 2), you do not need to install any of the above packages. They come preinstalled and preconfigured in your <code>package.json</code> file.</p>
<p>Now, let's discuss the purpose of each of the above test packages.</p>
<h4 id="heading-what-is-jest">What is Jest?</h4>
<p><a target="_blank" href="https://www.npmjs.com/package/jest">jest</a> is the test runner tool we will use to run this project's test scripts and print the test results on the command line.</p>
<h4 id="heading-what-is-testing-libraryreact">What is @testing-library/react?</h4>
<p><a target="_blank" href="https://www.npmjs.com/package/@testing-library/react">@testing-library/react</a> is the React Testing Library which gives you the APIs you need to write test cases for your React components.</p>
<h4 id="heading-what-is-testing-libraryjest-dom">What is @testing-library/jest-dom?</h4>
<p><a target="_blank" href="https://www.npmjs.com/package/@testing-library/jest-dom">@testing-library/jest-dom</a> provides some set of custom Jest matchers for testing the DOM's state.</p>
<p><strong>Note:</strong> Jest already comes with lots of matchers, so using <code>jest-dom</code> is optional. <code>jest-dom</code> simply extends Jest by providing matchers that make your test more declarative, clear to read, and easy to maintain.</p>
<h4 id="heading-what-is-testing-libraryuser-event">What is @testing-library/user-event?</h4>
<p><a target="_blank" href="https://www.npmjs.com/package/@testing-library/user-event">@testing-library/user-event</a> provides the <code>userEvent</code> API for simulating users' interaction with your app on a web page.</p>
<p><strong>Note:</strong> <code>@testing-library/user-event</code> is a better alternative to the <a target="_blank" href="https://testing-library.com/docs/dom-testing-library/api-events/#fireevent">fireEvent</a> API.</p>
<h3 id="heading-step-5-clean-up-the-src-folder">Step 5: Clean up the <code>src</code> folder</h3>
<p>Delete all files inside the project directory's <code>src</code> folder.</p>
<h3 id="heading-step-6-create-your-code-files">Step 6: Create your code files</h3>
<p>Create the following files inside your project's <code>src</code> folder.</p>
<ul>
<li><code>index.js</code></li>
<li><code>App.js</code></li>
<li><code>App.test.js</code></li>
</ul>
<h3 id="heading-step-7-render-the-app-component">Step 7: Render the <code>App</code> component</h3>
<p>Open your <code>index.js</code> file and render the <code>App</code> component to the DOM like so:</p>
<pre><code class="lang-js"><span class="hljs-comment">// index.js</span>

<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> { createRoot } <span class="hljs-keyword">from</span> <span class="hljs-string">"react-dom/client"</span>;
<span class="hljs-keyword">import</span> App <span class="hljs-keyword">from</span> <span class="hljs-string">"./App"</span>;

<span class="hljs-comment">// Render the App component into the root DOM</span>
createRoot(<span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">"root"</span>)).render(<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">App</span> /&gt;</span></span>);
</code></pre>
<h3 id="heading-step-8-write-your-test-case">Step 8: Write your test case</h3>
<p>Suppose you want your <code>App.js</code> file to render a <code>&lt;h1&gt;CodeSweetly Test&lt;/h1&gt;</code> element to the web page. In that case, open your <em>test script</em> and write some test code specifying the result you expect your <code>&lt;App /&gt;</code> component to produce.</p>
<p><strong>Here's an example:</strong></p>
<pre><code class="lang-js"><span class="hljs-comment">// App.test.js</span>

<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, screen } <span class="hljs-keyword">from</span> <span class="hljs-string">"@testing-library/react"</span>;
<span class="hljs-keyword">import</span> <span class="hljs-string">"@testing-library/jest-dom"</span>;
<span class="hljs-keyword">import</span> App <span class="hljs-keyword">from</span> <span class="hljs-string">"./App"</span>;

test(<span class="hljs-string">"codesweetly test heading"</span>, <span class="hljs-function">() =&gt;</span> {
  render(<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">App</span> /&gt;</span></span>);
  expect(screen.getByRole(<span class="hljs-string">"heading"</span>)).toHaveTextContent(<span class="hljs-regexp">/codesweetly test/i</span>);
});
</code></pre>
<p>Here are the main things we did in the test snippet above:</p>
<ol>
<li>We imported the packages needed to write our test case.</li>
<li><p>We wrote a test case specifying that we expect our <code>&lt;App /&gt;</code> component to render a heading element with a <code>"codesweetly test"</code> text.</p>
</li>
<li><p><a target="_blank" href="https://jestjs.io/docs/api#testname-fn-timeout"><code>test()</code></a> is one of Jest's global methods. We use it to run a test case. The method accepts three arguments:</p>
<ul>
<li>The name of the test (<code>"codesweetly test heading"</code>)</li>
<li>A function containing the expectations you wish to test</li>
<li>An optional timeout argument</li>
</ul>
</li>
<li><a target="_blank" href="https://testing-library.com/docs/react-testing-library/api/#render"><code>render()</code></a> is one of the React Testing Library APIs. We use it to render the component we wish to test.</li>
<li><a target="_blank" href="https://jestjs.io/docs/expect#expectvalue"><code>expect()</code></a> is a Jest method that lets you test the output of your code.</li>
<li><a target="_blank" href="https://testing-library.com/docs/queries/about/#screen"><code>screen</code></a> is a React Testing Library's object containing numerous methods for finding elements on a page.</li>
<li><a target="_blank" href="https://testing-library.com/docs/queries/about/#priority"><code>getByRole()</code></a> is one of the React Testing Library's query methods for finding elements on a page.</li>
<li><a target="_blank" href="https://github.com/testing-library/jest-dom#tohavetextcontent"><code>toHaveTextContent()</code></a> is one of <code>jest-dom</code>'s custom matchers that you can use to confirm the presence of a text content in a specific node.</li>
<li><code>/codesweetly test/i</code> is a <a target="_blank" href="https://codesweetly.com/javascript-regular-expression-object">regular expression</a> syntax that we used to specify a case-insensitive search for <code>codesweetly test</code>.</li>
</ol>
<p>Keep in mind that there are three alternative ways to write the above expect statement:</p>
<pre><code class="lang-js"><span class="hljs-comment">// 1. Using jest-dom's toHaveTextContent() method:</span>
expect(screen.getByRole(<span class="hljs-string">"heading"</span>)).toHaveTextContent(<span class="hljs-regexp">/codesweetly test/i</span>);

<span class="hljs-comment">// 2. Using the heading's textContent property and Jest's toMatch() method:</span>
expect(screen.getByRole(<span class="hljs-string">"heading"</span>).textContent).toMatch(<span class="hljs-regexp">/codesweetly test/i</span>);

<span class="hljs-comment">// 3. Using React Testing Library's name option and jest-dom's toBeInTheDocument() method</span>
expect(screen.getByRole(<span class="hljs-string">"heading"</span>, { <span class="hljs-attr">name</span>: <span class="hljs-regexp">/codesweetly test/i</span> })).toBeInTheDocument();
</code></pre>
<p><strong>Tip:</strong></p>
<p>Add a <code>level</code> option to the <code>getByRole()</code> method to specify your heading's level.</p>
<p><strong>Here's an example:</strong></p>
<pre><code class="lang-js">test(<span class="hljs-string">"codesweetly test heading"</span>, <span class="hljs-function">() =&gt;</span> {
  render(<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">App</span> /&gt;</span></span>);
  expect(screen.getByRole(<span class="hljs-string">"heading"</span>, { <span class="hljs-attr">level</span>: <span class="hljs-number">1</span> })).toHaveTextContent(<span class="hljs-regexp">/codesweetly test/i</span>);
});
</code></pre>
<p>The <code>level: 1</code> option specifies an <code>&lt;h1&gt;</code> heading element.</p>
<p>Suppose you run the test code now. The test will fail because you've not developed the component for which you created the test. So, let's do that now.</p>
<h3 id="heading-step-9-develop-your-react-component">Step 9: Develop your React component</h3>
<p>Open your <code>App.js</code> file and develop the component to pass the prewritten test.</p>
<p><strong>Here's an example:</strong></p>
<pre><code class="lang-js"><span class="hljs-comment">// App.js</span>

<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="xml"><span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>CodeSweetly Test<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span></span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> App;
</code></pre>
<p>The <code>App</code> component, in the snippet above, renders a <code>&lt;h1&gt;</code> element containing the <code>"CodeSweetly Test"</code> text.</p>
<h3 id="heading-step-10-run-the-test">Step 10: Run the test</h3>
<p>Run the prewritten test to check if your program passed or failed.</p>
<pre><code class="lang-bash">npm <span class="hljs-built_in">test</span> App.test.js
</code></pre>
<p>Alternatively, you can use Yarn like so:</p>
<pre><code class="lang-bash">yarn <span class="hljs-built_in">test</span> App.test.js
</code></pre>
<p>Once you've initiated the test, Jest will print a pass or fail message on your editor's console. The message will look similar to this:</p>
<pre><code class="lang-bash">$ jest
 PASS  src/App.test.js
  √ codesweetly <span class="hljs-built_in">test</span> heading (59 ms)

Test Suites: 1 passed, 1 total
Tests:       1 passed, 1 total
Snapshots:   0 total
Time:        3.146 s
Ran all <span class="hljs-built_in">test</span> suites related to changed files.
</code></pre>
<p><strong>Note:</strong> The <code>create-react-app</code> configured Jest in <a target="_blank" href="https://codesweetly.com/javascript-module-bundler/#what-is-webpack---progress---watch">watch mode</a> by default. Therefore, after running <code>npm test</code> (or <code>yarn test</code>), your currently opened terminal will continue to process the <code>test</code> command's activities. So, you won't be able to input any command on that terminal until you stop <code>test</code>'s execution. But you can open a new terminal window simultaneously with the one processing <code>test</code>. </p>
<p>In other words, use one terminal to run <code>test</code> and another to input commands.</p>
<h3 id="heading-step-11-run-the-application">Step 11: Run the application</h3>
<p>Take a look at your app in the browser by running:</p>
<pre><code class="lang-bash">npm start
</code></pre>
<p>Or, if your <a target="_blank" href="https://codesweetly.com/package-manager-explained">package manager</a> is Yarn, run:</p>
<pre><code class="lang-bash">yarn start
</code></pre>
<p>Once you run the command above, your app will automatically open on your default browser.</p>
<h3 id="heading-step-12-refactor-the-test-code-1">Step 12: Refactor the test code</h3>
<p>Suppose you wish to change the heading's text when users click a button. In that case, you can simulate users' interaction with the button to confirm that it works as intended.</p>
<p><strong>Here's an example:</strong></p>
<pre><code class="lang-js"><span class="hljs-comment">// App.test.js</span>

<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, screen } <span class="hljs-keyword">from</span> <span class="hljs-string">"@testing-library/react"</span>;
<span class="hljs-keyword">import</span> userEvent <span class="hljs-keyword">from</span> <span class="hljs-string">"@testing-library/user-event"</span>;
<span class="hljs-keyword">import</span> <span class="hljs-string">"@testing-library/jest-dom"</span>;
<span class="hljs-keyword">import</span> App <span class="hljs-keyword">from</span> <span class="hljs-string">"./App"</span>;

describe(<span class="hljs-string">"App component"</span>, <span class="hljs-function">() =&gt;</span> {
  test(<span class="hljs-string">"codesweetly test heading"</span>, <span class="hljs-function">() =&gt;</span> {
    render(<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">App</span> /&gt;</span></span>);
    expect(screen.getByRole(<span class="hljs-string">"heading"</span>)).toHaveTextContent(<span class="hljs-regexp">/codesweetly test/i</span>);
  });

  test(<span class="hljs-string">"a codesweetly project heading"</span>, <span class="hljs-function">() =&gt;</span> {
    render(<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">App</span> /&gt;</span></span>);

    <span class="hljs-keyword">const</span> button = screen.getByRole(<span class="hljs-string">"button"</span>, { <span class="hljs-attr">name</span>: <span class="hljs-string">"Update Heading"</span> });

    userEvent.click(button);

    expect(screen.getByRole(<span class="hljs-string">"heading"</span>)).toHaveTextContent(<span class="hljs-regexp">/a codesweetly project/i</span>);
  });
});
</code></pre>
<p>Here are the main things we did in the test snippet above:</p>
<ol>
<li>We imported the packages needed to write our test case.</li>
<li>We wrote a test case specifying that we expect the <code>&lt;App /&gt;</code> component to render a heading element with a <code>"codesweetly test"</code> text.</li>
<li>We wrote another test case simulating users' interaction with the app's button element. In other words, we specified that whenever a user clicks the button, we expect <code>&lt;App /&gt;</code>'s heading to update to <code>"a codesweetly project"</code> text.</li>
</ol>
<p><strong>Note:</strong></p>
<ul>
<li><a target="_blank" href="https://jestjs.io/docs/api#describename-fn"><code>describe()</code></a> is one of Jest's global methods. It is optional code that helps organize related test cases into groups. <code>describe()</code> accepts two arguments:<ul>
<li>A name you wish to call the test case group—for instance, <code>"App component"</code>.</li>
<li>A function containing your test cases.</li>
</ul>
</li>
<li><a target="_blank" href="https://www.npmjs.com/package/@testing-library/user-event"><code>userEvent</code></a> is the React Testing Library's package containing several methods for simulating users' interaction with an app. For instance, in the snippet above, we used <code>userEvent</code>'s <code>click()</code> method to simulate a click event on the button element.</li>
<li>We rendered <code>&lt;App /&gt;</code> for each test case because React Testing Library unmounts the rendered components after each test. However, suppose you have numerous test cases for a component. In that case, use Jest's <a target="_blank" href="https://jestjs.io/docs/api#beforeeachfn-timeout"><code>beforeEach()</code></a> method to run <code>render(&lt;App /&gt;)</code> before each test in your file (or <code>describe</code> block).</li>
</ul>
<h3 id="heading-step-13-refactor-your-react-component">Step 13: Refactor your React component</h3>
<p>So, now that you've refactored your test code, let's do the same for the <code>App</code> component.</p>
<pre><code class="lang-js"><span class="hljs-comment">// App.js</span>

<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> App = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">const</span> [heading, setHeading] = useState(<span class="hljs-string">"CodeSweetly Test"</span>);

  <span class="hljs-keyword">const</span> handleClick = <span class="hljs-function">() =&gt;</span> {
    setHeading(<span class="hljs-string">"A CodeSweetly Project"</span>);
  };

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>{heading}<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"button"</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{handleClick}</span>&gt;</span>
        Update Heading
      <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
    <span class="hljs-tag">&lt;/&gt;</span></span>
  );
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> App;
</code></pre>
<p>Here are the main things we did in the snippet above:</p>
<ol>
<li><code>App</code>'s <code>heading</code> state got initialized with a <code>"CodeSweetly Test"</code> string.</li>
<li>We programmed a <code>handleClick</code> function to update the <code>heading</code> state.</li>
<li>We rendered a <code>&lt;h1&gt;</code> and <code>&lt;button&gt;</code> elements to the DOM.</li>
</ol>
<p>Note the following:</p>
<ul>
<li><code>&lt;h1&gt;</code>'s content is the <code>heading</code> state's current value.</li>
<li>Whenever a user clicks the button element, the <code>onClick()</code> event listener will trigger the <code>handleClick()</code> function. And <code>handleClick</code> will update <code>App</code>'s <code>heading</code> state to <code>"A CodeSweetly Project"</code>. Therefore, <code>&lt;h1&gt;</code>'s content will change to <code>"A CodeSweetly Project"</code>.</li>
</ul>
<h3 id="heading-step-14-rerun-the-test-1">Step 14: Rerun the test</h3>
<p>Once you've refactored your component, rerun the test (or check the actively running test) to confirm that your app still works as expected.</p>
<p>Afterward, check the browser to see your recent updates.</p>
<h3 id="heading-and-thats-it-1">And that's it!</h3>
<p>Congratulations! You've successfully used Jest and the React Testing Library to test a React component. 🎉</p>
<h2 id="heading-overview">Overview</h2>
<p>This article discussed how test-driven development works in JavaScript and ReactJS applications. </p>
<p>We also learned how to use Jest and the React Testing Library to make testing simpler and faster.</p>
<p>Thanks for reading!</p>
<h3 id="heading-and-heres-a-useful-reactjs-resource"><strong>And here's a useful ReactJS resource:</strong></h3>
<p>I wrote a book about React!</p>
<ul>
<li>It's beginner friendly ✔</li>
<li>It has live code snippets ✔</li>
<li>It contains scalable projects ✔</li>
<li>It has plenty of easy-to-grasp examples ✔</li>
</ul>
<p>The <a target="_blank" href="https://www.amazon.com/dp/B09KYGDQYW">React Explained Clearly</a> book is all you need to understand ReactJS.</p>
<p><a target="_blank" href="https://www.amazon.com/dp/B09KYGDQYW"><img src="https://www.freecodecamp.org/news/content/images/2022/01/Twitter-React_Explained_Clearly-CodeSweetly-Oluwatobi_Sofela.jpg" alt="React Explained Clearly Book Now Available at Amazon" width="600" height="400" loading="lazy"></a></p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ What is DevTestOps? How to Combine DevOps and TestOps to Build Better Products ]]>
                </title>
                <description>
                    <![CDATA[ Technology is always improving, and developers are always trying to find easier and better ways to improve the software. This is how DevOps came to be, and over time DevTestOps emerged as a new strategy. Today, companies like Spotify apply DevTestOps... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/what-is-devtestops/</link>
                <guid isPermaLink="false">66d84fe7f6b5e038a1bde7f0</guid>
                
                    <category>
                        <![CDATA[ Devops ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Software Testing ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ EZINNE ANNE EMILIA ]]>
                </dc:creator>
                <pubDate>Mon, 18 Jul 2022 14:22:13 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2022/07/DEVTESTOPS_1.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Technology is always improving, and developers are always trying to find easier and better ways to improve the software. This is how DevOps came to be, and over time DevTestOps emerged as a new strategy.</p>
<p>Today, companies like Spotify apply DevTestOps in software production which makes it easier for them to update, test, and deploy any changes quickly and easily.</p>
<p>In this article, we are going to look at DevTestOps, its objectives, and processes. We'll also look at how to get started with DevTestOps, best practices, and why a company should adopt DevTestOps.</p>
<p>Before we dive into DevTestOps, let’s look at what DevOps and TestOps are and how they work.</p>
<h2 id="heading-what-are-devops-and-testops">What are DevOps and TestOps?</h2>
<p>DevOps is a combination of Development and Operations. DevOps was introduced in the software development life cycle because of the need for continuous product development. It helps teams more easily integrate and deploy software updates.</p>
<p>TestOps involves carrying out large automation test suites across software so that the software is highly efficient with fewer bugs.</p>
<p>Initially, DevOps was introduced in software teams which enabled collaboration across developers and operators only. Then testers carried out tests towards the end of development.</p>
<p>This posed some challenges to the team, though. Especially after working on some software and concluding it was ready for production – only for the testers to run it and discover complex bugs. It was through these challenges that DevTestOps came to be.</p>
<h2 id="heading-what-is-devtestops">What is DevTestOps?</h2>
<p>DevTestOps is a pattern and part of the software development life cycle that includes continuous testing, integration, and deployment.</p>
<p>In DevTestOps, you test the product throughout the different development stages, which helps reduce the number of bugs at later stages.</p>
<p>In DevTestOps, the Development, Testing, and Operations Teams work hand in hand to ensure quality and proper product testing.</p>
<p>This results in quick delivery, with few to no bugs at the end of the software development lifecycle.</p>
<p>DevTestOps came about as an improved version of DevOps with TestOps included. This makes it easier to build, deploy, and develop quality products with fewer bugs.</p>
<h2 id="heading-objectives-of-devtestops">Objectives of DevTestOps</h2>
<p>DevTestOps has objectives that are called manifestos. The manifestos define the goals that you expect to achieve.</p>
<p>According to <a target="_blank" href="https://www.google.com/amp/s/www.mabl.com/blog/the-road-to-devtestops%3fhs_amp=true">mabl.com</a>:</p>
<blockquote>
<p>"There are five manifestos of DevTestOps which include: Continuous testing over testing at the end. Embracing all testing activities over only automated functional testing. Testing what gives value over testing everything. Testing across the team over testing in siloed testing departments. Product coverage over code coverage." (Source: <a target="_blank" href="https://www.google.com/amp/s/www.mabl.com/blog/the-road-to-devtestops%3fhs_amp=true">mabl.com</a>)</p>
</blockquote>
<h2 id="heading-how-devtestops-works">How DevTestOps Works</h2>
<p>There are various stages of the DevTestOps process. These stages are:</p>
<ol>
<li><p><strong>Plan:</strong> In this stage, you define product details and cross-check to make sure everything aligns with the market.</p>
</li>
<li><p><strong>Build:</strong> In this stage, you build the program and upload it to the repository, carry out unit tests, and if you found the program to have no bugs, then it becomes the codebase. You can add possible updates (suggestions or improvements) before moving to the next stage.</p>
</li>
<li><p><strong>Testing:</strong> In this stage, you carry out and analyse all test cases. You can make subsequent updates and test the program again before delivering it and considering it ready for deployment.</p>
</li>
<li><p><strong>Release:</strong> You launch the product and test other written updates before it is added to the codebase.</p>
</li>
<li><p><strong>Monitor:</strong> You constantly check the product for feedback and issues which are handled and updated immediately.</p>
</li>
</ol>
<h2 id="heading-how-to-get-started-with-devtestops">How to Get Started With DevTestOps:</h2>
<p>Many organisations already use DevOps but keep producing buggy software. If you want to switch to DevTestOps to try to reduce the bugs in your code, here are some steps you can follow.</p>
<h3 id="heading-add-continuous-testing-to-yout-devops-roadmap-or-guide">Add continuous testing to yout DevOps roadmap or guide:</h3>
<p>DevTestOps has a similar culture to DevOps except that in this case, you add continuous testing. Testers should become part of the DevOps team so they can test the software immediately after an update.</p>
<h3 id="heading-create-a-devtestops-toolchain">Create a DevTestOps toolchain:</h3>
<p>A toolchain includes all the tools required to implement DevTestOps. For example, your toolchain might comprise tools like Jira, Kubernetes, Selenium, GitHub, Jenkins and more.</p>
<p>You can assign roles to different teams using these tools so they can work effectively with them.</p>
<h3 id="heading-implement-the-tools-in-your-organization">Implement the tools in your organization:</h3>
<p>Next, you'll need to teach teams how to implement these tools and follow the strategies you put in place for software production.</p>
<p>You could add testing roles to each team, which would transform the work culture and encourage collaboration between the developers, testers and operators in each team.</p>
<h3 id="heading-automation">Automation:</h3>
<p>You should apply automation in each of these processes, from the build phase to the deployment phase. This will help all the developers and testers work more efficiently.</p>
<h3 id="heading-make-constant-improvements">Make Constant improvements:</h3>
<p>Finally, you can constantly update the tools and processes to accommodate relevant trends and updates in the technological space.</p>
<h2 id="heading-best-practices-for-devtestops">Best Practices for DevTestOps:</h2>
<p>Here are some best practices you can follow to implement DevTestOps in your team:</p>
<ul>
<li><p>Use the right tools and frameworks for integration, testing, delivery and deployment. This will depend on what works best for the organization.</p>
</li>
<li><p>Apply automation in testing, deployment, and even other stages as well. Automation will help to speed up the process and make it easier for teams to produce faster and meet with deadlines.</p>
</li>
<li><p>All teams should communicate effectively. They should promote collaboration across teams to increase understanding which will increase productivity and eliminate confusion.</p>
</li>
<li><p>The pipeline which comprises continuous integration, testing, delivery and deployment should be monitored always. If you spot a problem, teams can make changes and integrate the updates immediately.</p>
</li>
</ul>
<h2 id="heading-why-should-you-adopt-devtestops">Why Should You Adopt DevTestOps?</h2>
<p>‌There are many reasons to adopt DevTestOps. First, it improves code quality.</p>
<p>It also improves collaboration between developers, testers, and operators. Like in the manifesto, testing is no longer done in siloed testing departments but across each phase.</p>
<p>Additionally, it saves time that is spent on fixing bugs when testing at the end instead of in each stage.</p>
<p>And finally, it makes it easier to perform continuous integration and deployment.‌</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>In a world of constant improvements in technology, companies must continually improve their software to meet market standards.</p>
<p>With DevTestOps, it becomes easier for software teams to make updates and improve their products.</p>
<h3 id="heading-resources">Resources:</h3>
<ul>
<li><p><a target="_blank" href="https://www.google.com/amp/s/www.xenonstack.com/insights/devtestops-advantages%3fhs_amp=true">DevOps Advantages And Best Practices | Quick Guide</a></p>
</li>
<li><p><a target="_blank" href="https://www.google.com/amp/s/blog.kms-solutions.asia/an-ultimate-guide-to-devtestops%3fhs_amp=true">What Is DevTestOps And How Can It Transform Agile</a></p>
</li>
<li><p><a target="_blank" href="https://www.google.com/amp/s/katalon.com/resources-center/blog/devtestops-orchestration-agile-teams%3fhs_amp=true">What Is DevOps Orchestration For Agile Teams?</a></p>
</li>
</ul>
 ]]>
                </content:encoded>
            </item>
        
            <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 Test PHP Code With PHPUnit ]]>
                </title>
                <description>
                    <![CDATA[ There are many different ways to test your software application, and unit testing is an important one. So what is unit testing and how can you do it? You'll learn that and more in this article. What is Unit Testing? Unit testing is a software develo... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/test-php-code-with-phpunit/</link>
                <guid isPermaLink="false">66c4c6adbd556981b1bdc462</guid>
                
                    <category>
                        <![CDATA[ PHP ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Software Testing ]]>
                    </category>
                
                    <category>
                        <![CDATA[ unit testing ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Zubair Idris Aweda ]]>
                </dc:creator>
                <pubDate>Wed, 09 Mar 2022 01:15:45 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2022/03/120480919-metal-bolts-nuts-group-drawing-technical-drafting-steel-screws-threaded-parts-with-hexagonal-head-bl--1-.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>There are many different ways to test your software application, and unit testing is an important one.</p>
<p>So what is unit testing and how can you do it? You'll learn that and more in this article.</p>
<h2 id="heading-what-is-unit-testing">What is Unit Testing?</h2>
<blockquote>
<p>Unit testing is a software development process in which the smallest testable parts of an application, called units, are individually and independently scrutinised for process operation. - <a target="_blank" href="https://searchsoftwarequality.techtarget.com/definition/unit-testing#:~:text=Unit%20testing%20is%20a%20software,developers%20and%20sometimes%20QA%20staff.">SearchSoftwareQuality</a></p>
</blockquote>
<p>In basic terms, unit testing means that you break your application down to its simplest pieces and test these small pieces to ensure that each part is error free (and secure). </p>
<p>This testing is automated and written by software engineers as part of their development process. This is a very important step during development as it helps developers build better applications with fewer bugs.</p>
<h2 id="heading-what-is-phpunit">What is PHPUnit?</h2>
<p>You can perform unit testing in PHP with <a target="_blank" href="https://phpunit.de">PHPUnit</a>, a programmer-oriented testing framework for PHP. PHPUnit is an instance of the xUnit architecture for unit testing frameworks. It is very easy to install and get started with.</p>
<h2 id="heading-phpunit-installation">PHPUnit Installation</h2>
<p>You can install PHPUnit globally on your server. You can also install it locally, on a per-project, development-time basis as a dependency to your project using composer. This article will explain how to use it on a per project basis.</p>
<p>To get started, create and initiate a new project with composer using these commands:</p>
<pre><code class="lang-bash">$ mkdir test-project
$ <span class="hljs-built_in">cd</span> test-project
$ composer init
</code></pre>
<p>The first command creates a folder in your current directory, <code>test-project</code> and the second command moves into it. The last command starts an interactive shell.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/03/Screenshot-2022-03-08-at-11.08.39.png" alt="Image" width="600" height="400" loading="lazy">
<em>Composer init prompt</em></p>
<p>Follow the prompt, filling in the details as required (the default values are fine). You can set the project description, author name (or contributors' names), minimum stability for dependencies, project type, license, and define your dependencies.</p>
<p>You can skip the dependencies part, as we are not installing any dependencies. PHPUnit is supposed to be a <code>dev-dependency</code> because testing as a whole should only happen during development.</p>
<p>Now, when the prompt asks <code>Would you like to define your dev dependencies (require-dev) interactively [yes]?</code>, press enter to accept. Then type in <code>phpunit/phpunit</code> to install PHPUnit as a <code>dev-dependency</code>.</p>
<p>Accept the other defaults and proceed to generating the <code>composer.json</code> file. The generated file should look like this currently:</p>
<pre><code class="lang-json">{
    <span class="hljs-attr">"name"</span>: <span class="hljs-string">"zubair/test-project"</span>,
    <span class="hljs-attr">"require-dev"</span>: {
        <span class="hljs-attr">"phpunit/phpunit"</span>: <span class="hljs-string">"^9.5"</span>
    },
    <span class="hljs-attr">"autoload"</span>: {
        <span class="hljs-attr">"psr-4"</span>: {
            <span class="hljs-attr">"Zubair\\TestProject\\"</span>: <span class="hljs-string">"src/"</span>
        }
    },
    <span class="hljs-attr">"authors"</span>: [
        {
            <span class="hljs-attr">"name"</span>: <span class="hljs-string">"Idris Aweda Zubair"</span>,
            <span class="hljs-attr">"email"</span>: <span class="hljs-string">"zubairidrisaweda@gmail.com"</span>
        }
    ],
    <span class="hljs-attr">"require"</span>: {}
}
</code></pre>
<p>To learn how to install PHPUnit globally on your server, read <a target="_blank" href="https://phpunit.readthedocs.io/en/9.5/installation.html#">here</a>.</p>
<h2 id="heading-how-to-write-tests-in-phpunit">How to Write Tests in PHPUnit</h2>
<p>Writing tests in PHPUnit is quite simple. Here are a few conventions to get you started:</p>
<ul>
<li>To test a class in PHP, you'll create a test class named after that class. For example, if I had some sort of <code>User</code> class, the test class would be named <code>UserTest</code>.</li>
<li>The test class, <code>UserTest</code>, will usually inherit the <code>PHPUnit\Framework\TestCase</code> class.</li>
<li>Individual tests on the class are public methods named with <code>test</code> as a prefix. For example, to test a <code>sayHello</code> method on the <code>User</code> class, the method will be named <code>testSayHello</code>.</li>
<li>Inside the test method, say <code>testSayHello</code>, you use PHPUnit's method like <code>assertSame</code> to see that some method returns some expected value.</li>
</ul>
<p>A popular convention is to have all tests in a <code>tests</code> directory, and all source code in the <code>src</code> directory. </p>
<h2 id="heading-phpunit-testing-example">PHPUnit Testing Example</h2>
<p>To help understand this article, here's a sample <code>User</code> class with simple methods that will be tested:</p>
<pre><code class="lang-php"><span class="hljs-meta">&lt;?php</span>

<span class="hljs-keyword">namespace</span> <span class="hljs-title">Zubair</span>\<span class="hljs-title">TestProject</span>;

<span class="hljs-keyword">use</span> <span class="hljs-title">InvalidArgumentException</span>;

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">User</span>
</span>{
    <span class="hljs-keyword">public</span> <span class="hljs-keyword">int</span> $age;
    <span class="hljs-keyword">public</span> <span class="hljs-keyword">array</span> $favorite_movies = [];
    <span class="hljs-keyword">public</span> <span class="hljs-keyword">string</span> $name;

    <span class="hljs-comment">/**
     * <span class="hljs-doctag">@param</span> int $age
     * <span class="hljs-doctag">@param</span> string $name
     */</span>
    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">__construct</span>(<span class="hljs-params"><span class="hljs-keyword">int</span> $age, <span class="hljs-keyword">string</span> $name</span>)
    </span>{
        <span class="hljs-keyword">$this</span>-&gt;age = $age;
        <span class="hljs-keyword">$this</span>-&gt;name = $name;
    }

    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">tellName</span>(<span class="hljs-params"></span>): <span class="hljs-title">string</span>
    </span>{
        <span class="hljs-keyword">return</span> <span class="hljs-string">"My name is "</span> . <span class="hljs-keyword">$this</span>-&gt;name . <span class="hljs-string">"."</span>;
    }

    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">tellAge</span>(<span class="hljs-params"></span>): <span class="hljs-title">string</span>
    </span>{
        <span class="hljs-keyword">return</span> <span class="hljs-string">"I am "</span> . <span class="hljs-keyword">$this</span>-&gt;age . <span class="hljs-string">" years old."</span>;
    }

    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">addFavoriteMovie</span>(<span class="hljs-params"><span class="hljs-keyword">string</span> $movie</span>): <span class="hljs-title">bool</span>
    </span>{
        <span class="hljs-keyword">$this</span>-&gt;favorite_movies[] = $movie;

        <span class="hljs-keyword">return</span> <span class="hljs-literal">true</span>;
    }

    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">removeFavoriteMovie</span>(<span class="hljs-params"><span class="hljs-keyword">string</span> $movie</span>): <span class="hljs-title">bool</span>
    </span>{
        <span class="hljs-keyword">if</span> (!in_array($movie, <span class="hljs-keyword">$this</span>-&gt;favorite_movies)) <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">InvalidArgumentException</span>(<span class="hljs-string">"Unknown movie: "</span> . $movie);

        <span class="hljs-keyword">unset</span>(<span class="hljs-keyword">$this</span>-&gt;favorite_movies[array_search($movie, <span class="hljs-keyword">$this</span>-&gt;favorite_movies)]);

        <span class="hljs-keyword">return</span> <span class="hljs-literal">true</span>;
    }
}
</code></pre>
<p>This user class could be the <code>User</code> class in your movie streaming application. The user has a name, age, and a list of favourite movies that can be updated. For the rest of the article we will test that all these features work as they're expected to.</p>
<p>Create a <code>UserTest</code> class in the <code>tests</code> folder. Paste this in to start:</p>
<pre><code class="lang-php"><span class="hljs-meta">&lt;?php</span>

<span class="hljs-keyword">namespace</span> <span class="hljs-title">Zubair</span>\<span class="hljs-title">TestProject</span>;

<span class="hljs-keyword">use</span> <span class="hljs-title">PHPUnit</span>\<span class="hljs-title">Framework</span>\<span class="hljs-title">TestCase</span>;

<span class="hljs-keyword">final</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">UserTest</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">TestCase</span>
</span>{
    <span class="hljs-comment">// Tests will go here</span>
}
</code></pre>
<h3 id="heading-test-constructor">Test Constructor</h3>
<p>Normally, you wouldn't be testing the <code>__construct</code> method. However, since we're setting values in it, it only makes sense to be sure that the values are being set correctly. </p>
<p>This seems like a very small thing to test, but that's the whole point of unit tests – to ensure that the smallest parts of your application function as expected.</p>
<p>Create a <code>testClassConstructor</code> method to test the constructor:</p>
<pre><code class="lang-php"><span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">testClassConstructor</span>(<span class="hljs-params"></span>)
</span>{
    $user = <span class="hljs-keyword">new</span> User(<span class="hljs-number">18</span>, <span class="hljs-string">'John'</span>);

    <span class="hljs-keyword">$this</span>-&gt;assertSame(<span class="hljs-string">'John'</span>, $user-&gt;name);
    <span class="hljs-keyword">$this</span>-&gt;assertSame(<span class="hljs-number">18</span>, $user-&gt;age);
    <span class="hljs-keyword">$this</span>-&gt;assertEmpty($user-&gt;favorite_movies);
}
</code></pre>
<p>Let's take a quick break now, to see how to run the tests.</p>
<h2 id="heading-how-to-run-tests-in-phpunit">How to Run Tests in PHPUnit</h2>
<p>You can run all the tests in a directory using the PHPUnit binary installed in your vendor folder.</p>
<pre><code class="lang-bash">$ ./vendor/bin/phpunit --verbose tests
</code></pre>
<p>You can also run a single test by providing the path to the test file.</p>
<pre><code class="lang-bash">$ ./vendor/bin/phpunit --verbose tests/UserTest.php
</code></pre>
<p>You use the <code>--verbose</code> flag to get more information on the test status.</p>
<p>Now, we can run the test and see the output:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/03/Screenshot-2022-03-08-at-13.17.54.png" alt="Image" width="600" height="400" loading="lazy">
<em>Test Output</em></p>
<p>The output shows that we ran 1 test, and made 3 assertions in it. We also see how long it took to run the test, as well as how much memory was used in running the test.</p>
<p>These assertions are what PHPUnit uses to compare values returned from the methods to their expected value. </p>
<p>This example uses <code>assertSame</code> to check if the <code>name</code> and <code>age</code> properties on the user object match the entered values. It also uses <code>assertEmpty</code> to check that the <code>favorite_movies</code> array is empty. </p>
<p>To see a list of all these assertions, you can check out PHPUnit's docs <a target="_blank" href="https://phpunit.readthedocs.io/en/9.5/assertions.html#appendixes-assertions">here</a>.</p>
<p>Edit the code to check if the user age is the same as <em>21</em>.</p>
<pre><code class="lang-php"><span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">testClassConstructor</span>(<span class="hljs-params"></span>)
</span>{
    $user = <span class="hljs-keyword">new</span> User(<span class="hljs-number">18</span>, <span class="hljs-string">'John'</span>);

    <span class="hljs-keyword">$this</span>-&gt;assertSame(<span class="hljs-string">'John'</span>, $user-&gt;name);
    <span class="hljs-keyword">$this</span>-&gt;assertSame(<span class="hljs-number">21</span>, $user-&gt;age);
    <span class="hljs-keyword">$this</span>-&gt;assertEmpty($user-&gt;favorite_movies);
}
</code></pre>
<p>Running the test again this time gives this output:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/03/Screenshot-2022-03-08-at-13.24.20.png" alt="Image" width="600" height="400" loading="lazy">
<em>Failed Assertion Output</em></p>
<p>The output now shows that we ran 1 test, with 2 successful assertions, and also a failed one. We can see some explanation of the failure, showing the expected value, the gotten value, and the line where the error is from.</p>
<h3 id="heading-test-testname-and-tellage">Test testName and tellAge</h3>
<p>Next, we can test the <code>testName</code> method. This method tells the name of a user as a sentence. So, we can write the test to check:</p>
<ul>
<li>If the returned value is a string.</li>
<li>If the returned string has the user's name in it (with or without case sensitivity).</li>
</ul>
<pre><code class="lang-php"><span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">testTellName</span>(<span class="hljs-params"></span>)
</span>{
    $user = <span class="hljs-keyword">new</span> User(<span class="hljs-number">18</span>, <span class="hljs-string">'John'</span>);

    <span class="hljs-keyword">$this</span>-&gt;assertIsString($user-&gt;tellName());
    <span class="hljs-keyword">$this</span>-&gt;assertStringContainsStringIgnoringCase(<span class="hljs-string">'John'</span>, $user-&gt;tellName());
}
</code></pre>
<p>The test uses the assertions <code>assertIsString</code>  and <code>assertStringContainsStringIgnoringCase</code> to check that the return value is a string and that it contains the string <em>John</em>, respectively.</p>
<p>The <code>testAge</code> method is very similar to <code>testName</code> and uses the same logic. Its test will be similar to the previous one:</p>
<pre><code class="lang-php"><span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">testTellAge</span>(<span class="hljs-params"></span>)
</span>{
    $user = <span class="hljs-keyword">new</span> User(<span class="hljs-number">18</span>, <span class="hljs-string">'John'</span>);

    <span class="hljs-keyword">$this</span>-&gt;assertIsString($user-&gt;tellAge());
    <span class="hljs-keyword">$this</span>-&gt;assertStringContainsStringIgnoringCase(<span class="hljs-string">'18'</span>, $user-&gt;tellAge());
}
</code></pre>
<h3 id="heading-test-addfavoritemovie">Test addFavoriteMovie</h3>
<p>We can test this method, too. This method adds a movie to the list of movies. To test it, we can check if the newly added movie is in the list, and that the number of items in the list actually increased. </p>
<p>The latter is for confirming that items are not being displaced. Also, since the function returns some value at the end, we can check that this value is correct too.</p>
<pre><code class="lang-php"><span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">testAddFavoriteMovie</span>(<span class="hljs-params"></span>)
</span>{
    $user = <span class="hljs-keyword">new</span> User(<span class="hljs-number">18</span>, <span class="hljs-string">'John'</span>);

    <span class="hljs-keyword">$this</span>-&gt;assertTrue($user-&gt;addFavoriteMovie(<span class="hljs-string">'Avengers'</span>));
    <span class="hljs-keyword">$this</span>-&gt;assertContains(<span class="hljs-string">'Avengers'</span>, $user-&gt;favorite_movies);
    <span class="hljs-keyword">$this</span>-&gt;assertCount(<span class="hljs-number">1</span>, $user-&gt;favorite_movies);
}
</code></pre>
<p>Here, we use a few new assertions – <code>assertTrue</code>, <code>assertContains</code>, and <code>assertCount</code> – to check that the returned value is true, that it contains the newly added string, and that the array now has one item in it.</p>
<h3 id="heading-test-removefavoritemovie">Test removeFavoriteMovie</h3>
<p>Finally, we can test that the method to remove a movie works. </p>
<pre><code class="lang-php"><span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">testRemoveFavoriteMovie</span>(<span class="hljs-params"></span>)
</span>{
    $user = <span class="hljs-keyword">new</span> User(<span class="hljs-number">18</span>, <span class="hljs-string">'John'</span>);

    <span class="hljs-keyword">$this</span>-&gt;assertTrue($user-&gt;addFavoriteMovie(<span class="hljs-string">'Avengers'</span>));
    <span class="hljs-keyword">$this</span>-&gt;assertTrue($user-&gt;addFavoriteMovie(<span class="hljs-string">'Justice League'</span>));

    <span class="hljs-keyword">$this</span>-&gt;assertTrue($user-&gt;removeFavoriteMovie(<span class="hljs-string">'Avengers'</span>));
    <span class="hljs-keyword">$this</span>-&gt;assertNotContains(<span class="hljs-string">'Avengers'</span>, $user-&gt;favorite_movies);
    <span class="hljs-keyword">$this</span>-&gt;assertCount(<span class="hljs-number">1</span>, $user-&gt;favorite_movies);
}
</code></pre>
<p>Here, we're adding some movies to the list. Then, we remove one of them, and confirm that the function returned true. Next, we confirm the removal by checking that the value is no longer in the list. Finally, we confirm that we have only one movie in the list, instead of two.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>Now you know how to set up PHPUnit in your projects and how to test and ensure that you're building world class software. You can find all the code for this article <a target="_blank" href="https://github.com/Zubs/php-testing">here</a>.</p>
<p>If you have any questions or relevant advice, please get in touch with me to share them.</p>
<p>To read more of my articles or follow my work, you can connect with me on <a target="_blank" href="https://www.linkedin.com/in/idris-aweda-zubair-5433121a3/">LinkedIn</a>, <a target="_blank" href="https://twitter.com/AwedaIdris">Twitter</a>, and <a target="_blank" href="https://github.com/Zubs">Github</a>. It’s quick, it’s easy, and it’s free!</p>
 ]]>
                </content:encoded>
            </item>
        
    </channel>
</rss>
