Unable to find web Element, Elements change based on field highlighting - selenium

Unable to find the Element, tried few ways but unable to get to the element
Picture 1:
id="1_s_1_l_MTO_Transaction_Type" and Class="" (is empty)
In the picture, the highlighted HTML (Document_For) is the next field and you can see Class being added as class="edit-cell ui-state-highlight
Picture 2:
The desired field is highlighted in this picture and id="1_s_1_l_MTO_Transaction_Type" and Class="edit-cell ui-state-highlight" and New HTML is added
<input id="1_MTO_Transaction_Type"...........
I tried the below:
driver.findElement(By.id("1_s_1_l_MTO_Transaction_Type")).click();
driver.findElement(By.xpath(("//tr[starts-with(#class,'ui-widget-content') and #role='row']//td[id='1_s_1_l_MTO_Transaction_Type']"))).click();
driver.findElement(By.xpath(("//tr[#id='1']/td[id='1_s_1_l_MTO_Transaction_Type']"))).click();
All the above gave me Unable to find element
Picture 3:
More HTML to figure out how to find element
It will be a great Help as I have a series of Elements to find in the same way.

Select the Transaction Type using the id and follow the code below.
// Select Transaction Type
String Transaction_Type = ExcelUtils.getCellData(8, 2);
driver.findElement(By.xpath(("//td[contains(#id,'Transaction_Type')]"))).click();
driver.findElement(By.id("s_1_2_47_0_icon")).click();
driver.findElement(By.xpath("//li[#class='ui-menu-item']/div[contains(text(), '" + Transaction_Type + "')]")).click();

