6

I am trying to check if an element does not exist but it is failing with timeout issue. From my observation, I found out that the driver is first trying to find out that element first and then waiting for the element to go away instead of checking whether an element exists or does not exist immediately. I tried below methods.

1. browser.element.all(selector)
2. browser.driver.findElements(selector)
3. browser.isElementPresent(browser.element(selector))
4. element(selector).isPresent()

Background: When a button is clicked, a modal will appear. It has cancel and save buttons. On click of Cancel button the modal window disappears. Now I am trying to write an expect condition to check if the Modal has disappeared or not.

All above are failing. Please tell me a correct way where I can check if an element exists immediately.

Here is the error for all the above

Error: function timed out after 60000 milliseconds

I am Really not sure, why Protractor is unable to help to me just check if the element is not present in the DOM. I tried all the ways possible. Every method is trying to find whether existing element is being transitioned to not existing state or not. Then why these many APIs if all doing the same job.

brightDot
  • 329
  • 2
  • 11
  • Does angular.element(document).find('...') not work? – rrd Jul 10 '17 at 06:08
  • It is inside Protractor. I am avoiding browser script execution. – brightDot Jul 10 '17 at 06:10
  • This is not a good problem description. Please add details about what happened when you used these selectors? Are you having an error/exception, or the code passes and nothing happens? Without this and the relevant HTML, it would just be a shot in the dark. – demouser123 Jul 10 '17 at 07:11
  • @demouser123 Added some context there. – brightDot Jul 10 '17 at 07:19

5 Answers5

3

Not sure why you're using browser. for your selectors, nor what your selector actually is, but I suspect you're hitting multiple issues.

First off, .isPresent() really asks is it in the dom; isDisplayed() asks is it visible. Thus, your strategy here will depend if your model his removed from the dom, or hidden (eg. display:none etc...).

Second, it doesn't appear you're handling the promise that either of these methods return. You also don't mention if you're running this in an expect (which automagically waits for the promise to resolve).

Thirdly, it's not clear if your modal selector returns a single element, or multiple (though you do indicate the later with your use of element.all.

Long story slightly longer, here's an example of how you might check if your modal is displayed, given the assumptions that your modal has a class of .myModal, is the only one, and it is removed from the dom when not displayed.

$('.myModal').isPresent().then(function(inDom) {
    return inDom; // returns bool
};

The above code grabs your element, checks if it is in the dom, handles the promise via .then and returns true/false if the element is in the dom.

That said, your code might have multiple modals, hidden via css. In this case, you'll need to find a strategy for that case. Maybe your code adds a .shown class to hidden elements? Great, check for the presence of $('.myModal.shown'). Maybe your code has multiple hidden modals in the dom... less great, but you could loop through each element, and test if any are displayed with isDisplayed().

Hope this helps a bit...

Brine
  • 3,733
  • 1
  • 21
  • 38
2

I know this post is very very old. But i found a way that could be useful: i've created a function that, with 3 parameters

  • field: the ElementFinder which should not be present,
  • fieldName: the name of field just for log,
  • present: boolean to use this function to test if field-present too.

that could be used to test every element present (and not) in DOM

export async function checkField(field: any, fieldName: string, present?: any) {
  let text: string;
  if (present === false) {
    if (field.length > 0) {
      field.forEach(async el => {
        try {
          text = await el.getText();
          expect('should not be present (' + fieldName + ')').toEqual('but it is');
        } catch (e) {
          expect(el.isPresent()).toBe(present);
        }
      });
    } else {
      try {
        text = await field.getText();
        expect('should not be present (' + fieldName + ')').toEqual('but it is');
      } catch (e) {
        expect(field.isPresent()).toBe(present);
      }
    }
  } else {
    if (field.length > 0) {
      field.forEach(async el => {
        try {
          text = await el.getText();
          expect(el.isPresent()).toBe(true);
        } catch (e) {
          expect('element present (' + fieldName + ')').toEqual('but i can\'t find it');
          throw e;
        }
      });
    } else {
      try {
        text = await field.getText();
        expect(field.isPresent()).toBe(true);
      } catch (e) {
        expect('element present (' + fieldName + ')').toEqual('but i can\'t find it');
        throw e;
      }
    }
  }
}

this could obviously be written in better way, but certanily works!

For everyone who could search again this post.

Luca Taccagni
  • 1,059
  • 6
  • 23
0
expect($(".example").isPresent()).toBe(false)

Every method in protractor returns a promise. You have to use a helper to resolve it. Such as the built in expect function.

clint
  • 301
  • 4
  • 9
  • I have selector in this form `by.css(selectorText)`. I can't change that, so I cannot use `$` – brightDot Jul 10 '17 at 06:11
  • $ is just shorthand for that. It's the same thing in protractor: https://github.com/angular/protractor/blob/master/docs/locators.md – clint Jul 10 '17 at 06:15
  • Ok. It is not working too. Just updated the question. Still, it is trying to find the element and waiting for it. Then timeout happens – brightDot Jul 10 '17 at 06:23
  • You need to use expect isPresent and toBe, as in my example, as querying returns a promise. Every method in protractor returns a promise. You have to use a helper like expect to resolve it. – clint Jul 10 '17 at 06:31
  • Please don't add code only or one liners. They are really not constructive in providing solutions for any question. Please add some explanation around why you think your solution would solve this problem. Otherwise, it can be downvoted. Thanks! – demouser123 Jul 10 '17 at 07:07
0

Below is an example taken from protractor api docs

expect(element(by.binding('notPresent')).isPresent()).toBe(false);

so your solution should be ,

expect(element(by.css('.elementClass')).isPresent()).toBe(false);

demouser123
  • 4,108
  • 9
  • 50
  • 82
Shawon Barua
  • 61
  • 10
0

I had a similar issue, you might find better luck using expectedConditions to wait for the modal to go away, before you try the expect statement.

var WaitForElement = function(item, timeout = 15000) {
  var el = element(by.css(item));
  var EC = protractor.ExpectedConditions;
  browser.wait(EC.not(EC.presenceOf(el)), timeout).then(function(){
    return;
  });
};

WaitForElement('.example').then(function() {
    expect(element(by.css('.example')).isPresent()).toBe(false);
}

This will make protractor wait for the specified element, ('.example' in this case) to disappear before running the expect statement, or else it will timeout after fifteen seconds and the expect will fail.

M. Hudson
  • 889
  • 5
  • 11
  • This does not work either :( It is still waiting for the element to be present. But element is gone long before – brightDot Jul 10 '17 at 08:33
  • [M. Hudson](https://stackoverflow.com/users/7709399/m-hudson) , I am using your method, as (var EC = protractor.ExpectedConditions;), All works fine, But in console, I am getting like "Exception Thrown, Keeping selenium alive". And test are all successful. Do you know the reason? How to solve it? – Vikas Gupta Sep 02 '17 at 05:11