<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Alex</title>
    <description>The latest articles on Forem by Alex (@alexkmarshall).</description>
    <link>https://forem.com/alexkmarshall</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F338758%2F3aabd7f0-dab8-4275-bce4-b773b832c56f.jpg</url>
      <title>Forem: Alex</title>
      <link>https://forem.com/alexkmarshall</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/alexkmarshall"/>
    <language>en</language>
    <item>
      <title>Better Tests for Text Content with React Testing Library</title>
      <dc:creator>Alex</dc:creator>
      <pubDate>Tue, 16 Mar 2021 15:01:40 +0000</pubDate>
      <link>https://forem.com/alexkmarshall/better-tests-for-text-content-with-react-testing-library-2mc7</link>
      <guid>https://forem.com/alexkmarshall/better-tests-for-text-content-with-react-testing-library-2mc7</guid>
      <description>&lt;p&gt;Cover Photo by &lt;a href="https://unsplash.com/@scottwebb?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText" rel="noopener noreferrer"&gt;Scott Webb&lt;/a&gt; on &lt;a href="/s/photos/abstract-background?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText"&gt;Unsplash&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When testing React apps, there can be many ways to write a test. Yet small changes can make a big difference in readability and effectiveness.&lt;/p&gt;

&lt;p&gt;In this post I'm going to explore a common scenario. Testing a component that renders some text based on a variable prop. I'll assume a basic familiarity with React and React Testing Library.&lt;/p&gt;

&lt;p&gt;For this example I have a greeting component which accepts a name prop. This renders a welcome message customised with the provided name.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;Greeting&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;h1&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Welcome&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;!&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/h1&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Let's test this. &lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;render&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;screen&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@testing-library/react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Greeting&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./greeting&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;it renders the given name in the greeting&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;render&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Greeting&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Jane&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;screen&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getByText&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Welcome Jane!`&lt;/span&gt;&lt;span class="p"&gt;)).&lt;/span&gt;&lt;span class="nf"&gt;toBeInTheDocument&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;We can write a test like this, and sure enough it passes. Here we're checking that the text we expect renders. But there are a few problems we can try and fix. &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;First off, the name 'Jane' appears twice in our test, we can pull that out into a variable making our test more readable.&lt;/li&gt;
&lt;li&gt;Second, if we change the component to render a different element rather than a heading, this test will still pass. But that's a change we would like our tests to tell us about. &lt;/li&gt;
&lt;li&gt;Third, if we break the component, and stop rendering the name, we don't get a great test failure message.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Use Variables in Tests
&lt;/h2&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;

&lt;span class="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;it renders the given name in the greeting&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Jane&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
  &lt;span class="nf"&gt;render&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Greeting&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="sr"&gt;/&amp;gt;&lt;/span&gt;&lt;span class="err"&gt;)
&lt;/span&gt;  &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;screen&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getByText&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Welcome &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;!`&lt;/span&gt;&lt;span class="p"&gt;)).&lt;/span&gt;&lt;span class="nf"&gt;toBeInTheDocument&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Here we extract the name into a variable. It is now clearer that the name is the focus of the test.&lt;/p&gt;

&lt;p&gt;We could go even further and use a library like &lt;a href="https://github.com/marak/Faker.js/" rel="noopener noreferrer"&gt;FakerJs&lt;/a&gt; to generate a random name. That way we can communicate that the specific name itself is not important, just that the name is rendered.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;faker&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;faker&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;it renders the given name in the greeting&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;faker&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;firstName&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="nf"&gt;render&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Greeting&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="sr"&gt;/&amp;gt;&lt;/span&gt;&lt;span class="err"&gt;)
&lt;/span&gt;  &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;screen&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getByText&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Welcome &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;!`&lt;/span&gt;&lt;span class="p"&gt;)).&lt;/span&gt;&lt;span class="nf"&gt;toBeInTheDocument&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
  
  
  Test for Accessible Elements
&lt;/h2&gt;

&lt;p&gt;Now we can address the element that is being rendered. Instead of only looking for the element by its text, we can check by its role, in this case &lt;code&gt;heading&lt;/code&gt;. We provide the text we are looking for as the &lt;code&gt;name&lt;/code&gt; property in the optional second argument to &lt;code&gt;getByRole&lt;/code&gt;.&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;

&lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nx"&gt;screen&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getByRole&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;heading&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`Welcome &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;!`&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toBeInTheDocument&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;If we were to change the component to render a &lt;code&gt;div&lt;/code&gt; instead of an &lt;code&gt;h1&lt;/code&gt; our test would fail. Our previous version would have still passed, not alerting us to this change. Checks like these are very important to preserve the semantic meaning of our rendered markup.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fw95snxrjpjqjadjndh8k.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fw95snxrjpjqjadjndh8k.png" alt="Test failure with text 'Unable to find an accessible element with the role "&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Improving Test Failure Message
&lt;/h2&gt;

&lt;p&gt;If we break the component, and stop rendering the name, our failure message still isn't ideal.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzn1q3ati6e4mn60gfgre.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzn1q3ati6e4mn60gfgre.png" alt="Similar error message to previous failure, but with a list of accessible roles, including 'heading: Name "&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It's not terrible. Jest gives us the accessible elements that it found, and we can see here that the name is missing. But if this was a larger component it may be time consuming to search through this log to find what's wrong. We can do better.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;

&lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nx"&gt;screen&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getByRole&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;heading&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sr"&gt;/welcome/i&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toHaveTextContent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Welcome &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;!`&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;We've done a couple of things here. We've extracted the static part of the text, which in this case is the word 'welcome'. Instead of searching by the full text string, we'll find the heading element that includes &lt;code&gt;/welcome/i&lt;/code&gt;. We use a regex here instead of a plain string, so we can do a partial match on just that part of the text.&lt;/p&gt;

&lt;p&gt;Next, instead of expecting what we found &lt;code&gt;toBeInTheDocument&lt;/code&gt; we can use a different matcher from &lt;code&gt;jest-dom&lt;/code&gt;. Using &lt;code&gt;toHaveTextContent&lt;/code&gt; checks that the text in the element is what we expect. This is better for two reasons. First, reading the text it communicates that the text content is the thing that we are checking - not only that some element exits. Second, we get a far better test failure message.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcmwp3j6ogh0yf20mjxx8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcmwp3j6ogh0yf20mjxx8.png" alt="Test failure saying 'Expected element to have text content: Welcome Jane!, Received: Welcome !'"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here we see right away what the problem is, we don't have to hunt anywhere to find it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Recap
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;We have extracted variables in our test to communicate what is important data for our test.&lt;/li&gt;
&lt;li&gt;We used &lt;code&gt;getByRole&lt;/code&gt; to validate the semantics of our component.&lt;/li&gt;
&lt;li&gt;We used &lt;code&gt;toHaveTextContent&lt;/code&gt; to communicate what output our test is checking. And to get more useful test failure messages.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I picked up some of the techniques here from &lt;a href="https://epicreact.dev/" rel="noopener noreferrer"&gt;Kent C Dodd's Epic React&lt;/a&gt; course. It has supercharged my understanding of all things React, even things I thought I already knew well.&lt;/p&gt;

&lt;p&gt;This guide of &lt;a href="https://testing-library.com/docs/queries/about/" rel="noopener noreferrer"&gt;which query to use with React Testing Library&lt;/a&gt; is also very useful. The &lt;a href="https://github.com/testing-library/jest-dom" rel="noopener noreferrer"&gt;jest-dom documentation&lt;/a&gt; gives you an idea of all the matchers you can use to improve your tests.&lt;/p&gt;

</description>
      <category>react</category>
      <category>testing</category>
    </item>
    <item>
      <title>How-to set up automated checks for your React project using Travis CI</title>
      <dc:creator>Alex</dc:creator>
      <pubDate>Wed, 02 Sep 2020 13:42:13 +0000</pubDate>
      <link>https://forem.com/alexkmarshall/how-to-set-up-automated-checks-for-your-react-project-using-travis-ci-p16</link>
      <guid>https://forem.com/alexkmarshall/how-to-set-up-automated-checks-for-your-react-project-using-travis-ci-p16</guid>
      <description>&lt;p&gt;This post assumes you are familiar with the basics of React, and saving your work to GitHub.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is automation and why should you care?
&lt;/h2&gt;

&lt;p&gt;Automation is just a way to have the computer run tasks for you so you don't have to do it manually.&lt;/p&gt;

&lt;p&gt;When you build software, you do it in small chunks, adding a bit here, and a bit there, making sure everything works. But every time you change something, there's a chance that you might break something that was working before.&lt;/p&gt;

&lt;p&gt;You could manually check everything still works every time you make a change. But as your project gets bigger, that takes more and more time. And you're more likely to miss something.&lt;/p&gt;

&lt;p&gt;So why not get the computer to do those checks for you. That way you can spend your time on something more productive. Getting this all up and running is part of the process called &lt;a href="https://en.wikipedia.org/wiki/Continuous_integration"&gt;Continuous Integration&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  A super simple app
&lt;/h2&gt;

&lt;p&gt;For this post, I've built a simple app in React. It's not even a full todo-list, but it's the start of one.&lt;/p&gt;

&lt;p&gt;The app allows you to add tasks to a list.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--K3WvCNFF--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/i9lz2rh0o09bhzt9g3gj.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--K3WvCNFF--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/i9lz2rh0o09bhzt9g3gj.gif" alt="Animated screenshot showing adding a task to a todo list"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I've pushed this app up to my GitHub account. You can find it here &lt;/p&gt;
&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--vJ70wriM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://practicaldev-herokuapp-com.freetls.fastly.net/assets/github-logo-ba8488d21cd8ee1fee097b8410db9deaa41d0ca30b004c0c63de0a479114156f.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/AlexKMarshall"&gt;
        AlexKMarshall
      &lt;/a&gt; / &lt;a href="https://github.com/AlexKMarshall/TravisAutomationExample"&gt;
        TravisAutomationExample
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      A simple todo app to demonstrate integration with Travis CI
    &lt;/h3&gt;
  &lt;/div&gt;
&lt;/div&gt;


&lt;h2&gt;
  
  
  Set up the automation
&lt;/h2&gt;

&lt;p&gt;So now the project is up on GitHub, lets add some automation checks.&lt;/p&gt;

&lt;p&gt;To set up with Travis, the first thing you'll have to do is go to &lt;a href="https://travis-ci.com/"&gt;Travis CI&lt;/a&gt; and sign up there to link it to your GitHub account.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--xODPpV93--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/46117qnt1lvxna6nbtjr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--xODPpV93--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/46117qnt1lvxna6nbtjr.png" alt="Travis CI Sign up screen"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once you've done that, you're almost set. You need to add one file to your project, at the top level. Create a file called &lt;code&gt;.travis.yml&lt;/code&gt; with the following content.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;language: node_js
node_js:
  - "stable"
script:
  - yarn build
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;If you created your project with NPM instead of Yarn, replace &lt;code&gt;yarn build&lt;/code&gt; with &lt;code&gt;npm run build&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;This is pretty much the simplest script there is. We're telling Travis that our project is using &lt;code&gt;node_js&lt;/code&gt; and that we want it to use the stable version. And then we ask it to run the build script. That will run the React build process, and if we've made any mistakes that stop it from working, Travis will tell us.&lt;/p&gt;

&lt;p&gt;So, commit this file and push the change up to GitHub. Now, at the top of the GitHub page, you'll see your latest commit number, with an orange indicator next to it. If you hover over this, you'll see it tells you that some checks have not completed yet. And that the Travis build is in progress.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--w1aCVBwL--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/elzwtrn8vb69pfy9e2a6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--w1aCVBwL--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/elzwtrn8vb69pfy9e2a6.png" alt="Screenshot of the build in progress indicator"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you give this a couple of minutes, you'll see the icon change to a green tick. And if you click on it, you'll see that the build has passed.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--NYonqReG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/gs36pcsyou5282d5gc7s.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--NYonqReG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/gs36pcsyou5282d5gc7s.png" alt="Screenshot showing the passing build"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Add a little process to your process
&lt;/h2&gt;

&lt;p&gt;So this setup was super basic - lets make this check a bit more thorough.&lt;/p&gt;

&lt;p&gt;I've created a test that will check that when we type in a task and click save, it gets added to our todo-list. And the input box gets cleared.&lt;/p&gt;

&lt;p&gt;I won't go into detail here about how to write these tests, but if you've not written any before, check out &lt;a href="https://testing-library.com/"&gt;React Testing Library&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;We want Travis to run this test every time we push a commit to GitHub. So lets add a line to &lt;code&gt;.travis.yml&lt;/code&gt; to do that.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;language: node_js
node_js:
  - "stable"
script:
  - yarn build
  - yarn test
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Again, if you're using NPM, that line would be &lt;code&gt;npm test&lt;/code&gt; instead.&lt;/p&gt;

&lt;p&gt;Lets commit and push this change up to GitHub. Again, we get the green tick. Lets click on it, and click on the link to see the details of the passing build. Travis shows us a log of everything that it ran. If we scroll down to the bottom, we'll see it shows details of our tests.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Ekuji7iH--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/kqtm89enk4v0x43qsnkj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Ekuji7iH--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/kqtm89enk4v0x43qsnkj.png" alt="Travis build log, showing a list of passing tests in green"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;They've got green ticks next to them, and everything passes, great!&lt;/p&gt;

&lt;h2&gt;
  
  
  Grab a branch for safety
&lt;/h2&gt;

&lt;p&gt;Now that we have these green ticks, and we know everything works, wouldn't it be great if we could make sure it stays that way?&lt;/p&gt;

&lt;p&gt;A great way to do this is to always make our changes on a separate &lt;em&gt;git branch&lt;/em&gt;. That way we can do our work separately from the main branch, and only merge our new changes in once we're sure everything works well. To create a new branch we run &lt;code&gt;git checkout -b my-new-branch&lt;/code&gt; in the terminal. Now if we make any mistakes, they won't impact the main code.&lt;/p&gt;

&lt;p&gt;We can go one step further, and stop any merging from our branch to main, unless the Travis build has passed.&lt;/p&gt;

&lt;p&gt;In your GitHub repo, go to &lt;em&gt;settings&lt;/em&gt; and select &lt;em&gt;Branches&lt;/em&gt;. There you can type the name of your main branch, and select &lt;code&gt;Require status checks to pass before merging&lt;/code&gt; and your Travis build check. Make sure to also check the &lt;code&gt;Include administrators&lt;/code&gt; option if you want to protect yourself from yourself.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--7Runv7E4--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/q4b9fjtf0t8nb56l1lr3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--7Runv7E4--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/q4b9fjtf0t8nb56l1lr3.png" alt="Screenshot of GitHub branch protection rule, requiring Travis Build to pass before merging"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Lets try and break things
&lt;/h2&gt;

&lt;p&gt;So what happens when something breaks? I've changed my code to remove the line that adds a new todo to the list. This should mean that my tests will fail. As this is a new branch, when push we need to make the new branch on GitHub too, so run &lt;code&gt;git push --set-upstream origin my-new-branch&lt;/code&gt; in the terminal.&lt;/p&gt;

&lt;p&gt;When we go to GitHub we see it suggest to make a pull request.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s---hYevO1M--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/2c7y21nj8zffpaz5z6rx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s---hYevO1M--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/2c7y21nj8zffpaz5z6rx.png" alt="Screenshot of GitHub asking if you want to make a pull request"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We'll press the green button to create the pull request. We'll see that we can't merge this pull request until the checks finish. And if we wait, we'll see a red cross on the Travis build.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--QvoySDyG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/s02xnh0mzoysoz0v6ebc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--QvoySDyG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/s02xnh0mzoysoz0v6ebc.png" alt="Screenshot of Pull Request with failing build check"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If we click through into the details on Travis, we can see what's wrong.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Xgo4I26_--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/ssxdssl5dq4a25dn8ffv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Xgo4I26_--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/ssxdssl5dq4a25dn8ffv.png" alt="Travis build log showing failing test"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This time we don't get the green ticks. We can see the test &lt;code&gt;can add a task&lt;/code&gt; has failed, just as we expected.&lt;/p&gt;

&lt;p&gt;Travis caught our mistake, and we get a chance to fix it, instead of breaking our main code-base.&lt;/p&gt;

&lt;p&gt;We can go back to our code, fix what was wrong, and push to GitHub again. This time the build passes, we get the green ticks, and we can merge our pull request safely.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where to go from here
&lt;/h2&gt;

&lt;p&gt;This was just the basics, from here you can automate pretty much anything you can think of. &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Running full end-to-end tests&lt;/li&gt;
&lt;li&gt;Testing on different browsers or different versions of node&lt;/li&gt;
&lt;li&gt;Automating deployment to a service like Netlify if everything passes&lt;/li&gt;
&lt;li&gt;much more&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I hope this post helps you to see the benefits of Continuous Integration, and how it can be simple to set up.&lt;/p&gt;

&lt;p&gt;If you have any other suggestions for cool ways to use automation, I'd love to hear them in the comments.&lt;/p&gt;

&lt;p&gt;Happy Coding!&lt;/p&gt;

</description>
      <category>github</category>
      <category>codenewbie</category>
      <category>codequality</category>
    </item>
  </channel>
</rss>
