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.......
Related
Is there a way to select by attribute? We have select drop down with incomplete visible text. We have to rely only on title. Is there a way to select by attribute?
My HTML looks something like
<select id="some ID" name="some Name" class="some class"
<option value="random number" title="testing pvt ltd">testing...</option>
<option value="random number" title="selenium HQ documentation">testing...
</option>
<option value="random number" title="selenium HQ API Request">selenium HQ...
</option>
Not natively, but nothing prevents you from implementing that method yourself, should you need it.
Something like this in C# should do the trick. Translation in your favourite language shouldn't be too hard.
public IWebElement GetWebElementByAttributeValue(string tagType, string attributeName, string attributeValue)
{
//finds all tags of a type, for example h1,a,etc...
//Here Driver is my instance of WebDriver
var allTags = Driver.FindElements(By.XPath("//" + tagType));
//iterate over all elements of that tag, and find the one whose attribute value you want
foreach (var v in allTags)
{
if ((v.GetAttribute.getText().equals(attributeName))
return v;
}
return null;
}
for you you would call it like that :
WebElement chosenOption = GetWebElementByAttributeValue("option","title","testing pvt ltd");
Hope this helps !
Naturally - the locators will go after the specific attribute and value.
Here are samples based on your source; xpath:
//select/option[#title="testing pvt ltd"]
If you're not familiar with xpath, it reads - select the option element that is a direct descendant (e.g. a child) of a select one, and has an attribute title (note the # char, which denotes thst an attribute name follows) with that value.
Absolutely the same with CSS:
select>option[title="testing pvt ltd"]
In general in CSS you can skip the double quotes around the value, if there's no whitespace in it - not like in your case, they are needed here.
el("input[value*='Edit'][type='submit']")
works without issue. I am using Fluentlenium and it makes thing a whole lot easier.
Use selectByValue method under Select class.
Actions a= new Actions(driver);
WebElement mainmenu=driver.findElement(By.xpath(".//*[#id='yui-gen2']/a"));
a.moveToElement(mainmenu).build().perform();
WebElement Sub = driver.findElement(By.xpath(".//*[#id='helpAbout']"));
a.moveToElement(Sub).build().perform();
Sub.click();
Code couldn't able to click on submenu it just stops at 3rd line.
With selenium you should be able to just do the following:
Select variableName = new Select(DropDownElementLocator);
variableName.selectByVisibleText("Whatever");
// or
variableName.selectByIndex(1);
Your code is 90% correct, just replace following code:
a.moveToElement(Sub).click().perform();
build() method works for hover on element,and after hover on it we have to click element.
Once you Mouse Hover over the element identified as By.xpath(".//*[#id='yui-gen2']/a") and therefafter invoke moveToElement(mainmenu), build(), perform(), at this stage the element identified as By.xpath(".//*[#id='helpAbout']") is visible and interactable. So you need to invoke click() directly as follows :
Actions a= new Actions(driver);
WebElement mainmenu=driver.findElement(By.xpath(".//*[#id='yui-gen2']/a"));
a.moveToElement(mainmenu).build().perform();
WebElement Sub = driver.findElement(By.xpath(".//*[#id='helpAbout']"));
Sub.click();
import org.openqa.selenium.support.ui.Select;
WebElement selectElement;
selectElement= driver.findElement(By.id("yourElementId"));
or
selectElement driver.findElement(By.xpath("yourElementXpath"));
Select selectObject = new Select(selectElement);
The Select object will now give you a series of commands that allow you to interact with a element. First of all, there are different ways of selecting an option from the element.
<select>
<option value=value1>Bread</option>
<option value=value2 selected>Milk</option>
<option value=value3>Cheese</option>
</select>
// Select an <option> based upon the <select> element's internal index
selectObject.selectByIndex(1);
// Select an <option> based upon its value attribute
selectObject.selectByValue("value1");
// Select an <option> based upon its text. Example: Bread
selectObject.selectByVisibleText("Bread");
I have a span as below:
<div class="ag-cell-label">
<span class="glyphicon glyphicon-asterisk" title="This is a draft row. It can only be seen by you. "/>
</div>
I want to get the text "glyphicon glyphicon-asterisk". How can I do it.
The validation of the test case is to check weather asterisk is not present after clicking on save button.
Assuming you are using Java, You should try as below :-
WebDriverWait wait = new WebDriverWait(driver, 10);
WebElement el = wait.until(ExpectedConditions.visibilityOfElementLocated(By.xpath("//div[#class='ag-cell-label']/span")));
String class = el.getAttribute("class");
Hope it will help you...:)
This is a simple case of:
Locate the WebElement using a suitable locator strategy (Class, CSS, XPath etc) and assign it to a new WebElement object.
Use the .getAttribute(String arg) method with an argument of "class" to retrieve the required class value from the WebElement object instantiated in the first step and assign it to a new String object.
Use the .contains(String arg) method with an argument of "asterisk" to determine whether the "class" attribute retrieved in the second step contains the text "asterisk".
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.
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.