How to capture a screenshot after each step in tests with JAVA and Cucumber?

ⅰ亾dé卋堺 提交于 2019-11-28 00:31:29

Can this post help you?

Embedding screenshots in Cucumber JVM

Here is the Answer to your Question:

  1. Lets assume your methods are as follows:

    @Given("^Open$")
    public void Open() throws Throwable 
    {
        //your code
    }
    
    @When("^I$")
    public void I(String uname, String pass) throws Throwable 
    {
        //your code
    }
    
    @Then("^User$")
    public void User() throws Throwable 
    {
        //your code
    }
    
  2. You can write a library to take screenshots like:

    public static void screenshot(WebDriver driver, long ms)
    {
    
    try {
        TakesScreenshot ts = (TakesScreenshot) driver;
        File source = ts.getScreenshotAs(OutputType.FILE);
        FileUtils.copyFile(source, new File("./ScreenShots/"+ms+"Facebook.png"));
        System.out.println("ScreenShot Taken");
    } 
    catch (Exception e) 
    {
        System.out.println("Exception while taking ScreenShot "+e.getMessage());
    }
    
    
    }
    
  3. Now you can easily call the library after every method to take the screenshot as follows:

    @Given("^Open$")
    public void Open() throws Throwable 
    {
        //your code
        Utility.screenshot(driver, System.currentTimeMillis());
    }
    
    @When("^I$")
    public void I(String uname, String pass) throws Throwable 
    {
        //your code
        Utility.screenshot(driver, System.currentTimeMillis());
    }
    
    @Then("^User$")
    public void User() throws Throwable 
    {
        //your code
        Utility.screenshot(driver, System.currentTimeMillis());
    }
    

Let me know if this Answers your Question.

Solved this using Aspects. Was pretty tricky, note the annotation:

@After("call(public * cucumber.runtime.StepDefinitionMatch.runStep(..)) && within(cucumber.runtime.Runtime)")

Below is the full code, written by Viviana Cattenazzi.

pom.xml

 <dependencies>
         <dependency>
             <groupId>org.aspectj</groupId>
             <artifactId>aspectjweaver</artifactId>
             <version>1.8.9</version>
         </dependency>
         <dependency>
             <groupId>org.aspectj</groupId>
             <artifactId>aspectjrt</artifactId>
             <version>1.8.9</version>
         </dependency>
         <dependency>
             <groupId>org.aspectj</groupId>
             <artifactId>aspectjtools</artifactId>
             <version>1.8.9</version>
         </dependency>
         <dependency>
             <groupId>info.cukes</groupId>
             <artifactId>cucumber-core</artifactId>
             <version>1.2.4</version>
         </dependency>
     </dependencies>

......

         <plugin>
             <groupId>org.codehaus.mojo</groupId>
             <artifactId>aspectj-maven-plugin</artifactId>
             <version>1.10</version>
             <configuration>
                 <weaveDependencies>
                     <weaveDependency>
                         <groupId>info.cukes</groupId>
                         <artifactId>cucumber-core</artifactId>
                     </weaveDependency>
                 </weaveDependencies>
                 <showWeaveInfo>true</showWeaveInfo>
                 <source>1.8</source>
                 <target>1.8</target>
                 <complianceLevel>1.8</complianceLevel>
             </configuration>
             <executions>
                 <execution>
                     <phase>process-test-classes</phase>
                     <goals>
                         <goal>compile</goal>
                         <goal>test-compile</goal>
                     </goals>
                 </execution>
             </executions>
         </plugin>

.......

StepsInterceptor.java

@Aspect
 public class StepsInterceptor {


     @After("call(public * cucumber.runtime.StepDefinitionMatch.runStep(..)) && within(cucumber.runtime.Runtime)")
     public void beforeRunningStep(JoinPoint thisJoinPoint) throws Exception {

         try {
             StepDefinitionMatch stepDefinitionMatch = (StepDefinitionMatch) thisJoinPoint.getTarget();
             Step step = (Step) retrievePrivateField(stepDefinitionMatch, "step");
             String stepName = step.getKeyword().trim();

             if ("Given".equals(stepName) || "When".equals(stepName)) {
                 Object theRealStepDef = extractJavaStepDefinition(stepDefinitionMatch);
                // take screen shot here
             }
         } catch (ClassCastException exc) { ....
}
}
}

I don't think it would be possible until following merge request is accepted and merged. if you are really interested you can merge it locally and have your own custom Jar.

