Switching to Cypress from Protractor in Less Than 30 Seconds

Anthony Jones
BrieBug Blog
Published in
4 min readFeb 5, 2019

If you haven’t heard of Cypress yet, I’m sure you will soon. Cypress is a self-proclaimed “developer-friendly” open source end-to-end testing framework. It offers features such as time travel, dev tool debugging, live reloads, automatic waiting (no waits or sleeps in test code), as well as screenshots and videos of test runs.

But I’m actually not here to tell you about Cypress itself or how to test with it (they have great documentation already). I’m going to show you how I created a schematic that allows you to easily install Cypress with Typescript compatibility out of the box. It also allows you to remove Protractor and its dependencies from your project if you so choose.

Alright, let’s get into some code.

If you’d like to follow along and/or contribute Fork the repo on Github.

To install: npm install -g @briebug/cypress-schematic & ng g @briebug/cypress-schematic:add or ng add @briebug/cypress-schematic

Every schematic starts off with a collection.json file.

collection.json

This is essentially a list of schematic commands, extending the @angular-devkit collection-schema. For each schematic, the factory and description properties are required, but there are several other schematic properties that can be added as well. One of those is the schema property. This allows us to create a schema.json file for our individual schematic:

schema.json

The schema.json is where you specify the details of your schematic and its properties. Properties are basically the “options” of schematics. For instance, in the @angular/cli new schematic, you have properties like styleext where you can set your project’s default style to CSS or one of the supported CSS preprocessors. Here, I’ve inserted a removeProtractor property of type boolean, with a CLI prompt asking the user “Would you like to remove Protractor from the project?”. You can also set certain properties as required. Just include the property name as a string in the required array.

Next up is the index.ts file. This is where the magic (logic) happens. Let’s look at each part separately:

index.ts — default function

From the index.ts file, you need to export at least one function. Here I’ve chosen to export a default function, but you can use a named function if you like. This function is going to return a Rule, which “transforms a tree into another tree”. Now you may be asking “what’s a tree?”. A Tree is an interface containing a bunch of really useful methods for creating, modifying, and removing files and directories from your schematic.

In this default function, I’m returning a chain of Rules that will comprise our “transformed tree”. First, I update the package.json dependencies, then remove any unnecessary files, after that, I add the files needed for Cypress as well as a couple of scripts to get Cypress going.

index.ts — updateDependencies

While updating the package.json dependencies, I’m first going to check the value of the removeProtractor options property. If you remember the schema.json file, it’s the only property we defined for our schematic, and it will prompt the user to enter a boolean value. If removeProtractor is true, I remove that dependency using a utility method called removePackageJsonDependency. If you check out the repository, you’ll see a utility directory with three different ts files: dependencies.ts, json-utils.ts, and util.ts. The first two are borrowed from the @angular/cli schematics, and the util.ts file is custom. These files contain helper methods for building schematics, interacting with the tree, and traversing/modifying json.

index.ts — removeFiles

In this schematic, I only remove files if removeProtractor has a value of true. Otherwise, I skip right to returning the tree. Using a tree method, I delete the entire e2e directory. Then by modifying the angular.json file, I remove the e2e “project”.

index.ts — addCypressFiles

Adding files is one of the most powerful things you can do with a schematic. You’ll mainly see this in the @angular/cli generate schematics, such as ng generate module “module name” or ng generate component “component name”. Here, I’m adding a tsconfig.json file which extends the root tsconfig.json, as well as two plugin files, a cypress/typescript preprocessor, and an index.js file. These allow you to write your cypress tests in TypeScript.

index.ts — addCypressScriptsToPackageJson

Finally, I add a couple of scripts to the package.json file. cypress-open and cypress-run. These definitely aren’t required, but allow you to run yarn cypress-open rather than $(npm bin)/cypress open.

I think schematics are an incredibly powerful tool, and we’re just seeing the tip of the iceberg as far as what this community will do with them. In this relatively small schematic, I was able to add and remove package.json dependencies, remove and add files within the project, modify the angular.json, as well as add scripts to the package.json.

Thank you for taking the time to read this article, and if you’d like to dig further into schematics, here are a couple of great resources:

https://brianflove.com/2018/12/11/angular-schematics-tutorial/

I’d like to thank Kevin Schuchard for setting up the Schematic Sandbox, and writing the Jest schematic which inspired this schematic. (More info on this sandbox approach is detailed in this blog post kevinschuchard.com/blog/2018–11–20-schematic-sandbox/) Also, thank you to Zahid Mahmood for writing this blog post detailing setting up cypress in an Angular project.

--

--

Anthony Jones
BrieBug Blog

Christian, Husband, Father, Friend, Developer, Coffee Extractor/Drinker