Search on descendants of an element

Brad8118 picture Brad8118 · May 21, 2014 · Viewed 46k times · Source

With protractor whats the best way to select child elements? Say we have the layout below...

<div id='parent_1'>
    <div class='red'>Red</div>
    <div class='blue'>Blue</div>
</div>
<div id='parent_2'>
    <div class='red'>Red</div>
    <div class='blue'>Blue</div>
</div>

With jQuery we'd do something like this.

var p1 = $('#parent_1');
var p1_red = $('.red', p1);  //or p1.find('.red');
var p1_blue = $('.blue', p1); //or p1.find('.blue');

But with Protractor does it make sense to first get the parent element? Since doing this var p1 = element('#parent_1'); doesn't actually retrieve/search for the object until getText() or something is called.

so doing this..

Scenario 1

expect(p1.element('.red')).toBe('red');
expect(p1.element('.blue')).toBe('blue');

OR

Scenario 2

expect(element('#parent_1').element('.red')).toBe('red');
expect(element('#parent_1').element('.blue')).toBe('blue');

OR

Scenario 3

expect(element('#parent_1 > .red')).toBe('red');
expect(element('#parent_1 > .blue')).toBe('blue');

Are there any benefits in one approach over the other?

This is what I'm doing but I don't know if there's any advantage of separating the parent from the cssSelector:

function getChild(cssSelector, parentElement){
    return parentElement.$(cssSelector);
}

var parent = $('#parent_1');
var child_red = getChild('.red', parent);
var child_blue = getChild('.blue', parent);

Looking at Protractor's elementFinder I could be doing this:

function getChild(cssSelector, parentCss){
    return $(parentCss).$(cssSelector);
}

var child_red = getChild('.red', '#parent_1');
var child_blue = getChild('.blue', '#parent_1');

Answer

Jmr picture Jmr · Jul 22, 2014

The advantage of separating the child from the child css selector would only be if you'd like to use the parent for something else. Otherwise, it's slightly faster to do it in one call, like expect(element('#parent_1 > .red')).toBe('red'); since Protractor doesn't need to make two calls to the browser in this case.

Another reason to use the first approach would be if you were using a Locator strategy that cannot be expressed in CSS. For example:

var parent = element(by.css('.foo'));
var child = parent.element(by.binding('childBinding'));
expect(child.getText()).toEqual('whatever');