14

I'm trying to check if an element exists before I can execute this line:

driver.findElement(webdriver.By.id('test'));

This throws an error "no such element" if the id test doesn't exist in the document, even in a try-block. I've found answers for Java, where you can check if the size is 0, but in node-js this throws an error before I can check the size.

throw error; ^ NoSuchElementError: no such element

F. Rakes
  • 1,407
  • 2
  • 17
  • 25

7 Answers7

31

You can leverage the optional error handler argument of then().

driver.findElement(webdriver.By.id('test')).then(function(webElement) {
        console.log('Element exists');
    }, function(err) {
        if (err.state && err.state === 'no such element') {
            console.log('Element not found');
        } else {
            webdriver.promise.rejected(err);
        }
    });

I couldn't find it explicitly stated in the documentation, but determined this from the function definition in webdriver/promise.js in the selenium-webdriver module source:

  /**
   * Registers a callback on this Deferred.
   * @param {Function=} opt_callback The callback.
   * @param {Function=} opt_errback The errback.
   * @return {!webdriver.promise.Promise} A new promise representing the result
   *     of the callback.
   * @see webdriver.promise.Promise#then
   */
  function then(opt_callback, opt_errback) { 
Aaron Silverman
  • 21,105
  • 20
  • 79
  • 102
  • 3
    This should be the accepted answer as it is the only that demonstrates how to determine is an element exists using the NodeJS Web Driver. – mcranston18 Jan 21 '14 at 20:59
  • 2
    Unless the op is mistaken on using python not javascript, this should be the correct answer. Up voted! – mekdev Jul 27 '15 at 01:17
  • in my case, the `err` object doesn't have a "state" prop. it returns this if i console log the error `{ NoSuchElementError: no such element: Unable to locate element: {"method":"css selector","selector":"img"}`. and the second condition returns `TypeError: Cannot read property 'promise' of undefined` – RZKY Feb 28 '17 at 09:33
  • Hi @Zugwait , may I just ask if it is possible to use `then` after a `driver.findElement(By.xpath('test')).click()` ? Thanks! – JPaulPunzalan Jul 05 '17 at 06:01
  • @Zugwalt Grateful for the answer, however how would you implement it in a scenario where you use `await`? I tried `await driver.findElement(webdriver.By.id('test')).then(function(webElement) { console.log('Element exists'); }, function(err) {...` but it throws an error – Malcolm Salvador Jul 17 '18 at 23:14
  • @JPaulPunzalan an Promise in that library should have the `then()` interface. @Malky.Kid if using `await` I imagine you could just surround with a `try`/`catch` and not use `then()`. – Aaron Silverman Jul 18 '18 at 15:45
2

Why not just use the isElementPresent(locatorOrElement) method? here's a link to the code:

http://selenium.googlecode.com/git/docs/api/javascript/source/lib/webdriver/webdriver.js.src.html#l777

Tomasz Wszelaki
  • 622
  • 4
  • 2
2

The selected answer did not work as expected (err.state was undefined and a NoSuchElementError was always thrown) -- though the concept of using the optional callbacks still works.

Since I was getting the same error as the OP is referencing, I believe NoSuchElementError should be referenced when determining if the targeted element exists or not. As it's name implies is the error that is thrown when an element does not exist. So the condition in the errorCallback should be:

err instanceof webdriver.error.NoSuchElementError

So the complete code block would be as follows (I also am using async/await for those taking advantage of that syntax):

var existed = await driver.findElement(webdriver.By.id('test')).then(function() {
    return true;//it existed
}, function(err) {
    if (err instanceof webdriver.error.NoSuchElementError) {
        return false;//it was not found
    } else {
        webdriver.promise.rejected(err);
    }
});
//handle value of existed appropriately here
Arthur Weborg
  • 7,867
  • 5
  • 29
  • 62
  • Tried this example, but now it says that 'webdriver' is undefined. tried getting it with "var webdriver = require('selenium-webdriver')" in the beginning of the file, but now it says that there's no property 'promise' in that variable. How could I implement that condition in that case? – Leonardo Montenegro Aug 18 '20 at 13:23
  • @LeonardoMontenegro I'm presuming the current version of the nodejs `selenium-webdriver` has updated and the properties of the webdriver have changed. I'd advise to go checkout the spec for the webdriver, it's possible they made the framework more stable and the hacky solutions in the post are no longer needed :fingers-crossed: If I get some free time I'll check it out as I probably have code I'll need to update somewhere as a result >_< Let me know if you find anything? – Arthur Weborg Aug 18 '20 at 15:35
  • @drasko kokic's answer below actually might be the solution (because of version updates and method/rpoperty deprecation): https://stackoverflow.com/a/62069633/1992129 – Arthur Weborg Aug 18 '20 at 15:41
1

The accepted answer did not work for me fully, though some parts of it were helpful. Arthur Weborg's answer above worked for me, though some parts caused issues: https://stackoverflow.com/a/45273140/5648143

My typical use case for "checking if element exists" is when I want to click the element, only if it exists, since if it doesn't exist, it crashes the program due to the error. All I want is for the application to note that it doesn't exist, and move on. So what I do is:

await driver.findElement(By.id("test")).then(found => {
  driver.findElement(By.id("test")).click()
}, error => {
  if (error instanceof webdriver.error.NoSuchElementError) {
    console.log('Element not found.');
  }
});

Just a simple console log, and moves on with the rest of the program like I wanted.

Jason
  • 308
  • 2
  • 7
0

You want to check whether an element exists before you want to find an element on UI. You can wait until the element gets located on UI then you can perform the find element operation.

Ex: Below code waits until element located then it will perform the find element.

driver.wait(webdriver.until.elementLocated(webdriver.By.id(LocatorValue)),20000)
.then(()=>{
   return driver.findElement(webdriver.By.id('test'));
}).then((element)=>{
    // Perform any operation what you to do.
      return element.click();
}).catch(()=>{
     console.log('Element not found');
})
Saurabh Bishnoi
  • 534
  • 5
  • 8
0

I know this is a bit late, but this is the code that worked for me.

var assert = require('assert');
var expect = require('chai').expect;
var should = require('chai').should();
var chai = require('chai');
var chaiAsPromised = require('chai-as-promised');

chai.use(chaiAsPromised);
chai.should();

var webdriver = require('selenium-webdriver');
By = webdriver.By;
until = webdriver.until;

describe('checking if an element id exists', function() {

  it.only('element id exists', function () {
    var driver = new webdriver.Builder().forBrowser('chrome').build();
    driver.get('http://localhost:3000');
    this.timeout(6000);

    return driver.wait(until.elementLocated(By.id('idWeWantToTest')), 5 * 1000).then( (e) => {
    }, function(err) {
      throw {
        msg: "element not found"
      }
    }).then( () => {
      driver.quit();
    });     
  });
})
Nikhil Das Nomula
  • 1,805
  • 5
  • 30
  • 46
0

Here the summary for newbies like me ;-)

As described here:

For consistency with the other Selenium language bindings, WebDriver#isElementPresent() and WebElement#isElementPresent() have been deprecated. These methods will be removed in v3.0. Use the findElements command to test for the presence of an element:

  driver.findElements(By.css('.foo')).then(found => !!found.length);
Draško Kokić
  • 1,207
  • 1
  • 19
  • 32
  • 1
    This looks promising and cleaner than my solution from a couple years ago. I'll check this out and if it works, will upvote (TBD on when I have the time to test it out) – Arthur Weborg Aug 18 '20 at 15:43