I need to get all items in the list, but my script shows only the first item. Please refer to the verifyDisplay assertion in for loop, where I want to show all items in the list. Thanks for the help.
My script:
List<WebElement> groups = driver.findElements(By
.xpath(".//*[#id='competitiveCategoryTemp']/option"));
verifyDisplay("'" + competitive_categories_id_with_space + "'" + "===> The newly added Competitive Category is listed",
By.xpath(".//*[#id='competitiveCategoryTemp']/option"));
boolean sortedGroups = false;
for (int i = 0; i < groups.size() - 1; i++) {
verifyDisplay("'" + groups.get(i).getText() + "'" + "\n"+
"Other Competitive Categories are available and names are SORTED",
By.xpath(".//*[#id='competitiveCategoryTemp']/option"));
if (groups.get(i).getText()
.compareToIgnoreCase(groups.get(i + 1).getText()) > 0) {
sortedGroups = true;
break;
}
sortedGroups = true;
}
if (sortedGroups) {
System.out.println("The Competitive Category names are SORTED");
} else
System.out.println("The Competitive Category names are UN-SORTED");
}
if (groups.get(i).getText()
.compareToIgnoreCase(groups.get(i + 1).getText()) > 0) {
sortedGroups = true;
break;
}
If this condition is met, it breaks out of the for loop, and thus does not proceed forward to the second element. Could that be the problem?
WebDriver has Select class to control dropdown objects. Your approach will also work. But this way it will look neat and you can reuse the existing methods.
Import this lib.
import org.openqa.selenium.support.ui.Select;
Then,
Select dropdown = new Select(driver.findElement(By.id("competitiveCategoryTemp")));
dropdown.getOptions() // will return all the options - it is a List<WebElement>
//To use
for(WebElement option: dropdown.getOptions()){
System.out.println(option.getText());
}
dropdown.getAllSelectedOptions() // will return the default selected options - it is a List<WebElement>
Related
I only want to check for:
if (lore.contains("§eSigned of ")) {
but it doesn't get that it does contain "§eSigned of "
I wrote a Minecraft Command /sign you can add a lore to an item ("Signed of playerrank | playername").
Then i wanted to add an /unsign command to remove this lore.
ItemStack is = p.getItemInHand();
ItemMeta im = is.getItemMeta();
List<String> lore = im.hasLore() ? im.getLore() : new ArrayList<String>();
if (lore.contains("§eSigned of " + getChatName(p))) { // this line is important!
for (int i = 0; i < 3; i++) {
int size = lore.size();
lore.remove(size - 1);
}
im.setLore(lore);
is.setItemMeta(im);
p.setItemInHand(is);
sendMessage(p, "§aThis item is no longer signed");
} else {
sendMessage(p, "§aThis item is not signed!");
}
return CommandResult.None;
Everything works fine until you e.g. change your name. than you can't remove the sign because getChatName(p) has changed.
To fix this i only want to check
if (lore.contains("§eSigned of ")) {
but than it doesn't get it and returns false. (it says lore does not contain "§eSigned of ")
I tried a lot but it only works with the string "§eSigned of " and getChatName(p).
As the documentation "contains" searches for the specific string so it should work as I thought right?
Add:
getChatName(p) returns the rank of the player and the playername like: "Member | domi"
sendMessage(p, "") sends a simple message in the Minecraft chat
The problem you run into is that contains(String) looks for a matching string. What you search for is a check if any string in the list starts with "§eSigned of ".
I would suggest adding a function isSignedItem like this:
private boolean isSignedItem(List<String> lore) {
for (String st : lore)
if (st.startsWith("§eSigned of "))
return true;
return false;
}
and then to use this function to check if the item is signed or not:
[...]
List<String> lore = im.hasLore() ? im.getLore() : new ArrayList<String>();
if (isSignedItem(lore)) { // this line is important!
for (int i = 0; i < 3; i++) {
int size = lore.size();
lore.remove(size - 1);
}
[...]
This is what my code does.
(1.) Open chrome browser and go to footlocker.ca
(2.) Click on the Mens button
(3.) Select 1 random product from the list of 60
(4.) Print the product name and price
(5.) Print all available sizes for the selected product (avaSizes)
(6.) Go back to the products page
(7.) Select a 2nd random product from the list of 60
(8.) Print the product name and price
(9.) Print all available sizes for the selected product (avaSizes)
(10.) Close chrome browser
My problem is that it fails to read the available sizes for the product. I think my problem is in the xpath but I am not to sure as I have tinkered with various xpath's so it may be my code that is the problem. The method is called (avaSizes). If someone can help it would be great. I am doing this for practice so if anyone has some real time job scenario test cases that I could add on to this code it would help me a lot. Thanks.
public class FootlockerExample {
WebElement next;
WebDriver driver = new ChromeDriver();
public void productOne (){
// Open Chrome Browser
System.setProperty("webdriver.chrome.driver", "C:\\Users\\Working\\Workspace\\SeleniumProject\\chromedriver.exe");
// Open Footlocker website and maximize window
driver.get("http://www.footlocker.ca/");
driver.manage().window().maximize();
// Find button element 'Mens' and click
next = driver.findElement(By.xpath("//*[#id='global-nav']/ul/li[1]/a"));
next.click();
// Select a random product
selectRandomProduct();
// Print out the product name and price
String productName = driver.findElement(By.xpath("//*[#id='product_form']/div/span[2]/div/div[1]")).getText();
String Price = driver.findElement(By.xpath("//*[#id='product_form']/div/span[2]/div/div[2]")).getText();
System.out.println("The 1st randomly selected product is " + productName + " and it's cost is " + Price + ".");
// Print all available product sizes
avaSizes();
// Execute new method
productTwo();
}
public void productTwo(){
// Go back a browser page
driver.navigate().back();
// Select a new random product
selectRandomProduct();
// Print out the product name and price
String productName = driver.findElement(By.xpath("//*[#id='product_form']/div/span[2]/div/div[1]")).getText();
String Price = driver.findElement(By.xpath("//*[#id='product_form']/div/span[2]/div/div[2]")).getText();
System.out.println("The 2nd randomly selected product is " + productName + " and it's cost is " + Price + ".");
// Print all available product sizes
avaSizes();
driver.close();
}
public void selectRandomProduct(){
// Find and click on a random product
List<WebElement> allProducts = driver.findElements(By.xpath("//*[#id='endecaResultsWrapper']/div[3]//img"));
Random rand = new Random();
int randomProduct = rand.nextInt(allProducts.size());
allProducts.get(randomProduct).click();
}
public void avaSizes(){
// Find all the available shoe sizes for each randomly selected product
List<WebElement> avaSizes = driver.findElements(By.xpath("//*[#id='product_sizes']"));
int totalSizes = 0;
for(int i=0; i<avaSizes.size(); i++){
if(avaSizes.get(i).isEnabled()==true){
avaSizes.get(i).getText();
System.out.println(avaSizes);
totalSizes++;
}else{
System.out.println("Out of stock in all sizes.");
}
}
System.out.println("This product is available in: " + totalSizes + " sizes.");
}
public static void main(String[] args) {
FootlockerExample obj1 = new FootlockerExample();
obj1.productOne();
}
}
I see that the dropdown element has an id and is of type Select.
You can work with it using the Select object:
Select select = new Select(driver.findElement(By.id("product_sizes")));
List<WebElement> availableSizes = select.getOptions();
for (WebElement size : availableSizes) {
System.out.println(size.getText());
}
With a little help from Marius D above, I have figured out the problem and fixed my code.
Here is my fixed answer for future in case someone is stuck on the same issue.
public void avaSizes(){
Select select = new Select(driver.findElement(By.id("product_sizes")));
// Find all the available shoe sizes for each randomly selected product
List<WebElement> avaSizes = select.getOptions();
int totalSizes = 0;
for(WebElement size:avaSizes){
if(size.isEnabled()==true){
System.out.println(size.getText());
totalSizes++;
}else{
System.out.println("Out of stock in " + size.getText());
}
}
System.out.println("This product is available in: " + totalSizes + " sizes.");
}
When the code is ran the nested loop causes it to create occasional duplicate entries to the system, i have spent a while looking through this but still cant find what is causing this, would greatly appreciate any help?
for(int i = 0; i < subWorkItemElement.getChildNodes().getLength(); i++) {
Boolean test = false;
WorkItemCommon existingChild = null;
String summary = null;
if(subWorkItemElement.getChildNodes().item(i).getNodeName().equals("workitem")) {
// We know it's a work item - but is it in the existing list?
Element childWorkItem = (Element) subWorkItemElement.getChildNodes().item(i);
for(int j = 0; j < subWorkItemElement.getChildNodes().getLength(); j++) {
if(childWorkItem.getChildNodes().item(j) instanceof Element) {
if(((Element)childWorkItem.getChildNodes().item(j)).getNodeName().equals("details")) {
summary = ((Element) childWorkItem.getChildNodes().item(j)).getElementsByTagName("summary")
.item(0).getTextContent();
for(String k : userInfoHashMap.keySet()) {
summary = summary.replace("${" + k + "}", userInfoHashMap.get(k));
}
if(childHashTable.containsKey(summary)) {
test = true;
existingChild = childHashTable.get(summary);
IWorkItem workItem = existingChild.getWorkItem();
System.out.println("INFO: The task with summary \"" + summary + "\" already exists. Skipping creation.");
System.out.println("this task is work item: " + workItem.getId());
//either check the tasks in the xml for updated details and then modify the existing workitem
//or just modify the work item without checking for updates
makeChildTask(childWorkItem, existingChild, childHashTable, userInfoHashMap, workItemHashMap, rtc, false);
break;
}
}
}
}
if(!test) {
System.out.println("INFO: The task with summary " + summary + " does not currently exist. Creating.");
makeChildTask(childWorkItem, thisItem, childHashTable, userInfoHashMap, workItemHashMap, rtc, true);
} else makeFromExistingChildTask(childWorkItem, existingChild, userInfoHashMap, workItemHashMap, rtc);
}
}
You are possibly (not sure what makeChildTask() does) changing an XML structure while iterating through the children list. While not necessarily incorrect, this can mean you get entries inserted while you process the list. Since you call the subWorkItemElement.getChildNodes().getLength() each time instead of cache'ing it, this might result in the length changing in between the loop iterations.
Using Selenium to gather text of all p elements within a specific div. I noticed while using List, Selenium scanned the whole DOM and stored empty text. So, I wanted to iterate through the DOM and only store values that are not equal to empty text via java.util.Iterator. Is this possible? Is there a more efficient way other than the List approach?
Iterator Approach:
public static boolean FeatureFunctionsCheck(String Feature){
try
{
Iterator<WebElement> all = (Iterator<WebElement>) Driver.Instance.findElement(By.xpath("//a[contains(text()," + Feature + ")]/ancestor::h3/following-sibling::div/div[#class='navMenu']/p"));
boolean check = false;
while(all.hasNext() && check){
WebElement temp = all.next();
if(!temp.getText().equals(""))
{
Log.Info("Functions: " + temp.getText());
all = (Iterator<WebElement>) Driver.Instance.findElement(By.xpath("//a[contains(text()," + Feature + ")]/ancestor::h3/following-sibling::div/div[#class='navMenu']/p"));
}
else
check = true;
}
return false;
}
catch(Exception e)
{
Log.Error("Failed()" + e);
return false;
}
}
Iterator Approach throws exception...
java.lang.ClassCastException: org.openqa.selenium.remote.RemoteWebElement cannot be cast to java.util.Iterator
List Approach Works, However Not Sure If This Is Efficient
public static boolean FeatureFunctionsCheck(String Feature){
try
{
List<WebElement> AllModelFunctions = new ArrayList<WebElement>();
Log.Info("[Test-235]: Selecting Feature");
for(WebElement element: AllModelFunctions){
if(!element.getText().equals(""))
{
Log.Info("Functions: " + element.getText());
}
}
return false;
}
catch(Exception e)
{
Log.Error("Failed()" + e);
return false;
}
}
findElement returns one WebElement. What you probably meant to do is to search for all elements with given xpath, using findElements:
Driver.Instance.findElements(...
Also the syntax is over-complicated. You can just get the list and iterate through it:
List<WebElement> elements = Driver.Instance.findElements(...);
for(WebElement element : elements) {
if(!element.getText().equals(""))
{
Log.Info("Functions: " + element.getText());
}
}
BTW I have to fully trust that Driver.Instance is an instance of the driver (typically in Java you don't have capitals for class instances, so I'm not sure if I understood it right). A more common syntax would be something like:
WebDriver driver = new FirefoxDriver(); // or another browser
driver.findElements(...);
// ...
I received a table and was able to get and validate the data (whether the email is ACTUALLY an email and so forth). We want to validate the data that is displayed on the front end with the backend. There was a table (I had seen the table- the first column was name and then email , phone number, company , country and the date).
Now, the person on the front-end, switched up the columns. I had seen the table before and therefore I knew the order I would receive my information. I will have to change the code everytime a small change is made on the front end. FYI, the table headers are defined with "data-name" so I will be able to use it if your solution involves something w/ table headers. My code is posted below:
public static void getTableContents(){
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
//TODO Replace this w. until it find command
e.printStackTrace();
}
log("TABLE CONTENTS VERIFICATION");
//Get the table contents
WebElement table_element = driver.findElement(By.className(TABLE_RESPONSE));
//Click on a button to switch into the desired column
WebElement switchColumn = driver.findElement(By.cssSelector(".switchColumn img.pull-right"));
switchColumn.click();
// We do not want the first two contents as they represent default or error case.
List<WebElement> tr_collection=table_element.findElements(By.xpath("//tbody//tr[position()>2]"));
int i=1;
for(WebElement trElement : tr_collection)
{
List<WebElement> td_collection=trElement.findElements(By.xpath("td"));
int j=1;
for(WebElement tdElement : td_collection)
{
String check = tdElement.getText();
if(j==1) {
if(isValidName(check))
passed("Name Test : " );
else{
log(check + " is not a valid name");
}
}
if(j==2) {
if(isValidEmail(check))
{ passed("Email address Test : ");
}
else
log(check + " is not a valid email");
}
if(j==3) {
if(isValidNumber(check))
passed("Valid Number test : ");
else
log(check + " is not a valid number");
}
if(j==6){
if(isValidIccid(check))
passed("Valid Iccid test : ");
else
log(check+ " is not a valid Iccid");
}
if(j==4){
//Blank (for a while)
}
if(j==5){
if(isValidCountry(check))
passed("Valid country test : ");
else
log(check+ " is not a valid country");
}
j++;
}
System.out.println();
i++;
}
}
Is there any quick way of changing this code to my requirements? I can't keep changing the numbers (1,2,3,4,5,6) all the times. I am just looking for clever ways to UPDATE my code rather than CHANGE my code completely.
Any help/tip is greatly appreciated.EDIT: Also, I will be changing my if/else statements to switch cases so it is easier to understand. But as of now, I got a great problem cause I might have to change my entire code so please do not mind.
If your table has the table headers with classes like:
data-Name
data-Email
then you can use this in the code as follows:
// We do not want the first two contents as they represent default or error case.
List<WebElement> tr_collection=table_element.findElements(By.xpath("//tbody//tr[position()>2]"));
int i=1;
for(WebElement trElement : tr_collection)
{
List<WebElement> td_collection=trElement.findElements(By.xpath("td"));
int j=1;
for(WebElement tdElement : td_collection)
{
String check = tdElement.getText();
String header = driver.findElement(By.xpath("//tbody//tr/th[" + j + "]")).getAttribute("class");
if(header.equals("data-Name")) {
if(isValidName(check))
passed("Name Test : " );
else{
log(check + " is not a valid name");
}
}
if(header.equals("data-Email")) {
if(isValidEmail(check))
{ passed("Email address Test : ");
}
else
log(check + " is not a valid email");
}
//... and so on
}
}
You might need to change this line to reflect the correct way for you to identify the table headers:
String header = driver.findElement(By.xpath("//tbody//tr/th[" + j + "]")).getAttribute("class");
but the point is to use the "j" counter to track the column that you are on and check the class name of the header for that column. The order of the columns should no longer matter if you identify them this way.