0

I'm working through Selenium Webdriver, and I've come up to the issue of dynamic objects as a DOM ID. One of my instances gets generated as an ID, something like this:

"//*[@id="888itsAnExampleBoi573"]/div[1]/div[2]", 

and I need to click on the button in the example item to Make Stuff Happen.

Because I cannot predict what an objectID will be for my dynamic content, however, I would like to be able to do this, instead:

//*[contains(text(), 'example')]/div[1]/div[2]. 

I've tried to do this, but I'm returned a strange error:

Caused by: org.openqa.selenium.InvalidSelectorException: invalid 
    selector: Unable to locate an element with the xpath expression 
    //*[contains(text(), 'example')]/div/div/div[1]/div[3]/div 
    because of the following error:
    SyntaxError: Failed to execute 'evaluate' on 'Document': 
    The string '//*[contains(text(), 'example')]/div/div/div[1]/div[3]/div' 
    is not a valid XPath expression.  

On a different element that is a hyperlink with text elements, I've been able to use contains(text()) to solve things, so I believe I've formatted this correctly.

I've tried a few different things to solve this issue, but am at somewhat of a loss as to how to solve this. Does anyone have any ideas or resources to point me towards? Or better yet, a solution?

DebanjanB
  • 118,661
  • 30
  • 168
  • 217
  • It is highly unethical to change the question once you have received well researched answers. Your initial question was on `"//*[@id="888itsAnExampleBoi573"]/div[1]/div[2]"`. Once @AndreiSuvorkov answered you have changed it to `("//*[contains(text(), '"+ dynamicUpdate +"')]/div[1]/div[2])` and now after my answer is published you have changed your question as `"//*[@id="8885667673833573"]/div[1]/div[2]"` which is highly unethical as per stackoverflow guideline. I am reverting back your question for now. Feel free to raise a new question as per your new requirement. – DebanjanB Jul 18 '18 at 16:11
  • The example text was just something there that didn't accurately reflect what the question was. an objectID will constantly change and be dynamic, so it is not an option for dynamic strings of random numbers. I'm trying to eliminate Personally Identifiable Information from this question. To put it simply, text is the most predictable variable I can use to solve this. – LawrenceThomp Jul 18 '18 at 17:27

2 Answers2

0

This error message...

Caused by: org.openqa.selenium.InvalidSelectorException: invalid selector: Unable to locate an element with the xpath expression //*[contains(text(), 'example')]/div/div/div[1]/div[3]/div because of the following error: SyntaxError: Failed to execute 'evaluate' on 'Document': The string '//*[contains(text(), 'example')]/div/div/div[1]/div[3]/div' is not a valid XPath expression.

...implies that the Locator Strategy is not a valid XPath expression.

The expressions:

  • '//*[contains(text(), 'example')]/div/div/div[1]/div[3]/div'
  • "//*[contains(text(), "example")]/div/div/div[1]/div[3]/div"

Are invalid as '' and "" were present in multiple places within the xpath.

Solution

As an effective alternative dynamic xpath for the following:

"//*[@id="888itsAnExampleBoi573"]/div[1]/div[2]"

will be:

"//*[contains(@id,'itsAnExampleBoi')]/div[1]/div[2]"
DebanjanB
  • 118,661
  • 30
  • 168
  • 217
  • I have this working elsewhere in the code (where its something WebDriver can click on like a hyperlink) as a standalone element that gets generated: "//*[contains(text(), '"+ dynamicUpdate +"')] . It's passed in as a string. However, when I add divs onto the working example, it stops working. I think this might be moreso conceptually. The element should be moreObjectId like -> 5667673833 is probably better to put in than a cheeky example – LawrenceThomp Jul 18 '18 at 15:59
  • @El-Teezus Checkout my updated answer and let me know the status – DebanjanB Jul 18 '18 at 16:06
0

It appears that in order to solve this, sometimes you must frame the question. As I had been using a relative XPATH, I had been working under the pretense that the text div itself was where I would be able to access elements that were not the children of my div. They were actually only loosely related!

"//*[contains(text(), 'Flag this')]
      //parent::div
      //parent::div[contains(@class,'exampleDrop')]
      //child::div[contains(@class, 'pointed exampleAction')]"

I ended up installing Chropath and spidering around the DOM, finding the div with the text in it, and using a relative path in this statement. If you're having issues like these, sometimes I would recommend making sure that you're asking the right question.