Search code examples
javaseleniumtestngscreenshotextentreports

Naming a screenshot for each step with a unique name at runtime


I am working on Selenium WebDriver with Java for automation and TestNG is my framework. I am running Login Test in which i log each step in the Extent report. I have a function for each step and for each step, i am attaching a screenshot.

I am unsure on how to name each screenshot with a unique descriptive name. I tried getting the current method(step) name but it seems like I need to create an anonymous class eveytime and eveywhere to get the current running method name as per the below code.

String name = new Object(){}.getClass().getEnclosingMethod().getName();

Here is my code.

@Test(priority = 0, testName="Verify Login")
public void login() throws Exception {
    lp = new LoginPage(driver, test);
    tm = new TabMenu(driver, test);
    driver.get(Constants.url);
    lp.verifyLoginPageLogo();
    lp.setUserName("admin");
    lp.setPassword("admin");
    lp.clickLoginBtn();
    tm.isCurrentTab("Dashboard");
}

public void verifyLoginPageLogo() throws IOException {
    String name = new Object(){}.getClass().getEnclosingMethod().getName();
    Assert.assertTrue(loginLogo.isDisplayed());
    test.log(LogStatus.PASS, "Logo is displayed", Screenshots.takeScreenshot(driver, name, test));      
}

public static String takeScreenshot(WebDriver driver, String name, ExtentTest test) throws IOException {

    String directory = "C:\\Users\\JACK\\Documents\\eclipse-workspace\\OrangeHRM\\Screenshots\\";
    String fileName = name + ".png";
    File destFile = new File(directory + fileName);
    TakesScreenshot ss = (TakesScreenshot) driver;
    File sourceFile = ss.getScreenshotAs(OutputType.FILE);
    FileUtils.copyFile(sourceFile, destFile);
    String imgPath = test.addScreenCapture(directory+fileName);
    return imgPath;
}

Is there any other way to do this?


Solution

  • Sure, there are lots of options:

    1. If you don't care what the filename is, you could use File.createTempFile() or just UUID.randomUUID() to get a name. That wouldn't be semantically meaningful, but it would get you unique filenames easily enough.
    2. If you don't need multiple filenames per test, you could use the test name. In JUnit you could use the Test-Name Rule. For TestNG, there seem to be other solutions using @Before methods. Even if you do need multiples, you could combine test-name-rule with a sequence number.
    3. You could just use a sequence number, like an integer in a static variable / singleton. It's not very sophisticated, but it would still work. ;)
    4. Java doesn't make it particularly easy to get the current method name, so you'd either have to do your anonymous object or get a stack trace, either way is a bit painful and not particularly performant.

    Using #2 as an example, you could modify your code do something like:

    @Test(priority = 0, testName="Verify Login")
    public void login(ITestContext context) throws Exception {
        lp = new LoginPage(driver, test);
        tm = new TabMenu(driver, test);
        driver.get(Constants.url);
        lp.verifyLoginPageLogo(context.getName(), 0);
        lp.setUserName("admin");
        lp.setPassword("admin");
        lp.clickLoginBtn();
        tm.isCurrentTab("Dashboard", context.getName(), 1);
    }
    
    public void verifyLoginPageLogo(String testName, int stepName) throws IOException {
        String name = new Object(){}.getClass().getEnclosingMethod().getName();
        Assert.assertTrue(loginLogo.isDisplayed());
        test.log(LogStatus.PASS, "Logo is displayed", Screenshots.takeScreenshot(driver, testName, stepName, test));      
    }
    
    public static String takeScreenshot(WebDriver driver, String testName, int stepName, ExtentTest test) throws IOException {
        String fileName = testName + "_" + stepName ".png";
        // the rest of your screenshot code
    }
    

    You could even replace the step number with another semantically meaningful word, "loginLogo", "dashboardTab" if that's helpful