I'm automating with Selenium. I'm dealing with 2 variants (mobile, desktop) of a page. Both have a "Login" button, but the HTML is different.
First variant:
<div role="button"><div ...><span><span>Foo Bar MaybeQuux</span></span></div></div>
Second variant:
<a href="p/q/r" data="loginButton"><div><span><span>Foo Bar MaybeQuux</span></span></div></a>
I've written MaybeQuux
as for small screens it turns into Mayb...
. However Bar
is guaranteed.
Here's my code so far:
def waitClickable(by, text, timeout=60):
return WebDriverWait(driver, timeout).until(
EC.element_to_be_clickable(
(by, text)
)
)
waitClickable(By.XPATH, "???").click()
So my question is, would it possible to write a single xpath that can locate both variants?
If so I can avoid the awkwardness of having to wait on an object of unknown form.
ref: Python selenium : Explicitly wait for one of two elements to be loaded
CodePudding user response:
You can use below XPATH
//*[self::div or self::a and starts-with(span, 'Foo Bar Maybe')]
but the easiest way is
//span[starts-with(., 'Foo Bar Mayb')]
or
//span[contains(., 'Bar Mayb')]
CodePudding user response:
This XPath should get the inner span
in both cases
'//div[@role="button"]/descendant::span[starts-with(.,"Foo Bar")] | //a[@data="loginButton"]/descendant::span[starts-with(.,"Foo Bar")]'
Alternative expressions
//*[(name()="div" and @role="button") or (name()="a" and @data="loginButton")]/descendant::span[starts-with(.,"Foo Bar")]
//*[(self::div and @role="button") or (self::a and @data="loginButton")]/descendant::span[starts-with(.,"Foo Bar")]
CodePudding user response:
Considering both the HTMLs:
First:
<div role="button"><div ...><span><span>Foo Bar MaybeQuux</span></span></div></div>
Second:
<a href="p/q/r" data="loginButton"><div><span><span>Foo Bar MaybeQuux</span></span></div></a>
Both have the following identical features:
Bar
is the guaranteed textMayb
is the guaranteed text- The above texts are within a
<span>
- The grandchild
<span>
is within it's immediate parent<span>
- The parent
<span>
is within it's immediate parent<div>
Solution
A common xpath to both the elements would be:
//div/span/span[contains(., 'Bar') and contains(., 'Mayb')]