Saturday 2 January 2016

Test Data - Handling multiple test environments using configuration and conventions

Create a config,js for each environment and include a global parameter identifying the environment.


exports.config = {
   
seleniumAddress: 'http://127.0.0.1:4444/wd/hub',

   
baseUrl: '',

   
params: {
       
environment: 'sys'
    },


...

}

When running protractor you will include this config.js in the runtime parameters. So you can call protractor with different config.js files for each environment while running the same tests.

I use a function in a library which will look for a data file named the same as the spec file with -data appended before the .js extension. It also uses the above parameter to identify the correct data file for the environment I'm running my tests in.

If I have the spec file I will have a data file to go with it (convention).


  • smoketest-spec.js
  • smoketest-sys-data.js

Datafile as a Module:

Function to locate Data File:

function assignDataFile (inFile) {
    var temp = inFile.split'.js' );
    var outFile temp[0] + "-" browser.params.environment "-data.js";
    console.log("Using the data file: " + outFile );
    var DataFile = require ( outFile );
    return (new DataFile ());
}

Datafile:

module.exports = function() {
   
this.shoppingItem1 = "Toothbrush"
;
}


Datafile as JSON:

Function to locate Data File:

function assignDataFile (inFile) {
    var temp = inFile.split'.js' );
    var outFile temp[0] + "-" browser.params.environment "-data.js";
    console.log("Using the data file: " + outFile );
    var DataFile = require ( outFile );
    return (DataFile);
}

Datafile:

{
   
"
shoppingItem1": "Toothbrush"
}

Using the Data:

I then just call the above function at the start of each spec.

var testData actions.assignDataFile ( __filename );

So I am then able to refer to my test data within the spec like this:

element(by.cssContainingText('option', testData.shoppingItem1);

The above example selects 'Toothbrush' from a drop down and assumes there is only one drop down on the page and that the strings match exactly.

Commentary:

I prefer to use a module for the data file. Not sure why, I think I just picked that first as I had no previous experience with JSON files. I like the way I can require other files inside the module and create tiered data as well as reuse data across multiple environments and manage that in one place. Also being able to use date functions, moment.js etc for test data.

module.exports = function() {
    //Generic test data (ie today, tomorrow and yesterday)
    var DataHelper = require ( './dataHelper.js' );
    var dataHelper = new DataHelper () ;

    this.cartName = "Automated test -> " + dataHelper.today; 
    this.shoppingItem1 "Toothbrush";
}



Friday 1 January 2016

Save text from an element to a variable to reuse later


This post is my first post and covers something that I needed to solve the first day I started using Protractor.

Take this bit of HTML code below. Perhaps I want to get the value inside the SPAN to store for reuse.

<html>
    <head>
        <title>Example Page</title>
    </head>

    <body>
        <span id='name'>Ferris Beuller</span>
    </body>
</html>

My first attempt resulted in something like this.


var reusuableVariable = null;
reusuableVariable = pages.dashboard.greeting.getText();
console.log(reusuableVariable);

That did not work. I ended up with something like this (partial extract); 
{ ptor_: 
   { controlFlow: [Function],
     schedule: [Function],
     getSession: [Function],
     getCapabilities: [Function],
     quit: [Function],
     actions: [Function],

     executeScript: [Function], ...

I knew enough to tell myself that looks like an object being printed out... So off to Stackoverflow.
It didn't take too long to find a post which solved my problem.

var reusuableVariable = null;

element(by.id('name')).getText().then(function(text) {
    console.log('Getting the text');
    reusuableVariable = text;  
});
console.log(reusuableVariable);

This didn't seem to work. The console would output:
null
Getting the text

You may notice that the first thing that is output to the console is null. 

Perhaps you expected 'Getting the text' first, if so remember that Protractor runs on Node.Js and is asynchronous.

Therefore the element(by.id('name')).getText() returns a promise then execution continues to console.log(reuseableVariable); and as the promise has not been fulfilled yet the variable is still set to null.

Using Protractor we do know that the promises will be managed and processed in order. So if we make use of this we can reuse variables inside callbacks later in the script. In these scripts the callback is the argument given to the .then function which is executed when Protractor locates the element.

var reusuableVariable = null;

element(by.id('name')).getText().then(function(text) {

    console.log('Getting the text');
    reusuableVariable = text;
});

element(by.binding('vm.name')).getText().then(function(text) {

    console.log('Re-using the text')
    console.log(reusuableVariable);
});


Output
Getting the text
Re-using the text
Ferris Beuller

You can extend this further by reusing variables between jasmine describe and it functions. Just remember to scope your variable declaration appropriately so it can be seen in the places you want to reuse it.