Selenium - Click list item from unordered list - Java - java

I am trying to click on an option (array of images) from an unordered list using Selenium Java.
I have tried doing a click on the className of "attachment" but that doesn't seem to pick up the list item that I need to click on.
Is there anyway to pick up something like the data-id?
The code that I have tried:
public void click(By by) {
waitProvider.waitFor().waitUntilElementIsClickable(by);
WebElement clickableElement = locate(by);
Actions actions = new Actions(webDriverProvider.driver());
actions.moveToElement(clickableElement);
actions.click().perform();
}
and then we do:
public void selectFirstImage() {
click("attachment");
}
locate:
public WebElement locate(By by) {
waitProvider.waitFor().waitUntilVisibilityOfElementLocatedBy(by);
scrollIntoView(by);
return webDriverProvider.driver().findElement(by);
}

I think click method call is incorrect.
Since click expects By not String it should look like this:
click(new ByCssSelector(".attachment-preview"));

Related

Selenium cannot find ul Element that is visible on Page

I'm currently testing an email service, and upon opening a list of options to filter email, I want to be able to automate clicking on an option in the list. The code for the list is:
However, selenium cannot find this element, even though I can find it by searching the HTML using CTRL+F. The code I'm currently using to try and find and click this list element is:
wait.until(ExpectedConditions.visibilityOfElementLocated(org.myorg.automation.Objects.ManageEmails.Locators.FilterList));
Select dropdown = new Select(driver.findElement(org.myorg.automation.Objects.ManageEmails.Locators.FilterList));
dropdown.selectByVisibleText("Unread");
The xpath of the list is:
/html/body/div[7]/div/div/div/div/div/div/ul
Any help would really be appreciated!!
The problem is that you don't have a select in this case and the: Select dropdown = new Select(); wont work. You'll need a custom method to select a value from that list
public class Testing {
public WebDriver driver;
#Test
public void TestSomething() {
driver = new ChromeDriver();
driver.get("<the url where this list is present>");
// assuming that the ul list is unique on the page if not find another way to get it
WebElement ulListParent = driver.findElement(By.xpath("//ul[contains(#class,'ms-ContextualMenu-list is-open')]"));
SelectBasedOnValue(ulListParent, "Unread");
driver.close();
}
public void SelectBasedOnValue(WebElement parentElement, String optionValue) {
parentElement.findElement(By.xpath(String.format("//li[text()='%s']", optionValue))).click();
}
}

How I can provide the click on a suggestions-result (dropdown menu) in wikipedia with a selenium test in java?

I try to write a selenium test cases in java and I am having a problem. The test involves a click on a drop down menu. But I can't reach this...
Here are my steps. First I go to the german wikipedia:
#Given("^You want to search for \"Baum\" on \"([^\"]*)\"$")
public void youWantToSearchForOnWikipediaOrg(String page) throws Throwable
{
System.setProperty("webdriver.chrome.driver",
"C:\\...\\chromedriver_win32\\chromedriver.exe");
driver = new ChromeDriver();
driver.get("https://"+page+"/wiki/Wikipedia:Hauptseite");
}
Then I search for the word "Baum":
#Then("^You tipp the letters \"([^\"]*)\", \"([^\"]*)\" and \"([^\"]*)\"$")
public void youTippTheLettersAnd(String letter1, String letter2, String letter3) throws Throwable
{
Thread.sleep(5);
driver.findElement(By.xpath("//input[#id='searchInput']")).sendKeys(letter1);
driver.findElement(By.xpath("//input[#id='searchInput']")).sendKeys(letter2);
driver.findElement(By.xpath("//input[#id='searchInput']")).sendKeys(letter3);
Thread.sleep(25);
}
Now a dropdown menu appaers an I want to click on the entry "Baum".
#Then("^Click on the appearing Baum$")
public void clickOnTheAppearing() throws Throwable
{
//Thread.sleep(50);
driver.findElement(By.xpath("//a/div")).click();
}
But xpath can't find the element.
I try different xpath and css, but nothing helps...
Examples:
//*[#classname='mw-searchSuggest-linkinput']//*[text()='Baum']
/html/body/div[6]/div/a[1]/div/span
/html/body/div[6]/div/a[1]/div
body > div.suggestions > div > a:nth-child(1) > div > span
The website:
You just need to put some wait and after that element load use the following:
Thread.sleep(3000);
driver.findElement(By.xpath(".//a[#title='Baum']")).click();
Hope it helps you!
Instead of click, Select the value from drop down.
Webelement e1=driver.findElement(By.id(dropdownId));
Select s1=new Select(e1);
s1.selectByVisibleText("Baum");//selecting value from dropdown

