Running Selenium Webdriver tests with TestNG in parallel does not sent correct data to browser - testing

I have two TestNG classes with one test method in each. Each test class has its own #Dataprovider. Each test executes functionality on a web application using Selenium Webdriver. The driver is created for each TestNG class via a factory method and threadlocal so driver should be threadsafe. However when running the tests in parallel using testng.xml the same data is being used across both tests causing one to fail. Here is the code. I'm thinking it might be a problem with the thread safety of the Excel Utility class.
/ DriverFactory
#Listeners(ScreenshotListener.class)
public class DriverFactory {
public final static String URL = "http://localhost/Quotation/Development/index.php";
private static List<WebDriverThread> webDriverThreadPool = Collections.synchronizedList(new ArrayList<WebDriverThread>());
private static ThreadLocal<WebDriverThread> driverThread;
#BeforeClass
public static void instantiateDriverObject() {
System.out.println("Before Class");
driverThread = new ThreadLocal<WebDriverThread>() {
#Override
protected WebDriverThread initialValue() {
WebDriverThread webDriverThread = new WebDriverThread();
webDriverThreadPool.add(webDriverThread);
return webDriverThread;}};
}
#BeforeTest
public void setUp() throws Exception {
System.out.println("Before Test");}
public static WebDriver getDriver() throws Exception {
return driverThread.get().getDriver();}
protected String debug(String methodName) throws Exception {
return methodName + " running on Thread " + Thread.currentThread().getId() +
" with instance as " + this + " and driver " + driverThread.get().getDriver().toString();
}
#AfterSuite
public static void closeDriverObjects() {
System.out.println(webDriverThreadPool.size());
for (WebDriverThread webDriverThread : webDriverThreadPool) {
webDriverThread.quitDriver();}
}
}
// WebDriver thread
public class WebDriverThread {
private WebDriver webdriver;
private DriverType selectedDriverType;
private final DriverType defaultDriverType = FIREFOX;
private final String browser = "CHROME"; //System.getProperty("browser").toUpperCase();
private final String operatingSystem = System.getProperty("os.name").toUpperCase();
private final String systemArchitecture = System.getProperty("os.arch");
private final boolean useRemoteWebDriver = Boolean.getBoolean("remoteDriver");
public WebDriver getDriver() throws Exception {
if (null == webdriver) {
selectedDriverType = determineEffectiveDriverType();
DesiredCapabilities desiredCapabilities = selectedDriverType.getDesiredCapabilities();
instantiateWebDriver(desiredCapabilities);}
return webdriver;}
public void quitDriver() {
if (null != webdriver) {
webdriver.quit();
webdriver = null;
}}
private DriverType determineEffectiveDriverType() {
DriverType driverType = defaultDriverType;
try {
driverType = valueOf(browser);}
catch (IllegalArgumentException ignored) {
System.err.println("Unknown driver specified,defaulting to '" + driverType + "'...");}
catch (NullPointerException ignored) {
System.err.println("No driver specified, defaulting to '" + driverType + "'...");}
return driverType;}
private void instantiateWebDriver(DesiredCapabilities desiredCapabilities) throws MalformedURLException {
System.out.println(" ");
System.out.println("Current Operating System: " + operatingSystem);
System.out.println("Current Architecture: " + systemArchitecture);
System.out.println("Current Browser Selection: " + selectedDriverType);
System.out.println(" ");
if (useRemoteWebDriver) {
URL seleniumGridURL = new URL(System.getProperty("gridURL"));
webdriver = new RemoteWebDriver(seleniumGridURL,desiredCapabilities);
}
else
webdriver = selectedDriverType.getWebDriverObject(desiredCapabilities);
}
}
// ValidLoginTest
public class ValidLoginTest extends DriverFactory{
#BeforeMethod
public void setup() throws Exception {
System.err.println(debug("validLoginTest"));
}
//#Test(dataProvider="ValidLogin" ,dependsOnMethods = { "inValidLoginTest" })
#Test(dataProvider="ValidLogin")
public void validLoginTest(String username, String password, String expectedUserName, String expectedUserEmail) throws Exception {
Login login = new Login();
getDriver().get(URL);
String[] loggedin = login.navigateTo()
.enterUserName(username)
.enterPassword(password)
.andSubmit()
.andCheckLoggedIn();
assertEquals(loggedin[0],expectedUserName);
assertEquals(loggedin[1],expectedUserEmail);
}
#AfterMethod
public void teardown() throws Exception {
JavascriptExecutor jsExecutor = (JavascriptExecutor) getDriver();
jsExecutor.executeScript("sessionStorage.clear();");
}
#DataProvider
public Object[][] ValidLogin() throws Exception{
Object[][] testObjArray = ExcelUtils.getTableArray("SystemTestData.xlsx","ValidLogin");
return (testObjArray);}
}
public class InvalidLoginTest extends DriverFactory{
#BeforeMethod
public void setup() throws Exception {
System.err.println(debug("inValidLoginTest"));
}
#Test(dataProvider="InvalidLogin")
public void inValidLoginTest(String username, String password, String expectedResult) throws Exception {
Login login = new Login();
getDriver().get(URL);
String error = login.navigateTo()
.enterUserName(username)
.enterPassword(password)
.andSubmit()
.andCheckValidation();
assertEquals(error, expectedResult);
login.andClose();
}
#DataProvider
public Object[][] InvalidLogin() throws Exception{
Object[][] testObjArray = ExcelUtils.getTableArray("SystemTestData.xlsx","InvalidLogin");
return (testObjArray);}
}
public class Login {
#FindBy(xpath = "/html/body/nav/div/div[2]/ul/li[3]/a")
private WebElement loginMenu;
#FindBy(name = "user")
private WebElement usernameLocator;
#FindBy(name = "password")
private WebElement passwordLocator;
#FindBy(id = "loginUser")
private WebElement loginUserLocator;
#FindBy(css = "#loginForm > div:nth-child(2) > button:nth-child(2)")
private WebElement closeLocator;
#FindBy(id = "loginError")
private WebElement error;
#FindBy(xpath = "/html/body/nav/div/div[2]/ul/li[3]/ul/li[1]/div/div/div/p[1]/strong")
private WebElement loggedInUserName;
#FindBy(xpath = "/html/body/nav/div/div[2]/ul/li[3]/ul/li[1]/div/div/div/p[2]/strong")
private WebElement loggedInUserEmail;
#FindBy(xpath = "/html/body/nav/div/div[2]/ul/li[3]")
private WebElement account;
private WebDriverWait wait;
public Login() throws Exception {
PageFactory.initElements(DriverFactory.getDriver(), this);
wait = new WebDriverWait(DriverFactory.getDriver(), 30);
System.out.println("Login " + DriverFactory.getDriver().toString());
}
public Login navigateTo() throws Exception {
wait.until(ExpectedConditions.visibilityOf(loginMenu));
loginMenu.click();
return this;
}
public Login enterUserName(String username) {
wait.until(ExpectedConditions.visibilityOf(usernameLocator));
usernameLocator.clear();
for(int i = 0; i < username.length(); i++){
char c = username.charAt(i);
String s = new StringBuilder().append(c).toString();
usernameLocator.sendKeys(s);
}
return this;
}
public Login enterPassword(String password) {
wait.until(ExpectedConditions.visibilityOf(passwordLocator));
passwordLocator.clear();
passwordLocator.sendKeys(password);
return this;
}
public Login andSubmit() {
wait.until(ExpectedConditions.visibilityOf(loginUserLocator));
loginUserLocator.click();
return this;
}
public String[] andCheckLoggedIn() {
String[] actualResult = new String[2];
wait.until(ExpectedConditions.visibilityOf(account));
account.click();
wait.until(ExpectedConditions.visibilityOf(loggedInUserName));
actualResult[0] = loggedInUserName.getText();
actualResult[1] = loggedInUserEmail.getText();
return actualResult;
}
public String andCheckValidation() {
wait.until(ExpectedConditions.visibilityOfAllElements(error));
return error.getText();
}
public void andClose() throws Exception {
wait.until(ExpectedConditions.visibilityOf(closeLocator));
closeLocator.click();
}
}
public class ExcelUtils {
private static XSSFSheet ExcelWSheet;
private static XSSFWorkbook ExcelWBook;
private static XSSFCell Cell;
private static XSSFRow Row;
public static Object[][] getTableArray(String FilePath, String SheetName) throws Exception {
String[][] tabArray = null;
try {
FileInputStream ExcelFile = new FileInputStream(FilePath);
// Access the required test data sheet
ExcelWBook = new XSSFWorkbook(ExcelFile);
ExcelWSheet = ExcelWBook.getSheet(SheetName);
int startRow = 1;
int startCol = 1;
int totalRows = ExcelWSheet.getLastRowNum();
int totalCols = ExcelWSheet.getRow(0).getLastCellNum();
tabArray = new String[totalRows][totalCols -startCol];
for (int row = startRow; row <= totalRows; row++) {
for (int col = startCol; col < totalCols; col++){
tabArray[row - startRow][col - startCol] = getCellData(row, col);
}}}
catch (FileNotFoundException e){
System.out.println("Could not read the Excel sheet");
e.printStackTrace();
}
catch (IOException e){
System.out.println("Could not read the Excel sheet");
e.printStackTrace();
}
return(tabArray);
}
public static String getCellData(int RowNum, int ColNum) throws Exception {
try{
Cell = ExcelWSheet.getRow(RowNum).getCell(ColNum);
if (Cell == null || Cell.getCellTypeEnum() == CellType.BLANK) {
return "";
}else{
String CellData = Cell.getStringCellValue();
return CellData;
}}catch (Exception e){
System.out.println(e.getMessage());
throw (e);
}}}
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd" >
<suite name="Quotation" parallel="classes" thread-count="3" verbose="1" >
<test name="System Test" >
<classes>
<class name="com.quotation.systemtest.tests.ValidLoginTest"/>
<class name="com.quotation.systemtest.tests.InvalidLoginTest"/>
</classes>
</test>
</suite>
[Testng_Result][1]
[1]: https://i.stack.imgur.com/vLx0y.png

