My Selenium test looks something like this: customer selects a financial product, fills some necessary data and is presented with terms / agreement document in print preview (as required by local law). After printing / closing the print preview dialog customer enters more data and proceeds further, selects some options and finally gets another print preview of the contract. After that he confirms contract and process is done. I run my tests against Chrome version 75.
So far I've tried two things:
1. Switching to the print preview using Selenium, navigating to the "Cancel" button trough DOM and clicking it. But because the dialog uses shadow DOM it's very ugly, hard to maintain and frequently breaks after Chrome updates.
2. Tried using Robot class from awt, it works well when running locally but fails when running on Selenium grid because Chrome window is not focused and does not receive keyboard events.
Current state of the method handling the closure of print dialog:
public void closePrintPreview() {
WebDriverWait wait = new WebDriverWait(driver, 5);
wait.until(driver -> driver.getWindowHandles().size() > 1);
driver.switchTo().window(driver.getWindowHandles().toArray()[1].toString());
wait.until(d -> {
if (d.getWindowHandles().size() > 1) {
d.switchTo().window(driver.getWindowHandles().toArray()[1].toString());
try {
Robot robot = new Robot();
robot.keyPress(KeyEvent.VK_ESCAPE);
robot.keyRelease(KeyEvent.VK_ESCAPE);
} catch (AWTException e) {
throw new RuntimeException(e);
}
return false;
}
return true;
});
driver.switchTo().window(driver.getWindowHandles().toArray()[0].toString());
}
So my question would be if there is a simpler way to get the "Cancel" button in print print preview or maybe some way to force the Chrome window to be focused so it can receive key events from Robot?
Here is the solution in python.
You can update the same to work in java.
Python:
def cancelPrintPreview():
# get the current time and add 180 seconds to wait for the print preview cancel button
endTime = time.time() + 180
# switch to print preview window
driver.switch_to.window(driver.window_handles[-1])
while True:
try:
# get the cancel button
cancelButton = driver.execute_script(
"return document.querySelector('print-preview-app').shadowRoot.querySelector('#sidebar').shadowRoot.querySelector('print-preview-header#header').shadowRoot.querySelector('paper-button.cancel-button')")
if cancelButton:
# click on cancel
cancelButton.click()
# switch back to main window
driver.switch_to.window(driver.window_handles[0])
return True
except:
pass
time.sleep(1)
if time.time() > endTime:
driver.switch_to.window(driver.window_handles[0])
break
Java:
public void closePrintPreview() {
String jsCancel = "return document.querySelector('print-preview-app')" +
".shadowRoot.querySelector('#sidebar')" +
".shadowRoot.querySelector('print-preview-header#header')" +
".shadowRoot.querySelector('paper-button.cancel-button')";
WebDriverWait wait = new WebDriverWait(driver, 5);
JavascriptExecutor jse = (JavascriptExecutor) driver;
WebElement cancelButton;
wait.until(driver -> driver.getWindowHandles().size() > 1);
driver.switchTo().window(driver.getWindowHandles().toArray(new String[0])[1]);
while (driver.getWindowHandles().size() > 1) {
driver.switchTo().window(driver.getWindowHandles().toArray(new String[0])[1]);
cancelButton = (WebElement) jse.executeScript(jsCancel);
cancelButton.click();
}
driver.switchTo().window(driver.getWindowHandles().toArray(new String[0])[0]);
}
You can check my answer here for more information on working with shadow-root elements.
Here is the Java implementation based on answer by #supputuri:
public void closePrintPreview() {
String jsCancel = "return document.querySelector('print-preview-app')" +
".shadowRoot.querySelector('#sidebar')" +
".shadowRoot.querySelector('print-preview-header#header')" +
".shadowRoot.querySelector('paper-button.cancel-button')";
WebDriverWait wait = new WebDriverWait(driver, 5);
JavascriptExecutor jse = (JavascriptExecutor) driver;
WebElement cancelButton;
wait.until(driver -> driver.getWindowHandles().size() > 1);
driver.switchTo().window(driver.getWindowHandles().toArray(new String[0])[1]);
while (driver.getWindowHandles().size() > 1) {
driver.switchTo().window(driver.getWindowHandles().toArray(new String[0])[1]);
cancelButton = (WebElement) jse.executeScript(jsCancel);
cancelButton.click();
}
driver.switchTo().window(driver.getWindowHandles().toArray(new String[0])[0]);
}
Related
I have this react application being tested using selenium webdriver.
if my login is wrong, how do i detect the text using selenium webdriver? I am unable to find the code/ figure out how to trap the pop up message . 'authentication failed'
#Test
public void failed_login() {
System.setProperty("webdriver.chrome.driver",
"C:\\Users\\rahul\\Downloads\\chromedriver_win32_83\\chromedriver.exe");
WebDriver driver = new ChromeDriver();
driver.manage().timeouts().implicitlyWait(5, TimeUnit.SECONDS);
driver.get("http://testingapp.workspez.com");
driver.manage().window().maximize();
WebElement username = driver.findElement(By.id("field_email"));
WebElement password = driver.findElement(By.id("field_password"));
WebElement login = driver.findElement(By.xpath("//*[text()='Log In']"));
username.sendKeys("wrongemail#gmail.com");
password.sendKeys("wrongpassword");
login.click();
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
driver.manage().timeouts().implicitlyWait(120, TimeUnit.SECONDS);
String url = driver.getCurrentUrl();
assertEquals(url, "http://testingapp.workspez.com/login");
}
You can use below code to verify if authentication failed pop up is displayed or not:
List<WebElement> popUpElement = driver.findElements(By.id("client-snackbar");
if(popUpElement.size() != 0){
System.out.println("Pop up is Present "+popUpElement.get(0).getText());
}else{
System.out.println("Pop up is Absent");
}
After you perform click, you can use Explicit Wait:
try{
WebDriverWait wait = new WebDriverWait(driver, 10); //10 seconds
WebElement messageElement = wait.until(
ExpectedConditions.visibilityOfElementLocated(
By.xpath("//*[#id = 'client-snackbar']")
)
);
//if reach here, means the error is visible.
System.out.println(messageElement.getText());
}catch(TimeoutException ignored){
//if trigger timeoutexception
//that means the element with message is not visible, that means no error
}
This will wait 10 seconds for the element to be visible.
If it is not visible, it will throws TimeoutException which you can simply ignore.
That means the error was not visible in first 10 seconds after click.
You can change the time with whatever you want.
You can find the locator for that toast message.
For locating web element
Go to your login.
Enter your invalid credentials.
Press F12 and go to console/Sources
Click on login to get your message.
Press F8 to pause it. Now you can inspect your element.
So from webelement you can fetch text with gettext() method.
You can apply explicit wait to wait for your error message.
I have a question regarding selenium wait.
I want selenium to wait until a text displayed in specific xpath.
the text is: "Hensley and Workman Trading"
the xpath is: //td[#class='td_company ng-star-inserted']
I tried the wait until.attributeTobe function but can not make it wait.
What I am doing wrong (I think the until row is not working, the order or condition true)
public static void getWebElementByXpathWithWaitTextToBeSeen()
{
WebDriver driver2 = WebDriverMgr.getDriver();
// driver2.manage().timeouts().implicitlyWait(IMPLICIT_WAITE, TimeUnit.SECONDS);
WebDriverWait wait = new WebDriverWait(driver2,EXPLICIT_WAITE);
wait.until(ExpectedConditions.attributeToBe(By.xpath("//td[#class='td_company ng-star-inserted']"),"Hensley and Workman Trading","true"));
}
From Dev Tool:
To wait for the text Hensley and Workman Trading to be displayed within the WebElement you can use the following Locator Strategies:
new WebDriverWait(driver, 20).until(ExpectedConditions.textToBePresentInElementLocated(By.xpath("//td[#class='td_company ng-star-inserted']"), "Hensley and Workman Trading"));
OpenQA.Selenium.Support.UI implements wait.Until(expectedCondition) functionality. Here's an example of what you're trying to do:
public static void WaitForElementText(this IWebDriver driver, By by, string text)
{
var wait = new WebDriverWait(driver, TimeoutScope.Current.Timeout);
wait.Until(d => d.FindElement(by).Text == text);
}
In your case, it would look like this:
var wait = new WebDriverWait(driver, TimeoutScope.Current.Timeout);
wait.Until(d => d.FindElement(By.XPath("//td[#class='td_company ng-star-inserted']")).Text == text);
Try
" Hensley and Workman Trading " // With the extra spaces
instead of
"Hensley and Workman Trading"
Not positive, but those spaces may be throwing it off?
Can we catch in Selenium WebDriver events generated by the user (or events in general)? I know we can check state of page f.e. with WebDriverWait and ExpectedConditions, but that is not always appropriate.
Let's say I wanted to wait for user input to continue execution of test class. It would look something like this:
driver.get("https://www.google.com");
waitForKey(driver, org.openqa.selenium.Keys.RETURN);
/* rest of code */
driver.quit();
Where waitForKey would be implemented as:
public static void waitForKey(WebDriver driver, org.openqa.selenium.Keys key) {
Wait wait = new WebDriverWait(driver, 2147483647);
wait.until((WebDriver dr) -> /* what should be here? */);
}
Is there any way to do this?
I never heard that Selenium support it. However, you can make it yourself by adding an eventListener to the document to create or change DOM. Then you can use Selenium to detect the change. See my example below.
The example uses JavaScript Executor to add a keydown listener to the document. When the key Enter has been pressed, it will create a div with ID onEnter and then add it to the DOM. Finally, Selenium will looking for the element with ID onEnter, and then it will click a link in the web.
driver.get("http://buaban.com");
Thread.sleep(5000);
String script = "document.addEventListener('keydown', function keyDownHandler(event) {" +
" const keyName = event.key;" +
" if(keyName===\"Enter\") {" +
" var newdiv = document.createElement('DIV');" +
" newdiv.id = 'onEnter';"+
" newdiv.style.display = 'none';"+
" document.body.appendChild(newdiv);" +
" }" +
"});";
((JavascriptExecutor)driver).executeScript(script);
WebDriverWait wait = new WebDriverWait(driver, 20);
wait.until(ExpectedConditions.presenceOfElementLocated(By.id("onEnter")));
driver.findElement(By.cssSelector("#menu-post a")).click();
Thread.sleep(5000);
Following is short program & in the following web site:
https://uk.webuy.com/search/index.php?stext=*§ion=&catid=956
I am trying to click the first three product's "I want to buy this item" button &
view them in the VIEW BASKET at the right side of the page.
For some reason, I am able to see the second and third product only. For some reason, the first product never makes it to the basket, & it does not produce an error.
Only when I change the following line:
allButtons.get(0).click();
to:
allButtons.get(0).click();
allButtons.get(0).click();
allButtons.get(0).click();
I will see one occurrence of the first product in the basket.
What am I doing wrong? Is there something missing that is causing this problem?
Using Java 1.8
Selenium WebDrive Version #2.48
Mac OS Version #10.11.13
Thank you
public class ZWeBuy {
static WebDriver driver;
#Test
public void testProductPurchaseProcess() {
driver = new FirefoxDriver();
driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
driver.manage().window().maximize();
driver.get("https://uk.webuy.com/search/index.php?stext=*§ion=&catid=956");
closePopupIfPresent();
//xpath for all product names in this page
List<WebElement> allNames = driver.findElements(By.xpath("//div[#class='searchRecord']/div[2]/h1/a"));
List<WebElement> allButtons = driver.findElements(By.xpath("//div[#class='action']/div/a[2]/div/span"));
System.out.println("Total names = "+ allNames.size());
System.out.println("Total buttons = "+ allButtons.size());
System.out.println("I= " + 0 + " PRDCT: --- " +allNames.get(0).getText());
allButtons.get(0).click();
WebDriverWait wait = new WebDriverWait(driver,120);
wait.until(ExpectedConditions.elementToBeClickable(By.xpath("html/body/div[5]/div[1]/div[3]/div[5]/div[1]/div[1]/div[3]/div/a[2]/div/span")));
System.out.println("I= " + 1 + " PRDCT: --- " +allNames.get(1).getText());
allButtons.get(1).click();
System.out.println("I= " + 2 + " PRDCT: --- " +allNames.get(2).getText());
allButtons.get(2).click();
}
public static void closePopupIfPresent(){
Set<String> winIds = driver.getWindowHandles();
System.out.println("Total windows -> "+ winIds.size());
if(winIds.size() == 2){
Iterator<String> iter = winIds.iterator();
String mainWinID = iter.next();
String popupWinID = iter.next();
driver.switchTo().window(popupWinID);
driver.close();
driver.switchTo().window(mainWinID);
}
}
}
Your code isn't functional. Popup closing logic doesn't work, its actually not a separate window, its a dialog box within the same window. You should also consider simplifying your selectors. Alright enough said, here is working and tested code.
WebDriver driver = new FirefoxDriver();
WebDriverWait wait = new WebDriverWait(driver, 30);
driver.get("https://uk.webuy.com/search/index.php?stext=*§ion=&catid=956");
WebElement element;
try {
element = driver.findElement(By.cssSelector(".deliver-component-wrapper>a>div"));
System.out.println("Closing pop up");
element.click();
} catch (NoSuchElementException e) {
System.out.println("Alright, no such dialog box, move on");
}
List<WebElement> buyButtons = wait.until(ExpectedConditions.visibilityOfAllElementsLocatedBy(By.cssSelector(
"span.listBuyButton_mx")));
Assert.assertTrue("Less than three buttons found", buyButtons.size() >= 3);
for (int i = 0; i < 3; i++) {
WebElement buyButton = buyButtons.get(i);
wait.until(ExpectedConditions.elementToBeClickable(buyButton)).click();
System.out.println("Clicked Buy Button " + (i + 1));
}
WebElement basketCount = wait
.until(ExpectedConditions.presenceOfElementLocated(By.cssSelector("#buyBasketRow>td.basketTableCell")));
System.out.println(basketCount.getText());
driver.quit();
It prints
Closing pop up
Clicked Buy Button 1
Clicked Buy Button 2
Clicked Buy Button 3
3 item/s
Your browser could not render that first button. you may put wait.until() method before each click event.
try this
WebDriverWait wait = new WebDriverWait(driver,120);
wait.until(ExpectedConditions.elementToBeClickable(By.xpath("/html/body/div[5]/div[1]/div[3]/div[5]/div[1]/div[1]/div[3]/div/a[1]/div/span")));
allButtons.get(0).click();
I'm admittedly REALLY new to Selenium WebDriver, but I've hit a snag when running a rudimentary test in IntelliJ. I'm able to run and pass my test if I put breakpoints in the code and run it in Debug mode and step through the steps. However, when I just click run regularly it fails on the 2nd step saying the following: org.openqa.selenium.WebDriverException: Element is not clickable at point (596.5, 1128.63330078125). Other element would receive the click:
I'm stuck on trying to figure out why it would pass and run as expected in Debug, but not when I run regularly. Here's my test:
public class BF_Test {
private WebDriver driver;
#Test
public void checkURL()
{
WebDriver driver = BrowserFactory.getDriver("firefox");
driver.get("http://www.vizio.com");
WebElement homePagePopup = driver.findElement(By.xpath("//div[#id='modal']/div/a"));
homePagePopup.click();
//NEED TO FIGURE OUT WAIT TIMER OF SOME SORT
WebDriverWait wait = new WebDriverWait(driver, 15);
wait.until(ExpectedConditions.elementToBeClickable(By.cssSelector("html body.cms-index-index.cms-index div.page-wrapper div.main.col1-layout div.std section#heroslider.kslider.hero-home.section-wrap.section-wrap-primary div.navi-wrap ul.navi.navi-bind.navi-count-3 li.item-0")));
WebElement naviButtonsCarousel = driver.findElement(By.cssSelector("html body.cms-index-index.cms-index div.page-wrapper div.main.col1-layout div.std section#heroslider.kslider.hero-home.section-wrap.section-wrap-primary div.navi-wrap ul.navi.navi-bind.navi-count-3 li.item-0"));
naviButtonsCarousel.click();
WebElement homePageTVPButton = driver.findElement(By.cssSelector("#tvp-marquee-inner > div.container > div.content > a.vz-btn"));
homePageTVPButton.click();
WebElement resultsAreInValidation = driver.findElement(By.cssSelector(".thanks.fade-in"));
System.out.println(resultsAreInValidation.getText());
WebElement robinsonBtn = driver.findElement(By.cssSelector("#robinsonHomeVote > span"));
robinsonBtn.click();
WebElement robinsonPlayerText = driver.findElement(By.cssSelector("#modal-container > div > div > div.player > div.playerInfo > section > h1"));
Assert.assertEquals("Verify that Allen Robinson text is on the page","Allen Robinson",robinsonPlayerText.getText());
WebElement btnClose = driver.findElement(By.cssSelector("button.close"));
btnClose.click();
driver.quit();
}
}
So as you can see, nothing crazy to report in what I'm trying to do. Just open a website, click on a couple links and assert on some text and whatnot.
Any thoughts on what I can do to get this to work for me? I've been messing around with WebDriverWait to see if it was Selenium being too quick...but nothing seems to help.
THANKS!
WebDriverException: Element is not clickable at point means the element you want to click on is not visible. You can solve it by scrolling to the element before the click.
WebElement element = driver.findElement(By.cssSelector("selector"));
Actions actions = new Actions(driver);
actions.moveToElement(element).build().perform();
WebDriverWait wait = new WebDriverWait(driver, 15);
wait.until(ExpectedConditions.elementToBeClickable(element)).click();
Works for me, with the following instructions in C# using Selenium, 3.0 :
Thread.Sleep(TimeSpan.FromSeconds(15));
and then I can create the webElement and send event click.
create an extension like so:
public static class WebDriverExtensions
{
public static IWebElement FindElementUntil(this IWebDriver driver, By by, int waitSeconds = 15)
{
var wait = new WebDriverWait(driver, System.TimeSpan.FromSeconds(waitSeconds));
wait.Until(driver => driver.FindElement(by));
return driver.FindElement(by);
}
}