retrieving only certain properties when building a list of objects - java

I recently switch from C# to Java and not able to solve this problem. I am automation UI using selenium. I like to build a model for a list of elements on a page, retrieve property and then work with these properties. In the example bellow, I am searching on amazon.com and getting a list of results. I have SearchResultsModel class which represents every item returned, public List<SearchResultModel> GetAllResults(bool title = false;bool isPrime = false;bool price = false) method which retrieves data from UI and place it my model, it has default parameters which allows me to manipulate what data I want to retrieve instead of retrieving everything. Then I invoking by List<SearchResultModel> actual = myPage.GetAllResults(title:true,isPrime:true); in this instance I get a list of SearchResultsModel that each contain only 2 properties - title and isPrime.
In ideal world I should retrieve all the data from the page but it takes lots of time to do so and defeats the whole purpose of automation of being faster then manual testing.
I could use method overload but then I end up with tens or even hundreds methods. In this example I have only 3 property so I will end up having 9 methods, in case of an object with 10 properties, I am afraid to even do a math. I could use varagrs but then building an argument will become a mess.
I am not sure how to solve this problem in Java. Please advise
public class SearchResultsModel
{
//model that represents a single search result item
public string Title{get;set;}
public boolean IsPrime{get;set;}
public float Price {get;set;]
}
//method to retrieve all the search results from UI
public List<SearchResultModel> GetAllResults(bool title = false;bool isPrime = false;bool price = false)
{
List<SearchResultModel> toReturn = new List<SearchResultModel>();
IList<IWebElement> results = driver.FindElements(By.css("my locattors"))
foreach(IWebElement element in results)
{
SearchResultModel result = new SearchResultModel();
result.Title = title? element.FindElement(By.css("some locator")).GetText(): null;
result.IsPrime = isPrime? element.FindElement(By.css("some locator")).Selected(): false;
result.Price = price? element.FindElement(By.css("some locator")).GetText(): null;
toReturn.Add(result);
}
return toReturn;
}
//this is how I can invoke objects only with a specific properties
List<SearchResultModel> actual = myPage.GetAllResults(title:true,isPrime:true);
foreach(SearchResultModel model in actual)
{
Assert.That(model.isPrime == true);
}

I would build a class that represents what options you want to search for. It's basically a parallel to your SearchResultsModel. You pass an instance of that class into the GetAllResults method and then check each property's value to see if it should be pulled or not.
An example of the options class
public class SearchResultsOptions
{
public boolean Title{get;set;}
public boolean IsPrime{get;set;}
public boolean Price {get;set;]
...
}
An adapted version of your GetAllResults method
public List<SearchResultModel> GetAllResults(SearchResultsOptions searchResultsOptions)
{
List<SearchResultModel> toReturn = new List<SearchResultModel>();
IList<IWebElement> results = driver.FindElements(By.css("my locattors"))
foreach(IWebElement element in results)
{
SearchResultModel result = new SearchResultModel();
result.Title = searchResultsOptions.Title? element.FindElement(By.css("some locator")).GetText(): null;
result.IsPrime = searchResultsOptions.IsPrime? element.FindElement(By.css("some locator")).Selected(): false;
result.Price = searchResultsOptions.Price? element.FindElement(By.css("some locator")).GetText(): null;
// add more fields here
toReturn.Add(result);
}
return toReturn;
}
You would have to instantiate the options class and then pass it to your method
SearchResultsOptions searchResultsOptions = new SearchResultsOptions(true, false, true);
List<SearchResultModel> searchResultsModel = GetAllResults(searchResultsOptions);

Related

GSON - Serialize ArrayList into a JSON array containing JSON objects without duplicates

