Let me explain the problem statement :
I want to design Page Object Model for a page using selenium. And the requirement is, scripts executing on multiple browsers will use this class. How should I deal with element locators in my Page class ? What I can think of is
Get the driver object, and using if else, pick the browser specific XPath for locating the element . Like if the driver is chrome then locateChromeElement.
Create different page classes for different browsers.
Create base page class and extend it based on browsers.
What is the best way? What is used in industry?
It depends entirely on your AUT (Application under test). If you have different locators for the same webelement on a page (e.g. in case of multi-lingual sites), then use properties file for storing the webelements and name it as per your page (e.g. for HomePage class you can have different files HomePage.properties (English), HomePage_it.properties (Italian) etc.)
Usually, if you go for CSS for location webelement, you will find it same for almost every browser.
The xpaths will be the same regardless of which browser you use.
to make a script work in multiple browsers, you can create multiple TestNg suites for different browsers, and have the same script for all the suites.
All you need to change in the suites are the Browser classes.
Consider the following script
You can run this entire code in one go. All the test suites will be executed one after the other
class MultipleBrowser{
//for Firefox
#Test
public void FirefoxBrowser()
{
WebDriver driver = new FirefoxDriver();
driver.get("http://www.google.com");
driver.findElement(By.id("lst-ib")).sendKeys("Automating in firefox Browser");
}
//for ChromeBrowser
#Test
public void ChromeBrowser()
{
WebDriver driver = new ChromeDriver(); //only the class is changed from firefoxDriver to ChromeDriver
driver.get("http://www.google.com");
driver.findElement(By.id("lst-ib")).sendKeys("Automating in Chrome Browser");
}
//for InternetExplorer
#Test
public void IEBrowser()
{
WebDriver driver = new InternetExplorerDriver(); //only the class is changed from ChromeDriver to IEDriver
driver.get("http://www.google.com");
driver.findElement(By.id("lst-ib")).sendKeys("Automating in IE Browser");
}
}
Related
I'm using webdrivermanager with browserInDocker() for my test automation framework. So far it works great. But now I have trouble trying to use a chrome profile.
Usually, when I use selenium webdriver, I simply can set a ChromeOption and it works.
How can I use it with browserInDocker()?
I tried the following code:
public void setupBrowserInDockerWithProfile() {
ChromeOptions options = new ChromeOptions();
options.addArguments("--user-data-dir=/home/seluser/.config/google-chrome/Default");
driver = WebDriverManager
.chromedriver()
.capabilities(options)
.browserInDocker()
.dockerVolumes("/var/lib/docker/volumes/chromeprofile/_data:/home/seluser/.config/google-chrome/Default")
.create();
driver.manage().window().maximize();
driver.get(APP_URL);
}
I tried it with and without a docker volume, but I'm not even sure if I use it right. I'm searching for days now, but could't find a solution yet.
The problem is the argument --user-data-dir=/home/seluser/.config/google-chrome/Default. As explained in the doc, WebDriverManager uses the Aerokube's Docker images. That path is available in the docker-images, but not in Aerokube's. You can drop that argument or change it to the following:
options.addArguments("--user-data-dir=/home/selenium/.config/google-chrome/Default");
I created a custom webdriver (for a custom browser) by extending RemoteWebDriver. I can easily use it as standalone, by simply instantiating the driver.
But actually I want to use it in a Selenium Grid. Is there a way to register this custom web driver on a node, so that I can use it with via RemoteWebDriver and desired capabilities? I so, what do I need to do.
Any hint is welcome. Thanks in advance.
The WebDriver (server) variants are specifically designed/created/modified continously to be able to drive the ever evolving Web Browsers.
So if you want to drive a Custom Browser through a Custom Webdriver, it seems to be the perfect approach.
At this point, it is not clear from the question if your usecase resembles as a case where you don't actually want a browser.
However, as per the configuration in Browser.java the following set of Browsers are extensively tested before any release:
package org.openqa.selenium.testing.drivers;
import java.util.logging.Logger;
public enum Browser {
chrome,
edge,
ff,
htmlunit,
ie,
none, // For those cases where you don't actually want a browser
opera,
operablink,
safari;
private static final Logger log = Logger.getLogger(Browser.class.getName());
public static Browser detect() {
String browserName = System.getProperty("selenium.browser");
if (browserName == null) {
log.info("No browser detected, returning null");
return null;
}
try {
return Browser.valueOf(browserName);
} catch (IllegalArgumentException e) {
log.severe("Cannot locate matching browser for: " + browserName);
return null;
}
}
}
Solution
To make a provision for your own Custom Webdriver and Custom Browser you may need to add the relevant entries within Browser.java and other required files and you will be good to go.
Please follow the below set of instructions to setup support for a custom browser type when running selenium tests against a Selenium Grid.
Implement the interface org.openqa.selenium.remote.server.DriverProvider (or) extend org.openqa.selenium.remote.server.DefaultDriverProvider wherein you take care of building support for your custom browser.
Create a directory named META-INF\services under your main resources folder and ensure that this directory gets bundled into the jar, when you create a jar out of your project.
Create a service loader file named org.openqa.selenium.remote.server.DriverProvider wherein you add the fully qualified class name of the new class you created in step (1) and place it in the directory created in step (2)
Bundle your project into a jar.
Now start the selenium node by adding the jar created in (4).
Now your new browser is ready to be supported by the Selenium Grid.
Please refer to this selenium-users google forums thread which also talks about the same query wherein the user confirmed that the above mentioned approach worked for them.
You still need to take care of creating a new custom capabilities object from your client side when you instantiate the RemoteWebDriver object for your custom browser.
I have several tests that run with Selenium and HtmlUnitDriver. Sometimes when I run them and want to click on an element or read text, the elements can not be found. Every time a Exception is thrown I save the Code of the Page for debugging purposes. But when I check the Code, the element is there and when I rerun the test everything works fine.
My guess is that the page was not completely loaded when I try to access the element.
So I would like to wait until Selenium has finished loading the page before I try to access elements.
I fond two ways to achieve it:
Execute Javascript (e.g. window.initComplete) and wait for the result to be true. The problem: In Selenium I have to have an instance of JavascriptExecuter but HtmlUnitDriver is not derived from that class and I cannot switch to FirefoxDriver (which implements the JavascriptExecuter interface) because we are running the tests headless.
Wait for the last element on the page to load
The problem with this approach is that the page is based on our framework and if that changes and suddenly there are different elements on the bottom of the page I have to adapt every test.
Any suggestions on how to approach the problem?
You can create a custom ExpectedCondition:
public static ExpectedCondition<Boolean> waitForLoad() {
return new ExpectedCondition<Boolean>() {
#Override
public Boolean apply(WebDriver driver) {
return ((JavascriptExecutor) driver).executeScript("return document.readyState").equals("complete");
}
};
}
I'm testing a GWT + SMARTGWT application like Paint and I'm trying to locate the elements of this web application using Selenium Webdriver. The method which I have used to locate the elements is by the relative XPath of those elements but the problem which I am currently facing is that this method is working correctly on the browsers like Chrome, Firefox, and Edge but not on the IE browser. The version of IE on my PC is 11.1593.14393.0. In the IE browser, this relative XPath method is giving a TimeOutException. I have given the explicit wait:
wait.until(ExpectedConditions.elementToBeClickable(webelement));
The IE browser is not able to find the element. I am also getting the following exception sometimes for other elements:
Exception in thread "main" org.openqa.selenium.InvalidSelectorException: Unable to locate an element with the xpath expression //img[contains(#src,'Insert XXX'] because of the following error:
Error: Bad token: ]
Among the troubleshooting solutions to this issue, I tried enabling/disabling the protected mode in IE for all the levels but this method didn't work. Along with that, I also tried checking the box next to the option - "Allow active content to run files on My Computer" but this method also failed to work.
What should I do to fix my issue?
This is my code. Here firstly, I will click on the Insert button located on the top bar of the application and after clicking on the Insert button, a window will launch on which I will click on the Close button.
public static void main(String[] args) throws InterruptedException {
System.setProperty("webdriver.ie.driver", "D:\\SELENIUM\\Drivers\\iedriverserver.exe");
WebDriver driver = new InternetExplorerDriver();
Thread.sleep(3000);
driver.get(baseURL);
WebDriverWait wait = new WebDriverWait(driver, 10);
final String InsertPath = "//img[contains(#src,'Insert XXXX')]";
final String closePath="//img[contains(#src,'close')]";
WebElement Insert = driver.findElement(By.xpath(InsertPath));
wait.until(ExpectedConditions.elementToBeClickable(Insert));
Thread.sleep(2000);
Insert.click();
WebElement close = driver.findElement(By.xpath(closePath));
wait.until(ExpectedConditions.elementToBeClickable(close));
Thread.sleep(3000);
close.click();
}
}
Edit: I also used finding the element using Javascript executor in my code as follows:
WebElement Insert = driver.findElement(By.xpath(InsertPath));
Thread.sleep(2000);
JavascriptExecutor jse = (JavascriptExecutor) driver;
jse.executeScript("arguments[0].click();", Insert);
Sadly, this method also failed to work in the IE browser.
So, I was able to locate the elements by using the latest driver of the Internet Explorer and giving the following desired capabilities in my code to the IE browser.
DesiredCapabilities ieCapabilities = DesiredCapabilities.internetExplorer();
ieCapabilities.setCapability("requireWindowFocus", true);
ieCapabilities.setCapability("unexpectedAlertBehaviour", "accept");
ieCapabilities.setCapability("ignoreProtectedModeSettings", true);
ieCapabilities.setCapability("disable-popup-blocking", true);
ieCapabilities.setCapability("enablePersistentHover", true);*/
System.setProperty("webdriver.ie.driver", "D:\\IEDriverServer.exe");
WebDriver driver = new InternetExplorerDriver(ieCapabilities);
I am currently working on a project using Java, Selenium and Testng. My overall goal is to test the functionality of a webpage over different web browsers. I have my Selenium code working and am able to run the test on Chrome and Firefox. However, I have to manually change the code to switch the browser. I do this by commenting out driver = new ChromeDriver();
I would like to edit my code so the test runs in Firefox and when that test is complete start the test in Chrome. Can someone please guide me in the right direction?
Here is a sample of what my code looks like:
WebDriver driver = null;
Selenium selenium = null;
#BeforeSuite
public void setup() throws Exception {
/// Chrome Driver ///
System.setProperty("webdriver.chrome.driver", "mac/chromedriver.exe");
//driver = new ChromeDriver();
/// Firefox Driver ///
driver = new FirefoxDriver();
}
#Test
public void testGoogle() throws Exception {
selenium = new WebDriverBackedSelenium(driver,"URL");
There could be quite a few ways of achieving this.
In the setup you can read a property and based on that you can instantiate the right driver.
String driverType = System.getProperty("driverType");
if ("firefox".equals(driverType))
driver = new FirefoxDriver().....
You can run the test twice, once with firefox property and then with chrome property.
Other option is to keep all the test in one class. Then extend this class by two classes, one for firefox setup and another for chrome setup. Then you can run both the subclass tests in a suite. They would run one after the another.