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.
Related
I'm brand new to javascript, dojo and HTML and I've searched everywhere for examples of this and cannot find any.
I have a map with some feature points and a find task to highlight the feature points on the map, and display them in a grid with it's field attributes. This works great when I specify the search field as:
findParams.searchFields = ["LOCATION"];
But if I add:
findParams.searchFields = ["LOCATION", "MODEL_NUM"];
The grid displays results from multiple fields (ie. searching for attributes in LOCATION "A" would also find attributes in MODEL_NUM containing the letter "A"). So I decided to add a drop down menu select to specify which field to search in (one at a time) so the results are more precise.
So I added the following dijit:
<select id="fieldSelect" data-dojo-type="dijit/form/Select" name="fieldSelect">
<option value="" selected="selected">Select a field</option>
<option value="MODEL_NUM">Model Number</option>
<option value="LOCATION">Location</option>
<option value="NUM_DEFICIENCIES">Number of Deficiencies</option>
<option value="INSTALL_DATE">Install Date</option>
</select>
I then modified the search field statement to:
findParams.searchFields = "[" + "\"" + dom.byId("fieldSelect").value +
"\"" + "]";
When I click my search button I get an Uncaught TypeError: a.join is not a function (FindParameters.js:5)
I hope this is enough information. Does anyone have a solution or a recommendation?
UPDATE
After a suggestion to pass an array and not a string to the findParams.searchFields, I made the following changes:
findParams.searchFields = [];
findParmas.searchFields.push(dom.byId("fieldSelect").value);
This still gave me attribute results from multiple fields. After running a couple small tests:
var selectedField = document.getElementById('fieldSelect').value;
var index = selectedField.options[selectedField.selectedIndex].value;
And:
var selectedField = dom.byId('fieldSelect').value;
I'm finding that in the Chrome developer tools debugger, when I created a breakpoint at that line and executed the statement, both examples had the value of selectedField as 'undefined'.
Is this an issue of not getting the value from the drop down select dijit?
If no value is passed to findParams.searchFields, the API assumes all fields are valid, which is why I'm getting attribute results from multiple fields.
Thanks.
Use dijit.byId instead of dom.byId.
The following works for me:
var value = dijit.byId("fieldSelect").value;
if ("" != value) {
findParams.searchFields = [value];
} else {
findParams.searchFields = ["MODEL_NUM", "LOCATION", "NUM_DEFICIENCIES", "INSTALL_DATE"];
}
I found the problem.
Ultimately it was the registry.byId that led me to the answer, I had to rearrange some code after I realized the searchFields was in the wrong function and not in the function that is called when I click the search button.
But when accessing the dijit, the only thing that worked was registry.byId to access the dijit node and pass the value of the selected value into my searchFields.
Thanks.
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.
This question already has answers here:
Selenium WebDriver - get options from hidden select [closed]
(2 answers)
Closed 7 months ago.
I'm having a big problem with select on one page.
Code:
<select name="fw3k_ad_input_et_type_group" class=""
id="_id_fw3k_ad_input_et_type_group"
onchange=" eurotax.change_type_group( this.value ); "
style="display: none; ">
<option value="0"> --- odaberite tip --- </option>
<option value="-1" class="special">> nema mog tipa </option>
<option value="16390">CD</option>
<option value="17605">S</option>
<option value="17636">SE</option>
</select>
--- odaberite tip ---
Select is hidden and a href="" is visible part that changes its text depending on a selected option.
I don't know how to manage that. I can get all options with JavascriptExecutor and I can use a.click() to view dropdown box but I don't know how to click on some option.
I have tried to use Select class and .getOptions() method but it doesn't work with hidden select and I cannot change <a href=""> text.
A little confused with the question but have you you tried
WebElement element = driver.findElement(By.id("fw3k_ad_input_et_type_group"));
Select select = new Select(element);
Then use either
select.selectByValue(value);
select.selectByVisibleText(text);
select.selectByIndex(index);
1st way:
it is not the problem to click any element using the same js. As you know how to get any option the last actions remaning is to perform a click.
This should work for you:
WebElement hiddenWebElement =driver.findElement(By(..selector of the element....));
((JavascriptExecutor)driver).executeScript("arguments[0].click()",hiddenWebElement);
2nd way:
String cssSelector= ...//i gave them in your previous question
JavascriptExecutor js = (JavascriptExecutor) driver;
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append("var x = $(\'"+cssSelector+"\');");
stringBuilder.append("x.click();");
js.executeScript(stringBuilder.toString());
3rd 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();
You can also some additional info here
Hope this somehow helps you)
driver.findElement(By.name("_id_fw3k_ad_input_et_type_group")).sendKeys("16390");
worked for me for something very similar.
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.
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.......