Best approach to use when values are dynamically created? - selenium

I'm looking for some advice on how to select a WebElement.
When I click a button that creates a new 'page', the given value is dynamic, in that it is totally random and not sequential. I would expect it to follow something like: page 1 = 0, page 2 = 1, page 3 = 2, etc.
By default I begin with a page, and its value is c3. Although when I trigger a button to create new pages the values appear as follows:
<select class="j-currentPage f-feature-A" name="currentPage"> <option value="c3">New Page</option> <option value="c277">New Page 2</option> <option value="c383">New Page 3</option> <option selected="" value="c461">New Page 4</option> </select>
So when I attempt to use the following:
List<WebElement> option = chrome.findElements(By.tagName("option"));
option.get(0).click();
option.get(1).click();
option.get(0).click();
It's obviously failing as the values are c277, c346 etc etc, and there is no way of knowing what the values will be in a new session as they will always be different.
The stacktrace is throwing a StaleElementReferenceException because its not in the DOM.
How can I select each page when the values are completely random?
I'm using Webdriver and JUnit4.
EDIT
Test method: to create some new pages.
#Test
public void createANewPage(){
WebDriverWait wait = new WebDriverWait(chrome, 60);
wait.until(ExpectedConditions.visibilityOfElementLocated(By.cssSelector("select.j-currentPage.f-feature-A[name=\"currentPage\"]")));
WebElement newPage = chrome.findElement(By.cssSelector("span.j-addViewBtn.ss-layers"));
newPage.click();
List<WebElement> option = chrome.findElements(By.tagName("option"));
option.get(1).click();
option.get(0).click();
}
Then a few tests later I want to call back the created page(s)
#Test
public void goToPage(){
new WebDriverWait(chrome, 60).until(ExpectedConditions.visibilityOfElementLocated(By.cssSelector("select.j-currentPage.f-feature-A[name=\"currentPage\"]")));
List<WebElement> option = chrome.findElements(By.tagName("option"));
option.get(0).click();
option.get(1).click();
option.get(0).click();
}
I receive a org.openqa.selenium.StaleElementReferenceException at the point of the third option.get(0).click();
However I feel as though I'm approaching this the wrong way as the values are dynamically created <option value="c3">New Page</option>
<option value="c207">New Page 2</option>
<option value="c288">New Page 3</option>
<option selected="" value="c366">New Page 4</option>

The StaleElementReferenceException does not mean that it is not in the DOM. It means that the DOM has changed since you found that object and therefore may be deleted or changed. The change coudld be due to the page reloading or HTML refreshed via javascript. Either way, Webdriver throws the error because it thinks it is probably good idea to refind objects as the page has changed.
If you refind the elements, then it will work. You are finding by tag name, so the fact that ids have changed, should have no impact.
The following would work but does have performance issues;
chrome.findElements(By.tagName("option")).get(0).click
chrome.findElements(By.tagName("option")).get(1).click
chrome.findElements(By.tagName("option")).get(2).click
There will a better way to approach your problem for your particular application but hopefully understanding what stale elements actually indicates, will help you solve your issue.

None of the FindElement() strategies support using regular expressions for finding elements.
Though there is another way using regex, might help you
List<WebElement> option = chrome.findElements(By.tagName("option"));
now loop on the options and getText. Then do the regex check programmetically
Below is a demo code will not run. Please transfer it to jave
foreach(WebElement link in links)
{
string text = link.Text;
if (Regex.Match("your Regex here", text))
{
matchingLinks.Add(text);
}
}
foreach(string linkText in matchingLinks) // now you have the texts even if they are dynamics
{
WebElement element = driver.findElement(By.LinkText(linkText));
element.Click();
// do stuff on the page navigated to
driver.Navigate().Back();
}