I'm currently making a novel reader/editor in java using JSON. I've made the reader part with no problem, but the JSON serialization in the editor is giving me problems.
The idea is to add or set an object to an ArrayList like this:
ArrayList<Chapters> allChapters = new ArrayList<>();
private void TAContentKeyTyped(java.awt.event.KeyEvent evt) {
Chapters newChapter = new Chapters(LSChapters.getSelectedValue(), TAContent.getText());
if (allChapters.contains(newChapter)) {
allChapters.set(0, newChapter);
}
else {
allChapters.add(newChapter);
}
String json = gson.toJson(allChapters);
Iterator allChaptersIterator = allChapters.iterator();
while (allChaptersIterator.hasNext()) {
System.out.println(allChaptersIterator.next().toString());
}
System.out.println(json);
}
which outputs this when I press backspace 3 times:
Chapter: Test Content:
Chapter: Test Content:
Chapter: Test Content:
[{"chapter":"Test","content":""},{"chapter":"Test","content":""},{"chapter":"Test","content":""}]
As you can see, instead of putting all inputs with the same chapter name into a single element, the code uses the .add() method instead of the .set() method every time despite putting a .contains() method on the if. Admittedly I didn't expect this approach to work, but I have no idea how to approach this at all.
The desired output should look like this:
Chapter: Test Content: This is content 1
Chapter: Test 2 Content: This is content 2
[{"chapter":"Test","content":"This is content 1"},{"chapter":"Test 2","content":"This is content 2"}]
Where every chapter with the same name is stored in a single element no matter how many keys were pressed.
Thank you in advance.
The Chapters class look like this:
public class Chapters {
private String chapter;
private String content;
public Chapters(String chapter_name, String chapter_content) {
chapter = chapter_name;
content = chapter_content;
}
#Override
public String toString() {
return "Chapter: " + chapter + " Content: " + content;
}
}
Notes:
Please ignore that the .set() method uses index 0, that's just for testing. The real function would use the chapter name's index.
Maybe you should use Set instead of a List? Change your
ArrayList<Chapters> allChapters = new ArrayList<>();
to - for example :
Set<Chapters> chapters = new HashSet<>();
To Set function correctly you should also implement equals(..) and hashCode() in your Chapters, for example, if you can rely only chapter
#Override
public int hashCode() {
return chapter.hashCode();
}
#Override
public boolean equals(Object obj) {
if (obj != null) {
if (obj instanceof Chapters) {
return chapter.contentEquals(((Chapters) obj).getChapter());
}
}
return false;
}
NOTE: above though working are just examples that use only chapter string as 'id' and not fully tested. See more What issues should be considered when overriding equals and hashCode in Java?.
There is no more need to check duplicates explicitly. You can just add chapters to your set and above changes will ensure no duplicates.
Turns out the main problem is the keyboard event. No matter which listener I use (KeyPressed, KeyReleased, KeyTyped) some kind of indexing error always pops up. I finally relented and gave the function its own button. It works perfectly now. This is the new code:
try {
String contentString = TAContent.getText();
int contentStringLen = contentString.length();
int selectedIndex = LSChapters.getSelectedIndex();
int ArrayIndexLength = sessionContent.size();
if (contentStringLen > 1) {
if (ArrayIndexLength < selectedIndex) {
for (int i = 0; i < selectedIndex; i++) {
sessionContent.add(0, "");
}
}
if (selectedIndex >= ArrayIndexLength) {
sessionContent.add(selectedIndex, contentString);
}
else {
sessionContent.set(selectedIndex, contentString);
}
}
else {
JOptionPane.showMessageDialog(null, "Please write chapter content first!");
}
}
catch (Exception e) {
System.err.println(e);
}

how to use page object factory framework for child elments of a webelement

