I implemented cucumber-jvm picocontainer with SharedDriver and works well locally. I would like to use Selenium Grid which has been configured well but I don't know how should I modify Shareddriver class in order to use RemoteWebDriver instead of WebDriver and connect to Selenium GRID.
new RemoteWebDriver(new("http://..../wd/hub"), capability); doesn't work because I need to throw MalFormedException and REAL_DRIVER is a static field.
Any idea? Thanks!
public class SharedDriver extends EventFiringWebDriver {
private static final WebDriver REAL_DRIVER = WebDriverFactory.internetExplorerWebDriver();
private static final Thread CLOSE_THREAD = new Thread() {
#Override
public void run() {
REAL_DRIVER.close();
}
};
static {
Runtime.getRuntime().addShutdownHook(CLOSE_THREAD);
}
public SharedDriver() {
super(REAL_DRIVER);
}
#Override
public void close() {
if(Thread.currentThread() != CLOSE_THREAD) {
throw new UnsupportedOperationException(
"WebDriver should not close!"
);
}
super.close();
}
#Before
public void deleteAllCookies() {
manage().deleteAllCookies();
}
#After
public void embedScreenshot(Scenario scenario) {
...
}
}
WebDriverFactory:
class WebDriverFactory {
static {
System.setProperty("webdriver.ie.driver", "src/test/resources/webDrivers/IEDriverServer.exe");
}
static WebDriver internetExplorerWebDriver() {
DesiredCapabilities returnCapabilities = DesiredCapabilities.internetExplorer();
System.setProperty("webdriver.ie.driver", "src/test/resources/webDrivers/IEDriverServer.exe");
returnCapabilities.setCapability("requireWindowFocus", true);
returnCapabilities.setCapability(InternetExplorerDriver.ENABLE_PERSISTENT_HOVERING, false);
returnCapabilities.setCapability(InternetExplorerDriver.IE_ENSURE_CLEAN_SESSION, true);
returnCapabilities.setCapability(CapabilityType.ACCEPT_SSL_CERTS, true);
returnCapabilities.setCapability("ignoreZoomSetting", true);
return new InternetExplorerDriver(returnCapabilities);
}
You can wrap the return statement into a try..catch block and return null in case of exception is being thrown.
class WebDriverFactory {
static {
System.setProperty("webdriver.ie.driver", "src/test/resources/webDrivers/IEDriverServer.exe");
}
static WebDriver internetExplorerWebDriver() {
DesiredCapabilities returnCapabilities = DesiredCapabilities.internetExplorer();
System.setProperty("webdriver.ie.driver", "src/test/resources/webDrivers/IEDriverServer.exe");
returnCapabilities.setCapability("requireWindowFocus", true);
returnCapabilities.setCapability(InternetExplorerDriver.ENABLE_PERSISTENT_HOVERING, false);
returnCapabilities.setCapability(InternetExplorerDriver.IE_ENSURE_CLEAN_SESSION, true);
returnCapabilities.setCapability(CapabilityType.ACCEPT_SSL_CERTS, true);
returnCapabilities.setCapability("ignoreZoomSetting", true);
try {
return new RemoteWebDriver(new URL("http://www.google.com"), returnCapabilities);
} catch (MalformedURLException e) {
return null;
}
}
then, check that the REAL_DRIVER value is not null.
Related
I have a maven project that runs testng and cucumber. If I run the testng and my test fails my program takes screenshots and creates a report. However if I run my cucumber tests and it fails, I get java.lang.NullPointerException: Cannot invoke "org.openqa.selenium.TakesScreenshot.getScreenshotAs(org.openqa.selenium.OutputType)" because "screenShot" is null.
Both the testng and cucumber references the same listeners and base class.
My listeners class (on failure):
#Override
public void onTestFailure(ITestResult result) {
ExtentThred.get().fail(result.getThrowable());
WebDriver driver = null;
String testMethodName = result.getMethod().getMethodName();
try {
driver = (WebDriver)result.getTestClass().getRealClass().getDeclaredField("driver").get(result.getInstance());
}
catch (Exception e)
{
}
try {
ExtentThred.get().addScreenCaptureFromPath(getScreenshotPath(testMethodName, driver),result.getMethod().getMethodName());
}
catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
My base class:
public class Base {
public static WebDriver driver;
public Properties prop;
public WebDriver initializeDriver() throws IOException {
prop = new Properties();
FileInputStream file = new FileInputStream(System.getProperty("user.dir") + "\\src\\main\\java\\resources\\data.properties");
prop.load(file);
String browserName = prop.getProperty("browser");
if (browserName.contains("chrome")) {
System.setProperty("webdriver.chrome.driver", System.getProperty("user.dir") + "\\chromedriver.exe");
ChromeOptions chromeOptions = new ChromeOptions();
if (browserName.contains("headless")){
chromeOptions.addArguments("headless");
}
driver = new ChromeDriver(chromeOptions);
}
else if (browserName == "firefox") {
}
else if (browserName == "edge") {
}
driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
return driver;
}
public String getScreenshotPath(String testCaseName, WebDriver driver) throws IOException
{
TakesScreenshot screenShot = (TakesScreenshot) driver;
File source = screenShot.getScreenshotAs(OutputType.FILE);
String destinationFile = System.getProperty("user.dir")+"\\reports\\"+ testCaseName +".png";
FileUtils.copyFile(source, new File(destinationFile));
return destinationFile;
}
}
My testng class that works fine:
public class ValidateLoggedIn extends Base {
public WebDriver driver;
#BeforeTest
public void initialize() throws IOException {
driver = initializeDriver();
}
#Test(dataProvider = "getData")
public void HomePageTitle(String mobileNumber, String password, String access) throws IOException {
driver.get(prop.getProperty("cars"));
MainPage mainPage = new MainPage(driver);
mainPage.getLogin().click();
mainPage.getMobileNumber().sendKeys(mobileNumber);
mainPage.getPassword().sendKeys(password);
mainPage.getLoginButton().click();
if (access == "Allowed User") {
LoggedInPage loggedInPage = new LoggedInPage(driver);
Assert.assertTrue(loggedInPage.getLogOutButton().isDisplayed());
loggedInPage.getLogOutButton().click();
}
else {
mainPage.getLoginButton();
Assert.assertTrue(mainPage.getLoginButton().isDisplayed());
}
}
#DataProvider
public Object[][] getData() {
Object[][] userData = new Object[1][3];
userData[0][0] = "0720127992";
userData[0][1] = "Dr0medar!s";
userData[0][2] = "Allowed User";
return userData;
}
#AfterTest
public void teardown()
{
driver.close();
}
}
My step definition for my cucumber:
public class StepDefinition extends Base {
public WebDriver driver;
#Given("^Initilize the browser with Chrome$")
public void initilize_the_browser_with_chrome() throws Throwable {
driver = initializeDriver();
}
#When("^User enters (.+) and (.+) and logs in$")
public void user_enters_and_and_logs_in(String mobilenumber, String password) throws Throwable {
MainPage mainPage = new MainPage(driver);
mainPage.getLogin().click();
mainPage.getMobileNumber().sendKeys(mobilenumber);
mainPage.getPassword().sendKeys(password);
mainPage.getLoginButton().click();
}
#Then("^verify if user is successfully logged in$")
public void verify_if_user_is_successfully_logged_in() throws Throwable {
LoggedInPage loggedInPage = new LoggedInPage(driver);
Assert.assertTrue(loggedInPage.getLogOutButton().isDisplayed());
loggedInPage.getLogOutButton().click();
}
#And("^Navigate to \"([^\"]*)\" site$")
public void navigate_to_something_site(String strArg1) throws Throwable {
driver.get(strArg1);
}
#And("^Close Browser$")
public void close_browser() throws Throwable {
driver.quit();
}
}
My test runner:
#CucumberOptions(
features = "src/test/java/features",
glue = "stepDefinitions")
public class TestRunner extends AbstractTestNGCucumberTests {
}
My error:
java.lang.NullPointerException: Cannot invoke "org.openqa.selenium.TakesScreenshot.getScreenshotAs(org.openqa.selenium.OutputType)" because "screenShot" is null
at resources.Base.getScreenshotPath(Base.java:53)
at cars.Listeners.onTestFailure(Listeners.java:52)
at org.testng.internal.TestListenerHelper.runTestListeners(TestListenerHelper.java:96)
at org.testng.internal.TestInvoker.runTestResultListener(TestInvoker.java:220)
at org.testng.internal.TestInvoker$MethodInvocationAgent.invoke(TestInvoker.java:832)
at org.testng.internal.TestInvoker.invokeTestMethods(TestInvoker.java:147)
at org.testng.internal.TestMethodWorker.invokeTestMethods(TestMethodWorker.java:146)
at org.testng.internal.TestMethodWorker.run(TestMethodWorker.java:128)
at java.base/java.util.ArrayList.forEach(Unknown Source)
at org.testng.TestRunner.privateRun(TestRunner.java:764)
at org.testng.TestRunner.run(TestRunner.java:585)
at org.testng.SuiteRunner.runTest(SuiteRunner.java:384)
at org.testng.SuiteRunner.runSequentially(SuiteRunner.java:378)
at org.testng.SuiteRunner.privateRun(SuiteRunner.java:337)
at org.testng.SuiteRunner.run(SuiteRunner.java:286)
at org.testng.SuiteRunnerWorker.runSuite(SuiteRunnerWorker.java:53)
at org.testng.SuiteRunnerWorker.run(SuiteRunnerWorker.java:96)
at org.testng.TestNG.runSuitesSequentially(TestNG.java:1218)
at org.testng.TestNG.runSuitesLocally(TestNG.java:1140)
at org.testng.TestNG.runSuites(TestNG.java:1069)
at org.testng.TestNG.run(TestNG.java:1037)
at org.testng.remote.AbstractRemoteTestNG.run(AbstractRemoteTestNG.java:115)
at org.testng.remote.RemoteTestNG.initAndRun(RemoteTestNG.java:251)
at org.testng.remote.RemoteTestNG.main(RemoteTestNG.java:77)
I am not sure why cucumber gives a NullPointerException and testng one does not. using `e.printStackTrace()' I see that the driver is null.
I have looked at answers such as null-pointer-exception-when-trying-to-take-a-screenshot-with-selenium and exception-while-taking-screenshot but nothing helped.
Replace getDeclaredField with getField
driver = (WebDriver)result.getTestClass().getRealClass().getDeclaredField("driver").get(result.getInstance());
getField can get a field inherited from a superclass but getDeclaredField cannot. getDeclaredField restricts itself to the class you call the function on.
And Remove static from public static WebDriver Driver from base class.
It has a close browser step and then you are trying to access this session in the listener class so obviously, the session will be null.
remove the after test and try
I think that the problem might be with your base file, where you have:
"public static WebDriver driver;"
remove "static" and it should work properly
I have Three Classes as below:
And When I run the test as TestNG from 'Tests.java' I get java.lang.NullPointerException exception:
NOTE:
-It picks the browser name 'chrome' successfully from the .properties file.
-If I discard the 'Tests.java' class and move the #Test method to 'LaunchBrowserTemp.java' class and add remaining corresponding tags (i.e. BeforeClass, BeforeMethod, AfterClass, AfterMethod) to corresponding methods in 'LaunchBrowserTemp.java' it works fine. It fails only when I keep the testng annotations to the 'Tests.java' class.
src\main\java\utilities\LaunchBrowserTemp.java
public class LaunchBrowserTemp {
private static ChromeDriverService srvc;
private static WebDriver driver;
private static String browser = getProperties("selenium.browser");
private static final String baseBrowserPath = "src\\main\\resources\\drivers\\";
private static ChromeOptions options;
public static void initBrowser() throws Exception {
switch (browser.toLowerCase()){
case "chrome":
options = new ChromeOptions();
options.addArguments("--start-maximized");
options.addArguments("--disable-extensions");
options.setAcceptInsecureCerts(true);
srvc = new ChromeDriverService.Builder()
.usingDriverExecutable(new File(baseBrowserPath + "chromedriver.exe"))
.usingAnyFreePort()
.build();
srvc.start();
break;
default:
throw new Exception("Browser Not handled in code!");
}
}
public static void stopDriverService() {
srvc.stop();
}
public void startDriver() {
driver = new RemoteWebDriver(srvc.getUrl(), options);
}
public void endDriver() {
driver.quit();
}
public static WebDriver driver() {
return driver;
}
}
src\main\java\utilities\LoadProperties.java
public class LoadProperties {
public static String getProperties(String propName) {
Properties prop = new Properties();
try {
FileInputStream fis = new FileInputStream("src/main/resources/config.properties");
prop.load(fis);
} catch (Exception e){}
return prop.getProperty(propName);
}
}
src\test\java\Tests.java
public class Tests {
LaunchBrowserTemp obj = new LaunchBrowserTemp();
#BeforeClass
public void init() throws Exception{
LaunchBrowserTemp.initBrowser();
}
#BeforeTest
public void start(){
obj.startDriver();
}
#Test
public void openUrl(){
driver().get("https://www.google.com");
}
#AfterTest
public void teardown(){
obj.endDriver();
}
#AfterClass
public void terminate() {
LaunchBrowserTemp.stopDriverService();
}
}
Error Screenshot
I have made an TestListener and implement method which should make screenshot when test got failed. But if test got failed screenshot is not taken but I don't know why. If method takeScreenshot() is called the screenshot is not saved in allure results. Below I post code of TestListener and TestBase:
public class TestListener extends TestBase implements ITestListener {
#Override
public void onTestFailure(ITestResult result) {
Object testClass = result.getInstance();
driver = ((TestBase) testClass).getTestDriver();
if(driver != null) {
takeScreenshot();
}
}
#Override
public void onTestSkipped(ITestResult result) {
}
#Attachment(value = "Page screenshot", type = "image/png")
public byte[] takeScreenshot() {
setThisDriver(driver);
return ((TakesScreenshot)driver).getScreenshotAs(OutputType.BYTES);
}
public class TestBase {
public WebDriver driver;
public static Properties prop;
public static String env;
public static String url;
public TestBase() {
try {
this.prop = new Properties();
FileInputStream ip = new FileInputStream(
"src/main/java/config/env.properties");
this.prop.load(ip);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
public void initialization() {
System.setProperty("webdriver.gecko.driver", "src/main/resources/geckodriver");
System.setProperty("http.agent", "Mozilla/5.0");
FirefoxBinary firefoxBinary = new FirefoxBinary();
File downloadsDir = new File("src/main/documents/");
//firefoxBinary.addCommandLineOptions("--headless");
FirefoxOptions options = new FirefoxOptions();
FirefoxProfile profile = new FirefoxProfile();
profile.setPreference("browser.download.folderList", 2);
profile.setPreference("browser.download.dir", downloadsDir.getAbsolutePath());
profile.setPreference("browser.download.manager.alertOnEXEOpen", false);
profile.setPreference("browser.helperApps.neverAsk.saveToDisk",
"application/msword, application/csv, application/ris, text/csv, image/png, application/pdf, text/html, text/plain, application/zip, application/x-zip, application/x-zip-compressed, application/download, application/octet-stream");
profile.setPreference("browser.download.manager.showWhenStarting", false);
profile.setPreference("browser.download.manager.focusWhenStarting", false);
profile.setPreference("browser.download.useDownloadDir", true);
profile.setPreference("browser.helperApps.alwaysAsk.force", false);
profile.setPreference("browser.download.manager.alertOnEXEOpen", false);
profile.setPreference("browser.download.manager.closeWhenDone", true);
profile.setPreference("browser.download.manager.showAlertOnComplete", false);
profile.setPreference("browser.download.manager.useWindow", false);
profile.setPreference("services.sync.prefs.sync.browser.download.manager.showWhenStarting", false);
profile.setPreference("pdfjs.disabled", true);
//options.setHeadless(true);
options.setBinary(firefoxBinary);
//options.setProfile(profile);
this.driver = new FirefoxDriver(options);
try {
this.driver.manage().window().maximize();
this.driver.manage().deleteAllCookies();
}
catch (WebDriverException e) {
System.out.println(e.toString());
this.driver.quit();
}
}
public WebDriver getTestDriver() {
return this.driver;
}
public void setThisDriver(WebDriver webDriver) {
this.driver = webDriver;
}
public String getCurrentDate() {
String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(
Calendar.getInstance().getTime());
return timeStamp;
}
public void captureScreenshots(String result) {
try {
TakesScreenshot ts = (TakesScreenshot) driver;
File source = ts.getScreenshotAs(OutputType.FILE);
FileUtils.copyFile(source, new File("src/screenshots/" + getCurrentDate() + ".png"));
System.out.println("Takes screenshot");
} catch (Exception e) {
System.out.println("Exception" + e.getMessage());
}
}
Ok, if someone have the same problem here is an answer. Configuration was ok but if we want generate report with screenshots we should run tests from command line using: ./gradlew clean test and ./gradlew allureReport to generate report.
I am using the FirefoxDriverInstance as the singleton for calling driver. Also, using a firefox profile to bypass 2-factor-authentication.
public class FirefoxDriverInstance {
public static WebDriver Instance = null;
public static void Initialize() {
if (Instance == null) {
System.out.println("Initializing Firefox Driver!!!");
System.setProperty("webdriver.gecko.driver","./src/test/resources/driver/geckodriver2.exe");
ProfilesIni profile = new ProfilesIni();
FirefoxOptions options = new FirefoxOptions();
options.setProfile(profile.getProfile("SeleniumTester"));
Instance = new FirefoxDriver(options);
}
Instance.manage().timeouts().implicitlyWait(5, TimeUnit.SECONDS);
Instance.manage().window().maximize();
}
public static void close() {
System.out.println("Closing Browser!!!");
Instance.close();
Instance = null;
}
public static void quit() {
System.out.println("Quitting Browser!!!");
Instance.quit();
Instance = null;
}
}
Below is my login code using cucumber-selenium-webdriver. I have used the same driver instance.
public class TC01_Login {
#BeforeMethod
public void openbrowser() throws IOException {
FirefoxDriverInstance.Initialize();
}
public Properties propertyFileReader() throws Exception {
Properties obj = new Properties();
FileInputStream objfile = new FileInputStream(System.getProperty("user.dir")+"\\src\\test\\resources\\testdata\\application.properties");
obj.load(objfile);
return obj;
}
WebDriverWait wait = new WebDriverWait(FirefoxDriverInstance.Instance, 150);
#Given("^user has entered the required URL$")
public void user_has_entered_the_required_URL() throws Throwable {
Properties obj = propertyFileReader();
System.out.println("In the First Loop!!");
FirefoxDriverInstance.Instance.get(obj.getProperty("baseUrl"));
String actualTitle = FirefoxDriverInstance.Instance.getTitle();
System.out.println("Actual Title :" + actualTitle);
if (actualTitle.contains("test")){
System.out.println("INFO : Title is being displayed as expected.");
}
else {
System.out.println("ERROR : Title is NOT being displayed as expected."); }
}
}
Unable to understand how to bypass this error.
Try to put below code in constructor :
FirefoxDriverInstance.Initialize();
Example:
public class TC01_Login {
public TC01_Login (){
FirefoxDriverInstance.Initialize();
}
}
Remove it from BeforeMethod
Class1:
public class LaunchApp {
AndroidDriver<WebElement> driver;
#BeforeTest
public void Test1() throws MalformedURLException {
DesiredCapabilities capability = new DesiredCapabilities();
capability.setCapability("deviceName", "Android");
capability.setCapability("platformName", "Android");
capability.setCapability("platformVersion", "5.1.1");
capability.setCapability("deviceName", "Samsung Galaxy On5");
capability.setCapability("app",
"D:\\whatsapp.apk");
capability.setCapability("PackageName",
"com.movocado.socialbostonsports");
capability.setCapability("ActivityName",
"com.movocado.socialbostonsports.Activity.LogInSceen");
try {
driver = new AndroidDriver<WebElement>(new URL(
"http://127.0.0.1:4723/wd/hub"), capability);
} catch (MalformedURLException e) {
e.printStackTrace();
}
driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
}
Class2:
public class DrawerMenuTest {
AndroidDriver<WebElement> driver;
#Test(priority = 1)
public void DrawerMenuIcon() {
WebElement drawerMenu = driver.findElement(By
.id("com.movocado.socialbostonsports:id/rel_drawer"));
try {
drawerMenu.click();
} catch (NullPointerException e) {
System.out.println(e.getMessage());
}
}
Problem:
Second class is showing NullPointerException. Suggest me a solution.
You are initializing AndroidDriver into LaunchApp but does not pass this driver reference into DrawerMenuTest where you are creating only refrence variable of AndroidDriver with null that's causes of NullPointerException.
To overcome it you should create separate singlton class which will give single instance of AndroidDriver to each and every class as below :-
public class DriverInit {
private AndroidDriver<WebElement> driver;
private static DriverInit driverInit = null;
public static DriverInit getInstance() {
if (driverInit == null) {
driverInit = new DriverInit();
}
return driverInit;
}
private DriverInit() {
DesiredCapabilities capability = new DesiredCapabilities();
capability.setCapability("deviceName", "Android");
capability.setCapability("platformName", "Android");
capability.setCapability("platformVersion", "5.1.1");
capability.setCapability("deviceName", "Samsung Galaxy On5");
capability.setCapability("app", "D:\\whatsapp.apk");
capability.setCapability("PackageName", "com.movocado.socialbostonsports");
capability.setCapability("ActivityName", "com.movocado.socialbostonsports.Activity.LogInSceen");
this.driver = new AndroidDriver<WebElement>(new URL(
"http://127.0.0.1:4723/wd/hub"), capability);
this.driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
}
public WebDriver getDriver() {
return this.driver;
}
}
Now you can use this into LaunchApp class as below :-
public class LaunchApp {
AndroidDriver<WebElement> driver;
#BeforeTest
public void Test1() throws MalformedURLException {
driver = DriverInit.getInstance().getDriver();
//now do your stuff with this driver
}
}
And use in DrawerMenuTest class as below :-
public class DrawerMenuTest {
AndroidDriver<WebElement> driver;
#Test(priority = 1)
public void DrawerMenuIcon() {
//get driver instance first
driver = DriverInit.getInstance().getDriver();
WebElement drawerMenu = driver.findElement(By
.id("com.movocado.socialbostonsports:id/rel_drawer"));
try {
drawerMenu.click();
} catch (NullPointerException e) {
System.out.println(e.getMessage());
}
}
}
Hope it helps..:)