I am trying to find either one of the 2 elements in selenium (java). If anyone is found then that should be clicked. following is not working;
WebDriverWait wait5 = new WebDriverWait(driver, 5);
wait5.until(ExpectedConditions.elementToBeClickable(By.xpath("//a[#data-period='R6M'] || //span[#title='FYTD']"))).click();
The xpath is invalid, or is a single |
wait5.until(ExpectedConditions.elementToBeClickable(By.xpath("//a[#data-period='R6M'] | //span[#title='FYTD']"))).click();
You can also use ExpectedConditions.or fo this
wait5.until(ExpectedConditions.or(
ExpectedConditions.elementToBeClickable(By.xpath("//a[#data-period='R6M']")),
ExpectedConditions.elementToBeClickable(By.xpath("//span[#title='FYTD']"))));
To get WebElement from one of two conditions you can build your own implementation
public ExpectedCondition<WebElement> customCondition(By... locators) {
#Override
public WebElement apply(WebDriver d) {
for (By locator in locators) {
return ExpectedConditions.elementToBeClickable(locator).apply(d);
}
}
}
WebElement element = wait4.until(customCondition(By.xpath("//a[#data-period='R6M']"), By.xpath("//span[#title='FYTD']")));
To induce WebDriverWait for either one of the 2 elements using Selenium java client you can use the following Locator Strategy:
WebDriverWait wait = new WebDriverWait(driver, 10);
wait.until(ExpectedConditions.or(
ExpectedConditions.elementToBeClickable(By.xpath("//a[#data-period='R6M']")),
ExpectedConditions.elementToBeClickable(By.xpath("//span[#title='FYTD']"))
));
Reference
You can find a relevant discussion in:
How to wait for either of the two elements in the page using selenium xpath
Related
I am trying to make some tests using selenium based Katalon Studio. In one of my tests I have to write inside a textarea. The problem is that I get the following error:
...Element MyElement is not clickable at point (x, y)... Other element would receive the click...
In fact my element is place inside some other diva that might hide it but how can I make the click event hit my textarea?
Element ... is not clickable at point (x, y). Other element would receive the click" can be caused for different factors. You can address them by either of the following procedures:
Element not getting clicked due to JavaScript or AJAX calls present
Try to use Actions Class:
WebElement element = driver.findElement(By.id("id1"));
Actions actions = new Actions(driver);
actions.moveToElement(element).click().build().perform();
Element not getting clicked as it is not within Viewport
Try to use JavascriptExecutor to bring the element within Viewport:
JavascriptExecutor jse1 = (JavascriptExecutor)driver;
jse1.executeScript("scroll(250, 0)"); // if the element is on top.
jse1.executeScript("scroll(0, 250)"); // if the element is at bottom.
Or
WebElement myelement = driver.findElement(By.id("id1"));
JavascriptExecutor jse2 = (JavascriptExecutor)driver;
jse2.executeScript("arguments[0].scrollIntoView()", myelement);
The page is getting refreshed before the element gets clickable.
In this case induce some wait.
Element is present in the DOM but not clickable.
In this case add some ExplicitWait for the element to be clickable.
WebDriverWait wait2 = new WebDriverWait(driver, 10);
wait2.until(ExpectedConditions.elementToBeClickable(By.id("id1")));
Element is present but having temporary Overlay.
In this case induce ExplicitWait with ExpectedConditions set to invisibilityOfElementLocated for the Overlay to be invisible.
WebDriverWait wait3 = new WebDriverWait(driver, 10);
wait3.until(ExpectedConditions.invisibilityOfElementLocated(By.xpath("ele_to_inv")));
Element is present but having permanent Overlay.
Use JavascriptExecutor to send the click directly on the element.
WebElement ele = driver.findElement(By.xpath("element_xpath"));
JavascriptExecutor executor = (JavascriptExecutor)driver;
executor.executeScript("arguments[0].click();", ele);
I assume, you've checked already that there is no any other component overlapping here (transparent advertisement-iframes or some other component of the DOM => seen quite often such things in input/textfield elements) and, when manually (slowly) stepping your code, it's working smoothly, then ajax calls might cause this behaviour.
To avoid thread.sleep, try sticking with EventFiringWebDriver and register a handle to it.
(Depending on your application's techstack you may work it for Angular, JQuery or wicket in the handler, thus requiring different implementations)
(Btw: This approach also got me rid of "StaleElementException" stuff lots of times)
see:
org.openqa.selenium.support.events.EventFiringWebDriver
org.openqa.selenium.support.events.WebDriverEventListener
driveme = new ChromeDriver();
driver = new EventFiringWebDriver(driveme);
ActivityCapture handle=new ActivityCapture();
driver.register(handle);
=> ActivityCapture implements WebDriverEventListener
e.g. javascriptExecutor to deal with Ajax calls in a wicket/dojo techstack
#Override
public void beforeClickOn(WebElement arg0, WebDriver event1) {
try {
System.out.println("After click "+arg0.toString());
//System.out.println("Start afterClickOn - timestamp: System.currentTimeMillis(): " + System.currentTimeMillis());
JavascriptExecutor executor = (JavascriptExecutor) event1;
StringBuffer javaScript = new StringBuffer();
javaScript.append("for (var c in Wicket.channelManager.channels) {");
javaScript.append(" if (Wicket.channelManager.channels[c].busy) {");
javaScript.append(" return true;");
javaScript.append(" }");
;
;
;
javaScript.append("}");
javaScript.append("return false;");
//Boolean result = (Boolean) executor.executeScript(javaScript.toString());
WebDriverWait wait = new WebDriverWait(event1, 20);
wait.until(new ExpectedCondition<Boolean>() {
public Boolean apply(WebDriver driver) {
return !(Boolean) executor.executeScript(javaScript.toString());
}
});
//System.out.println("End afterClickOn - timestamp: System.currentTimeMillis(): " + System.currentTimeMillis());
} catch (Exception ex) {
//ex.printStackTrace();
}
}
As #DebanjanB said, your button (or another element) could be temporarily covered by another element, but you can wait and click it even if you don't know which element is covering the button.
To do this, you can define your own ExpectedCondition with the click action:
public class SuccessfulClick implements ExpectedCondition<Boolean> {
private WebElement element;
public SuccessfulClick(WebElement element) { //WebElement element
this.element = element;
}
#Override
public Boolean apply(WebDriver driver) {
try {
element.click();
return true;
} catch (ElementClickInterceptedException | StaleElementReferenceException | NoSuchElementException e) {
return false;
}
}
}
and then use this:
WebDriverWait wait10 = new WebDriverWait(driver, 10);
wait10.until(elementToBeClickable(btn));
wait10.until(new SuccessfulClick(btn));
Try Thread.Sleep()
Implicit - Thread.Sleep()
So this isn’t actually a feature of Selenium WebDriver, it’s a common feature in most programming languages though.
But none of that matter.
Thread.Sleep() does exactly what you think it does, it’s sleeps the thread. So when your program runs, in the majority of your cases that program will be some automated checks, they are running on a thread.
So when we call Thread.Sleep we are instructing our program to do absolutely nothing for a period of time, just sleep.
It doesn’t matter what our application under test is up to, we don’t care, our checks are having a nap time!
Depressingly though, it’s fairly common to see a few instances of Thread.Sleep() in Selenium WebDriver GUI check frameworks.
What tends to happen is a script will be failing or failing sporadically, and someone runs it locally and realises there is a race, that sometimes WedDriver is losing. It could be that an application sometimes takes longer to load, perhaps when it has more data, so to fix it they tell WebDriver to take a nap, to ensure that the application is loaded before the check continues.
Thread.sleep(5000);
The value provided is in milliseconds, so this code would sleep the check for 5 seconds.
I was having this problem, because I had clicked into a menu option that expanded, changing the size of the scrollable area, and the position of the other items. So I just had my program click back on the next level up of the menu, then forward again, to the level of the menu I was trying to access. It put the menu back to the original positioning so this "click intercepted" error would no longer happen.
The error didn't happen every time I clicked an expandable menu, only when the expandable menu option was already all the way at the bottom of its scrollable area.
I am trying to automate application,tried first to find xpath or CSS locators unable to find looks no frame also inside the element.
I am able to handle using JavaScript but unable to enter full text in the search box,it's trimming some text,,please help me.
JavaScript which i tried.
((JavascriptExecutor)driver).executeScript("return document.querySelector('#app').shadowRoot.querySelector('#base > wego-search-form').shadowRoot.querySelector('div > wego-hotel-search-form').shadowRoot.querySelector('#loc').shadowRoot.querySelector('#item0 > div.disable-select.city-country-name').click();");
((JavascriptExecutor)driver).executeScript("return document.querySelector('#app').shadowRoot.querySelector('#base > wego-search-form').shadowRoot.querySelector('div > wego-hotel-search-form').shadowRoot.querySelector('#dates').shadowRoot.querySelector('#depart').shadowRoot.querySelector('#btn').click();");
My scenario i want to click search form and enter some destination details,If possible anyway i can handle this case using locators suggest me
Shadow DOM Elements are used in this website. Shadow DOM provides encapsulation for the JavaScript, CSS, and templating in a Web Component.
Shadow DOM allows hidden DOM trees to be attached to elements in the
regular DOM tree — this shadow DOM tree starts with a shadow root,
underneath which can be attached to any elements you want, in the same
way as the normal DOM.
Refer this To get details about it or for more details Google it.
Now handle Shadow element take reference from this blog. I've tried the below code to enter text as you expected and its working for me.
public static WebDriver driver;
public static void main(String[] args){
System.setProperty("webdriver.chrome.driver", "driver_path");
driver = new ChromeDriver();
driver.get("https://www.wego.com.my/hotels");
driver.manage().timeouts().implicitlyWait(15, TimeUnit.SECONDS);
driver.manage().window().maximize();
WebElement root1 = driver.findElement(By.id("app"));
WebElement shadowRoot1 = expandRootElement(root1);
WebElement root2 = shadowRoot1.findElement(By.tagName("wego-search-form"));
WebElement shadowRoot2 = expandRootElement(root2);
WebElement root3 = shadowRoot2.findElement(By.tagName("wego-hotel-search-form"));
WebElement shadowRoot3 = expandRootElement(root3);
WebElement root4 = shadowRoot3.findElement(By.id("loc"));
WebElement shadowRoot4 = expandRootElement(root4);
shadowRoot4.findElement(By.cssSelector("div.root-container div.container")).click();
WebElement element = shadowRoot4.findElement(By.id("searchKeywordInput"));
Actions action = new Actions(driver);
action.click(element).sendKeys(Keys.chord(Keys.CONTROL, "a"));
element.sendKeys(Keys.DELETE);
element.sendKeys("narendra");
}
public static WebElement expandRootElement(WebElement element) {
WebElement newElement = (WebElement) ((JavascriptExecutor) driver).executeScript("return arguments[0].shadowRoot", element);
return newElement;
}
Updated
As an alternative of sendKeys(), JavascriptExecutor can be used to set the value of text box. Use below code
WebElement element = shadowRoot4.findElement(By.id("searchKeywordInput"));
JavascriptExecutor javascriptExecutor = (JavascriptExecutor) driver;
javascriptExecutor.executeScript("arguments[0].value='Your Text Goes Here';", element);
I've tested this so many time and this is working fine in each case.
Note: using JavascriptExecutor may not trigger the search result auto suggestion.
Selenium cant find this xpath I tried every way I need to click last button Deactivate but I cant
I tried xpath,cssSelectors,
#When("^I click deactivate button$")
public void iClickDeactivateButton(){
WebElement deactivateBatchButton = driver.findElement(By.xpath("//BUTTON[#_ngcontent-c14=''][text()='Deactivate'][text()='Deactivate']/self::BUTTONclass='deactivate']"));
deactivateBatchButton.click();
}
I want to click this button and carry one rest of the tests.
As the desired element is a Angular element and to locate it you have to induce WebDriverWait and you can use either of the following solutions:
cssSelector:
WebElement deactivateBatchButton = new WebDriverWait(driver, 20).until(ExpectedConditions.elementToBeClickable(By.cssSelector("button.deactivate.xh-highlight")));
xpath:
WebElement deactivateBatchButton = new WebDriverWait(driver, 20).until(ExpectedConditions.elementToBeClickable(By.xpath("//button[#class='deactivate xh-highlight' and text()='Deactivate']")));
You can carry on with the button name.
WebElement deactivateBatchButton = driver.findElement(By.xpath("//*[text()='Deactivate']"));
deactivateBatchButton.click();
I'm new to Selenium and need to check if element is clickable in Selenium Java, since element.click() passes both on link and label.
I tried using the following code, but it is not working:
WebDriverWait wait = new WebDriverWait(Scenario1Test.driver, 10);
if(wait.until(ExpectedConditions.elementToBeClickable(By.xpath("(//div[#id='brandSlider']/div[1]/div/div/div/img)[50]")))==null)
elementToBeClickable is used for checking an element is visible and enabled such that you can click it.
ExpectedConditions.elementToBeClickable returns WebElement if expected condition is true otherwise it will throw TimeoutException, It never returns null.
So if your using ExpectedConditions.elementToBeClickable to find an element which will always gives you the clickable element, so no need to check for null condition, you should try as below :-
WebDriverWait wait = new WebDriverWait(Scenario1Test.driver, 10);
WebElement element = wait.until(ExpectedConditions.elementToBeClickable(By.xpath("(//div[#id='brandSlider']/div[1]/div/div/div/img)[50]")));
element.click();
As you are saying element.click() passes both on link and label that's doesn't mean element is not clickable, it means returned element clicked but may be there is no event performs on element by click action.
Note:- I'm suggesting you always try first to find elements by id, name, className and other locator. if you faced some difficulty to find then use cssSelector and always give last priority to xpath locator because it is slower than other locator to locate an element.
Hope it helps you..:)
There are instances when element.isDisplayed() && element.isEnabled() will return true but still element will not be clickable, because it is hidden/overlapped by some other element.
In such case, Exception caught is:
org.openqa.selenium.WebDriverException: unknown error: Element is not
clickable at point (781, 704). Other element would receive the click:
<div class="footer">...</div>
Use this code instead:
WebElement element=driver.findElement(By.xpath"");
JavascriptExecutor ex=(JavascriptExecutor)driver;
ex.executeScript("arguments[0].click()", element);
It will work.
wait.until(ExpectedConditions) won't return null, it will either meet the condition or throw TimeoutException.
You can check if the element is displayed and enabled
WebElement element = driver.findElement(By.xpath);
if (element.isDisplayed() && element.isEnabled()) {
element.click();
}
There are certain things you have to take care:
WebDriverWait inconjunction with ExpectedConditions as elementToBeClickable() returns the WebElement once it is located and clickable i.e. visible and enabled.
In this process, WebDriverWait will ignore instances of NotFoundException that are encountered by default in the until condition.
Once the duration of the wait expires on the desired element not being located and clickable, will throw a timeout exception.
The different approach to address this issue are:
To invoke click() as soon as the element is returned, you can use:
new WebDriverWait(driver, 10).until(ExpectedConditions.elementToBeClickable(By.xpath("(//div[#id='brandSlider']/div[1]/div/div/div/img)[50]"))).click();
To simply validate if the element is located and clickable, wrap up the WebDriverWait in a try-catch{} block as follows:
try {
new WebDriverWait(driver, 10).until(ExpectedConditions.elementToBeClickable(By.xpath("(//div[#id='brandSlider']/div[1]/div/div/div/img)[50]")));
System.out.println("Element is clickable");
}
catch(TimeoutException e) {
System.out.println("Element isn't clickable");
}
If WebDriverWait returns the located and clickable element but the element is still not clickable, you need to invoke executeScript() method as follows:
WebElement element = new WebDriverWait(driver, 10).until(ExpectedConditions.elementToBeClickable(By.xpath("(//div[#id='brandSlider']/div[1]/div/div/div/img)[50]")));
((JavascriptExecutor)driver).executeScript("arguments[0].click();", element);
From the source code you will be able to view that, ExpectedConditions.elementToBeClickable(), it will judge the element visible and enabled, so you can use isEnabled() together with isDisplayed(). Following is the source code.
public static ExpectedCondition<WebElement> elementToBeClickable(final WebElement element) {
return new ExpectedCondition() {
public WebElement apply(WebDriver driver) {
WebElement visibleElement = (WebElement) ExpectedConditions.visibilityOf(element).apply(driver);
try {
return visibleElement != null && visibleElement.isEnabled() ? visibleElement : null;
} catch (StaleElementReferenceException arg3) {
return null;
}
}
public String toString() {
return "element to be clickable: " + element;
}
};
}
the class attribute contains disabled when the element is not clickable.
WebElement webElement = driver.findElement(By.id("elementId"));
if(!webElement.getAttribute("class").contains("disabled")){
webElement.click();
}
List<WebElement> wb=driver.findElements(By.xpath(newXpath));
for(WebElement we: wb){
if(we.isDisplayed() && we.isEnabled())
{
we.click();
break;
}
}
}
I'm using #FindBy annotations to locate WebElements. But I want to use these WebElements in methods as parameters. I had success with this only if WebElement was found on page. But if I want to wait for it I must use By (with same locator) instead.
E.g.
private static final String SEARCHFIELD_LOC = "#search input[placeholder]";
#FindBy(css = SEARCHFIELD_LOC)
public WebElement searchField;
public By searchField_by = new By.ByCssSelector(SEARCHFIELD_LOC);
That way I can use this WebElement as By object in some method, like
public boolean isElementDisplayedWithWait(final By by) { .... }
So for each element I have 4 lines of code. I'm to lazy and searching for a way to simplify that.
I found totally another solution. I will store my locators as strings.
public String searchField = ".slide.slide_search input[placeholder]"
So only 1 line of code per locator. And I hope supporting only CSS locators will be enough. I will NOT use #FindBy for getting WebElements. Instead, I will get WebElements using special method that will wait for element and will log what's going on. I will implement getting WebElement like this:
WebElement we = wait.until(ExpectedConditions.visibilityOfElementLocated(new By.ByCssSelector(locator)));
where wait is
Wait<WebDriver> wait = new FluentWait<WebDriver>( driver )
.withTimeout(timeout, TimeUnit.SECONDS)
.pollingEvery(1, TimeUnit.SECONDS)
.ignoring( StaleElementReferenceException.class ) ;
The alternate of having wait/assertions/verification methods with webelement itself is available with extended webelement in QAF formerly ISFW. For example:
#FindBy(css = SEARCHFIELD_LOC)
public WebElement searchField;
searchField.waitForPresent();
searchField.assertPresent(); //auto wait
searchField.verifyPresent(); //auto wait
Reference:
QAF Selenium testing-frameworks
ISFW FAQ