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.
Related
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.
I am taking the HTML code from website and then I would like to take the value "31 983" from attribute using Jsoup:
<span class="counter nowrap">31 983</span>
The code below is almost ready, but do not take this value. Could you please help me?:
public class TestWebscrapper {
private static WebDriver driver;
#BeforeClass
public static void before() {
System.setProperty("webdriver.chrome.driver", "src/main/resources/chromedriver.exe");
driver = new ChromeDriver();
}
#Test
public void typeAllegroUserCodeIntoAllegroPageToAuthenticate() {
String urlToAuthencicateToTypeUserCode="https://www.test.pl/";
driver.get(urlToAuthencicateToTypeUserCode);
Document doc = Jsoup.parse(driver.getPageSource());
//how to take below value:
System.out.println(doc.attr("counter nowrap"));
}
#AfterClass
public static void after() {
driver.quit();
}
}
I was trying to use doc.attr, but does not help.
Jsoup uses CSS selectors to find elements in HTML source. To achieve what you want use:
// select the first element containing given classes
Element element = doc.select(".counter.nowrap").first();
// get the text from this element
System.out.println(element.text());
I'm afraid in your case there may be many elements containing classes counter and nowrap so you may have to iterate over them or try different selector to address directly the one you want. It's hard to tell without webpage URL.
Answering you original question, how to select by attribute:
Element element = doc.select("span[class=counter nowrap]").first();
or just:
Element element = doc.select("[class=counter nowrap]").first();
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;
I am using Selenium WebDriver with Java. I am trying to create a method that loops through a list of WebElements to return the first WebElement that contains the text "Ooga Booga", or return null if there are no elements in the list that contains this text.
public class myClass {
private static WebElement element = null;
private static List<WebElement> elements = null;
public static WebElement returnOneElement (WebDriver driver){
elements = driver.findElements(By.cssSelector("someSelector"));
for (WebElement element : elements){
String myText = element.findElement(By.cssSelector("classC")).getText();
if (myText.contains("Ooga Booga")) {
return element;
}
}
return null;
}
This all works fine until I run into an element that does not have this attribute:
String myText = element.findElement(By.cssSelector("classC")).getText();
How can I continue to loop through my List while ignoring any elements that do not have "someDiv" inside of it?
<div class="someSelector">
<div class="classA">
<div class="classB">
</div>
<div class="someSelector">
<div class="classA">
<div class="classB">
<div class="classC">
</div>
I need to search for text inside div "classC".
Use findElement-S method as shown below.
for (WebElement element : elements) {
List<WebElement> mightHaveSomeDiv = element.findElements(By.cssSelector("someDiv"));
if (mightHaveSomeDiv.size() > 0) {
//Can iterate the list if you expect more than one div of type someDiv.
String myText = mightHaveSomeDiv.get(0).getText();
if (myText.contains("Ooga Booga")) {
return element;
}
}
}
Btw, I would recommend to try and break away from static methods like this. It will make your life a living hell later on because of it being static. Everything using it starts to want static.
Anyway, lets break it down. This cssSelector will allow you to grab the child divs by the tagname instead of classname.
By.cssSelector(".someSelector div")
Now that we have a list of WebElement, which are all div elements, lets just look for the text in the div. No need to worry about class attribute
public static WebElement returnOneElement (WebDriver driver){
elements = driver.findElements(By.cssSelector(".someSelector div"));
for (WebElement element : elements){
if(element.getText().contains("Ooga Booga")) {
return element;
}
}
return null;
}
Alternatively, you may find the target directly with xpath locators such as
//div[#class='someSelector']//div[contains(.,'Ooga Booga')]
Be warned though, if you have multiple div that contains the text "Ooga Booga", you will get multiple WebElements, and what you do with it next may not be what you expect. Actually, this warning should also apply to the loop. It will break out of your first div element that contains "Ooga Booga". You will have to adjust the logic if you want exact match.
Here is your answer.. Firstly Declare a parent web locator
WebElement element1 = driver.findElement(By.id("##abc##"));
Now in case you want to perform any action or anything within the locator defined above then you can do it as follows:
element1.findElement(By.xpath(" . //##yourFurtherLocABC")).click();
element1.findElement(By.xpath(" . //##yourFurtherLocXYZ")).getText();
Important = Do remember to keep a . at the beginning of any child elements!
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