OKay, I've just managed to solve the issue with the help of the contributors to this question.
It seems as though I just needed to use xpath instead of List<WebElement> so the below code now selects the pages I want.
#Test
public void jGoToPage(){
new WebDriverWait(chrome, 60).until(ExpectedConditions.visibilityOfElementLocated(By.cssSelector("select.j-currentPage.f-feature-A[name=\"currentPage\"]")));
WebElement page1 = chrome.findElementByXPath("//option[contains(.,'New Page')]");
page1.click();
WebElement page2 = chrome.findElementByXPath("//option[contains(.,'New Page 2')]");
page2.click();
WebElement selectPage1Again = chrome.findElementByXPath("//option[contains(.,'New Page')]");
selectPage1Again.click();
Perhaps not the best code, but if anyone would like to suggest a better way to refine it, please comment so others can learn.
The reason I declared New Page twice was because I was receiving a staleElementReferenceException again. So by simply attempting to perform page1.click(); immediately after page2.click(); is when that happened which is why I declared it as selectPage1Again
I also used this question to help with the solution.

Related

Advise on locating elements on a webpage I am building a selenium script for

I am after some advice regarding a Selenium script I am building. The screenshot of the webpage I am writing the selenium scripts against, is attachedScreenshot. I have a webpage where I am mouse hovering over the ‘Reports’ text from the navigation pane which brings up a menu…..from that menu there I am selecting ‘Asset Management’, then ‘Terminated Report: Completed’ from the sub-menu.
I’ve attached the selenium code below which highlights what I am trying to do….I thought the best way to do this would be via xpath, as there wasn’t a great deal of information to work off in terms of elements.
public class optionFocusControls {
//REPORTS TAB
public static void reportWindowFocus(InternetExplorerDriver driver){
WebElement reportWindowFocus = driver.findElement(By.linkText("Reports"));
Actions hoverOnReportText = new Actions(driver);
hoverOnReportText.moveToElement(reportWindowFocus).build().perform();
}
public static void assetManagementFocus(InternetExplorerDriver driver){
WebElement assetManagementFocus = driver.findElement(By.xpath("html/body/div[1]/form/div[2]/div/ul/li[4]/ul/li[1]/a"));
Actions hoverOnReportWindow = new Actions(driver);
hoverOnReportWindow.moveToElement(assetManagementFocus).build().perform();
}
public static void daysInStockFocus(InternetExplorerDriver driver){
WebElement daysInStockFocus = driver.findElement(By.xpath("html/body/div[1]/form/div[2]/div/ul/li[4]/ul/li[1]/ul/li[1]/a"));
Actions hoverOnDaysInStock = new Actions(driver);
hoverOnDaysInStock.moveToElement(daysInStockFocus).build().perform();
daysInStockFocus.click();
}
public static void terminatedReportCompletedFocus(InternetExplorerDriver driver){
WebElement terminatedReportCompletedFocus = driver.findElement(By.xpath("html/body/div[1]/form/div[2]/div/ul/li[4]/ul/li[1]/ul/li[2]/a"));
Actions hoverOnReportWindow = new Actions(driver);
hoverOnReportWindow.moveToElement(terminatedReportCompletedFocus).build().perform();
terminatedReportCompletedFocus.click();
}
}
I’ve also attached the HTML from the webpage (Screenshot 2, which hopefully gives an idea of how I built the above test scripts in Selnenium(apologies for the formatting!)
body class="customer-search">
<div id="wrapper">
<form id="aspnetForm" action="CustomerSearch.aspx" method="post">
<div class="aspNetHidden">
<div id="top-nav">
<div class="inner">
<img id="ctl00_Img1" alt="*" src="../Images/chinook/gfx-topnav-left.gif">
<ul class="drop-down-menu sub-nav">
<li>
<li id="GN02">
<li id="GN03">
<li>
<a class="" href="../CCLReports/Overall">Reports</a>
<ul id="ddm-74938" style="display: none;">
<li>
<a class="" href="#">Asset Management</a>
<span>»</span>
<ul style="display: none;">
The issue I have had is that I want to arrive at the 'Asset Management' > 'Terminated Report: Completed' page. After I have checked that page I want to go to 'Asset Management' > 'Terminated Report: Pending' page. However, the XPath when selecting the ‘Asset Management’ option is now different when I go to 'Terminated Report: Pending', than it was when I went to 'Terminated eReport: Completed', even thought the selection of it is the same..... I’m assuming this is because I am selecting the menu option from a different page, does this change the Xpath? Based on the above, I have two questions which I am hoping for assistance on:
1) Given that it looks like XPath isn’t the best way of me navigating through this navigation menus, what would be the best element locator to use, in order to get to the desired location?
2) Another issue I have is that when I arrive at a page, using the above selenium code, the focus is still on the option I have selected from the menu e.g. ‘Terminated Report: Completed’. This prevents me from being able to select any elements on the page, and I can’t see any way around this. Is there an action whereby the focus can be switched to the webpage as a whole, so I can complete any actions I need to.
XPath and CssLocators are pretty flexible since they support multiple ways of identifying an element. I'm not sure you'll find a better alternative. This is a good reference for what they can do.
Your approach is pretty rigid in that your xpath string specifies the full hierarchy - the element you're searching for plus all its parents. If any element in that hierarchy changes or gets re-ordered it will fail.
Based on your html snippet, the link text is the most unique key to identify our elements. This isn't ideal since we can come across other links with the same text, but we can use parent or sibling relations with other elements to improve robustness.
All our menu elements are in the top navigation bar so we can limit our search to its descendants. The unspecified path look up // lets us skip stating the full hierarchy chain and use a more generic relationship.
e.g.
public static void daysInStockFocus(InternetExplorerDriver driver){
WebElement daysInStockFocus = driver.findElement(By.xpath("//div[#id='top-nav']//a[contains(text(),'Asset Management')]"));
Actions hoverOnDaysInStock = new Actions(driver);
hoverOnDaysInStock.moveToElement(daysInStockFocus).build().perform();
daysInStockFocus.click();
}
public static void terminatedReportCompletedFocus(InternetExplorerDriver driver){
WebElement terminatedReportCompletedFocus = driver.findElement(By.xpath("//div[#id='top-nav']//a[contains(text(),'Terminated Report: Completed')]"));
Actions hoverOnReportWindow = new Actions(driver);
hoverOnReportWindow.moveToElement(terminatedReportCompletedFocus).build().perform();
terminatedReportCompletedFocus.click();
}

