I am trying to fetch data from Handsontable. The table contains 700 data, however when i am locating through the Xpath, At first only 27 data found out of 55 and when i scroll down it changes to 22 out of 40. every time its taking random data. Below I have tried to create a scroll and getColumnData functions.
private void scrollDown() {
JavascriptExecutor js = (JavascriptExecutor) driver();
js.executeScript("arguments[0].scrollIntoView({block: 'center'});", rows().get(rows().size()-1));
}
protected LinkedList<WebElement> getColumnWebElement(String columnName)
{
LinkedList<WebElement> columnElement = new LinkedList<WebElement>();
int indexColumn = getLocationOfColumnInHeader(columnName) + 3;
WebElement headerRow = this.headerRow();
List<WebElement> rows = this.rows();
System.out.println(this.rows());
for (WebElement currentRow : rows)
if (currentRow != headerRow)
{
scrollDown();
WebElement td = driver.getValidatedElementNoWait(currentRow, By.xpath("./td[" + indexColumn + "]"));
if (td != null)
{
columnElement.add(td);
}
}
return columnElement;
}
Is there anyway to read all dynamic changing data based on Column name.
Thanks in Advance!
I used below workaround.
public void changeTableAttribute() {
JavascriptExecutor js = (JavascriptExecutor) driver();
WebElement element = driver().findElement(By.xpath("//hot-table/div[#class='handsontable-container handsontable htColumnHeaders']"));
js.executeScript("arguments[0].setAttribute('style', 'height:15000px')", element);
}
Related
Hi Iam new to selenium,
In URL: https://jqueryui.com/sortable/ with help of Mouse We need to sort the list. I tried this code but nothing happens any workaround in selenium how we can do this?
there are 7 items we need to sort data in descending order by mouse
I tried the below code but it's not working how can I achieve it
WebDriver driver =new ChromeDriver();
driver.manage().window().maximize();
driver.get("https://jqueryui.com/sortable/");
driver.switchTo().frame(0);
List<WebElement> lists = driver.findElements(By.xpath("//ul[#id='sortable']/li"));
Actions a = new Actions(driver);
for(int i=0;i<lists.size();++i){
WebElement element = lists.get(i);
String text = lists.get(i).getText();
String[] values = text.split(" ");
int number = Integer.valueOf(values[1]);
}
a.clickAndHold(lists.get(0)).dragAndDrop(lists.get(0), lists.get(6)).build().perform();
a.clickAndHold(lists.get(0)).moveToElement(lists.get(3)).release().build().perform();
///////////////////////////////////////////////////////////////
for(int i =dragAndDropElement.size();i>1;i--) {
WebElement element = driver.findElement(By.xpath("((//ul[#id='sortable']/li)["+i+"])"));
//Just collected all the destination location,
WebElement destination1 = driver.findElement(By.xpath("((//ul[#id='sortable']/li)[1])"));
WebElement destination2 = driver.findElement(By.xpath("((//ul[#id='sortable']/li)[2])"));
WebElement destination3 = driver.findElement(By.xpath("((//ul[#id='sortable']/li)[3])"));
WebElement destination4 = driver.findElement(By.xpath("((//ul[#id='sortable']/li)[4])"));
WebElement destination5 = driver.findElement(By.xpath("((//ul[#id='sortable']/li)[5])"));
WebElement destination6 = driver.findElement(By.xpath("((//ul[#id='sortable']/li)[6])"));
WebElement destination7 = driver.findElement(By.xpath("((//ul[#id='sortable']/li)[7])"));
Actions action = new Actions(driver);
if(element!=null) {
action.dragAndDrop(destination1,element).perform();
action.dragAndDrop(destination2,element).perform();
action.dragAndDrop(destination3,element).perform();
action.dragAndDrop(destination4,element).perform();
action.dragAndDrop(destination5,element).perform();
action.dragAndDrop(destination6,element).perform();
action.dragAndDrop(destination7,element).perform();
break;
}
You can check with this solution, Further, you could enhance this as per your requirement and simplification. Anyway, I hope it will help you.
WebDriver driver = new ChromeDriver();
driver.get("https://jqueryui.com/sortable/");
new WebDriverWait(driver,10).until(ExpectedConditions.frameToBeAvailableAndSwitchToIt(By.xpath("//iframe[#class='demo-frame']")));
List<WebElement> dragAndDropElement = driver.findElements(By.xpath("//ul[#id='sortable']/li"));
System.out.println(dragAndDropElement.size());
for(int i =1;i<dragAndDropElement.size();i++) {
WebElement element = driver.findElement(By.xpath("((//ul[#id='sortable']/li)["+i+"])"));
//Just collected all the destination location,
WebElement destination1 = driver.findElement(By.xpath("((//ul[#id='sortable']/li)[1])"));
WebElement destination2 = driver.findElement(By.xpath("((//ul[#id='sortable']/li)[2])"));
WebElement destination3 = driver.findElement(By.xpath("((//ul[#id='sortable']/li)[3])"));
WebElement destination4 = driver.findElement(By.xpath("((//ul[#id='sortable']/li)[4])"));
WebElement destination5 = driver.findElement(By.xpath("((//ul[#id='sortable']/li)[5])"));
WebElement destination6 = driver.findElement(By.xpath("((//ul[#id='sortable']/li)[6])"));
WebElement destination7 = driver.findElement(By.xpath("((//ul[#id='sortable']/li)[7])"));
Actions action = new Actions(driver);
if(element!=null) {
action.dragAndDrop(destination7,element).perform();
action.dragAndDrop(destination6,element).perform();
action.dragAndDrop(destination5,element).perform();
action.dragAndDrop(destination4,element).perform();
action.dragAndDrop(destination3,element).perform();
action.dragAndDrop(destination2,element).perform();
action.dragAndDrop(destination1,element).perform();
break;
}
}
You can try this code:
List<WebElement> lists = driver.findElements(By.xpath("//ul[#id='sortable']/li"));
// above list holds size of 7
Actions a = new Actions(driver);
WebElement lastEle = driver.findElement(By.xpath("//li[text()='Item " + lists.size() + "']"));
// I am picking last element as we have to sort in descending order. That means 1-7, 2-7, 3-7 etc..
// At last the order should be Item 7, 6, 5, 4, 3, 2, 1.
for(int i=1;i<=lists.size() - 1;++i) {
// Here, I don't want to drag last element i.e Item 7 as it will be on top at last. That is why I am not considering 7th element to drag
WebElement elementToDrag = driver.findElement(By.xpath("//li[text()='Item " + i + "']"));
a.clickAndHold(elementToDrag).dragAndDrop(elementToDrag, lastEle).build().perform();
Thread.sleep(1000);
}
This is how my page looks like on which I need to work.
The DOM looks like this
Scenario :- I need to traverse the table and where the header data(BH001 etc) and first column data(ABC etc) matches the data input by the user, I need to click on the textbox corresponding to it.
I have written the below specified code but its not working :-
public static void getMarksBox(WebDriver driver, String user, String taskCode) {
UserData userNm = TestData.findUserById(user);
String userName = userNm.getName();
WebElement table = WaitUtils.waitForElement(driver, By.cssSelector("table.eds-o-table.cvr-c-table--marksbook"));
List<WebElement> tableCols = table.findElements(By.cssSelector("td.eds-o-table__cell"));
int columnIndex = -1;
for(int i=1; i<tableCols.size();i++)
{
if(userName.equals(tableCols.get(i).findElement(By.cssSelector(".v-label-cvr-c-data-nav-link")).getText()))
{
columnIndex = i;
break;
}
}
List<WebElement> tableRows = table.findElements(By.cssSelector("tr.eds-o-table__row"));
List<WebElement> tableHeaders = tableRows.get(1).findElements(By.cssSelector(".v-label-cvr-u-margin-right--sm"));
WebElement textBox = table.findElement(By.cssSelector(".v-textfield"));
for(WebElement header :tableHeaders)
{
if(taskCode.equals(header.getText()))
{
textBox = tableRows.get(columnIndex);
textBox.click();
WaitUtils.sleepInSeconds(5);
break;
}
}
}
As #supputuri suggested, you can find the matched row or cell directly via XPath/Css selector to avoid complex loop to reduce execution time.
public static void getMarksBox(WebDriver driver, String user, String taskCode) {
UserData userNm = TestData.findUserById(user);
String userName = userNm.getName();
WebElement table = WaitUtils.waitForElement(driver,
By.cssSelector("table.eds-o-table.cvr-c-table--marksbook"));
WebElement matchedRow = table.findElement(By.xpath(
String.format("./tobdy/tr[td[1][normalize-space(.)='%s']]", userName)))
WebElement matchedTextBox = matchedRow.findElement(
By.cssSelector("./td:nth-child(2) input.v-textfield-eds-c-input"))
matchedTextBox.click()
// or you can directly find the matchedTextBox in one findElement
String xpath = String.format(
"./tobdy/tr[td[1][normalize-space(.)='%s']]" +
"/td[2]//input[contains(#class,'v-textfield-eds-c-input')]", userName)
WebElement matchedTextBox = table.findElement(By.xpath(xpath))
matchedTextBox.click()
}
Use this below xpath to access the inputbox directly, rather doing the loops that you have written in the above method.
//td[position()=count(//th[contains(.,'First Name')]/preceding-sibling::th)+1 and normalize-space(.)='ABC']/ancestor::tr//td[position()=count(//th[contains(.,'BH001')]/preceding-sibling::th)+1]//input[contains(#class,'v-textfield-eds-c-input')]
Here is the general notation:
//td[position()=count(//th[contains(.,'your reference column name')]/preceding-sibling::th)+1 and normalize-space(.)='reference value']/ancestor::tr//td[position()=count(//th[contains(.,'target column name')]/preceding-sibling::th)+1]//input[contains(#class,'v-textfield-eds-c-input')]
I have a list of links inside of several shadowRoots. Already solved this problem.
public WebElement expandRootElement(WebElement element) {
WebElement ele = (WebElement) ((JavascriptExecutor) driver).executeScript("return arguments[0].shadowRoot",element);
return ele;
}
WebElement root5_adminPanel = shadowRoot4_MduiContainerChild2.findElement(By.cssSelector("#layout > border-layout > ng-view > admin-panel"));
WebElement shadowRoot5_AdminPanel= expandRootElement(root5_adminPanel);
WebElement root6_breadCrumb = shadowRoot5_AdminPanel.findElement(By.cssSelector("#layout > border-layout > breadcrumb"));
WebElement shadowRoot6_breadCrumb = expandRootElement(root6_breadCrumb);
WebElement root6_domainPanel = shadowRoot5_AdminPanel.findElement(By.cssSelector("#layout > border-layout > ng-view > gdsr-domain-panel"));
WebElement shadowRoot6_domainPanel = expandRootElement(root6_domainPanel);
WebElement root7_selectDomain = shadowRoot6_domainPanel.findElement(By.cssSelector("#domainContainer > domain-panel-item.ng-binding.last"));
WebElement shadowRoot7_selectDomain = expandRootElement(root7_selectDomain);
When I reach this shadowRoot7, I have a list of items with the same name, which I already created a List to fix it.
List<WebElement> rows_table = shadowRoot6_domainPanel.findElements(By.cssSelector("#domainContainer > domain-panel-item:nth-child(n)"));
(They are around 45 items)
This will select all of them, in this case all the domain-panel-item rows.
My problem is that each domain-panel-item still contain another shadowRoot (the same path for all of them) an i would like to select a random item, not the first or last one, for example, the item number 43.
enter image description here
My solution was this one but it doesn't work because it doesnt access to the link that i want:
public void clickSelectedDomain(String domain) {
List<WebElement> rows_table = shadowRoot6_domainPanel.findElements(By.cssSelector("#domainContainer > gdsr-domain-panel-item:nth-child(n)"));
int rows_count = rows_table.size();
for (int row=0; row<rows_count; row++) {
if(rows_table.get(row).getAttribute("href").contains(domain)) {
rows_table.get(row).click();
}
}
}
Some have an idea how to fix this?
You solved the problem by calling recursively executeScript() in order to get the imbricated Shadow DOMs but actually you could have just called executeScript() once, and inside got the Shadow DOMs successively.
driver.executeScript( function ()
{
var root1 = document.querySelector( 'selector string 1' ).shadowRoot
var root2 = root1.querySelector( 'selector string 2' ).shadowRoot
var root3 = root2.querySelector( 'selector string 3' ).shadowRoot
...
return foundElement
}
Anyways, in the for() {} loop, you should extract the ultimate Shadow DOM one last time, and then select the <a> element to check its content.
HTMLCODE
I am getting StaleElementReferenceException: element is not attached to the page document. I went through some of the solutions that are already there in StackOverflow. It did not work and it continues to throw the same error. Here is the code I am using which is throwing the stale reference error
WebElement table2 = driver.findElement(By.cssSelector("body > div:nth-child(74) > div.sp-palette-container"));
List<WebElement> allrows2 = table2.findElements(By.tagName("div"));
for(WebElement row2: allrows2){
List<WebElement> cells = row2.findElements(By.tagName("span"));
for(WebElement cell:cells){
if (cell.getAttribute("title").equals("rgb(0, 158, 236)")) {
cell.click();
}
}
}
Because clicking the found cell lead some HTML changes on the current page , due to this changes selenium will treat the page(after click) is an "new" page (even though not redirect to another page actually).
In the next iteration of the loop, the loop still refer to element belongs to "previous" page, this is the root cause of "StateElementReference" exception.
So you need to find those elements again on the "new" page to change the reference of element comes from "new" page.
WebElement table2 = driver.findElement(By.cssSelector("body > div:nth-child(74) > div.sp-palette-container"));
List<WebElement> allrows2 = table2.findElements(By.tagName("div"));
int rowSize, cellSize = 0;
rowSize = allrows2.sie();
for(int rowIndex=0;rowIndex<rowSize;rowIndex++){
WebElement row2 = allrows2.get(rowIndex);
List<WebElement> cells = row2.findElements(By.tagName("span"));
cellSize = cells.size();
for(int cellIndex=0;cellIndex<cellSize;cellIndex++){
WebElement cell = cells.get(cellIndex);
if (cell.getAttribute("title").equals("rgb(0, 158, 236)")) {
cell.click();
// find cells again on "new" page
cells = row2.findElements(By.tagName("span"));
// find rows again on "new" page
allrows2 = table2.findElements(By.tagName("div"));
}
}
}
If your usecase is to click() on the elements with title as rgb(0, 158, 236) you can use the following code block :
String baseURL = driver.getCurrentUrl();
List<WebElement> total_cells = driver.findElements(By.xpath("//div[#class='sp-palette-container']//div//span"));
int size = total_cells.size();
for(int i=0;i<size;i++)
{
List<WebElement> cells = driver.findElements(By.xpath("//div[#class='sp-palette-container']//div//span"));
if (cells.get(i).getAttribute("title").contains("rgb(0, 158, 236)"))
{
cells.get(i).click();
//do your other tasks
driver.get(baseURL);
}
}
Use a "break" after clicking on the element found. The exception occurs because, after clicking on your element, the loop continues.
WebElement table2 = driver.findElement(By.cssSelector("body > div:nth-child(74) > div.sp-palette-container"));
List<WebElement> allrows2 = table2.findElements(By.tagName("div"));
for(WebElement row2: allrows2){
List<WebElement> cells = row2.findElements(By.tagName("span"));
for(WebElement cell:cells){
if (cell.getAttribute("title").equals("rgb(0, 158, 236)")) {
cell.click();
break;
}
}
}
I'm trying to select an element from a select list in selenium using java with WebDriver - based syntax.
I've got the select list by
elements = driver.findElements(By.xpath("//form[#action='inquiry/']/p/select[#name='myselect']"));
if (elements.size() == 0) {
return false;
}
if (guests != null) {
//what do I do here?
}
How do I do that?
WebElement select = driver.findElement(By.name("myselect"));
Select dropDown = new Select(select);
String selected = dropDown.getFirstSelectedOption().getText();
if(selected.equals(valueToSelect)){
//already selected;
//do stuff
}
List<WebElement> Options = dropDown.getOptions();
for(WebElement option:Options){
if(option.getText().equals(valueToSelect)) {
option.click(); //select option here;
}
}
If this is slower, then consider something like
dropDown.selectByValue(value);
or
dropDown.selectByVisibleText(text);
A little side note which applies to Java:
In my case, when I was writing the test according the example of #nilesh, I got a strange error, that the constructor is invalid. My import was:
import org.openqa.jetty.html.Select;
If you happen to have similar errors, you have to correct that import to this:
import org.openqa.selenium.support.ui.Select;
If you use this second import, everything will work.
element = driver.findElements(By.xpath("//form[#action='inquiry/']/p/select[#name='myselect']/option[*** your criteria ***]"));
if (element != null) {
element.click();
}
find the option, and then click it
Try to do it like this :
//method to select an element from the dropdown
public void selectDropDown(String Value) {
webElement findDropDown=driver.findElements(By.id="SelectDropDowm");
wait.until(ExpectedConditions.visibilityOf(findDropDown));
super.highlightElement(findDropDown);
new Select(findDropDown).selectByVisibleText(Value);
}
//method to highlight the element
public void highlightElement(WebElement element) {
for (int i = 0; i < 2; i++) {
JavascriptExecutor js = (JavascriptExecutor) this.getDriver();
js.executeScript(
"arguments[0].setAttribute('style', arguments[1]);",
element, "color: yellow; border: 3px solid yellow;");
js.executeScript(
"arguments[0].setAttribute('style', arguments[1]);",
element, "");
}
}