Video details

How To Test Your React App (unit / functional testing and CI pipeline tutorial)


Automated testing by a developer is still a topic that is heavily contested. Developers continue to struggle to understand how to test their apps, when to test, and how to put this all together into a continuous integration pipeline. This process can be surprisingly simple with the combination of the right tools. In this live-coding session developers will learn how to create a web-app using React. Afterward, we will shift-left by adding some automated unit tests using Jest. Next, we will shift-right by adding some functional tests using Finally, the developers will learn how to continuously build and test the web app through a Github workflow.
By the end of the session, the developers will:
- Learn a bit about unit testing with Jest
- Learn Cypress for functional testing
- Put all of this together into a CI pipeline that builds and tests in a continuous manner.
PUBLICATION PERMISSIONS: Original video was published with the Creative Commons Attribution license (reuse allowed). Link:


Alright. So let's go ahead and start creating our React app. You can see that here in a folder called React Web app. I've only got a license and a read me. So let's go ahead and do an NPM in need to set up this directory. And so now we have added our package JSON. If you don't already have it installed, we should install Create React app. It's an easy way to create React applications from Facebook. Once you have Create React app installed, you can actually use Create React app to create a new React application. So let's go ahead and do that. And we're calling this app my app. Wonderful. So once that's done, downloading and installing, you can see a bunch of commands that Create React App provides for us to get started. And they tell us exactly what we can do is to CD to my app, and then in my app, you can see now if we open this up, we now have my app folder, has a tone node modules, has a bunch of code here that we will explore in a moment. So let's actually go ahead and start up our app and see what that looks like. And here is the start of our wonderful little application running on local Host 3000 that's also pointed out in the logs here. So the really wonderful thing about Create React App is not only does it build us an application that's ready to go and ready to be modified, it even comes with a test that we can execute. If we look at a package JSON, we can see that if we run A and PM test command is going to run some tests. And so what we can do is open up a new tab here and do NPM test, and that's going to execute a unit test here that we have an app that says yes. And this test is actually using React Testing library. But what you can see here is we have a test that will render the Learn React link here. We use a method called Render and we are rendering our app component. And next you can see that we are using the screen to get an element by text called Learn React. And then finally we are expecting that link element to be in the document. This is a just expect and to be in the document is the React Testing library assertion. That's fantastic, because now we have a unit test that's already ready for us and it can run regardless of whether our application is up or not. So if I close down our app and then come back here and rerun the test, they will still continue to work because they don't need a server. We are actually going to go ahead and push this up into CI. So the easiest way to get started with GitHub Actions is to come over here to the Actions tab in your GitHub repo, making sure that you have one created, and then you can come and say a new workflow. Github Actions will provide you some suggested workflows and then notices that we are obviously using NodeJS. And so then it can recommend us a potential workflow. This one right here looks fantastic. So let's go ahead and click it. It already comes with a bunch of steps that have been configured for for us. And the other nice thing about creating your Yamo file here is that you also get a little IDE that you can use. For example, you can see that if we don't do something right, let's say we do something like this. The UI automatically highlights anything that may go wrong. And so it says that we're missing a runs on here. And so then we can do runs on and then now it says that the value cannot be null, and then that's where you supply the value. So this is what our CI pipeline should look like. And let's go over it step by step. By the way, you can see it automatically gets created in a GitHub workflows folder, and then you give your file a name. I'm calling our CI pipeline CI. You can call it, of course, anything you want. And then at the very top, I am setting three environment variables. These environment variables are the Screener API key, Sauce Username and Sauce access key. They are coming from Secrets variable that is part of GitHub actions, and then coming from the key called Screener API key. Here Sauce Username and Sauce Access key. So the value from here is retrieved and stored in the environment variable on the left hand side. So where are these values coming from? Let me show you that it's very intuitive. In GitHub actions, you come to settings, scroll down to Secrets. You can see I have three keys that have been created here and inside of them they have the corresponding values that will then be set in here. Next, we are saying that we want this CI to run on push requests and pull requests whenever we do that to the master main branch. Next, here we are defining the jobs that we want to execute. We're saying we're going to run on Ubuntu latest. There are multiple types of different kinds of VMs available for you to execute on, and I'm going to be running on Node version 14. You can execute on other node versions if you want, of course. And then we are using the steps. A lot of these steps were previously provided for us, and I've made some modifications to help you get started faster with your CI pipeline. So the very first thing we want to do is install dependencies. And here we are doing exactly what we were doing in our command line for our application. And so we would have done CD, my app and then Donna NPM install. However, I'm simply using NPM CI, which is actually faster in GitHub actions because it ends up caching our dependency. So this is the recommended action to take NCI. Next, we're going to build the app. I was just heading to my app and doing an NPM run build to make sure we have a production version, because whenever we do an NPM start here and our application comes up here in local Host 3000 and we take a look at our React developer tools. We can see it's red and it says this page is using the development build of React, which we obviously don't want to use for production. We want to use the CI. We want to use the production build, and so that's how you do with NPM run build. Next, we're executing our component tests after our app is built, we simply do the same thing by navigating to that directory and running the test exactly as you saw before. And then finally we are starting off our application, actually starting the server by doing NPM start, and then we're doing a weight on command that will wait for the app to start up for up to 60 seconds and before erroring out. And we will expand this pipeline as we expand our testing. So once it's ready, the only reason I recommend that to use the UI was to help you with the IntelliSense, but ultimately the best way to do it is to come to my app and then make sure we're going to add a GitHub. I'm going to do that GitHub slash workflows Oops and then we're going to add a new file here. Let's call it C o. It will look exactly as I showed you here. I actually named the two C two so that we can see let's quit our tests and do a push. And once we do a push that should start executing our CI pipeline. Let's come and take a look at that. We'll see that I have this new branch open. So let's go ahead and do a PR with this branch. I made one mistake here. I should have put GitHub workflows in the very root not inside of my app. So what you'll see is I moved that to the correct location, did another push. And so now we have a CI pipeline that started executing here's the name called CI Two exactly the name that we gave it in the YAML file and it did fail after 9 seconds. So let's go ahead and take a look exactly what happened. So the error says that we can only install packages with the package log JSON or in PM shrimp grab JSON. So let's go ahead and fix that. In order to do that, what we need to do is come to my app and do an NPM install, which will create a package lock JSON and then let's go ahead and add it and we can watch our CI run here. You can see we just committed 14 seconds ago. Here's a little yellow circle that shows that RCI pipeline is running. Let's go ahead and take a look at the details. Wonderful. So there is our CI pipeline that is not only able to build our app and start it up, it's also able to even run some component tests against it. So if we take a look of where we are in our testing journey, you can see based on this table that we've actually got a pretty long way to go before our app is fully tested. It's a really tiny app that we haven't even made any functional changes to. And so far, the only thing that we know about this application without testing it manually is that a URL with the correct text does exist in the Dom of the application. We've validated that with a component test which came with our app create React app. And we did that using React testing library. And just how about actually knowing whether the URL is correct? Right. It may be there with the right text, but does it go to the right location? So let's go ahead and write up another test for that. The very first thing that we want to do is make sure that we are running our test suite here, and then we can add a test that looks like this where we say where that we're testing that a URL is correct. Rendering our component is before getting our link element as before. However, now we are going to validate that the href of the Inklink element will contain ultimate QA. Com, because that's where we want our URL to navigate to. And then once we hit Save, watch this window in the bottom right. It's going to execute all of the tests in this file here. The first one passed, which makes sense, but the second one failed. The URL is correct. It's saying that we expected ultimate QA. Com, but we got react JS. Org and that's because we need to make an update to our application to go to ultimate QA. Com. So let's come here and go to APS and we will change the URL two ultimate QA dot com. We're going to hit Save. Our tests are going to rerun, and now both of them have succeeded. Also, while we're here, this link text is no longer correct because we're not going to learn React. Instead, we are going to learn testing. So let's put learn testing and Dev and Hit Save now, and our tests both have failed. And the reason that they both have failed is we can take a look at our logs and it's saying that it's unable to find an element with the text learn react, and then it spits out the Dom for us here showing everything that it is visible. And of course, this is the tax that exists. However, this exercise also showed us that having text as a check in our test is not really a good strategy because we can often change the text of our links, and so we can instead use a better strategy, such as supplying a data attribute. And so here we can do a data. A test ID and we can call it a learn link will hit save. Here we'll come back to app that test. And now instead of getting by text, we can get by ID. So let's go and do that. Let's give this a run. And now everything passes because we are getting our element by test ID. And of course, if we decide to change the text, our tests continue to work. Let's go ahead and push this up into RCI. Here's our commit, and here is our check. We can check on it back in a moment. So our CI pipeline has executed successfully, which is wonderful. So let's see where we are in our testing journey. So at this point we have now tested that the URL is correct. Now how about making sure that our application actually renders correctly? We can do this test as well as making sure that our application looks correct on Web and mobile using two different technologies. We're going to use WebDriver IO and Shift right by testing our rendered application later in the stage of the development cycle. And we're going to use visual snapshots to check our application in different resolutions in the browser to make sure that our app is responsive and that it looks correct on different types of devices. And for that, we are going to use WebDriver IO. Let's install WebDriver IO. Let's configure Web Dario. You're going to get a nice handy menu that allows you to decide what you're going to do. So we're going to execute in the cloud using Source Labs. Yes, this will be our username, and this will be our access key. No, we don't want to do that, which is the default. Once you've selected all the options, now you're going to wait for Web Drop IO to install all the appropriate packages. So once all the installation is done, the only other thing that you'll need to install is the Dio sync service. And so once you have anything installed, this is what our package JSON looks like. Everything that we added. If we look at the if you can see, we've got a few do services added for our testing purposes. Webdriver IO tests by default go to Test Spec directory. And in here I created a visual spec JS file, and in here we're going to have our visual test. This visual test uses a standard describe it format, and then the commands come from the browser object, which is a global object from WebDriver. We navigate to a URL, and then we execute two important commands. First, we do an idiot, which will provide a name for the app that we're testing. So we can say my React app, for example, and then the next one we're going to do is a snapshot. This is capturing a snapshot of the page that we want to test. And so in this case, it's our home page. And so we are calling it Home page. So the config file for Web Drive Williams over here. And there's a lot going on in here, but we can take a look at only the important components. So here I've created two constants called Visual Options and Source Options, where I am setting some API keys. Here I'm setting the screener API key. I am providing a project name. I'll show you how that correlates to the actual UI, and then I'm saying two on stitch screenshots to enable that to true, so that when my apps are pulled up, the entire page is scrolled and stitched together. Next, I am enabling a Sauce connect, which is an Https proxy that allows me a secure connection for Home Local host into the cloud execution environments for Screener and Sauce Labs. This is telling us where the specs are for our tests. And then finally, the most important part of this, I would say, is the configuration to run on multiple different browsers and operating systems. So I'm running this on two of the most popular browser resolutions. The very first one is this one here on this viewport size, which is the most popular desktop and running on Windows Ten and Chrome. And then the other type of browser that we're running on is macOS Safari. On this resolution, which is an iphone X viewport size. And of course, we can have a lot more resolution here. And what's going to happen is our visual spec is going to run on both of these platforms at the same time. We can, of course, run it. We can run our tests using this command here. But instead, let's add a test script to our package. Json you can come here and add and then ensuring that in a separate terminal you have the application actually running on Local has 3000, because it has to be up for us to do end to end visual testing. We can now run our visual testing command. At this point, we can see that it's executing two specs, and of course, that's our Safari and Chrome specs. Let's go take a look at the screen or UI to see what's going on over there. So we can see that here is our new app two that we started. There are currently test running. The build has failed, and the reason why it failed is because we have two brand new snapshots that we've never accepted before. What screeners currently telling us is that hey, I've got these two snapshots of these resolutions of this page here of the home page, and I don't know whether they are acceptable to you or not, so we can open each one up and take a look. Does this look good to us and correct? Yes, it does. We can come here and set this as a baseline from this point forward. Every single automated test will validate against this version of the baseline. And this is the bigger resolution here. And this one looks fantastic to us as well. Well, let's go ahead and accept it. And so now from this point forward, a new execution will run against those baselines. Let's also now add this visual step to our CI pipeline and see that execute. Here we are back in RCI game. We've added a brand new step after application has rendered to run visual tests and performing the following commands. Let's go ahead and check all this into CI and see what happens. We've got a new commit here for adding visual tests. And here is our CI pipeline executing. So here's our pipeline after execution. We can see our visual tests have executed successfully with a check Mark. And if we scroll all the way down, we can see that two tests have pass. So the current version of our application, it's a little boring. Right. Let's make it a little bit better and actually see the power of visual testing. So we're going to replace this logo with another logo by coming into App JS. And we can see that up here at the top. We're pointing to an SVG. Let's change this SVG, and instead we're gonna point to Dot JPEG, which is a nice file that I've uploaded. So let's save that and watch our application render. And here is the cutest little dog in the world. Her name is Mia. And of course, we can also even change this link right here to be. Instead of learn testing, we can change it to something else. We can say learn testing with Nicolai and Mia. Fantastic. Our application rebuilt, and this is what it looks like. And we can even run our tests to make sure that everything is working as before our component tests, both of them working successfully. Because remember we added that nice data test ID attribute, and now we can check in these changes and see what happens to our visual test. Here's our change in GitHub. Let's see what's going on. So now if we look at the screener UI, we can see that our new app to has two changes. So let's take a look and see exactly what happened. And so what screen shows is two visual changes that have occurred. A screener uses a smart hyper Div, meaning that it analyzes the Dom and element shifts, and it identifies exactly the two elements that we have changed. And so now it's for us to decide whether this is a valid change or not. And yes, this is a valid change, and it looks fantastic. And we want to use this as the new version of the baseline. So we're going to accept this one looking at this page here. We like all of the changes here as well, and we can accept that as well. And with all of that said, we are pretty far down in our coding and testing journey. We validated pretty much everything about our application. We validated that the app renders correctly and that the app looks as expected on web and mobile using our visual Don to database tests, also known as end to end tests, and we did it with the following technologies. There is still a lot further to go and a lot more to test. However, this is all the time that we have today and this is where we have to part ways. So thank you so much for tuning in today. To watch my tutorial. In summary, we learned how to create a simple React Web app using Create React app. We added component tests using React testing library. We shifted right by adding visual test using Web drive, IO and screener, and then we put it all into a CI pipeline using GitHub actions that executes on the push and pull request. It's been my pleasure. If you want to to learn more, you can always reach out to me at ultimate dot com or my social medias and I'd be happy to connect. Have a wonderful day.