Can someone let me know which approach is good for verifying HTML Table. I have to write test case related to adding/deleting/editing HTML table using selenium.
Table looks like this
Name and Branch could be duplicate, the only way to uniquely Identify the row is using id (First column).
I am using the page object pattern, so I need to write the function for adding/editing/deleting and verifying that row exist or not.
how should I write a function to add record and then a separate function to verify that record has been added successfully. As the name could be duplicate I can not verify if name exist in the table or not. The other way is, I return the ID of last row once I add the record. And then I can verify if name on last id is same as I recently added. However this approach has some glitch as well.
is there any better approach for this situation.
For add test case, you could create a function in your PageObject that returns the count of rows that have the same value in the Name field.
In your test case,
Store this number in a variable
Add a record
Back to the grid screen, invoke the row counting function again, comparing it with the stored value
It must be the stored value + 1, otherwise something is wrong.
As an additional check, you could also store the total number of rows in the table prior adding, and check if that value has also increased by one after edition (ensuring no record has been replaced in the process).
Note: If you're using PageFactory, you could also create an IList with the rows in the table, and use its count property instead of creating a counting function.
Edit:Your add method can be stored inside your PageObject, so that you have it separated from assertion. Even if you return the id, without knowing what was in the table prior adding your record, a separated individual verification won't be of much use.
So without seeing the html for this table, I'll have to make some assumptions. It looks like the ID column are hyperlinks, so the xpath for those will be slightly different from the other cells. Okay, so onto the solution.
We first need to think about how we're going to store the data from the table. You want some kind of 2 dimensional object that is easy to work with. I like to use HashMap to store the individual rows. HashMap stores information in un-ordered, key-value pairs. They Key would be the name of the column, and the Value would be the value of that cell for that row.
To store a table's worth of data, I would then put each of those rows that are stored in separate HashMaps and put that into an ArrayList.
Now onto how to scrape the data, the fastest solution is always the one that does the least number of lookups and calls to Selenium. In this case since you have all kinds of weirdness going on with the table, I would target all of the data cells with one lookup.
Without seeing the HTML, my xpath would look something like //table[#id='something']/tbody/tr/td[1]/a|//table[#id='something']/tbody/tr/td[not(./a[./text()='View' or ./text()='Edit' or ./text()='Delete'])]
The Pipe symbol conjoins the 2 xpaths together so it will target both types of cells in the correct order.
Here's my generic TableData class. You create an instance of this class to store the data. The data itself gets stored in the _data object.
public class TableData {
public ArrayList<HashMap<String, String>> _data;
public TableData(ArrayList<HashMap<String, String>> data) {
_data = data;
}
public static TableData get_SiteTable_ByCell(WebDriver driver, By tableCells, String[] headerValues) {
ArrayList<WebElement> tableCellElements = new ArrayList<WebElement>(driver.findElements(tableCells));
ArrayList<HashMap<String, String>> data = new ArrayList<HashMap<String, String>>();
int numberRows = tableCellElements.size() / headerValues.length;
for (int i = 0; i < numberRows; ) {
HashMap<String, String> newRow = new HashMap<>();
for (int j = 0; j < headerValues.length; j++, i++) {
newRow.put(headerValues[j], tableCellElements.get(i).getText());
}
data.add(newRow);
}
return new TableData(data);
}
}
So now that we have our method for getting the data, the values that I need to pass in are...
public TableData getTable(WebDriver driver)
{
String[] headers = {"ID", "Name", "Branch"};
By cellsBy = By.xpath("//table[#id='something']/tbody/tr/td[1]/a|//table[#id='something']/tbody/tr/td[not(./a[./text()='View' or ./text()='Edit' or ./text()='Delete'])]");
return TableData.get_SiteTable_ByCell(driver, cellsBy, headers);
}
Okay, so now we want to get a specific row. I need to write a method that will return a HashMap for the given criteria. This will also go in the TableData class from earlier.
public HashMap<String, String> returnRow(String columnName, String columnValue){
for(HashMap<String, String> row : _data){
if(row.get(columnName).equals(columnValue)){
return row;
}
}
return null;
}
So now that I have all that, my code would look something like...
#Test
public void newTest1()
{
TableData customerTable = getTable(driver);
HashMap<String, String> rowWeWant = customerTable.returnRow("ID", "1");
String valueWeWant = rowWeWant.get("Name");
}
Related
How can I get the last key or value in a Kotlin Map collection? It seems like it cannot be done by using an index value.
There's a couple ways it can be done. While you can't elegantly print a map directly, you may print it's entry set.
The first way, and the way that I DO NOT recommend, is by calling the .last() function on the entry set. This can be accomplished with testMap.entries.last(). The reason I don't recommend this method is because in real data this method is non-deterministic -- meaning there's no way to guarantee the characteristics of the value returned.
While I don't recommend this method, I don't know your application and this may be sufficient.
I DO recommend using the .sortedBy() function on your entry set, and then calling .last() on it. This allows you to make some sort of assumption about the results returned, something that is typically necessary, otherwise why do you want the last?
See this example comparing the two methods and then comparing the method against the order you would get if you iterate with the .forEach function:
fun main(args: Array<String>) {
val testMap = mutableMapOf<Long, String>()
testMap[1] = "Hello"
testMap[5] = "World"
testMap[3] = "Foobar"
println(testMap.entries.last())
println(testMap.entries.sortedBy { it.key }.last())
println("\norder via loop:")
testMap
.entries
.forEach {
println("\t$it")
}
}
Take a look at the output:
3=Foobar
5=World
order via loop:
1=Hello
5=World
3=Foobar
Here we see that the value returned from .last(), is the last value that was inserted into the map - the same happens with .forEach. This is okay, but usually we want our map to have some sort of order. In this example, i've called for the entry set to be sorted by the key value, so that our call to .last() on the entry set returns the key/value pair with the largest key.
I have two classes.
class A {
String aName;
B b;
public A(String aName, B b) {
this.aName = aName;
this.b = b;
}
public String getaName() {
return aName;
}
public B getB() {
return b;
}
}
class B {
String bName;
public B(String bName) {
this.bName = bName;
}
public String getbName() {
return bName;
}
}
I am storing A as a set in Aerospike and A.aName is primary key. I want a secondary key on A.b. I have created index on A.b attribute and able to persist also. But search from the index is not returning anything. As per my understanding, Aerospike supports only three type of indexes: String, Numeric and Geo,. Is there any option for custom object.
Actually you can also index string, numeric and geo within different source types - basic (meaning just a bin with scalar data), list (so you can index strings or numeric data that is contained in a list), map keys and map values.
See: https://www.aerospike.com/docs/guide/query.html#secondary-index-key-source-type
You could model this in a few ways:
As a map. Let's assume that you store the value of A in a bin whose type is a map, it could have two map-keys - aName and bName. You can build a secondary index for string data on map values. Now, if you search for a specific bName you'll have this record come up.
More rationally you'd do the following as separate bins.
Assume that you use several bins, among them two bins to hold aname and bname. Their values are strings. You could now build a secondary index for string values and a basic index type (string data not contained in a complex data type such as list or map). You'd query for all the records where the predicate is bname = foo.
For a more complex situation one or more bname values map to a single aname, you'd actually model this as a lookup table.
Assume a set (table) called users holding records whose keys are the aname. A single key-value operation such as a read or an upsert works on a specific instance of class A, identified by a given aname. One record in Aerospike per instance of A.
You have another set (table) as the lookup table, where for each unique bname you create a record. The specific bname is the key to this record. The value is the aname. So to find the record in the users set, you first look it up in the lookup table by the bname. You use the value of this record as the key for the users record for that aname. This is the most common way of modeling this type of use case, without a secondary index.
Here is the answer post on Aerospike forum.
Binary blobs can be anything, there’s definitely no way to index that. If there is a particular field in your class you can pull out and set as a separate bin with a string/long type then that would work
https://discuss.aerospike.com/t/secondary-index-on-custom-java-object/6485
What is a good way to query (always selecting all columns) and insert into arbitrary Oracle database tables using JDBC? I created the following method (haven't tested it yet) for retrieving any table's attribute names and types (I need the names for display purposes):
public ArrayList<Map<String, String>> retrieveTableAttributes(String tableName) throws SQLException{
ArrayList<Map<String, String>> attributes = new ArrayList<>();
DatabaseMetaData dbmd = conn.getMetaData();
ResultSet resultSet = dbmd.getColumns(null, null, tableName, null);
int i = 0;
while (resultSet.next()) {
attributes.add(new HashMap<String, String>());
attributes.get(i).put(resultSet.getString("COLUMN_NAME"), resultSet.getString("TYPE_NAME"));
i++;
}
resultSet.close();
return attributes;
}
I found this method PreparedStatement#setObject(int parameterIndex, Object x, int targetSqlType) which I think can be used to set a value for any arbitrary column type (in this case I would need to get the column type as an int instead of the type name), but I am not sure about this. So, is there a better way for setting and more importantly getting values from columns with arbitrary types? If it helps, I am trying to create a Java EE GUI tool for manipulating a database (adding, deleting, updating rows from any table in the database).
A simple method to get the type code from a named type using reflection:
public int getTypeByName(String name) {
for (Field field : java.sql.Types.class.getFields()) {
if (name.equalsIgnoreCase(field.getName())) return (Integer) field.get(null);
}
return -1;
}
Note that the TYPE_NAME column is probably not guaranteed to match Oracle's column support. A safer bet might just be to rely on the driver to make the right conversion choices using the untyped setObject and getObject methods.
I am using Maps in my code for the first time, hence require some inputs from you experts.
My requirement is I have to check two different tables from database. Value from First table will be used as Key and Value for second table will be used as Value for the key.
Each key will have multiple values, so I will be storing all values against each key in a arraylist i.e. my Map will be like MAP.
Now, my issue is following:
I don't know the total no. of keys, so I can't create arraylist objects in advance. How to manage this?
How can I check if key exists in map such that if it exists then I have to updated the arraylist corresponding to it only. And if it doesn't exist then create new key, create arraylist corresponding to it, populate arraylist with the value.
Finally I have to iterate whole map and use the key and values.
How can it be implemented? Am I following the right approach? if not what is a better approach?
Thanks
With lists in Java you do not need to know the size up front. That is a requirement for Arrays. Therefore just create your Map
Map> myMap = new HashMap<>();
This should work
if (myMap.containsKey(someKey)) {
myMap.get(someKey).add(someValue); // adds a value to the list that already is in the map
} else {
myMap.put(someKey, Arrays.asList(someValue)); // which inserts a new key/value
}
If you need to iterate over all values in the list then you need a nested for loop
for (Map.Entry> entry : myMap.entrySet()) {
// your key = entry.getKey()
for (ValueType value : entry.getValue()) {
// use your value
}
}
http://docs.oracle.com/javase/7/docs/api/java/util/Map.html
Hope that helps.
I want to use some of predefined lookups without roundrips to Database in NHibernate.
Basically I would like to have code like this:
public class Countries
{
static Countries() {
Australia = new Country
{
Id = 14,
Description = "Australia"
}
}
public static Country Austrlia { get; protected set }
}
Then write this code snippets:
address.Country = Countries.Australia;// Snippet1
if (address.Country == Countries.Australia) { // Snippet2
// Do something
}
So I do override Equals, GetHashCode and even overload operators == and != for Country class lookup.
The Snippet1 works ONLY if the Country with given Id has not been loaded into memory.
Otherwise it throws NonUniqueObjectException saying the object with given Id is already in memory.
To workaraound this I have to evict the loaded country and then assign the lookup value.
This feels wrong and I'm not sure what will happen when the query for Country lookup will be executed again.
So the question is: How to maintain static lookup classes in NHibernate?
Thanks,
Dmitriy.
Check out what we call Enumeration classes..
It's basically the flyweight pattern.
You can persist them, using an IUserType implementation, as the value or the display name.
We do crazy stuff with them. Like provide auto-genned lookup tables with foreign keys for DBA folks while keeping all the values in code.
It seems NHibernate cannot handle 2 objects logically the same (but different instances).
So instead of mixing "static lookup" with Database lookups it is better to only use one of them.
In my case - lookups stored in the database. BUT to avoid roundtrip to the database just for the sake of obtaining the object it is only needed to use Load instead of Get:
address.Country = Session.Load<Country>(CountryIds.Australia); // This does not hit DB
address.Country = Session.Get<Country>(CountryIds.Australia); // This DOES hit DB