Can someone please help me to figure out how to set up saucelabs for testNg on Java?
I’ve tried different guides, and it’s always different variations of set up, here's one of the examples that didn't work for me
#BeforeClass
public void init() throws MalformedURLException {
MutableCapabilities sauceOpts = new MutableCapabilities();
sauceOpts.setCapability("username", "oauth-xxxxxx.yyyyyy-51awdfsa");
sauceOpts.setCapability("accesskey", "xxxxx-32b1-4c4d-ac70-yyyyyyyyy");
DesiredCapabilities options = new DesiredCapabilities();
options.setCapability("sauce:options", "sauceOpts");
options.setCapability("browserVersion", "latest");
options.setCapability("platformName", "windows 10");
options.setCapability("browserName","chrome");
Webdriver driver = new RemoteWebDriver(new URL("https://ondemand.us-west-1.saucelabs.com:443/wd/hub"), options);
}
import com.saucelabs.saucebindings.testng.SauceBaseTest;
import org.testng.Assert;
import org.testng.annotations.Test;
/**
* Example Test for running with the TestNG Sauce Bindings library.
*/
public class SauceBindingsTestngTest extends SauceBaseTest {
#Test
public void correctTitle() {
getDriver().navigate().to("https://www.saucedemo.com");
Assert.assertEquals("Swag Labs", getDriver().getTitle());
}
}
Chrome/Win10 is the default so no setup code is required. If you want to change the configuration, check the Sauce Bindings docs below.
Source Code for example
We have a Demo Java repo with any example you want, just browse the table of contents
We use Sauce Bindings to make the code so simple
This is working for me,
DesiredCapabilities DC = DesiredCapabilities.chrome();
DC.setBrowserName("chrome");
DC.setPlatform(Platform.WIN10);
driver = new RemoteWebDriver(new URL("https://oauth-jayanth_balakrishnan-ae.saucelabs.com:443/wd/hub"), DC); //http://127.0.0.1:4444/wd/hub
Related
I was hoping for some help setting up my test frame work as its causing me issue. Im currently using zalenium in conjunction with my selenium tests. Currently im setting the desired capabilities in the #BeforeTest section of my tests:
#BeforeTest
#Parameters("browser")
public void setup(String br)throws MalformedURLException {
de = new DesiredCapabilities();
if (br.equals("chrome")) {
de.setCapability(CapabilityType.BROWSER_NAME, BrowserType.CHROME);
de.setCapability(CapabilityType.PLATFORM_NAME, org.openqa.selenium.Platform.LINUX);
}
else if(br.equals("firefox")){
de.setCapability(CapabilityType.BROWSER_NAME, BrowserType.FIREFOX);
de.setCapability(CapabilityType.PLATFORM_NAME, Platform.LINUX);
}
URL url = new URL("http://localhost:4444/wd/hub");
driver = new RemoteWebDriver(url,de);
driver.get(URL);
This allows me to run my testing in the docker environment and not on my local machine and is working correctly.
However i would like to create a base for these capabilities so i don't have to keep stating the desired capabilities for each test.
I want to do this also because I would like to set up separate classes for each page. Currently when i try this im getting a null pointer exception because the driver isnt declared. I tried to inject the Remote webdriver like so:
#Test
public void loginTest( RemoteWebdriver driver){
WebElement user_account_menu = driver.findElement(By.cssSelector("[data-user-account-settings-button]"));
WebDriverWait wait = new WebDriverWait(driver, 10);
wait.until(ExpectedConditions.elementToBeClickable(user_account_menu));
user_account_menu.click();
System.out.println("Login clicked successfully");
}
Im receiving the error: Cannot inject #Test annotated Method [loginTest] with [class org.openqa.selenium.remote.RemoteWebDriver
So im basically trying to figure out how i can set up these capabilities for the driver in a class and then extend them onto my tests.
From this link, it appears, you're not adding the right annotation, namely #Parameters.
However, in some other testing frameworks, it's not typical to be able to pass in variables that aren't determined at runtime, i.e. variables for objects like RemoteWebdriver won't work, but variables for strings or ints will work. From this link, it appears that what you're trying to accomplish is doable. But I recommend the following approach.
Have an enumeration:
enum BrowserType
{
Chrome, Firefox, IE;
}
Have your test base page:
public class BrowserSetup
{
public static RemoteWebdriver Initialize(string browserType)
{
switch (browserType)
{
case BrowserType.Chrome:
// set chrome capabilities and initialize your browser here
break;
case BrowserType.Firefox:
// set firefox capabilities and initialize your browser here
break;
default:
// set default case, or fail if browser type doesn't match
break;
}
}
Then, from you're test class, assuming you have a private RemoteWebdriver driver initialized somewhere in the test class, you can do the following:
#BeforeTest
#Parameters("Chrome")
public void setup(String browserType) throws MalformedURLException
{
driver = BrowserSetup.Initialize(browserType);
}
I am trying to run tests in Chrome headless mode but getting java.lang.NullPointerException
Chrome version: Version 72.0.3626.121 (Official Build) (64-bit)
Selenium version: 3.8.1
Chromedriver version: 2.45.615355
Here is my BaseTest:
public abstract class BaseTest {
public WebDriver driver;
protected abstract String getUrl();
#Before
public void setUp() {
Log.startLog("Test is Starting...");
System.setProperty("webdriver.chrome.driver", "src//test//resources//chromedriver");
ChromeOptions chromeOptions = new ChromeOptions();
chromeOptions.setHeadless(true);
WebDriver driver = new ChromeDriver(chromeOptions);
driver.manage().timeouts().pageLoadTimeout(20, TimeUnit.SECONDS);
driver.manage().timeouts().implicitlyWait(5, TimeUnit.SECONDS);
driver.get(getUrl());
}
#After
public void tearDown() {
Log.endLog("Test is Ending...");
driver.manage().deleteAllCookies();
driver.close();
}
}
When I'm running tests, not in headless mode every test works good but in headless mode, I can't even run a simple test to understand if the headless mode is working or not.
Test example:
#Test
public void test() {
System.out.println(driver.getTitle());
}
Example URL: https://www.wikipedia.org/
UPDATE:
I've created new sample project with this code:
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.chrome.ChromeOptions;
public class test {
public static void main(String[] args) {
System.setProperty("webdriver.chrome.driver", "/Users/alexsomov/Desktop/chromedriver2");
//Set Chrome Headless mode as TRUE
ChromeOptions options = new ChromeOptions();
options.setHeadless(true);
//Instantiate Web Driver
WebDriver driver = new ChromeDriver(options);
driver.get("https://www.google.com/");
System.out.println("Page title is - " + driver.getTitle());
driver.close();
}
And bingo, everything works well... Need to figure out why code above from real project doesn't work seems something wrong with BaseTest class and when I run code with debugger I'm getting driver == null, maybe anyone have a solution how I can solve this problem :/
ANSWER
The solution was super easy, just need to change 1 string in setUp() method in BaseTest class.
This one:
WebDriver driver = new ChromeDriver(chromeOptions);
change to this:
driver = new ChromeDriver(chromeOptions);
and everything will work.
If you are using linux environment, may be you have to add --no-sandbox as well and also specific window size settings. --no-sandbox is no needed in windows if you set user container properly.
disable-gpu Only on Windows. Other platforms no longer require it. The --disable-gpu flag is a temporary work around for a few bugs.
if(browser.equalsIgnoreCase("HLChrome")){
//Headless chrome browser and configure
WebDriverManager.chromedriver().setup();
ChromeOptions chromeOptions = new ChromeOptions();
chromeOptions.addArguments("--no-sandbox");
chromeOptions.addArguments("--headless");
chromeOptions.addArguments("disable-gpu");
// chromeOptions.addArguments("window-size=1400,2100"); // linux should be activate
driver = new ChromeDriver(chromeOptions);
ANSWER The solution was super easy, just need to change 1 string in setUp() method in BaseTest class.
This one:
WebDriver driver = new ChromeDriver(chromeOptions);
change to this:
driver = new ChromeDriver(chromeOptions);
and everything will work.
I have created a common webdriver class that I can use for my selenium tests. Whenever I create a new test, I get the webdriver from this class.
Here is what I am using to create my driver
package com.atmn.config;
import java.net.MalformedURLException;
import java.net.URL;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.remote.CapabilityType;
import org.openqa.selenium.remote.DesiredCapabilities;
import org.openqa.selenium.remote.RemoteWebDriver;
public class Driver {
private static Log log = LogFactory.getLog(Driver.class);
public static String USERNAME = "name";
public static String ACCESS_KEY = "key";
public static WebDriver driver = createDriver("firefox", "47.0", "Windows 10");
public static WebDriver createDriver(String browser, String version, String os) {
try{
DesiredCapabilities capabilities = new DesiredCapabilities();
capabilities.setCapability(CapabilityType.BROWSER_NAME, browser);
capabilities.setCapability(CapabilityType.VERSION, version);
capabilities.setCapability(CapabilityType.PLATFORM, os);
// Launch remote browser and set it as the current thread
return new RemoteWebDriver(
new URL("http://"+USERNAME+":"+ACCESS_KEY+"#ondemand.saucelabs.com:80/wd/hub"),
capabilities);
}
catch(MalformedURLException e)
{
e.printStackTrace();
//log message
log.info(e.getMessage());
}
return null;
}
Here is my test, which will run on SauceLabs use Windows 10 and firefox 47.
package com.atmn.tests;
import com.tplus.atmn.tasks.CommonTasks;
import com.tplus.atmn.objects.TOA6;
import java.lang.reflect.Method;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.openqa.selenium.By;
import org.testng.Assert;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
import com.tplus.atmn.tasks.HttpRequest;
public class Testing extends CommonTasks {
private static Log log = LogFactory.getLog(TB6_TOA.class);
#Test (groups = {"Testing"})
public static void endToEnd() throws Exception {
//Load URL
HttpRequest http = new HttpRequest();
String URL = http.internetWebAddress();
driver.get(URL);
//Page 1
// Item Text
verifyText(Object.ItemText, "Multiple Choice - Single Answer Radio - Vertical");
verifyText(Object.Progress_PercentComplete, "0%");
//URL
verifyNoRedirect();
//Go to next page
driver.findElement(Object.Start).click();
System.out.println("Next Button was clicked.");
}
}
Instead of just running my test on 1 browser in SauceLabs, I want to run this test on multiple browser/OS combinations in parallel. I'm not sure how to change my driver class to make this happen.
So you are using TestNG. That test framework has support for running in parallel built in (it's a setting you can add to a suite file as well as set in other ways). It also allows you to take in arguments to a test method using a DataProvider. There are many, many ways to set up a testing framework and there are a lot of factors that should go into how it's structured.
First off, you are creating a static WebDriver instance in the Driver class which is not what you are going to want. You need multiple instances so what you are really going to want is the factory method on that class that allows you to create WebDrivers for each method as needed. Another consideration you are going to want to take into account is the fact that TestNG does not create new instances of the test class object for each method. Because of that, you either can't store any state as a field on the test class object unless it is done in a way that avoids contention (e.g. a ThreadLocal field for instance). Unfortunately, in the case of a Selenium test, you are going to want to quit the WebDriver when you are finished with it to free up the SauceLabs resources. You could normally do that with an #AfterMethod configuration method, but you aren't guaranteed that the configuration methods will run in the same thread as the test method so using a ThreadLocal field won't work to allow access to the same argument (e.g. the web driver). You could use a map of test methods to web drivers on the class object (TestNG allows you to inject the test method as an argument) but in the case of a data provider to allow for multiple OS / browser combinations it will have the same test method as well. In the end with TestNG and Selenium I find it best (or at least easiest), in my experience, to use DataProviders and just store the fields on the test class object and restrict parallelism to class level.
That being said, here is an example of how to test with parallel methods that. Starting with a simple pom.xml dependency section to show the versions used for this example. Even if your versions are a little different, it should be very similar.
<dependencies>
<dependency>
<groupId>org.seleniumhq.selenium</groupId>
<artifactId>selenium-java</artifactId>
<version>2.53.1</version>
</dependency>
<dependency>
<groupId>org.testng</groupId>
<artifactId>testng</artifactId>
<version>6.9.10</version>
</dependency>
</dependencies>
Update the Driver class to make sure it cleanly returns a new driver instance each time. I removed the logger portions of it just to save some space. I also just made it non-instantiable since it is really only a static factory and allowing instances of it doesn't make sense. Also you really probably shouldn't allow access to things like the name and key as they are purely implementation details.
public final class Driver {
private static final String USERNAME = "name";
private static final String ACCESS_KEY = "key";
public static WebDriver createDriver(String browser, String version, String os) {
// Should probably validate the arguments here
try {
DesiredCapabilities capabilities = new DesiredCapabilities();
capabilities.setCapability(CapabilityType.BROWSER_NAME, browser);
capabilities.setCapability(CapabilityType.VERSION, version);
capabilities.setCapability(CapabilityType.PLATFORM, os);
return new RemoteWebDriver(new URL("http://" + USERNAME + ":" + ACCESS_KEY + "#ondemand.saucelabs.com:80/wd/hub"),
capabilities);
} catch (MalformedURLException e) {
throw new RuntimeException("Failure forming the URL to create a web driver", e);
}
}
private Driver() {
throw new AssertionError("This is a static class and shouldn't be instantiated.");
}
}
Finally, in the test class itself you need to define the actual test method and a data provider. If you want the same data provider for multiple tests / test classes, that is fine. Refer to the TestNG documentation for details:
http://testng.org/doc/documentation-main.html#parameters-dataproviders
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
public class FooTest {
#DataProvider(name = "DriverInfoProvider", parallel = true) // data providers force single threaded by default
public Object[][] driverInfoProvider() {
return new Object[][] {
{ "firefox", "47.0", "Windows 10" },
{ "chrome" , "51.0", "Windows 10" },
// etc, etc
};
}
#Test(dataProvider = "DriverInfoProvider")
public void testFoo(String browser, String version, String os) {
WebDriver driver = Driver.createDriver(browser, version, os);
try {
// simple output to see the thread for each test method instance
System.out.println("starting test in thread: " + Thread.currentThread().getName());
// Putting this in a try catch block because you want to be sure to close the driver to free
// up the resources even if the test fails
driver.get("https://www.google.com");
driver.findElement(By.name("q")).sendKeys("Hello, world");
} finally {
driver.quit();
}
}
}
Please note that there are a number of things about these examples that I don't like from an architecture standpoint, but I wanted to give you an idea of a few of the issues to think about and a quick working example that is similar to what you already have. Finally, to run test classes in parallel, you would create and then run a TestNG suite. These are usually defined in XML (though you can also use YAML).
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd">
<suite name="MySuiteNameHere" parallel="methods" thread-count="15">
<test name="Selenium Tests">
<classes>
<class name="foo.bar.FooTest"/>
</classes>
</test>
</suite>
Finally running that lead to two tests that loaded google and performed the action along with this sample output:
starting test in thread: PoolService-1
starting test in thread: PoolService-0
I want to create some user defined functions for my webdriver automation code. I tried it, but resulted in failure.
the following is my code
public class snapdeal {
WebDriver driver= new FirefoxDriver();
#Test
public void test() {
// I want open browser in function 1
driver.get("http://amazon.in");
driver.manage().window().maximize();
// Function 2 for searching
driver.findElement(By.xpath("//li[#id='nav_cat_2'")).click();
driver.findElement(By.id("twotabsearchtextbox")).sendKeys("Shoes");
driver.findElement(By.xpath("//input[#class='nav-submit-input']")).click();
driver.findElement(By.xpath("//h2[#class='a-size-medium s-inline s-access-title a-text-normal' and contains(text(), \"Fbt Men's 8876 Casual Shoes\")]")).click();
}
}
How ca i write two functions inside the class?
You were probably trying to nest methods inside test() . It is not possible.
You can use this code below which calls the respective methods in the test(). It works as expected:
public class snapdeal {
static WebDriver driver= new FirefoxDriver();
#Test
public void test() {
//Method1 for Opening Browser.
openBrowser();
// Method2 for searching
searchElement();
}
public static void openBrowser(){
driver.get("http://amazon.in");
driver.manage().window().maximize();
driver.manage().timeouts().implicitlyWait(20, TimeUnit.SECONDS);
}
public static void searchElement(){
driver.findElement(By.xpath("//li[#id='nav_cat_2']")).click();
driver.findElement(By.id("twotabsearchtextbox")).sendKeys("Shoes");
driver.findElement(By.xpath("//input[#class='nav-submit-input']")).click();
driver.findElement(By.xpath("//h2[#class='a-size-medium s-inline s-access-title a-text-normal' and contains(text(), \"Fbt Men's 8876 Casual Shoes\")]")).click();
}
}
I think this is like a Hello World for Selenium for you, you could make use defined methods in Java using Junit with the following annotations which can be found here
But as per norms we usually have a #Before method in Junit or #BeforeTest method in testng for setting up the webdriver and the url of AUT, also in your code a couple of xpaths were wrong which were causing the error, Please find below the correct working code with comments:
import java.util.concurrent.TimeUnit;
import org.junit.Before;
import org.junit.Test;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.safari.SafariDriver;
public class snapdeal {
public WebDriver driver;
#Before
public void setUP()
{
// I want open browser in function 1
driver= new SafariDriver();
driver.manage().timeouts().implicitlyWait(20, TimeUnit.SECONDS);
driver.get("http://amazon.in");
driver.manage().window().maximize();
}
#Test
public void test() {
// Function 2 for searching
//driver.findElement(By.xpath("//li[#id='nav_cat_2")).click(); //element not needed
driver.findElement(By.id("twotabsearchtextbox")).sendKeys("Shoes");
driver.findElement(By.xpath("//input[#class='nav-submit-input']")).click();
driver.findElement(By.xpath("//*[#title=\"Fbt Men's 8876 Casual Shoes\"]//h2")).click();
}
}
The above code works as desired.
Creating user defined function have two different scope
1) Create function with piece of code and call that function whenever u needed it (Which is done above)
2) Second one creating a custom function wrt each controls like edit boxes , radiobutton , check boxes - etc , so by creating this functions u can make better feasible of your automation framework
I just discovered selenium - a great tool!
I plan to run/use selenium-ide generated junit4 code. But I need it to run with many browsers/web drivers.
Is there a junit/java-pattern for this use case? My first idea was to use #RunWith(Parameterized.class) and provide a List of WebDrivers (the parameter for the class - probably provided as an external file listing browsers and versions?!). Is this a good idea? Is it possible to provide a central #Parameters -method to be used by all my Selenium-tests?
What alternatives are there?
Probably it is possible to change the "Format" that Selenium exports to minimize manual changes?
Well, I do need to switch drivers from time to time, so I did this:
I initialize selenium related stuff in my own Class - called by name of the application and the driver is approached by the getters. When calling my class constructor, I use enum type of driver to initialize with:
private WebDriver driver;
public TestUI(Environment.DriverToUse drv){
switch (drv){
case CHROME:{
ChromeDriverService service = ChromeDriverService.createDefaultService();
File file = new File(TestUI.class.getResource("/chromedriver.exe").toURI());
System.setProperty(ChromeDriverService.CHROME_DRIVER_EXE_PROPERTY, file.getAbsolutePath());
ChromeOptions options = new ChromeOptions();
options.addArguments("--start-maximized");
driver = new ChromeDriver(service,options);
driver.manage().timeouts().implicitlyWait(30, TimeUnit.SECONDS);
break;
}
case FIREFOX:{
FirefoxProfile ffProfile = new FirefoxProfile();
ffProfile.setPreference("browser.safebrowsing.malware.enabled", false);
driver = new FirefoxDriver(ffProfile);
driver.manage().window().setPosition(new Point(0, 0));
java.awt.Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
Dimension dim = new Dimension((int) screenSize.getWidth(), (int) screenSize.getHeight());
driver.manage().window().setSize(dim);
driver.manage().timeouts().implicitlyWait(30, TimeUnit.SECONDS);
break;
}
public WebDriver getDriver(){
return driver;
}
of course my Environment class looks like this
public class Environment {
public enum DriverToUse {FIREFOX, CHROME};
// .. and some other stuff, because I need to test on different environments, so I store here Environment URL for example
And my test class looks something like this
#Before
public static final Environment.DriverToUse USED_DRIVER = Environment.DriverToUse.FIREFOX;
#Test
public void testVersionNumber() throws Exception{
TestUI testUI= new TestUI(USED_DRIVER);
WebElement version = testUI.getDriver().findElement(By.id("the Id of element"));
version.click();
//...
}
Use Selenium RC/Selenium Server. These come with the API's you will need to run remote tests in multiple browsers simply. Happy Hunting!
Check out the Selenide library. It's an open source wrapper for selenium that makes UI testing a breeze. Here's an example test.
#Test
public void userCanLoginByUsername() {
open("/login");
$(By.name("user.name")).setValue("johny");
$("#submit").click();
$(".loading_progress").should(disappear); // Waits until element disappears
$("#username").shouldHave(text("Hello, Johny!")); // Waits until element gets text
}