<?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[ Matthes B. - 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[ Matthes B. - freeCodeCamp.org ]]>
            </title>
            <link>https://www.freecodecamp.org/news/</link>
        </image>
        <generator>Eleventy</generator>
        <lastBuildDate>Thu, 14 May 2026 22:43:29 +0000</lastBuildDate>
        <atom:link href="https://www.freecodecamp.org/news/author/DearFutureMe/rss.xml" rel="self" type="application/rss+xml" />
        <ttl>60</ttl>
        
            <item>
                <title>
                    <![CDATA[ API Testing with Postman: A Step-by-Step Guide Using the Spotify API ]]>
                </title>
                <description>
                    <![CDATA[ 🎯 The Objective In this guide, I’ll introduce you to Postman, a popular API development and testing tool. If you are a beginner mainly focused on frontend development, you may not have had much experience fetching data from an API. And in that case ... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/api-testing-with-postman-a-step-by-step-guide-using-the-spotify-api/</link>
                <guid isPermaLink="false">66e1d20cbe8f281fa6f7660a</guid>
                
                    <category>
                        <![CDATA[ Postman ]]>
                    </category>
                
                    <category>
                        <![CDATA[ APIs ]]>
                    </category>
                
                    <category>
                        <![CDATA[ API basics  ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Spotify ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Matthes B. ]]>
                </dc:creator>
                <pubDate>Wed, 11 Sep 2024 17:23:24 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/uv5_bsypFUM/upload/ef5e3375e4ea08db6b5addd47afbc82f.jpeg" medium="image" />
                <content:encoded>
                    <![CDATA[ <h2 id="heading-the-objective"><strong>🎯</strong> The Objective</h2>
<p>In this guide, I’ll introduce you to Postman, a popular API development and testing tool.</p>
<p>If you are a beginner mainly focused on frontend development, you may not have had much experience fetching data from an API. And in that case you probably haven't encountered many situations where you need to make multiple requests to an API for testing purposes during your development process.</p>
<p>But understanding how to test APIs and connect with them via Postman or similar tools will become important at some point in your career. If you decide to venture into backend development, understanding these concepts is essential.</p>
<p>After covering some basic information about Postman and the Spotify API documentation, we’ll dive into more key Postman features. Then, we’ll select one Spotify endpoint and walk through the process of making requests to it.</p>
<h2 id="heading-heres-what-well-cover"><strong>🔐 Here's What We'll Cover</strong></h2>
<ul>
<li><p>You'll gain fundamental knowledge of working with Postman.</p>
</li>
<li><p>You'll strengthen your ability to work with APIs and their documentation.</p>
</li>
<li><p>You'll explore the basics of the public Spotify API.</p>
</li>
</ul>
<h2 id="heading-prerequisites"><strong>📝</strong> Prerequisites</h2>
<ul>
<li><p>You should have a basic understanding of APIs.</p>
</li>
<li><p>You don't need any prior knowledge of Postman.</p>
</li>
</ul>
<h2 id="heading-table-of-contents">Table of Contents</h2>
<ol>
<li><p><a class="post-section-overview" href="#heading-exploring-the-spotify-api-with-postman">Exploring the Spotify API with Postman</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-the-postman-experience">The Postman Experience</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-make-your-first-request-to-the-spotify-api">How to Make Your First Request to the Spotify API</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-spotify-api-authorization">Spotify API Authorization</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-spotify-api-authorization-scopes">Spotify API Authorization Scopes</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-summary">Summary</a></p>
</li>
</ol>
<h2 id="heading-exploring-the-spotify-api-with-postman">Exploring the Spotify API with Postman</h2>
<p>To get a brief overview of what Postman is, let's refer to the following explanation from ChatGPT:</p>
<blockquote>
<p>"Postman is a popular API (Application Programming Interface) development and testing tool that simplifies working with APIs by providing an easy-to-use interface for sending HTTP requests and receiving responses. It's widely used by developers, QA engineers, and teams who work with APIs to ensure they function correctly and efficiently."</p>
</blockquote>
<p>While we will focus on making HTTP requests, it's important to note that Postman is also versatile and can be used to work with GraphQL, gRPC, WebSocket, Socket.IO, and MQTT.</p>
<p>With Postman in hand, we need an API endpoint to test. For this, we’ll use the public Spotify API, which offers a variety of endpoints for different use cases. This can even be an exciting opportunity for your next project if you're a beginner looking for a fun project to explore.</p>
<p>The <a target="_blank" href="https://developer.spotify.com/documentation/web-api">Spotify Web API</a> is professionally designed, offering all the necessary information for developers. With their "Overview" and "Getting Started" sections, it's straightforward to follow along, even for beginners.</p>
<p>While learning the basics of Postman, we will explore key parts of the Spotify API documentation necessary for successful API testing. For instance, we will demonstrate how to make an HTTP request to the endpoint for <a target="_blank" href="https://developer.spotify.com/documentation/web-api/reference/get-playlist">retrieving data from a playlist</a>.</p>
<p>But first, let’s cover some Postman fundamentals.</p>
<h2 id="heading-the-postman-experience">The Postman Experience</h2>
<p>You can use Postman in a number of different ways. In my case, I'm using the <a target="_blank" href="https://www.postman.com/downloads/">desktop version</a> of Postman.</p>
<p>But you can also use Postman directly in your browser, or even via the Postman CLI (Command Line Interface). There's also an official Postman extension for VS Code. You can find these versions through the link I just shared.</p>
<p>If you're completely new to Postman, you may want to start with the web version or the downloadable desktop version, especially if you plan to use Postman regularly in the future.</p>
<p>After starting the desktop version of Postman, the first thing you’ll see is this:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1725784802934/f999e51b-13d1-4bfc-b51a-99cf16c51209.png" alt="Initial Postman interface view" class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<p>This might look slightly different from what you see initially. I already have an account. You may need to create one first for free. You also may need to create a workspace first. In my case, I’m already inside the "My Workspace" workspace.</p>
<p>In the upper left corner, you'll find several tabs, including "Collections", "Environments", "History", and an icon to configure this sidebar.</p>
<p>For now, we’ll stay on the "Collections" tab and click on "Create Collection":</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1725785048909/3751a2a7-c583-4918-ba92-b14ddf09787c.png" alt="Creating a new collection in Postman" class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<p>Once you click on that, your focus will shift to the name of the collection in the top center. By typing, you can rename your collection from "New Collection" to something more appropriate for your specific use case.</p>
<p>For this case, I named the collection "Spotify API":</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1725785166414/65ae8c54-be76-4b70-99b1-87897ef0506d.png" alt="Viewing a created collection in Postman" class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<p>Now, we have a collection, but what exactly is that? A collection is essentially a space to organize multiple request structures. This will become clearer once we add our first HTTP request. You can do this by clicking on the blue text that says "Add a request":</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1725785355577/2b7cb0ea-9fe4-41e5-a0b4-a01472a6c4b5.png" alt="Creating the first request within a collection in Postman" class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<p>When you do that, your focus will again be on the name of the element. If you type something now, you can rename the request from "New Request" to something more appropriate for the situation. In this case, since I’m not sure which request I want to create yet, I'll simply call it "test" for now.</p>
<p>If you'd like to create another request at this point, you can click on the three dots to the right of the collection's name (the 6th option):</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1725785494545/227bad55-040f-45c4-8afc-5fb978714d53.png" alt="Creating new requests within a collection in Postman" class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<p>There are multiple options you can choose from, with "Add request" being one of them.</p>
<p>At this point, we've created a collection within our workspace, and inside that collection, we've added an HTTP request. You can have multiple collections, each containing multiple requests. This helps organize your requests, especially when you reach a point where having one large list of pre-configured requests becomes cumbersome to manage.</p>
<p>On the newly created HTTP request, we can see some details:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1725785740673/b7d66a0d-d16c-4cf5-846b-21c0289e1fc9.png" alt="Viewing a created HTTP request in Postman" class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<p>The first thing you might notice is the HTTP request method, which is set to "GET" by default. If you click on "GET" with the downward arrow, you can choose from various methods or even type in your own if needed.</p>
<p>To the right of that, there’s a text field where you'll enter your API’s URL along with its endpoint (we'll try this shortly).</p>
<p>Below, there are several important tabs. Right now, we're on the "Params" tab. Here, you can add key-value pairs that will directly modify the request you're making. These are called Query Params, which you may have encountered before. For example, if your URL is <code>https://google.com</code>, adding a key-value pair as a Query Param might look like this:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1725786057766/5c379d02-a1db-4484-9951-17d8fc63d9f5.png" alt="Adding Query Params to a HTTP request in Postman" class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<p>As for Query Params, whether you need them depends on the request you're making. A common use case would be pagination on a website with a table. For example, you might use a query param like "page=4" to specify which page of results you want.</p>
<p>Next is the "Authorization" tab, which handles authentication and authorization for your request. We’ll cover this in more detail later, so we’ll skip it for now.</p>
<p>Then, we have the "Headers" tab, which is crucial because it contains all the information included in your request’s header, such as any authorization data if that’s set up.</p>
<p>Finally, the "Body" tab, located to the right, is also quite important. For instance, if you’re making a POST request to add an item to a database, you’d likely need to send information such as the item’s name or category. This kind of data is often included in the request body in JSON format.</p>
<p>To add JSON-formatted data, you can click on "raw" within the "Body" tab, and then select the format you want (with "JSON" being the default option):</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1725786376804/334980e7-f2a4-44ec-b354-6923254c842b.png" alt="Viewing the &quot;Body&quot; tab of a HTTP request in Postman" class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<p>As with Query Params, the format and data required depend heavily on the API and endpoint you're using. Just keep in mind that you can configure all the necessary options within these tabs.</p>
<p>The remaining two tabs are "Scripts" and "Settings." In the "Scripts" tab, you can add custom code, but this is more advanced and not necessary for our current situation. The "Settings" tab allows for adjustments, though in most cases, you won’t need to modify anything here.</p>
<h2 id="heading-how-to-make-your-first-request-to-the-spotify-api">How to Make Your First Request to the Spotify API</h2>
<p>Now, we’ll make our first actual request using Postman. For this, we can dive into the Spotify API developer documentation, where all endpoints are listed. For this first test, we’ll <a target="_blank" href="https://developer.spotify.com/documentation/web-api/reference/get-playlist">fetch data about a playlist</a>.</p>
<p>In that description, you’ll find a wealth of useful information, including the endpoint and the required data for a successful response. You also have the option to make the request directly from the page after logging in with your Spotify account:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1725786874122/dfc15da0-4c9d-465d-8f29-470b7978ed18.png" alt="Viewing the &quot;Get Playlist&quot; Spotify API documentation" class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<p>Such extensive API documentation is incredibly helpful and makes it easy to work with, especially for beginners. Keep in mind, though, that not all API documentation is this thorough.</p>
<p>In this case, we can see the endpoint is <code>https://api.spotify.com/v1/playlists/{playlist_id}</code>, with <code>playlist_id</code> being the only required parameter in the curly brackets. You’ll also see optional parameters like <code>market</code>, <code>fields</code>, and <code>additional_types</code>, which can help refine the response. But again, these are optional, and you only need <code>playlist_id</code> for the basic request.</p>
<p>If you want to include optional information, like <code>market</code>, you’d use the Query Params mentioned earlier. For example, adding <code>ES</code> as the market alongside the <code>playlist_id</code> would change the URL to: <code>https://api.spotify.com/v1/playlists/3cEYpjA9oz9GiPac4AsH4n?market=ES</code>.</p>
<p>To make the basic request in Postman (without any optional parameters), we’ll return to our "test" request and enter the URL with the corresponding endpoint:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1725787287945/6c54e09f-08c0-4bf9-9dd9-deabe5a24a22.png" alt="Inserting the &quot;Get Playlist&quot; Spotify API endpoint in a HTTP request in Postman" class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<p>This approach will work, but I recommend another method.</p>
<p>Since we have our Spotify API collection and may want to add multiple requests to that collection, it's a good practice to use variables for sections of the URL or information that will remain consistent across multiple requests. In this case, the base URL, <code>https://api.spotify.com/v1/</code>, will stay the same for all Spotify API requests. Instead of manually adding it to every request, we can create a variable for it.</p>
<p>To do this, we’ll switch to the "Environments" tab in the upper left corner. From there, click on the plus icon to create a new environment:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1725787536747/937b306f-1f54-4434-973d-6ba389a865fe.png" alt="Creating a new environment in Postman" class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<p>We'll name the environment “Spotify API”.</p>
<p>Next, we'll create variables, such as <code>base_url</code>, and assign the appropriate value to it. You can also choose between the type options: <code>default</code> or <code>secret</code>. Since this isn't sensitive data, it can remain set to <code>default</code>. If you choose <code>secret</code>, you'd need to click on an eye icon to reveal the variable’s value each time, otherwise, it would be masked with <code>••••</code>, similar to how passwords are displayed.</p>
<p>Here’s what it looks like so far:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1725787778964/02e4bcf5-3f36-47e8-9882-6cdba591e443.png" alt="Creating an environment variable in Postman" class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<p>Next, we’ll return to the Spotify API collection and look at the upper right corner, where it currently says "No environment". Click there and select the "Spotify API" environment that we just created:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1725787865310/abb97e82-2a6b-4411-a8cd-9e4430e83956.png" alt="Selecting the created environment for the current collection in Postman" class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<p>Now, we can use the variables from that environment for all the requests within the "Spotify API" collection. To insert a variable, you’ll use double square brackets, like this:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1725788017057/10cd4dbc-fecf-46d7-9789-9c80b1325215.png" alt="Inserting the created environment variable for the HTTP request in Postman" class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<p>If you receive a message that the variable couldn't be found, make sure to save the "Spotify API" environment. The dots on the right of the tab names indicate that you can save new information by pressing <code>CTRL + S</code>, for example. This step is necessary for the created variable to be recognized.</p>
<p>With the variable in place, you can now modify just this one variable to change the <code>base_url</code> for all your corresponding requests. While this may not seem immediately useful for the <code>base_url</code>, since it likely won’t change anytime soon, variables can be incredibly helpful in other scenarios. This was an opportunity to introduce you to how they work.</p>
<p>Next, I’ll rename the HTTP request from "test" to something more descriptive, like "Playlist," to indicate what this request is about. Along with the "GET" method, it will be clear that this request is for fetching playlist data.</p>
<p>Now that everything is set, let's send the request by clicking the "Send" button on the right while viewing the HTTP request. You’ll see the response appear in the bottom half of the screen:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1725788403952/4212378e-c000-4b5c-bdc1-43a5658b1f11.png" alt="Viewing the first response of the sent HTTP request in Postman" class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<p>What a bummer, the request wasn’t successful!</p>
<p>This happened because we didn’t provide any authorization. That’s why we received a "401 Unauthorized" error with the message "No token provided".</p>
<p>Since this is a protected endpoint, we need an access token, which you would obtain by logging into Spotify. If you tried making a request on the Spotify API documentation website earlier, you probably noticed that it asked you to log in before sending the request. By doing so, it acquired your session's access token, which is exactly what we need in our situation as well.</p>
<p>However, instead of logging in with our username and password, we’ll use a different authorization method.</p>
<h2 id="heading-spotify-api-authorization">Spotify API Authorization</h2>
<p>To make basic requests to the Spotify API, you'll need an access token, which can be generated using your credentials. This is a common approach with many APIs, where you need to obtain an access token before you can access the endpoints you're targeting.</p>
<p>The Spotify Developer API provides a <a target="_blank" href="https://developer.spotify.com/documentation/web-api/tutorials/getting-started#request-an-access-token">step-by-step guide</a> on how to get your access token.</p>
<p>Following the outlined steps, the first task is to create an application profile, which you can do in just a few seconds, especially for a test project:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1725824014786/22229e4f-0605-488b-80ef-72034fd8a414.png" alt="Viewing the created &quot;test&quot; application in the Spotify API Developers dashboard" class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<p>After completing this step, we can proceed by clicking on the "test" project to navigate to the "Settings" of the project. Here, you'll find the "Client ID" and "Client Secret":</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1725824076709/5adfd96a-f7e9-45e8-9dcf-67137ef2c814.png" alt="Viewing detailed information for the created &quot;test&quot; application in the Spotify API Developers dashboard" class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<p>Keep in mind that this information is generally considered sensitive, so you should avoid sharing it publicly (in most cases). But since this is just a test project, which will be deleted by the time this guide is published, I am showing it to make it easier for you to follow along with my explanations.</p>
<p>With your Client ID and Client Secret in hand, you now have the information needed to request an access token. These access tokens are used to authorize yourself when interacting with API endpoints.</p>
<p>You can kinda compare this to logging into software, where you need to authenticate yourself before accessing certain information. In such cases, it’s likely that an access token is generated for the duration of your session to authorize your requests to the software’s backend API.</p>
<p>Also, remember that access tokens change with each login session, meaning you receive a different token every time. Just keep in mind that with our current selected method, we don’t have access to specific user information. Instead, we only can make basic GET requests without acting on the behalf of a user. Later on we will cover this a little more.</p>
<p>The Spotify API documentation is quite helpful and provides detailed instructions on the exact request you need to make. We’ll now jump into Postman for this step.</p>
<p>Go to your "Spotify API" collection and click on the "Authorization" tab. Here, you need to choose the appropriate "Auth Type". There are several options, and the authorization method can differ depending on the API you’re using.</p>
<p>If you already have an access token, you may opt for the "Bearer Token" auth type, where you simply paste the token directly. This is the type of authorization we’ll use in the end. But instead of manually requesting a token and then inputting it into the "Bearer Token" field, we can automate this process. For this, we’ll select "<a target="_blank" href="https://oauth.net/2/">OAuth 2.0</a>" as the auth type.</p>
<p>How did I know "OAuth 2.0" was the right choice? If you check the Spotify API documentation, you’ll find some corresponding information while going through their step-by-step guide. Also, all endpoints that need authorization are tagged with "OAuth 2.0", including the "<a target="_blank" href="https://developer.spotify.com/documentation/web-api/reference/get-playlist">Get Playlist</a>" endpoint:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1725971891125/724c447e-3016-42b2-9538-a311933738e6.png" alt="Viewing the needed &quot;Auth Type&quot; for the &quot;Get Playlist endpoint" class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<p>The documentation also mentions that Spotify uses "Client Credentials" for its tutorial. This is the "grant type" and indicates the information you’ll provide for the authorization request. With "Client Credentials," you pass your Client ID and Client Secret (the information from our test application).</p>
<p>For instance, with the "Password Credentials" grant type, you would also pass a "Username" and "Password," which is used when logging in with an actual user account.</p>
<p>There are other authorization methods as well, and the API documentation usually specifies which approach to use. In our case, since we have the Client ID and Client Secret and don’t need specific user access, we know the "Client Credentials" grant type is the appropriate choice.</p>
<p>When passing your Client ID and Client Secret in Postman, you may receive a suggestion to use variables for this information:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1725824602370/d488cb29-6a62-4756-995e-32a018237893.png" alt="Setting up the &quot;Authorization&quot; for the Spotify API collection in Postman" class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<p>Similar to the <code>base_url</code> variable we used earlier, creating variables for the Client ID and Client Secret can be helpful, especially if you plan to use multiple HTTP requests with similar authorizations. This way, you can reference the same variables in all your requests, and if anything changes, you only need to update the variable in one place.</p>
<p>In this case, we’ll do the same by switching to the "Environments" tab and adding variables for both <code>client_id</code> and <code>client_secret</code>.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1725824729649/77ed62b1-7221-4e32-bccf-be366102c3df.png" alt="Adding environment variables for the Client ID and Client Secret" class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<p>Next, you’ll insert those variables into the authorization process we started earlier:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1725824827178/98394518-2a93-40ca-9e6f-01544ee3bfbb.png" alt="Updating the &quot;Authorization&quot; for the Spotify API collection with environment variables in Postman" class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<p>Now, we just need to add the token authorization URL, which can be found on the same page as before: <code>https://accounts.spotify.com/api/token</code>. Enter this into the "Access Token URL" field. Then, give the setup a fitting name of your choice and scroll down to click the "Get New Access Token" button:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1725824937975/e94e1701-6a4f-43c9-949d-136160a6aeb4.png" alt="Successfully creating an access token in Postman" class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<p>It was successful! Now, click on "Proceed" to view more details about the generated access token:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1725824969843/f3985bad-e596-4b72-a31f-cf9fc7b49b8d.png" alt="Viewing detailed information about the created access token in Postman" class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<p>With our access token ready, click on "Use Token" in the upper right, and Postman will confirm that the token has been added.</p>
<p>Now, if we switch to the "Playlist" GET request we created earlier, you’ll see the option to set up an authorization method for this specific request. But since we’ve already set up authorization for the entire collection, simply select "Inherit auth from parent" as the "Auth Type" for this request:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1725825052455/c1167201-89b5-4560-8f83-be0a0e39bcea.png" alt="Viewing the &quot;Auth Type&quot; for the HTTP request within the Spotify API collection in Postman" class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<p>Postman will indicate which authorization type is being used and where it’s coming from. In this case, it will say: "The request is using OAuth 2.0 from collection Spotify API."</p>
<p>Next, if we switch to the "Headers" tab and click on "8 hidden," we can see an "Authorization" key. By clicking on the eye symbol to the right, we can reveal this information.</p>
<p>If you compare this with the access token we just generated, you'll notice they are the same (with "Bearer" in front of the actual access token). When you create a new token for the collection, as we did earlier, this information updates automatically.</p>
<p>With everything set up, we are now ready to send the request we tried earlier, this time with a valid access token in the "Authorization" header.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1725825252369/eedff426-4843-4e63-8022-28ca6f783f8a.png" alt="Inspecting the &quot;Headers&quot; tab of the HTTP request in Postman" class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<p>And if we now hit "Send", we will get a response like this:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1725905470563/ac771bf6-a278-4564-8360-6397b01ea05c.png" alt="Viewing the JSON response of the sent HTTP request in Postman" class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<p>The response is a JSON object containing a lot of information to explore. You can do this for your own playlist as well, as long as it’s set to public on Spotify.</p>
<p>To give another example, I’ll go to Spotify, use the "Share" option for my playlist, and copy the playlist link, which looks like this: <code>https://open.spotify.com/playlist/1OPgvkPckzXm9SB0CIJf3o?si=cbe9c361f8024abd</code>.</p>
<p>The part we’re interested in is the playlist ID, which is found after the last forward slash and before the question mark—in this case, <code>1OPgvkPckzXm9SB0CIJf3o</code>. We’ll replace the current playlist ID with this one in Postman:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1725905870964/588a8569-b8b3-48f4-98c6-3bf1cb636dd1.png" alt="Adjusting the &quot;Playlist ID&quot; for the HTTP request in Postman" class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<p>Now, if we hit "Send," we’ll receive the corresponding JSON response:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1725905937409/3dd3c6b2-cacb-4a1c-9f2b-687772b34fae.png" alt="Inspecting the JSON response of the adjusted HTTP request in Postman" class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<p>This response is also a large JSON object with plenty of data to explore.</p>
<p>And that's it! We've successfully configured a fundamental Postman setup with an HTTP GET request, including authorization, to fetch data from the Spotify API.</p>
<h2 id="heading-spotify-api-authorization-scopes">Spotify API Authorization Scopes</h2>
<p>By now, we’ve successfully used authorization with our Client ID and Client Secret. But if you dive deeper into the Spotify API documentation, you’ll find situations where this method of authorization is insufficient for certain actions.</p>
<p>While fetching playlist data and other GET requests work with Client ID and Client Secret authorization, you may encounter endpoints that use POST, PUT, or DELETE methods.</p>
<p>For example, adding new songs to a playlist requires more than just Client ID and Client Secret authorization. You need to authenticate as the actual user associated with the playlist.</p>
<p>In such cases, the documentation lists "Authorization scopes" that define the required permissions. For instance, "playlist-modify-public" and "playlist-modify-private" scopes are needed for modifying public and private playlists, respectively:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1725972202770/5109da66-792a-4430-855c-9c6db4d06105.png" alt="Recognizing the mentioned &quot;Authorization scopes&quot; for the &quot;Add Items to Playlist&quot; endpoint in the Spotify API" class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<p>If you review the Spotify API documentation, you’ll see that it outlines four main authorization methods:</p>
<ul>
<li><p><a target="_blank" href="https://developer.spotify.com/documentation/web-api/tutorials/code-flow">Authorization code</a></p>
</li>
<li><p><a target="_blank" href="https://developer.spotify.com/documentation/web-api/tutorials/code-pkce-flow">Authorization code with PKCE extension</a></p>
</li>
<li><p><a target="_blank" href="https://developer.spotify.com/documentation/web-api/tutorials/client-credentials-flow">Client credentials</a></p>
</li>
<li><p><a target="_blank" href="https://developer.spotify.com/documentation/web-api/tutorials/implicit-flow">Implicit grant</a></p>
</li>
</ul>
<p>The Client credentials method (which we used) does not provide access to user-specific data. To perform actions on behalf of a user, such as modifying their playlists, the "Authorization code" method is required.</p>
<p>In real-world projects, you would typically implement this as part of your app's authentication and authorization process when users log in. For instance, in Next.js projects, NextAuth offers a Spotify login mechanism that simplifies this process.</p>
<p>Alternatively, you could manually handle the necessary requests during the authentication process and add relevant data to the session information.</p>
<p>This topic goes beyond the scope of this guide, as it deals with general authorization and authentication flows for the Spotify API (and other APIs) rather than Postman-specific use cases. But the Spotify API documentation provides valuable resources if you’re interested in exploring more advanced testing with Postman. They also provide a <a target="_blank" href="https://developer.spotify.com/documentation/web-api/howtos/web-app-profile">how-to guide</a> on retrieving a user's profile data and displaying it in your frontend application.</p>
<h2 id="heading-summary">Summary</h2>
<p>In this guide, we covered the fundamentals of Postman: how to set up your first workspace with a collection, create an HTTP request, use variables to simplify the process for future requests, and add authorization logic to obtain an access token required for making requests. All of this was demonstrated using the Spotify API, which provides extensive documentation on accessing its endpoints.</p>
<p>From here, you might want to explore deeper by learning how to access Spotify API endpoints that require user-specific access information, combined with specific scopes, such as adding new songs to a Spotify playlist.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Implement a Blender Model in a React.js Application using Three.js ]]>
                </title>
                <description>
                    <![CDATA[ In this step-by-step guide, you'll learn how to build a basic Blender file with incorporated fundamental animations. After that, you'll learn how to integrate Three.js with your React apps using React Three Fiber.  Getting familiar with these concept... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/blender-three-js-react-js/</link>
                <guid isPermaLink="false">66bb8f3cdeef71ff683a6d2a</guid>
                
                    <category>
                        <![CDATA[ animations ]]>
                    </category>
                
                    <category>
                        <![CDATA[ React ]]>
                    </category>
                
                    <category>
                        <![CDATA[ three.js ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Matthes B. ]]>
                </dc:creator>
                <pubDate>Thu, 17 Aug 2023 14:58:49 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2023/08/pexels-chevanon-photography-1335971.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>In this step-by-step guide, you'll learn how to build a basic Blender file with incorporated fundamental animations. After that, you'll learn how to integrate Three.js with your React apps using React Three Fiber. </p>
<p>Getting familiar with these concepts can help you make sure your upcoming React.js applications stand out.</p>
<h2 id="heading-heres-what-well-cover"><strong>🔐</strong> Here's What We'll Cover:</h2>
<ul>
<li>Crafting a Blender model, encompassing animations, materials and the export process.</li>
<li>Building a React.js application integrated with Three.js via React Three Fiber.</li>
<li>Incorporating your personally created Blender model into the React.js application.</li>
</ul>
<h2 id="heading-prerequisites"><strong>📝</strong> Prerequisites:</h2>
<ul>
<li>A fundamental grasp of the 3D software Blender is recommended.</li>
<li>Basic familiarity with React.js is required.</li>
<li>Prior experience with Three.js is not necessary.</li>
</ul>
<h2 id="heading-table-of-contents">Table of Contents</h2>
<ol>
<li><a class="post-section-overview" href="#heading-what-are-threejs-and-blender">💭 What are Three.js and Blender?</a></li>
<li><a class="post-section-overview" href="#heading-how-to-set-up-reactjs-with-threejs">🔧 How to Set Up React.js with Three.js</a></li>
<li><a class="post-section-overview" href="#heading-how-to-create-a-blender-model"><strong>🔨</strong> How to Create a Blender Model</a></li>
<li><a class="post-section-overview" href="#heading-texture-baking-for-procedural-materials"><strong>✏️</strong> Texture Baking for Procedural Materials</a></li>
<li><a class="post-section-overview" href="#-how-to-implement-the-blender-model-into-the-react-js-application"><strong>✒️</strong> How to Implement the Blender Model into the React.js Application</a></li>
<li><a class="post-section-overview" href="#heading-additional-information"><strong>📄</strong> Additional information</a></li>
<li><a class="post-section-overview" href="#heading-wrap-up"><strong>📋</strong> Wrap-up</a></li>
</ol>
<h2 id="heading-what-are-threejs-and-blender">💭 What are Three.js and Blender?</h2>
<p>Three.js is a JavaScript library that functionas as an API, allowing you to exhibit 3D models within web browsers. </p>
<p>Leveraging Three.js helps you seamlessly integrate interactivity and distinctive functionalities into your website. </p>
<p>Blender is a robust software tailored for crafting and refining 3D models. Its versatility offers boundless opportunities, catering to a wide spectrum of creative visions.</p>
<p>Beyond its display capabilities, Blender provides you with an array of tools encompassing cameras, lighting, and even post-production enhancements.</p>
<p>When used together, these tools facilitate boundless creativity, allowing you to seamlessly translate your artistic creations into your upcoming website project.</p>
<h2 id="heading-how-to-set-up-reactjs-with-threejs">🔧 How to Set Up React.js with Three.js</h2>
<p>To start the process, install the React.js application:</p>
<p><code>npx create-react-app my-app</code></p>
<p>Next, we'll install Three.js and <a target="_blank" href="https://docs.pmnd.rs/react-three-fiber/getting-started/installation">React Three Fiber</a>. React Three Fiber serves as a React renderer for Three.js, harnessing the power of React components to streamline Three.js integration within a React.js environment:</p>
<p><code>npm install three @react-three/fiber</code></p>
<p>For an enriched Three.js experience, we'll also integrate <a target="_blank" href="https://www.npmjs.com/package/@react-three/drei">React Three Drei</a>, a package that introduces an assortment of helpers for diverse Three.js scenarios, including several camera controls, for example:</p>
<p><code>npm install @react-three/drei</code></p>
<h3 id="heading-gltf-tools-extension">glTF Tools extension</h3>
<p>I also recommend installing the <strong>glTF Tools</strong> extension. Although not strictly necessary, this extension can help you perform various tasks. </p>
<p>If you're using Visual Studio Code as your Integrated Development Environment (IDE), you can conveniently add the extension through the extensions tab. Again, this extension is optional, but it can significantly simplify certain processes later on. I will use it throughout this tutorial:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/08/React1.0.PNG" alt="Image" width="600" height="400" loading="lazy">
<em><strong>gltf Tools</strong> extension in Visual Studio Code</em></p>
<h3 id="heading-completed-setup-for-threejs-in-reactjs">Completed setup for Three.js in React.js</h3>
<p>The dependencies in the <code>package.json</code> file of our React.js application now appear as follows:</p>
<pre><code class="lang-javascript"><span class="hljs-string">"dependencies"</span>: {
    <span class="hljs-string">"@react-three/drei"</span>: <span class="hljs-string">"^9.80.2"</span>,
    <span class="hljs-string">"@react-three/fiber"</span>: <span class="hljs-string">"^8.13.6"</span>,
    <span class="hljs-string">"@testing-library/jest-dom"</span>: <span class="hljs-string">"^5.17.0"</span>,
    <span class="hljs-string">"@testing-library/react"</span>: <span class="hljs-string">"^13.4.0"</span>,
    <span class="hljs-string">"@testing-library/user-event"</span>: <span class="hljs-string">"^13.5.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">"three"</span>: <span class="hljs-string">"^0.155.0"</span>,
    <span class="hljs-string">"web-vitals"</span>: <span class="hljs-string">"^2.1.4"</span>
  },
</code></pre>
<p>These dependencies are sufficient for accomplishing a variety of tasks with Three.js in a React.js environment. Of course, you can incorporate any additional libraries you may desire for purposes beyond Three.js integration.</p>
<p>In addition to this, I have also made the code from this tutorial available on <a target="_blank" href="https://github.com/Matthes-Baer/blender-threejs-reactjs-article-app">GitHub</a>. This will allow you to quickly access the information without having to scroll through the entire article.</p>
<h2 id="heading-how-to-create-a-blender-model">🔨 How to Create a Blender Model</h2>
<p>To begin, our initial task involves creating a Blender model that will then be integrated into our React.js application. For this stage, let's consider a scene in the <strong>Layout</strong> tab where we've got three objects: two spheres and one plane. You can add such objects with the <code>Shift + A</code> shortcut in Blender.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/08/blenderFirstImage.PNG" alt="Image" width="600" height="400" loading="lazy">
<em>Blender scene with two spheres and one plane in the <strong>Layout</strong> tab</em></p>
<p>This composition includes just a plane and two spheres, with no additional details. Of course, you can work on more elaborate scene and model designs according to your preferences. </p>
<p>But for the purpose of illustrating the fundamental process of incorporating your custom Blender models into React.js, this basic example will serve us just fine.</p>
<h3 id="heading-how-to-add-animations-to-the-model">How to add animations to the model</h3>
<p>Now, our focus shifts to introducing basic animations to all three objects within this Blender scene. These animations can facilitate movement, rotation, or even adjustments in scale for the objects, enabling dynamic transformations.</p>
<p>In order to add animations in Blender for your objects, you can switch to the <strong>Animation</strong> tab, next to the <strong>Shading</strong> and <strong>Rendering</strong> tab.</p>
<p>In the Animation tab, you can add points to a certain frame. For instance, if you want to shift a sphere a bit to the left, begin by adding a starting keyframe (right-click on the object, choose "Insert Keyframe," then pick "Location"). </p>
<p>Afterward, move ahead a few frames on the object's animation timeline, adjust the object's position, and repeat the same process. This way, you'll have two keyframes: the initial one and the new position.</p>
<p>Remember, this motion is in one direction. If you want to repeat the animation, it will move to the new location and then return to its initial position with a jump. </p>
<p>To make the movement smoother, you can copy the initial keyframe and insert it at the end. This will make the object move back with a smooth motion after reaching the new location. This is also how I set up the keyframes in our Blender model.</p>
<p>Of course, you can add more keyframes to make more complex animations. This is just a basic introduction to starting with Blender animations. Like many aspects of Blender, there's a lot more to explore and learn.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/08/blenderSecondImage.PNG" alt="Image" width="600" height="400" loading="lazy">
<em>Adding animations to all three objects in the <strong>Animation</strong> tab</em></p>
<p>In this context, it's not necessary to have a thorough understanding of the specifics of these animations we added here. So, you don't really need to know to which exact position the first sphere is being moved through the animation. </p>
<p>The key point is to acknowledge their presence, as they will be integrated into our React.js application at a later stage so we can activate them in the browser.</p>
<h3 id="heading-how-to-add-colors">How to add colors</h3>
<p>Moving forward, we'll add some simple colors for the small sphere and the underlying plane, which you can do within the <strong>Shading</strong> tab, for example.</p>
<p>For basic colors, you can also go to the <strong>Material Properties</strong> section of the object (right-click on the object, then choose the second-to-last category at the bottom). But I want to focus on a specific situation you might encounter with your models later on. Therefore, I'll exclusively use the <strong>Shading</strong> tab for setting object colors in this tutorial.</p>
<p>In the <strong>Shading</strong> tab, you can add nodes at the bottom of the screen. These nodes can modify the color and texture of an object, among other things. You'll also find <code>Vector</code> and <code>Shader</code> nodes that, when combined, can create unique visuals for your objects. </p>
<p>All these adjustments apply to a specific material. So, if you want the same visual for different objects, you can simply apply the same material to them.</p>
<p>The <code>Principled BSDF</code> and <code>Material Output</code> nodes are initially generated when we open the <strong>Shading</strong> tab to look up on of our object's material for the first time. Both nodes are pretty much the basic case. </p>
<p>The <code>Principled BSDF</code> has a lot of settings you can play around with. In our case we just want to change the <code>Base Color</code> property to a blue color.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/08/blender3.0.PNG" alt="Image" width="600" height="400" loading="lazy">
<em>Material of one sphere where we just adjust the <code>Base Color</code> within the <code>Principled BSDF</code> node</em></p>
<p>For the larger sphere, a similar material application is used. But, in contrast to the <code>Principled BSDF</code> node, we'll use the <code>Glossy BSDF</code> node which is such a node from the <code>Shader</code> category. This will help us recognize a possible issue that you might come across when designing a Blender model for your React.js application – which you will see later on.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/08/blender3.2-1.PNG" alt="Image" width="600" height="400" loading="lazy">
<em>Using the <code>Glossy BSDF</code> node to add a material to the large sphere</em></p>
<p>Once we've done this, we're ready to export our Blender model. Note that this version is considerably simplified. You can work on more detailed model designs tailored to your preferences. Still, the overall workflow remains similar.</p>
<h3 id="heading-how-to-export-the-model">How to export the model</h3>
<p>To export the model, we need to generate a <code>.glb/.gltf</code> file. This is crucial as Three.js expects particular file formats for compatibility, and in this instance, a <code>.glb</code> or <code>.gltf</code> file aligns with the library's requirements.</p>
<p>So, once you've finished creating your model with objects, animations, colors, and more, you can do the following:</p>
<ol>
<li>Click on the <strong>File</strong> tab located at the top left corner.</li>
<li>Choose <strong>Export</strong> from the options that appear. Now, a variety of export formats will be shown.</li>
<li>If you plan to use your model with Three.js in your application, you need to pick the <code>glTF 2.0 (.glb/.gltf)</code> option, like I mentioned earlier.</li>
</ol>
<p>After selecting this option, a new window will pop up. This window lets you pick the folder where you want to save your file. </p>
<p>On the right side of this window, there are additional choices. You can decide which specific objects you want to export, for instance. In most situations, the default settings should work well. Just remember that you can adjust these settings to your liking if necessary.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/08/blender3.1-1.png" alt="Image" width="600" height="400" loading="lazy">
<em>Remember to export with the <code>glTF 2.0 (.glb/.gltf)</code> format.</em></p>
<h3 id="heading-how-to-visualize-the-exported-model">How to visualize the exported model</h3>
<p>Next, let's transition to Visual Studio Code and navigate to the folder where we've stored our exported file. </p>
<p>Within this directory, you'll find a <code>.glb</code> file. Referring back to the <strong>glTF Tools</strong> extension setup from earlier, you can simply right-click on the <code>.glb</code> file in order to find two additional options positioned at the bottom, called <code>glTF: Import from GLB</code> and <code>glTF: Validate a GLB or GLTF file</code>.</p>
<p>In this scenario, we'll opt for the <code>glTF: Import from GLB</code> option. This action will generate a <code>.gltf</code> file in the same folder, in our case <code>blenderFile.gltf</code>.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/08/blender4.0.png" alt="Image" width="600" height="400" loading="lazy">
<em>Generating a <code>.gltf</code> file from the original <code>.glb</code> file we exported in Blender with the <strong>glTF Tools</strong> extension</em></p>
<p>We've chosen this approach to bring enhanced accessibility to the <code>.gltf</code> file, enabling direct viewing within Visual Studio Code through the <strong>glTF Tools</strong> extension. This can be quite helpful to check on your file prior to its actual implementation.</p>
<p>If we access the newly created <code>.gltf</code> file, we can observe a bunch of information based on the Blender model. It's important to note that the specifics could differ in your case, as they're tailored to reflect the attributes of the objects and scenes within your Blender project.</p>
<p>If we look at the upper-right corner, there is a symbol that looks like a cube with a cone next to it. By clicking on this symbol, you can seamlessly preview your Blender scene directly within your IDE. This functionality is exclusively accessible for the <code>.gltf</code> file and not applicable to the <code>.glb</code> file in this case.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/08/blender4.5.png" alt="Image" width="600" height="400" loading="lazy">
<em>The newly created <code>.gltf</code> file with the option to view the model directly in Visual Studio Code (in the upper-right corner, circled in red)</em></p>
<p>It's worth noting that you don't have to do this through the <strong>glTF Tools</strong> extension. Alternatively, various websites allow you to upload your file for visualization. But I've personally found this in-IDE approach to be especially convenient. It centralizes the process, enabling you to assess your file's integrity before actually implementing it. </p>
<p>If you find any errors, this practice lets you preemptively find out whether the issue is based on a problematic file export or just an implementation oversight within your React.js application. Consequently, I wholeheartedly recommend evaluating your model file following its export from Blender.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/08/blender5.0.PNG" alt="Image" width="600" height="400" loading="lazy">
<em>Viewing the Blender model with <strong>glTF Tools</strong> in Visual Studio Code</em></p>
<p>By using the <strong>glTF Tools</strong> extension to view our Blender model in Visual Studio Code, we can see that all three objects are correctly recognized. Both the small sphere and the plane are shown in their intended colors.</p>
<p>But the large sphere doesn't have the expected color assigned and just appears with a default white color instead. </p>
<p>This discrepancy raises the question: what led to this anomaly? It's circumstances like this that demonstrate how useful it is to preview your model before integrating it into your React.js application.</p>
<p>By scrutinizing your model at this stage, you can affirm that the issue originates from the Blender model itself rather than the implementation process, given that we haven't done any implementation yet. </p>
<p>This pre-implementation assessment proves to be handy and enables you to diagnose and address potential complications before proceeding with the implementation process in React.js.</p>
<h2 id="heading-texture-baking-for-procedural-materials">✏️ Texture Baking for Procedural Materials</h2>
<p>In a nutshell, Blender provides the flexibility to employ procedural nodes for your materials. While these nodes function seamlessly within Blender, they are not directly compatible with other game engines or software frameworks such as Three.js. </p>
<p>To learn more, consider watching the following video. In just 10 minutes, it demonstrates the process of texture baking, which effectively resolves the issue at hand. </p>
<div class="embed-wrapper">
        <iframe width="560" height="315" src="https://www.youtube.com/embed/AioskAgcU2U" style="aspect-ratio: 16 / 9; width: 100%; height: auto;" title="YouTube video player" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen="" loading="lazy"></iframe></div>
<p>Personally, when confronted with this challenge and initially uncertain about its nature, I found this video to be a valuable resource for gaining deeper insights into the subject matter.</p>
<p>In our specific scenario, while we might not encounter as complex a situation as seen in the video, we are still faced with the use of nodes that lack direct compatibility with various software tools.</p>
<p>Next, we'll briefly walk through the steps mentioned in the video. However, if you're interested in delving deeper into this process, I highly recommend watching the video.</p>
<h3 id="heading-how-to-create-an-image-texture-node">How to create an image texture node</h3>
<p>To start, in the <strong>Shading</strong> tab for the material containing the <code>Glossy BSDF</code> node, we'll introduce an <code>Image Texture</code> node and connect it to a new image (by click on <code>New</code>). </p>
<p>We'll leave the settings at their default values, which means a width and height of <code>1024px</code>. Using larger values would considerably extend the processing time we're going to face. Still, it's important to note that a larger texture can offer more detail and an overall improved appearance. </p>
<p>In our current situation, we're aiming for a quick process. But for more significant projects, visual quality might be crucial. In such cases, opting for a higher resolution could be desirable.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/08/blender6.0-1.PNG" alt="Image" width="600" height="400" loading="lazy">
<em>Creating an <code>Image Texture</code> node and assigning a new image to it with default settings</em></p>
<h3 id="heading-how-to-apply-the-smart-uv-project-process">How to apply the Smart UV Project process</h3>
<p>Next, we need to employ the <code>Smart UV Project</code> option located in the <strong>UV Editing</strong> tab. Essentially, this action unwraps the faces of the particular object onto a texture. </p>
<p>This process enables us to specify which parts of the texture should be colored and modified as soon as we are back in the <strong>Shading</strong> tab. To make this process effective, we must select all the faces of the large sphere.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/08/blender7.0.png" alt="Image" width="600" height="400" loading="lazy">
<em>Selecting all faces of the object in the <strong>UV Editing</strong> tab and applying <code>Smart UV Project</code> on it</em></p>
<p>Once we've finished this step and utilized the default settings for the <code>Smart UV Project</code> procedure, the image on the left —previously featuring a grid— will now display the shapes of the sphere we applied this process to. In our situation, it seems like the texture captured various angles of our sphere.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/08/blender8.0.PNG" alt="Image" width="600" height="400" loading="lazy">
<em>The texture after <code>Smart UV Project</code></em></p>
<p>Depending on the specific object, you may need to fine-tune the settings presented after clicking the <code>Smart UV Project</code> button. If you encounter challenges with a particular object, the video I shared earlier can give you additional guidance on this aspect.</p>
<p>Generally, to mitigate issues, you should optimize your object layout during its creation phase. Avoiding the introduction of excessive edges in specific locations can prevent problems like clipping, for instance.</p>
<h3 id="heading-the-bake-process">The Bake process</h3>
<p>Now, let's return to the <strong>Shading</strong> tab, where we'll access the <code>Render Properties</code> on the right side (represented by the small screen or TV symbol). If not already selected, pick <code>Cycles</code> as your <code>Render Engine</code>. Then navigate to the <code>Bake</code> category, which is located below the <code>Performance</code> category.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/08/blender9.0-1.PNG" alt="Image" width="600" height="400" loading="lazy">
<em><code>Bake</code> option in the <strong>Shading</strong> tab within the <code>Render Properties</code></em></p>
<p>With the existing default settings, you can proceed by clicking the <code>Bake</code> button while ensuring that both the <code>Image Texture</code> node and the large sphere are selected. </p>
<p>Keep in mind that I integrated a <code>Sun</code> light into my scene, as this bake process takes the scene's lighting into account. Without sufficient lighting, the result might appear excessively dark.</p>
<p>After a period of processing (which might be more time-consuming if you've employed larger dimensions for the <code>Image Texture</code> node's image), the baking process will finish. This results in the texture being applied to the image from the <code>Image Texture</code>. Instead of obtaining the texture from the <code>Shader</code> node named <code>Glossy BSDF</code>, we now have access to it through a regular "normal" image texture.</p>
<p>Then we can establish a connection from the <code>Image Texture</code> node to the <code>Material Output</code> node, thereby successfully implementing our material. At this stage, there isn't a significant difference compared to the previous method where we had the <code>Principled BSDF</code> node connected to the <code>Surface</code> input of the <code>Material Output</code> node.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/08/blender10.0.PNG" alt="Image" width="600" height="400" loading="lazy">
<em><code>Image Texture</code> node with the "baked" texture is connected with the <code>Material Output</code> node instead of the <code>Glossy BSDF</code> node</em></p>
<h3 id="heading-how-to-see-the-final-result">How to see the final result</h3>
<p>Now, we can export the file again, repeat the same process from before in our IDE with <strong>glTF Tools</strong> and view the <code>.gltf</code> file with the extension. Upon examining the outcome, you might notice that it's not an exact match to the version we had using the <code>Glossy BSDF</code> node in Blender. This difference can be primarily attributed to the lighting conditions in the Blender scene.</p>
<p>Bear in mind that the approach I've outlined isn't the typical usage for the baking process, since in this case you could also just have picked a similar base color with the <code>Principled BSDF</code> node and would achieve pretty much the same solution, for example.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/08/blender11.0.PNG" alt="Image" width="600" height="400" loading="lazy">
<em>Finalized view with <strong>glTF Tools</strong>, including the "baked" texture for the large sphere</em></p>
<p>I introduced the baking process based on personal experience. There were instances where I encountered a scenario where materials appeared differently in Blender compared to when implemented them in a React.js application with Three.js. This situation prompted me to explore the concept of baking, which turned out to be a helpful solution.</p>
<p>To summarize, if you find yourself facing a scenario where your materials don't appear as expected in your React.js application with Three.js, considering the baking process and researching this topic can provide valuable insights. This can be particularly beneficial for people who are new to Blender.</p>
<h2 id="heading-how-to-implement-the-blender-model-in-the-reactjs-application">✒️ How to Implement the Blender model in the React.js Application</h2>
<p>To implement the Blender file, we can use a really useful shortcut (source: <a target="_blank" href="https://github.com/pmndrs/gltfjsx">https://github.com/pmndrs/gltfjsx</a>):</p>
<p><code>npx gltfjsx public/blenderFileName.glb</code></p>
<p>It's important to note that you need to store your Blender file within the <code>public</code> folder of your React.js application for this step. It's also worth highlighting that you need React Three Drei to use this helper. So in our case, we can directly use this shortcut without the need for any additional preparations.</p>
<p>Upon executing this shortcut, we are presented with the following file:</p>
<pre><code class="lang-javascript"><span class="hljs-comment">/*
Auto-generated by: https://github.com/pmndrs/gltfjsx
Command: npx gltfjsx@6.1.4 public/blenderStuff/blenderFile.glb
*/</span>

<span class="hljs-keyword">import</span> { useLayoutEffect, useRef } <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;
<span class="hljs-keyword">import</span> { useGLTF, useAnimations } <span class="hljs-keyword">from</span> <span class="hljs-string">"@react-three/drei"</span>;

<span class="hljs-keyword">export</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Model</span>(<span class="hljs-params">props</span>) </span>{
  <span class="hljs-keyword">const</span> group = useRef();
  <span class="hljs-keyword">const</span> { nodes, materials, animations } = useGLTF(
    <span class="hljs-string">"./blenderStuff/blenderFile.glb"</span>
  );
  <span class="hljs-keyword">const</span> { actions } = useAnimations(animations, group);

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">group</span> <span class="hljs-attr">ref</span>=<span class="hljs-string">{group}</span> {<span class="hljs-attr">...props</span>} <span class="hljs-attr">dispose</span>=<span class="hljs-string">{null}</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">group</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"Scene"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">mesh</span>
          <span class="hljs-attr">name</span>=<span class="hljs-string">"Cube"</span>
          <span class="hljs-attr">geometry</span>=<span class="hljs-string">{nodes.Cube.geometry}</span>
          <span class="hljs-attr">material</span>=<span class="hljs-string">{materials.Material}</span>
          <span class="hljs-attr">position</span>=<span class="hljs-string">{[-0.07,</span> <span class="hljs-attr">0.16</span>, <span class="hljs-attr">-0.27</span>]}
          <span class="hljs-attr">scale</span>=<span class="hljs-string">{[1,</span> <span class="hljs-attr">0.03</span>, <span class="hljs-attr">1</span>]}
        /&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">mesh</span>
          <span class="hljs-attr">name</span>=<span class="hljs-string">"Sphere"</span>
          <span class="hljs-attr">geometry</span>=<span class="hljs-string">{nodes.Sphere.geometry}</span>
          <span class="hljs-attr">material</span>=<span class="hljs-string">{materials[</span>"<span class="hljs-attr">Material.002</span>"]}
          <span class="hljs-attr">position</span>=<span class="hljs-string">{[-0.62,</span> <span class="hljs-attr">0.43</span>, <span class="hljs-attr">-0.79</span>]}
          <span class="hljs-attr">rotation</span>=<span class="hljs-string">{[-0.01,</span> <span class="hljs-attr">0.11</span>, <span class="hljs-attr">-0.02</span>]}
          <span class="hljs-attr">scale</span>=<span class="hljs-string">{0.09}</span>
        /&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">mesh</span>
          <span class="hljs-attr">name</span>=<span class="hljs-string">"Sphere001"</span>
          <span class="hljs-attr">geometry</span>=<span class="hljs-string">{nodes.Sphere001.geometry}</span>
          <span class="hljs-attr">material</span>=<span class="hljs-string">{materials[</span>"<span class="hljs-attr">Material.001</span>"]}
          <span class="hljs-attr">position</span>=<span class="hljs-string">{[0.4,</span> <span class="hljs-attr">0.55</span>, <span class="hljs-attr">0.15</span>]}
          <span class="hljs-attr">scale</span>=<span class="hljs-string">{0.41}</span>
        /&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">group</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">group</span>&gt;</span></span>
  );
}

useGLTF.preload(<span class="hljs-string">"./blenderStuff/blenderFile.glb"</span>);
</code></pre>
<p>At first glance, you can see that this process has added many elements, so we basically don't need to add much on our own.</p>
<p>An important aspect to configure is the path within the <code>useGLTF</code> hook. In my instance, the accurate path to incorporate is <code>./blenderStuff/blenderFile.glb</code> (this applies to <code>useGLTF.preload()</code> as well). This is because I created a sub-folder named <code>blenderStuff</code> within my <code>public</code> directory.</p>
<h3 id="heading-how-to-add-a-canvas-wrapper-and-other-components">How to add a Canvas wrapper and other components</h3>
<p>With this configuration in place, we're now ready to use the <code>Model</code> component. But to effectively integrate this <code>Model</code> component into our desired location, we need to make some adjustments in the parent component. </p>
<p>In my case, I've opted to implement it within the main <code>App.js</code> file. And I've assigned a height of <code>100vh</code> to the <code>App</code>'s CSS class to ensure the desired display.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> <span class="hljs-string">"./App.css"</span>;
<span class="hljs-keyword">import</span> { Model } <span class="hljs-keyword">from</span> <span class="hljs-string">"./BlenderFile"</span>;
<span class="hljs-keyword">import</span> { Canvas } <span class="hljs-keyword">from</span> <span class="hljs-string">"@react-three/fiber"</span>;
<span class="hljs-keyword">import</span> { OrbitControls } <span class="hljs-keyword">from</span> <span class="hljs-string">"@react-three/drei"</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">Canvas</span> <span class="hljs-attr">camera</span>=<span class="hljs-string">{{</span> <span class="hljs-attr">fov:</span> <span class="hljs-attr">64</span>, <span class="hljs-attr">position:</span> [<span class="hljs-attr">-2</span>, <span class="hljs-attr">2</span>, <span class="hljs-attr">0</span>] }}&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">ambientLight</span> <span class="hljs-attr">intensity</span>=<span class="hljs-string">{5}</span> /&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">OrbitControls</span> <span class="hljs-attr">enableZoom</span>=<span class="hljs-string">{true}</span> /&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">Model</span> /&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">Canvas</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>Generally speaking, you'll need a component to encapsulate all the Three.js related elements. Within the <code>Canvas</code> component, there's an opportunity to configure various settings. In my specific instance, I'm adjusting the initial camera position.</p>
<p>The light for the component plays a crucial role. In our case we made use of <code>ambientLight</code> which will add a light to the whole scene. Without adequate lighting, your scene might appear exceedingly dark or even entirely black despite the presence of object colors. You can also use additional light sources like the <code>spotLight</code> component.</p>
<p>The <code>OrbitControls</code> component, accessible from the Drei helper library, enhances your interactivity by enabling scrolling and rotation within the model right within the browser. This single line of code substantially improves user interactivity options.</p>
<p>Remember that your <code>Canvas</code> component can accommodate multiple models. You can also selectively apply components like <code>OrbitControls</code> to specific Blender models, thereby tailoring their behavior. </p>
<p>To do this, you'll need to build a parent component for each scene you want to make to be integrated within the <code>Canvas</code>. Within each new parent component, incorporate your Blender model component, along with any supplementary helper components you want to add. </p>
<p>This approach proves particularly advantageous when distinct models require different lighting or unique camera positions, for example.</p>
<h3 id="heading-how-to-implement-the-animations">How to implement the animations</h3>
<p>At this point, we've established a functional Three.js <code>Canvas</code> environment, featuring our Blender model. But it's important to remember that we've also introduced basic animations, which are not yet operational.</p>
<p>To tackle this, we can leverage the pre-implemented <code>useAnimations</code> hook.</p>
<pre><code class="lang-javascript">  <span class="hljs-keyword">const</span> { actions, names } = useAnimations(animations, group);

  useLayoutEffect(<span class="hljs-function">() =&gt;</span> {
    names.forEach(<span class="hljs-function">(<span class="hljs-params">animation</span>) =&gt;</span> {
      actions?.[animation]?.play();
    });
  }, [actions, names]);
</code></pre>
<p>By incorporating this implementation, all animations associated with this Blender model will start playing upon the rendering of the page. This behavior also includes an indefinite loop for each animation.</p>
<h2 id="heading-additional-information">📄 Additional Information</h2>
<p>While this tutorial primarily focused on integrating a Blender model into a React.js application using Three.js, there's a realm of untapped potential within Three.js that we didn't cover.</p>
<p>Although we didn't use it in this basic example, you can introduce Post Processing to your Three.js models within React.js. The <a target="_blank" href="https://www.npmjs.com/package/@react-three/postprocessing">React Three Postprocessing</a> library serves as a valuable tool in this regard. It lets you elevate your Three.js scenes with sophisticated effects like Bloom or Noise effects, which can add a more advanced dimension to your visualizations.</p>
<p>Also, when working on future Three.js projects, consider exploring the <a target="_blank" href="https://docs.pmnd.rs/react-three-fiber/tutorials/using-with-react-spring">React Spring</a> library which integrates well with React Three Fiber. React Spring provides the opportunity to incorporate custom animations within your Three.js scenes, on top of any animations directly integrated within Blender. </p>
<p>For instance, you could make a specific object within your scene get larger or smaller upon clicking it. As with other aspects of Three.js, this aspect might enhance interactivity and might be worth your time to get into.</p>
<p>By the way, if you find that your frames are running at a lower rate, consider toggling Hardware Acceleration within your browser settings to potentially improve performance.</p>
<h2 id="heading-wrap-up">📋 Wrap-up</h2>
<p>At this point, we've successfully crafted a Blender model with animations and materials. Afterwards we integrated it into our React.js application using React Three Fiber.</p>
<p>Although the example we looked at here was quite basic, the integration approach remains the same for more complex Blender models. The fundamental functions of Three.js can be combined with supplementary helpers to enhance your scenes. </p>
<p>In addition to Post Processing, additional animations or also specific Blender materials, aspects like cameras and lights often are the most important when aiming to enhance the visual impact of your Blender models within Three.js scenes.</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[ Routing in Next.js – How to Set Up Dynamic Routing with Pre-Rendering in Next ]]>
                </title>
                <description>
                    <![CDATA[ In this tutorial, you'll learn how to set up dynamic routing in Next.js. You'll also learn about pre-rendering and why it's important. 🔐 Here's what we'll cover: You'll get to know getStaticPaths(), one of the core principles of Next.js. You'll imp... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-setup-dynamic-routing-in-nextjs/</link>
                <guid isPermaLink="false">66bb8f3f5d242388375d3878</guid>
                
                    <category>
                        <![CDATA[ Next.js ]]>
                    </category>
                
                    <category>
                        <![CDATA[ routing ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Matthes B. ]]>
                </dc:creator>
                <pubDate>Fri, 29 Jul 2022 21:21:21 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2022/07/pexels-pixabay-2150.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>In this tutorial, you'll learn how to set up dynamic routing in Next.js. You'll also learn about pre-rendering and why it's important.</p>
<h2 id="heading-heres-what-well-cover">🔐 Here's what we'll cover:</h2>
<ul>
<li>You'll get to know <code>getStaticPaths()</code>, one of the core principles of Next.js.</li>
<li>You'll improve your general Next.js knowledge and confidence.</li>
<li>You'll have access to a quick-replicable example for your own Next.js learning purposes.</li>
</ul>
<h2 id="heading-prerequisites"><strong>📝</strong> Prerequisites</h2>
<ul>
<li>You should be familiar with what Next.js is and why you should consider using it.</li>
<li>You should have some understanding of what <a target="_blank" href="https://nextjs.org/docs/routing/introduction"><strong>Routing</strong></a> and <a target="_blank" href="https://nextjs.org/docs/routing/dynamic-routes"><strong>Dynamic Routing</strong></a> mean in React and/or Next.js.</li>
<li>For this example, I work with TypeScript. But it's not necessary for you to be familiar with TypeScript. I will address the code which would be omitted when using JavaScript. Also, whenever you see <code>.tsx</code> regarding any files, you can just replace that with <code>.js</code> if you are using JavaScript.</li>
</ul>
<h2 id="heading-the-objective"><strong>🎯</strong> The Objective</h2>
<p>This quick guide aims to help you manage fetching data, which can be used for pre-rendering purposes within dynamic routes in Next.js. We'll discuss some theory as well as a practical example.</p>
<p>While we are focusing on the actual logic of the required code, I won't do any CSS styling whatsoever. Feel free to get creative on the frontend for your own project when you're using the techniques we discuss in this tutorial.</p>
<h2 id="heading-how-routing-works-in-nextjs">🔎 How Routing Works in Next.js</h2>
<p>While React itself uses a code-based approach for any routing intentions, Next.js utilizes a file-system for the concept of routing.</p>
<p>Therefore, you are probably familiar with code-based routing in React, which may look similar to this:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/07/React-Routing.PNG" alt="Image" width="600" height="400" loading="lazy">
<em>Example for code-based React Routing</em></p>
<p>With this code-based approach, you are, for example, able to navigate from the main route at <code>/</code> to the <code>about</code> page through <code>/about</code>.</p>
<p>You are also able to find a dynamic routing approach in this React example with the <code>:productId</code> path.</p>
<p>With Next.js, though, we don't use such code-based routing anymore. Instead, this React framework makes use of file-based routing. This means that you set up your routes directly through page files. </p>
<p>Consider the following <code>pages</code> folder containing subfolders and files:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/07/Nextjs-Routing.PNG" alt="Image" width="600" height="400" loading="lazy">
<em>Example for file-based Next.js Routing</em></p>
<p>The <code>index.tsx</code> file would be the equivalent to the <code>/</code> path in the React Routing example from above. So you would be able to reach the content within the <code>user-profile.tsx</code> file through <code>/user-profile</code> – that's it! </p>
<p>On the other hand, if you want to reach out to some nested content, you can use <code>/stars/[id]</code> in order to find the content in the corresponding page file.</p>
<p>Maybe you noticed that I'm using square brackets for <code>[id].tsx</code> as well as for <code>[something].tsx</code>. That's needed in order to set up dynamic routing in Next.js. </p>
<p>You could technically insert any input you would like for <code>[id]</code> and the page would load for this specific path. </p>
<p>Just keep in mind that if this dynamic route requires a valid input for <code>[id]</code> (maybe some sort of existing product id for which we want to fetch the respective data), then there could be an error.</p>
<h2 id="heading-data-fetching-in-nextjs-with-dynamic-routing">✂️ Data Fetching in Next.js with Dynamic Routing</h2>
<p>Imagine you apply this dynamic routing approach to a shop page where you list a bunch of different items. Each item would have a link for more information about that specific item. </p>
<p>Within this Link element, you would be able to lead the user to a dynamic route with a valid parameter (the corresponding product id, for example). For such cases, dynamic routing is the best approach.</p>
<h3 id="heading-how-does-getstaticprops-work">❗How does <code>getStaticProps()</code> work?</h3>
<p>With this function, you can pre-render a page at build time. This is useful for Search Engine Optimization (SEO) purposes, for example, and can overall generate a better user experience.</p>
<p>The data which should be pre-rendered can typically be found on some database, for example. Like with <code>getStaticProps()</code>, you are able to directly write any server-side code within this function for data fetching purposes (instead of reaching out to an API route on the backend, which then goes through any required server-side actions).</p>
<p>There is more to say about <code>getStaticProps()</code>. If you are pretty new to all this stuff, I highly recommend checking out the <a target="_blank" href="https://nextjs.org/docs/basic-features/data-fetching/get-static-props">official Next.js documentation</a> on this topic.</p>
<h3 id="heading-whats-the-purpose-of-getstaticpaths">❓ What's the purpose of <code>getStaticPaths()</code>?</h3>
<p>While <code>getStaticProps()</code> on its own seems to already do all the work we need to be done for our pages, we will encounter an error when we use this function alone on dynamic routing pages. The error message will actually call you out on this specific fact that <code>getStaticPaths()</code> is missing.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/07/error-message.PNG" alt="Image" width="600" height="400" loading="lazy">
<em>Screenshot of server error. SSG stands for Static-Site Generation</em></p>
<p><code>getStaticProps()</code> utilizes the static-site generation concept. So Next.js will pre-render the respective page at build time. In the case of dynamic routes, however, Next.js doesn't know by itself which paths to pre-render. Instead, you have to step in and help – and this is where <code>getStaticPaths()</code> comes in handy.</p>
<p>So with <code>getStaticPaths</code> you can specify which paths of the dynamic routing should be pre-rendered and/or how unknown paths should be handled.</p>
<h3 id="heading-quick-side-note">📋 Quick side note</h3>
<p>If you are using <code>getServerSideProps()</code>, which can be used for similar reasons as <code>getStaticProps()</code>, you will notice that <code>getStaticPaths()</code> is actually not needed. Why is that?</p>
<p><code>getServerSideProps()</code> doesn't use the static generation principle. Instead of building the page, Next.js pre-renders the page on each request with the returned data. This is called server-side rendering.</p>
<p>We don't have to tell Next.js which paths have to be statically pre-rendered while using <code>getServerSideProps()</code>, since there is no such thing for this function in the first place.</p>
<p>If you want to read more about this function, I can again recommend the official Next.js documentation for s<a target="_blank" href="https://nextjs.org/docs/basic-features/data-fetching/get-server-side-props">erver-side rendering</a>. However, this is out of the scope of this quick guide and I won't need <code>getServerSideProps()</code> for any of the following steps.</p>
<h2 id="heading-how-to-setup-our-project">🔧 How to Setup Our Project</h2>
<p>For this example, we will reproduce a small dynamic routing case. For this, I prepared a subfolder <code>test</code> in the <code>pages</code> folder. The <code>pages</code> folder gets automatically created by Next.js. </p>
<p>In the <code>test</code> folder, I insert the <code>[something].tsx</code> file (<code>[something].js</code> if you are using JavaScript and not TypeScript).</p>
<p>There is also a <code>backendData</code> folder at the root level of our Next.js application with the <code>some-backend-data.json</code> file (thus not in the <code>pages</code> folder). This file will provide us with the data which we will insert dynamically.</p>
<h3 id="heading-setup-for-the-backend-json-data">🔨 Setup for the backend <code>JSON</code> data</h3>
<p>For this example, I'm creating some dummy data which will be embedded in the <code>some-backend-data.json</code> within the <code>backendData</code> folder. This way, we can reproduce a situation where you have access to some sort of data in the backend that you want to use on the frontend.</p>
<p>Here's what the <code>some-backend-data.json</code> file looks like:</p>
<pre><code class="lang-json">{
    <span class="hljs-attr">"stars"</span>: [
        { 
            <span class="hljs-attr">"id"</span>: <span class="hljs-string">"St2-18"</span>, 
            <span class="hljs-attr">"name"</span>: <span class="hljs-string">"Stephenson 2-18"</span>, 
            <span class="hljs-attr">"description"</span>: <span class="hljs-string">"Stephenson 2-18 is a red supergiant (RSG) or possible extreme red hypergiant (RHG) star in the constellation of Scutum."</span>, 
            <span class="hljs-attr">"link"</span>: <span class="hljs-string">"https://en.wikipedia.org/wiki/Stephenson_2-18"</span> 
        },
        { 
            <span class="hljs-attr">"id"</span>: <span class="hljs-string">"UY-SC"</span>, 
            <span class="hljs-attr">"name"</span>: <span class="hljs-string">"UY Scuti"</span>, 
            <span class="hljs-attr">"description"</span>: <span class="hljs-string">"UY Scuti is an extreme red hypergiant or red supergiant star in the constellation Scutum."</span>, 
            <span class="hljs-attr">"link"</span>: <span class="hljs-string">"https://en.wikipedia.org/wiki/UY_Scuti"</span>
        },
        { 
            <span class="hljs-attr">"id"</span>: <span class="hljs-string">"RSGC1"</span>, 
            <span class="hljs-attr">"name"</span>: <span class="hljs-string">"RSGC1-F01"</span>, 
            <span class="hljs-attr">"description"</span>: <span class="hljs-string">"RSGC1-F01 is a red supergiant located in the RSGC1 open cluster in the constellation of Scutum."</span>, 
            <span class="hljs-attr">"link"</span>: <span class="hljs-string">"https://en.wikipedia.org/wiki/RSGC1-F01"</span>
        }
    ]
}
</code></pre>
<p>In this file you will find some <code>JSON</code> formatted data. There is <code>"stars"</code> which is just an array with three objects. All three objects have the same format and include an <code>id</code>, a <code>name</code>, a <code>description</code>, and a <code>link</code> to an external web page.</p>
<p>As you may have figured out by now, these are actually some real stars in our universe.</p>
<p>In a real-world situation, you would probably have some sort of connection to a databank, but the actual data you are receiving from this databank could technically be formatted as in this example. So this is sufficient for our example setup.</p>
<h3 id="heading-imports-and-interface">🔑 Imports and interface</h3>
<p>As a next step, we can dive into actually creating the Next.js <code>[something].tsx</code> dynamic route. Let's start with the required imports for this example:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { GetStaticProps, GetStaticPaths  } <span class="hljs-keyword">from</span> <span class="hljs-string">'next'</span>;
<span class="hljs-keyword">import</span> { useRouter } <span class="hljs-keyword">from</span> <span class="hljs-string">'next/router'</span>;
<span class="hljs-keyword">import</span> path <span class="hljs-keyword">from</span> <span class="hljs-string">'path'</span>;
<span class="hljs-keyword">import</span> fs <span class="hljs-keyword">from</span> <span class="hljs-string">'fs/promises'</span>;

<span class="hljs-keyword">interface</span> starInterface {
    id: <span class="hljs-built_in">string</span>
    name: <span class="hljs-built_in">string</span>
    description: <span class="hljs-built_in">string</span>
    link: <span class="hljs-built_in">string</span>
}
</code></pre>
<p>Keep in mind that I'm using TypeScript here. If you are using JavaScript, that's of course fine as well. Just remember that you don't need the <code>interface starInterface</code> or <code>import { GetStaticProps, GetStaticPaths } from 'next'</code>.</p>
<h3 id="heading-how-to-create-the-data-fetching-function">💎 How to Create the Data Fetching Function</h3>
<p>For the next step, I will prepare an <code>async</code> function called <code>getData()</code>, which will be helpful for the <code>getStaticProps()</code> and <code>getStaticPaths()</code> functions. This will look quite confusing, especially if you have never had contact with backend JavaScript code like you would expect in any Node.js application, for example. </p>
<p>Just bear with me for a few more seconds. You don't have to understand the following code in detail. We just need to know what the result of the <code>getData()</code> function is.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getData</span>(<span class="hljs-params"></span>) </span>{
    <span class="hljs-keyword">const</span> filePath = path.join(process.cwd(), <span class="hljs-string">'backendData'</span>, <span class="hljs-string">'some-backend-data.json'</span>);
    <span class="hljs-keyword">const</span> fileData = <span class="hljs-keyword">await</span> fs.readFile(filePath);
    <span class="hljs-keyword">const</span> data = <span class="hljs-built_in">JSON</span>.parse(jsonData.toString());

    <span class="hljs-keyword">return</span> data;
  }
</code></pre>
<p>As you can see, there are three variables: <code>filePath</code>, <code>fileData</code>, and <code>data</code>. With <code>filePath</code> we are just focusing on the file where we have our <code>JSON</code> data placed. So we are targeting the current working directory (cwd), then the <code>backendData</code> folder, and then the <code>JSON</code> file.</p>
<p>With <code>fileData</code> we are trying to read this file and extract the actual <code>JSON</code> data that is stored in it.</p>
<p>We need <code>data</code> to convert this <code>fileData</code> so we can actually use it for our next steps.</p>
<p>All in all, <code>getData()</code> basically just provides us with the data from the <code>some-backend-data.json</code> file so we can utilize it in <code>getStaticProps()</code> as well as in <code>getStaticPaths()</code>. There is not much more to it.</p>
<h3 id="heading-setup-for-getstaticprops">🔨 Setup for <code>getStaticProps()</code></h3>
<p>After we implement <code>getData()</code> (which will come in handy when we try to fetch our dummy backend data), we'll now create the <code>getStaticProps()</code> function next.</p>
<p>Here, we'll use <code>getStaticProps()</code> to enable pre-rendering for the specific fetched data for the paths in our dynamic route.</p>
<p>Before we jump right into the code example below, have a quick thought about what we actually want to accomplish. </p>
<p>The user should be directed to this specific dynamic route, which is indicated by a unique identifier in the URL. By that, I mean that we want <code>/test/St2-18</code> and <code>test/UY-SC</code> to lead to the same dynamic page. </p>
<p>The data that the user will see there should, however, differ from each other since we want to fetch data for <code>St2-18</code> and <code>UY-SC</code>, respectively.</p>
<p>We have a <code>getData()</code> function which helps reach out to our backend data. But we still have to know which exact data we want to extract from our dummy backend.</p>
<p>For this step, we can pull the specific identifier from the URL, <code>St2-18</code> for example, and combine this with our extracted <code>getData()</code> result data. </p>
<p>From there we can search for the specific object containing the data we want to display within our backend's <code>getData()</code> result.</p>
<p>Now, let's head back to our code example to see this process in action.</p>
<p>See the following code section where we implement <code>getStaticProps()</code>:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> getStaticProps: GetStaticProps = <span class="hljs-keyword">async</span> (context) =&gt; {
    <span class="hljs-keyword">const</span> itemID = context.params?.something;
    <span class="hljs-keyword">const</span> data = <span class="hljs-keyword">await</span> getData();
    <span class="hljs-keyword">const</span> foundItem = data.stars.find(<span class="hljs-function">(<span class="hljs-params">item: starInterface</span>) =&gt;</span> itemID === item.id);

    <span class="hljs-keyword">if</span> (!foundItem) {
      <span class="hljs-keyword">return</span> {
        props: { hasError: <span class="hljs-literal">true</span> },
      }
  }

  <span class="hljs-keyword">return</span> {
    props: {
      specificStarData: foundItem
    }
  }
}
</code></pre>
<p>For JavaScript, you can just omit <code>GetStaticProps</code> as the type for <code>getStaticProps()</code>. </p>
<p><code>getStaticProps()</code> can provide us with a <code>context</code> parameter through which we can reach some helpful methods. For now, it's just important to understand that through <code>context</code> we are able to access <code>params</code> and then afterwards reach out to the current identifier of our specific path for which <code>something</code> is the placerholder. </p>
<p>Remember that this file is actually called <code>[something].tsx</code>, which is why we access <code>something</code> in this context.</p>
<p>With this approach, we successfully extract the information we need from our URL to search for the specific object in our backend data array. Then we save this information in the <code>itemID</code> variable.</p>
<p>Let's say the user reaches out to <code>/test/St2-18</code>, then <code>itemID</code> would hold the value of <code>St2-18</code>.</p>
<p>Since we have our handy <code>getData()</code> function, we can just get our backend data through this function and save it to <code>data</code>.</p>
<p>Since we now have <code>itemID</code> as well as <code>data</code>, we can combine both variables and create <code>foundItem</code>. This returns the object that includes the <code>itemID</code> as an <code>id</code>.</p>
<p>With the <code>if</code> statement, we are checking if <code>foundItem</code> actually exists. Or in other words, we check if our backend data contains data with the corresponding <code>id</code> we extracted through our <code>itemID</code>.</p>
<p>If no data can be found, we return this boolean <code>hasError</code> with the value <code>true</code>. This helps us manage such cases on the frontend.</p>
<p>If there is data, then we return our <code>foundItem</code> to the frontend. Keep in mind that everything you return in this <code>props</code> object will actually be exposed to the frontend. So don't return any credentials (personal API keys, for example).</p>
<h3 id="heading-setup-for-getstaticpaths">🔨 Setup for <code>getStaticPaths()</code></h3>
<p>Before we head to the frontend part of our dynamic page, we still need to implement the <code>getStaticPaths()</code> function:</p>
<pre><code class="lang-typescript">  <span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> getStaticPaths: GetStaticPaths = <span class="hljs-keyword">async</span> () =&gt; {
    <span class="hljs-keyword">const</span> data = <span class="hljs-keyword">await</span> getData();
    <span class="hljs-keyword">const</span> pathsWithParams = data.stars.map(<span class="hljs-function">(<span class="hljs-params">star: starInterface</span>) =&gt;</span> ({ params: { something: star.id }}))

    <span class="hljs-keyword">return</span> {
        paths: pathsWithParams,
        fallback: <span class="hljs-literal">true</span>
    }
  }
</code></pre>
<p>For JavaScript, you can just omit <code>GetStaticPaths</code> as the type for <code>getStaticPaths()</code>. You can also delete <code>starInterface</code> for JavaScript.</p>
<p>Within the <code>getStaticPaths()</code> function, we want to tell Next.js which paths should be pre-rendered. </p>
<p>For this step, we are accessing our backend data with <code>getData()</code>, as you saw in <code>getStaticProps()</code>.</p>
<p><code>getStaticPaths()</code> demands a specific form for the <code>paths</code> within the return. You actually have two options:</p>
<ul>
<li>The first one is the approach I am using in this example: <code>paths: [{ params: { something: star.id } }]</code>. It should be an array with an object for every path you want Next.js to pre-render.</li>
<li>The second option is to use path strings like this: <code>paths: ['/test/St2-18', '...', '...']</code>.</li>
</ul>
<p>Both techniques achieve the same behavior, so just pick the one you prefer.</p>
<h3 id="heading-what-is-the-fallback-property">What is the <code>fallback</code> property?</h3>
<p>It's important to understand is that you don't need to include every path which should be pre-rendered. This is especially helpful when you have a lot of cases to consider and don't want everything to be pre-rendered. </p>
<p>To handle such cases, the <code>fallback</code> property is particularly useful</p>
<p>You can read more about the <code>fallback</code> in detail in the <a target="_blank" href="https://nextjs.org/docs/api-reference/data-fetching/get-static-paths#fallback-false">official Next.js documentation</a>.</p>
<p>In my own words, I would explain it like this:</p>
<ul>
<li><code>fallback</code> set to <code>false</code> would automatically lead to a 404 error page whenever the user tried to access a path which wasn't recognized by <code>getStaticPaths()</code> through the paths property.</li>
<li><code>fallback</code> set to <code>true</code> doesn't automatically lead to a 404 error page whenever the user tries to access a path that doesn't exist in <code>getStaticPaths()</code>.
This way, we still reach out to the frontend and are able to handle the situation there by displaying some sort of loading sequence, for example. 
You can also display an error on the frontend if there wasn't any data to be fetched when there was no valid item data for the specific path parameter.</li>
<li><code>fallback</code> set to <code>'blocking'</code> doesn't automatically lead to a 404 error page whenever the user tries to access a path that doesn't exist in <code>getStaticPaths()</code>. 
It's similar to <code>fallback</code> set to <code>true</code> but now we basically omit any manual loading processes. Instead, the browser just takes a moment longer to fetch the data and then displays the page ready to go. 
This is helpful when you don't want to present a "Loading..." to the user, for example, and instead just let them wait a little longer before the page is loaded successfully. If no data could be found, then we still have the opportunity to create a manual error on the frontend.</li>
</ul>
<p>Since we have such a small dataset, we are just giving every possible path to <code>getStaticPaths()</code>. So we technically don't need too much attention to the <code>fallback</code> property. </p>
<p>Still, I am setting <code>fallback</code> to <code>true</code> to show you how you can handle such manual errors as well as loading sequences that might occur.</p>
<h3 id="heading-how-to-configure-the-frontend">📐 How to Configure the Frontend</h3>
<p>In the last step, we'll configure our actual page. Anything in here will be the frontend content that the user will see:</p>
<pre><code class="lang-typescript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">projectPage</span>(<span class="hljs-params">props: { specificStarData: starInterface, 
hasError: <span class="hljs-built_in">boolean</span> }</span>) </span>{
  <span class="hljs-keyword">const</span> router = useRouter();

  <span class="hljs-keyword">if</span> (props.hasError) {
    <span class="hljs-keyword">return</span> &lt;h1&gt;<span class="hljs-built_in">Error</span> - please <span class="hljs-keyword">try</span> another parameter&lt;/h1&gt;
  }

  <span class="hljs-keyword">if</span> (router.isFallback) {
      <span class="hljs-keyword">return</span> &lt;h1&gt;Loading...&lt;/h1&gt;
  }

  <span class="hljs-keyword">return</span> (
    &lt;div&gt;
      &lt;h1&gt;{props.specificStarData.name}&lt;/h1&gt;
      &lt;p&gt;{props.specificStarData.description}&lt;/p&gt;
      &lt;a href={props.specificStarData.link}&gt;More Information here (link)&lt;/a&gt;
    &lt;/div&gt;
  )
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> projectPage;
</code></pre>
<p>For JavaScript, you don't have to mention the <code>starInterface</code> as well as <code>boolean</code> within the function's arguments.</p>
<p>In the code above you can find our <code>specificStarData</code> as well as <code>hasError</code>, which both hold some values. Besides that, we utilize the <code>useRouter()</code> hook in order to have access to <code>isFallback</code>, which helps us handle any <code>fallback</code> cases. </p>
<p>Remember that the <code>fallback</code> from <code>getStaticPaths()</code> can be set to <code>true</code> or <code>'blocking'</code> if you are not able to provide every dynamic route for pre-loading. In these cases, it would prevent your page from crashing. </p>
<p>Instead, it will load for some time on the fly as the user accesses this specific dynamic route and then provides the respective information.</p>
<p>For this potential loading sequence, we use <code>router.isFallback</code> in order to return JSX with some sort of loading indication for the user.</p>
<p>If there actually is an error because the user tried to access a dynamic path for which no data can be found, <code>hasError</code> steps in, indicating that there is an actual error.</p>
<p>Assuming that the user actually reached a dynamic path for which data could be fetched, the actual intended JSX output will be returned.</p>
<p>Following all the configuration steps (with <code>fallback: true</code>), we receive this output for the <code>/test/St2-18</code> path:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/07/image-250.png" alt="Image" width="600" height="400" loading="lazy">
<em>Result for <strong>/test/St2-18</strong></em></p>
<p>If we try to put in an invalid parameter, it first tries to load and then returns our manual set up error message:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/07/image-252.png" alt="Image" width="600" height="400" loading="lazy">
<em>Result for <strong>/test/this-will-produce-an-error</strong></em></p>
<h3 id="heading-how-to-test-the-fallback-property">🎲 How to Test the <code>fallback</code> Property</h3>
<p>And that's pretty much it! The result is a dynamic route which uses <code>getStaticProps()</code> as well as <code>getStaticPaths()</code> in order to pre-render the fetched data from our dummy backend. </p>
<p>When you are working with <code>getStaticPaths()</code> for the first time, I recommend trying out the different <code>fallback</code> values (<code>true</code>, <code>false</code>, <code>'blocking'</code>) to find out how exactly your application's behavior changes.</p>
<p>Since we are using <code>fallback: true</code> in our example, we are also able to just insert one possible path out of the three without having our application crash. </p>
<p>So let's say we change the <code>paths</code> property within <code>getStaticPaths()</code> to <code>paths: ['/test/St2-18']</code>. While we inserted all the paths before, we now just use one path with the string method I mentioned earlier instead of the <code>{ params: { something: star.id }}</code> format. </p>
<p>With this configuration, you can still access <code>/test/UY-SC</code>, for example, but you'll notice that the <code>Loading...</code> message appears for a brief moment because we prepared this case in our if-statement with <code>router.isFallback</code>. After the data is loaded, it will successfully show up on the screen.</p>
<p>When using <code>fallback: 'blocking'</code> and <code>paths: ['/test/St2-18']</code>, you'll notice that you can't see any <code>Loading...</code>. Instead, the browser just takes a moment longer to load the data before changing the browser's content.</p>
<p>It's up to you which way you prefer.</p>
<h2 id="heading-conclusion"><strong>✅</strong> Conclusion</h2>
<p>While this example shows the fundamental parts of <code>getStaticProps()</code> as well <code>getStaticPaths()</code>, there is still more to read about these Next.js functions.</p>
<p>Still, all you've read here is enough to get started working with <code>getStaticProps()</code> and <code>getStaticPaths()</code> on your own in a lot of cases.</p>
<h2 id="heading-resources-amp-learning-material"><strong>📃</strong> Resources &amp; learning material</h2>
<ul>
<li>Official Next.js documentation for <a target="_blank" href="https://nextjs.org/docs/basic-features/data-fetching/overview"><strong>Data Fetching</strong></a>.</li>
<li>For learning more about Next.js on the whole, I can strongly recommend checking out the <a target="_blank" href="https://www.udemy.com/course/nextjs-react-the-complete-guide/">udemy course by Maximilian Schwarzmüller for Next.js</a>. This course helped me a lot, at least.</li>
</ul>
 ]]>
                </content:encoded>
            </item>
        
    </channel>
</rss>
