Element “id” changes(not static) in some web pages

2020-04-16 02:58发布

问题:

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.

回答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.



回答2:

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']")));


回答3:

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();