1

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.

2
  • 1
    Add e.printStackTrace() in first catch block in 'onTestFailure(' .Most probably driver is null Commented Dec 14, 2020 at 10:10
  • Sorry forgot to mention, Yes it is null. - Updated the question. Commented Dec 14, 2020 at 10:14

3 Answers 3

1

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.

Sign up to request clarification or add additional context in comments.

Comments

0

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

Comments

0

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

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.