Related

How to use Extent Report logs in Page Objects?

I am getting Null Pointer Exception when using the test.log() method into Page Objects.
My Extent Report test is defined in the "#BeforeMethod" at the TestBase class. Hence, I need to access the test.log(); into the Page Object e.g. LoginPage.java. It's works fine at the test case level i.e. LoginPageTest.java
#BeforeMethod
public void beforeMethod(Method method) {
String testMethodName = method.getName();
test = extent.createTest(testMethodName);
String testReslt = method.getName();
test.info(MarkupHelper.createLabel(testReslt, ExtentColor.BLUE));
log.info("**************" + method.getName() + "Started***************");
}
public static void logExtentReport(String str) {
test.log(Status.INFO, str);
}
Below is the LoginPage.java (which is a page-object class)
public class LoginPage {
private WebDriver driver;
private final Logger log = LoggerHelper.getLogger(LoginPage.class);
VerificationHelper verificationHelper;
WaitHelper waitHelper;
#FindBy(css = "#email")
WebElement loginEmail;
#FindBy(css = "#password")
WebElement loginPassword;
#FindBy(css = "#loginbutton")
WebElement loginBtn;
#FindBy(css = "#loginerrormsg")
WebElement authenticationFailureMessage;
#FindBy(css = "#soflow-color")
WebElement userProfileDrpDwn;
#FindBy(xpath = "//option[#value='string:logout']")
WebElement logout;
#FindBy(tagName = "a")
List<WebElement> allLinks;
String urls[] = null;
public LoginPage(WebDriver driver) {
this.driver = driver;
PageFactory.initElements(driver, this);
waitHelper = new WaitHelper(driver);
waitHelper.waitForElement(loginBtn,
ObjectReader.reader.getExplicitWait());
}
public void enterEmailAddress(String emailAddress) {
log.info("entering email address...." + emailAddress);
this.loginEmail.clear();
this.loginEmail.sendKeys(emailAddress);
}
public void enterPassword(String password) {
log.info("entering password...." + password);
this.loginPassword.clear();
this.loginPassword.sendKeys(password);
}
public ProspectorPage clickOnSubmitButton(String isValidCredentials) {
log.info("clicking on submit button...");
loginBtn.click();
if (isValidCredentials.equalsIgnoreCase("yes")) {
return new ProspectorPage(driver);
}
return null;
}
public boolean verifySuccessLoginMsg() {
return new VerificationHelper(driver).isDisplayed(userProfileDrpDwn);
}
public boolean verifyAuthenticationFailureMsg() {
return new
VerificationHelper(driver).isDisplayed(authenticationFailureMessage);
}
public void loginToApplication(String emailAddress, String password,
String isValidCredentials) {
enterEmailAddress(emailAddress);
loginBtn.click();
enterPassword(password);
new TestBase().captureScreen("Login Page_1", driver);
clickOnSubmitButton(isValidCredentials);
}
public void logout() {
userProfileDrpDwn.click();
new TestBase().captureScreen("Logout", driver);
waitHelper.waitForElement(logout,
ObjectReader.reader.getExplicitWait());
logout.click();
log.info("clicked on logout link");
TestBase.logExtentReport("clicked on logout link");
waitHelper.waitForElement(loginBtn,
ObjectReader.reader.getExplicitWait());
}
}
}
As you can see in the LoginPage class, I have used TestBase.logExtentReport() method, which is showing NullPointerException, and I cannot initialize the TestBase reference in the PageObject class. Hence, How can I use the logExtentReport method there?
Helper Class is also getting NPE, even after changing the scope of logger from final to static. Below is the code:
import com.uiFramework.engie.prospector.helper.logger.LoggerHelper;
import com.uiFramework.engie.prospector.testbase.TestBase;
public class VerificationHelper {
private WebDriver driver;
private static Logger log =
LoggerHelper.getLogger(VerificationHelper.class);
public VerificationHelper(WebDriver driver){
this.driver = driver;
}
public boolean isDisplayed(WebElement element){
try{
element.isDisplayed();
log.info("element is Displayed.."+element.getText());
TestBase.logExtentReport("element is
Displayed.."+element.getText());
return true;
}
catch(Exception e){
log.error("element is not Displayed..", e.getCause());
TestBase.logExtentReport("element is not
Displayed.."+e.getMessage());
return false;
}
}
public boolean isNotDisplayed(WebElement element){
try{
element.isDisplayed();
log.info("element is present.."+element.getText());
TestBase.logExtentReport("element is
present.."+element.getText());
return false;
}
catch(Exception e){
log.error("element is not present..");
return true;
}
}
public String readValueFromElement(WebElement element){
if(null == element){
log.info("WebElement is null..");
return null;
}
boolean status = isDisplayed(element);
if(status){
log.info("element text is .."+element.getText());
return element.getText();
}
else{
return null;
}
}
public String getText(WebElement element){
if(null == element){
log.info("WebElement is null..");
return null;
}
boolean status = isDisplayed(element);
if(status){
log.info("element text is .."+element.getText());
return element.getText();
}
else{
return null;
}
}
}
Just change
private final Logger log = LoggerHelper.getLogger(LoginPage.class);
to
private static final Logger log = LoggerHelper.getLogger(LoginPage.class);

How to connect Selenium Cucumber results to TestRail using JUnit

My issue is mainly to know how to populate TestRail results after Cucumber scenarios are run. I'm trying to have the results from my JUnit tests run set on an existing TestRail run. I have the APIClient and APIException as per this project. I then created this JUnit class also copying that same project. Not sure how to proceed now as first time using Cucumber and JUnit. Our project has also a Hooks class and a MainRunner if that helps?
public class Hooks {
public static WebDriver driver;
#Before
public void initializeTest() {
System.out.println("Testing whether it starts before every scenario");
driver = DriverFactory.startDriver();
}
}
import java.io.File;
#RunWith(Cucumber.class)
#CucumberOptions(
features = {"src/test/java/clinical_noting/feature_files/"},
glue = {"clinical_noting.steps", "clinical_noting.runner"},
monochrome = true,
tags = {"#current"},
plugin = {"pretty", "html:target/cucumber",
"json:target/cucumber.json",
"com.cucumber.listener.ExtentCucumberFormatter:target/cucumber-
reports/report.html"}
)
public class MainRunner {
#AfterClass
public static void writeExtentReport() {
Reporter.loadXMLConfig(new File(FileReaderManager.getInstance().getConfigReader().getReportConfigPath()))
;
}
}
Thanks for the help.
Update
Got TestRail to update when running the JUnit tests separately. Still not sure how to do it after the Cucumber scenario is run though? That's how it's working now:
public class JUnitProject {
private static APIClient client = null;
private static Long runId = 3491l;
private static String caseId = "";
private static int FAIL_STATE = 5;
private static int SUCCESS_STATE = 1;
private static String comment = "";
#Rule
public TestName testName = new TestName();
#BeforeClass
public static void setUp() {
//Login to API
client = testRailApiClient();
}
#Before
public void beforeTest() throws NoSuchMethodException {
Method m = JUnitProject.class.getMethod(testName.getMethodName());
if (m.isAnnotationPresent(TestRails.class)) {
TestRails ta = m.getAnnotation(TestRails.class);
caseId = ta.id();
}
}
#TestRails(id = "430605")
#Test
public void validLogin() {
comment = "another comment";
Assert.assertTrue(true);
}
#Rule
public final TestRule watchman = new TestWatcher() {
Map data = new HashMap();
#Override
public Statement apply(Statement base, Description description) {
return super.apply(base, description);
}
#Override
protected void succeeded(Description description) {
data.put("status_id", SUCCESS_STATE);
}
// This method gets invoked if the test fails for any reason:
#Override
protected void failed(Throwable e, Description description) {
data.put("status_id", FAIL_STATE);
}
// This method gets called when the test finishes, regardless of status
// If the test fails, this will be called after the method above
#Override
protected void finished(Description description) {
try {
data.put("comment", comment);
client.sendPost("add_result_for_case/" + runId + "/" + caseId, data);
} catch (IOException e) {
e.printStackTrace();
} catch (APIException e) {
e.printStackTrace();
}
};
};
}
And the annotation
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.METHOD) //on method level
public #interface TestRails {
String id() default "none";
}
Working now. Had to add the scenario param inside the before method and do the TestRail connection from there.
#regressionM1 #TestRails(430605)
Scenario: Verify the user can launch the application
Given I am on the "QA-M1" Clinical Noting application
Then I should be taken to the clinical noting page
And
public class Hooks {
private static APIClient client = null;
private static Long runId = 3491l;
private static String caseId = "";
private static int FAIL_STATE = 5;
private static int SUCCESS_STATE = 1;
private static String SUCCESS_COMMENT = "This test passed with Selenium";
private static String FAILED_COMMENT = "This test failed with Selenium";
#Rule
public TestName testName = new TestName();
public static WebDriver driver;
#Before
public void initializeTest() {
client = testRailApiClient();
System.out.println("Testing whether it starts before every scenario");
driver = DriverFactory.startDriver();
}
#After()
public void tearDown(Scenario scenario) {
String caseIdSplit = "";
for (String s : scenario.getSourceTagNames()) {
if (s.contains("TestRail")) {
caseIdSplit = s.substring(11, 17); // Hardcoded for now as all the ids have 6 characters
System.out.println("Testing whether the browser closes after every scenario" + caseIdSplit);
}
}
caseId = caseIdSplit;
Map data = new HashMap();
if (!scenario.isFailed()) {
data.put("status_id", SUCCESS_STATE);
data.put("comment", SUCCESS_COMMENT);
} else if (scenario.isFailed()) {
data.put("status_id", FAIL_STATE);
data.put("comment", SUCCESS_COMMENT);
}
try {
client.sendPost("add_result_for_case/" + runId + "/" + caseId, data);
} catch (IOException e) {
e.printStackTrace();
} catch (APIException e) {
e.printStackTrace();
}
}
}
Update
Wrote a post on this here

Unable to load chrome/gecko driver after using Cucumber Driver Factory

This is my first question ever asked here, so I hope I ask it the right way:
I'm working on a multimodule maven project to test a software that is still in a development. I've been using Cucumber, Selenium, JUnit for some time and doing online courses to improve my skills. In one of the tutorials was explained how to use Driver Factory and configuration files so I applied it to my project, but after that was unable to run any of the drivers (gecko/chrome/ie). Here is a big part of the code, so I hope someone can help :)
I catch the exception from the DriverFactory.class:
"Unable to load browser: null"
config.properties file has only one line:
browser=chrome
public class DriverFactory {
public static WebDriver driver;
public WebDriver getDriver() {
try {
//Read Config
ReadConfigFile file = new ReadConfigFile();
String browserName = file.getBrowser();
switch (browserName) {
case "firefox":
if (driver == null) {
System.setProperty("webdriver.gecko.driver", Constant.GECKO_DRIVER_DIRECTORY);
FirefoxOptions options = new FirefoxOptions();
options.setCapability("marionette", false);
driver = new FirefoxDriver(options);
driver.manage().window().maximize();
}
break;
case "chrome":
if (driver == null) {
System.setProperty("webdriver.chrome.driver", Constant.CHROME_DRIVER_DIRECTORY);
driver = new ChromeDriver();
driver.manage().window().maximize();
}
break;
/*case "ie":
if (driver == null) {
DesiredCapabilities capabilities = DesiredCapabilities.internetExplorer();
System.setProperty("webdriver.ie.driver", Constant.IE_DRIVER_DIRECTORY);
capabilities.setCapability("ignoreZoomSetting", true);
driver = new InternetExplorerDriver(capabilities);
driver.manage().window().maximize();
}
*/
}
} catch (Exception e) {
System.out.println("Unable to load browser: " + e.getMessage());
} finally {
driver.manage().timeouts().pageLoadTimeout(60, TimeUnit.SECONDS);
}
return driver;
}
public class ReadConfigFile {
protected InputStream input = null;
protected Properties prop = null;
public ReadConfigFile() {
try {
input = ReadConfigFile.class.getClassLoader().getResourceAsStream(Constant.CONFIG_PROPERTIES_DIRECTORY);
prop = new Properties();
prop.load(input);
} catch(IOException e) {
e.printStackTrace();
}
}
public String getBrowser() {
if(prop.getProperty("browser") == null) {
return "";
}
return prop.getProperty("browser");
}
public class Constant {
public final static String CONFIG_PROPERTIES_DIRECTORY = "properties\\config.properties";
public final static String GECKO_DRIVER_DIRECTORY = System.getProperty("user.dir") + "\\src\\test\\resources\\geckodriver.exe";
public final static String CHROME_DRIVER_DIRECTORY = System.getProperty("user.dir") + "\\src\\test\\resources\\chromedriver.exe";
public class CreateCaseSteps extends DriverFactory {
//Background Steps
#Given("^user accesses the login page$")
public void userAccessesTheLoginPage() throws Throwable {
getDriver().get("http://localhost:8080/");
}
#When("^user enters a valid username")
public void userEntersAValidUsername(DataTable table) throws Throwable {
Thread.sleep(3000);
List<List<String>> data = table.raw();
getDriver().findElement(By.xpath("//input[#placeholder='username']")).sendKeys(data.get(0).get(0));
}
#When("^user enters a valid password")
public void userEntersAValidPassword(DataTable table) throws Throwable {
Thread.sleep(3000);
List<List<String>> data = table.raw();
getDriver().findElement(By.xpath("//input[#placeholder='password']")).sendKeys(data.get(0).get(0));
}
#And("^user clicks on the login button$")
public void userClicksOnTheLoginButton() throws Throwable {
getDriver().findElement(By.xpath("//input[#value='Login']")).click();
}
#Then("^user should be taken successfully to the login page$")
public void userShouldBeTakenSuccessfullyToTheLoginPage() throws Throwable {
Thread.sleep(3000);
WebElement logoutMenu = getDriver().findElement(By.xpath("//i[#class='glyphicon glyphicon-user']"));
Assert.assertEquals(true, logoutMenu.isDisplayed());
}

Unable to run multiple feature files together at once

I want to run multiple feature files first the partyfeatures.feature and next policyfeature.feature , but I am unable to run the second one . Below is my runner class .
#RunWith(Cucumber.class)
#CucumberOptions(features = {"src/test/resources"},
glue = {"com.cucumber.bhsibase.party.tests"})
public class TestRunner {
//runner class
public static WebDriver driver ;
private TestNGCucumberRunner testNGCucumberRunner;
#BeforeClass(alwaysRun = true)
public void setUpClass() throws Exception {
ConfigReader reader = new ConfigReader();
driver = new FirefoxDriver() ;
driver.get(reader.readurls("ExpressURL"));
testNGCucumberRunner = new TestNGCucumberRunner(this.getClass());
}
#Test(description = "Runs Cucumber Feature", dataProvider = "features")
public void feature(CucumberFeatureWrapper cucumberFeature) {
testNGCucumberRunner.runCucumber(cucumberFeature.getCucumberFeature());
}
#DataProvider
public Object[][] features() {
return testNGCucumberRunner.provideFeatures();
}
#AfterClass(alwaysRun = true)
public void tearDownClass() throws Exception {
driver.quit();
testNGCucumberRunner.finish();
}
}

Configuring ExtentReports to provide accurate test statuses and screenshot on failure

I am having some difficulty tweaking ExtentReports to provide the desired output.
I have a simple test framework with TestNG, using a TestBase class to do the heavy lifting to keep tests simple. I wish to implement ExtentReports in a simple fashion, using the TestNG ITestResult interface to report Pass, Fail and Unknown.
Here are example tests, 1 pass and 1 deliberate fail:
public class BBCTest extends TestBase{
#Test
public void bbcHomepagePass() throws MalformedURLException {
assertThat(driver.getTitle(), (equalTo("BBC - Home")));
}
#Test
public void bbcHomePageFail() throws MalformedURLException {
assertThat(driver.getTitle(), (equalTo("BBC - Fail")));
}
And here is the relevant section in TestBase:
public class TestBase implements Config {
protected WebDriver driver = null;
private Logger APPLICATION_LOGS = LoggerFactory.getLogger(getClass());
private static ExtentReports extent;
private static ExtentTest test;
private static ITestContext context;
private static String webSessionId;
#BeforeSuite
#Parameters({"env", "browser"})
public void beforeSuite(String env, String browser) {
String f = System.getProperty("user.dir") + "\\test-output\\FabrixExtentReport.html";
ExtentHtmlReporter h = new ExtentHtmlReporter(f);
extent = new ExtentReports();
extent.attachReporter(h);
extent.setSystemInfo("browser: ", browser);
extent.setSystemInfo("env: ", env);
}
#BeforeClass
#Parameters({"env", "browser", "login", "mode"})
public void initialiseTests(String env, String browser, String login, String mode) throws MalformedURLException {
EnvironmentConfiguration.populate(env);
WebDriverConfigBean webDriverConfig = aWebDriverConfig()
.withBrowser(browser)
.withDeploymentEnvironment(env)
.withSeleniumMode(mode);
driver = WebDriverManager.openBrowser(webDriverConfig, getClass());
String baseURL = EnvironmentConfiguration.getBaseURL();
String loginURL = EnvironmentConfiguration.getLoginURL();
APPLICATION_LOGS.debug("Will use baseURL " + baseURL);
switch (login) {
case "true":
visit(baseURL + loginURL);
break;
default:
visit(baseURL);
break;
}
driver.manage().deleteAllCookies();
}
#BeforeMethod
public final void beforeTests(Method method) throws InterruptedException {
test = extent.createTest(method.getName());
try {
waitForPageToLoad();
webSessionId = getWebSessionId();
} catch (NullPointerException e) {
APPLICATION_LOGS.error("could not get SessionID");
}
}
#AfterMethod
public void runAfterTest(ITestResult result) throws IOException {
switch (result.getStatus()) {
case ITestResult.FAILURE:
test.fail(result.getThrowable());
test.fail("Screenshot below: " + test.addScreenCaptureFromPath(takeScreenShot(result.getMethod().getMethodName())));
test.fail("WebSessionId: " + webSessionId);
break;
case ITestResult.SKIP:
test.skip(result.getThrowable());
break;
case ITestResult.SUCCESS:
test.pass("Passed");
break;
default:
break;
}
}
private String takeScreenShot(String methodName) {
String path = System.getProperty("user.dir") + "\\test-output\\" + methodName + ".jpg";
try {
File screenshotFile = ((TakesScreenshot) driver).getScreenshotAs(OutputType.FILE);
FileUtils.copyFile(screenshotFile, new File(path));
} catch (Exception e) {
APPLICATION_LOGS.error("Could not write screenshot" + e);
}
return path;
}
#AfterClass
public void tearDown() {
driver.quit();
}
#AfterSuite()
public void afterSuite() {
extent.flush();
}
Here is the report:
The issues are:
The name of the failed test is not recorded at left hand menu
The screenshot is not displayed despite correctly being taken
It is reporting both a Pass and Unexpected for the passed test
Version 3.0
Most of code is provided by person created this library, i just modified to your needs.
public class TestBase {
private static ExtentReports extent;
private static ExtentTest test;
#BeforeSuite
public void runBeforeEverything() {
String f = System.getProperty("user.dir")+ "/test-output/MyExtentReport.html";
ExtentHtmlReporter h = new ExtentHtmlReporter(f);
extent = new ExtentReports();
extent.attachReporter(h);
}
#BeforeMethod
public void runBeforeTest(Method method) {
test = extent.createTest(method.getName());
}
#AfterMethod
public void runAfterTest(ITestResult result) {
switch (result.getStatus()) {
case ITestResult.FAILURE:
test.fail(result.getThrowable());
test.fail("Screenshot below: " + test.addScreenCaptureFromPath(takeScreenShot(result.getMethod().getMethodName())));
break;
case ITestResult.SKIP:
test.skip(result.getThrowable());
break;
case ITestResult.SUCCESS:
test.pass("Passed");
break;
default:
break;
}
extent.flush();
}
protected String takeScreenShot(String methodName) {
String path = "./screenshots/" + methodName + ".png";
try {
File screenshotFile = ((TakesScreenshot)driver).getScreenshotAs(OutputType.FILE);
FileUtils.copyFile(screenshotFile, new File(path));
} catch (Exception e) {
APPLICATION_LOGS.error("Could not write screenshot" + e);
}
return path;
}
}
You need several changes to make. Instantiate the ExtentReport & add configuration information in any of the configuration methods except BeforeClass.
#BeforeTest
#Parameters({"env", "browser"})
public void initialiseTests(String env, String browser, String emulatorMode, String mode) {
EnvironmentConfiguration.populate(env);
WebDriverConfigBean webDriverConfig = aWebDriverConfig()
.withBrowser(browser)
.withDeploymentEnvironment(env)
.withSeleniumMode(mode);
driver = WebDriverManager.openBrowser(webDriverConfig, getClass());
APPLICATION_LOGS.debug("Will use baseURL " + EnvironmentConfiguration.getBaseURL());
try {
visit(EnvironmentConfiguration.getBaseURL());
} catch (MalformedURLException e) {
e.printStackTrace();
}
driver.manage().deleteAllCookies();
}
Initailize test = extent.startTest(testName); in the #BeforeMethod section.
#BeforeMethod
public void beforeM(Method m) {
test = extent.startTest(m.getName());
}
And, you may call extent.endTest(test); in the #AfterTest method.
#AfterTest
public void afterTests() {
extent.endTest(test);
extent.close();
}
}
And, to log your step info call test.log(LogStatus, "your info to show"); with appropirate status.