Archive

Archive for the ‘Programming, QA, Test and Automation Stuffs’ Category

Build a docker image for your protractor automation

Hey guys, today I will post about an example of Docker file where you can run your protractor automation in a Docker container on firefox and chrome.

You will need to have the known hosts and the public key from github to be able to clone the repository and run the automation. Also you need to install java to be able to run the selenium server in your docker container.

Create an empty file in your project and paste these instructions:

Docker file

FROM node

WORKDIR /tmp

#Install required applications

RUN echo 'deb http://httpredir.debian.org/debian jessie-backports main' >> /etc/apt/sources.list.d/jessie-backports.list

RUN apt-get update && \
apt install -y -t jessie-backports openjdk-8-jre-headless ca-certificates-java && \
apt-get install -y xvfb wget openjdk-8-jre && \
wget https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb && \
dpkg --unpack google-chrome-stable_current_amd64.deb && \
apt-get install -f -y && \
apt-get clean && \
rm google-chrome-stable_current_amd64.deb && \
apt-get install -y pkg-mozilla-archive-keyring

ENV JAVA_HOME /usr/lib/jvm/java-8-openjdk-amd64/
RUN export JAVA_HOME

#Install Firefox on Linux
RUN touch /etc/apt/sources.list.d/debian-mozilla.list
RUN echo "deb http://mozilla.debian.net/ jessie-backports firefox-release" >> /etc/apt/sources.list.d/debian-mozilla.list
RUN wget mozilla.debian.net/pkg-mozilla-archive-keyring_1.1_all.deb
RUN dpkg -i pkg-mozilla-archive-keyring_1.1_all.deb
RUN apt-get update && apt-get install -y -t jessie-backports firefox

#Creating user
RUN useradd -ms /bin/bash admin

# Copy key for github for user admin
ADD id_rsa /home/ci_box/.ssh/id_rsa
ADD known_hosts /home/ci_box/.ssh/known_hosts

ADD id_rsa /home/ci_box/.ssh/id_rsa
RUN chmod 700 /home/ci_box/.ssh/id_rsa; chown -R admin:staff /home/ci_box/.ssh
ADD known_hosts /home/ci_box/.ssh/known_hosts

#Changing user
USER admin

#To avoid conflicts with host machine dbus
ENV DBUS_SESSION_BUS_ADDRESS=/dev/null

#Copying script which will clone repository
WORKDIR /home/admin/workspace
ADD docker.sh ./docker.sh

#Open the bash
CMD ["/bin/bash"]

 

Script to clone the branch

#!/bin/bash

#Branch and repository
BRANCH=$1
REPOSITORY
=$2

#Clone the repository

git clone -b ${BRANCH} rsouza@github.com:azevedorafaela/${REPOSITORY}.git
cd ${REPOSITORY}

#Script to run your automation

./tests.sh ${BRANCH}

 

Script to run the tests

#!/bin/bash
set -e

#Starting dbus daemon and exporting related environmental variables
export $(dbus-launch)

#Starting X server to be able to run firefox
Xvfb :1 -screen 0 1200x800x24 &

# Clean the target with reports
rm -rf target

# Install all dependencies
npm install

# Run tests
DISPLAY=:1.0 npm run regression

 

Build the image in the folder that contains the docker file

docker build -t rafazzevedo/test .

 

Push the image to your account

docker login
docker push rafazzevedo/test

 

Run the automation in the container:

docker run --name=test rafazzevedo/test:latest /home/admin/docker.sh master regression

 

See you guys soon !

Cucumber report with protractor tests

Hi guys, today I will show what you can do with the module cucumber-html-report that I am currently using in my protractor automated tests.

So, it is a node library that reads the Json reports and convert them into a nice html report. It should show the coverage of your scenarios and if you want you can have pictures attached as well.
I am pasting here some snippets that you guys can use and customise as you want.
To install you need to add the cucumber-html-report in your dependencies like:
{
    "name": "Rafazzevedo",
    "version": "1.0.0",
    "description": "Rafazzevedo",
    "private": true,
    "dependencies": {
        "cucumber-html-reporter": "^0.4.0",
        "protractor": "^5.1.1"
    },

    "devDependencies": {
        "chai": "^3.5.0",
        "chai-as-promised": "^6.0.0",
        "chai-string": "^1.3.0",
        "cucumber": "^1.3.2",
        "protractor-cucumber-framework": "^1.0.2"
    }
}
Then you create an After in your Hooks class and Add the creation of the report:
import { browser } from 'protractor';
import reporter from 'cucumber-html-reporter';
import _ from 'lodash';
import Navigation from './helpers/navigation';

