In webpage i have multiple grids like below
As you can see not all the web elements are in view. We need to scroll to see other elements.
This grid have around 20 rows and 10 columns. Number of rows will change as per scenario.
My requirement is to fetch data of all the web elements of this grid
I have written web elements as below
#FindBy(xpath = "xpath here")
private static List<WebElement> sampleGridDate; (This should return all web elements from date column)
#FindBy(xpath = "xpath here")
private static List<WebElement> sampleGridCode; (This should return all web elements from code column)
I am fetching data with below code
for (int i = 0; i < sampleGridDate.size(); i++) {
scrollToViewElement(driver,sampleGridDate.get(i));
row.setDate(sampleGridDate.get(i).getText());
scrollToViewElement(driver,sampleGridCode.get(i));
row.setCode(sampleGridCode.get(i).getText());
.....so on
}
public static void scrollToViewElement(WebDriver driver, WebElement element) {
JavascriptExecutor js = (JavascriptExecutor) driver;
js.executeScript("arguments[0].scrollIntoView();", element);
}
**
Problems i am facing are
sampleGridDate.size() returns 16 instead of 20
this for loop runs only once as sampleGridDate is not found after first iteration (stale webelement exception)
**
How do i fix this
Related
Im using this method to retrieve all src from div classes. For example in the page from my code there are 5 elements, but when I run this code I get only 2 src. And if I run my code multiple times, sometimes it returns all of 5 elements.
public static void main(String[] args) throws IOException, URISyntaxException {
System.setProperty("webdriver.chrome.driver", "S:\\behance-id\\src\\main\\resources\\chromedriver.exe");
WebDriver driver = new ChromeDriver();
driver.get("https://www.behance.net/gallery/148589707/Hercules-and-Randy");
List<WebElement> firstResult = new WebDriverWait(driver, Duration.ofSeconds(10))
.until(ExpectedConditions.presenceOfAllElementsLocatedBy(By.xpath("//div[#class='ImageElement-root-kir ImageElement-loaded-icR']/img")));
for (WebElement webElement : firstResult) {
System.out.println(webElement.getAttribute("src"));
}
driver.quit();
}
Also tried to add this line, but it didn't help:
((JavascriptExecutor)driver).executeScript("window.scrollTo(0, document.body.scrollHeight)");
So this script doesn't return all of needed elements even though they are the same class.
Page source code looks like:
ExpectedCondition<java.util.List<WebElement>> presenceOfAllElementsLocatedBy(By locator)
Above is for checking that there is at least one element present on a web page and will break as soon as it find one, it will not wait for 5 elements.It returns true as soon as elements.size>0
You need to add to some other wait to make sure all elements are loaded before you do findelements
Below will wait for count of elements be 5
WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(30));
wait.until(new ExpectedCondition<Boolean>() {
public Boolean apply(WebDriver driver) {
int elementCount = driver.findElements(By.xpath("xxxx")).size();
if (elementCount == 5)
return true;
else
return false;
}
});
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 trying to do automation for one of my application using selenium webdriver. The problem is I am trying to fetch the data from table which contains the value inside a "div" tag.The table is nothing but a calendar.
This is my code for fetching the value from table.(i.e.,div tag)
public boolean webElement_Table_findCellValue_WD(String locatorType, String locatorVal, String cellText){
boolean elementStatus = false;
WebElement tbl = this.getWebElement(locatorType, locatorVal);
List<WebElement> tbTag=tbl.findElements(By.tagName("table"));
int num=tbTag.size();
System.out.println("hhhhhhhhhhhhhhhhhhh"+num);
for(WebElement tbTagEle: tbTag)
{
List<WebElement> trTag=tbTagEle.findElements(By.tagName("tr"));
System.out.println("iiiiiiiiiiiiii"+trTag.size());
for(WebElement trTagEle: trTag)
{
List<WebElement> tdTag=trTagEle.findElements(By.tagName("td"));
System.out.println("jjjjjjjjjjjjj"+tdTag.size());
for(WebElement tdTagEle: tdTag)
{
List<WebElement> divTag=tdTagEle.findElements(By.tagName("div"));
for(WebElement divTagEle: divTag)
System.out.println("the contents are:"+divTagEle.getText());
}
}
}
return elementStatus;
}
My intention is just to select(click) a date from the calender.(Table) which I will pass it through a properties file.
In answer to the first part of the question, #Striter Alfa got most of the way.
The following will print the content of each <div> within each cell within each table (whether one or multiple):
for (WebElement elem : driver.findElements(By.cssSelector("table td div"))) {
System.out.println("Each div:" + elem.getText());
}
I don't know whether you need to store those values in a List. The rest of your question isn't very clear, but hopefully you will be able to solve it from here.
The following will find the specific date table and click on the same.pass date value as parameter.
WebElement el = driver.findElement(By.xpath("//table//div[contains(.,'"+date+"')]"))
el.click();
Im trying to automate the Google Images page:
https://www.google.com/search?q=pluralsight&biw=1416&bih=685&source=lnms&tbm=isch&sa=X&ei=qGd6VN6bEZTooAT7q4C4BQ&sqi=2&ved=0CAgQ_AUoAw
All the images have the same class but no id and the results are constantly changing. So I would like to be able to click on the images based on their index.
I know how to do it in C#...but I cant figure out how to specify in the index in Java. When I try to select an index beyond 0, I get and IndexOutOfBounds error, but i cant figure out why
WebElement image = chromeDriver.findElement(By.className("rg_di"));
WebElement imageLink = image.findElements(By.tagName("a")).get(1);
imageLink.click();
Here is the entire code im using...any help would be appreciated:
System.setProperty("webdriver.chrome.driver", "/Users/user/chromedriver");
WebDriver chromeDriver = new ChromeDriver();
chromeDriver.get("http://www.google.com");
WebElement searchBox = chromeDriver.findElement(By.id("gbqfq"));
searchBox.sendKeys("pluralsight");
searchBox.sendKeys(Keys.RETURN);
chromeDriver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
WebElement imagesLink = chromeDriver.findElement(By.linkText("Images"));
imagesLink.click();
WebElement image = chromeDriver.findElement(By.className("rg_di"));
WebElement imageLink = image.findElements(By.tagName("a")).get(1);
imageLink.click();
Any help would be greatly appreciated
In your code:
WebElement image = chromeDriver.findElement(By.className("rg_di"));
will return the first element found on the page with a class of "rg_di".
That element has only one <a href=... /a> tag in it.
You are getting an IndexOutOfBounds exception because you are asking for the second one (zero based indexing). If you change your final WebElement to:
WebElement imageLink = image.findElements(By.tagName("a")).get(0);
The code should work for you with that small change.
This is my quick version (note the lack of storing elements I only need to do one thing with as WebElements):
public static void main(String[] args) {
// I don't have Chrome installed >.<
WebDriver driver = new FirefoxDriver();
driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
driver.get("http://www.google.com");
WebElement searchBox = driver.findElement(By.id("gbqfq"));
searchBox.sendKeys("pluralsight");
searchBox.sendKeys(Keys.RETURN);
driver.findElement(By.linkText("Images")).click();
WebElement image = driver.findElement(By.className("rg_di"));
image.findElements(By.tagName("a")).get(0).click();
// super-shortened version:
// driver.findElement(By.className("rg_di")).findElements(By.tagName("a")).get(0).click();
}
I'd do:
List<WebElement> we = chromeDriver.findElements(By.cssSelector(".your-class a"));
we.get(1) //should get first element in array
This code worked very well when we have similar object properties for same web buttons, then using
List<WebElement> we = webdriver.findElements(By.cssSelector(""));
and then getting
we.get(1).click();
Thank you so much for posting this answer.
Another solution may be like this:
If the class name and the index of the web element are known, then following code works:
driver.findElement(By.xpath("(//*[#class='android.widget.ImageView'])[18]")).click();
I'm testing a webpage and some of its content is loaded with XMLHttpRequest. I need to check if my <table> contains 2 rows (because the page already contains 1 row when loading) after the Ajax call.
My test:
#Before
public void setUp() throws Exception {
driver = new FirefoxDriver();
driver.get("http://localhost/index.html");
driver.manage().timeouts().implicitlyWait(3, TimeUnit.SECONDS);
}
#Test
public void testIfPartnerListPageIsPresent() {
driver.findElement(By.id("123")).click();
List<WebElement> rawList = driver.findElement(By.id("id-213"))
.findElements(By.tagName("tr"));
assertTrue("More than 1 raw", rawList.size() > 1);
}
How can I ask to Selenium to wait for other rows in my table?
This function will wait until the table contains at least given number of rows
public void waitUntilRowPopulates(WebElement element, final int rowCount) {
final WebElement table = element;
new FluentWait<WebDriver>(driver)
.withTimeout(60, TimeUnit.SECONDS)
.pollingEvery(10, TimeUnit.MILLISECONDS)
.until(new Predicate<WebDriver>() {
public boolean apply(WebDriver d) {
List<WebElement> rawList = table.findElements(By.tagName("tr"));
return (rawList.size() >= rowCount);
}
});
}
Following piece of code should help:
int noOfRowsBeforeAJAXCall = driver.findElement(By.id("id-213")).findElements(By.tagName("tr")).size();
int noOfRowsAfterAJAXCall;
driver.findElement(By.id("123")).click();
while(1)
{
noOfRowsAfterAJAXCall = driver.findElement(By.id("id-213")).findElements(By.tagName("tr")).size();
// Check whether row nos. increased
if(noOfRowsAfterAJAXCall>noOfRowsBeforeAJAXCall)
break;
// Re-check after 1 sec
Thread.sleep(1000m);
}
For web pages, especially ones that have a lot of content inside, it is advisable to use JSoup library to grab the html, parse inside. This can also be used for the purpose of synchronization.
Sample code:
String pageSource = driver.getPageSource();
Document doc = Jsoup.parse(pageSource);
String someValue = doc.getElementsByAttributeValue("id", "specificValue");
JSoup has a lot of getter methods that allow flexibility in finding what we want. It supports CSS query as well.