Getting webelement from dynamic text

firstli i write my scenario:
go http://demo.opencart.com/
search ipod
click add to compare in every found items
here is my code (java webdriver pagefactory)
searchresultspage (my object page)
#FindBy(id = "compare-total")
WebElement numberOfProductToCompare;
public void compareAllItems() {
for (WebElement compareButtons: compareButton) {
compareButtons.click();
}
}
public void areAllItemsClickedCompare() {
String text = numberOfProductToCompare.getText();
System.out.println(text);
}
My main test class
#Test
public void addToCompare() {
searchresultspage.compareAllItems();
searchresultspage.areAllItemsClickedCompare();
}
i click all compare buttons and i want to get number from link Product Compare (4) but when i use searchresultspage.areAllItemsClickedCompare(); then System.out.println(text); print me Product Compare (0), even this method is after adding to compare (should be should be Product Compare (4)) Dont know what to do, some advice?
Think, the problem appears because the compare-total element is captured by Selenium on class instantiating, but when its content is updated on the page, it doesn't affect the captured value.
Try to capture the compare-total element only after all checkboxes were clicked:
public void areAllItemsClickedCompare() {
WebElement numberOfProductToCompare = driver.findElement(By.id("compare-total"));
String text = numberOfProductToCompare.getText();
System.out.println(text);
}
Where driver is your WebDriver instance.

Mockito stubbing void methods

I am currently writing unit tests for my selenium project and I am using Mockito to mock up my webelements and drivers.
The problem I am having is that I have a function that is used to change the radio option in a list of radio buttons but I am having a problem with this. the code looks like this:
#Test
public void testChangeRadioState(){
WebElement mockElement = mock(WebElement.class);
List<WebElement> mockElementList = new ArrayList<>();
WebElement selectedMockElement = mock(WebElement.class);
/*The when statements*/
when(selectedMockElement.isSelected()).thenReturn(true);
doReturn(when(mockElement.isSelected()).thenReturn(true)).when(mockElement).click();
doReturn(when(selectedMockElement.isSelected()).thenReturn(false)).when(mockElement).click();
/*Add a selected and a none selected element to the list*/
mockElementList.add(mockElement);
mockElementList.add(selectedMockElement);
/*The method that is beeing tested*/
elementSetter.changeRadioState(mockElementList);
Assert.assertTrue("The radio state was not selected",mockElement.isSelected());
}
What I am trying to do int he doReturn part is to tell the element "mockElement" that when it recieves a click it should allways return true on a isSelected() call. but since Click() is a void function it won't let me do that. Anybody know a way around this?
Ok, it is separate topic - what you are testing and would I mock things so deep.
I would just rewrite test like this:
#Test
public void testChangeRadioState() {
WebElement mockElement = mock(WebElement.class);
WebElement selectedMockElement = mock(WebElement.class);
List<WebElement> mockElementList = new ArrayList<>();
/*The when statements*/
when(selectedMockElement.isSelected()).thenReturn(true);
// By default mockito will return false but maybe I want to highlight
// that this is important
when(mockElement.isSelected()).thenReturn(false);
/*Add a selected and a none selected element to the list*/
mockElementList.add(mockElement);
mockElementList.add(selectedMockElement);
/*The method that is beeing tested*/
elementSetter.changeRadioState(mockElementList);
verify(selectedMockElement).click();
// according to test method name I would add
// one more verification that something was dis-selected
}
Another variant with state which I think has unnecessary mocks:
boolean selected;
#Test
public void testChangeRadioState() {
selected = false;
WebElement mockElement = mock(WebElement.class);
WebElement selectedMockElement = mock(WebElement.class);
List<WebElement> mockElementList = new ArrayList<>();
/*The when statements*/
when(selectedMockElement.isSelected()).thenReturn(true);
doAnswer(new Answer<Object>() {
public Object answer(InvocationOnMock invocation) {
selected = true;
return null;
}
}).when(mockElement).click();
/*Add a selected and a none selected element to the list*/
mockElementList.add(mockElement);
mockElementList.add(selectedMockElement);
/*The method that is beeing tested*/
elementSetter.changeRadioState(mockElementList);
Assert.assertTrue("The radio state was not selected", selected);
// according to test method name I would add
// one more verification that something was dis-selected
}
But again there is misleading in names. For example I would expect that there are elements which don't become selected when they clicked. Question again about what you are testing