Google signup page: Selenium cannot find select listbox

I would like to use selenium to select a value in the Month list box for birthday on google page: https://accounts.google.com/SignUp
When I view page code, the code for the list box looks like:
<select id="BirthMonth" name="BirthMonth">
<option value="">Month</option>
<option value="01" >January</option>
<option value="02" >February</option>
......
<option value="12" >December</option>
</select>
However, when I use Selenium driver.findElements(), I cannot find this select and its option elements. It looks like every list box on this page (as well as gender one) cannot be accessed.
Can anyone give some suggestion how Selenium can access to these elements? Thanks
The code is as follows:
driver.get("https://accounts.google.com/SignUp");
List<WebElement> inputElements = driver.findElements(By.xpath("//select[#name]"));
for(WebElement input: inputElements){
if(input.getTagName().equals("select")){
Select selectinput = new Select(input);
List<WebElement> selects = selectinput.getOptions();
}
}
I did not get the select element I want.
EDIT:
I also try to use Select select1 = new Select(driver.findElement(By.tagName("select"))) but still cannot find this BirthMonth list box. It is wired. There is only one listbox which is inside Javascritpt that can be accessed.
Here's a suggestion for how access these elements in Selenium, with a Java example.
It gets a little messy with CSS Selectors (which I generally prefer) because this month field has some fancy widgets on it to help hide your choices for security reasons. So here we go with XPath as our selector mechanism.
Take notice I broke it down - 1st by selecting the month, and 2nd by selecting the month itself. Hope that helps.
public class Google Month Example {
public static void main(String[] args) throws Exception {
// Just picked Firefox for this example
FirefoxDriver driver;
driver = new FirefoxDriver();
driver.manage().timeouts().implicitlyWait(7, TimeUnit.SECONDS);
// Head to URL
driver.get("https://accounts.google.com/SignUp");
// Get the first click on the month field to generate the listbox pop-up
driver.findElement(By.xpath(".//*[#id='BirthMonth']/div")).click();
// This is ":a" because each item in this month list is assigned a hex value starting at an index of zero
driver.findElement(By.xpath(".//*[#id=':a']/div")).click();
// Check to see if November got selected
if (!driver.findElement(By.xpath(".//*[#id='BirthMonth']/div[1]")).getText().equals("November")) {
driver.close();
throw new RuntimeException("assertText 'November' failed");
}
// Close browser window
driver.quit();
}
}
Update: I realized you wanted to pass in the Month as an argument.
So swap out from the example above:
driver.findElement(By.xpath(".//*[#id=':a']/div")).click();
for the below code:
String month = "November";
driver.findElement(By
.xpath("//div[#class='goog-menuitem']/div[.='" + month + "']")).click();
Second Update:
So at one point you saw the HTML as:
<select id="BirthMonth" name="BirthMonth">
<option value="">Month</option>
<option value="01" >January</option>
<option value="02" >February</option>
......
<option value="12" >December</option>
</select>
But as I look at it in Chrome Dev Tools right now (pressing F12) after clicking on the Month field I see multiple small structure changes (posted what I see in the of the Gist link).Examples include select now becoming span and value="01" now shown as id=":0" (Why the counting starts at zero and not 1). Hope that explains some of why my example is different.

