Selenium not picking up found elements on xpath - java

Found list of elements either with xpath or CSS (same results in browser console)
int alltips = driver.findElements(By.xpath("//div[#class='column medium-12']//div/ul/li")).size();
int alltips1 = driver.findElements(By.cssSelector("ul.feed-tips#Grid > li.feed-item")).size();
System.out.println(alltips);
System.out.println(alltips1);
As a result of both printing got same result (that there are 21 of 'li' containers exist on a page)
But, when put ran that in selenium webdriver, I got same result for both and it is zero.
Added screenshot from console
What did I do wrong?
Here is a part of HTML:
<div class="column medium-12">
<h1>Free Tips</h1>
<p>Here you'll always find the latest tips posted by our international community of sports betting tipsters. If you're ever in need of inspiration for a bet, this is the place to be! </p>
<div class="row">
<ul class="feed-tips" id="Grid" data-sport="" data-country="" data-
league="">
And below HTML looks like as on screenshot:

findElements does not throw an error if no elements are found, so it is possible that the elements are not found at the time of calling this method.
You can wait for the ul element to be visible before calling findElements by using a WebDriverWait like this
WebDriverWait wait = new WebDriverWait(driver, 10);
wait.until(ExpectedConditions.visibilityOfElementLocated(By.id(#Grid)));
This will wait up to 10 seconds before throwing a timeout. After that, call your findElements method. At this point you know that the parent ul is visible
int alltips = driver.findElements(By.xpath("//ul[#id='Grid']/li")).size();

Related

Selenium | Unable to locate input element

No idea how to address this input text field element with selenium / Java (openjdk 11 2018-09-25).
I tried xpath, cssSelector etc. it never works. Its always "Unable to locate element".
<slot name="input">
<input part="value" tabindex="0" aria-labelledby="vaadin-text-field-input-3">
</slot>
This did NOT work:
driver.findElement(By.xpath("//input[#aria-labelledby='vaadin-text-field-input-3']")).sendKeys("test");
Is there a solution for this?
UPDATE:
This thread solved partly my problem. The solution that worked for me can be found here link.
To send a character sequence to the element you need to induce WebDriverWait for the elementToBeClickable() and you can use either of the following locator strategies:
css_selector:
new WebDriverWait(driver, 20)
.until(ExpectedConditions.elementToBeClickable(
By.cssSelector("div.vaadin-text-field-container div[part=input-field][id^='vaadin-text-field-input'] slot[name='input'] > input[part='value'][aria-labelledby^='vaadin-text-field-input']")
)).sendKeys("pixelhead");
xpath:
new WebDriverWait(driver, 20)
.until(ExpectedConditions.elementToBeClickable(
By.xpath("//div[#class='vaadin-text-field-container']//div[#part='input-field' and starts-with(#id, 'vaadin-text-field-input')]//slot[#name='input']/input[#part='value' and starts-with(#aria-labelledby, 'vaadin-text-field-input')]")
)).sendKeys("pixelhead");
Xpath:
//div[#class='vaadin-text-field-container']//descendant::input[#part='value' and starts-with(#aria-labelledby, 'vaadin-text-field-input')]
Please check in the dev tools (Google chrome) if we have unique entry in HTML DOM or not.
Steps to check:
Press F12 in Chrome -> go to element section -> do a CTRL + F -> then paste the xpath and see, if your desired element is getting highlighted with 1/1 matching node.
If this is unique //div[#class='vaadin-text-field-container']//descendant::input[#part='value' and starts-with(#aria-labelledby, 'vaadin-text-field-input')] then you need to check for the below conditions as well.
Check if it's in any iframe/frame/frameset.
Solution: switch to iframe/frame/frameset first and then interact with this web element.
Check if it's in any shadow-root.
Solution: Use driver.execute_script('return document.querySelector to have returned a web element and then operates accordingly.
Make sure that the element is rendered properly before interacting with it. Put some hardcoded delay or Explicit wait and try again.
Solution: time.sleep(5) or
WebDriverWait(driver, 20).until(EC.visibility_of_element_located((By.XPATH, "//div[#class='vaadin-text-field-container']//descendant::input[#part='value' and starts-with(#aria-labelledby, 'vaadin-text-field-input')]"))).send_keys("test")
If you have redirected to a new tab/ or new windows and you have not switched to that particular new tab/new window, otherwise you will likely get NoSuchElement exception.
Solution: switch to the relevant window/tab first.
If you have switched to an iframe and the new desired element is not in the same iframe context then first switch to default content and then interact with it.
Solution: switch to default content and then switch to respective iframe.
You can start debugging from step1.
Update:
Solution specific to the problem:
Thread.sleep(2000);
WebElement inputButton = (WebElement) ((JavascriptExecutor)driver).executeScript("return document.querySelector('#TextFieldTitle').shadowRoot.querySelector('#vaadin-text-field-input-3 > slot:nth-child(2) > input')");
inputButton.sendKeys("test");
in the place of paste query selector here you will have to go to dev tools again in goog chrome by pressing F12, and then
Go to that input box
Do a right click
Select copy
Select copy JS path.
Ctrl + v into notepad to see what you've got from the dev tool.
It'd be something like this:
document.querySelector("#vaadin-text-field-input-3 > slot:nth-child(2) > input")
replace this paste query selector here with the stuff that is wrapped inside ""
Per the html provided, this works:
driver.find_element(By.XPATH, "//input[#part='value' and contains(#aria-labelledby, 'vaadin-text-field-input')]"]
x = WebDriverWait(driver, 10).until(EC.element_to_be_clickable((By.XPATH, "//input[#part='value' and contains(#aria-labelledby, 'vaadin-text-field-input')]")))
x.send_keys('This is typed here by selenium')
print(f"the typed text in input box is: {x.get_attribute('value')}")
Output:
the typed text in input box is: This is typed here by selenium
Process finished with exit code 0
Looks like part of HTML looks like:
<div class="vaadin-text-field-container">
<label part="label" id="vaadin-text-field-label-3"></label>
<div part="input-field" id="vaadin-text-field-input-3">
<slot name="prefix"></slot>
<slot name="input">
<input part="value" tabindex="0" aria-labelledby="vaadin-text-field-input-3">
</slot>
</div>
</div>
Much better is to build your XPATH locator from some id field:
//div[#id='vaadin-text-field-input-3']//input[contains(#aria-labelledby, 'vaadin-text-field-input')]"]
Also, as mentioned earlier have to check:
if it is unique for this page
if the input element is not dynamic
If you found solved that comment you could move to the code part and use the founded locator with WebDriver:
driver.findElement(
By.xpath("//div[#id='vaadin-text-field-input-3']//input[contains(#aria-labelledby, 'vaadin-text-field-input-3')]"]"
)).sendKeys("test");
Also, keep in mind that you have to know that element is already loaded on a page. As suggested before you could use some explicit wait for your element.

How do you wait for an element in a dynamic web table?

I enter a value into a search box and then the web table starts loading its values based on the search. I do not go to a new page nor is the page itself
refreshing, meaning we are still on the same page. I want to wait for the values of the table to load without having to specifically say "wait X seconds", I want to fetch the elements as soon as the they have loaded in. How do I do this?
Ideally all the values in the table should be loaded but as of right now I am simply trying to wait for the first element in the table:
WebElement element = (new WebDriverWait(driver, 10)).until(ExpectedConditions.elementToBeClickable(By.xpath("//*[#id=\"TableBox-react-component-2dd9bf99-63cb-4c78-9e0d-bed81526e7e5\"]/div/div[2]/table/tbody/tr[1]/td[1]/a")));
This just ends up giving me an error after 10 seconds because it was unable to locate the element. This is with Selenium 2, chromedriver.
Thanks in advance!
EDIT:
HTML structure:
<head>...</head>
<body class="class-name" style>
<div class="main">...</div>
<script src="src-of-script"></script>
<div class>
<header class="page-header" uk-grid uk-panel uk-panel-box">...</header>
<div class="teaching">
<script type="application/json" class="js-react-on-rails-component" data-component-name="TableBox" data-dom-id="TableBox-react-component-*dynamic id*">
<div id="TableBox-react-component-*dynamic id*>
<div data-test="table-box" class="search-table-container">...</div>
You can use try and catch with recursion function. Create a method with try and catch block where In try block, put Thread.sleet(seconds); and then call findElement. In catch call the function again. I had a problem with toast message which generate dynamically for specified time and it resolved with this approach
Considering the id of the elements are dynamic - their suffixes change on every page load, you could try having a locator based on their constant parts. For that, the xpath function contains() is very handy. This locator will select the very last <div> in your sample:
//div[#class="teaching"]/div[contains(#id, "TableBox-react-component")]/div[#data-test="table-box"]
The matched/reuturned element is going to be the <div> with the attribute data-test equal to "table-box" (the right-most in the expression), whose parent element is a <div> with id attribute having "TableBox-react-component" in its value. The <div> with the id must have a <div> parent whose class value is "teaching".
It might take a couple of trails and errors until you get the exact constant parts of the attributes, but that's the idea here.
Once certain about this part of the locator, you have to append the elements down to the <table> and <td> to it, to get to the actual target html element.

FindElement in Selenium without using Xpath

I want do find the element without using xpath, but I have another ul´s elements and "class=title" on my page. So, I cannot use Type or "class=title" either.
<div id="pai">
<div class="def">
<div class="abc" >
<p class=title>Title</p>
<ul>
<li></li>
I´m thinking about something like below, but I don´t know if it is the best practice:
WebElement um = driver.findElements(By.className("abc"));
WebElement dois = um.findElements(By.className("title"));
tamUl = dois.findElements(By.tagName("ul")).size();
In case when you can't or not willing to use Xpath or CSS selectors, you want to get list of all needed elements present on the page. Then you choose (either empirically, by debugging or using conditionals) the index of the specific element to use. Following might be the case you want to try:
List <WebElement> elements = driver.findElements(By.className("title"));
if (elements.size() > 0) {
elements.get(INDEX_OF_YOUR_ELEMENT).findElements(By.tagName("ul")).size();
}
Pay attention to the difference between findElement() and findElements() methods. While findElement() returns only first element if multiple occurrences are found, at the same time it throws NoSuchElementException if nothing is found, where findElements() only returns empty list.

Selecting a value from <md-select> tag using Selenium Webdriver

I am using Selenium Webdriver and working on automating an AngularJS Web App on Chrome. It was going pretty well until I hit a dropdown list on the app.
My test keeps crashing everytime I try to select a value from it. I have been doing my research on this and I have only seen 2 solutions (both of which I have tried but don't work)
Use the Select object. This doesn't work because the html tag is not <select>, its <md-select> and this fails the test.
I then tried to just click on the dropdown element and click on the value - driver.findElement(By.xpath("xpath to dropdown list")).click(); and driver.findElement(By.xpath("xpath do dropdown value")).click();
With example 2, I also tried creating it as a WebElement variable and calling click() separate, but this did not work either.
Any ideas on how I can solve this issue?
Update
HTML for the dropdown list
<div ng-switch-when="dropdown" class="ng-scope">
<zf-form-dropdown>
<div class="dropdown">
<div layout="row">
<div flex="50" class="quote-label">
<p ng-bind-html="::label" class="ng-binding">Title</p>
</div>
<div ng-show="false" flex="10" class="tooltip-icon ng-hide" ng-click="showToolTip(field.get('toolTip'))" role="button" tabindex="0" aria-hidden="true"><img src="img/item-question#2x.png"></div>
<md-select flex="" ng-disabled="quote.isRated() || !input.enabled" ng-change="onDropdownChange()" ng-model="input.value" class="ng-valid md-default-theme ng-touched ng-dirty" role="combobox" id="select_0Q9" aria-haspopup="true" aria-expanded="false" aria-labelledby="select_label_0I1" tabindex="0" aria-disabled="false" aria-invalid="false" aria-owns="select_menu_0Q8"><md-select-label class="md-select-label md-placeholder" id="select_label_0I1"><span></span><span class="md-select-icon" aria-hidden="true"></span></md-select-label></md-select>
</div>
</div>
</zf-form-dropdown>
</div>
HTML for the value I want to select
<md-option ng-value="::item.val" ng-selected="item.checked" ng-repeat="item in getOpts()" tabindex="0" class="ng-scope" role="option" aria-selected="false" id="select_option_0QD" value="MR">
<div class="md-text ng-binding">Mr</div>
<div class="md-ripple-container"></div>
</md-option>
The xpath for the dropdown list is //*[#id="select_0Q9"]
The xpath for the dropdown value is //*[#id="select_option_0QD"]
If you are sure that your Xpath is fine then you can also click using javascriptexecutor so try it out like below:-
WebElement element= driver.findElement(By.xpath("//md-option[#id='select_option_0QD']/div[1]"));
JavascriptExecutor executor = (JavascriptExecutor) driver;
executor.executeScript("arguments[0].click();", element);
Please feel free to locate the element in above code as per your convenience .
As per me your xpath of dropdown should be like below:-
//md-option[#id='select_option_0QD']
And xpath of first div which I suppose want to click is:-
//md-option[#id='select_option_0QD']/div[1]
Change [1] to [2] if you want 2nd value.
In an another aspect you can also store all your element in the list(As you know you can't use select) and click them as per your need or all.
For that you need to use xpath like:-
//md-option[#id='select_option_0QD']/div
Now implement it into code:-
List<WebElement> allelemts = driver.findElements(By.xpath("//md-option[#id='select_option_0QD']/div"));
for(WebElement ele: allelemts){
driver.findElement(By.xpath("//md-option[#id='select_option_0QD']")).click();
JavascriptExecutor executor = (JavascriptExecutor) driver;
executor.executeScript("arguments[0].click();", ele);
}
Hope it will help you :)
Since you are receiving a NoSuchElementException exception, I believe the issue lies in Selenium not able to identify the element. Try any of the following wait methods and then try to click the element.
Explicit Wait: (Most Preferred)
WebDriverWait wait = new WebDriverWait(driver, 20);
WebElement element = wait.until(ExpectedConditions.elementToBeClickable(By.id("elementID")));
or
WebDriverWait wait = new WebDriverWait(driver, 20);
WebElement element = wait.until(ExpectedConditions.presenceOfElementLocated(By.id("elementID")));
Implicit Wait:
driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
Sleep: (Try to avoid this unless absolutely necessary)
Thread.sleep(1000);
EDIT: Added code to check for element's presence using findElements method.
Before using any of these wait methods you could also check for the presence of your element using findElements method.
List<WebElement> element = driver.findElements(By.id("elementId"));
if (element.size() == 0) {
System.out.println("Element not found");
} else{
System.out.println("Element found");
}
I have finally solved the issue!
I got the Selenium IDE and recorded a session where I got as far as selecting the dropdown menu and selecting my value. I then exported the file as a java test case and was able to read the lines where it selected the values, and they were;
driver.findElement(By.cssSelector("#select_08D > #select_label_005 > span.md-select-icon")).click();
driver.findElement(By.id("select_option_08H")).click();
So first off they both do not use xpath to find the elements, the dropdown menu itself is found with the cssSelector and the value is found by the id.
I am just cross referencing again and the id for the value is select_option_08H but while I am looking at Google Console I can see the id for the value is select_option_189

Selenium - unable to locate element by classname

I want to find a p tag with class = "big-number". Here is the code I wrote:
WebElement myDynamicElement = (new WebDriverWait(driver, 10)).until(ExpectedConditions.presenceOfElementLocated(By.className("big-number")));
System.out.println(driver.getTitle());
System.out.println(myDynamicElement);
Here is my output:
[[FirefoxDriver: firefox on MAC (fed46ad4-9ca9-9344-a57a-1d336db3927c)] -> class name: big-number]
I cannot identify the error, it is giving me an output but its makes no sense to me.
Any tips on how I can at least identify my error?
I am certainly sure the element is present, here is the HTML code:
<div id="users-online-container" style="">
<img class="big-number-icon" src="images/usersOnline.png">
<p class="big-number">228</p>
<p class="caption">Users Online</p>
</div>
<div id="users-online-loading"></div>
TimeOutException occurs because driver cannot find element in specific time. Problem in selector i think. If you sure that element always visible, and exists on the page so try next code:
//Select first paragraph in div
driver.FindElement(By.CssSelector("#users-online-container .big-number"));
//if you have several p with same classes you could access any of them using index. e.g.
driver.findElements(By.CssSelector(".big-number"))[index];
Selectors can be #users-online-container .big-number or .big-number. Both will work.
Try below code..
WebElement myDynamicElement = (new WebDriverWait(driver, 10)).until(ExpectedConditions.presenceOfElementLocated(By.className("big-number")));
// It will print the text of the Element:
system.out.println(myDynamicElement.getText());
Also you try to locate the element with the help of XPATH and make sure your locator is uniquely identify the element. Also check that IsDisplayed() and IsEnabled() returns True.
In your code you are printing the WebElement that will print the Hashcode.
In order to get the text of the Element, you'll have to use getText() method.
Hope it will help!

Categories

Resources