E2E testing with TestCafe | Introduction
Tags: testing, e2e, testcafe, javascript
Published: 2017-12-30 03:05:25

---
title: E2E testing with TestCafe | Introduction
published: true
tags: #testing #e2e #testcafe #javascript
cover_image: https://community.devexpress.com/blogs/thinking/TestCafe/browserstack-img-1.png
series: E2E testing with TestCafe
---

## WARNING

#### This will be a looong post. So, grab a cup of coffee/tea and hang on tight!

## Introduction

### What is E2E?

End-To-End (E2E) testing is a technique used to test an entire flow as if we were an actual user by simulating their actions (clicks, pressing certain keys, typing into a field, etc).

This is quite useful for testers, since as the project grows the amount of scenarios to test also increases and having humans do all that work can result in them overlooking/missing things because of distractions or fatigue.

Also, these tests can be configured to run on a `Continuous Integration` (CI) system that can execute all the tests every X amount of time or after a deploy. But that's a topic for another article :)

### What is TestCafe?

[TestCafe](https://github.com/DevExpress/testcafe) is a tool for E2E testing based on NodeJS that is fairly easy to setup and use that supports both JavaScript and TypeScript.

## Requirements

### Install NodeJS

This can be done via their [website](https://nodejs.org/en/download/) or via your operating system's terminal/command line (steps will be different depending on your OS).

After that, in order to verify that your NodeJS was installed successfully, run the following command in your terminal/command line:

`npm -v`

You should be able to see the version number, mine is `5.6.0` as I write this post.

### Install TestCafe

Now that we have `npm` installed, run the following command (This may require root/admin privileges):

`npm install -g testcafe`

To run this as a root/admin user, execute the same command in macOS or a linux based OS while also adding `sudo` at the beginning of the command above, and Windows users should `right click` and select `Run as administrator` when opening the `cmd` or `PowerShell`.

If everything went well, you should be able to see the version of your TestCafe module by running:

`testcafe -v`

The output should say something like:

```
Using locally installed version of TestCafe.
0.18.6
```

#### Great job! We are almost ready to start 👨‍💻 /👩‍💻.

## Choose your weapon (IDE/editor)

I'll be using [VS Code](https://code.visualstudio.com/download) as my weapon of choice + some extensions (I'll show them later, I'm also excited to start coding!) but feel free to choose whatever IDE/editor you prefer.

## Project Structure

Our initial project structure will look like this:

```
project
|
└─── tests
     │  
     └─── devto.js
```

### First test

The first thing we need to do is to `import` a class called `Selector` from the `testcafe` module, like this:

```js
import { Selector } from 'testcafe'
```

Then, we need to create a `fixture`, give it a name and the `page` url that will be used at the beginning of all your tests.

You will see where the name of the `fixture` is used later.

Now your code should look like:

```js
import { Selector } from 'testcafe'

fixture('DEV Tests')
    .page('http://dev.to/');
```

Now that we have this, let's start writing the code for our tests.

For simplicity, these will be the steps we will perform:

- Go to dev.to home page.
- Click on the About link.
- Check every founder's name.

## Back to the code-cave!

In order to do this we need to add a `test` method which takes two arguments: A `String` value which will be the name of the test and an `async` arrow function which will have the logic inside.

Something like:

```js
test("Check founder's names", async (t) => {
    // Brace yourself, the real magic goes here.
});
```

### Why do we use `async`?

This will allow us to run our tests in _parallel_ (which is awesome!) later on. But for now, we will run our tests in a single browser.

#### Where is the real magic at?

#### Why did we `import` the `Selector` class?

#### What does the fox say?

Ssssh... just let it happen.

We will get there :)

First thing we need to do is to get the about link's `selector`.

> A `selector` is basically a way to identify a element or group of elements on a page.

To acheive this, I'll use Chrome's built-in DevTools. Head over to the [dev.to](https://dev.to/) home page, scroll down and `right click` on top of the About link and select the `Inspect` option.

This will open up the DevTools options and you want to focus on the `<a>` HTML element highlighted.

On the DevTools panel, `right click` on the `<a>` of the About link and select `Copy > copy selector`. This will copy the `selector` value to your clipboard.

Now, go back to your editor and store that value like this:

```js
const aboutLink = Selector('#sidebar-wrapper-left > div.side-bar > div.widget > div.side-footer > a:nth-child(1)');
```

All the code should look like this now: 

```js
import { Selector } from 'testcafe'

fixture('DEV Tests')
    .page('http://dev.to/');

test("Check founder's names", async (t) => {
    const aboutLink = Selector('#sidebar-wrapper-left > div.side-bar > div.widget > div.side-footer > a:nth-child(1)');
});
```

## But wait!

Let's take this as a chance to use another _spell_ that TestCafe provides us with... the `.withText()` method.

We can write the same code like this:

```js
const aboutLink = Selector('a').withText('About');
```

The `.withText()` method takes a `String` `argument` and works similarly to the `.contains()` method you may be familiar with. It will compare the element's text value with the `argument` you pass in and only return `true` when the `argument` matches with any part of the given text value (note: it is case-sensitive); otherwise, it will return `false`.

> _Case-sensitive_ means that the capitalization of a letter makes it different from another, even if they sound the same. Example: "test" and "Test" are considered to be different in this case.

Let's head over to the About page to find the other `selector` values we will need to use.

We could do it the _copy-pasta_ way, and repeat all the steps we did with the DevTools, but we know we are better than that (or so we think). 

So, let's do it like we just learned. With the power of the `withText()` method.

The only difference is that this time our `selector` is not a `<a>` tag, it's actually a `<b>` tag. You can verify it by inspecting each of the founder's names or just trusting my word (I actually wouldn't).

Our code would look something like this now:

```js
const aboutLink = Selector('a').withText('About');
const firstFounder = Selector('b').withText('Ben Halpern');
const secondFounder = Selector('b').withText('Jesse Lee');
const thirdFounder = Selector('b').withText('Peter Frank');
```

Awesome!

If we look at the entire `devto.js` file, it should be:

```js
import { Selector } from 'testcafe'

fixture('DEV Tests')
    .page('http://dev.to/');

test("Check founder's names", async(t) => {
    const aboutLink = Selector('a').withText('About');
    const firstFounder = Selector('b').withText('Ben Halpern');
    const secondFounder = Selector('b').withText('Jesse Lee');
    const thirdFounder = Selector('b').withText('Peter Frank');
});
```

Now let's start using our new shiny selectors!

Did you forget what we were actually gonna do in our test?

Yeah, me too. But don't worry, I gotchu fam! 😎

- Go to dev.to home page.
- Click on the About link.
- Check every founder's name.

The `.page()` method already covers the first step, so we can mark that one.

[x] Go to dev.to home page.
[ ] Click on the About link.
[ ] Check every founder's name.

In order to click on the "About Link" we will need to add the following code at the end of our test:

```js
await t
    .click(aboutLink);
```

After that, we will have to check if every founder name header is displayed on the page:

```js
await t
    .click(aboutLink)
    .expect(firstFounder.exists).ok()
    .expect(secondFounder.exists).ok()
    .expect(thirdFounder.exists).ok();
```

Let's take a step back and verify that everything looks like this in our `devto.js`:

```js
import { Selector } from 'testcafe'

fixture('DEV Tests')
    .page('http://dev.to/');

test("Check founder's names", async(t) => {
    const aboutLink = Selector('a').withText('About');
    const firstFounder = Selector('b').withText('Ben Halpern');
    const secondFounder = Selector('b').withText('Jess Lee');
    const thirdFounder = Selector('b').withText('Peter Frank');

    await t
    .click(aboutLink)
    .expect(firstFounder.exists).ok()
    .expect(secondFounder.exists).ok()
    .expect(thirdFounder.exists).ok();
});
```
## Are you still there?

Well, I hope you do. Because now comes the _fun_ part!

## Run the test

In order to run the test you will need to make your way to the folder where your `devto.js` is located and run the following command:

`testcafe chrome devto.js`

> Note: you can replace `chrome` with your favorite browser.

Now aliens will take control over your computer and start doing crazy stuff... like running your test.

If everything went well, you should see something like this in your console:

```
Using locally installed version of TestCafe.
 Running tests in:
 - Chrome 63.0.3239 / Mac OS X 10.13.2

 DEV Tests
 ✓ Check founder's names


 1 passed (4s)
```

## Woof!

That was quite a lot of work!

But there are still more goodies to learn.

- Using multiple browsers at once.
- Running tests in parallel.
- Refactor our code to use Page Object Model design pattern.

### We can continue on the next part:

{% link https://dev.to/chrisvasqm/e2e-testing-with-testcafe--part-2-1lfg %}