Unable to find elements with multiple classes assigned - java

If I used this code:
#FindBy(how = How.XPATH, using= ".//*[#class='leaflet-control-pan leaflet-control']")
private WebElement movingPageButtonsLocator;
The element movingPageButtonsLocator is found, but if I use following code it doesn't:
#FindBy(how = How.CLASS_NAME, using= "leaflet-control-pan leaflet-control")
private WebElement movingPageButtonsLocator;
Aren't both the same ?
If not, how is How.XPATH different from How.CLASS_NAME in this case ?

This can be done using CSS Selector
#FindBy(how = How.CSS, using= ".leaflet-control-pan.leaflet-control")

#FindBy(how = How.XPATH, using= ".//*[#class='leaflet-control-pan leaflet-control']")
private WebElement movingPageButtonsLocator;
Will match any XPATH query, which can be anything on the page. Where className is a single class on an element if you want to match multiple classes on an element you need to use #FindBys.
According to the JavaDoc, this is how it should be:
#FindBys({#FindBy(how = How.CLASS_NAME, using= "leaflet-control-pan"),
#FindBy(how = How.CLASS_NAME, using= "leaflet-control") })
private WebElement movingPageButtonsLocator;
or more succinctly:
#FindBys({#FindBy(className = "leaflet-control-pan"),
#FindBy(className = "leaflet-control") })
private WebElement movingPageButtonsLocator;
#FindBys is a logical AND it will only find where both class are on an element. I think it should have been called #FindByAll to be semantically correct
Used to mark a field on a Page Object to indicate that lookup should
use a series of #FindBy tags in a chain as described in ByChained
#FindAll is a logical OR it find where any of the specified criteria match an element. I think it should have been called #FindByAny to be semantically correct
Used to mark a field on a Page Object to indicate that lookup should
use a series of #FindBy tags It will then search for all elements that
match any of the FindBy criteria. Note that elements are not
guaranteed to be in document order.

if you will look at carefully how = How.CLASS_NAME says class name and not class names. see singular vs plural.
So How.CLASS_NAME should be used only when a element could be identified by single class.
Following will work, not sure if it will give you an element you are interested in or not.
#FindBy(how = How.CLASS_NAME, using= "leaflet-control-pan")
private WebElement movingPageButtonsLocator;

Related

Unable to find locators(Xpath,Css) ,in the webpage

