3

I am trying to capture a drop-menu field using test automation in SELENIUM with chrome driver.

Why does the element "id" changes in some web pages when inspecting elements time to time, with Chrome browser? How to keep the "id"s static, without changing?

Steps I followed:

  1. When I inspect elements in the web page, the particular drop-menu shows its "id" as: id="combo-1782-inputEl"

HTML:

<input id="combo-1782-inputEl**" type="text" class="x-form-field x-form-required-field x-form-text x-trigger-noedit x-form-focus x-field-form-focus x-field-default-form-focus" autocomplete="off" name="type" readonly="readonly" aria-invalid="false" data-errorqtip="" style="width: 135px;">

id observed by inspecting the web page in normal chrome browser:

-

  1. Then I used the above id in my java code(automation script) as below:

    driver.findElement(By.id("combo-1782-inputEl")).click();

  2. When I run the test > The google chrome browser opens automatically > The test gets successful till it meets the above line of code.

  3. But, when it meets the above code line, the test failed Throwing the following exception:

    • class org.openqa.selenium.NoSuchElementException *
  4. Then I inspected the same drop menu item in chrome web page opened (controlled) by automated test software, and found out that the "id" is different than the previous id mentioned in step 1. The "id" in this case is: "combo-1781-inputEl"

id observed by inspecting the web page in chrome browser controlled by automated software:

-

As you can see, the number in the middle of the id has reduced from 1. (1782-1 = 1781)

Same issue was found in the other drop menu items on the same web page.

What is the issue cause for this? How can I overcome this situation? Please help. :)

P.S. When I used "combo-1781-inputEl" ("id" from step 5) in my code, the test passed successfully.

driver.findElement(By.id("combo-1782-inputEl")).click();  //Test: failed
driver.findElement(By.id("combo-1781-inputEl")).click();  //Test: passed

I expected the test to be passed when I used the "id" I got in step 1 by inspecting the web page in normal chrome browser which is not controlled by automated software.

undetected Selenium
  • 183,867
  • 41
  • 278
  • 352
  • You can refer https://sqa.stackexchange.com/a/18358 link – Pradnya Bolli Apr 23 '19 at 12:50
  • 1
    if you have dynamically generated ID, I would suggest using contains and just take a part of the id essentially do By.xpath(//*[contains(id, 'combo-178')]) – Tomasz Wida Apr 23 '19 at 12:52
  • I would suggest going and talking to the developer that created it and ask them to make the ID static, if that isn't possible suggest setting a custom data tag (e.g. `data-webdriver-id="SOME-ID"`). Testability is a feature. – Ardesco Apr 29 '19 at 13:48

3 Answers3

1

In order to provide you with the best answer, I'd need to see a section of HTML code for the web page, enough that I can see other attributes. When you have dynamic ID's you have two options:

Option 1: use an xpath that uses part of the ID that is constant, i.e.:

//*[starts-with(@id, 'combo-')]

might do the trick, but only if there are no other similar ID's.

Or perhaps:

//*[starts-with(@id, 'combo-') and ends-with(@id, '-inputEl')]

but that might still not be specific-enough. This is why seeing a section of your HTML would help.

Option 2: use other attributes instead of ID, i.e. class, text, or some other attribute.

//*[@name='FirstName']

for example. You can craft rather elaborate xpaths using combinations of attributes, and it will be fairly stable if you do it right. Sharpening your xpath creation skills will come in handy for things like this.

Bill Hileman
  • 2,798
  • 2
  • 17
  • 24
  • @Bill: Thank you for the explanation. There are only 2 drop menus in the same web page with the same starting prefix and ending suffix in their 'id's. I tried with your solutions, but then I got org.openqa.selenium.InvalidSelectorException Something must be wrong in my code. Can you help? Below are the HTML code of those 2 fields: – Nirmani Nayanathara Apr 24 '19 at 11:59
  • * 1st drop menu field name = "Campaign type" / HTML code: – Nirmani Nayanathara Apr 24 '19 at 12:00
  • * 2nd drop menu field name = "Number mask" / HTML code: – Nirmani Nayanathara Apr 24 '19 at 12:01
  • Since the name attribute is provided, the first one can be located using `//input[@name='type']` and the second one using `//input[@name='mt_port']` – Bill Hileman Apr 24 '19 at 13:00
  • Also, for future reference, it would be better to add that HTML code to the original post instead of as a comment (which I now see it appears you did, but screenshots of code are frowned-upon - highlighted code would be better) – Bill Hileman Apr 24 '19 at 13:01
0

Use Xpath and WebDriverWait to handle dynamic element.Hope this will work.

WebDriverWait wait = new WebDriverWait(driver, 30);
WebElement element = wait.until(ExpectedConditions.elementToBeClickable(By.xpath("//input[starts-with(@id, 'combo-')][@type='text']")));
KunduK
  • 32,888
  • 5
  • 17
  • 41
0

As it is evident that the id attribute of the <input> tag changes dynamically e.g. "combo-1782-inputEl", "combo-1781-inputEl" and so on so you need to create a Dynamic Locator inducing WebDriverWait and you can use either of the following Locator Strategies:

  • cssSelector:

    new WebDriverWait(driver, 20).until(ExpectedConditions.elementToBeClickable(By.cssSelector("input.x-form-field.x-form-required-field.x-form-text.x-trigger-noedit.x-form-focus.x-field-form-focus.x-field-default-form-focus[id$='-inputEl'][name='type']"))).click();
    
  • xpath:

    new WebDriverWait(driver, 20).until(ExpectedConditions.elementToBeClickable(By.xpath("//input[starts-with(@id, 'combo-') and @class='x-form-field x-form-required-field x-form-text x-trigger-noedit x-form-focus x-field-form-focus x-field-default-form-focus'][@name='type']"))).click();
    
undetected Selenium
  • 183,867
  • 41
  • 278
  • 352
  • Thank you. But I am getting "class org.openqa.selenium.TimeoutException" when using this method. How can I avoid the timeout exception? – Nirmani Nayanathara Apr 24 '19 at 12:20
  • _TimeoutException_ is the outcome of **failed** _ExpectedConditions_. Debug your code through `findElement()` inconjunction with `Thread.sleep()`. If you are able to locate the element, update the question with the observations. – undetected Selenium Apr 24 '19 at 12:21