This post is part of the E2E Testing Series. If you haven't already, I suggest going back and reading previous posts before continuing.
Just give me the code...
Here is the "tl;dr" version of the article below, with just the commands to run and the code you'll need to add. If anything isn't clear, I suggest reading the full post.
- Install the sample app:
npx create-next-app e2e-testing --ts --use-npm
- Create a
src
directory and move thepages
andstyles
directories into it. - Install these packages:
npm i -D cypress cypress-watch-and-reload start-server-and-test
- Rename the
dev
script in yourpackage.json
todev:next
. - Add these scripts to your
package.json
:
"cy:e2e": "cypress open --e2e --browser chrome --config baseUrl=http://localhost:3000",
"dev": "start-test dev:next 3000 cy:e2e"
- Run
npm run dev
to initialize Cypress. - Update/add these files (click on the file link to view the code):
- Run the
dev
script to enable E2E test development with hot reloading of test and source files.
Introduction: Keeping E2E tests front and center
One of most common anti-patterns I see relating to E2E testing is that, while a test suite has been set up and some tests have been written, it is almost never run locally and new tests are only rarely added for new features. This obviously is not a good thing, since we effectively are wasting all the effort that went into setting up the test suite.
But why would we let such a valuable resource go to waste?
One simple answer is that it is out of sight, out of mind. In other words, while the command to run the E2E test locally does exist, it's something you have to remember to do, and it's kind of a hassle, since you usually have to first fire up the dev environment, and then start the E2E runner in a second terminal.
One way to address this problem is to automate running of the E2E test suite whenever you start up your development environment. As we'll see, this can have a significant positive impact on your E2E practice.
Add a single command for starting both dev environment and test runner
To help ensure E2E tests get written, we want to make it is easy to have both our app running and the test runner in a hot-reloading state. In other words, as we write tests, we want to be able to get quick feedback on if tests are passing or not.
When we are done with the steps below, you'll be able to just run npm run dev
to both start you dev environment and also start up your E2E test runner in dev mode, meaning that it will rerun tests automatically if changes are made either to the tests or your code. As an added bonus, it will reduce the amount of terminal windows you have open in your IDE.
Setting up our sample app
We'll be using NextJS as the basis for our sample app. One reason for this is that our newsletter feature will require an API endpoint, and NextJS makes it super easy to add that.
To get started, go ahead and run the following to install the sample app:
npx create-next-app e2e-testing --ts --use-npm
You can replace e2e-testing
with any app name you prefer. Both the --ts
and --use-npm
are optional. NPM is just my personal preference, and I am a strong proponent of using TypeScript.
Install the E2E test runner and utility packages
For this tutorial, we're going to use Cypress, which in my opinion currently is the best end-to-end testing solution. (My one gripe with Cypress is the lack of support for testing of older browsers, which are the ones often causing regressions.)
Let's install all the packages we'll need, as development dependencies:
npm i -D cypress cypress-watch-and-reload start-server-and-test
Add the dev scripts
Next, let's update the scripts
section of our package.json
as follows:
First, rename the dev
script to dev:next
. Then, add the following scripts:
"scripts": {
...
"cy:e2e": "cypress open --e2e --browser chrome --config baseUrl=http://localhost:3000",
"dev": "start-test dev:next 3000 cy:e2e"
...
}
Configuring Cypress
We need to configure Cypress to use TypeScript and also to hot reload when our source files change.
Add Typescript support
Cypress has built-in Typescript support. To enable it, and allow for writing TS-based tests, we need to add a tsconfig.json
to the root of the cypress
folder.
Add the following code to cypress/tsconfig.json
and you should now be able to create test files using Typescript.
{
"compilerOptions": {
"target": "es5",
"lib": ["es5", "dom"],
"types": ["cypress"]
},
"include": ["**/*.ts"]
}
Also, update the main tsconfig.json
in the root directory to exclude the cypress directory, so we do not compile test files as part of compiling the main source code.
{
...
"exclude": ["node_modules", "cypress"]
}
Get Cypress to hot reload if your source files change
By default, the Cypress runner will only re-run if you modify test files. However, we really also want it to restart when we make changes to our code. To achieve this, we need to make the following updates:
First, update cypress.config.ts
as follows:
import Cypress, { defineConfig } from "cypress";
interface Config extends Cypress.UserConfigOptions<any> {
"cypress-watch-and-reload": {
watch: string | string[]
}
}
const config: Partial<Config> = {
"cypress-watch-and-reload": {
watch: ["src/**/*"],
},
e2e: {
setupNodeEvents(on, config) {
return require("cypress-watch-and-reload/plugins")(on, config);
},
},
}
export default defineConfig(config);
Next, add the following to the end of the file cypress/support/e2e.ts
.
require("cypress-watch-and-reload/support");
Your local environment and dev
command should now be set up.
Go ahead and run npm run dev
and you should see the dev server first start up, then the test runner will start. The first time you run Cypress, you may be asked to click through their startup wizard.
Btw, a huge shout-out to Gleb Bahmutov who is the author of both the utility packages we are using here! 👏 👏 👏
Top comments (0)