I am trying to automate application,tried first to find xpath or CSS locators unable to find looks no frame also inside the element.
I am able to handle using JavaScript but unable to enter full text in the search box,it's trimming some text,,please help me.
JavaScript which i tried.
((JavascriptExecutor)driver).executeScript("return document.querySelector('#app').shadowRoot.querySelector('#base > wego-search-form').shadowRoot.querySelector('div > wego-hotel-search-form').shadowRoot.querySelector('#loc').shadowRoot.querySelector('#item0 > div.disable-select.city-country-name').click();");
((JavascriptExecutor)driver).executeScript("return document.querySelector('#app').shadowRoot.querySelector('#base > wego-search-form').shadowRoot.querySelector('div > wego-hotel-search-form').shadowRoot.querySelector('#dates').shadowRoot.querySelector('#depart').shadowRoot.querySelector('#btn').click();");
My scenario i want to click search form and enter some destination details,If possible anyway i can handle this case using locators suggest me
Shadow DOM Elements are used in this website. Shadow DOM provides encapsulation for the JavaScript, CSS, and templating in a Web Component.
Shadow DOM allows hidden DOM trees to be attached to elements in the
regular DOM tree — this shadow DOM tree starts with a shadow root,
underneath which can be attached to any elements you want, in the same
way as the normal DOM.
Refer this To get details about it or for more details Google it.
Now handle Shadow element take reference from this blog. I've tried the below code to enter text as you expected and its working for me.
public static WebDriver driver;
public static void main(String[] args){
System.setProperty("webdriver.chrome.driver", "driver_path");
driver = new ChromeDriver();
driver.get("https://www.wego.com.my/hotels");
driver.manage().timeouts().implicitlyWait(15, TimeUnit.SECONDS);
driver.manage().window().maximize();
WebElement root1 = driver.findElement(By.id("app"));
WebElement shadowRoot1 = expandRootElement(root1);
WebElement root2 = shadowRoot1.findElement(By.tagName("wego-search-form"));
WebElement shadowRoot2 = expandRootElement(root2);
WebElement root3 = shadowRoot2.findElement(By.tagName("wego-hotel-search-form"));
WebElement shadowRoot3 = expandRootElement(root3);
WebElement root4 = shadowRoot3.findElement(By.id("loc"));
WebElement shadowRoot4 = expandRootElement(root4);
shadowRoot4.findElement(By.cssSelector("div.root-container div.container")).click();
WebElement element = shadowRoot4.findElement(By.id("searchKeywordInput"));
Actions action = new Actions(driver);
action.click(element).sendKeys(Keys.chord(Keys.CONTROL, "a"));
element.sendKeys(Keys.DELETE);
element.sendKeys("narendra");
}
public static WebElement expandRootElement(WebElement element) {
WebElement newElement = (WebElement) ((JavascriptExecutor) driver).executeScript("return arguments[0].shadowRoot", element);
return newElement;
}
Updated
As an alternative of sendKeys(), JavascriptExecutor can be used to set the value of text box. Use below code
WebElement element = shadowRoot4.findElement(By.id("searchKeywordInput"));
JavascriptExecutor javascriptExecutor = (JavascriptExecutor) driver;
javascriptExecutor.executeScript("arguments[0].value='Your Text Goes Here';", element);
I've tested this so many time and this is working fine in each case.
Note: using JavascriptExecutor may not trigger the search result auto suggestion.

Selenium Webdriver - Java - How to click checkbox based on product

I would like to click checkbox based on link text. There are several checkbox in the page so using the link text I wanted to find value of the checkbox so that I can click on the checkbox
Note # All values are dynamically generated
Can you please help correct the code to include this logic. Thanks
driver.get(new URI(driver.getCurrentUrl()).resolve("/admin/lms/tag").toString());
String tag_name = sheet1.getRow(j).getCell(0).getStringCellValue();
driver.findElement(By.linkText(tag_name)).click();
WaituntilElementpresent.isExist();
String tag_value = sheet1.getRow(j).getCell(1).getStringCellValue();
driver.findElement(By.cssSelector("a[href*='"+tag_value+"']")).click();
WaituntilElementpresent.isExist();
String product = sheet1.getRow(j).getCell(2).getStringCellValue();
WaituntilElementpresent.isExist();
driver.findElement(By.cssSelector("input[name='products[]'][value='11']")).click();
https://i.stack.imgur.com/mOBY2.png
You could use an xpath like this:
//tr[.//*[text()='OPIOIDMORTEPID']]//input
this means to locate the td that has this exact text and find the input from it.
If you want to use partial text then:
//tr[.//*[contains(text(), 'MORTEPID')]]//input
You can do it with the following strategy:
find the link by using the link text
get the parent tr element
from there, find the input element of the checkbox
click on the checkbox
This can be done as follows:
WebElement link = driver.findElement(By.linkText("OPIOIDMORTEPID"));
WebElement trElement = link.findElement(By.xpath("../.."));
WebElement checkboxElement = trElement.findElement(By.tagName("input"));
checkboxElement.click();
Check this out:
Get a list of checkbox WebElements that have a common locator i.e. a common class name or tag name (this WebElement would have to have the text or be a parent of the element that has the text).
List<WebElement> checkBoxElements = webDriver.findElements(By.cssSelector("checkbox"));
Iterate through the list and check if the WebElement has the text you are looking for. If it does, click it!
for (WebElement e : checkBoxElements) {
if (e.getText().contains("Something dynamic")) {
e.click();
}
}
Be happy that this works.
I would write this section as a function so that it's reusable.
public static void selectByProductName(String value)
{
driver.findElement(By.xpath("//tr[//a[text()='" + value + "']]/td/input")).click();
}
and then call it like
selectByProductName("OPIOIDMORTEID");