const API = automation.API;

const Hooks = function () {
    const api = new API(browser.params);
    const navigation = new Navigation(browser);
    const credentials = browser.params.credentials;

    this.registerHandler('BeforeFeatures', () => {
        api.authenticate(credentials);
        browser.api = api;
        browser.navigation = navigation;
        browser.get(browser.baseUrl);
    });
    this.registerHandler('AfterFeatures', () => {
        browser.getProcessedConfig().then((config) => {
            const jsonFile = config.capabilities.cucumberReportPath;
            browser.getCapabilities().then((capabilities) => {
                const reportName = createReportName
(config.capabilities, capabilities);
                const htmlFile = jsonFile.replace('.json', '.html');
                const options = {
                    name: `Automation (${reportName})`,
                    theme: 'bootstrap',
                    jsonFile,
                    output: htmlFile,
                    reportSuiteAsScenarios: true,
                };
                reporter.generate(options);
            });
        });
    });
    function createReportName(configCapabilities, browserCapabilities) {
        const browserName = configCapabilities.browserName;
        let deviceName = 'desktop';
        let browserVersion = '';
        if (!_.isUndefined(configCapabilities.chromeOptions)) {
            browserVersion = ` ${browserCapabilities.get('version')}`;
            if (!_.isUndefined(
configCapabilities.chromeOptions.mobileEmulation)) {
                deviceName = configCapabilities.chromeOptions.
mobileEmulation.deviceName;
            }
        }
        return `${browserName} ${deviceName}${browserVersion}`;
    }
};

module.exports = Hooks;
After adding these 2 functions about creating the report for multiple browsers and adding the version and the device name (desktop or mobile) in the report, you can add pictures in case of the scenario fails:
this.After((scenario) => {
        if (scenario.isFailed()) return browser.takeScreenshot().
then(screenshot => scenario.attach(new 
Buffer (screenshot, 'base64'), 'image/png'));
    });
 
You can always customise and improve the functions, if you feel that you need a picture after all the scenarios even they passed, you can just remove the condition in the after. Also you have different available themes and other options on https://www.npmjs.com/package/cucumber-html-reporter
See you guys !

Avoiding false positives with Protractor and Javascript

Do you have false positives when automating with protractor ?

Asynchronous code can be really annoying sometimes, callback pyramids, error handling on every second line, promises swallowing errors by default…

When using ES6 promises any exception which is thrown within a then or a catch handler, will be silently disposed of unless manually handled.

If you are not getting the errors, you are probably coding the promise something like this:

Promise.resolve('promised value').then(function() {
 throw new Error('error'); 
});

Then the more obvious way  to print the error is adding a catch after the promise:

Promise.resolve('promised value').then(function() {
 throw new Error('error'); 
}).catch(function(error) {
 console.error(error.stack); 
});

Remember that you need to add this after all the promises you want to print the error. Do you really think this is reliable ? Are you going to repeat yourself adding a catch after all the promises ?

So, how can you print the error without need to repeat yourself when creating a promise ? You can use .done instead of .then. This will run the promise and after print the error that you want.

Here is how you can avoid them:

Promise.resolve('promised value').done(function() {
 throw new Error('error');
 });

But what do you do when you chain multiple thens ?

There is a library called Bluebird which has a fix integrating your existing code by extending the ES6 Promises API. You can make sure you know about unhandled rejections, so no more false positives.

Promise.onPossiblyUnhandledRejection(function(error){
 throw error; 
});

Then if you want to discard an exception not because it is been swallowed, but you don’t need to print it, you can do something like this:

Promise.reject('error value').catch(function() {
});

 

Webinar: Using Espresso for Fast and Reliable Feedback

How to test angular and non angular pages with protractor

February 13, 2017 Leave a comment

