0

I'm using JavaScript with selenium to automate a webpage that has several buttons I need to click on. My code starts by connecting to the existing chrome window as shown:

var chrome = require("selenium-webdriver/chrome");
    var options = new chrome.Options();
    options.options_["debuggerAddress"] = "127.0.0.1:9222";
    var driver = new webdriver.Builder()
        .forBrowser('chrome')
        .setChromeOptions(options)
        .build();

The driver works successfully and has the correct page, I have verified this by having the driver print the source code of the page, which matches with the page source of the site from the right-click menu.

I also have a function called checkForName(), which, given an XPath, returns the element for selenium to interact with

async function checkForName(selector) {
  console.log("Checking for name");
  try {
            const element = await driver.findElement(By.xpath(selector));
            return element;
  } finally {
            console.log("Error: element " + selector + " not found");
            return false;
  }
}

This function is then called later on in the program

element = await checkForName("//button[@class='mBiMV']");
if(element) {
   element.click();
}

However, when the program is run, this error pops up in the console:

Checking for name
SnapBot-JS.js:18
Error: label //button[@class='mBiMV'] not found

I've verified that the button exists, and the document is fully loaded before the chromedriver connects, so I'm not sure what to do at this point

EDIT: Here's the HTML code of the button in question:

<button type="button" class="mBiMV">
Ajax21
  • 53
  • 4
  • What I suspect would sort out your issue is using waits, something along the lines of ` await driver.wait(until.elementLocated(By.id('foo')), 30000);`. Selenium documentation on this one can be found at https://www.selenium.dev/documentation/webdriver/waits/ – Barry the Platipus Aug 12 '22 at 22:35
  • I changed the code in the try block to this, but it instantly throws the same error. `const element = await driver.wait(until.elementLocated(By.xpath(selector)), 30000); return element;` – Ajax21 Aug 12 '22 at 23:48
  • I suggest switching to playwright which will wait automatically. It's much more foolproof for beginners (and especially for javascript) – pguardiario Aug 13 '22 at 10:33

1 Answers1

0

The classname i.e. mBiMV is dynamically generated and is bound to chage sooner/later. They may change next time you access the application afresh or even while next application startup. So can't be used in locators. Instead you need to use the attributes with static values.


Solution

As per the HTML:

<button type="button" class="mBiMV">

There seems to be no other attributes with static values provided type="button" is too generic as an attribute. In these cases you may like to move to the parent element and use the static attribute to identify it's decendent <button> uniquely. As an example:

<div class="foo" id="bar">
    <button type="button" class="mBiMV">
    

An effective locator strategy for the above HTML would be either of the following:

  • Using css:

    const element = await driver.findElement(By.css("div.foo#bar > button"));
    
  • Using xpath:

    const element = await driver.findElement(By.xpath("//div[@class='foo' and @id='bar']/button"));
    
undetected Selenium
  • 183,867
  • 41
  • 278
  • 352