ebsk
ebsk

Reputation: 85

Protractor ElementFinder/ElementArrayFinder understanding

Learning AngularJS from a book and there was an example of simple Protractor test:

    it('Should redirect to #/posts/1/sample-title1', function () {
        var posts = element.all(by.repeater('post in posts'));
        posts.first().then(function (postElem) {
            postElem.findElement(by.tagName('a')).then(function (a) {
                a.click(); 
                expect(protractor.getCurrentUrl()).toMatch('/posts/1/sample-title1');
            });
        });
    });

It didn't work and threw an error: Failed: undefined is not a function

Not sure what was wrong, dig into the Protractor documentation and figured out a solution that work, which is:

it('Should redirect to #/posts/1/sample-title1', function () {
    var link = element.all(by.repeater('post in posts')).first().element(by.tagName('a'));
    link.click();
    expect(browser.getCurrentUrl()).toMatch('/posts/1/sample-title1');
  });
});

I'm happy that it works, however I don't quite understand why it work, still the documentation isn't very helpful here (or I'm just too tired at the moment).

Seems that I don't understand the difference between .findElement and .element

When I change the line:

var link = element.all(by.repeater('post in posts')).first().element(by.tagName('a'));

To:

var link = element.all(by.repeater('post in posts')).first().getWebElement().findElement(by.tagName('a'));

It also works, however it doesn't work when it's:

var link = element.all(by.repeater('post in posts')).first().findElement(by.tagName('a'));

Can someone explain this ? Thanks in advance !

Upvotes: 1

Views: 4354

Answers (2)

giri-sh
giri-sh

Reputation: 6962

There are differences to each of those functions. In your first case you got an error: Failed: undefined is not a function because the usage of .first() was incorrect. first() function returns an ElementFinder and not a promise.

  • This means that there is no promise to be resolved on it using .then().
  • You can chain it with other ElementFinder dependent operations like element(), $$, getText(), etc.

Next, the lines that you wrote -

var link1 = element.all(by.repeater('post in posts')).first().element(by.tagName('a'));
var link2 = element.all(by.repeater('post in posts')).first().getWebElement().findElement(by.tagName('a'));
var link3 = element.all(by.repeater('post in posts')).first().findElement(by.tagName('a'));

Explanation -

  1. .findElement() works on top of two instances, one is an element and the other one is a browser or driver.

    • link1 works because it has an element() (which is also an ElementFinder) function chained to another ElementFinder and its valid.
    • link2 is valid in its syntax because findElement() is chained to getWebElement(). As explained above this is valid because getWebElement() returns an element.
    • However your link3 doesn't work because the syntax chaining of function/method is improper. findElement() is neither chained to an element nor a browser instance, but it is chained to an ElementFinder and so you get an error while you use it.
  2. .element() is an ElementFinder and so works when used alone or chained with other ElementArrayFinder or ElementFinder. link1 is an example of that. Valid syntaxes for ElementFinder -

    element(LOCATOR);
    element(LOCATOR1).element(LOCATOR2);
    element.all(PARENT_LOCATOR).element(LOCATOR);
    

Hope it helps.

Upvotes: 2

reutsey
reutsey

Reputation: 1993

FindElement is a webdriver.webElement function, so you must use it after a webElement which is why it doesn't work in your last example. The documentation in the protractor API may help you for webdriver.WebElement.findElement:

http://angular.github.io/protractor/#/api?view=webdriver.WebElement.prototype.findElement

Upvotes: 0

Related Questions