DEV Community


Posted on

Automation E2E Testing in Angular with Protractor

This week I dove into automated testing with Protractor. Since building a branch fails a lot lately with timeouts and other issues, I am gonna to try to find out more and fix this.

What is automated testing.

Automated testing makes life easier once it is set up correctly and useful :) Automated testing uses software/tooling to test code fast. You set up testcases and those are executed through the tooling. No human interaction to test is required after you wrote those cases. It can compare, execute an enter data through the tests.

The most common tests and their differences.

The two most common test methods I ran into so far are Unit testing and E2E testing.

Unit testing

Unit testing is focused on testing single units. Think about this like a function or a small part of code. You mock(fake) services, network and other resources and do all the testing isolated.
In Angular Karma and Jasmine framework are mostly used to write unit tests.

E2E testing

With e2e testing you can go through the GUI like a user does. Clicking buttons, pages, menu's,CRUD. (not in production)
Most common use for E2E testing with Angular is Selenium web-driver with Protractor.
So for testing your code it is useful to use unit tests. If you want to test functional use of your site then you should try E2E.

Why test?

The purpose is to encounter problems fast. For E2E testing: Also you don't want to test by clicking though screens to see if a button still works or a page loads by yourself. That would be a lot of work and is not consistent if it would be done by different developers.

Setting up Protractor.

How to install protractor.

To install protractor you run the following from the command-line:
You install protractor by running:

npm install -g protractor

Then you install webdriver manager for selenium.

webdriver-manager update

webdriver-manager start

Build a test.

First you need two files to create a test, a spec file and config file.
In the config file you configure the location of the spec files. It also contains the browser that you want to use to test, default is Chrome. The the selenium serveraddress is in included to communicate. And also the framework is set, this is Jasmine. Then it looks something like this:

 // conf.js
exports.config = {
  framework: 'jasmine',
  seleniumAddress: 'http://localhost:4444/wd/hub',
  specs: ['yourtest.spec.ts']

To build a test you have to determine a case. You build the case in the spec file. First you determine what the the test must do. In this case you check if your landing page displays the welcome message.

describe('Landing page', () => {
let page: YourApp

beforeEach(() => {
    page = new YourApp()

 it('should display welcome message', () => {

First you describe the page or element you want to test, in this example it is the landing page. Describe is the name of the testsuite and Jasmine syntax.It contains the flow from end to end. Within this are 'it' testcases.
Then you determine what 'it' needs to do. 'It' is a global function from Jasmine. You can have multiple 'it' testcases in the flow.(describe)
In this case you check if the landing page had got the welcome message displayed and therefore is available as expected. (true, toBeThruthy) You also check if the text is the same as the text on the landing page ( toEqual('yourText')

Async Await.

JavaScript is asynchronous, you don't know what script is gonna execute first. Protractor flows are synchronous, your steps are in a specific order of execution. Click this, then that button.
Protractor flows are written with a promise. Protractor can handle the promise with a wait until it is complete.

The syntax of async await is much like the TypeScript syntax.
The asynchronous function can be wrapped with 'async' and 'await'.
Await is used before the line that we want to wait for.

describe('Landing page', () => {
let page: YourApp

beforeEach(() => {
    page = new YourApp()

 it('should display welcome message',async () => {
    expect(await page.containsElement('#welcome')).toBeTruthy()
    expect(await page.getElementText('#welcome')).toEqual('Welcome')

What was the main problem with my builds?

My tests failed a lot with timeouts. I used async await and still had some issues. As you can see, the syntax is almost the same with TypeScript async/await.

I found this on the site.

Don’t forget to turn off control_flow, you cannot use a mix of async/await and the control flow: async/await causes the control flow to become unreliable (see github issue). So if you async/await anywhere in a spec, you should use the SELENIUM_PROMISE_MANAGER: false

I added this to the config and debugged the left over errors.
I build in some wait/sleep time between some tests and it runs fine.

Top comments (2)

jahrenski profile image

Thanks so much for this I've banged my head on the wall for a full day before reading this article!

francisca80s profile image

That is so great to hear, thank you!