Hello Testing with Cypress and Selenium
Tags: selenium, cypress, testing, beginners
Published: 2020-01-02 14:08:56

<i>
This article will test a simple log in page. Consider it the Hello World of testing using  two frameworks.
 I'll be writing using two different languages.

<ul>
<li>Selenium using Java</li>
<li>Cypress using JavaScript</li>
</ul>
</i>


For the sake of brevity, the article will be divided into three sections
<ol>
<li>Setting up and Testing with Cypress</li>
<li>Testing with Selenium</li>
<li>Comparison between Cypress and Selenium and use case scenarios</li>
</ol>


<h4>Setting up and Cypress installation</h4>

<p>
Let’s call the web app we will work on NASS Protector Launch. Anytime there is an alien attack on the planet, we can always login into the web app and click the “Rescue” button to wade off the incoming attacks. As such we need to monitor our login page to ensure it never malfuncions – and even if it does, for us to know on time

 </p>

<p>
Since is a grand app,our engineers need to keep working round the clock to add additional more functionality to save the world but our concern here is to ensure the login always works regardless of the changes being made and for us to detect as fast as possible if any major functionality is broken
And this is where automation test comes in
</p>

<b>Let's setup the page first before we embark on automating testing</b>

<i>Here is a simple codebase for the login page and the dashboard with plain html, a little css and javascript.</i>

