I am writing a test and would like to replicate the user's workflow -- users don't go by CSS selectors, element names, or XPath queries, all they can see is what the user agent renders. To that end, I would like to find an element on the page based on its [rendered] content, and being case-insensitive at that (since that's what more closely resembles how the user will approach it). I'd accept the equivalent of the //label[contains(lower-case(text()), "username")]
XPath 2.0 expression.
Since Selenium appears to defer XPath query execution to the driven browser, where my testing indicates it's only ever XPath 1.0, I can't use XPath 2.0 functions like lower-case
or matches
, in order to find an element that has the desired content.
None of the other locator strategies (e.g. using a CSS selector) match capabilities of XPath, certainly none of them allow me to find an element based on its content.
I thought if it were possible to write a custom locator strategy somehow, that would allow me to use it with the find_element
procedure, but I can't find much information on whether that is even possible, let alone if it's possible with specifically the selenium
Python module provided by Selenium, or how to accomplish it in the first place.
Is it possible? How can it be done, if so? Alternatively, am I solving the wrong problem?
I am writing a test and would like to replicate the user's workflow -- users don't go by CSS selectors, element names, or XPath queries, all they can see is what the user agent renders. To that end, I would like to find an element on the page based on its [rendered] content, and being case-insensitive at that (since that's what more closely resembles how the user will approach it). I'd accept the equivalent of the //label[contains(lower-case(text()), "username")]
XPath 2.0 expression.
Since Selenium appears to defer XPath query execution to the driven browser, where my testing indicates it's only ever XPath 1.0, I can't use XPath 2.0 functions like lower-case
or matches
, in order to find an element that has the desired content.
None of the other locator strategies (e.g. using a CSS selector) match capabilities of XPath, certainly none of them allow me to find an element based on its content.
I thought if it were possible to write a custom locator strategy somehow, that would allow me to use it with the find_element
procedure, but I can't find much information on whether that is even possible, let alone if it's possible with specifically the selenium
Python module provided by Selenium, or how to accomplish it in the first place.
Is it possible? How can it be done, if so? Alternatively, am I solving the wrong problem?
Share Improve this question asked Feb 14 at 14:36 Armen MichaeliArmen Michaeli 9,1409 gold badges65 silver badges100 bronze badges 10- Yes, you are solving the wrong problem. Users (generally) don't know HTML/CSS, they interact with elements. How you find the elements they interact with doesn't really have anything to do with users. The important thing is to create a locator that reliably finds the correct element. What are you going to do with elements that the script needs to interact with that doesn't have any content? – JeffC Commented Feb 14 at 14:53
- You could create a custom locator type but it would have to be backed by one of the supported locator types which is going to be the ones you listed. If you are limiting yourself to elements with content, the only one available is XPath. – JeffC Commented Feb 14 at 14:55
- How about finding all elements of a class/tag and cycling through them in python. Use python to filter these based on content (which will be a linear-time search) – inspectorG4dget Commented Feb 14 at 15:02
- @JeffC, to reiterate, it is in large part because users don't know (or care for) HTML/CSS/XPath that I want to locate an element replicating how the user would be looking for it -- on the page, using their eyeballs, not seeing element IDs/classes/names/hierarchy. The test is, after all, designed to answer the question "does this aspect/workflow of the Web page, function?". The workflow in question, is user's workflow, not necessarily a technical evaluation that hinges on correct CSS classes or something on that level. – Armen Michaeli Commented Feb 14 at 15:09
- 1 @ArmenMichaeli I've been doing this for years... a well written locator will not be brittle. Also, you are assuming that the content on the page that you want to base your new locators on doesn't change... but it does as well. For example, an element that has an ID is going to be WAY more reliable than finding it by contained text. The odds of the ID changing is near zero... and so on. – JeffC Commented Feb 14 at 15:30
1 Answer
Reset to default 0There are ways to work around this limitation and achieve case-insensitive text search for elements.
1.Use XPath with translate()
element = driver.find_element(By.XPATH, '//label[contains(translate(text(), "ABCDEFGHIJKLMNOPQRSTUVWXYZ", "abcdefghijklmnopqrstuvwxyz"), "username")]')
Find All, Then Filter.
Use JavaScript Execution (execute_script)
script = """ return Array.from(document.querySelectorAll("*")) .filter(el => el.innerText.toLowerCase().includes("username")); """ elements = driver.execute_script(script)