WebDriver / Read elements into variables and re-use them - selenium

I have a big issue With Webdriver (Selenium 2).
In my test code, I find all the elements in the beginning of my test, and do some actions on them (like click(), checking attributes, etc.). My problem is that my page is refreshed and re-load my elements, and Webdriver don't know to recognize the elements again.
I know that I can find my elements again, but in some functions I don't know my XPath/ids, and I get just the WebElements, not XPath/IDs.
Am I right in saying that it's no possible to read elements into variables and re-use them?

WebElement element = driver.findElement(By.id("xyz"));
The above line will store the element object in element. You can certainly pass this element to other functions to make use of it over there.
We generally follow a pattern called PageObject patterns where we create all objects of a page as members of a class and instantiate them at once. This way we can use them any where in our project. For example all objects in Login page will be created as public static variables in a class called LoginPage. The constructor of LoginPage class will find elements and store them.
Next time any where you want to access an object of LoginPage, we access them as below(asuming that you have created elements userName and submit)...
LoginPage.userName.sendKeys("buddha");
LoginPage.submit.click();
However as Robie mentioned there is a chance for this objects to become unaccessible using the previously created object after page refresh. You can use the below modified approach for ensuring these objects are always found.
Instead of creating the objects as a member variable, create a getmethod for each object that you may need to use.
class LoginPage
{
public static WebElement getUserName()
{
return driver.findElement(By.id("xyz"));
}
}
Once LoginPage is defined that way, next time you want to use userName, you use below syntax.This way you don't have to give locators to the functions that needs to use these objects.
LoginPage.getUserName().sendKeys("buddha");
By using this approach, you can ensure that the objects are always accessible.

Buddha is incorrect in the following statement:
You can reuse it any number of times, however, it only works as long as the id doesn't change.
As you have correctly observed, if the page reloads, then elements become stale, even if the original object is still displayed on screen. In fact, refreshing of HTML via AJAX calls can also make objects stale even if the URL has not changed.
This is how Selenium works, and you have to understand this when deciding how to implement a test framework.
You can store elements, reuse them and pass them to functions, but understand when they will become stale and need to be refound.
In my current project, I have a very AJAX heavy application in which objects are continually becoming stale, so have extended WebElement to find and store it's HTML Id when constructed, then refinds by id if a stale element exception occurs and re performs the method that failed. However, this was achieved using Ruby and very specific to my application as I know every object has a unique HTML Id. I do not believe this approach would work for most applications under test.
I would also question whether storing elements in public static variables populated on construction, is actually following the Page Object pattern. I have never seen it implemented this way before, and can see lots of potential pitfalls. Lazy instantiation may be a better approach when following the Page Object pattern.

Related

Is it possible to combine multiple commands in single webdriver http call?

I'm using Selenium from Java with a remote grid. When I find an element on a page I would like to retrieve its text, multiple attributes from this element, check whether it is displayed and whether it is enabled.
As far as I can see each thing I retrieve triggers a new remote call (to http endpoint of the webdriver). Since I know beforehand which values I'm interested in I would like to combine them in a single http call (as the call can be quite slow). Is this possible in Selenium with Java? Or even with the webdriver protocol?
To be clear: my problem is not finding an element based on multiple criteria in one go, I know how to do that. But after I find the element I want to know the values of multiple properties, and I want to gather these efficiently.
As far as I can see the protocol requires a separate call for each attribute value, the text, whether the element is displayed and whether it enabled. For me this means for instance 6 round trips to the server, where one could suffice if I were able to 'multiplex' all data I would like to retrieve in a single call.
Is there a way to optimize retrieving multiple details/properties of an element once I found it?
On solution to have less calls between the driver and server could be to use some javascript in the context of the client side/window.
You can write something like
combinedObject = driver.executeScript("function(domelement) {
return { abc: domelement.getAttribute('abc'), efg: domelement.getAttribute('efg'), hij: domelement.getAttribute('hij') };
}",foundedElement);
This can reduce the number of calls between driver and server.
If it makes sense to mix some javascript functions with your java code is your decision.

Page Factory - how does it work

I've tried to implement one of our app modules by using PageFactory (for iOS)
Most of the elements are located by name and others by classname
In general everything works (more or less) but the thing is that the appium server has tons of logs , it seems that each time I'm trying to use some page control , and all the declared controls within that page are being update (?) which cause to longer time execution.
In case and I'm trying to debug my test , it takes a lot of time to move step by step (the appium server works extra hours ...)
I do use "CacheLookup" whenever it possible ...
Where my mistake is, or it's just should be like that ?
Thanks
Updated
Not enough info provided to say for sure. If you have a bunch of cucumber steps and each step is creating a new page instance then yes, you could create a class variable to communicate between cucumber steps
Class variables get thrown out at the end of each scenario so no cross scenario contamination. However, if a single scenario leaves a page and comes back you would need to explicitly set the class page handle to nil/null so that it is reinitialized upon reentry to that page. You want to avoid stale element errors.

