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
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
How to test sub links on a page in Selenium. I have an events page. Then from that events page i collect all the different events links. Then i want to recursively run tests on those links.
I have attached an image of the page. The green text are all links. So i collected the href values of all these. After that I have some tests to run on those pages. I have a test class called EventsPageTest for the main page. The test class for the sub pages is called SingleEventsPageTest. How do I transfer the href values from the main class to the other class. Or is there any other method I need to follow.
I searched the internet so much but was of no use.
Any help would be appreciated.
Thanks
EventsPageTest
package test;
import pages.EventsPageObjects;
#Listeners(listeners.TestListener.class)
public class EventsPageTest {
private static ExtentHtmlReporter htmlReporter;
private static ExtentReports extent;
private static ExtentTest test;
static WebDriver driver = null;
private static EventsPageObjects eventsPage;
public MutableCapabilities capabilities;
static Set<String> eventsLinks = new HashSet<String>();
String url;
#BeforeSuite
public void setUp() {
// initialize the HtmlReporter
htmlReporter = new ExtentHtmlReporter("extentReportsEventsPage.html");
// initialize ExtentReports and attach the HtmlReporter
extent = new ExtentReports();
// attach only HtmlReporter
extent.attachReporter(htmlReporter);
}
#BeforeTest
public void setUpTest() throws IOException{
WebDriverManager.chromedriver().setup();
driver = new ChromeDriver();
url = "abc.com";
driver.get(url);
System.out.println("Inside setUpTest");
//Create eventsPageObject
eventsPage = new EventsPageObjects(driver);
}
#Test(alwaysRun=true)
public void collectEventsLinks() throws InterruptedException, IOException {
test = extent.createTest("Collect all Events Links on a page","Test to Collect all Events Links on a page ");
test.log(Status.INFO, "Starting Test Case");
List<WebElement> links = driver.findElements(By.tagName("a"));
for (int i = 0; i<links.size(); i++) {
if(Pattern.matches("^https://"+ TestRunner.url +"/events/[^/]+[^\\s]$", links.get(i).getAttribute("href")))
eventsLinks.add((links.get(i).getAttribute("href")));
}
test.log(Status.INFO, "Finished Test Case");
}
#AfterTest(alwaysRun = true)
public void tearDownTest() {
//close browser
driver.close();
driver.quit();
}
#DataProvider(name="getURLS")
#AfterTest
public Object[] getURLS() {
System.out.println("Inside get Urls");
System.out.println("getURLS : " + eventsLinks.size());
Object[] objArray = eventsLinks.toArray();
System.out.println(eventsLinks.size());
return objArray;
}
#AfterSuite
public void tearDown() {
extent.flush();
}
}
SingleEventsPageTest
package test;
#Listeners(listeners.TestListener.class)
public class SingleEventsPageTest{
private static ExtentHtmlReporter htmlReporter;
private static ExtentReports extent;
private static ExtentTest test;
static WebDriver driver;
private static SingleEventsPageObjects singleEventsPage;
static List<Object> eventsURLS = new ArrayList<Object>();
#BeforeSuite
public void setUp() {
PropertiesFile.getProperties();
// initialize the HtmlReporter
htmlReporter = new ExtentHtmlReporter("extentReportsSingleEventsPage.html");
// initialize ExtentReports and attach the HtmlReporter
extent = new ExtentReports();
// attach only HtmlReporter
extent.attachReporter(htmlReporter);
}
#BeforeTest
public void setUpTest() throws IOException{
WebDriverManager.chromedriver().setup();
driver = new ChromeDriver();
//Create eventsPageObject
singleEventsPage = new SingleEventsPageObjects(driver);
}
#Test(dataProvider="getURLS",dataProviderClass=EventsPageTest.class,alwaysRun=true)
public void findIfEventsTitleExists(String url) throws InterruptedException, IOException {
driver.get(url);
System.out.println("Inside findIfEventsTitleExists : " + driver.getCurrentUrl());
test = extent.createTest("Events Title Exists","Test to verify if the Events Title exists after opening the page");
test.log(Status.INFO, "Starting Test Case");
test.log(Status.INFO, "Checking If the URL points to the events page else navigate to that");
Assert.assertEquals(true,singleEventsPage.findIfEventsTitleExists());
test.log(Status.INFO, "Finished Test Case");
}
#Test(dataProvider="getURLS",dataProviderClass=EventsPageTest.class,alwaysRun=true)
public void verifyIfEventDescriptionExists(String url) throws InterruptedException, IOException {
driver.get(url);
test = extent.createTest("Events description Exists","Test to verify if the Events description exists");
test.log(Status.INFO, "Starting Test Case");
test.log(Status.INFO, "Checking If the URL points to the events page else navigate to that");
if(singleEventsPage.getCurrentUrl() != url)
singleEventsPage.navigateTo(url);
test.log(Status.INFO, "Checking If the Page Sub Title Exists");
Assert.assertEquals(true,singleEventsPage.checkIfElementExists(singleEventsPage.getEventDesc()));
test.log(Status.INFO, "Finished Test Case");
}
#AfterTest(alwaysRun = true)
public void tearDownTest() {
//close browser
driver.close();
driver.quit();
}
#AfterSuite
public void tearDown() {
extent.flush();
}
}
It would be good if you could post your code here. You can try to store them in one class as List, then pass them to another.
I am not sure how your framework is working now. I am thinking of something like this. Please post more code here.
class EventsPageTest {
public List<T> getAllHref() {
// return List
}
}
class SingleEventsPage {
#Test
public void someTest () {
EventsPageTest eventsPageTest = new EventsPageTest();
List<T> hrefs = eventsPageTest.getAllHref();
}
}
Hope this helps
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
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.
I am using Java with Webdriver, and I am having problem with taking screenshots with failed test.
My jUnit test:
....
public class TestGoogleHomePage extends Browser {
....
#Test
public void testLoadGoogle() {
//this test will fail
}
}
My Browser class:
public class Browser {
protected static WebDriver driver;
public Browser() {
driver = new FirefoxDriver();
}
.....
#Rule
public TestWatcher watchman = new TestWatcher() {
#Override
protected void failed(Throwable e, Description description) {
File scrFile = ((TakesScreenshot) driver)
.getScreenshotAs(OutputType.FILE);
try {
FileUtils.copyFile(scrFile, new File(
"C:\\screenshot.png"));
} catch (IOException e1) {
System.out.println("Fail to take screen shot");
}
// this won't work
// driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
}
#Override
protected void succeeded(Description description) {
....
}
};
#After
public void closeBrowser() {
driver.quit();
}
}
The execution of the test will result in the following error message (part of the error message):
org.openqa.selenium.remote.SessionNotFoundException: The FirefoxDriver cannot be used after quit() was called.
Looks like it is complaining about my #After method.
I have tried to change the Browser class to be:
public class Browser {
protected static WebDriver driver;
public Browser() {
driver = new FirefoxDriver();
}
.....
#Rule
public TestWatcher watchman = new TestWatcher() {
#Override
protected void failed(Throwable e, Description description) {
File scrFile = ((TakesScreenshot) driver)
.getScreenshotAs(OutputType.FILE);
try {
FileUtils.copyFile(scrFile, new File(
"C:\\screenshot.png"));
} catch (IOException e1) {
System.out.println("Fail to take screen shot");
}
driver.quit();
}
#Override
protected void succeeded(Description description) {
....
driver.quit();
}
};
}
And the above codes work fine. But I don't want to quit the driver there because there might be something else I want to clean up after each test run, and I want to close the browser in the #After method.
Is there a way I can do that?
The problem is because of the following code:
#After
public void closeBrowser() {
driver.quit();
}
The driver.quit() is attempting to close the browser after EVERY test; and it is getting executed before the call-back methods of your TestWatcher. This is preventing TestWatcher from getting a handle of the driver. Try using a more restrictive life-cycle annotation like #AfterClass or #AfterSuite.