Homewrecker February 2016

Protractor element handling

I have a question regarding how protractor handles the locating of elements. I am using page-objects just like I did in Webdriver. The big difference with Webdriver is that locating the element only happens when a function is called on that element.

When using page-objects, it is advised to instantiate your objects before your tests. But then I was wondering, if you instantiate your object and the page changes, what happens to the state of the elements?

I shall demonstrate with an example

  it('Change service', function() {
      servicePage.clickChangeService();
      serviceForm.selectService(1);
      serviceForm.save();

      expect(servicePage.getService()).toMatch('\bNo service\b');
  });

When debugging servicePage.getService() returns undefined. Is this because serviceForm is another page and the state of servicePage has been changed?

This is my pageobject:

var servicePage = function() { 
  this.changeServiceLink = element(by.id('serviceLink')); 
  this.service = element(by.id('service'));

  this.clickChangeService = function() { 
    this.changeServiceLink.click(); 
  };

this.getService = function() { 
  return this.service.getAttribute('value'); 
}; 
}; 
module.exports = servicePage;

Thank you in advance. Regards

Answers


ktom February 2016

When you navigate another page, the web elements will be clear, that you selected. So you have to select again. You can select all elements that is in a page of HTML. You can click that you see. So the protactor + Selenium can decide what is displayed.

You have a mistake in your code, try this:

 expect(servicePage.getService()).toMatch('\bNo service\b');


martin770 February 2016

Essentially, element() is an 'elementFinder' which doesn't do any work unless you call some action like getAttribute().

So you can think of element(by.id('service')) as a placeholder.

When you want to actually find the element and do some action, then you combine it like element(by.id('service')).getAttribute('value'), but this in itself isn't the value that you are looking for, it's a promise to get the value. You can read all about how to deal with promises elsewhere.

The other thing that protractor does specifically is to patch in a waitForAngular() when it applies an action so that it will wait for any outstanding http calls and timeouts before actually going out to find the element and apply the action. So when you call .getAttribute() it really looks like

return browser.waitForAngular().then(function() { 
    return element(by.id('service')).getAttribute('value');
 });

So, in your example, if your angular pages aren't set up correctly or depending on the controls you are using, you might be trying to get the value before the page has settled with the new value in the element.

To debug your example you should be doing something like

it('Change service', function() {
    servicePage.getService().then(function(originalService) {
        console.log('originalService: ' + originalService);
    });

    servicePage.clickChangeService();
    serviceForm.selectService(1);
    serviceForm.save();

    servicePage.getService().then(function(newService) {
        console.log('newService: ' + newService);
    });

    expect(servicePage.getService()).toMatch('\bNo service\b');
});

The other thing that I'm seeing is that your pageObject appears to be a constructor when you could just use an object instead:

// name this file servicePage.js, and use as 'var servicePage = require('. 

Post Status

Asked in February 2016
Viewed 2,810 times
Voted 13
Answered 2 times

Search




Leave an answer