Map the column and click on an index (as i'm seeing, when the column cell is clicked, the input field is created, so you have to click it first)
Try it like this (this is C#, java below):
List<IWebElement> TransactionTypeFields => driver.FindElements(By.CssSelector("td[id*='Transaction_type']"));
IWebElement TransactionTypeInput => driver.FindElement(By.CssSelector("td[id*='Transaction_type'] input"));
public void TypeInTransactionTypeCell(string value, int index)
{
TransactionTypeFields[index].Click();
TransactionTypeInput.SendKeys(value);
}
in java, using your logic, should be something like this (there may be some syntax errors as im using notepad++):
public void TypeInTransactionTypeCell(string value, int index)
{
driver.findElements(By.cssSelector("td[id*='Transaction_type']")).get(index).click();
driver.findElement(By.cssSelector("td[id*='Transaction_type'] input")).sendKeys(value);
}
Let me know if it works!

Related

In selenium, how to click all elements in long list of lazy loaded elements?

What do I have - I'm automating one website where there is a big list of elements but not loaded all at once. Say for example I have 200 elements in the list, but only 10 elements are loaded at the moment, and out of these 10 only 5 are visible on the screen.
What I want to do - Now I want to select all of these elements 1 by 1, by clicking on them, because clicking on element selects check box in front of each (Basically i want to tick checkbox). So i will 1st select 5 elements which are visible on page, then i will scroll down to select another visible group, like wise i want to select all 200 elements.
What Problem I'm facing - webdriver.findElements(..) method is returning list of 10 elements which are loaded. But it is not returning list in the order in which the elements are displayed on the page. I'm using for loop to iterate over the list and clicking on elements one by one.
As a result if 6th element is clicked which is not displayed in page, page scrolls till that element and click it, now after that if 2nd element got chance to be clicked, then page should scrolls up to click it, but this time since DOM has loaded again due to scrolling, I get StaleElementReferenceException. If I handle this exception within try catch and get element list again by finding elements, it is not guaranteed to be in the correct order and does not solve my problem.
Solution?? - Is there any way in selenium to get list of elements in order it is displayed on page? Or please let me know what should be the approach to achieve above scenario?
Any suggestions are much appreciated.
Note - JAVA is being used as a programming laungage.
If you also post the HTML that would be more helpful to explain the solution. I am trying to give you a solution by making some assumptions.
Taking a sample HTML code
<div id "checkbox_container>
<input type="checkbox " id="checkbox1 ">
<input type="checkbox " id="checkbox1 ">
<input type="checkbox " id="checkbox1 ">
<input type="checkbox " id="checkbox1 ">
.
.
.
<input type="checkbox " id="checkbox1 ">
</div>
Now write the locators that will give the count of the available checkbox elements and a locator that will select the specific checkbox.
public class SamplePageObjects {
//This locator will select all available checkboxes
public static By ALL_CHECK_BOX = By.xpath("//div[#id='checkbox_container']//input");
//This locator will select the particular element for the given index
public static getMeExpectedCheckBox(int index, int maxCount) {
if (index < 0 || index > maxCount) {
throw new IlleagalArgumentException(index+" is not a valid index");
}
return By.xpath("//div[#id='checkbox_container']//input[" + index + "];
}
}
Now, write your page class
public class SamplePage{
//Gives the count of available elements
public int getCountOfAvailableCheckBox(WebDriver driver){
return driver.findElements(SamplePageObjects.ALL_CHECK_BOX).size();
}
//Selects the specific element
public void selectWebElement(WebDriver driver,int index){
driver.findElement(SamplePageObjects.getMeExpectedCheckBox(index).click();
}
//Selects all available element one by one
public void click(){
int totalCount = getCountOfAvailableCheckBox();
for(int i=0; i< totalCount-1; i++){
try{
selectWebElement(i,totalCount);
} catch(StaleElementReferenceException e){
selectWebElement(i,totalCount);
}
}
}
So first get the list of all available checkboxes. After getting the count, just pass the index value to the locator and perform the action.
Hope it will help you.

How to edit element in table with selenium?

I'm trying to edit value of element that placed it the table on
this page.
I'm using this code:
driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
driver.get("http://samples.gwtproject.org/samples/Showcase/Showcase.html#!CwCellTable");
WebElement firstName = driver.findElement(By.xpath("//*[#id=\"gwt-debug-contentPanel\"]/div[2]/div/div[2]/div/div[3]/div/div/div/table/tbody/tr[1]/td/table/tbody[1]/tr[1]/td[2]/div"));
firstName.click();
firstName.clear();
firstName.sendKeys("test");
It says:
"Element must be user-editable in order to clear it."
How i can edit this element?
Also i have troubles with "Category" field on this page. I'm trying to select each of them successively. Doing this with:
WebElement category = driver.findElement(By.xpath("//*[#id=\"gwt-debug-contentPanel\"]/div[2]/div/div[2]/div/div[3]/div/div/div/table/tbody/tr[1]/td/table/tbody[1]/tr[1]/td[4]/div/select"));
category.sendKeys("Businesses");
category.sendKeys("Friends");
category.sendKeys("Coworkers");
category.sendKeys("Businesses");
category.sendKeys("Family");
I tried to make category.sendKeys(""); once and it works well.
But throws this: "stale element reference: element is not attached to the page document" when i get a lot. How i can change this elements one by one?
This is kinda a strange one. The DOM keeps changing which makes it harder to see what's going on so that you can do the right thing to make it work. You have to click one element which changes the DOM and inserts an INPUT which is what you need to .sendKeys() to. I have tested the code below and it works.
I like to create functions for things like this so that they are reusable. This function changes the first name. rowIndex is the row of the table you want to change and firstName is the desired first name. You have to wait for the table to finish loading because it loads dynamically after the page is loaded.
public static void setFirstName(int rowIndex, String firstName)
{
WebElement firstNameElement = new WebDriverWait(driver, 10)
.until(ExpectedConditions.visibilityOfAllElementsLocatedBy(By.cssSelector("tr[__gwt_row='" + rowIndex + "'] > td > div")))
.get(1);
firstNameElement.click();
firstNameElement.findElement(By.tagName("input")).sendKeys(firstName + "\n");
}
To change the first name of the first row to "FirstName" you would call it like,
setFirstName(0, "FirstName");

dijit/form/select to select search fields in Arc JS API

I'm brand new to javascript, dojo and HTML and I've searched everywhere for examples of this and cannot find any.
I have a map with some feature points and a find task to highlight the feature points on the map, and display them in a grid with it's field attributes. This works great when I specify the search field as:
findParams.searchFields = ["LOCATION"];
But if I add:
findParams.searchFields = ["LOCATION", "MODEL_NUM"];
The grid displays results from multiple fields (ie. searching for attributes in LOCATION "A" would also find attributes in MODEL_NUM containing the letter "A"). So I decided to add a drop down menu select to specify which field to search in (one at a time) so the results are more precise.
So I added the following dijit:
<select id="fieldSelect" data-dojo-type="dijit/form/Select" name="fieldSelect">
<option value="" selected="selected">Select a field</option>
<option value="MODEL_NUM">Model Number</option>
<option value="LOCATION">Location</option>
<option value="NUM_DEFICIENCIES">Number of Deficiencies</option>
<option value="INSTALL_DATE">Install Date</option>
</select>
I then modified the search field statement to:
findParams.searchFields = "[" + "\"" + dom.byId("fieldSelect").value +
"\"" + "]";
When I click my search button I get an Uncaught TypeError: a.join is not a function (FindParameters.js:5)
I hope this is enough information. Does anyone have a solution or a recommendation?
UPDATE
After a suggestion to pass an array and not a string to the findParams.searchFields, I made the following changes:
findParams.searchFields = [];
findParmas.searchFields.push(dom.byId("fieldSelect").value);
This still gave me attribute results from multiple fields. After running a couple small tests:
var selectedField = document.getElementById('fieldSelect').value;
var index = selectedField.options[selectedField.selectedIndex].value;
And:
var selectedField = dom.byId('fieldSelect').value;
I'm finding that in the Chrome developer tools debugger, when I created a breakpoint at that line and executed the statement, both examples had the value of selectedField as 'undefined'.
Is this an issue of not getting the value from the drop down select dijit?
If no value is passed to findParams.searchFields, the API assumes all fields are valid, which is why I'm getting attribute results from multiple fields.
Thanks.
Use dijit.byId instead of dom.byId.
The following works for me:
var value = dijit.byId("fieldSelect").value;
if ("" != value) {
findParams.searchFields = [value];
} else {
findParams.searchFields = ["MODEL_NUM", "LOCATION", "NUM_DEFICIENCIES", "INSTALL_DATE"];
}
I found the problem.
Ultimately it was the registry.byId that led me to the answer, I had to rearrange some code after I realized the searchFields was in the wrong function and not in the function that is called when I click the search button.
But when accessing the dijit, the only thing that worked was registry.byId to access the dijit node and pass the value of the selected value into my searchFields.
Thanks.

How to retrieve the value of an attribute using Seleium WebDriver?

The HTML code is given attached, I do not want to use hard code xpath, the requirement is to make it generic:
<td bgcolor="#FFFFFF">
<input name="hotel_name_0" id="hotel_name_0" type="text" value="Hotel Creek" class="select_text" onfocus="disable_ctrlV()" onkeypress="return Nothingonly(event)">
</td>
Code:
public static boolean fncVerifyTextInColumn(WebElement gridObjWebElement,
String stringToValidate, int columnNumber,String colName) {
boolean flagTextinColumn=false;
ArrayList<WebElement> objRows;
ArrayList<WebElement> objCols;
ArrayList<WebElement> childElement;
objRows=(ArrayList<WebElement>)gridObjWebElement.findElements(By.tagName("tr"));
objCols=(ArrayList<WebElement>)objRows.get(0).findElements(By.tagName("td"));
if(objCols.get(columnNumber).getText().equalsIgnoreCase(colName)){
for(int index=1;index<objRows.size();index++){
objCols=(ArrayList<WebElement>)objRows.get(index).findElements(By.tagName("td"));
childElement=(ArrayList<WebElement>)objCols.get(columnNumber).findElements(By.xpath("//input"));
System.out.println(childElement.get(0).getAttribute("value"));
if(stringToValidate.trim().equalsIgnoreCase(childElement.get(0).getAttribute("value").trim())){
flagTextinColumn=true;
}
}
}
return flagTextinColumn;
}
Method Calling:
fncVerifyTextInColumn(objGrid,hotels,1,"Hotel Name");
I would use cssSelector [id^='hotel_name_'] to locate the element and then getAttribute() retrieve the attribute value
By css = By.cssSelector("[id^='hotel_name_']");
WebElement myDynamicElement = (new WebDriverWait(driver, 10))
.until(ExpectedConditions.presenceOfElementLocated(css));
System.out.println(myDynamicElement.getAttribute("value"));
Notice the regex search of cssSelector here. With ^ I am skipping any dynamic number. Hoping that's the only element with hotel_name_someNumber on the page.
Just do
String attValue = driver.findElement(byAnyMethod).getAttribute("AttributeName");
Hope it helps
I think what you are looking for is this. (I'm assuming you know how to code, you just need a general direction so I'm going to leave out specific code.)
First, find the table the td is in. You might need to use an xPath for this or you'll need to assign an ID to the table so you can locate it.
Then once you have the table, do a FindElements to get the list of TRs under it.
Once you have the TRs, you can loop through them, grab the TDs under that and grab the TD at the index that has the INPUT you want the value of, get the INPUT and then get it's value.
Yep, lots of steps.
A shortcut may be to class all of the inputs you want the value for with a unique class and do a FindElements By className and loop through that list.

Selenium Xpath Not Matching Items

I am trying to use Selenium's Xpath ability to be able to find an set of elements. I have used FirePath on FireFox to create and test the Xpath that I have come up with and that is working just fine but when I use the Xpath in my c# test with Selenium nothing is returned.
var MiElements = this._driver.FindElements(By.XPath("//div[#class='context-menu-item' and descendant::div[text()='Action Selected Jobs']]"));
and the Html looks like this:-
Can Anyone please point me right as everything that I have read the web says to me that this Xpath is correct.
Thanking you all in-advance.
Please post the actual HTML, so we can simply "drop it in" into a HTML file and try it ourselves but I noticed that there is a trailing space at the end of the class name:
<div title="Actions Selected Jobs." class="context-menu-item " .....
So force XPath to strip the trailing spaces first:
var MiElements = this._driver.FindElements(By.XPath("//div[normalize-space(#class)='context-menu-item' and descendant::div[text()='Action Selected Jobs']]"));
Perhaps you don't take into consideration the time that the elements need to load and you look for them when they aren't yet "searchable". UPDATE I skipped examples regarding this issue. See Slanec's comment.
Anyway, Selenium recommends to avoid searching by xpath whenever it is possible, because of being slower and more "fragile".
You could find your element like this:
//see the method code below
WebElement div = findDivByTitle("Action Selected Jobs");
//example of searching for one (first found) element
if (div != null) {
WebElement myElement = div.findElement(By.className("context-menu-item"));
}
......
//example of searching for all the elements
if (div != null) {
WebElement myElement = div.findElements(By.className("context-menu-item-inner"));
}
//try to wrap the code above in convenient method/s with expressive names
//and separate it from test code
......
WebElement findDivByTitle(final String divTitle) {
List<WebElement> foundDivs = this._driver.findElements(By.tagName("div"));
for (WebElement div : foundDivs) {
if (element.getAttribute("title").equals(divTitle)) {
return element;
}
}
return null;
}
This is approximate code (based on your explanation), you should adapt it better to your purposes. Again, remember to take the load time into account and to separate your utility code from the test code.
Hope it helps.