I am currently capturing screenshots on failure and success in TestNG by way of overriding the TestListenerAdapter methods onTestFailure, and onTestSuccess respectively. In order to do this you need to specify which driver you want to take a screenshot of.
My question: Is there a good way to capture screenshots when running tests in parallel on the method level?
In order to run tests in parallel, each individual test needs a unique driver instance. So, at any given time you have x number of driver instances running. When it comes time to capture a screenshot, how do you determine which driver to use?
Code excerpts below:
public class OnFailureListener extends TestListenerAdapter {
#Override
public void onTestFailure(ITestResult tr) {
Screenshots.captureScreenshot(tr);
super.onTestFailure(tr);
}
--
public static void captureScreenshot(ITestResult tr) {
WebDriver driver = TestClass.driver;
if (driver instanceof TakesScreenshot) {
String filename = "path/to/screenshot/file";
try {
File scrFile = ((TakesScreenshot)driver).getScreenshotAs(OutputType.FILE);
FileUtils.copyFile(scrFile, new File(filename));
} catch (IOException e) { e.printStackTrace(); }
}
If you create a base test class with access to the driver, then that driver will always be the correct driver
The following will achieve this;
All test classes must extend a simple base test class;
public asbtract baseTestCase() {
private WebDriver driver;
public WebDriver getDriver() {
return driver;
}
#BeforeMethod
public void createDriver() {
driver=XXXXDriver();
}
#AfterMethod
public void tearDownDriver() {
if (driver != null){
try{
driver.quit();
}
catch (WebDriverException e) {
System.out.println("***** CAUGHT EXCEPTION IN DRIVER TEARDOWN *****");
System.out.println(e);
}
}
}
In your listener, you need to access the base class:
public class ScreenshotListener extends TestListenerAdapter {
#Override
public void onTestFailure(ITestResult result){
Object currentClass = result.getInstance();
WebDriver webDriver = ((BaseTest) currentClass).getDriver();
if (webDriver != null){
File f = ((TakesScreenshot)webDriver).getScreenshotAs(OutputType.FILE);
//etc.
}
}
}
Related
#Aftertest
#AfterSuite
#AfterClass Nothing is helpful in my case when we talk about sending the latest reports in the email.
#AfterSuite
public void statusupdate() throws Exception
{
SendMail.execute();
}
This is what I am doing and every time I am getting an older version of my emailable-report.html as I am struggling with JAVA as well so hopefully someone can help me understanding what is wrong here. My assumption is I am sending the email before the fresh report is generated but have no clue what to do next. Thanks for the patience and your replies.
Best you can do is to help yourself with Listeners for reports, instead of an #afterXxxx method.
So you can do something like:
import org.testng.annotations.Listeners;
#Listeners(TestListener.class)
public class MyTestClass {
#Test
public void myTest {
doTest();
}
}
Where your Listener has your SendMail action in the onFinish method:
import org.testng.ITestContext;
import org.testng.ITestListener;
import org.testng.ITestResult;
public class TestListener implements ITestListener {
#Override
public void onTestStart(ITestResult result) {
}
#Override
public void onTestSuccess(ITestResult result) {
}
#Override
public void onTestFailure(ITestResult result) {
}
#Override
public void onTestSkipped(ITestResult result) {
}
#Override
public void onTestFailedButWithinSuccessPercentage(ITestResult result) {
}
#Override
public void onStart(ITestContext context) {
}
#Override
public void onFinish(ITestContext context) {
SendMail.execute();
}
}
I hope this does what you need, if not let me know.
Finally I am able to get the latest .html report by implementing extent reports and TestNG listeners in my framework. I am using 7.0 TestNG and its limitation is that it does not update the emailable-report.html so to overcome this problem you will have to implement extent reports where you will always get the latest .html fancy report which you can send through email in onFinish method of your listener class. But before jumping in you have to understand listeners and extent reports rest is given below. Also thanks #rodrigo for giving me a direction :)
public class TestClass{
WebDriver driver=null;
public ExtentHtmlReporter htmlReporter;
public ExtentReports extent;
public ExtentTest test;
public static String getScreenshot(WebDriver driver, String screenshotName) throws IOException {
String dateName = new SimpleDateFormat("yyyyMMddhhmmss").format(new Date(0));
TakesScreenshot ts = (TakesScreenshot) driver;
File source = ts.getScreenshotAs(OutputType.FILE);
// after execution, you could see a folder "FailedTestsScreenshots" under src folder
String destination = System.getProperty("user.dir") + "/Screenshots/" + screenshotName + dateName + ".png";
File finalDestination = new File(destination);
FileUtils.copyFile(source, finalDestination);
return destination;
}
#BeforeTest()
#Parameters("browser")
public void setup(String browsername) {
if(browsername.equalsIgnoreCase("chrome"))
{
WebDriverManager.chromedriver().setup();
driver=new ChromeDriver();
}
else if(browsername.equalsIgnoreCase("firefox"))
{
WebDriverManager.firefoxdriver().setup();
driver=new FirefoxDriver();
}
htmlReporter = new ExtentHtmlReporter(System.getProperty("user.dir")+"\\test-output\\myReport.html");
htmlReporter.config().setDocumentTitle("Automation Report"); // Tile of report
htmlReporter.config().setReportName("Functional Testing"); // Name of the report
htmlReporter.config().setTheme(Theme.DARK);
extent = new ExtentReports();
extent.attachReporter(htmlReporter);
// Passing General information
extent.setSystemInfo("Host name", "NerdBox");
extent.setSystemInfo("Environemnt", "QA");
extent.setSystemInfo("user", "AB");
}
#Test(priority=1,enabled=true)
public void SubmitQuestions() throws Exception {
driver.manage().window().maximize();
driver.get("https://com/questions");
driver.findElement(By.xpath("/html/body/div/div/div[3]/div/div/div[1]/div/div/div[2]/div")).click();
}
#AfterMethod(alwaysRun=true)
public void end(ITestResult result) throws IOException
{
test= extent.createTest("The Test is "+result.getName());
if (result.getStatus() == ITestResult.FAILURE) {
test.log(Status.FAIL, "TEST CASE FAILED IS " + result.getName()); // to add name in extent report
test.log(Status.FAIL, "TEST CASE FAILED IS " + result.getThrowable()); // to add error/exception in extent report
String screenshotPath = NerdboxJobSubmit.getScreenshot(driver, result.getName());
test.addScreenCaptureFromPath(screenshotPath);// adding screen shot
} else if (result.getStatus() == ITestResult.SKIP) {
test.log(Status.SKIP, "Test Case SKIPPED IS " + result.getName());
}
else if (result.getStatus() == ITestResult.SUCCESS) {
test.log(Status.PASS, "Test Case PASSED IS " + result.getName());
}
}
#AfterTest(alwaysRun=true)
public void flush() throws Exception
{
System.out.println("After test");
extent.flush();
driver.quit();
}
This is My setup class:
public class SetupClass {
//AppiumDriver<MobileElement> driver;
AndroidDriver<MobileElement> d;
public Properties prop =null;
public File file;
public FileInputStream fis;
#Parameters(value ="Android")
#BeforeSuite
public void setup(String Android) throws IOException, Exception{
LoadPropertiesFile();
DesiredCapabilities caps = new DesiredCapabilities();
/*caps.setCapability("plateformName", "Android");
caps.setCapability(CapabilityType.PLATFORM_NAME, "Android");*/
if (Android.equalsIgnoreCase("Moto_g4_Plus")) {
caps.setCapability(MobileCapabilityType.PLATFORM_NAME, "Android");
caps.setCapability(MobileCapabilityType.PLATFORM_VERSION, "7.0");
caps.setCapability(MobileCapabilityType.UDID, "ZY223WZSQ9");
caps.setCapability(MobileCapabilityType.DEVICE_NAME, "Moto G4 Plus");
}
caps.setCapability("app", "C:\\Users\\amarjeet.sharma\\eclipse-workspace\\com.asm.app\\src\\test\\resources\\app\\asmVisit.apk");
caps.setCapability("appPackage", "com.sumasoft.net.asmscheduler");
caps.setCapability("appActivity", "md5f32326382a711c73d2de951d70f3bd5e.MainActivity");
caps.setCapability("autoGrantPermissions", true);
URL url;
try {
url = new URL("http://127.0.0.1:4723/wd/hub");
//driver = new AppiumDriver<MobileElement>(url, caps);
d = new AndroidDriver<MobileElement>(url, caps);
Thread.sleep(5000);
} catch (MalformedURLException e) {
// TODO Auto-generated catch block
System.out.println("Cause is:" +e.getCause());
System.out.println("Message is:" +e.getMessage());
e.printStackTrace();
}
}
public void LoadPropertiesFile() throws IOException {
prop=new Properties();
file =new File(System.getProperty("user.dir")+"/src/main/resources/config.properties");
fis=new FileInputStream(file);
prop.load(fis);
//System.out.println(prop.getProperty("userId"));
}
//#AfterTest
public void TearDown() throws IOException{
System.out.println("Quit");
d.quit();
}
}
This is My LoginTest
public class LoginTest extends SetupClass{
#Test(priority = 1)
public void login() throws Exception {
LoginPage lp = new LoginPage(d);
//System.out.println(prop.getProperty("userId"));
lp.userName(prop.getProperty("userId"));
Thread.sleep(500);
lp.password(prop.getProperty("Passwd"));
Thread.sleep(500);
lp.loginButton();
}
}
And this is my create new journey class
public class AddJourneyTest extends SetupClass{
#Test(priority=2)
public void AddNewJourney() throws Exception {
AddjourneyPage addobj = new AddjourneyPage(d);
addobj.ClicktoAdd();
addobj.SelectFromToDate();
addobj.SelectState();
addobj.SelectCity();
addobj.ClickonSubmit();
}
}
I am getting NullPointerException for AddJourney class
I think when I run it as TestNG then the driver gets initiated for the LoginTest and holds the control. So that AddJourney class does not get driver initiated and hence getting NullPointerException.
I am using Appium Server, Java + Selenium + TestNG for the Android Application automation on Windows system with physical android device.
Maybe I am wrong. But I am not getting solution over it. Please help.
Below is the code am trying to execute
Not sure why am getting [TestNG] No tests found. Nothing was run
if I remove the before class annotation method, it executes but fails due the dependency
public class TestNG_Practice3 {
static WebDriver driver ;
String url = "https://in.linkedin.com/";
#BeforeClass(description = "To open the browser")
public void openBrowser()
{ driver = new FirefoxDriver();
driver.get(url);
System.out.println("Browser got open");
}
#Test (dependsOnMethods ="openBrowser",description = "To signin")
public void login()
{
driver.manage().timeouts().implicitlyWait(2000, TimeUnit.SECONDS);
WebElement signin = driver.findElement(By.id("login-email"));
Assert.assertTrue(signin.isDisplayed());
WebElement password = driver.findElement(By.id("login-password"));
WebElement signinbutton = driver.findElement(By.id("login-submit"));
signin.sendKeys("xyz");
password.sendKeys("abc");
signinbutton.click();
Assert.assertTrue(driver.getCurrentUrl().contains("feed/"));
}
#Test(dependsOnMethods = "login")
public void logout()
{
WebElement meDropdown = driver.findElement(By.xpath("//*[#id=\"nav-settings__dropdown-trigger\"]/div/span[2]/li-icon/svg"));
meDropdown.click();
WebElement logout = driver.findElement(By.id("ember545"));
logout.click();
}
#AfterClass
public void closebrowser()
{
driver.quit();
}
}
Step-1 : Basic trial with Project Build,
public class TestNG_Demo {
#BeforeClass
public void openbrowser()
{
System.out.println("Browser got open");
}
#Test
public void testbrowser()
{
System.out.println("Test execution");
}
#AfterClass
public void closebrowser()
{
System.out.println("Browser got close");
}
}
So you will be have idea, Your project build get successful execution.
If you have maven project and Build did not get pass, you will be have trigger what is causing from maven build dependency.
Update
Step-2 : After tracing first trial
public class TestNG_Demo {
#Test
public void testbrowser()
{
WebDriver driver = new FirefoxDriver();
driver.get("http://google.com");
}
}
Remove dependsOnMethods ="openBrowser" because it's not a test method and will be execute before test without it
I have a testcase that will invoke the driver as a non static variable. I also have added screenshot listener in my test case. When the test case fails The control is automatically sent to the screenshot listener, however since my driver is a NON-STATIC variable it could not be accessed in the screenshot listener. So I get nullpointer exception.
To solve this I created a simple base test class with help of stackoverflow like below and extend it in each testclass
public asbtract baseTest() {
private WebDriver driver;
public WebDriver getDriver() {
return driver;
}
#BeforeMethod
public void createDriver() {
Webdriver driver=XXXXDriver();
}
#AfterMethod
public void tearDownDriver() {
if (driver != null)
{
try
{
driver.quit();
}
catch (WebDriverException e) {
System.out.println("***** CAUGHT EXCEPTION IN DRIVER TEARDOWN *****");
System.out.println(e);
}
}
}
In my listener, I access the base class as follows
public class ScreenshotListener extends TestListenerAdapter {
#Override
public void onTestFailure(ITestResult result)
{
Object currentClass = result.getInstance();
WebDriver webDriver = ((baseTest) currentClass).getDriver();
if (webDriver != null)
{
File f = ((TakesScreenshot) webDriver).getScreenshotAs(OutputType.FILE);
//etc.
}
}
My test class looks like this
#Listeners(value = FailureReport.class)
public class LoginTest extends baseTest{
Login login = new Login(getDriver());
#Test(description = "Verify Expand the Menu", priority = 0)
public void navigateloginpage() {
login.expandMenuScreenLogin();
login.navigateLoginPage();
}
#Test(description = "User login Sucessfully", priority = 1)
public void successLogin() {
login.login();
}
When I run this it gives me the error
org.testng.TestNGException:
Cannot find class in classpath: com.fbf.automation.tests.LoginTest
at org.testng.xml.XmlClass.loadClass(XmlClass.java:81)
at org.testng.xml.XmlClass.init(XmlClass.java:73)
at org.testng.xml.XmlClass.<init>(XmlClass.java:59)
at org.testng.xml.TestNGContentHandler.startElement(TestNGContentHandler.java:548)
at com.sun.org.apache.xerces.internal.parsers.AbstractSAXParser.startElement(AbstractSAXParser.java:509)
at com.sun.org.apache.xerces.internal.impl.dtd.XMLDTDValidator.startElement(XMLDTDValidator.java:745)
at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl.scanStartElement(XMLDocumentFragmentScannerImpl.java:1359)
at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl$FragmentContentDriver.next(XMLDocumentFragmentScannerImpl.java:2784)
at com.sun.org.apache.xerces.internal.impl.XMLDocumentScannerImpl.next(XMLDocumentScannerImpl.java:602)
at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl.scanDocument(XMLDocumentFragmentScannerImpl.java:505)
at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(XML11Configuration.java:841)
at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(XML11Configuration.java:770)
at com.sun.org.apache.xerces.internal.parsers.XMLParser.parse(XMLParser.java:141)
at com.sun.org.apache.xerces.internal.parsers.AbstractSAXParser.parse(AbstractSAXParser.java:1213)
at com.sun.org.apache.xerces.internal.jaxp.SAXParserImpl$JAXPSAXParser.parse(SAXParserImpl.java:643)
at com.sun.org.apache.xerces.internal.jaxp.SAXParserImpl.parse(SAXParserImpl.java:327)
at javax.xml.parsers.SAXParser.parse(SAXParser.java:195)
at org.testng.xml.XMLParser.parse(XMLParser.java:38)
at org.testng.xml.SuiteXmlParser.parse(SuiteXmlParser.java:16)
at org.testng.xml.SuiteXmlParser.parse(SuiteXmlParser.java:9)
at org.testng.xml.Parser.parse(Parser.java:172)
at org.testng.TestNG.initializeSuitesAndJarFile(TestNG.java:302)
at org.testng.IDEARemoteTestNG.run(IDEARemoteTestNG.java:45)
at org.testng.RemoteTestNGStarter.main(RemoteTestNGStarter.java:123)
Process finished with exit code 0
Later when I changed my test class as follows it ran correctly
#Listeners(value = FailureReport.class)
public class LoginTest extends baseTest{
Login login;
#Test(description = "Verify Expand the Menu", priority = 0)
public void navigateloginpage() {
login = new Login(getDriver());
login.expandMenuScreenLogin();
login.navigateLoginPage();
}
#Test(description = "User login Sucessfully", priority = 1)
public void successLogin() {
login.login();
}
Isn't it possible to declare the code
login = new Login(getDriver());
outside #test method rather than writing it inside the #test method. Or are there anyother alternative ways I can call the above code
You may create Login object inside #BeforeClass method
#BeforeClass(alwaysRun = true)
public void setUp() throws Exception {
login = new Login(getDriver());
}
Currently, I am using Selenium TestNG and Extent Reports framework for reporting. I am facing a problem where all are my test cases are showing Pass and not showing Fail.
#BeforeTest
public void setUp()
{
//where we need to generate the report
htmlReporter = new ExtentHtmlReporter(System.getProperty("user.dir")+"/test-output/MyReport.html");
extent = new ExtentReports();
extent.attachReporter(htmlReporter);
// Set our document title, theme etc..
htmlReporter.config().setDocumentTitle("My Test Report");
htmlReporter.config().setReportName("Test Report");
htmlReporter.config().setTestViewChartLocation(ChartLocation.TOP);
htmlReporter.config().setTheme(Theme.DARK);
}
#Test
public void On_Page_IM() throws InterruptedException {
test = extent.createTest("On_Page_IM");
wd.manage().window().maximize();
Thread.sleep(10000);
test.log(Status.INFO,"On page intent media: Show");
}
#AfterSuite
public void tearDown()
{
extent.flush();
wd.quit();
}
After Added this code its solved
#AfterMethod
public void getResult(ITestResult result)
{
if(result.getStatus()==ITestResult.FAILURE)
{
test.log(Status.FAIL, result.getThrowable());
}
// extent.endTest(test);
}
Just add below code at end of ur tests
#AfterMethod
public void AfterMethod(ITestResult result) {
if (result.getStatus() == ITestResult.FAILURE) {
test.log(Status.FAIL,
MarkupHelper.createLabel(result.getName()
+ " Test case FAILED due to below issues:",
ExtentColor.RED));
test.fail(result.getThrowable());
} else if (result.getStatus() == ITestResult.SUCCESS) {
test.log(
Status.PASS,
MarkupHelper.createLabel(result.getName()
+ " Test Case PASSED", ExtentColor.GREEN));
} else {
test.log(
Status.SKIP,
MarkupHelper.createLabel(result.getName()
+ " Test Case SKIPPED", ExtentColor.ORANGE));
test.skip(result.getThrowable());
}
}
#AfterTest
public void AfterTest() {
extent.flush();
}
Selenium WebDriver 4 + JUnit 5 + Extent Reports 5 (JDK 17)
I used this and this to write the modern JUnit 5 solution, since most examples are for the older TestNG. ExtentHtmlReporter has also been deprecated.
abstract class BaseTest {
private static ExtentReports extent; // Prevent overwriting reports per test
protected WebDriver driver; // WebDriver should never be static
#RegisterExtension
protected AfterEachExtension afterEachExtension = new AfterEachExtension();
#BeforeAll
public static void beforeAll() {
extent = new ExtentReports();
spark = new ExtentSparkReporter("target/spark-reports/index.html");
extent.attachReporter(spark);
spark.config(
ExtentSparkReporterConfig.builder()
.theme(Theme.DARK)
.documentTitle("Extent Reports")
.build()
);
}
#BeforeEach
public void beforeEach() {
driver = // Initialise driver
}
#AfterEach
public void afterEach() {
AfterEachExtension.setExtent(extent);
afterEachExtension.setDriver(driver);
}
#AfterAll
public static void afterAll() {
extent.flush();
}
}
import com.aventstack.extentreports.Status;
// Other imports
public class AfterEachExtension implements AfterEachCallback {
private static ExtentReports extent;
private WebDriver driver;
public static void setExtent(ExtentReports extent) {
AfterEachExtension.extent = extent;
}
public void setDriver(WebDriver driver) {
this.driver = driver;
}
#Override
public void afterEach(ExtensionContext context) throws Exception {
var test = extent.createTest(context.getDisplayName());
context.getExecutionException().ifPresent(value -> test.log(Status.FAIL, value));
driver.quit();
}
}