This is not a code problem as much as it is an automation problem.
There is a desktop website made of iframes(to me looks like those are iframes) which is some kind of B2B shop. All website elements are fixed in place, they are not moving or changing when moving from screen to screen.
What I need is to automatize a few clicks on buttons, until I come to confirmation, one of those clicks is one pop-up window with Confirm/Cancel. After this pop-up, the next screen is opened and one more button to click, which is manual work for me.
I have tried using a few QA testing software such as Selenium IDE to automatize, but it is not helping, when I come to that pop-up it just stops. To me looks like the software is not aware of that pop-up overlay, even though that pop-up is always the same.
Does anyone have any idea how to overcome the above problem?
Thanks everyone in advance.
Important: Pop-up window is part of website.
If the OS is Windows, and the popup is a native Windows dialog - and not part of the website accessible by Selenium IDE - you could try solving your problem by using calls to Windows API. Not sure how if this can be done using selenium.ide, but it sure can be achieved using regular Selenium Webdriver code written in one of the supported programming languages that are able to execute native Windows functions.
Here, for example, is a stand-alone Java class that starts Chrome, navigates to a website and then clicks on OK button displayed in the native dialog called "Warning".
package example;
import com.sun.jna.Native;
import com.sun.jna.Pointer;
import com.sun.jna.win32.StdCallLibrary;
import com.sun.jna.win32.W32APIOptions;
import org.openqa.selenium.chrome.ChromeDriver;
import java.time.Duration;
public class Main {
public static void main(String... args) {
ChromeDriver driver = new ChromeDriver();
driver.get("https://google.com");
Pointer dialog = getNativeDialog("Warning");
Pointer button = getNativeButton(dialog, "OK");
click(button);
}
/**
* Returns a handle to a dialog window by its name
* #param dialogTitle exact name of the window to find
*/
public static Pointer getNativeDialog(String dialogTitle) {
final String DIALOG_CLASS = "#32770";
return User32.INSTANCE.FindWindowEx(null, null, DIALOG_CLASS, dialogTitle);
}
/**
* Returns a handle to the button with specific label within a parentWindow
* #param parentWindow handle to a window, obtained e.g. with {#link #getNativeDialog(String)}
* #param buttonLabel label of the button to search by
*/
public static Pointer getNativeButton(Pointer parentWindow, String buttonLabel) {
final String BUTTON_CLASS = "Button";
return User32.INSTANCE.FindWindowEx(parentWindow, null, BUTTON_CLASS, buttonLabel);
}
/**
* Sends BM_CLICK message to a window (or other control) which is equivalent of clicking it
* with primary mouse button
* #param target an input handle obtained with e.g. {#link #getNativeButton(Pointer, String)}
*/
public static void click(Pointer target) {
final int BM_CLICK = 0x00F5;
User32.INSTANCE.SendMessage(target, BM_CLICK, null, null);
sleep(Duration.ofMillis(500));
}
private static void sleep(Duration duration) {
try {
Thread.sleep(duration.toMillis());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
private interface User32 extends StdCallLibrary {
User32 INSTANCE = (User32) Native.loadLibrary("user32", User32.class, W32APIOptions.DEFAULT_OPTIONS);
/**
* Finds window (or other type of control, specified by lpszClass).
* See https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-findwindowexw
*/
Pointer FindWindowEx(Pointer hWndParent, Pointer hWndChildAfter, String lpszClass, String lpszWindow);
/**
* Sends message to a window (or other type of control). Can be used to simulate user input.
* Note when the result of sending message triggers modal dialog to show, this method may block indefinitely,
* unless the dialog is handled in separate thread.
* See https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-sendmessage
*/
Pointer SendMessage(Pointer hWnd, int Msg, String wParam, String lParam);
}
}
This particular example requires these libraries
<dependencies>
<dependency>
<groupId>org.seleniumhq.selenium</groupId>
<artifactId>selenium-java</artifactId>
<version>3.141.59</version>
</dependency>
<dependency>
<groupId>net.java.dev.jna</groupId>
<artifactId>jna</artifactId>
<version>3.4.0</version>
</dependency>
<dependency>
<groupId>net.java.dev.jna</groupId>
<artifactId>platform</artifactId>
<version>3.4.0</version>
</dependency>
</dependencies>
Related
clear method clears the value but retains and when send keys new value is passed the text box shows previous value + new value in selenium Appium. Kindly suggest.
Version:java-client-4.1.2
Appium Server:v1.7.2
Selenium: 3.0.1
I tried this but it did not work out.
public void clearTextBox(WebElement element,String text) throws Exception
{
element.click();
Thread.sleep(3000);
element.clear();
element.sendKeys(text);
}
Getting this
The reason your code is failing (and you should have included your code in the original question) is because you are doing it through TWO separate calls to the page object element.
Each time you call the page object, it looks-up the element freshly, so the first time you call it and issue a .clear() and then you are calling it again after an unnecesary sleep with the .sendkeys() method. The click is also unnecessary.
You should write a public method in your page object model to perform the sendkeys() for you which does the clear() and then the sendkeys(), i.e.:
public void setMsisdnValue(String text) {
Msisdn.clear();
Msisdn.sendKeys(text);
}
Personally, I use a set of helper methods so that I can error-trap and log things like sendkeys, but I would still call it from within the page object model itself. That helper would do the same two steps, but also do it inside a try/catch and report any errors, so it would be simplified to:
public void setMsisdnValue(String text) {
helper.sendKeys(Msisdn, text);
}
Hope this helps.
I am having some issues using selenium, and specifically using actions, although this could just be a symptom for a bigger issue. To quickly explain what try to do:
I scroll down to the bottom of a page using SendKeys(Keys.ArrowDown)
I press a button, and I change the page to a different language.
I try to scroll down on the new page using SendKeys(Keys.ArrowDown). This is where i receive an error!
The strange thing here is that i have no issues with the scrolling in step 1 even though I am using the same function, but in step 3 i receive an error message:
OpenQA.Selenium.StaleElementReferenceException: 'The element reference of is stale; either the element is no longer attached to the DOM, it is not in the current frame context, or the document has been refreshed'
I have tried to redeclare my footer variable, and also included it as a Footer class variable (originally it wasn't), but nothing i do change anything
The reason I am using SendKeys and not MoveToElement is due to MoveToElement doesn't work for off-screen elements in Firefox. I have included all relevant code below, including an image of the error and when it happens.
Could anyone please advice what I am doing wrong?
[TestMethod]
public void Reset_newsletter_subscription_form_BR_site()
{
Browser.Goto(siteUrl);
Webpage.Footer.GoTo_CountryPageViaFooter("br");
Webpage.Footer.ScrollToFooter(); // -> This is where it fails!
Other.Irrelevant.Stuff();
}
Below this is the Selenium parts:
public static class Browser
{
public static IWebDriver webDriver;
public static Actions actions;
public static void Goto(string url)
{
webDriver.Url = url;
}
}
public static class Webpage
{
public static Footer Footer
{
get
{
var footer = new Footer(Browser.webDriver, Browser.actions);
return footer;
}
}
}
public class Footer
{
private IWebDriver webDriver;
private Actions actions;
private IWebElement footer;
public Footer(IWebDriver webDriver, Actions actions)
{
this.webDriver = webDriver;
this.actions = actions;
}
public void GoTo_CountryPageViaFooter(string CountryTag)
{
footer = webDriver.FindElement(By.ClassName("c-footer"));
var changeCountryButton = footer.FindElement(By.ClassName("c-footer__toggle-country-selector"));
ScrollToFooter();
actions.MoveToElement(footer).Perform();
actions.MoveToElement(changeCountryButton).Perform();
changeCountryButton.Click();
var intPageLink = footer.FindElement(By.XPath("//*[#href='/" + CountryTag + "/']"));
intPageLink.Click();
}
public void ScrollToFooter()
{
footer = webDriver.FindElement(By.ClassName("c-footer"));
//MoveToElement does not work for Firefox, so a workaround is needed.
if (webDriver is FirefoxDriver)
{
int i = 0;
while (i < 5)
{
actions.SendKeys(Keys.ArrowDown).Perform(); //This is where it fails!
i++;
}
}
actions.MoveToElement(footer).Perform();
}
Image of the exception
Whenever Perform() method is invoked, it figures how to interact with the Page. So its job is to find out the active element present in the Page(if element not specified as in MoveToElement(element) or during clicking an element using Actions).
So in your case, as no Element is specified actions.SendKeys(Keys.ArrowDown).Perform(); so Actions will focus on any Active Element present in the Page and Perform the SendKeys Operation on that.
Details about Actions Interaction with Web Page..
So, as soon as the Language change link is getting clicked the Elements attached to the DOM are changing as a result Selenium Webdriver detects this as a change in the current Active Element as a result StaleElementReference Exception thrown.
In order to get rid of the Exception, you can add wait statement in between or there is a great way to handle StaleElementReference Exception given here
Thanks :)
I wouldn't use .SendKeys() to scroll the page. It won't be consistent. Imagine if the page is longer or shorter... how many times will you need to scroll? I think a better approach is to use JS to scroll the page to the desired element.
public void ScrollToFooter()
{
footer = webDriver.FindElement(By.ClassName("c-footer"));
// MoveToElement does not work for Firefox, so a workaround is needed
if (webDriver is FirefoxDriver)
{
IJavaScriptExecutor jse = (IJavaScriptExecutor)webDriver;
jse.ExecuteScript("arguments[0].scrollIntoView();", footer);
}
else
{
actions.MoveToElement(footer).Perform();
}
}
If you decide to stick with your method, you have a bug because of a missing else. If the driver is FF, after your scrolldown code is executed, it will execute .MoveToElement() and fail.
You could simplify this function to just use JS for all drivers.
public void ScrollToFooter()
{
footer = webDriver.FindElement(By.ClassName("c-footer"));
IJavaScriptExecutor jse = (IJavaScriptExecutor)webDriver;
jse.ExecuteScript("arguments[0].scrollIntoView();", footer);
}
Instead of
actions.SendKeys(Keys.ArrowDown).Perform();
I suggest:
webDriver.FindElement(By.cssSelector("body")).sendKeys(Keys.ArrowDown);
I am working on Selenium webdriver and I have write a function for window handling. I have written code for naukri.com popup handling. My scenario is to Open the naukri.com and without closing popup window. I want to switch main window and click on Login button.I have written the code and created a function. when I am running the script focus is going on main page and url is displayed as selected but I am not able to click on Login button. I am not understanding where the problem is.Please suggest me.
public static WebDriver fn_SetFocus_According_Title(WebDriver dObj, String arg_title)
{
Set<String> setcol_windowHandle=dObj.getWindowHandles();
Iterator<String>itcol_handleval=setcol_windowHandle.iterator();
while(itcol_handleval.hasNext()==true){
String windowhanldval=itcol_handleval.next();
dObj=dObj.switchTo().window(windowhanldval);
String apptitle=dObj.getTitle();
if(apptitle.contains(arg_title))
{
dObj=dObj.switchTo().window(arg_title);
}
}
return dObj;
}
}
WebDriver dObj = new FirefoxDriver();
dObj.manage().window().maximize();
dObj.get("https://www.naukri.com");
dObj.manage().timeouts().implicitlyWait(60,TimeUnit.SECONDS);
dObj=fn_SetFocus_According_Title(dObj,"Jobs - Recruitment - Job Search - Employment - Job Vacancies - Naukri.com");
dObj.findElement(By.xpath("//a[#id='login_Layer']")).click();
Make the following changes in your code:
Change to:
dObj.switchTo().window(windowhanldval);
Reduce the actual string of "arg_title" as you would be looking for this entire string within the String obtained by getTitle()
When you are already on that page trying to match the page title which means the focus is already on the actual page where we need to locate the Login button element. So remove the second switch () line entirely. Rather use "break" to come out if loop.
Let me know if these steps works for you.
The function below works for me.
public static void switchToWindow(String windowTitle)
{
for (String window : driver.getWindowHandles())
{
driver.switchTo().window(window);
if (driver.getTitle().equals(windowTitle))
{
return;
}
}
throw new InvalidParameterException("The window titled <" + windowTitle + "> does not exist.");
}
One issue you may run into is that when a new tab/window is created, you may need to wait for it to appear. To do that, you can use something like
int count = driver.getWindowHandles().size() + 1; // add 1 to the current window count
// do something that spawns a new window
new WebDriverWait(driver, 3).until(ExpectedConditions.numberOfWindowsToBe(count));
You don't need to return the WebDriver instance. It's the same driver instance you are already using. If the expected window title is not found, the function will throw an exception.
Hope this will work for you.
public void Parenthandle(WebDriver wb){
try {
String ParentPageHandle = wb.getWindowHandle();
for (String newPage : wb.getWindowHandles()) {
if (!ParentPageHandle.equals(newPage)) {
wb.switchTo().window(newPage);
}
}
} catch (Exception e) {
System.err.println(e.getMessage());
}
In webpage I test is a modal which appears after pressing a button for circa 5sec.
And now I'm trying to make this in selenium.
I have method like this:
public static void ClickHold(IWebElement by)
{
SpecialInteractions.ClickAndHold(by);
}
where
public static Actions SpecialInteractions { get; set; }
and there is no hold time to set.
It looks like just clicking and releasing. Is there a way to wait for particular amount of time and then release?
Without digging dipper I can tell you the program above probably returns NulReference exception. I suspect you need to instantiate the Actions by wrapping the current driver instance.
Possible solution could be:
public void ClickHold(IWebElement element)
{
Actions action = new Actions(driver);
action.clickAndHold(webelement).build().perform();
//you need to release the control from the test
//actions.MoveToElement(element).Release();
}
Keep in mind that this will not work if you are using Selenium Grid. There is a bug that makes moveToElement an unrecognized command.
public static Boolean moveToThenSlowClickElement(final WebDriver driver, final WebElement toElement, final int millisecondsOfWaitTime) {
final Actions clickOnElementAndHold = new Actions(driver);
final Actions release = new Actions(driver);
clickOnElementAndHold.moveToElement(toElement).clickAndHold(toElement).perform();
sleep(millisecondsOfWaitTime);
release.release(toElement).perform();
final Action hoverOverCheckBox = clickOnElementAndHold.build();
hoverOverCheckBox.perform();
return true;
}
How to make the WebDriver wait until the page loading stops completely.
Means, it waits and checks whether entire page has been loaded or not, then only it proceeds with the next line execution.
The biggest problem is that there is no generic, one-size-fits-all solution that will work for even a majority of users. The concept of "when is my page finished loading" is rendered nearly meaningless in today's dynamic, AJAX-heavy, JavaScript-dependent web. One can wait for the browser to determine network traffic is complete, but that doesn't take JavaScript execution into account. One could define "complete" as the page's onload event having fired, but that overlooks the possibility of the page using setTimeout(). Furthermore, none of these definitions take frames or iframes into account.
When it comes to Selenium, there are a couple of factors to consider. Remember that the Selenium RC API is 10 years old. When it was designed and developed, the architecture of typical web pages made a method like waitForPageToLoad practical. The WebDriver API, on the other hand, recognizes the current reality. Individual driver implementations usually will try to wait for a page load during an explicit page navigation (e.g., driver.get()), but this wait will be a "best effort", and is not a guarantee. Please note that navigation caused by user interaction (e.g., element.click()) will be less likely to fully wait, because such interactions are asynchronous, and thus inherently have race conditions.
The correct approach for WebDriver is to wait for the element you want to interact with to appear on the subsequent page. This is best accomplished with a WebDriverWait or a similar construct. You might find some of these other constructs in the support library, mainly in those dealing with the Page Object pattern. You could also try setting the implicit wait timeout in your driver instance, but I believe using it obscures intent.
That's actually the default behavior of Selenium - it waits until all requests are complete before going on to the next line of code.
There is a design pattern provided through the Selenium support library SlowLoadableComponent that would do what you want: https://selenium.googlecode.com/svn/trunk/docs/api/java/org/openqa/selenium/support/ui/SlowLoadableComponent.html. The gist is that you write your page object to extend SlowLoadableComponent. You will have to provide implementations for two abstract methods in SlowLoadableComponent: load() and isLoaded()
TheisLoaded() method should check everything you need to consider your page 'loaded'. The load() method performs the actions necessary to load your page object. You specify a load timeout for your page object (I do this through the page object's constructor). When you invoke the get() method on your page object, which is inherited from SlowLoadableComponent, it will call isLoaded(). If your page object is not loaded, it will then call load() to load your page object. It will continue to do this until your page object is loaded or until your timeout expires.
You will have to define yourself what it means for your page object to be loaded, however. There is no out of the box way for Selenium to determine if your particular page object is loaded or not because these determinations are so context-sensitive. For example, consider a page object representing the login page for a web app. It is 'loaded' if the username and password entry text boxes and the submit login button are visible. This does not apply to a page object representing some other page in a web app. You have to custom tailor the 'is loaded' criteria for any given page object.
Here is a simple example. Basic abstract loadable object:
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.support.PageFactory;
import org.openqa.selenium.support.ui.SlowLoadableComponent;
import org.openqa.selenium.support.ui.SystemClock;
public abstract class AbstractLoadableComponent<T extends AbstractLoadableComponent<T>> extends SlowLoadableComponent<T> {
public static final int DEFAULT_TIMEOUT_IN_SECONDS = 30;
private final WebDriver driver;
private final int timeoutInSeconds;
public AbstractLoadableComponent(final WebDriver driver, final int timeoutInSeconds) {
super(new SystemClock(), timeoutInSeconds);
this.driver = driver;
this.timeoutInSeconds = timeoutInSeconds;
this.load();
}
public final WebDriver getDriver() {
return driver;
}
public final int getTimeoutInSeconds() {
return timeoutInSeconds;
}
#Override
protected void load() {
PageFactory.initElements(getDriver(), this);
}
}
Basic abstract page object:
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.support.ui.SlowLoadableComponent;
public abstract class AbstractPage<T extends AbstractPage<T>> extends AbstractLoadableComponent<T> {
private final String url;
public AbstractPage(final WebDriver driver) {
this(driver, driver.getCurrentUrl(), DEFAULT_TIMEOUT_IN_SECONDS);
}
public AbstractPage(final WebDriver driver, final String url) {
this(driver, url, DEFAULT_TIMEOUT_IN_SECONDS);
}
public AbstractPage(final WebDriver driver, final String url, final int timeoutInSeconds) {
super(driver, timeoutInSeconds);
this.url = url;
}
public final String getUrl() {
return url;
}
#Override
protected void load() {
super.load();
if(url != null) {
getDriver().get(url);
}
}
}
Basic concrete page object class for a login page:
import org.openqa.selenium.NoSuchElementException;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.FindBy;
import org.openqa.selenium.support.How;
import static org.testng.Assert.assertTrue;
public final class LoginPage extends AbstractPage<LoginPage> {
#FindBy(how = How.ID, using = "username")
private WebElement usernameBox;
#FindBy(how = How.ID, using = "password")
private WebElement passwordBox;
#FindBy(how = How.NAME, using = "login")
private WebElement loginButton;
public LoginPage(final WebDriver driver) {
this(driver, driver.getCurrentUrl(), DEFAULT_TIMEOUT_IN_SECONDS);
}
public LoginPage(final WebDriver driver, final String url) {
this(driver, url, DEFAULT_TIMEOUT_IN_SECONDS);
}
public LoginPage(final WebDriver driver, final String url, final int timeoutInSeconds) {
super(driver, url, timeoutInSeconds);
}
#Override
protected final void isLoaded() throws Error {
try {
assertTrue(usernameBox.isDisplayed(), "Username text box is not displayed");
assertTrue(passwordBox.isDisplayed(), "Password text box is not displayed");
assertTrue(loginButton.isDisplayed(), "Login button is not displayed");
} catch(NoSuchElementException nsee) {
throw new Error(nsee);
}
}
}
driver.manage.implicitlywait(3, TimeUnit.Seconds) will hep.