Building The Most Powerful Test Recorder On The Market
Tags: webdev, testing, productivity
Published: 2020-02-21 15:09:14

---
title: Building The Most Powerful Test Recorder On The Market
published: true
description: Building the Endtest Chrome Extension
tags: webdev, testing, productivity
cover_image: https://dev-to-uploads.s3.amazonaws.com/i/txi92m0o6b77fyu3gpkn.png
---

###**Introduction**###
[Endtest](https://endtest.io) allows you to create, manage and execute Automated Tests, without having to write any code. 
 
You can use the [Endtest Chrome Extension](https://chrome.google.com/webstore/detail/endtest-codeless-automate/jbdgfkeimppmnfemmgfafiomihlibdfa) to record a test directly in the browser.

And yes, it's open-source and free to use. 🤗

This extension works by recording all the steps that a user performs in the browser and converts those steps into an automated test.

{% youtube cFboO4O5moU %}

###**1. How we record the steps**###

We record the following actions:
• Click
• Right Click
• Write Text
• Select option from dropdown
• Press Key
• Hover
• Scroll
• Open tab
• Close tab
• Switch to next tab
• Switch to previous tab
• Go back
• Go forward
• Access URL from navigation bar
• Entering an iframe
• Exiting an iframe
... and many more

Since we're talking about a Chrome extension, the only way to detect such events is through JavaScript and the [Chrome API](https://developer.chrome.com/extensions).

We used different JavaScript event listeners such as onclick, onchange, onkeyup, onmousemove, etc to figure out what the user does. 

It's important to distinguish between the different actions. 

For example, when a user is typing inside an input, you need to register that as a "Write Text" action. 

But when the user pressed the Enter key or the Escape key, you need to register that as a "Press Key" action.

The user has the option to enable or disable the detection of Hover and Scroll events, since they're not relevant in all situations. 

![Endtest Recorder Settings](https://dev-to-uploads.s3.amazonaws.com/i/mkv7pmp8q4qzvh9m58xe.png)

Even if a user enables the detection of Hover events, they will only be logged if the duration of Hover is above a certain number of miliseconds. 

This is done to avoid recording unnecessary Hover events when the user is simply moving the pointer.

The Chrome API is used to detect actions which cannot be detected with JavaScript, such as when the user is opening a new tab or switching focus to a different tab.


###**2. Getting the right permissions**###

Being able to record everything that a user does in the browser might sound like a job for the NSA.

Luckily, Chrome is smart enough to let you declare what permissions you need in the manifest.json file.

They also review those permissions when you publish the extension in the Chrome Web Store. 

And the user is informed about those permissions when installing the extension.

Here is what the permissions for our extension like:

```javascript
  "permissions": [
    "activeTab", "<all_urls>","cookies","storage","tabs","webNavigation"
  ],
```

###**3. Locating the elements**###

It's no secret that our engine for Web Tests is using Selenium.

That's why we need to fetch locators for the elements that the users interacts with. 

If we would rely on coordinates or image recognition, that would lead to brittle tests.


We fetch the following locators:
• ID
• Name
• CSS Selector
• XPath

Fetching the ID for an element might seem as simple as this:
```javascript
window.onclick = function(e) {
   the_id = e.target.id;
}
```

But there are plenty of tricky situations:
1. The element does not have an ID
2. Multiple elements share the same ID
3. The ID is generated dynamically and changes with each refresh

This means that we always check for uniqueness and we try to detect and avoid using IDs which are dynamic. 

The same rules apply for the Name attribute. 

CSS Selectors can be generated by using the using the attributes from an element and the parent nodes.

Let's take a look at this example:

```html
<html>
   <body>
      <div class="login-form">
         <input id="mat-input-6" type="text" placeholder="Email">
         <input id="mat-input-9" type="password" placeholder="Password">
      </div>
   </body>
</html>
```
We can easily spot that the IDs are dynamic, so we have to avoid them.

The basic CSS Selector for the Email input would look like this:

```javascript
body > div > input[type=text]:nth-child(1)
```

But we can easily construct something more reliable:
```javascript
input[placeholder="Email"]
```

Most people ditch XPaths for CSS Selectors, thinking that they're just as powerful, but slower. Big mistake.

XPaths have some hidden tricks up their sleeves. 

The XPath equivalent to the previous CSS Selector would look like this:
```xpath
//input[@placeholder = "Email"]
```

But here's a situation where XPath can save your life:

```html
<html>
   <body>
      <ul class="items">
         <li class="item">Apple</li>
         <li class="item">Orange</li>
         <li class="item">Banana</li>
      </ul>
   </body>
</html>
```

Let's try to fetch a locator for the Orange list item.

CSS Selectors do not have the ability to locate an element based on the text, but XPaths do. 

The XPath for the Orange list item is:
```xpath
//li[contains(text(),'Orange')]
```

We even offer advanced settings for detecting locators:

![Endtest Recorder](https://dev-to-uploads.s3.amazonaws.com/i/rbgoqzwq7c5yvmq0ghz6.png)

Using classes in CSS Selectors and XPaths can also be tricky, since they can only appear in the element when you click on it. 

Let's take a look at this example:
```html
<html>
   <body>
      <div class="container">
         <input type="button" class="login-form">
      </div>
   </body>
</html>
```
We want to locate the input type="button" element. 

But when we click on that input, it gets 2 extra classes:
```html
<html>
   <body>
      <div class="container">
         <input type="button" class="login-form active focus">
      </div>
   </body>
</html>
```
Since we're recording the event at the moment of the click, our Chrome Extension would record the element as having 2 extra classes.

If this would happen, our engine would throw an "Element not found" error when the test would be executed, since those 2 extra classes are not appended if the element isn't clicked. 

That's why allow the users to have a list of classes that our Chrome Extension can simply ignore:

![Endtest Chrome Extension Classes](https://dev-to-uploads.s3.amazonaws.com/i/yp5r7qd97ey8qlul4c05.png)

###**4. Going the extra mile**###

We always make sure our users get the best experience.

Steps for taking screenshots and adding assertions can be added directly from the recorder. 

The recording process can also be paused and resumed.

![Endtest Recorder](https://dev-to-uploads.s3.amazonaws.com/i/yw4s98e8be0hohdfbzfy.png)

You can find more details in our [Documentation](https://endtest.io/guides/docs/how-to-create-web-tests/)

###**Q&A**###

####**1. Why do we also offer a cross-browser cloud infrastructure?**####

We take testing very seriously.

That's why our cloud platform offers real browsers on Windows and macOS machines and mobile devices. 

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/cx4qm6rde0hduxi5e4vv.png)

We encourage developers to avoid using headless browsers on Linux machines for their automated tests, since those browsers do not have the same behavior as the real browsers used by users.


####**2. Why record the tests with JavaScript and execute them with Selenium?**####

Since our recorder had to be a Chrome extension, we had no other choice than to use JavaScript.

Our engine for Web Tests is using Selenium, because it's open-source, constantly improved, mimics real user behavior and it works with all the major browsers.

We advise developers to avoid using JavaScript-based libraries for executing automated tests in the UI, since those libraries have severe limitations and do not mimic real user behavior. 

For example, a JavaScript-based library for testing the UI can easily click on an element which is completely covered by another element. 
A real user and a Selenium test cannot do that.

A JavaScript library for testing the UI cannot perform file uploads, cannot manage iframes and cannot manage multiple browser tabs. 

Currently, there isn't any JavaScript library for UI testing that works on all the major browsers and devices.