i need to test a sorting function of a table. My problem is, that the developer implemented something like "lazy-loading" for the rows - the rows (div-elements of an ag-grid-table) only appears in the DOM, when they are in the view. So if you scroll through the table, the top elements disappear (even cant find the divs through dev-tools in chrome). Thats why i cant read all elements under the table and work with them - i need to scroll with my WebDriver through the table and read every row and write them into an array, where i can test, if the result is sorted.
WebElement table = Helper.driver.findElement(By.xpath("hidden"));
Actions builder = new Actions(Helper.driver);
//here i read the total number of elements in the table from a string, which displayed the total number directly under the table
String totalNumberOfRows = Helper.driver.findElement(By.xpath("hidden")).getText();
int totalInt = Integer.parseInt(Arrays.asList(total.split(" ")).get(1));
String[] sortedTableColumn = new String[totalInt];
List<WebElement> tableRows = table.findElements(By.className("ag-row")); //all active Elements, which exist in the DOM at the point, where the user looks. Mostly around 15 elements (35 total in my example)
for(int i = 0; i<totalInt; i++) {
builder.moveToElement(tableRows.get(i)).perform(); //scroll through the elements
sortedTableColumn[i] = Arrays.asList(tableRows.get(i).getText().split(" ")).get(0); //dont ask, its necessary to get the first part of the string
}
System.out.println(Arrays.toString(sortedTableColumn));
assertTrue(Ordering.natural().isOrdered(Arrays.asList(sortedTableColumn)));
problem is, that the loop end with an error, because the tableRow has only 15 elements and the loop want to go further. Pretty understandable.
But I dont know how to handle this. I need something like "take the tableRows, go one step down (tableRows will change), put this new tableRows and the old ones in a new array and kill duplicates. AND be sure, that this is the new List, where i use the iterator "i".
Has anyone an idea to fix/complete my code or maybe a better way to test sorting funtions of dynamic loaded tables?
Related
I have 5 elements which I am tryin to hover 1 by 1. I am putting these elements in a List. But when I use List for Hover(with and without loop) it gives Stale Element Exception. Note I can perform it when I use individual elements without using list. I have printed the elements from List and the xpath returned also looks correct.
System.out.println("=====================All star start ================");
Actions actions= new Actions(driver);
List<WebElement> starList= new ArrayList<WebElement>();
ArrayList<WebElement> starColorList= new ArrayList<WebElement>();
Reporter.log("Started adding star elements", true);
for(i=11,j=22;i<=15;i++,j=j+2)
{
Reporter.log("Started adding star elements"+i+j, true);
WebElement s = driver.findElement(By.xpath("(//*[name()='svg'][#class='rvs-star-svg'])["+i+"]"));
WebElement sc = driver.findElement(By.xpath("(//*[name()='svg']//*[name()='path'])["+j+"]"));
starList.add(s);
starColorList.add(sc);
}
//Does not work even without loop
actions.moveToElement(starList.get(2)).build().perform();
//Works
actions.moveToElement(star1).build().perform();
Does not work
for(i=0;i<starList.size();i++)
{
Reporter.log("Started Hover"+i, true);
actions.moveToElement(starList.get(i)).build().perform();
Thread.sleep(2000);
System.out.println(starList.get(i));
//System.out.println("Star"+i+"has color "+starColorList.get(i).getAttribute("stroke"));
}
'''
There are several problems to watch out for:
StateElementReferenceException is always thrown when you try to interact with an element which is no longer accessible because the DOM has changed. Are you trying to interact with the second element after you hovered over the first one? Does this cause a new element, like a tooltip, to show up and thus invalidating the WebElements from the list? You'd have to re-execute the search after that. One basic solution is to keep locators, and not located WebElements in the list, so that you run findElement(locators.get(i)).click() in a loop.
This not necessarily matches your example, but it seems to be quite common problem: if you use findElements - the variant returning a list of multiple elements matching a single locator - make sure your locator is not too generic, as sometimes the found elements are not necessarily what you are expecting them to be. Like finding nested <td> elements inside other <td> and not after the ones you'd expect.
All in all, the list use here is probably a red herring - the real problem is what happens in the DOM between calls to findElement() and whatever interaction you have with that element.
StateElementReferenceException will occur on when trying to access the element before page load or after the element is vanished. so please try to add visibility wait conditions.
By tmpBy = By.xpath("//div[contains(text(),'"+deno+"')]");
WebDriverWait wait = new WebDriverWait(driver, 20);
wait.until(ExpectedConditions.elementToBeClickable(tmpBy));
wait.until(ExpectedConditions.visibilityOfElementLocated(tmpBy));
driver.findElement(tmpBy).click();
And please add code to take screenshot whenever it is failing. it will be easy for you debug.
How can you generate for eg. 10 buttons in JavaFX Builder? I don't want to insert them manually.
I need this to create a virtual shop. And i want to have N products on a page, but i need text, image, etc for every product and if i don't know how many products i will have i can't put there 10 of them from the start, because maybe i will have more or less and then there will be blank images with no text set. I hope that my question is clear.
I would like to get 1 product from my database and create a textbox and a button for it. If i get 5 objects from my database i would like to create 5 textboxes and 5 buttons and so on.
So say you were to extract the full list of Objects from your database into your running program, then you could write code that looks something like
foreach(Object in Objects) do
MakeTextBox
MakeButton
MakeImage
Insert TextBox, Button and Image
So without ever having used JavaFX in any meaningful way I could hint you towards doing something like this:
//This is the incoming package, I will assume this is a JSONArray for now since it seems obvious enough and I will assume it's called jarray_stock
for(int i = 0; i < jarray_stock.length(); i++){
Button b = new Button();
TextBox t = new TextBox();
Image i = new Image();
parent.add(b);
parent.add(t);
parent.add(i);
}
Now you just have to take that and replace my button textbox image with the actual appropriate classes for JavaFX and replace the parent.add with the actual methods to add that to your Frame or whatever you're actually using.
Of course if you know how many elements you need to generate you can replace jarray_stock.length() with any number you need.
I have a website that has a long horizontal table. I have Xpath that extracts column headers of a table that stretches more than the screen width (3X of the screen width). Now I have to extract all column heads with their respective index as my table has show columns filters from where user can select or deselect the rows. So I need to dynamically fetch the columns with the index. Now I when I try to fetch the column heads for the first time then system fetch me the column heads till it is visible on the first screen without scroll but now when the system tries to get the column head which is not visible on chrome then code returns a null value.
I have tried to get the total number of columns and checked that scrolling right by 8 columns will do my job but then with this, I am not able to reuse this function on other web tables where there are lesser columns as the system does not find the i+8 column and shows the exception.
I tried to scroll right every time by one column when I get column head as blank. But with this, my code has to check one if condition each time when it does get blank and this is making my method very slow which I can't afford as I need to get at least 35 columns and that too more than 2-3 time in bigger methods.
Now, what I know here is I know which is the last column head was visible to me so I need to scroll right till column head which I had is not visible to me on a screen which other way means I have scrolled maximum to right without hiding the column which I haven't covered. How can I do it?
This is what I tried for this scrolling by 8 columns by seeing the general width of columns. This is working for me but restricting the reusability of function.
if (colHead.equalsIgnoreCase("")) {
WebElement elementToBeScrolled1 = driver.findElement(By.xpath("//th["+i+"+8]"));
By elementToBeScrolled = getByLocator(elementToBeScrolled1);
do {
keyPress(Keys.ARROW_RIGHT);
} while (waitForElement(elementToBeScrolled, 5, WaitType.invisibilityOfElementLocated));
colHead = driver.findElement(By.xpath("//th[" + i + "]"))
.getText();
Ok so I think the title is all I've got to ask here.
My AbstractTableModel works fine, when I want to add an empty row, I use the following code to do so:
public void addRow() {
Object[][] oldData = data;
data = new Object[oldData.length + 1][3];
// Copy old data to new data
for (int x = 0; x < oldData.length; x++) {
data[x] = oldData[x];
}
// Append new row
data[oldData.length] = new Object[] {"", "", false};
fireTableRowsInserted(data.length - 2, data.length - 1);
}
Now, since I'm showing an empty row, I want the user to edit it, and I assume that the user will. Now, how do I make sure that the data is saved in my array as the user makes changes? Or, if that's not possible, what better alternative is there?
Ok so I should probably explain what I want to do:
I'm loading contents from a file, and displaying as a table. Now, the user might add new rows to the table on clicking the Add Row button. This will add 1 empty row per click. (In this image above is an instance when the button is pressed twice.
Now, I want that the user can edit the cells, and then maybe delete some rows (maybe) but on clicking the Save Database button, the updated data in the table is stores.
You may get a better understanding by comparing several approaches:
In this example, either a background thread or a button can add a new row to a table. The background thread sequences instances of Runnable on the EDT via invokeLater(). It is conceptually easier to understand, but it is also easier to get wrong.
SwingWorker encapsulates sequencing access to shared data. The API and tutorial show the basic approach of updating a component's model using publish()/process(). This preferred mechanism is more robust and scalable.
In this more advanced example, a Swing Timer paces an Executor that controls a series of SwingWorker instances.
In all cases, the tables remain functional. You might use any as a basis for an sscce.
Addendum: Could you explain a little more about the strategies you suggested?
I've updated the list of examples and suggested some things to look for in context.
I've reccently run into issues with indexing my tabs and though I'd give it some concrete ordering by using the setComponentAt method. Here's my code:
public ContainerPane() {
this.setLayout(new BorderLayout());
myPlayerManagerPane = new PlayerManagerPane();
myGameManagerPane = new GameManagerPane();
myCharacterManagerPane = new CharacterManagerPane();
myPaneTab = new JTabbedPane(JTabbedPane.TOP);
myPaneTab.addTab("Character",myCharacterManagerPane);
myPaneTab.addTab("Player",myPlayerManagerPane);
myPaneTab.addTab("Games",myGameManagerPane);
System.out.println(myPaneTab.getTabCount());
//myPaneTab.setEnabledAt(1, false);
//myPaneTab.setEnabledAt(2, false);
myPaneTab.setComponentAt(0, myPlayerManagerPane);
myPaneTab.setMnemonicAt(0, KeyEvent.VK_1);
myPaneTab.setComponentAt(1, myCharacterManagerPane);
myPaneTab.setMnemonicAt(1, KeyEvent.VK_2);
myPaneTab.setComponentAt(2, myGameManagerPane);<---outOfBoundsException
myPaneTab.setMnemonicAt(2, KeyEvent.VK_3);
add(myPaneTab);
}
So for the count I have, 3 tabs (according to me, and getTabCount()), and I am counting from 0 (correct?). I'm setting the last index the last component that I have. But I still have this printing to screen:
3 <---from tabCount
Exception in thread "AWT-EventQueue-0" java.lang.ArrayIndexOutOfBoundsException: 2 >= 2
Where am I tripping up, is there an easier way to order my panes?
Edit: Commenting out the setComponent methods, and putting in a for loop I get this output:
There are 3 tabs!
Tab at 0 is Character
Tab at 1 is Player
Tab at 2 is Games
And uncommmenting one pair of methods at a time, I get only 2, of the one I've not overwritten, and one of the ones I've now set.
Is setComponentAt removing duplicates? Should I ever have fewer than 3 tabs with my set up? Does JTabbedPanel have odd behaviour for duplicate panes?
You get an error due to changes you are trying to do - by putting some of the panes into another position you automatically remove another tab. That is why you get the error - there is less than 3 tabs after some of the changes (you can check that outputting tabs amount after each of "setComponentAt" operations).
Simple remove all tabs you want to reorder and readd them using either addTab or insertTab - that will get the job done without any errors.
Looking at source code of the setComponentAt you can see that component you're setting is removed:
int count = getComponentCount();
Component children[] = getComponents();
for (int i = 0; i < count; i++) {
if (children[i] == page.component) {
super.remove(i);
}
}
next this component is set as page's component (overriding last present component on that page):
page.component = component;
So setting order of existing tab component you end up with 2 tabs.
I'm not sure how or why setComponentAt wasn't working, though it could be the fact that tabs use a Vector and I've heard they are bad.
If you want to have a fixed order of adding, just use insertTab Like so:
myPaneTab.insertTab("Games",null, myGameManagerPane,"CharacterManagerPane",2);
Where null is for the icon, and doesn't accept it as an empty argument.
This way you know in your source code the index of the tab. The only issue with this is that you can't add a new tab at an index past the current tabCount (which you can find via getTabCount), i.e. you can't count 1,3,4 with your tabs!
I'm sure you could write a new JTabb Class, and overload the insertTab method to do something more helpful but it might obsfuscate where the tab is (I.e this way you could tell it put the tab at index 2 and it goes into index 1.
If you want your tabs in another order, add them in another order:
myPaneTab = new JTabbedPane(JTabbedPane.TOP);
myPaneTab.addTab("Player",myPlayerManagerPane);
myPaneTab.addTab("Character",myCharacterManagerPane);
myPaneTab.addTab("Games",myGameManagerPane);
Et voilĂ .