I was trying to search and add product in the cart using selenium but was not able to successfully do it
driver.get("https://www.bigbasket.com/cl/fruits-vegetables/?nc=nb");
List<WebElement> product = driver.findElements(By.xpath("//div[#qa=\'product\']"));
System.out.println("prdoduct=" + product.size());
for(int i=0;i<product.size();i++)
{
String name = product.get(i).getText();
System.out.println("NAME is" + name);
String xp= "(//button[#qa=\'add\'])" + "["+i+ "]";
System.out.println("xp="+xp);
if(name.contains("Cauliflower"))
{
System.out.println("xp" +xp);
driver.findElement(By.xpath(xp)).click();
}
}
In this previous product is getting selected but when I was debugging it was on the cauliflower but still the previous product is getting selected
there is a chance that some time the element get overlapped by another element. At this time, the normal selenium click will try to click on the overlapped element. so it is better to use js click, it will click the exact element even if it is overlapped
WebElement element= driver.findElement(By.xpath(xp));
JavascriptExecutor js = (JavascriptExecutor) driver;
js.executeScript("arguments[0].click();", element);
There is also a chance for issue in your xpath. Since list starts at 0 , you may need to change i in to i+1 in xp for getting current selection add button.do try this xpath too
String xp= "(//button[#qa=\'add\'])" + "["+(i+1)+ "]";
Induce WebDriverWait() and wait for visibilityOfAllElementsLocatedBy() and use following css selector and xpath.
driver.get("https://www.bigbasket.com/cl/fruits-vegetables/?nc=nb");
List<WebElement> product =new WebDriverWait(driver, 20).until(ExpectedConditions.visibilityOfAllElementsLocatedBy(By.cssSelector("div[qa='product_name']>a")));
System.out.println("prdoduct=" + product.size());
for(int i=0;i<product.size();i++)
{
String name = product.get(i).getText();
System.out.println("NAME is" + name);
if(name.contains("Cauliflower"))
{
driver.findElement(By.xpath("//div[#qa='product_name']//a[text()='" + name + "']/following::button[1]")).click();
}
}
Related
I have a strange case where Angular element is rendering html with 2 random IDs:
WebDriverWait webDriverWait = new WebDriverWait(driver, 5);
System.out.println("Click on Sub Tab " + title_id + " using id locator " + tab_id);
WebElement webElement = webDriverWait.until(ExpectedConditions.elementToBeClickable(By.id("mat-tab-label-5-0")));
webElement.click();
OR
WebDriverWait webDriverWait = new WebDriverWait(driver, 5);
System.out.println("Click on Sub Tab " + title_id + " using id locator " + tab_id);
WebElement webElement = webDriverWait.until(ExpectedConditions.elementToBeClickable(By.id("mat-tab-label-3-0")));
webElement.click();
The order is random and I need some way to click on the available id. Is there some way to combine then for example:
By.id("mat-tab-label-3-0" OR "mat-tab-label-5-0")
Is there some solution?
You can switch to a CSS selector.
ExpectedConditions.elementToBeClickable(By.cssSelector("#mat-tab-label-3-0,#mat-tab-label-5-0"))
# indicates an ID and , indicates an OR.
Assuming those 2 listed are the only 2 ID's that show up, but it is random which one shows up, you can try this:
WebElement webElement = webDriverWait.until(ExpectedConditions.elementToBeClickable(By.id("mat-tab-label-3-0" | "mat-tab-label-5-0")));
Lets consider below href element, here I need to identify "cn=" text in the all the available href links.
My page has 1000 href elements, in that I need to identify the href url which has "cn=" text.
href="/software-advice/article/maternity-benifits-of-office-cn=welcome-inc"
You can use following css selector to identify the number of elements whose href value contains cn=
List<WebElement> listElement=driver.findElements(By.cssSelector("a[href*='cn=']"));
System.out.println("Total number of elements :" + listElement.size());
Or identify the anchor tag and then get the attribute value and then check the value contains
List<WebElement> listelement=driver.findElements(By.cssSelector("a[href]"));
for(WebElement ele:listelement)
{
if(ele.getAttribute("href").contains("cn="))
{
System.out.println("Text found");
}
}
You can use selenium webDriver. and the code snippet is given below
//Get all the webelement starts with tagname a
List<WebElement> urllinks = driver.findElements(By.tagName("a"));
//Iterate one by one until last element present
for (int i = 0; i < urllinks.size(); i++) {
WebElement urllink = urllinks.get(i);
//Get Attribute
String link = urllink.getAttribute("href");
if (link.contains("cn=") {
System.out.println("href contains cn=");
System.out.println(link)
}
Sure go with XPath
//a[contains(#href,'cn=')]
it will identify all the href which has cn= present in it on the page.
if you are sure there is only one element then
WebElement desiredElement=driver.findElements(By.xpath("//a[contains(#href,'cn=')]"));
<div id="address" class="guideFieldDescription short" style="null;display:none">
<p>
Enter home address for the contact person. Leave blank if you don't have one. Home Address and Mailing Address must be located in the United States. No international addresses will be accepted. If the home addresses and mailing addresses are different, you must fill out both sections.<br>
</p>
I'm trying to get the tag content but I'm getting either null or empty using the script below
WebElement WebElement = driver.findElement(By.xpath("//*[#id='address']"));
List<WebElement> paras = WebElement.findElements(By.tagName("p"));
System.out.println("Size = " + paras.size() + " " + paras.toString() );
for (WebElement para : paras) {
System.out.println(para.getText());}
I get the size is = 1, but the getText() return empty.
Selenium getText() can't get text from elements with display: none, which includes the div and its children p paragraphs. If the elements were visible (weren't set to display: none;), your code would be working.
Instead of using getText(), you can use a JavascriptExecutor to get the innerText of the element if it's invisible. See this possible duplicate question: Using selenium, can I get the text of an invisible element?
Here is a function which gets the inner text
/**
* Get the innerText from an element.
* #param driver the WebDriver
* #param element the element to get innerText from
* #return the element's innerText
*/
public static String getInnerText(WebDriver driver, WebElement element) {
JavascriptExecutor executor = (JavascriptExecutor) driver;
return (String) executor.executeScript("return arguments[0].innerText", element);
}
This function is used in the below code sample.
To see the difference between getText() and getting innerText for visible and invisible elements, here is a complete working example program (NOTE the step in the middle to debug and add the display: none manually):
import io.github.bonigarcia.wdm.WebDriverManager;
import java.util.List;
import org.openqa.selenium.By;
import org.openqa.selenium.JavascriptExecutor;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.chrome.ChromeDriver;
class DemonstrateGetTextVsGetInnerTextForDisplayNoneElements {
public static void main(final String[] args) {
WebDriverManager.chromedriver().setup();
WebDriver driver = new ChromeDriver();
// Let's go to a page that mirrors the use case of a div container,
// with children paragraphs.
// The difference: this page doesn't have display: none set on the container.
driver.get("https://www.google.com/intl/en/about/");
final WebElement container = driver.findElement(By.className("home-hero-copy"));
final List<WebElement> paragraphs = container.findElements(By.tagName("p"));
System.out.println("getText() works as normal for *VISIBLE* containers and paragraphs.");
System.out.println("CONTAINER: " + container.getText());
System.out.println(
"LIST OF PARAGRAPHS, Size = " + paragraphs.size() + " " + paragraphs.toString());
for (final WebElement paragraph : paragraphs) {
System.out.println("PARAGRAPH: " + paragraph.getText());
}
System.out.println("SET THE JAVA DEBUGGER TO PAUSE RIGHT HERE, "
+ "GO INTO THE BROWSER AND INJECT \"display: none;\" "
+ "as a style on the div.home-hero-copy element to make"
+ "the div and its child paragraphs invisible. "
+ "You can do this by using the developer tools elements panel.");
System.out.println("If you've made the container invisible, "
+ "you should notice that in the following block of printouts "
+ "that we've still got references to the WebElements (they aren't stale) "
+ "but when we try to getText() while they are invisible from 'display: none;', "
+ "we won't get any text back.");
System.out.println("CONTAINER: " + container.getText());
System.out.println(
"LIST OF PARAGRAPHS, Size = " + paragraphs.size() + " " + paragraphs.toString());
for (final WebElement paragraph : paragraphs) {
System.out.println("PARAGRAPH: " + paragraph.getText());
}
System.out.println("Now, let's try getting the text via 'innerText' with a Javascript Executor");
System.out.println("CONTAINER: " + getInnerText(driver, container));
System.out.println(
"LIST OF PARAGRAPHS, Size = " + paragraphs.size() + " " + paragraphs.toString());
for (final WebElement paragraph : paragraphs) {
System.out.println("PARAGRAPH: " + getInnerText(driver, paragraph));
}
System.out.println("As you can see, getting inner text works when the element is invisible!");
driver.quit();
}
/**
* Get the innerText from an element.
* #param driver the WebDriver
* #param element the element to get innerText from
* #return the element's innerText
*/
public static String getInnerText(WebDriver driver, WebElement element) {
JavascriptExecutor executor = (JavascriptExecutor) driver;
return (String) executor.executeScript("return arguments[0].innerText", element);
}
}
The output of this program should look like this
Connected to the target VM, address: '127.0.0.1:62943', transport: 'socket'
Starting ChromeDriver 71.0.3578.33 (269aa0e3f0db08097f0fe231c7e6be200b6939f7) on port 15369
Only local connections are allowed.
Nov 13, 2018 11:07:46 AM org.openqa.selenium.remote.ProtocolHandshake createSession
INFO: Detected dialect: OSS
getText() works as normal for *VISIBLE* containers and paragraphs.
CONTAINER: Our mission is to organize the world’s information and make it universally accessible and useful.
LIST OF PARAGRAPHS, Size = 1 [[[[[ChromeDriver: chrome on MAC (bbb9840f94250510047ac8e04b055d88)] -> class name: home-hero-copy]] -> tag name: p]]
PARAGRAPH: Our mission is to organize the world’s information and make it universally accessible and useful.
SET THE JAVA DEBUGGER TO PAUSE RIGHT HERE, GO INTO THE BROWSER AND INJECT "display: none;" as a style on the div.home-hero-copy element to makethe div and its child paragraphs invisible. You can do this by using the developer tools elements panel.
If you've made the container invisible, you should notice that in the following block of printouts that we've still got references to the WebElements (they aren't stale) but when we try to getText() while they are invisible from 'display: none;', we won't get any text back.
CONTAINER:
LIST OF PARAGRAPHS, Size = 1 [[[[[ChromeDriver: chrome on MAC (bbb9840f94250510047ac8e04b055d88)] -> class name: home-hero-copy]] -> tag name: p]]
PARAGRAPH:
Now, let's try getting the text via 'innerText' with a Javascript Executor
CONTAINER: Our mission is to organize the world’s information and make it universally accessible and useful.
LIST OF PARAGRAPHS, Size = 1 [[[[[ChromeDriver: chrome on MAC (bbb9840f94250510047ac8e04b055d88)] -> class name: home-hero-copy]] -> tag name: p]]
PARAGRAPH: Our mission is to organize the world’s information and make it universally accessible and useful.
As you can see, getting inner text works when the element is invisible!
Disconnected from the target VM, address: '127.0.0.1:62943', transport: 'socket'
Process finished with exit code 0
And just in case Google ever changes their page, here is what the div and its children look like:
<div class="home-hero-copy center">
<p>Our mission is to <span class="color-hero">organize</span> the world’s <span class="color-hero">information</span> and make it <span class="color-hero">universally accessible</span> and <span class="color-hero">useful</span>.</p>
</div>
I am having difficulty selecting options from a dropdown list using Selenium Webdriver. Below is the HTML snippet:
<span id="id14">
<div class="stadium-input-row">
<span class="inputContainer">
<select id="id1f" class="departurePoint stadiumSelect" onchange="var wcall=..........">
<option value="">Please select</option>
<option value="BHX"> Birmingham - (BHX) </option>
<option value="GLA"> Glasgow - (GLA) </option>
<option value="LON"> London - (LON) </option>
<option value="MAN"> Manchester - (MAN) </option>............
The select tag id changes each time the DOM is loaded.
The select tag is greyed out until it is interacted with.
My code
Select oSelect = new Select(driver.findElement(By.xpath("(.//select)[1]"));
oSelect.selectByVisibleText("Birmingham");
Error
org.openqa.selenium.NoSuchElementException: Cannot locate element
with text: Birmingham
In debugging mode, the dropdown does not seem to be activated (clicked) by the driver.
There's a weird (at least it's weird to me) thing going on on that site. The SELECT that you are trying to access is permanently hidden (which means it can't be interacted with using Selenium). Users interact with DIVs, etc. via a fake dropdown (it's not a SELECT) and the result of those selections are stored in the hidden SELECT. There are two ways to accomplish your task.
Deal with what you can see.
This is really a pain on this site. I think it can be ultimately done but I don't want to spend any more time on it myself so I'll show you the door and you'll have to pick up where I left off. The code below will open the departure dropdown. From there, you find the departure airport and click on it. Done. Harder than it sounds...
driver.findElement(By.cssSelector("div.custom-select.departurePoint.airportSelect")).click();
Cheat and use JavascriptExecutor.
NOTE: By doing this you are no longer executing a real user scenario since users can't click on hidden elements or inject Javascript commands into the page. As long as you are OK with this, here's a sample.
This code executes Javascript on the page using the JavascriptExecutor. You pass the function a string you are looking for in the options, e.g. you can pass "EMA" or "East Midlands - (EMA)" or anywhere inbetween. The JS code will grab the hidden SELECT, search through the OPTIONS, and select the first that matches.
Also note: You will not see the UI update with the selection. Once you click SEARCH, it will work. I have tried it myself and it works.
Yet another note: I use Eclipse as my editor so the // #formatter:off you see in the code below keeps Eclipse from wrapping/reformatting the extra long string that contains the JS code. You can leave or remove it as you like. I like it there because I can still read the JS code with it formatted and indented like it is and I don't want Eclipse messing it up.
selectOption("EMA");
public void selectOption(String option)
{
// #formatter:off
String script =
"function selectOption(s) {\r\n" +
" var sel = document.querySelector('select.departurePoint.airportSelect');\r\n" +
" for (var i = 0; i < sel.options.length; i++)\r\n" +
" {\r\n" +
" if (sel.options[i].text.indexOf(s) > -1)\r\n" +
" {\r\n" +
" sel.options[i].selected = true;\r\n" +
" break;\r\n" +
" }\r\n" +
" }\r\n" +
"}\r\n" +
"return selectOption('" + option + "');";
// #formatter:on
((JavascriptExecutor) driver).executeScript(script);
}
what you need to do:
List<WebElement> options = driver.findElement(By.xpath("//div[#class='stadium-input-row']//select")).findElements(By.tagName("option"));
that will create you list of option tags as WebElement objects
or
Select oSelect = new Select(driver.findElement(By.xpath("//div[#class='stadium-input-row']//select"));
or just take the select as WebElement object
WebElement selectElement = driver.findElement(By.xpath("//div[#class='stadium-input-row']//select"));
Hovering element
Actions action = new Actions(driver);
WebElement hoverElement = driver.findElement(By.xpath("//div[#class='stadium-input-row']//select"));
action.moveToElement(hoverElement);
action.click().build().perform();
As your exception clearly says Cannot locate element with text: Birmingham means it compares with whole visible text option so you should try as below :-
WebDriverWait wait = new WebDriverWait(driver, 10);
WebElement select = wait.until(ExpectedConditions.visibilityOfElementLocated(By.xpath("(.//select)[1]")));
Select oSelect = new Select(select);
oSelect.selectByVisibleText("Birmingham - (BHX)");
or
oSelect.selectByIndex(1);
or
oSelect.selectByValue("BHX");
Edited :- If unfortunately none of the above solution works you should try using JavascriptExecutor as below :-
((JavascriptExecutor)driver).executeScript("var select = arguments[0]; for(var i = 0; i < select.options.length; i++){ if(select.options[i].text.indexOf(arguments[1]) != -1){ select.options[i].selected = true; } }",
driver.findElement(By.xpath("(.//select)[1]")),
"Birmingham");
Hope it will help you..:)
Select will not work in all the situations. Try this code
List <WebElement> options = driver.findElements(By.xpath("Target Element with Options"));
String element;
for(int i=0;i<options.size();i++)
{
element = options[i].get(i).getAttribute("value");
if(element.equals("BHX")){
options.get(i).click();
}
}
I need a script that will navigate through online profiles and return. I have some code that shows me how much online profiles links on page:
driver.get("http://mygirlfund.com");
driver.findElement(By.id("email")).sendKeys("somemail");
driver.findElement(By.id("password")).sendKeys("somepass");
driver.findElement(By.id("btn-submit")).submit();
driver.findElement(By.xpath(".//*[#id='btn-2i']/a")).click();
// log in
List<WebElement> allLinks = driver.findElements(By.xpath("//img[#alt='Online Now!']/../..//a"));
// miracle, have found links of all online profiles
System.out.println(allLinks.size());
for (int i = 1; i < allLinks.size(); i++)
{
for (WebElement link : allLinks)
{
link.click();
driver.navigate().back();
// here write a message
}
i++;
// navigating through user profiles
}
So I need to click on a link then return to previous (main) page but it only navigates to the first link and returns back.
What is the outer for-loop for? Why do you initialise i with 1 (instead of 0)? Why do you increment i twice? The inner loop should be sufficient:
List<WebElement> allLinks = driver.findElements(By.xpath("//img[#alt='Online Now!']/../..//a"));
for (WebElement link : allLinks) {
link.click();
driver.navigate().back();
}
Alternatively, you could retrieve the web elements one by one in a for loop like this (but this will throw an Exception, if there are less than 25 links):
for (int i = 0; i < 25; i++) {
String xpath = "//img[#alt='Online Now!']/../..//a[" + (i+1) + "]";
WebElement link = driver.findElement(By.xpath(xpath));
link.click();
//....
}
I have discovered that when I update webpage the consequences of profile links is breaking down. So, the decision was to open profile link in new window. Do some action and close it.
As guys above said using two loops was stupid decision. This code works for me perfect:
for(WebElement link : driver.findElements(By.xpath("//img[#alt='Online Now!']/../..//a"))){
String originalWindow =driver.getWindowHandle();
System.out.println("Original handle is: "+ originalWindow);
//open link in new window
act.contextClick(link).perform();
act.sendKeys("w").perform();
Thread.sleep(4000);
for (String newWindow : driver.getWindowHandles())
{
driver.switchTo().window(newWindow);
System.out.println("NOW THE CURRENT Handle is: "+ newWindow);
}
Thread.sleep(2000);
//here write a message
driver.close();
driver.switchTo().window(originalWindow);
}
Note:
When I store found links in variable and use it in loop:
List<WebElement> allLinks = driver.findElements(By.xpath("//img[#alt='Online Now!']/../..//a"));
//have found links of all online profiles
System.out.println(allLinks.size());
for (WebElement link : allLinks)
{
String originalWindow =driver.getWindowHandle();
System.out.println("Original handle is: "+ originalWindow);
//open link in new window
act.contextClick(link).perform();
act.sendKeys("w").perform();
Thread.sleep(4000);
//continue handling new window
My script opens just first founded link perpetually.
May be for someone it will be useful. Thanks all!