Selenium Xpath Not Matching Items

I am trying to use Selenium's Xpath ability to be able to find an set of elements. I have used FirePath on FireFox to create and test the Xpath that I have come up with and that is working just fine but when I use the Xpath in my c# test with Selenium nothing is returned.
var MiElements = this._driver.FindElements(By.XPath("//div[#class='context-menu-item' and descendant::div[text()='Action Selected Jobs']]"));
and the Html looks like this:-
Can Anyone please point me right as everything that I have read the web says to me that this Xpath is correct.
Thanking you all in-advance.
Please post the actual HTML, so we can simply "drop it in" into a HTML file and try it ourselves but I noticed that there is a trailing space at the end of the class name:
<div title="Actions Selected Jobs." class="context-menu-item " .....
So force XPath to strip the trailing spaces first:
var MiElements = this._driver.FindElements(By.XPath("//div[normalize-space(#class)='context-menu-item' and descendant::div[text()='Action Selected Jobs']]"));
Perhaps you don't take into consideration the time that the elements need to load and you look for them when they aren't yet "searchable". UPDATE I skipped examples regarding this issue. See Slanec's comment.
Anyway, Selenium recommends to avoid searching by xpath whenever it is possible, because of being slower and more "fragile".
You could find your element like this:
//see the method code below
WebElement div = findDivByTitle("Action Selected Jobs");
//example of searching for one (first found) element
if (div != null) {
WebElement myElement = div.findElement(By.className("context-menu-item"));
}
......
//example of searching for all the elements
if (div != null) {
WebElement myElement = div.findElements(By.className("context-menu-item-inner"));
}
//try to wrap the code above in convenient method/s with expressive names
//and separate it from test code
......
WebElement findDivByTitle(final String divTitle) {
List<WebElement> foundDivs = this._driver.findElements(By.tagName("div"));
for (WebElement div : foundDivs) {
if (element.getAttribute("title").equals(divTitle)) {
return element;
}
}
return null;
}
This is approximate code (based on your explanation), you should adapt it better to your purposes. Again, remember to take the load time into account and to separate your utility code from the test code.
Hope it helps.

