WebDriver is not being instantiated in Cucumber tests - java

I'm trying to instantiate a single instance of WebDriver to use throughout some tests and, in doing so, I may have over complicated. I think I just need to instantiate a static webdriver and then re-use once for each feature file, assuming that's possible.
I'm not clear why the driver is not being instantiated. I am trying to Debug by running from feature file in the IDE (intelliJ). I'm expecting driver to instantiate when Super is called.
Step Defs:
public class FindAHolidayStepDefs extends DriverBase {
private HolidaysHomePage tcHomePage;
private SearchResultsPage searchPage;
#Before //this is the cucumber #Before
public void setup(){
holHomePage = new HolidaysHomePage(driver);
searchPage = new SearchResultsPage(driver);
}
#Given("^I am on the Holidays homepage$")
public void IAmOnTheHolidaysHomepage() {
assertEquals("the wrong page title was displayed !", "Cheap Travel\u00ae : Cheap Holidays & Last Minute Package Deals", holHomePage.getTitle());
} // more step defs below...
PageObject:
public class HolidaysHomePage extends SeleniumBase {
public HolidaysHomePage(WebDriver driver) {
super(driver); //Expecting driver to instantiate here
visit("");
driver.manage().window().maximize();
assertTrue("The Holidays header logo is not present",
isDisplayed(headerLogo));
}
//code...
DriverBase:
public class DriverBase implements Config {
protected WebDriver driver;
#Before //this is the Junit #Before
public void before() throws Throwable {
if (host.equals("localhost")) {
switch (browser) {
case "firefox":
driver = new FirefoxDriver();
break;
case "chrome":
System.setProperty("webdriver.chrome.driver",
System.getProperty("user.dir") + "\\drivers\\chromedriver.exe");
driver = new ChromeDriver();
break;
}
}
}
#After
public void after() {
driver.quit();
}
};
SeleniumBase (just a class with Selenium API methods abstracted out)
public class SeleniumBase implements Config {
public WebDriver driver;
public SeleniumBase(WebDriver driver) {
this.driver = driver;
}
public void visit(String url) {
if (url.contains("http")) {
driver.get(url);
} else {
driver.get(baseUrl + url);
}
}
Config:
public interface Config {
final String baseUrl = System.getProperty("baseUrl", "http://holidaystest.co.uk/");
final String browser = System.getProperty("browser", "chrome");
final String host = System.getProperty("host", "localhost");
}

Based on your code, here are my suggestions:
You do not need to have a DriverBase class as you already created a SeleniumBase class
Move the below driver initialization code to setup() method in FindAHolidayStepDefs
FindAHolidayStepDefs should extend SeleniumBase
if (host.equals("localhost")) {
switch (browser) {
case "firefox":
driver = new FirefoxDriver();
break;
case "chrome":
System.setProperty("webdriver.chrome.driver",
System.getProperty("user.dir") + "\\drivers\\chromedriver.exe");
driver = new ChromeDriver();
break;
}
}

Related

how to make driver as thread safe to run methods of a class in parallel in selenium java

I have 3 test methods using driver from Base class. I tired to run these methods in parallel but getting failures. Reponse to my problem is appreciated. Thanks
Class having 3 test methods
public class TestCases extends BaseClass {
#Test
public void Test1() {
homePage.checkIfElementIsDisplayed(homePage.emailElement);
homePage.checkIfElementIsDisplayed(homePage.passwordElement);
homePage.checkIfElementIsDisplayed(homePage.signInElement);
homePage.emailElement.sendKeys("karteek#gmail.com");
homePage.passwordElement.sendKeys("******");
}
#Test
public void Test2() {
homePage.checkValuesInListGroup();
homePage.checkSecondListItem();
homePage.checkSecondListItemBadgeValue();
}
#Test
public void Test3() throws InterruptedException {
homePage.ScrolltotheElement(homePage.dropDownOption);
homePage.checkDefaultSelectedValue();
homePage.selectOption3();
}
}
Base Class
public class BaseClass {
public WebDriver driver;
public HomePage homePage;
public WebDriver setup() throws IOException {
Properties prop = new Properties();
FileInputStream fis = new FileInputStream(
System.getProperty("user.dir") + "\\src\\main\\resource\\GlobalData.Properties");
prop.load(fis);
String browserName = System.getProperty("browser") != null ? System.getProperty("browser")
: prop.getProperty("browser");
if (browserName.contains("chrome")) {
WebDriverManager.chromedriver().setup();
driver = new ChromeDriver();
}
else if (browserName.contains("edge")) {
WebDriverManager.edgedriver().setup();
driver = new EdgeDriver();
} else if (browserName.contains("firefox")) {
WebDriverManager.firefoxdriver().setup();
driver = new FirefoxDriver();
}
driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(10));
driver.manage().window().maximize();
return driver;
}
#BeforeMethod
public HomePage LaunchApplication() throws IOException {
driver = setup();
homePage = new HomePage(driver);
homePage.goTo();
return homePage;
}
#AfterMethod
public void tearDown() throws IOException {
driver.close();
}
I tried creating ThreadLocal Class for WebDriver as
ThreadLocal<WebDriver> threadSafeDriver=new ThreadLocal<WebDriver>();
and use this in setup() method of BaseClass by writing
threadSafeDriver.set(driver);
but this didnot really help
Most likely you are using the TestNG framework. One of the differences between JUnit and TestNG is that JUnit creates a new class instance for each test method by default but TestNG creates a single instance for all test methods in the class.
You can see the parallel option in TestNG suite (see docs) but there is no way to force TestNG to create a new instance for each test.
The simplest solution is to switch to JUnit framework. Then the code from the example should work.

Selenium PageObject throws Invocation Target Exception

I am trying to create a framework(Selenium+TestNg+java) for a Web app(The environment is MacOs+ChromeDriver and the driver server is in \usr\local\bin) but got stuck in basic structure. I have a class(Driversetup.java) that starts the browser, another one that contains WebElements and methods(ProfileUpdateObjects.java) and the third one containing test methods. Now, when I try to run this TestNG class having just a single method, I get following exception.
java.lang.RuntimeException: java.lang.reflect.InvocationTargetException
at org.openqa.selenium.support.PageFactory.instantiatePage(PageFactory.java:138).
Below is the code (All the classes are in different packages).
public class ProfileUpdateTest {
#Test(enabled = true, priority = 1)
public void profileUpdate() throws MalformedURLException, InterruptedException, ParseException {
WebDriver driver = DriverSetup.startBrowser("chrome");
ProfileUpdateObjects pu = PageFactory.initElements(driver, ProfileUpdateObjects.class);
pu.navigateProfile();
}
}
The code for ProfileUpdateObject class
public class ProfileUpdateObjects {
WebDriver driver;
public ProfileUpdateObjects(WebDriver cdriver) {
this.driver = cdriver;
}
#FindBy(xpath = " //div[#class='ico-menu']")
private WebElement menu;
#FindBy(xpath = "//a[#title='My Dashboard']")
private WebElement myDashboard;
#FindBy(xpath = " //a[contains(text(),'View Profile')]")
public WebElement profile;
#FindBy(xpath = "//li[contains(text(),'Permanent Address')]")
private WebElement permanentAddress;
#FindBy(xpath = "//li[contains(text(),'Banking Information')]")
private WebElement bankingInformation;
WebDriverWait waitfor = new WebDriverWait(driver, 2000);
public void navigateProfile() throws InterruptedException {
menu.click();
profile.click();
waitfor.until(ExpectedConditions.visibilityOf(permanentAddress));
}
}
DriverSetup.java
public class DriverSetup {
public static WebDriver driver;
public static WebDriver startBrowser(String browserName, String url) {
if (browserName.equalsIgnoreCase("chrome")) {
driver = new ChromeDriver();
}
driver.manage().window().maximize();
driver.get(url);
return driver;
}
}
It is failing in pu.navigateProfile() call. Also, is it true that #FindBy takes more memory compared to driver.find() syntax and besides POM are there any other design principles for Automation framework because most of the resources over Web are one or the other implementation of POM.
Simple solution is to move new WebDriverWait. It should not be instantiated as instance variable.
Instead of:
WebDriverWait waitfor = new WebDriverWait(driver, 2000);
public void navigateProfile() throws InterruptedException {
menu.click();
profile.click();
waitfor.until(ExpectedConditions.visibilityOf(permanentAddress));
}
Use:
public void navigateProfile() {
menu.click();
profile.click();
new WebDriverWait(driver, 2000).until(ExpectedConditions.visibilityOf(permanentAddress));
}
This will solve your issue (Already tested it)

TestNG Selenium: Why does #Before work fine but #BeforeTest throws a NullPointerException?

This is my step definition class which is failing, the first #Test where the driver gets the URL is throwing a NullPointerException:
public class stepDefinitionASOS extends base {
AsosElements ae;
#BeforeTest
public void initializeTest() throws IOException {
driver = initializeDriver();
PageFactory.initElements(driver, this);
driver.manage().window().maximize();
ae = new AsosElements(driver);
}
#Test
#Given("^User goes to the \"([^\"]*)\" website$")
public void user_navigates_to_the_ASOS_website(String url) throws Throwable {
driver.get(url);
}
#Test
#Given("^User navigates to the account page$")
public void user_navigates_to_the_account_page() throws Throwable {
ae.clickAsosMyAccountDropdown(driver);
ae.clickAsosMyAccountButton(driver);
}
#Test
#When("^User logs in with (.+) and (.+)$")
public void user_logs_in_with_username_and_password(String username, String password) throws Throwable {
ae.typeEmailAddress(username);
ae.typePassword(password);
ae.clickSignInButton();
}
#Test
#Then("^Login should be successful$")
public void login_successful_is_something() throws Throwable {
Assert.assertTrue(ae.getMyAccountTitle().isDisplayed());
}
#AfterTest
public void teardown() {
driver.close();
driver = null;
}
}
The tests seem to run fine when I use the #Before Cucumber annotation instead of #BeforeTest TestNG annotation.
This is the base class that the step definition class is inheriting from:
public class base {
public WebDriver driver;
public Properties prop;
public static final String USERNAME = ""; // I have blanked this out for security reasons
public static final String AUTOMATE_KEY = ""; // I have blanked this out for security reasons
public static final String URL = "https://" + USERNAME + ":" + AUTOMATE_KEY + "#hub-cloud.browserstack.com/wd/hub";
public WebDriver initializeDriver() throws IOException {
DesiredCapabilities caps = new DesiredCapabilities();
DesiredCapabilities capability = new DesiredCapabilities();
caps.setCapability("os", "OS X");
caps.setCapability("os_version", "High Sierra");
caps.setCapability("browser", "Firefox");
caps.setCapability("browser_version", "54.0");
caps.setCapability("browserstack.local", "false");
caps.setCapability("browserstack.selenium_version", "3.5.2");
driver = new RemoteWebDriver(new URL(URL), caps);
driver.manage().timeouts().implicitlyWait(10,TimeUnit.SECONDS);
return driver;
}
Feature file:
#AsosLogin
Feature: Logging into ASOS
Scenario Outline: Going to ASOS website and logging in correct details
Given User goes to the "https://www.asos.com" website
And User navigates to the account page
When User logs in with <username> and <password>
Then Login should be successful
Examples:
|username |password |
|random#hotmail.co.uk |password |
StackTrace:
java.lang.NullPointerException at
stepDefinitions.stepDefinitionASOS.user_navigates_to_the_ASOS_website(stepDefinitionASOS.java:24)
at ✽.Given User goes to the "https://www.asos.com"
website(C:/Users/aliba/Documents/googleTingYaKnaDisOne/src/test/java/features/asosLogin.feature:5)
Does anyone know how I can go about fixing this?

Inject WebDrivers in TestNG #before test with #guice

I am new with configure selenium. Looked for passing drivers find this solution https://stackoverflow.com/a/35101914/7104440 I wonder is possible to #inject many drivers from browsers in this way. Is possible to bind different drivers? I got error with this code:
encom.google.inject.CreationException: Unable to create injector, see the following errors:
1) Binding to null instances is not allowed. Use toProvider(Providers.of(null)) if this is your intended behaviour.
at assecobs.driver.DriverModule.configure(DriverModule.java:31)
2) A binding to org.openqa.selenium.WebDriver was already configured at assecobs.driver.DriverModule.configure(DriverModule.java:31).
at assecobs.driver.DriverModule.configure(DriverModule.java:31)
DriverModule.class
private DriverSetup driverSetup = new DriverSetup();
#BeforeSuite
#Override
public void configure(Binder binder) {
for (BrowserNames browserName : BrowserNames.values()) {
System.out.println(" bind " + browserName.toString());
WebDriver driver = driverSetup.initDriver(browserName.toString());
binder.bind(WebDriver.class).toInstance(driver);
}
}
}
DriverSetup.class
#SneakyThrows
public WebDriver initDriver(String browser) {
if (browser.equalsIgnoreCase("chrome")) {
capabilities = chromeCapabilities();
driver = initChromeDriver(capabilities);
} else if (browser.equalsIgnoreCase("firefox")) {
capabilities = firefoxCapabilities();
driver = initFirefoxDriver(capabilities);
} else if (browser.equalsIgnoreCase("opera")) {
capabilities = operaCapabilities();
driver = initOperaDriver(capabilities);
} else {
capabilities = firefoxCapabilities();
return driver = initFirefoxDriver(capabilities);
}
return driver;
}
ClientTest.class
#Guice(modules = {DriverModule.class})
public class ClientTest extends DriverSetup {
#Inject
WebDriver driver;
I have been using Guice + WebDriver for a while. You can inject webdriver as you have shown in the ClientTest.java.
Check here for the detailed steps. - http://www.testautomationguru.com/selenium-webdriver-dependency-injection-using-guice/

How to get focus on firefox driver in conjunction with TestNG implementing ITestListener

I'd appreciate and thank for any advice here. I am trying to user the driver object from POM framework by use of TestNG and implementing ITestListerner interface.
This is a TestNG class implementing ItestListener
public class TestNGListener implements ITestListener {
#Override
public void onFinish(ITestContext result) {
WebDriver driver = BrowserFactory.LanuchBrowser("firefox", "http://10.207.182.108:81/opencart/");
Util.takescreenshot(driver, result.getName());
}
This class is used to return a WebDriver Object after launch one of the browser from switch case. I am using same driver as apart of TestNG by implementing Itestlistener & overriding failure public void onFinish(ITestContext result) in the above class & unfortunately, it doesn't return a webdriver object & take a screen shot but launches a new browser instead.
public class BrowserFactory {
static WebDriver driver;
public static WebDriver LanuchBrowser(String Brwsr, String URL){
System.out.println(Brwsr.toLowerCase());
switch (Brwsr.toLowerCase()){
case "firefox":
driver=new FirefoxDriver();
break;
case "chrome":
driver= new ChromeDriver();
System.setProperty("WebDriver.chrome.driver", "chromedriver.exe");
break;
case "internet explorer":
System.out.println("IE");
driver= new InternetExplorerDriver();
System.setProperty("WebDriver.IE.driver","IEDriverServer.exe");
break;
default:
System.out.println("Please select one of the Browsers listed : Chrome,Firefox or InternetExplorer");
break;
}
driver.manage().window().maximize();
driver.get(URL);
return driver;
}
}
Here is my method to capture screenshot
public class Util {
final static Logger logger = Logger.getLogger(Util.class);
public static void validatePgeNavgtn(WebDriver driver, String PgeTitle){
PropertyConfigurator.configure("log4j.properties");
String pgtitle=driver.getTitle();
if (pgtitle.equalsIgnoreCase(PgeTitle)){
logger.info("title matched");
}
}
public static void takescreenshot(WebDriver driver, String screen){
TakesScreenshot ts = (TakesScreenshot)driver;
File src= ts.getScreenshotAs(OutputType.FILE);
try {
FileUtils.copyFile(src, new File("./Screenshot/"+screen+".png"));
} catch (IOException e) {
logger.warn(e.getMessage());
}
}
Could you please suggest an approach that below method shouldn't launch a new browser session but the focus should be retained on first browser instance & also capture a screenshot
You need create BrowserFactory class as singleton which will create always give single instance of BrowserFactory as below :-
public class BrowserFactory {
private WebDriver driver;
private static BrowserFactory browserFactoryInstance = null;
private BrowserFactory(String Brwsr, String URL) {
System.out.println(Brwsr.toLowerCase());
switch (Brwsr.toLowerCase()) {
case "firefox":
this.driver = new FirefoxDriver();
break;
case "chrome":
System.setProperty("WebDriver.chrome.driver", "chromedriver.exe");
this.driver = new ChromeDriver();
break;
case "internet explorer":
System.out.println("IE");
System.setProperty("WebDriver.IE.driver", "IEDriverServer.exe");
this.driver = new InternetExplorerDriver();
break;
default:
System.out
.println("Please select one of the Browsers listed : Chrome,Firefox or InternetExplorer");
break;
}
this.driver.manage().window().maximize();
this.driver.get(URL);
}
public static BrowserFactory getInstance(String Brwsr, String URL) {
if(browserFactoryInstance == null) {
browserFactoryInstance = new BrowserFactory(Brwsr, URL);
}
return browserFactoryInstance;
}
public WebDriver getDriver() {
return this.driver;
}
}
Now you can get WebDriver instance as below :-
//It will return always single instance per test run
WebDriver driver = BrowserFactory.getInstance("firefox", "http://10.207.182.108:81/opencart/").getDriver();
Util.takescreenshot(driver, result.getName());

Categories

Resources