https://github.com/cucumber/cucumber-jvm/pull/838

This might not be what you asked but this can help others too! (I haven't used Cucumber though)

Here is my code to take a screen shot and add it to a PDF file (If you want to do something else with it that you can).

Just you have to call screenshotPDF(webDriver, testName) method whenever you want!

package com.helper;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;

import org.apache.commons.io.FileUtils;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDPage;
import org.apache.pdfbox.pdmodel.PDPageContentStream;
import org.apache.pdfbox.pdmodel.PDPageContentStream.AppendMode;
import org.apache.pdfbox.pdmodel.font.PDFont;
import org.apache.pdfbox.pdmodel.font.PDType1Font;
import org.apache.pdfbox.pdmodel.graphics.image.PDImageXObject;
import org.openqa.selenium.Capabilities;
import org.openqa.selenium.OutputType;
import org.openqa.selenium.TakesScreenshot;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebDriverException;
import org.openqa.selenium.remote.RemoteWebDriver;
import org.openqa.selenium.remote.server.handler.WebDriverHandler;
import org.testng.annotations.Test;

public class ScreenshotPDF {

    @SuppressWarnings("deprecation")
    @Test
    //public static void screenshotPDF() {
    public static void screenshotPDF(WebDriver webDriver, String testName){

                {

            PDDocument doc = null;
            boolean isNewFile = false;

            Date date = new Date();
            SimpleDateFormat sdf = new SimpleDateFormat("MM/dd/yyyy h:mm:ss a");
            String timeStemp = sdf.format(date);


            try {
                try {
                    doc = PDDocument.load(new File(
                            "C:/Users/Documents/sample.pdf"));
                } catch (FileNotFoundException f) {
                    doc = new PDDocument();
                    PDPage p = new PDPage();
                    doc.addPage(p);
                    isNewFile = true;
                }

                File screenshot = ((TakesScreenshot) webDriver)
                        .getScreenshotAs(OutputType.FILE);

                Integer numberP = doc.getNumberOfPages();
                PDPage blankPage = new PDPage();
                PDPage page;
                if (!isNewFile) {
                    doc.addPage(blankPage);
                    page = doc.getPage(numberP);
                } else { 
                    page = doc.getPage(numberP - 1);
                }
                PDImageXObject pdImage = PDImageXObject
                        .createFromFileByContent(screenshot, doc);
                PDPageContentStream contentStream = new PDPageContentStream(
                        doc, page, AppendMode.APPEND, true);
                PDFont font = PDType1Font.HELVETICA_BOLD;
                contentStream.beginText();
                contentStream.setFont(font, 12);
                contentStream.moveTextPositionByAmount(100, 600);
                contentStream.drawString(testName+"  "+timeStemp);
                contentStream.endText();

                float scale = 0.4f;

                Capabilities cap = ((RemoteWebDriver) webDriver).getCapabilities();
                String browserName = cap.getBrowserName().toLowerCase();
                if (browserName.contains("explorer"))
                    scale = 0.4f;

                contentStream.drawImage(pdImage, 50, 210, pdImage.getWidth() * scale, pdImage.getHeight() * scale);
                contentStream.close();
                contentStream.close();
                doc.save("C:/Users/Documents/sample.pdf");
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                if (doc != null) {
                    try {
                        doc.close();
                    } catch (IOException e) {

                        e.printStackTrace();
                    }
                }
            }
        }

    }

}

There is no afterStep annotation in cucumber java. So you cann't do it in straight forward. You can do it in another way as mentioned in @DebanjanB answer.

But this can be achievable in cucumber-ruby with after step annotation.

At this time, OP might have figured out alternative options. However this may help others. Latest version of io.cucumber has both @BeforeStep and @AfterStep, so you can embed screenshot capturing in to @AfterStep function at only one place which solves your problem.

https://stackoverflow.com/a/53135127/5885718

Selenium exposed a interfaced called as WebDriverEventListener, which you can implement you own code generally this interface has methods like afterFindBy , beforeFindBy just need to implement that method to take screen shots.

After implementing this method then you need to inject this implemented class to driver object as shown below

EventFiringWebDriver eventFiringWebDriver = new EventFiringWebDriver(driver);
    MyWebDriverListerner handler = new MyWebDriverListerner();
    eventFiringWebDriver.register(handler);

Now whenever driver finds the element then it will invoke that respective injected method.

Let me know if it solves your problem

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!