Selenium Webdriver: Select with display none [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Selenium WebDriver - hidden select and anchor
Before I post my question I just want to tell that I am new to Selenium..
I am trying to select an option from a dropdown. The options display when clicked on the down arrow in the dropdown box. But, when checked in the Firebug, the display style was "none" and when trying to select the option using JUnit webdriver code by using click method in Eclipse, it did not work and it gave the exception - "org.openqa.selenium.ElementNotVisibleException: Element is not currently visible and so may not be interacted with".
Please refer to the attached image for the dropdown and HTML tags.
<select class="size-dropdown mediumSelect selectBox" name="skuAndSize" style="display: none;">
<option value=""></option>
<option value="2545672:S" name="skuId"> S</option>
<option value="2545673:M" name="skuId"> M</option![enter image description here][1]>
<option value="2545674:L" name="skuId"> L</option>
<option value="2545675:XL" name="skuId"> XL</option>
<option value="2545676:XXL" name="skuId"> XXL</option>
<option value="2545677:XXXL" name="skuId"> XXXL</option>
<option value="2545678:XXXXL" name="skuId"> XXXXL</option>
</select>
I looked at this link before posting this question - Selenium WebDriver - hidden select and anchor
But, since I am just starting I am not able to understand clearly.
Note: The same worked in IDE when used clickAt method. But in Webdriver the clickAt method is not present. Can anyone help me in this. Thanks!
Well the matter is Selenium is unable to interact with invisible ( disabled) elemnts. So you need to make element visible. BAsic idea: to make dropdown roll down , then wait with driver.manage.timeout(...) and then click on the appear needed element in dropdown.
Or you can use javascript to click element directly without preceeding dropdown roll down. Js is able to cope with it.
So this approach ALWAYS works:
css1=select[class="size-dropdown mediumSelect selectBox"]>option[value=""]
css2=select[class="size-dropdown mediumSelect selectBox"]>option[value="2545672:S"]
css2=select[class="size-dropdown mediumSelect selectBox"]>option[value="value="2545673:M"]
//.... and so on.....
public void jsClickOn(String cssSelector){
JavascriptExecutor js = (JavascriptExecutor) driver;
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append("var x = $(\'"+cssSelector+"\');");
stringBuilder.append("x.click();");
js.executeScript(stringBuilder.toString());
}
jsClickOn(css1);
jsClickOn(css2);
jsClickOn(css3);
Another way:
using actions builder, advanced user actions API. You can read about it here And code will be smth like that:
WebElement mnuElement;
WebElement submnuElement;
mnEle = driver.findElement(By.Id("mnEle")).click();
sbEle = driver.findElement(By.Id("sbEle")).click();
Actions builder = new Actions(driver);
// Move cursor to the Main Menu Element
builder.moveToElement(mnEle).Perform();
// Giving 5 Secs for submenu to be displayed
Thread.sleep(5000L);
// Clicking on the Hidden SubMenu
driver.findElement(By.Id("sbEle")).click();
But also pay attention on the way how you found css selectors, xpaths verifying it in e.g. firepath, addon to firebug in ffox.
Hope this helps you)
See this screen as example of locating dropdown options.

selenium webdriver select element

I have a select control on my site. I am using page objects to interact with the page. If I do (with the first 2 lines under my class and the selectByValue in my method)
#FindBy(id="foo")
private Select foo;
foo.selectByValue("myValue");
It fails with a null pointer. I also tried without the #FindBy.
Now if I do this in my method it all works fine and selects the correct item
Select foo = new Select(sDriver.findElement(By.id("foo")));
foo.selectByValue("myValue");
Here is the actual web snippet for that control (edited to protect the innocent)
<select id="foo" name="service_name">
<option selected="selected" value="one">one</option>
<option value="two">two</option>
<option value="three">three</option>
</select>
Let me say that I have a work around for my issue but I don't get why the "normal" path is not working.
Thats because the Select class has this constructor:
Select(WebElement element)
See the Javadoc
So if you do something like this:
#FindBy(id="foo")
private WebElement wannabeSelect;
Select realSelect = new Select(wannabeSelect);
realSelect.selectByValue("myValue");
It should work.
BTW, I am using the same approach as you in the "workaround" because I dont wanna cast new WebElement object when I need Select object. But anyways, the
sDriver.findElement(By.id("foo"));
returns WebElement, so thats why its working. You can also do this:
WebElement wannabeSelect = sDriver.findElement(By.id("foo"));
Select foo = new Select(wannabeSelect);
There are two ways to select the option value:
One:
// Denotes option value - technical name
select.selectByValue(fieldValue);
Two:
// Denotes option text that is actually visible to be selected
select.selectByVisibleText(fieldValue);
Other way I achieved this is by using below method for all my onchange dropdownselection boxes. Pass id and selection and it works
public void onchangedropdownselection(String object, String value) {
WebElement obj = driver.findElement(By.id(object));
obj.sendKeys(value);
obj.sendKeys(Keys.UP);
obj.sendKeys(Keys.DOWN);
}
By doing up and down we are initialzing the script onchange.......