As you know Protractor is known as the best compatible automation framework for angular sites, since it awaits for angular to do his work and you don’t need to use waits methods. But what if you have an angular site that has some non angular pages ? How can you proceed ?

 

Protractor provides the means to test angularjs and non angularjs out of the box. The DSL is not the same for angular and non angular sites.

AngularJS:

element.find(By.model('details'))

The element keyword is exposed via the global, so you can use in any js file without need to require it. You can check on your runner.js that you are exporting all the necessary keywords.

// Export protractor to the global namespace to be used in tests.
    global.protractor = protractor;
    global.browser = browser;
    global.$ = browser.$;
    global.$$ = browser.$$;
    global.element = browser.element;

 

NonAngularJS: You may access the wrapped webDriver instance directly by using browser.driver.

browser.driver.find(By.model('details'))

You can also create an alias for this browser.driver. This will allow you to use elem.find(by.css(‘.details’)) instead of using browser.driver. for example:

onPrepare: function(){
      global.elem = browser.driver;
      }

So, how can you use the same DSL for non-angular and angular pages ? You will need to ignore the sync, keep in mind that once you set this value, it will run for the entire suite. This will allow you to start using the same DSL.

onPrepare:function(){
   global.isAngularSite = function(flag) {
     browser.ignoreSynchronization = !flag;
   };
}

You can add a Before for each angular/non angular scenario, you just need to tag each scenario indicating which one will run on an angular page, example:

 this.Before({tags: ['~@angular'] },
function(features, callback) {
   isAngularSite(false);
   callback();
 });

 this.Before({tags: ['@angular'] },
function(features, callback) {
   isAngularSite(true);
   callback();
 });

 

Hope this helps you guys !

Docker – Courses

January 15, 2017 Leave a comment

Hey guys, today I will post a link for you that are interested to learn docker. You can register yourself and follow the steps. It is really easy to understand all the usage and how to create/run containers.

 

But why should I use Docker ?

Remember when you need to create all your data before you run your automated tests ? So, with Docker you don’t need to code this part anymore, you just need to build an image automatically with all the basic data you need for the tests.

If your tests are creating the data upfront via API, you won’t be able to test this part anymore. But now your tests will be focused on the main goal of your project. Also, you will avoid all the data creation instability issues.

For instance, let’s say you have an UI automation and you need to create some users as a prerequisite to test the sort of those users. You will save time not coding this part, not waiting for the server response, so the test will be independent from the API calls and more focused, you will save time while executing, your repository is kept up-to-date with code changes automatically.

Give it a try: training.docker.com/category/self-paced-online

Thank you guys !

How to deal with data tables in Cucumber and Protractor

November 28, 2016 Leave a comment

 

So, today I will give a code snippet about how to deal with Cucumber data tables and protractor.

Following the example:

 

  • Scenario with data table:
 Scenario: Register multiple users from different countries
   Given I want to register multiple users
    | user  | country  |
    | nicko | uk       |
    | pitty | brazil   |
    | slash | us       |
   When I send the form
   Then all the users should be registered

 

Remember to create the data table with the headers. Don’t forget that data tables are different from examples, here the first step will create a hash table with the data from the table and send it as parameter. Examples are used to run the same scenario with different variables in each run.

 

  • Related Step Definitions:
'use strict';

var protractor = require('protractor');
var browser = protractor.browser;
var _ = require('lodash');
var Q = require('q');

var RegisterPageSteps = function() {

 this.Given(/^I want to register multiple users$/, function(data) {
    var promises = [];
    var rows = data.hashes();
    //For each row you will get the user and the country
    _.each(rows, function(row) {
       var user = row.user;
       var country = row.country;

       //Here you can add the promises to perform sequentially
       //you can call the promises passing the user and the 
       //country as parameters
       promises.push((addUserCountry(user, country));
    });

    //You can also have promises to be performed that don't need
    //the parameters from the data table
    promises.push(navigateToSubmit());

    //Here you return all the promises
    return Q.all(promises);
  });

 this.When(/^I send the form$/, function(callback) {
    callback();
 });

 this.Then(/^all the users should be registered$/, function(callback) {
    callback();
 });

};

module.exports = RegisterPageSteps;

 

I have not implemented other functions and steps as the aim here is to show how to deal with the data table in your scenario.

Thank you !

%d bloggers like this: