Cypress is an E2E testing tool designed specifically to be easy to use for frontend developers. In this lesson we test the functionality of a React application using Cypress.
Instructor: [00:00] We start off with a very barebones TypeScript React application. We have a checkbox with label component that we render to the root element in the DOM. The component takes an ID, an on label, and an off label.
[00:17] If you go ahead and start the application and visit localhost:8080, you can see the application running. The checkbox starts with an off state, and we can trigger it on with a click.
[00:32] Let's add a real browser test for this behavior using Cypress. We will go ahead and make a separate directory for Cypress.
[00:41] In that directory, we will go ahead and initialize a new package.json, and then install Cypress, as well as any tools Cypress needs to transpile TypeScript code on the fly using webpack. Of course, webpack, TypeScript, and ts-loader are the obvious things that we are installing here.
[01:08] Next we open the Cypress IDE using cypress open. This will initialize the Cypress folder structure for us. To configure Cypress for TypeScript, you will go into the cypress/plugins/index.js file and replace whatever is present there with a webpack TypeScript preprocessor.
[01:37] This is provided by the Cypress webpack preprocessor, and we simply need to initialize it to use ts-loader. The webpack options here are the standard webpack.config options for TypeScript and tsx.
[01:52] We will set it to mode transpile only as we do not want this to do any type checking, to save us some speed. Finally, we wire this preprocessor to the file preprocessor event in Cypress.
[02:14] We will go ahead and add a separate ts-config.json to this folder. Keeping the ts-config for the e2e tests separate from our project code prevents global type definition conflicts, for example, describe init.
[02:31] All the testing frameworks tend to use the same names. They are all in the global namespace, so it's best to keep Cypress separate from their pollution. The config options will be very similar to what you have in the root of your project.
[02:45] Optionally, we can go ahead and add a few script targets to our package.json. One would be for development, which will simply run cypress open, and the other would be cypress run for the build server.
[03:05] That's it for the configuration. Note that at this point, this e2e folder is primed to be copy-pasted into any TypeScript React project you want and it doesn't depend our project in any way whatsoever.
[03:19] Now let's write some tests. All the Cypress tests exist in the integration folder. It comes with a few examples, and we can safely delete that.
[03:28] We'll go ahead and create a new happy spec.ts file for our test. We will reference the Cypress type definitions, and we will create a happy path test that should work. Initially, we'll simply visit the server that we have running using npm start.
[03:48] If we go to the terminal and run the Cypress IDE using cypress open, we can see that our test is present, and clicking on it goes ahead and runs the test. You can see that the test passes. At this point, it is only visiting localhost:8080 using the site.visit command.
[04:13] The next step is to assert the text of the root label, then trigger a click on it, and then assert that its text changes. We can get a handle to the root label using the Cypress inspector. It tells us that it has the ID on/off, and we can use site.get to get it. We can copy this and paste it directly into our test.
[04:41] We can make assertions using the shoot command provided by Cypress, and passing in the chain have text. It should have the value off. Then we go ahead and trigger a click using the click command, and then we make an assertion that it should have text on.
[04:59] As soon as we save this file, Cypress is going to rerun the test in the background. We can actually go ahead and view the snapshot of the DOM as the test was running.
[05:14] We visited the page, then we got the element, asserted its text, and finally, we triggered a click, and asserted its text to change to the new value. If we want, we can also go ahead and rerun the test to see it unfold in front of our eyes.
[05:34] Finally, we can go ahead and make our tests more deterministic by sharing the code, like the constants between our application and the tests. We'll go ahead and create a new constants file in the source folder. We will isolate the ID for the root label, along with the text for the two options.
[06:00] Next, we jump into the application root and use these constant values to power our application. We can go to our test file and use the same constants file from the source directory to bring in these constant values and use them to power our test. You can see that the test continues to work as expected.
[06:35] If we go ahead and change something, for example, capitalize the on and the off text, the test continues to work, and we didn't have to edit any of the other files. This works thanks to the way we set up Cypress to use webpack and TypeScript.
[06:56] Finally, on the build server, you can execute the tests using cypress run. This runs the tests in a CI-friendly manner without prompts and window interactions.