3

I'm using protractor for end-to-end tests of an Angular 2 app (and I suck at CSS).

I'm stuck trying to select all elements, which do NOT have a (div) child with a certain class. They can have div children, just none with that class.

The individual elements look (more or less) like this:

<div class="card"
     (click)="clickEvent.emit(generator.id)">

    <div id="card-title-anchor">

        <div class="card-img-top">
             <img src="{{generator.imageUrls.small}}">
        </div>

        <div *ngIf="!canFulfillAAC()" class="sold-overlay">
            <p>bla</p>
        </div>                  

        <div class="col-3 price-overlay">
            <p class="big-price">
                bla
            </p>    
        </div>
    </div>
</div>

I can get all the ".card" elements with element.all(by.css('.card')).

But how do I get only the ones , which do not include a child div with the sold-overlay class?

EDIT: I removed the css tags. I mainly care about how to achieve this with protractor locators - be it through a css selector, xpath expression or otherwise.

EagleBeak
  • 5,655
  • 5
  • 27
  • 43
  • 1
    With CSS...you can't (**yet**). There is no CSS [**Parent Selector**](http://stackoverflow.com/questions/1014861/is-there-a-css-parent-selector) – Paulie_D Jan 10 '17 at 17:03
  • 1
    In CSS there really isn't any parent selectors. CSS will _cascade_ downward (and adjacent) through the DOM... but not upward. What it sounds like you want is _hey CSS, find all divs that don't have this child, then go back up and style that parent_ which would mean you would have to traverse upward. You'll probably have to use some javascript to solve your problem. – zgood Jan 10 '17 at 17:04
  • As mentioned above I would use Javascript to assign an additional class to the card div. As this class would be used for selection in protractor tests only I'd use a prefix like "protractor-" so that it is clear it is only there for tests. – chrigu Jan 10 '17 at 17:13
  • this is not possible with just CSS. This answer has a more detailed explanation: http://stackoverflow.com/a/2000614/4912604 – Tony Scialo Jan 10 '17 at 17:21

2 Answers2

3

You can also use filter() method to achieve this,

element.all(by.css(".card")).filter(function(cardElement){
    return cardElement.all(by.css(".sold-overlay")).count().then(function(count){
        return count == 0;
    });
});
Sudharsan Selvaraj
  • 4,751
  • 3
  • 11
  • 21
1

Sorry I don't know of a way to do it with a CSS selector, but it could be achieved with xpath:

element.all(by.xpath('//div[@class="card" and not(.//div[contains(@class, "sold-overlay")])]'))

if class contains more than one value, it wouldn't be a good idea to match @class=value as it will match the entire property. This is different than css when using div.value.

eLRuLL
  • 17,114
  • 8
  • 67
  • 91
  • Uh-huh! Thanks for thinking around my inadequate focus on css selectors. This didn't quite do the trick though. The test threw `Index out of bound. Trying to access element at index: 0, but there are only 0 elements that match locator By(xpath, //div[@class="card" and not(.//div[@class="sold-overlay"])])` – EagleBeak Jan 10 '17 at 17:39
  • At first glance I would even prefer this over adding an additional class with JavaScript as suggested in the comments under my question. This seems less invasive to me. – EagleBeak Jan 10 '17 at 17:40
  • well, this could be because all your `div`s with `class=card` have an inner `div` with `class="sold_overlay"`. You'll have to share the whole structure to be sure what you are getting. On the other hand I saw that you just edited your question with `class` containing multiple attributes, please check updated answer – eLRuLL Jan 10 '17 at 22:04
  • Hmm? [I did not edit anything in the html.](http://stackoverflow.com/posts/41574131/revisions). Sharing the whole structure won't help, because the the div in question is rendered dependent on a binding (`*ngIf="!canFulfillAAC()"`). – EagleBeak Jan 11 '17 at 09:54
  • Sorry, but the expression doesn't work for me. [Sudharsan's solution](http://stackoverflow.com/a/41583393/1492999) does. – EagleBeak Jan 11 '17 at 10:00