I have a search result page which contains many product items which are produced as a search result. I can get the list of the product items.
But there are product details like price, discount, shipping price which are inside these webelements as child elements. How can I use page object factory model to get the values of these child elements automatically by using the #FindBy annotation.
At the moment I do not know how so I am getting them explicitly by providing the context of the parent WebElement in the findElement(By) function explicitly rather than the automatic mechanism of POF. Question is how to make the context as a WebElement rather than a driver object for a PageObject class. I have not been able to find any understandable web article explaining how to do it. Could someone explain a SIMPLE way to do it hopefully with an example.... I would be really grateful.
Below is the code to explain the Test Class and the class to represent the product.
public class TestProducts {
.....
//I can get the list of products from a
List<WebElement> we_prod_box_list = driver.findElements(By.xpath("//div[#id='content']/descendant::div[starts-with(#class,'product_box_container')]"));
.....
}
public class ProductItem {
private WebDriver driver = null;
private Actions action = null;
private WebElement we_prod_box = null;
public String we_prod_box_title = "";
public WebElement we_pt = null;
public String slideImgTitle = "";
public String oldPrice = "";
public String oldPriceTitle = "";
public String subPrice = "";
public WebElement we_purch_disc = null;
private WebDriverWait wait = null;
public String shippingText = "";
public String shippingCost = "";
public String discPrice = "";
.....
we_pt = we_prod_box.findElement(By.xpath(".//div[contains(#class, 'subcategor_price_tag')]"));
slideImgTitle = we_pt.findElement(By.xpath(".//div[contains(#class, 'subcategor_slideimgtitle')]")).getText();
oldPrice = we_prod_box.findElement(By.xpath(".//div[contains(#class, 'oldprice')]")).getText();
oldPriceTitle = we_prod_box.findElement(By.xpath(".//div[contains(#class, 'oldprice')]")).getAttribute("title");
subPrice = we_prod_box.findElement(By.xpath(".//span[contains(#class, 'sub-price')]")).getText();
......
}
You can get the 4 webelements which contains the attribute of the product item into 4 different lists by using #FindBy. Just pass the complete xpath of these elements to FindBy.
You can iterate the lists to get individual values to test or create a Product Item object etc etc...
You would want to have a "factory" method in TestProducts to generate ProductItem instances:
TestProducts.getProductItems() {
List<ProductItem> items = new ArrayList<ProductItem>();
List<WebElement> we_prod_box_list = driver.findElements(By.xpath("//div[#id='content']/descendant::div[starts-with(#class,'product_box_container')]"));
for (WebElement item : we_prod_box_list) {
ProductItem newItem = new ProductItem(driver, item.getUniqueIdOfItemContainer);
items.add(newItem);
Of course, this implies that ProductItem has a constructor that takes an argument that represents a unique id for that item...I often see an attribute on the div wrapper around items. The constructor then sets the id, e.g. itemWrapperId, for use by other methods.
The ProductItem methods then use findElements to get item information based from that root. E.g. for subPrice in ProductItem
private itemWrapperLocator = "//div[#id='content']/descendant::div[#class,'product_box_container" + itemWrapperId + "')]";
public String subPriceLocator = ".//span[contains(#class, 'sub-price')]";
public getSubPrice() {
this.driver.findElement(By.xpath(this.itemWrapperLocator)).findElement(By.xpath(subPriceLocator)).getText();
Note that I just typed this into here, so please excuse syntax errors...there should be enough here that you get the drift.
This is the real solution that worked for me and what I was looking for.
Selenium Webdriver: Page factory initialization using paths relative to other elements?

Use List<string> created in one method and use in another

I am working on a quiz app that takes a group of questions from my DB and displays each question once after a button click, preferably without duplicating the same question. I have a method called on initialization which gets an array of two arrays from my db, then splits it into two the separate arrays. One of those arrays I then want to use in another method. This is the first method (at the moment I am creating an array string from the list and storing that as a global variable for future use - I am also using a random value from that list to display in a textview):
private class showNextRandomQuestion extends AsyncTask<Void, Void, String> {
#Override
protected String doInBackground(Void... params) {
SQLDatabaseHelper db = new SQLDatabaseHelper(MainActivity.this);
//get the data from the database
List<List<String>> listList = db.getAllAnswersByQuestion2();
//Get the question/text/answer Strings
List<String> questionStrings = listList.get(0); //question Strings
List<String> answerSetIds = listList.get(1);
//Generate random index
Random r = new Random();
int rand = Math.abs((r.nextInt() % questionStrings.size()));
//get answer description for randomly selected question
String questionString = questionStrings.get(rand);
String answerSetId = answerSetIds.get(rand);
questionstringarray = questionStrings.toString();
//remove and square brackets from array of strings
String regex = "\\[|\\]";
answerId = answerSetId.replaceAll(regex, "");
mQuestionString = questionString.replaceAll(regex, "");
return mQuestionString;
}
#Override
protected void onPostExecute(String result) {
//take returned question from above and display it
questionView.setText(mQuestionString);
}
}
I am for some reason really struggling to figure out how I can use the list as it is rather than converting it into a string array ('questionstringarray'). You'll see from my next method, which is triggered by button click, that I had tried to take that string array and turn it back into a list, so I could use it again.
private class showNextRandomQuestion2 extends AsyncTask<Void, Void, String> {
#Override
protected String doInBackground(Void... params) {
List<String> array1 = new ArrayList<String>();
//remove and square brackets from array of strings
String regex = "\\[|\\]";
questionstringarray = questionstringarray.replaceAll(regex, "");
StringTokenizer questionDescr = new StringTokenizer(questionstringarray, ",");
first = questionDescr.nextToken();
first = first.trim();
second = questionDescr.nextToken();
second = second.trim();
third = questionDescr.nextToken();
third = third.trim();
fourth = questionDescr.nextToken();
fourth = fourth.trim();
fifth = questionDescr.nextToken();
fifth = fifth.trim();
array1.add(first);
array1.add(second);
array1.add(third);
array1.add(fourth);
array1.add(fifth);
Collections.shuffle(array1);
//remove and square brackets from array of strings
String regex1 = "\\[|\\]";
//remove values from string when shuffling through so not repeated
String bQuestionText = array1.remove(0);
bQuestionString = bQuestionText.replaceAll(regex1, "");
return bQuestionString;
}
#Override
protected void onPostExecute(String result) {
//take returned question from above and display it
questionView.setText(bQuestionString);
}
}
I don't obviously want to convert from a list in one method only to convert it back to a list in the next. Ultimately I want the first method to get the data from my db which I am happy with - display one of the strings within that method, then store that same list for use in another method where I will display the next string in the list (hopefully then remove it from the list) and on button click display then next string, and next.... - hence the 'Collections.shuffle'.
Any help appreciated. Thanks
And here is my new class which retrieves and stores the list for further use:
package com.example.quizapp;
import java.util.List;
import android.app.Application;
public class QuizQuestionBank extends Application {
#SuppressWarnings("unused")
private List<String> questionStrings;
public List<String> getQuestionStrings(List<String> questionStrings2) {
SQLDatabaseHelper db = new SQLDatabaseHelper(QuizQuestionBank.this);
//get the data from the database
List<List<String>> listList = db.getAllAnswersByQuestion2();
// questionStrings.clear();
//Get the question/text/answer Strings
List<String> questionStrings = listList.get(0); //question Strings
// List<String> answerSetIds = listList.get(1);
return questionStrings;
}
public List<String> setQuestionStrings(List<String> questionStrings) {
return this.questionStrings = questionStrings;
}
}
Ideally you have three concerns here;
1. Return required data from the database, ensure it is in an appropriate format for all client methods.
2. Store the returned data
3. Select (random) question from the returned data.
I would return the data from the database in one method, the return from which I would then store in an instance variable of a class, perhaps called QuizQuestionBank or some such. This would have a method from which a question will be returned.
This way the method return the question can choose a random question from the list or simple the top one, or remove the used questions from listed. Depending on your requirement and it is transparent to the client class, all the client class knows if it calls method on QuizQuestionBank and a question is returned, it doenst worry about how that may be stored or selected.
Simplest way is to use a class for your Question object.
and after getting list of questions from db in a list variable, store that variable data with Application Class using setter methods and whenever required get it by calling getter method(of Application class) inside activity.
and use any shuffling method before starting quiz session(new attempt of quiz).
Edited:
Use it like below:
package com.example.quizapp;
import java.util.List;
import android.app.Application;
public class QuizQuestionBank extends Application {
#SuppressWarnings("unused")
private List<String> questionStrings;
public List<String> getQuestionStrings() {
return questionStrings;
}
public List<String> setQuestionStrings(List<String> questionStrings) {
return this.questionStrings = questionStrings;
}
}
Now use the code to get data from Database only once, before starting quiz,
and put that data into QuizQuestionBank class's questionStrings variable using setter method.
Set it from activity like below:
((QuizQuestionBank) getApplication()).setQuestionStrings(List<String> questionStrings);
And get it within an activity like below:
List<String> questionStrings = ((QuizQuestionBank) getApplication()).getQuestionStrings();
or get it within a fragment:
List<String> questionStrings = ((QuizQuestionBank) getActivity().getApplication()).getQuestionStrings();
of if any other class:
List<String> questionStrings = ((QuizQuestionBank) context.getApplicationContext()).getQuestionStrings();
where context(Context type) will be initialized with passed context argument.

How can I know after TAB where the focus is and how to work with that component in RFT?

I work with RFT and would like to know how to get the object where the Focus is and be able to work with the object after.
For example my script starts than I write
getScreen().inputKeys("{TAB}") and
I would like to know which component has the Focus
and after this I would like to know how can I get the properties of this focused object like
.getProperty(".text"); or .getProperty(".name");
The reason I Need this is because I would like to write a testscript to test the Focus order in our Website.
Thank you in advance,
Krisz
You can do this using a simple method like
private void hasFocus(TestObject to) {
boolean hasFocus = ((Boolean)to.getProperty(".hasFocus")).booleanValue();
if (!hasFocus)
throw new RuntimeException(to.getNameInScript()+" has an invalid focus order!");
}
and calling this method after each TAB press; giving the test object expected to gain focus as the parameter. Sample script code:
browser_htmlBrowser().inputKeys("{TAB}");
hasFocus(firstObj());
browser_htmlBrowser().inputKeys("{TAB}");
hasFocus(secondObj());
I'd do a search on objects whose ".hasFocus" property is set to "true". From there, you could just run the method in a loop to check that the currently focused element is the one you want. I'd also personally recommend (if possible) to check against the ".id" property, since for a given (web)page, that's guaranteed to be a unique identifier... whereas I'm not entirely sure the ".name" property is.
public void testMain(Object[] args) {
ArrayList<String> focusOrder = new ArrayList<String>();
String currentlyFocusedObjectName = "";
// Add element names to the list
focusOrder.add("Object1");
focusOrder.add("Object2");
// ...
focusOrder.add("Objectn");
// Iterate through the list, tabbing and checking ".name" property each time
for (String s: focusOrder) {
TestObject currentObject = getCurrentlyFocusedElement();
// Tab
getScreen().inputKeys("{TAB}");
if (currentObject != null) {
currentlyFocusedObjectName = getCurrentlyFocusedElement().getProperty(".name")
.toString();
// Do other stuff with the object
}
else {
currentlyFocusedObjectName = "";
}
// Verify that the currently focused object matches the current iteration in the list.
vpManual(s + "HasFocus", currentlyFocusedObjectName, s).performTest();
}
}
private TestObject getCurrentlyFocusedElement() {
RootTestObject root = RootTestObject.getRootTestObject();
TestObject[] focusedObjects = root.find(atProperty(".hasFocus", "true");
TestObject currentlyFocusedObject = null;
// Check to ensure that an object was found
if (focusedObjects.length > 0) {
currentlyFocusedObject = focusedObjects[0];
}
else {
unregister(focusedObjects);
return null;
}
// Clean up the object
unregister(focusedObjects);
return currentlyFocusedObject;
}

how do I compare members of an array list against a string?

I am so sorry for this simple question (I have only been working with java for a little bit).
I have an Array List of check boxes and they have a corresponding label with it from another Array List.
i want to be able to set a string variable to a certain value depending on what the label of the selected check box is. I need to compare up to four selected check boxes. So if check box A, with label A = X, then the serial number of that device = Y.
I have tried to use the contains() method, but it returns null.
I have tried to use get(index).getText(), but that only works for a single index (when I have up to four that I need to evaluate).
Any ideas and suggestions are welcome.
Thanks!!
ironmantis7x
===================================================================
Here is a part of my code with the suggestion below:
if (PlatformPanel.Android.isSelected() == true)
{
Iterator<JCheckBox> listIter = Devices.selectedDevices.iterator();
while(listIter.hasNext())
{
JCheckBox nextItemInList = listIter.next();
if (nextItemInList.toString().equals("HTC Droid Eris"))
//if (Devices.selectedDevices.iterator().toString() .equals("HTC Droid Eris"))
{
selectedSerial = "A100000DA78159";
System.out.println(selectedSerial);
System.out.println(Devices.selectedDevices.get(0));
}
if (nextItemInList.toString().equals("Asus Transformer Prime (#1)"))
//if (Devices.selectedDevices.iterator().toString() .equals("Asus Transformer Prime (#1)"))
{
selectedSerial = "BKOKAS127271";
System.out.println(selectedSerial);
System.out.println(Devices.selectedDevices.get(0));
}
}
}
I would use a static map (static means it's a class field, rather than an instance field, so all instances get to re-use the one map):
public class MyClass {
private static Map<String, String> serialNumbers = new HashMap<String, String>() {{
put("HTC Droid Eris", "A100000DA78159");
put("Asus Transformer Prime (#1)", "BKOKAS127271");
// etc
}};
// rest of class
}
then in your code, it's a one-liner:
String selectedValue = ...; // get it directly from the drop down
String selectedSerial = serialNumbers.get(selectedValue);
You may Iterate over the arraylist and compare with String.
Example: Assuming your list is of type String.
Iterator<String> listIter = yourList.iterator();
while(listIter.hasNext())
{
String nextItemInList = listIter.next();
if(nextItemInList.equals("YourOtherString")
{
//Do your logic.
}
}

Categories