Cypress Part I: Getting Started
In this new series, we look at how we could include Cypress as part of our testing strategy for our single page applications.
15th Nov. 2019
In this post, we are going to look at how we could add Cypress tests to an existing Single Page App project.
The instructions will include an optional, but highly recommended, step for people wanting to use TypeScript.
But before we begin, we will need an existing SPA project — here’s one built using Aurelia and Bulma.
Installation
Now that we have our existing SPA project, we can now add Cypress to it.
-
Using your preferred package manager, do
npm install cypress --save-dev
oryarn add cypress -D
. Either commands will add Cypress as a development dependency of your project. Hang tight, this installation might take a while ☕. -
Now run Cypress;
npx cypress open -d
oryarn cypress open -d
. That is not a typo,npx
is now bundled with newer version ofnpm
, more information about it here.The command should open (after a while) the Cypress test runner UI and would have prompted you that it added some example tests.
You can delete the folder
cypress/integration/examples
, we will add our own tests later on. If you are opting to use JavaScript, proceed to the Configuration section.
Adding TypeScript
Adding TypeScript support is optional, but highly recommended. To do so, you will need to install the following development dependencies: webpack
, @cypress/webpack-preprocessor
, ts-loader
, typescript
. For our sample project, we should only need to install @cypress/webpack-preprocessor
.
-
Add
cypress/webpack.config.js
and paste the code below. This will be a separatewebpack.config.js
from our existing project config.module.exports = { mode: ‘development’, // webpack will transpile TS and JS files resolve: { extensions: [‘.ts’, ‘.js’], }, module: { rules: [ { // every time webpack sees a TS file (except for node_modules) // webpack will use “ts-loader” to transpile it to JavaScript test: /\.ts$/, exclude: [/node_modules/], use: [ { loader: ‘ts-loader’, options: { // skip type checking for speed transpileOnly: true, }, }, ], }, ], }, }
-
We will then need to update the contents of
cypress/plugins/index.js
const wp = require(‘@cypress/webpack-preprocessor’) module.exports = (on) => { const options = { webpackOptions: require(’../webpack.config’), } // this adds a handler for the Cypress event to trigger the transpilation. on(‘file:preprocessor’, wp(options)) }
This will trigger the pre-processor to kick-in when Cypress encounters a TypeScript file.
-
For TypeScript to pick up the types provided by Cypress, we will need to amend the existing
tsconfig.json
with the new values shown below.{ “compilerOptions”: { “skipLibCheck”: true, “types”: [ “jest” “node”, “Cypress” ] }, “include”: [ “cypress” ], “exclude”: [ “node_modules” ] }
We need these for our demo application since we are using
jest
for our unit test and it clashes with some built-in types in Cypress.
That should be it, Cypress should now be set up to use TypeScript.
Configuration
Cypress configuration lives in cypress.json
. This should have been automatically created for us when we finished the installation steps above. In this post, we will only add the baseUrl
option.
{
“baseUrl”: “http://localhost:8080/”
}
With this set, we won’t need to have to type the full URL of our demo application. We will look at the other options in future posts.
Adding Selectors
Instead of using CSS selectors to query the DOM, Cypress suggests using data
attributes over more fragile selectors like class
es. This would lessen the chances of tests breaking when style classes change.
Cypress has the following default selector priority: data-cy
, data-test
, data-testid
, id
, class
, tag
, attributes
and lastly nth-child
.
For this series, we will be using data-test
as our selector.
Now let’s go ahead and add selectors to the login form elements.
<div class=”field”>
<label class=”label”>Username</label>
<div class=”control”>
<input
data-test=”login-username-input”
type=”text”
value.bind=”username”
class=”input”
placeholder=”john.smith”
/>
</div>
</div>
<div class=”field”>
<label class=”label”>Password</label>
<div class=”control”>
<input
data-test=”login-password-input”
type=”password”
value.bind=”password”
class=”input”
placeholder=”password”
/>
</div>
</div>
<div class=”field”>
<button
data-test=”login-login-button”
class=”button is-primary is-fullwidth”
click.delegate=”login()”
>
Login
</button>
</div>
As you can see from the snippet above, I have opted to append the element type at the end. This allows me to easily identify what element they represent when writing my tests.
Writing Tests
Let’s add our very first Cypress test. Put your test files inside cypress/integration
; let’s add login.spec.ts
and put the content in the snippet below.
describe(‘Login Page’, () => {
before(() => {
// Since we defined the baseUrl in the config, we only need the remaining path
cy.visit(’/#/login’)
})
})
Now that we have the initial setup of our Cypress tests for the login page, we can now move onto writing the actual tests.
it(‘navigates to the correct page and logs in successfully’, () => {
cy.url().should(‘contain’, ‘login’)
// I tend to always clear the input before I type anything
cy.get(‘[data-test=login-username-input]’).clear().type(‘john.smith’)
cy.get(‘[data-test=login-password-input]’).clear().type(‘pa$$w0rd’)
cy.get(‘[data-test=login-login-button]’).click()
cy.url().should(‘contain’, ‘dashboard’)
})
As you might have noticed, that seems to be a lot for a single test. With Cypress, each of those get
s could be considered as assertions. If any of those elements don’t exist, the test fails.
Also, Cypress is an end-to-end test so we should be testing a specific flow rather than specific elements on a page.
Running Tests
Before running our tests, make sure the demo application is running.
We have multiple ways of running our Cypress tests, in this post we will look at using the Cypress runner UI. If you have closed the runner from earlier, just reopen it with the command we used previously.
Select login.spec.ts
from the list of Integration Test and Cypress will run that.
You should then see the something line the video above 🎉🎉🎉.
Next Steps
Hopefully, you have learnt something through this tutorial. We will dig deeper into what you could do in Cypress in later posts. Thanks for getting this far 😬.