Identifying which web form element is selected after pressing tab key via selenium web-driver java?

I am using the sendKeys(key,Keys.TAB) method to navigate through a form.
Actions action = new Actions(driver);
CharSequence key = null;
for(int i=0;i<42;i++)
{
action.sendKeys(key,Keys.TAB).build().perform();
}
At the end of every action(a tab key press) I want to know which form element is selected
I want to reach to the 42nd element of the form and cross check whether its the desired element and for that i need to retrieve some of its information.
I am new to selenium and I am not able to figure out a way to achieve this.
You can use WebDriver's TargetLocator class for this purpose.
WebElement currentElement = driver.switchTo().activeElement();
This will return you with current element it focussed currently. If no element is focussed it will return you the body element, which is the case when u launch your browser.
Internally it will be returning u the element returned by document.activeElement. So to verify u can always run as:
JavascriptExecutor js = (JavascriptExecutor) driver;
WebElement currentElement = (WebElement) js.executeScript("return document.activeElement");

Using #FindBy to find WebElementS

We have a list of elements specified by "//input[contains(#name,'smcNetwork')]".
I am used to finding a webelement like
#FindBy(xpath = "//*[id='myId']") private WebElement myelement;
But, as per subject the xpath I mentioned returns an array (or list I guess) where I would do
List<WebElement> networks = driver.findElementsBy( xpath = "//input[contains(#name,'smcNetwork')]")
I would like to do this in a FindBy but it did not seem to work:
#FindBy( xpath = "//input[contains(#name,'smcNetwork')]") private List<WebElement> networks;
but that was returning null. Can you do this somehow?
You can do something like this.
#FindAll({#FindBy(xpath = "yourpath")})
public List<WebElement> networks;
To locate web element using #FindBy, you can use below snippet
#FindBy(xpath = "xpathValue")
private static WebElement xpathName;
here, you can change access level by making it as public or private/protected.
If you are making it as private then use this locator within that class and define a common method as public.

Is it possible to get By object having WebElement

I'm using #FindBy annotations to locate WebElements. But I want to use these WebElements in methods as parameters. I had success with this only if WebElement was found on page. But if I want to wait for it I must use By (with same locator) instead.
E.g.
private static final String SEARCHFIELD_LOC = "#search input[placeholder]";
#FindBy(css = SEARCHFIELD_LOC)
public WebElement searchField;
public By searchField_by = new By.ByCssSelector(SEARCHFIELD_LOC);
That way I can use this WebElement as By object in some method, like
public boolean isElementDisplayedWithWait(final By by) { .... }
So for each element I have 4 lines of code. I'm to lazy and searching for a way to simplify that.
I found totally another solution. I will store my locators as strings.
public String searchField = ".slide.slide_search input[placeholder]"
So only 1 line of code per locator. And I hope supporting only CSS locators will be enough. I will NOT use #FindBy for getting WebElements. Instead, I will get WebElements using special method that will wait for element and will log what's going on. I will implement getting WebElement like this:
WebElement we = wait.until(ExpectedConditions.visibilityOfElementLocated(new By.ByCssSelector(locator)));
where wait is
Wait<WebDriver> wait = new FluentWait<WebDriver>( driver )
.withTimeout(timeout, TimeUnit.SECONDS)
.pollingEvery(1, TimeUnit.SECONDS)
.ignoring( StaleElementReferenceException.class ) ;
The alternate of having wait/assertions/verification methods with webelement itself is available with extended webelement in QAF formerly ISFW. For example:
#FindBy(css = SEARCHFIELD_LOC)
public WebElement searchField;
searchField.waitForPresent();
searchField.assertPresent(); //auto wait
searchField.verifyPresent(); //auto wait
Reference:
QAF Selenium testing-frameworks
ISFW FAQ

Categories