I am automating a web application using Katalon studio with Selenium/Java. In a web table where we have to keep only first 15 records and rest of the records should be deleted. Each page contains 25 rows of data. The following is the code I have written but when I execute it deletes only 25 records and it stops. The code must delete the rows till it reaches 15, e.g. from 200 records to 15 records.
public void deleteRows() {
int rows_count;
int Row;
WebElement UsersTable;
WebElement UsersTable2;
List<WebElement> rows_UsersTable;
List<WebElement> cols_UserTable;
int cols_count;
int rowsNeeded = 15;
WebDriverWait wait;
List<WebElement> rows_UsersTable2;
UsersTable = driver.findElement(By.xpath("//table/tbody"));
rows_UsersTable = UsersTable.findElements(By.tagName("tr"));
rows_count = rows_UsersTable.size();
println ("Total rows is " +rows_count)
cols_UserTable = UsersTable.findElements(By.xpath("//table/tbody/tr[1]/td"));
cols_count = cols_UserTable.size();
println ("Total columns is " +cols_count)
if (rows_count >= rowsNeeded) {
int j = 1;
int newRowCount;
while (j <= rows_count) {
WebElement deleteIcon = driver.findElement(By.xpath("(//table/tbody/tr/td)[last()]/span"));
String text = deleteIcon.getText();
deleteIcon.click();
Thread.sleep(2000);
WebElement confirmBtn = driver.findElement(By.xpath("//button[text()='Confirm']"));
confirmBtn.click();
Thread.sleep(3000);
println ("Successfully deleted " + j);
UsersTable2 = driver.findElement(By.xpath("//table/tbody"));
rows_UsersTable2 = UsersTable.findElements(By.tagName("tr"));
newRowCount = rows_UsersTable2.size();
println ("The new row count is " + newRowCount)
j++;
}
}
}
I know there is something I have missed, please help.
Thanks
Related
website is dark sky and I want to verify current temp is greater or less than temps from timeline. I used array list. I need to get current temp and compare it with them. Thank you. I couldn’t do that. Do u have any idea for this. Thnx.
ArrayList<WebElement> list = new ArrayList<>(SharedSD.getDriver( ).findElements(greaterOrLess));
DarkSky considered for test:
Python Script on darksky:
Just converted the python code to java
driver.get("https://darksky.net/forecast/40.7127,-74.0059/us12/en");
String currentTemp = driver.findElement(By.cssSelector(".summary.swap")).getText();
System.out.println("Current Temp:" + currentTemp);
List<WebElement> tempsInTimeLine = driver.findElements(By.cssSelector(".temps span:last-child"));
int temp = Integer.parseInt(currentTemp.substring(0, 2));
int highestInTimeLine = temp;
int lowestInTimeLine = temp;
for (WebElement tempInTime: tempsInTimeLine) {
String sLIneTemp = tempInTime.getText();
int lineTemp = Integer.parseInt(sLIneTemp.substring(0, 2));
if (lineTemp > highestInTimeLine){
highestInTimeLine = lineTemp;
}
if (lineTemp < lowestInTimeLine ){
lowestInTimeLine = lineTemp;
}
}
System.out.println("Highest Temp:" + Integer.toString(highestInTimeLine));
System.out.println("Lowest Temp:" + Integer.toString(lowestInTimeLine ));
I have a code in which I traverse table rows and columns, and I'd like to add it's values to a list.
It takes me a significant amount of time.
So I added a time measurement, and I noticed that for some reason the time increases from row to row.
I cannot understand why.
Can you advise please?
private void buildTableDataMap() {
WebElement table = chromeWebDriver.findElement(By.id("table-type-1"));
List<WebElement> rows = table.findElements(By.tagName("tr"));
theMap.getInstance().clear();
String item;
for (WebElement row : rows) {
ArrayList<String> values = new ArrayList<>();
List<WebElement> tds = row.findElements(By.tagName("td"));
if(tds.size() > 0){
WebElement last = tds.get(tds.size() - 1);
long time = System.currentTimeMillis();
values.addAll(tds.stream().map(e->e.getText()).collect(Collectors.toList()));
System.out.println(System.currentTimeMillis() - time);
//remove redundant last entry:
values.remove(tds.size() - 1);
callSomeFunc(values, last);
item = tds.get(TABLE_COLUMNS.NAME_COL.getNumVal()).getText();
item = item.replaceAll("[^.\\- /'&A-Za-z0-9]", "").trim();//remove redundant chars
theMap.getInstance().getMap().put(item, values);
}
}
}
Guys, I continued researching.
First of all, Florent's kind answer did not help me because, at lease as I understand, It returned me an array list of strings which I had to parse, and I don't like this kind of solution too much...
So I nailed the problem in finding that the e.getText() call was increasing in time from call to call!!!
I also tried e.getAttribute("innerText") instead but no change.
Can't understand why. Any idea to solve?
WebElement last = null;
for (WebElement e : tds){
last = e;
long tm1 = 0, tm2 = 0;
if(Settings.verboseYN) {
tm1 = System.currentTimeMillis();
}
s = e.getText(); //This action increases in time!!!
if(Settings.verboseYN) {
tm2 = System.currentTimeMillis();
}
values.add(s); //a 0 ms action!!!
if(Settings.verboseYN) {
System.out.println("e.getText()) took " + (tm2 - tm1) + " ms...");
}
}
That is an graph of the time getText took...
08-May-18
Another source of growing execution time is this one:
void func(WebElement anchorsElement){
List<WebElement> anchors = anchorsElement.findElements(By.tagName("a"));
for (WebElement a : anchors) {
if (a.getAttribute("class").indexOf("a") > 0)
values.add("A");
else if (a.getAttribute("class").indexOf("b") > 0)
values.add("B");
else if (a.getAttribute("class").indexOf("c") > 0)
values.add("C");
}
}
Every functions has 5 iterations only, but still each call to the function increases its execution time.
Is there a solution for this one as well?
Calling the driver is an expensive operation. To significantly reduce the execution time, use a JavaScript injection with executeScript to read the whole table in a single call. Then process/filter the data on the client side with Java.
public ArrayList<?> readTable(WebElement table)
{
final String JS_READ_CELLS =
"var table = arguments[0]; " +
"return map(table.querySelectorAll('tr'), readRow); " +
"function readRow(row) { return map(row.querySelectorAll('td'), readCell) }; " +
"function readCell(cell) { return cell.innerText }; " +
"function map(items, fn) { return Array.prototype.map.call(items, fn) }; " ;
WebDriver driver = ((RemoteWebElement)table).getWrappedDriver();
Object result = ((JavascriptExecutor)driver).executeScript(JS_READ_CELLS, table);
return (ArrayList<?>)result;
}
The problem you are facing is because of the way Selenium works by design. Let's look at how a JavaScript get's executed or a operation is performed
tds.get(TABLE_COLUMNS.NAME_COL.getNumVal()).getText();
You have a collection of objects. Each object is assigned a unique ID on the browser side by the selenium driver
So when you do a getText() below is what happens
Your code -> HTTP Request -> Browser Driver -> Browser ->
|
<---------------------------------------------
Now if you have a table of 400rx10c then it accounts to 4000 HTTP calls, even if one call takes 10ms, we are looking at a 40000ms~=40sec, which is a decent delay to read a table
So what you want to do is to get all the data in single go by executing a javascript which give you 2d array back. It is quite simple, I found a code on below site
http://cwestblog.com/2016/08/21/javascript-snippet-convert-html-table-to-2d-array/
function tableToArray(tbl, opt_cellValueGetter) {
opt_cellValueGetter = opt_cellValueGetter || function(td) { return td.textContent || td.innerText; };
var twoD = [];
for (var rowCount = tbl.rows.length, rowIndex = 0; rowIndex < rowCount; rowIndex++) {
twoD.push([]);
}
for (var rowIndex = 0, tr; rowIndex < rowCount; rowIndex++) {
var tr = tbl.rows[rowIndex];
for (var colIndex = 0, colCount = tr.cells.length, offset = 0; colIndex < colCount; colIndex++) {
var td = tr.cells[colIndex], text = opt_cellValueGetter(td, colIndex, rowIndex, tbl);
while (twoD[rowIndex].hasOwnProperty(colIndex + offset)) {
offset++;
}
for (var i = 0, colSpan = parseInt(td.colSpan, 10) || 1; i < colSpan; i++) {
for (var j = 0, rowSpan = parseInt(td.rowSpan, 10) || 1; j < rowSpan; j++) {
twoD[rowIndex + j][colIndex + offset + i] = text;
}
}
}
}
return twoD;
}
I assume you store the above script in a SCRIPT variable and then you can run it like below
WebDriver driver = ((RemoteWebElement)table).getWrappedDriver();
Object result = ((JavascriptExecutor)driver).executeScript(SCRIPT + "\n return tableToArray(arguments[0]);" , table);
This will get you a 2D array of the data and you can then process it the way you like it
Why click() doesn't works?
website:
String startPage = "http://www.domiporta.pl/mieszkanie/sprzedam?Localization=dolno%C5%9Bl%C4%85skie&PageNumber=24&SortingOrder=InsertionDate";
Code:
List<WebElement> RowsMain = driver.findElements(By.className("detail-card__heading"));
for(int i=0;i<RowsMain.size();i++){
driver.get(startPage);
List<WebElement> rows = driver.findElements(By.className("detail-card__heading"));
List<WebElement> cols=new ArrayList<WebElement>();
cols=rows.get(i).findElements(By.tagName("div"));
for(WebElement col:cols) {
col.click();
}
}
Why click doesn't workS?
It is error because you navigate out of the current page, so DOM has been destroyed. The solution is simple, find the elements every time when you navigate out of the page. See code below.
int rowCount = driver.findElements(By.className("detail-card__heading")).size();
for(int i=0; i<rowCount; i++){
List<WebElement> rows = driver.findElements(By.className("detail-card__heading"));
int colsCount = rows.get(i).findElements(By.tagName("div")).size();
for(int j=0;j<colsCount; j++) {
rows = driver.findElements(By.className("detail-card__heading"));
List<WebElement>cols = rows.get(i).findElements(By.tagName("div"));
cols.get(j).click();
driver.get(startPage);
}
}
I have the following code, that allows me to remove a row from the right Jtable with a click. It works fine for all the rows, except when there is only one row remaining. BTW, sorry for most names being in portuguese, its my native language. Here are the images showing before and after i click the final row in the table. It updates the total, but the row remains. For every other case, it works perfectly.
Screenshot:
private void jtbSelecionadosMouseClicked(java.awt.event.MouseEvent evt)
{
int x = jtbSelecionados.rowAtPoint(evt.getPoint());
if (x >= 0)
{
String nomeProduto = (String)jtbSelecionados.getModel().getValueAt(x, 0);
for (int i = 0; i < itensVenda.size();i++)
{
if (itensVenda.get(i).getNomeProduto().equals(nomeProduto))
{
if(itensVenda.get(i).getQtd() > 1)
{
valorTotal -= (itensVenda.get(i).getPreco() / itensVenda.get(i).getQtd());
double precototal = itensVenda.get(i).getPreco();
double unit = precototal / itensVenda.get(i).getQtd();
System.out.println("Unidade: "+unit+"\nTotal: "+precototal);
itensVenda.get(i).setPreco(itensVenda.get(i).getPreco() - (itensVenda.get(i).getPreco() / itensVenda.get(i).getQtd()));
itensVenda.get(i).setQtd(itensVenda.get(i).getQtd() - 1);
recarregarTabela();
}
else if(itensVenda.get(i).getQtd() <= 1)
{
valorTotal -= itensVenda.get(i).getPreco() / itensVenda.get(i).getQtd();
itensVenda.remove(i);
recarregarTabela();
}
}
}
}
function that resets the table with new information:
private void recarregarTabela()
{
if (itensVenda.size() == 0)
{
dtm.getDataVector().removeAllElements();
dtm.setRowCount(0);
lblTotal.setText("Total: R$" + String.valueOf(valorTotal));
}
else
{
dtm.getDataVector().removeAllElements();
dtm.setRowCount(0);
for (Item item : itensVenda)
{
Object[] vetor = new Object[3];
vetor[0] = item.getNomeProduto();
vetor[1] = item.getQtd();
vetor[2] = String.format("%.2f", item.getPreco());
System.out.println(item.getPreco());
dtm.addRow(vetor);
}
lblTotal.setText("Total: R$" + String.valueOf(valorTotal));
}
}
You dont have to rebuild whole model everytime a single row is deleted. As you already have index of clicked or selected row you can just remove it from model using removeRow(index) method. I suspect that dtm is a DefaultTableModel so just call dtm.removeRow(index) everytime you need to remove row from table
As per title, how can I grab at least 10,000 tweets given that Twitter has their own limit ?
Twitter allows 180 queries per 15 minutes. So I was planning to use Timer and TimerTask to set an interval and keep running the code until I get 10,000 tweets like this:
timer.schedule((TimerTask) getTweets("$FB up"),0,900000);
The problem is that, every 15 minutes it will get back the same data as the first 15 minutes. How do I make it a continuation from where it stops in the previous 15 minutes ?
Below is the function for the
getTweets(String term)
int wantedTweets = 10000;
long lastSearchID = Long.MAX_VALUE;
int remainingTweets = wantedTweets;
Query query = new Query(term);
try{
while(remainingTweets > 0)
{
remainingTweets = wantedTweets - tweets.size();
if(remainingTweets > 100)
{
query.count(100);
}
else
{
query.count(remainingTweets);
}
QueryResult result = twitter.search(query);
tweets.addAll(result.getTweets());
Status s = tweets.get(tweets.size()-1);
long firstQueryID = s.getId();
query.setMaxId(firstQueryID);
remainingTweets = wantedTweets - tweets.size();
}
for (int i=0 ; i < tweets.size() ; i++) {
b = tweets.get(i);
//System.out.println(s);
//System.out.println("#" + b.getUser().getScreenName() + " - " + b.getText());
}
}
catch(TwitterException te)
{
System.out.println("Failed to search tweets: " + te.getMessage());
}
return b;
Use the twitter streaming API instead