WebElement.clear() fires javascript change event - Alternatives?

I use selenium IDE to initially record the tests and save them as Java WebDriver tests.
When I go into an input field, delete all the text and enter a new value, it records that as 2 commands:
driver.findElement(By.id("username")).clear();
driver.findElement(By.id("username")).sendKeys("johnnyleitrim");
One problem with this for me is that the clear() event fires a Javascript change event for the "username" field. This does not happen when I use the browser itself - it waits until the field loses focus before firing the change javascript event, and that's what I want to emulate in Selenium.
The reason I need this is that I do validation on the change() event, and when change is called with an empty value, it displays an alert telling the user the information is invalid - and this alert stops Selenium
So how do I clear the field without using WebElement.clear()?
You can avoid using the clear() method and use the Actions class to clear and set text in one go, therefore firing the onchange() event only once the text is set.
Call the below method like:
ClearAndSetText(By.id("username"),"johnnyleitrim");
The method clicks the element, selects the existing text using shift+home keys,clears using backspace, and then types in the new text - just like how a user would do.
public void ClearAndSetText(By by, string text)
{
WebElement element = driver.findElement(by);
Actions navigator = new Actions(driver);
navigator.click(element)
.sendKeys(Keys.END)
.keyDown(Keys.SHIFT)
.sendKeys(Keys.HOME)
.keyUp(Keys.SHIFT)
.sendKeys(Keys.BACK_SPACE)
.sendKeys(text)
.perform();
}
You can try it using JavaScriptExecutor (although I haven't tested it).
JavaScriptExecutor js = (JavaScriptExecutor) driver;
js.executeScript("document.querySelector(\"input[id='username']\").value = ''");
Seems like it's a known Selenium bug. There were a few options as workarounds mentioned on the bug page, but they all meant having to "heavily" modify the code returned from Selenium IDE. Instead, I decided to create a Proxy which would do the work for me without too much modification to the IDE generated code:
protected WebElement findElement(By criteria) {
try {
WebElementHandler webElementHander = new WebElementHandler(seleniumWebDriver.findElement(criteria));
return (WebElement) Proxy.newProxyInstance(getClass().getClassLoader(), new Class[]{WebElement.class}, webElementHander);
} catch (NoSuchElementException e) {
logger.error("Could not find " + criteria + " on page " + seleniumWebDriver.getCurrentUrl());
throw e;
}
}
private class WebElementHandler implements InvocationHandler {
private WebElement proxiedElement;
private WebElementHandler(WebElement proxiedElement) {
this.proxiedElement = proxiedElement;
}
#Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if (method.getName().equals("clear")) {
Keys[] keys = new Keys[proxiedElement.getAttribute("value").length()];
for (int i = 0; i < keys.length; i++)
keys[i] = Keys.BACK_SPACE;
proxiedElement.sendKeys(Keys.chord(keys));
return null;
}
return method.invoke(proxiedElement, args);
}
}

Categories