 In this tutorial, we will learn how to create a very simple React web app in under five minutes. We'll learn how to code component tests by using React testing library, how to shift right by adding automated visual testing using WebDriver.io and Screener, and finally, we're going to put it all into a CI pipeline using GitHub Actions with staged execution and true continuous integration. My name is Nikolaj Galakian. I'm a Principal Solutions Architect at SoftLabs and creator of UltimateQA.com. Let's go have some fun. Alright, so let's go ahead and start creating our React app. You can see that I'm here in a folder called React Web App, where I've only got a license and a readme, 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 MyApp. 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 MyApp. And then in MyApp, you can see now if we open this up, we now have a MyApp folder, has its own 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 localhost3000, 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 package.json, we can see that if we run a NPM test command, it's 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.test.js. 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 tests, 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 it notices that we are obviously using Node.js 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 us. And the other nice thing about creating your YAML 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 slash 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, source username and source 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, source username and source 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. Okay. 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 kind 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, right? And then done a 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 in CI. Next, we're going to build the app, right? This was just seeding to my app and doing a 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 localhost 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 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 tests exactly as you saw before. And then finally, we are starting up our application actually starting the server by doing NPM start. And then we're doing a wait on command that will wait for the app to start up for up to 60 seconds before airing out. And we will expand this pipeline as we expand our testing. So once it's ready, the only reason I recommended 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. We're going to do that github slash workflows. Oops. And then we're going to add a new file here. Let's call it ci.yaml. It will look exactly as I showed you here. I actually named it to ci2. 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 ci2. Exactly the name that we gave it in the yaml file. And it did fail after nine seconds. So let's go ahead and take a look at exactly what happened. So the air says that we can only install packages with a package log json or npm shrimp drag 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 log that json. And then let's go ahead and add it. And we can watch our CI rerun. Here you can see we just committed 14 seconds ago. Here's a little yellow circle that shows that our CI 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 suiz here in. 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 is before. However, now we are going to validate that the href of the link 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 app.js. And we will change the URL to ultimate qa.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, we 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 is visible. And of course, this is the text that exists. However, this exercise also showed us that having text as a check in our tests 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 dash attribute. And so here we can do a data dash test ID. And we can call it a learn link. We'll 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 our CI. 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. 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 a 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 Web driver 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 Web driver IO. Let's install Web driver IO. Let's configure Web driver IO. You're going to get a nice handy menu that allows it allows you to decide what you're going to do. So we're going to execute in the cloud using sauce labs. Yes. So 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 driver 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 WDIO 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 diff, you can see we've got a few WDIO services added for our testing purposes. Web driver IO tests by default go to test specs directory. And in here I created a visual dot 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 Web driver IO. We navigate to a URL and then we execute two important commands. First, we do an init, 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 driver IO lives 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 sauce 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 to scroll and stage 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 from 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 the 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 10 and Chrome. And then the other type of browser that we're running on is Mac OS Safari on this resolution, which is an iPhone X viewport size. And of course, we can have a lot more resolutions 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. We can come here and add and then ensuring that in a separate terminal, you have the application actually running on local host 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 screener UI to see what's going on over there. So we can see that here is our new app dash two that we've started. There are currently tests 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. Let's go ahead and accept it. And so now from this point forward and new executions, we'll 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 our CI YAML. We've added a brand new step our 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 passed. 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 going to point to mia.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 Nikolai 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 too has two changes. Let's click take a look and see exactly what happened. And so what screener shows is two visual changes that have occurred. A screener uses a smart hybrid 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 the 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 DOM 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 driver IO and screener. And then we put it all into a CI pipeline using GitHub actions that execute on push and pull requests. It's been my pleasure. If you want to learn more, you can always reach out to me at ultimate2a.com or my social medias and I'd be happy to connect. Have a wonderful day.