Sunday, July 27, 2025

Reqnroll (Specflow) in Gherkin

Reqnroll (pronounced as [reknroĘŠl]) is an open-source Cucumber-style BDD test automation framework for .NET. It has been created as a reboot of the SpecFlow project. Reqnroll enables writing executable specifications for BDD using Gherkin, the widely-accepted feature file specification format.

Saturday, April 27, 2024

Thursday, April 4, 2019

How to use Protractor elementExplorer for simple debugging

The elementExplorer is a good tool to debug Protractor scripts. You need to have an appropriate Protractor version and npm version for this, because the newest versions are not supported.

First of all, check the version of npm installed in your system:

nvm list







The highest version of npm must be 6.11.0. If it is not the case, you have to choose this one:

nvm use 6.11.0

If you don't have nvm, you may download from here:

https://app.box.com/s/of2zldgjfpjjbggch3bknzshdh6fx1om

Second, check the version of Protractor:

protractor --version

It must be not higher than 5.4.2. If it is not the case, you may do the following:

npm -g install protractor@5.4.2
webdriver-manager update

There are two ways to start elementExplorer:

1. protractor --elementExplorer
2. node <..>/npm/node_modules/protractor/bin/elementexplorer.js

I prefer the second one because it is then possible to repeat your commands you typed by means of using arrows Up and Down.
 

Wednesday, March 20, 2019

How to use Azure pipeline variables in Protractor automatic tests

Nowadays Microsoft Azure DevOps is very popular for Software development with the Agile way of working.

Protractor (with Selenium) is widely used for UI automation testing. It is useful to add flexibility to the Protractor test setup. You can find a blog: here.

However, the module.exports in that blog does not work for me, maybe because of the fact that I use exports.config, as follows:

exports.config = {
  framework: 'jasmine2',
  SELENIUM_PROMISE_MANAGER: false,
  suites: {
    newStyle: [
      'spec1.js',
    ],
  },

The parameter block can be added inside the exports.config,

  params: {
    login: {
      user: 'default',
      password: 'default'
    }
  }

In the spec file, the params can be used as follows, e.g.

let usr =browser.params.login.user; 
let pw = browser.params.login.password; 

Locally, you may run the Protractor tests by using the command line,

Protractor conf_*.js --params.login.user=someUserName --params.login.password=somePassword

The values of default are replaced by "someUserName" and "somePassword" in the runtime.

It works fine! If you use npm module combined with the Azure DevOps, then the relevant part of the package.json looks like as follows:

 "test": "protractor conf*.js --suite newStyle --params.login.user=__UserNameUITest__ --params.login.password=__PasswordUITest__",



Where the __UserNameUITest__, and __PasswordUITest__ are the tokens variables, which have to be replaced by the pipeline variables.

Then in the pipeline, you can just use:

 npm run test 

Last but not least, before this works you need to define two pipeline variables:

UserNameUITest          someUserName (shown as ****** ) and

PasswordUITest           somePassword (shown as ******), using the lock. 

 --- End of blog ----

Monday, October 31, 2016

Passing Command Line Parameters to a Autohotkey Script

Autohotkey is een scripting language designed for Test Automation. It is easy to use and the programs created are often very compact/light-weight. More info: http://ahkscript.org/

Between two or more scripts,  command line parameters may be passed among them, like this:







the '0' is the number of parameters!
(used in a if closure!)



the number of parameters, values of the 4 parameters

This script will be called by another script shown as below:






Run the script callPara.ahk (or callPara.exe) will show the following results:
- Starting ...
- got 4, a, b, c, 20000

If we call paraTest.exe %p1% %p2%, we will get the following answer:
- Starting ...
- needed at least 3 params, got 2

Please note: in a If closure, it must not contain ( ), otherwise it will not work:

if (0 < 3)  will always be true!

In the meantime, in a If closure with more conditions, the paramter must be at most left side:

line = blabla
if( line) and 0<3   ;will not work

if 0<3 and (line)   ;seems to work, but not reliable! (a bug?)

It is safe to use nested If closures:

if 0<3
    if(line)
        ;do something

Similarly, you may use '1', '2' or any other nubmer to replace '0',
if 1<3
    msgbox the first paramter is less than 3: %1%
if 2<3
    msgbox the second paramter is less than 3: %2%

When compared to a variable, like i = 3, then it must use %i% in the If closure,

i=3
if 3<%i%
    msgbox the third paramter is less than %i%: %3%

More info: See Passing Command Line Parameters to a Script 

Friday, October 28, 2016

Using Protractor in a loop by means of Closure function or .filter()

All functions of Protrator return only promises that are hard to use in a loop. For example,
var els = element.all(by.css('selector'));
for (var i = 0; i < 3; ++i) {
  els.get(i).getText().then(function(text) {
    if (text === 'should click') {
      els.get(i).click(); //Index out of bound. Trying to access element at index:3, but there are only 3 elements"
    }
  })
}
The index i takes the values of 0, 1 and 2 and no code inside the .then() block is executed. It will be executed when i = 3 causing the error of Index out of bound!
There are two solutions to such a problem:
1. Using Closure function for the promise in a loop
var els = element.all(by.css('selector'));
function closureFunc(i){
  return function(text){
    if (text === 'should click') {
       els.get(i).click(); // i should take 0, 1 and 2
    }
  };
} 

for (var i = 0; i < 3; ++i) {
  els.get(i).getText().then(closureFunc(i));
}
2. Using the method .filter() of Protrator to avoind using .then() in a loop
var els = element.all(by.css('selector'));
els.filter(function(elem) {
  return elem.getText().then(function(text) {
    return text === 'should click';
  });
}).click(); 
// note here we first used a 'filter' to select the appropriate elements, 
// and used the fact that actions like `click` can act on an array to click all matching elements.

Tuesday, October 25, 2016

How to use Jasmine for Protractor

Jasmine is essential for Protractor test. The testscripts of Protractor are in the style of Jasmine. Google has modified the speccial expect() function of Jasmine to work with promises. All functions of Protractor return only promises!

The expect() function is usually used to resolve the returned promises of Protractor for testing. When not using the expect() function, You have to resolve the returned promises first through the so-called then() function!

In summary, Protractor uses the same syntaxes and styles of Jasmine, like this:
describe('Angular App Test suite 1 -', function() {
  it('Testcase 1: should do xx job', function() {
    browser.get('');
    expect(element(by.xxx).getText()).toEqual(2);
    ...
    ...
  });
 
  it('Testcase 2: should do xxx job', function() {
    ...
    ...
  });
});
 
describe('Angular App Test suite 2 -', function() {
  it('Testcase 1: should do xx job', function() {
    browser.get('');
    expect(element(by.xxx).getText()).toEqual(2);
    ...
    ...
  });
 
  it('Testcase 2: should do xxx job', function() {
    ...
    ...
  });
});
I don't know "/some/some" comes from! (a bug in blogger self?)

Monday, October 24, 2016

How to use promise method .then() in Protractor

The hardest part of testing Angular apps using Protractor is promise! Protractor returns no other values than only promises So you may not use the returned value from webdriverJS unless you use .then() method to resolve them first. For example:

var rows = element.all(by.repeater('row in tabledata.display.body'));

You can only use the method expect() to check the value:

expect( rows.count()).toEqual(4);

But you cannot use the value '4' for e.g. in a loop! You have to use the so-called .then() method of promise to resolve, like this:
var rows = element.all(by.repeater('row in tabledata.display.body'));

rows.count().then( function(nrRows) { //nrRows=rows.count()

for(var i=0; i<nrRows; i++){
// do somthing with your loop
  }
})
If you need more than one value, then you may nest the .then() method, like this:
var rows = element.all(by.repeater('row in tabledata.display.body'));

var cells = element.all(by.repeater('cel in row'));

row.count().then( function(nrRows) {      //nrRows=rows.count()

  cells.count().then( function(nrCells){  //nrCells=cells.count()

    for (var i=0; i<nrRows; i++){
       // do something with your loop
    }
    // call a function using nrRows and nrCells

    if( nrRows > 0){
      func(nrRows, nrCells);
    }
    else{
      console.log('No rows in the table!');
    }

  })
})
You may use the method .all() to simplify the code, like this:
var rows = element.all(by.repeater('row in tabledata.display.body'));
 
var cells = element.all(by.repeater('cel in row'));
 
q.all([row.count(), cells.count()]).spread(function(nrRows, nrCells){
 
    for (var i=0; i<nrRows; i++){
       // do something with your loop
    }
    // call a function using nrRows and nrCells
 
    if( nrRows > 0){
      func(nrRows, nrCells);
    }
    else{
      console.log('No rows in the table!');
    }
})
Some similar ideas can be found here.
--- End of blog ---