{% gist https://gist.github.com/mySuulola/fd595fcfefc63df49b893891f49dbdd9 %}

Now that our login and dashboard pages are setup. It is time to move on to Cypress Installation

We start by creating a package.json  to manage the cypress dependency that will be installed later.

```
npm init
```

I prefer using npm init -y then make any edit from there. Its faster that way. The next thing is to install cypresss. I will be using npm

```
npm install cypress –only=dev
```
If you prefer yarn
```
 yarn add cypress
```
When its done, you will get something like this
![Alt Text](https://thepracticaldev.s3.amazonaws.com/i/xy69zvr50fqcwqdulvft.png)

At this stage, your project structure should resemble this
![Alt Text](https://thepracticaldev.s3.amazonaws.com/i/98cp0bwg3bmmwbdprvwl.png)


to run cypress, simply run

```
npx cypress open

```

![Alt Text](https://thepracticaldev.s3.amazonaws.com/i/qhpc94kpdqrm78vjm604.png)
This pops up the above test  modal suite you will get very familiar with very soon and if you look closely a folder will be created in your project directory named cypress. 

![Alt Text](https://thepracticaldev.s3.amazonaws.com/i/et2xb0n7s83b92bceiy6.png)


If you got here, you’ve successfully set up cypress and you’re good to start writing code using Cypress. You will be writing most of your test code inside the cypress/integration folder. There are some examples in the example folder to familiarize yourself with Cypress syntax.

I normally delete the example folder but its a good place to start learn the workings of Cypress.

The first thing is to create a file within the integration folder, I will call it protector_launch and it will contain all the tests that has to do with this particular application while deleting the example folder.

Inside the protector_launch,  create a test script. I will call mine login.spec.js

the ‘spec’ in-between is to show this is a test file and not a typical JavaScript file.

We start with a basic outline


{% gist https://gist.github.com/mySuulola/bd630b5593f0ef3da97866487e0007d2 %}

the first line which is the reference line indicates that this is a cypress file and this aids in bringing auto-suggestion of cypress syntax while typing. Without it, you wont have auto-suggest.

If you’ve ever worked with mocha/chai or similar testing frameworks, you will be familiar with the <i>describe</i> and <i>it</i> syntax used in cypress.

The describe block is a way to group our test.It takes two argument
<ul>
<li> a string name describing what the test group is about</li>
<li>a callback function where we write each of our <i>it</i> statements that execute the test </li>
</ul>

Inside the describe block callback, let's start writing our test.

```
  before(() => {
    cy.visit("./../../../index.html")
  })
```
The first thing we want to do before we run our test is to visit the url. In this case, it is a relative path on the local machine. Assuming, i want to test my facebook login url

```
cy.visit("https://web.facebook.com/login")
```

Now, this is where the fun begins. We are set to write our first test here after visiting the web page.

```
  it("checks that the input fields are visible", () => {
    cy.get('#mail').should('be.visible')
    cy.get('#pass').should('be.visible')
  })
```
The <i>it</i> block also takes the same arguments as the describe block except that the content of the callback are usually actual tests.
Here we use  cy.get() to locate the email input field that has an id of mail. You can use your developer tools to check the selector of the element you want to target. cy.get() in cypress acts like document.querySelector() in javascript. Just specify the selector and it does the magic.

After selecting the elements with id of mail and pass. We use the should method to check if it is visible on the page, if it is visible then the test will pass else the test fails.

```
  it("a user cannot login with incorrect credentials", () => {
    cy.get('#mail').type('user@alien.com')
    cy.get('#pass').type('frompluto')
    cy.contains('Log').click()
    cy.url().should('include', '/index.html')
    cy.get('#mail').should('be.visible')
    cy.get('p').should('not.have.text', 'Now you can save the world')
  })

```
The next test is to check if a user can login in with incorrect credentials. <i>type</i> is used to type the details in the input field selected. 
cy.contains() searches for an element on the page that contains the text, then .click() clicks on that element.

The assertion here tests that the user is still on the same page with 

```
cy.url().should('include', '/index.html')
```
A successful login will have changed the page to dashboard.html so if that passes, then the login failed. The other assertions ensures the input field with an id of mail is still present on the page and that the page does not contain the text present on the dashboard.


```
  it("logins into the application with the correct credentials", () => {
    cy.get('#mail').type('test@test.com')
    cy.get('#pass').type('tester')
    cy.contains('Log').click()
    cy.url().should('include', '/dashboard.html')
    cy.get('p').should('have.text', 'Now you can save the world')
  })
```
This next test code does the same thing as above except that it checks if a user with the correct credentials is able to login to the application and move to the dashboard where you can save the world.

Apart from web page testing, cypress can also be used for
<ul>
<li>API testing</li>
<li>Performance/Load testing</li>
</ul>

Using the current application, we can write a simple GET request
```
  // a simple api request mock
  it("checks if the app is up and running when called", () => {

    // the request body contains the method(whether GET, POST, PUT, DELETE), the endpoint/url and the necessary header options
    cy.request({
      method: 'GET',
      url: './../../../index.html',
      headers: {
        accept: 'text/html',
      }

    })
    .then(response => {
      // this is where the response gotten from the server is tested
      // 200 response means its okay and good
      // when not sure, you can always console.log(response)
      expect(response.status).to.eq(200)
      expect(response.statusText).to.eq("OK")
      expect(response).to.have.property("headers");
      expect(response.body).to.have.length.greaterThan(500);

    })
  })
```

A simple performance test with the current web page will look like this
```
  it('check page load time', () => {
    cy.visit('./../../../index.html', {
      onBeforeLoad: win => {
        // marks the start time when the request is launched
        win.performance.mark("start-loading")
      },
      onLoad: win => {
        // marks the time when the page is displayed
        win.performance.mark("end-loading")
      }
    }).its("performance").then(perf => {
      // when not sure, you can always console.log("this is perf",perf)

      // this is where the measure takes place. it subtracts the end-loading from the start-loading and stores it in pageLoad
      perf.measure("pageLoad", "start-loading", "end-loading")
      const load = perf.getEntriesByName("pageLoad")[0]
      // checks if the load duration is more than 10ms
      assert.isAtMost(load.duration, 10)
    })


  })
```

I added comments to the code to make it explanatory enough to understand. 

{% gist https://gist.github.com/mySuulola/da9ebf6ccfe9a785a5ce611acee5f78d %}

The full codebase can be found on

{% github mysuulola/hello_test %}

Comments, Questions and Observations are welcomed.


Next is writing our Selenium test