I have two buttons on a page that have really similar xpaths -
the button im trying to click -
/html/body/div[#id='wrapper']/div[#id='content']/div[#id='contentarea']/div[#id='votecontent']/div[#id='votetext']/div[#id='voteboxes']/div[#id='votenow'][2]/form/input[2]
and the other button im trying to ignore -
/html/body/div[#id='wrapper']/div[#id='content']/div[#id='contentarea']/div[#id='votecontent']/div[#id='votetext']/div[#id='voteboxes']/div[#id='votenow'][1]/form/input[2]
the only difference between the two is the
[#id='votenow'][1]
and
[#id='votenow'][2]
but I can't figure out how to interact with the one that has the votenow[2], whichever way I go about it, it always seems to interact with the first one because that's the first one it finds
this is for java using the firefox driver, any suggestions would be great :)
Just find them both and get the desired one by index:
List<WebElement> buttons = driver.findElements(By.xpath("your xpath"));
WebElement secondButton = buttons.get(1);
First
Please talk to your developers! It is really bad practice to assign the same id to two different elements (in your case buttons) on the same page! It makes life for DEV and QA unnecessarily harder than it need be!
Second
The xpath-expressions you posted already contain the differentiation between these two buttons. So you just need to find the first one and click it.
via xpath:
You can use xpath - should be enough to search for the elements with id="votenow". As said before, you can be pretty precise in this case and already filter for the 2nd button:
WebElement button02 = driver.findElement(By.xpath("//div[#id='votenow'][2]/form/input[2]"));
button02.click();
via id:
As #alecxe already pointed out, you can also first go for a more general search of several elements and then filter the right one out. Personally I would use the id in this case:
List<WebElement> buttonWrappers = driver.findElements(By.id("votenow"));
// you want the button-input-element in the 2nd wrapper element, indexing starts at 0, so do this:
WebElement button02 = buttonWrappers.get(1).findElement(By.xpath("//input[2]"));
// since it seems there are several input elements below the desired div, you can use xpath again
Related
I have an element to find:
//div[contains(#class, 'bPageBlock')][.//*[.='Agreement Documents']]//div[#class='pbBody']//tr[contains(#class,'dataRow')]//a[text()='View']
The problem is, this finds two elements and I want only one. One is under an iframe and one isn't. It would be easy if I wanted the one under the iframe. I could do
//iframe///div[contains(#class, 'bPageBlock')][.//*[.='Agreement Documents']]//div[#class='pbBody']//tr[contains(#class,'dataRow')]//a[text()='View']
However, as you probably guessed, I want the one that is NOT under the iframe. I don't know how to specify something like //not iframe//. And even if I could, the // would find something one step lower or higher that was not an iframe.
Any suggestions how to find the one NOT under the iframe. The roots and paths other than that all seem to be the same with each other. I have tried lots of different things.
If you want to see the specific iframe:
<iframe frameborder="0" id="RLPanelFrame" name="RLPanelFrame" src="/emptyHtmlDoc.html" title="Hidden Frame - Ignore" style="height: 176px;"></iframe>
Then there are many sub-units under it with auto-generated meaningless IDs.
I don't think I can find each one using driver.find() and get the full xpath and check for "iframe" because selenium does not have an xpath extractor. I guess for each one I could keep getting the parent until I got to //html or //iframe but that would take a long time.
Any suggestions? This with Java and Selenium
My site generates an arbitrary number of popups (please don't judge my monitization strategy). Each popup is a complex div that I eventually want reference to via xpath, but I specifically want the last one that was added to the DOM, since that will be the one that's on top.
So I tried this
//*[#class="popupContent"][last()]
I know I could try this
(//*[#class="popupContent"])[2]
but I have no idea how many of these popups there are.
But in the case of having multiple popups on screen at once, I get a reference to the first one (I'm not sure if this is reliably the case or not). Each of these popups has a popupContainer, but for the sake of this question, it is off limits.
Given that there are multiple elements with this class, how can I get the one that is on top (and thus interactive)?
These things aren't siblings, children, or parents of each other. Also, I have no idea how many exist on the page at any given time. I also do not have any control over the content or structure of the popups beyond that I know the class for one of their internal components (popupContent).
If this is not possible, please explain why.
I'm looking for a solution that will be compatible in a Java Selenium testing environment. No jquery please.
According to this question: Do WebDriver findElements retain the Table rows order on its retrieval findElements guarantees order, so in a Selenium environment, I could get the list from that and retrieve the last item.
List<WebElement> popups = findElements(By.classname("popup"));
WebElement activePopup = popups.get(popups.size - 1);
Xpath (//*[#class="popupContent"])[last()] and code below should give you same result - last element in the DOM:
List<WebElement> popups = driver.findElements(By.className("popup"));
WebElement activePopup = popups.get(popups.size - 1);
If last element not the top one try to get focused element:
WebElement focused = driver.switchTo().activeElement();
if (focused.getAttribute("class").equals("popupContent"))
//my active/interactive popup
You can check if last one is active now:
WebElement lastOne = driver.findElement(By.xpath("(//*[#class="popupContent"])[last()]"));
if (lastOne.equals(driver.switchTo().activeElement()))
//last one is active
Another approach could be to look for the popup with the highest z-index value:
private WebElement getTopPopUp() {
List<WebElement> allPopUps = driver.findElements(By.classname("popup"));
WebElement topPopUp = allPopUs.get(0);
for(WebElement popUp : allPopUs) {
if(Integer.parseInt(popUp.getCssValue("z-index")) > Integer.parseInt(topPopUp.getCssValue("z-index"))) {
topPopUp = popUp;
}
}
return topPopUp;
}
My web application is responsive. I.e. it resizes for different screen sizes. Our developers have coded for this, and as a result, most web elements found by xpath actually have 2. One of them for full screen and one for "mobile" or small screen.
For example, if I use Firepath to search for the Xpath by just link text, it will say "2 elements found" Only one can be seen, then if I resize the browser window, that one disappears and the other one can be seen.
My question is: Can I use one Selenium script for both screen size? It would automatically use whichever element is visible or is clickable? If I script for just one of the two elements, I'll get "Element is not clickable" exception.
Or s the best solution to add all of the mobile elements to the page object separately, and create my methods something like:
if (DesktopWebElement.isVisible)
do the test for desktop
else if (MobileWebElement.isVisible)
do the test for mobile
It seems like quite a bit of extra work to add every mobile element separately and script every method in the page object like this. In the interest of saving time, I was just wondering if there's a way I could use an Xpath that finds both elements, and Selenium will find the first one that is visible.
I have the situations where the columns that get displayed vary by screen size in addition to different buttons.
My page files contain methods like
public int getScreenWidth() {
Dimension aScreen = webDriver.manage().window().getSize();
return aScreen.getWidth();
}
Then my code has things like:
if (screenWidth < 1440 ) {
...
}
Developers worked out with the business which columns dropped and at which widths.
There are screen width cutoff values set by the developers that determine which button gets displayed. So I click on the desktop or mobile button depending on the current screen width. Ask development to document the screen width cutoff values that they coded.
Have you tried ExpectedConditions.visibilityOfElementLocatedBy, as per documents it would give you a visible element attached to the DOM. This would give you ability to just interact with the element that is visible our of the two
WebDriver driver = new FirefoxDriver();
WebDriverWait wait = new WebDriverWait(driver, 30);
WebElement element = wait.until(ExpectedConditions.visibilityOfElementLocatedBy(By.xpath(".//someXpath")));
element.click();
You can also try elementTobeClickable condition if that suits you better. Note that this is NOT going to slow your tests down, as soon as the element is visible/clickable it will be returned.
I am working on a testing program that operates with very little information. In this particular case, my program doesn't know the ID of elements in the page before it runs, because the Javascript on the page dynamically assigns those at run time. The only constants I have is the structure and the text I'm looking for. I'm including a screenshot of one example of the DOM being generated. In this case I know that I want to access the button with text apply that is displayed next to the label with the text "To Location:" Is there a way to use xpath manipulate their relationship and ensure that I'm accessing the right element. I can't just access the apply button because there are 6 apply buttons on the page with dynamically generated IDs. The label's next to them are different so I'm trying to use that and manipulate the path's from there. Help?
This is possible. If you provide the entire html code I could provide a better xpath. But for what you pasted, here's a simple one that might work:
//td[div//label[text()='To Location:']]/following-sibling::td[1]//button[text()='Apply']
There's a slightly longer winded way but thats generating a list of elements by class and clicking the one with the right text
`var elements = driver.FindElements(By.Class("text-pb"));
foreach(var element in elements)
{
if(element.Text.Equals("Searched Text"))
{
element.click();
}
}`
that might work thats if you want to click the button.
i use these sort of things on the pages works site generates so it should do what your after.
I've been asked this question on a interview. What is the best way to find particular button on a page, from two identical buttons?
Two buttons like this on a page, i need to find the second.
button class="button-signin" name="btnlogin_login" value="Login" type="submit"> Sign In /button>
I've answered that I'd locate both and choose what I need from the list - they said that it's no good, because page can be changed. Can you suggest me the good way to do this?
If they said to find always the second element I would go for a solution like this:
List<WebElement> buttons = driver.findElements(By.class("button-signin"));
if(buttons.size() > 1){
buttons.get(1);
}
But what dont make sense for me is what they told you, than the page can change...Technically if the page change you should modify yours tests to make them easier to find elements save time and make them more readable, you cant do a test forever as a page is not forever.
Basically, the buttons must be child elements of some HTML elements.
Case 1: Parent are different, you can refer to each button by specify different parent e.g. cssSelector("#component1 > button") and cssSelector("#component2 > button").
Case 2: They have the same parent or path are identical, there are a couple options.
Use index such as XPath //button[2] or CssSelector button:nth-child(2)
Change the application, add something to differentiate the buttons
For case 2, I do think there is no point to have the 2 buttons which have the exactly same properties in the application. Personally, I prefer the option#2