What is Injectable and Embeddable?

I have heard about both terms Injectable and Embeddable many times, but I am not getting actual meaning of it.
Please help me to understand both clearly.
Injectable means that something can be created and added to the main script while the script is running.
Embeddable means something can be added to a script or code before running it i.e before compilation or running of the script.
For better understanding lets take a website with a textbox as a context.
Now, In the textbox, suppose its very basic one. So, I can add a javascript into the textbox and when I will submit, it will run my JS script. This way, I am injecting my own script into the main page.
Now, suppose, I add an Iframe of another website to the HTML file of my website. In this way, when the website will be viewed, it contains the iframe. In this way, the Iframe is embedded to the website.
Injectable means that the object can be created and injected at run time. This is a hint to the compiler that this object will be managed outside the scope of the compilation and can be used at runtime to determine if the object was intended to be injected.
Embeddable means that the object can be serialized and stored in a column instead of as a separate table when the containing object is persisted. That also implies the lifetime of the embedded object is the same as the lifetime of the containing object.

Should test data be passed from PageObject or test classes?

I'm in the process of developing an automation framework using Selenium Webdriver following the PageObject pattern where there are 2 layers:
Test classes (Test specification)
PageObject classes (Test implementation)
My test classes contain TestNG annotation methods (#Test, #BeforeTest, #AfterTest etc) where I'm creating objects of the PageObject classes and calling the methods in those classes, which will actually interact with the AUT.
The way I'm passing data to the tests is by including:
All the locators (css/xpath/class/id locators) of elements in the
application.
All the test-data needed
in a properties file (For ex: testDataSet1.properties). I'm creating a HashMap<String, String> of the properties file and passing it as a parameter to all the pageobjects which will read the data from the hashmap and use them in the script. I'm not passing test data at all from the test classes.
What my problem is, I am not sure whether it is appropriate to read test-data in PageObjects. I get a feeling that this approach is very inflexible because I am tying test data to PageObjects instead of tying it to the tests. So when I need to perform data-driven tests / run the automation suite in multiple iterations, this will not work. Because, currently if I need to use different data each time I need to manually go and change the key specified in the hashmap which will fetch me a different value from the properties file.
Any suggestions?
I personally like having the page object act as a the web page itself, providing me actions to perform and validation methods to use. For example, I keep all of my CSS, ID, etc. selectors within the page object itself. This way, if there is ever an update to the webpage which breaks the tests, I simply go to the corresponding Page Object for that web page and update the selector there.
As far as test data, I have some other files (classes, properties, etc.) that I use to pull test data from eg. test users. The test classes themselves pull this test data and pass it into the Page Objects (when needed), or the Page Object methods for validation purposes.
An example of a test data class (mine is a bit more complex, but this is a simple example):
public TestUser(){
username = getUniqueUser();
password = "";
name = "Test User";
email = getUniqueEmail(username);
}
tl;dr;
I keep the html selectors IN their respective Page Objects (can use sub-page objects for re-use if needed).
I keep the test data mixed between classes, property files, and test classes.

Any documentation available for xe:objectData?

It seems, that the objectData control can be used as a performance boost for an xpage application. I understand the basic idea behind, but still have trouble to get it to work properly.
Using a objectData as input for a repeat control avoids the unneccessary refresh of the repeat during a partial refresh that was triggered on another refreshId than the id for the repeat. But due to the cache mechanism in the objectData, the objectData is not refreshed during a partial refresh of the surrounding div for example. Setting the scope to request, objectData is refreshed, but the issue with partial refresh also refreshing datasources outside the refreshId occurs.
A bit weird, I know, but I do not know, how to explain it better.
So is there any documentation or sample on how to use objectData? Found one sample in the JDBC sampleDb, but it did not help.
In the context of the repeat/specific row use case, introduce Partial Execution (execMode="partial" / execId="foo") to complement the Partial Refresh of the row. This will hone component tree execution to the row of interest and avoid redundant processing outside of the specified target area.
In terms of documentation for objectData, the best worked example is indeed within the XPagesJDBC.nsf sample database (JDBC_RowSetDatasource.xsp) - it succinctly demonstrates using this datasource as a delegate to create a specialized DataContainer object from the current "row" variable, and conversely managing the specialized saving of the DataContainer object during the save process. Although this example handles the delegation of SQL processing for the current row, the same approach is applicable under many use cases (eg: one example, the underlying view could be a view of XML documents, where you need to delegate per row handling using the objectData datasource through a custom specialized XML processing object).