From da8939b8719a5aa64934ccf4a56a4721e9a60702 Mon Sep 17 00:00:00 2001 From: VimalRaj Selvam Date: Mon, 6 Mar 2017 02:19:14 +0530 Subject: [PATCH] Updated to latest Extent and other few changes (#28) * The following changes are done: - Fixed scenario outline bugs - Displaying Examples data table for the scenario outline - Scenario outline and scenario parent child relationships are maintained properly now - Introduced Reporter class for fine step logging and screenshot captures * Updated the travis to use JDK8 --- .travis.yml | 4 +- Changelog.md | 21 + Readme.md | 135 ++- pom.xml | 18 +- report.html | 787 ++++++++++++++++++ .../listener/ExtentCucumberFormatter.java | 297 +++---- .../java/com/cucumber/listener/Reporter.java | 137 +++ .../com/cucumber/listener/package-info.java | 4 + .../com/cucumber/runner/RunCukesTest.java | 32 +- .../cucumber/stepdefinitions/MyStepdefs.java | 25 +- .../stepdefinitions/selenium/Google.java | 48 -- src/test/resources/features/MyFeature.feature | 3 +- .../features/MySecondFeature.feature | 2 +- .../features/selenium/google.feature | 6 - 14 files changed, 1160 insertions(+), 359 deletions(-) create mode 100644 Changelog.md create mode 100644 report.html create mode 100644 src/main/java/com/cucumber/listener/Reporter.java create mode 100644 src/main/java/com/cucumber/listener/package-info.java delete mode 100644 src/test/java/com/cucumber/stepdefinitions/selenium/Google.java delete mode 100644 src/test/resources/features/selenium/google.feature diff --git a/.travis.yml b/.travis.yml index f000e2d..570cd84 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,10 +1,10 @@ language: java jdk: -- openjdk7 + - oraclejdk8 notifications: email: - email2vimalraj@gmail.com before_script: - "export DISPLAY=:99.0" - "sh -e /etc/init.d/xvfb start" - - sleep 3 # give xvfb some time to start \ No newline at end of file + - sleep 3 # give xvfb some time to start diff --git a/Changelog.md b/Changelog.md new file mode 100644 index 0000000..39221cc --- /dev/null +++ b/Changelog.md @@ -0,0 +1,21 @@ +# Changelog + +### v2.0.0 +- Upgraded to the latest version of ExtentReport and made it provided +- Fixed scenario outline bugs +- Displaying Examples data table for the scenario outline +- Scenario outline and scenario parent child relationships are maintained properly now +- Introduced Reporter class for fine step logging and screenshot captures + +### v1.1.1 +- User now can add test runner log from anywhere. The output will be displayed under the Log tab in the report. Refer the example. +- All the step keywords from cucumber is now displayed. +- Fixed to list the feature tags in the Categories section. + +### v1.1.0 +- User now can add system information to the report. +- User now can load the extent report config xml to customize the report. +- Fixed the scenario outline, now each scenario in the scenario outline will be properly displayed in the report. + +### v1.0.0 +- Initial release with basic support of extent report. diff --git a/Readme.md b/Readme.md index 1f92c9d..ed82198 100644 --- a/Readme.md +++ b/Readme.md @@ -14,118 +14,81 @@ If you are using a maven based project, you can directly add this library as a d com.vimalselvam cucumber-extentsreport - 1.1.1 + 2.0.0 ``` +Please note that adding the dependency of ExtentReport v3.0.2+ is mandatory. + If not, download the jar from [here](http://search.maven.org/#search%7Cga%7C1%7Ccucumber-extentsreport). ## Release Notes -### v1.1.1 -- User now can add test runner log from anywhere. The output will be displayed under the Log tab in the report. Refer the example. -- All the step keywords from cucumber is now displayed. -- Fixed to list the feature tags in the Categories section. +For more details, look at [Changelog](Changelog.md). -### v1.1.0 -- User now can add system information to the report. -- User now can load the extent report config xml to customize the report. -- Fixed the scenario outline, now each scenario in the scenario outline will be properly displayed in the report. +## Getting Started -### v1.0.0 -- Initial release with basic support of extent report. +### Runner Class example: +Create a runner class and add the `com.cucumber.listener.ExtentCucumberFormatter` as a plugin followed by the report file as input. -## Cucumber runner class +A sample example is show below: -**Example**: ```java +package com.cucumber.runner; + +import com.cucumber.listener.Reporter; +import cucumber.api.CucumberOptions; +import cucumber.api.junit.Cucumber; +import org.junit.AfterClass; +import org.junit.runner.RunWith; + +import java.io.File; + +/** + * A sample test to demonstrate + */ @RunWith(Cucumber.class) -@CucumberOptions(plugin = {"com.cucumber.listener.ExtentCucumberFormatter"}) +@CucumberOptions( + features = {"src/test/resources/features"}, + glue = {"com.cucumber.stepdefinitions"}, + plugin = {"com.cucumber.listener.ExtentCucumberFormatter:output/report.html"} +) public class RunCukesTest { - - @BeforeClass + @AfterClass public static void setup() { - // Initiates the extent report and generates the output in the output/Run_/report.html file by default. - ExtentCucumberFormatter.initiateExtentCucumberFormatter(); - - // Loads the extent config xml to customize on the report. - ExtentCucumberFormatter.loadConfig(new File("src/test/resources/extent-config.xml")); - - // User can add the system information as follows - ExtentCucumberFormatter.addSystemInfo("Browser Name", "Firefox"); - ExtentCucumberFormatter.addSystemInfo("Browser version", "v31.0"); - ExtentCucumberFormatter.addSystemInfo("Selenium version", "v2.53.0"); - - // Also you can add system information using a hash map - Map systemInfo = new HashMap(); - systemInfo.put("Cucumber version", "v1.2.3"); - systemInfo.put("Extent Cucumber Reporter version", "v1.1.1"); - ExtentCucumberFormatter.addSystemInfo(systemInfo); + Reporter.loadXMLConfig(new File("src/test/resources/extent-config.xml")); + Reporter.setSystemInfo("user", System.getProperty("user.name")); + Reporter.setSystemInfo("os", "Mac OSX"); + Reporter.setTestRunnerOutput("Sample test runner output message"); } - } + ``` -## Initializing report -User can intialize the extent cucumber report in any one of the following ways. Make sure the initialization should happen before your cucumber test start. Ideally, you would be initializing the report in the junit `@BeforeClass` method: +The above example shows a JUnit runner. However, you can use the TestNG runner too. +Also make sure the `loadXMLConfig`, `setSystemInfo` and `setTestRunnerOutput` methods should be in your `@AfterClass` method. -``` -ExtentCucumberFormatter.initiateExtentCucumberFormatter(File filePath, Boolean replaceExisting, DisplayOrder displayOrder, NetworkMode networkMode, Locale locale) -ExtentCucumberFormatter.initiateExtentCucumberFormatter(File filePath, Boolean replaceExisting, DisplayOrder displayOrder, NetworkMode networkMode) -ExtentCucumberFormatter.initiateExtentCucumberFormatter(File filePath, Boolean replaceExisting, DisplayOrder displayOrder, Locale locale) -ExtentCucumberFormatter.initiateExtentCucumberFormatter(File filePath, Boolean replaceExisting, DisplayOrder displayOrder) -ExtentCucumberFormatter.initiateExtentCucumberFormatter(File filePath, Boolean replaceExisting, NetworkMode networkMode, Locale locale) -ExtentCucumberFormatter.initiateExtentCucumberFormatter(File filePath, Boolean replaceExisting, NetworkMode networkMode) -ExtentCucumberFormatter.initiateExtentCucumberFormatter(File filePath, NetworkMode networkMode) -ExtentCucumberFormatter.initiateExtentCucumberFormatter(File filePath, Boolean replaceExisting, Locale locale) -ExtentCucumberFormatter.initiateExtentCucumberFormatter(File filePath, Boolean replaceExisting) -ExtentCucumberFormatter.initiateExtentCucumberFormatter(File filePath, Locale locale) -ExtentCucumberFormatter.initiateExtentCucumberFormatter(File filePath) -ExtentCucumberFormatter.initiateExtentCucumberFormatter() -``` -* filePath - path of the file, in .htm or .html format -* replaceExisting - Setting to overwrite (TRUE) the existing file or append to it - * True (default): the file will be replaced with brand new markup, and all existing data will be lost. Use this option to create a brand new report - * False: existing data will remain, new tests will be appended to the existing report. If the the supplied path does not exist, a new file will be created. -* displayOrder - * OLDEST_FIRST (default) - oldest test at the top, newest at the end - * NEWEST_FIRST - newest test at the top, oldest at the end -* networkMode - * ONLINE (default): creates a single report file with all artifacts - * OFFLINE - all report artifacts will be stored locally in %reportFolder%/extentreports and report will be accessible without internet connectivity -* locale - locale of the HTML report, see list of supported locales [here](http://extentreports.relevantcodes.com/java/#localized-versions). To add a localized version of report, create a new .properties file as shown [here](https://github.com/anshooarora/extentreports/blob/master/java/extentreports/src/main/resources/com/relevantcodes/extentreports/view/resources/localized.properties). - -## Adding System Information -User can add system information in one of the two ways as follows: +### Logging +User can add logs at any step and those logs will be captured and attached to the corresponding step. The log should be added as follows: -``` -ExtentCucumberFormatter.addSystemInfo("BrowserName", "Firefox"); -ExtentCucumberFormatter.addSystemInfo("BrowserVersion", "v33.0"); +```java +Reporter.addStepLog("Step Log message goes here"); ``` -or +In case any log to be added at the scenario level, the following can be done: -``` -Map systemInfo = new HashMap(); -systemInfo.put("Cucumber version", "v1.2.3"); -systemInfo.put("Extent Cucumber Reporter version", "v1.1.1"); -ExtentCucumberFormatter.addSystemInfo(systemInfo); +```java +Reporter.addScenarioLog("Scenario Log message goes here"); ``` -## Loading configuration file -Refer here to create the config xml file: [ExtentReports Configuration](http://extentreports.relevantcodes.com/java/#configuration) -To load the config file: +### Adding screenshot / screen cast +The screenshot or screen cast can be added from any of the step as follows: -``` -ExtentCucumberFormatter.loadConfig(new File("your config xml file path")); +```java +Reporter.addScreenCaptureFromPath("absolute screenshot path"); +Reporter.addScreenCastFromPath("absolute screen cast path"); ``` -## Add Test Runner Logs -To add the test runner log from any of your step, you can do this: +## Demo +[Report](report.html) -``` -@Given("^I am on Google home page$") -public void iAmOnGoogleHomePage() { - open("http://www.google.com"); - ExtentCucumberFormatter.setTestRunnerOutput("Your log goes here"); -} -``` +Fore more details, kindly visit [Cucumber Extent Reporter](http://www.vimalselvam.com/cucumber-extent-reporter/). diff --git a/pom.xml b/pom.xml index c78a586..e3b5d50 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ com.vimalselvam cucumber-extentsreport - 1.1.1 + 2.0.0 jar Cucumber Extents Report @@ -45,8 +45,8 @@ UTF-8 - 1.2.3 - 2.41.0 + 1.2.5 + 3.0.2 @@ -75,18 +75,14 @@ info.cukes cucumber-java ${cucumber.version} + provided - com.relevantcodes + com.aventstack extentreports ${extentreports.version} - - - - org.apache.directory.studio - org.apache.commons.codec - 1.8 + provided @@ -165,4 +161,4 @@ - \ No newline at end of file + diff --git a/report.html b/report.html new file mode 100644 index 0000000..e63b259 --- /dev/null +++ b/report.html @@ -0,0 +1,787 @@ + + + + + + + + + + + + + + + + Cucumber Extent Reports - v1.0.0 + + + +
+ desktop_windows +
+ + + +
+ +
+ +
+ +
+ + +
+
+
+
+
Tests
+
+ +
+
+ 7 test(s) passed +
+
+ 0 test(s) failed, 0 others +
+
+
+ +
+
+
Steps
+
+ +
+
+ 8 step(s) passed +
+
+ 0 step(s) failed, 2 others +
+
+
+ +
+
+ +
+ +
+
Tests
+
    + + +
  • +
    + My First Feature + Mar 6, 2017 2:04:12 AM + pass +
    +
    +
    + Mar 6, 2017 2:04:12 AM + Mar 6, 2017 2:04:12 AM + 0h 0m 0s+320ms +
    +
    +
    + @featureTag +
    +
    +
      + +
    • +
      +
      Scenario Outline: My First Scenario
      + Mar 6, 2017 2:04:12 AM + 0h 0m 0s+292ms + pass +
      +
      +
      + + + + + + + + + + + + + + + +
      StatusTimestampDetails
      info_outline2:04:12 AM
      test
      1
      2
      +
      +
      +
        +
      • +
        +
        My First Scenario
        + Mar 6, 2017 2:04:12 AM + 0h 0m 0s+232ms + pass +
        +
        +
        + @featureTag + @scenarioTag +
        +
        + + + + + + + + + + + + + + + +
        StatusTimestampDetails
        info_outline2:04:12 AMThis is scenario log
        +
        +
        +
          +
        • +
          +
          I have 1 cukes in my belly
          + Mar 6, 2017 2:04:12 AM + 0h 0m 0s+220ms + pass +
          +
          +
          + + + + + + + + + + + + + + + + + + + + +
          StatusTimestampDetails
          info_outline2:04:12 AMMy test addStepLog message
          check_circle2:04:12 AMpassed
          +
          +
          +
        • +
        • +
          +
          I print
          + Mar 6, 2017 2:04:12 AM + 0h 0m 0s+0ms + pass +
          +
          +
          + + + + + + + + + + + + + + + +
          StatusTimestampDetails
          check_circle2:04:12 AMpassed
          +
          +
          +
        • +
        +
      • +
      • +
        +
        My First Scenario
        + Mar 6, 2017 2:04:12 AM + 0h 0m 0s+38ms + pass +
        +
        +
        + @featureTag + @scenarioTag +
        +
        + + + + + + + + + + + + + + + +
        StatusTimestampDetails
        info_outline2:04:12 AMThis is scenario log
        +
        +
        +
          +
        • +
          +
          I have 2 cukes in my belly
          + Mar 6, 2017 2:04:12 AM + 0h 0m 0s+17ms + pass +
          +
          +
          + + + + + + + + + + + + + + + + + + + + +
          StatusTimestampDetails
          info_outline2:04:12 AMMy test addStepLog message
          check_circle2:04:12 AMpassed
          +
          +
          +
        • +
        • +
          +
          I print
          + Mar 6, 2017 2:04:12 AM + 0h 0m 0s+0ms + pass +
          +
          +
          + + + + + + + + + + + + + + + +
          StatusTimestampDetails
          check_circle2:04:12 AMpassed
          +
          +
          +
        • +
        +
      • +
      +
    • +
    • +
      +
      My Second Scenario
      + Mar 6, 2017 2:04:12 AM + 0h 0m 0s+21ms + pass +
      +
        +
      • +
        +
        I have 7 cukes in my bellies
        + Mar 6, 2017 2:04:12 AM + 0h 0m 0s+1ms + pass +
        +
        +
        + + + + + + + + + + + + + + + +
        StatusTimestampDetails
        check_circle2:04:12 AMpassed
        +
        +
        +
      • +
      • +
        +
        I print
        + Mar 6, 2017 2:04:12 AM + 0h 0m 0s+10ms + pass +
        +
        +
        + + + + + + + + + + + + + + + +
        StatusTimestampDetails
        check_circle2:04:12 AMpassed
        +
        +
        +
      • +
      +
    • +
    +
    +
  • + + +
  • +
    + My Second Feature + Mar 6, 2017 2:04:12 AM + pass +
    +
    +
    + 0h 0m 0s+15ms +
    + Scenario + My First Scenario +
    +
      +
    • Given + I have 10 cukes in my belly +
    • +
    • Then + I print +
    • +
    +
    +
    + 0h 0m 0s+2ms +
    + Scenario + My Second Scenario +
    +
      +
    • Given + I have 7 cukes in my bellies +
    • +
    +
    +
    +
  • +
+
+
+ + +
+
+
+ +
+ info_outline + check_circle + cancel + cancel + error + warning + redo + clear +
+
+
+ + +
+
+ +
+
+ +
+ + search Search + + +
+ +
+ +
+ +
+
+ +
+ +
+
Categories
+
    + +
  • +
    + @featureTag + + 3 + +
    +
    +
    + Passed: 3 + + +
    + +
    + + + + + + + + + + + + + + + + + + + + + + + + + +
    TimestampTestNameStatus
    Mar 6, 2017 2:04:12 AMMy First Featurepass
    Mar 6, 2017 2:04:12 AMMy First Feature.Scenario Outline: My First Scenario.My First Scenariopass
    Mar 6, 2017 2:04:12 AMMy First Feature.Scenario Outline: My First Scenario.My First Scenariopass
    +
    +
    +
  • +
  • +
    + @scenarioTag + + 3 + +
    +
    +
    + Passed: 3 + + +
    + +
    + + + + + + + + + + + + + + + + + + + + + + + + + +
    TimestampTestNameStatus
    Mar 6, 2017 2:04:12 AMMy First Feature.Scenario Outline: My First Scenario.My First Scenariopass
    Mar 6, 2017 2:04:12 AMMy First Feature.Scenario Outline: My First Scenario.My First Scenariopass
    Mar 6, 2017 2:04:12 AMMy First Feature.My Second Scenariopass
    +
    +
    +
  • + +
+
+
+ +
+
+
+
+
+
+
+
+
Dashboard
+ +
+
+
+ Tests +
7
+
+
+
+
+ Steps +
10
+
+
+
+
+ Start +
Mar 6, 2017 2:04:11 AM
+
+
+
+
+ End +
Mar 6, 2017 2:04:12 AM
+
+
+
+
+ Time Taken +
523ms
+
+
+
+
+ Environment

 

+ + + + + + + + + + + + + + +
NameValue
uservimalrajselvam
osMac OSX
+
+
+
+
+ Categories

 

+ + + + + + + + + + + + + + + + + + + + +
NamePassedFailedOthers
@featureTag300
@scenarioTag300
+
+
+
+
+
+
+
+
TestRunner Logs
+ +
+ Sample test runner output message +
+
+
+ +
+ + + + + + + + + + diff --git a/src/main/java/com/cucumber/listener/ExtentCucumberFormatter.java b/src/main/java/com/cucumber/listener/ExtentCucumberFormatter.java index 4405bc5..1870885 100644 --- a/src/main/java/com/cucumber/listener/ExtentCucumberFormatter.java +++ b/src/main/java/com/cucumber/listener/ExtentCucumberFormatter.java @@ -1,253 +1,204 @@ package com.cucumber.listener; -import com.relevantcodes.extentreports.*; -import cucumber.runtime.CucumberException; -import cucumber.runtime.io.URLOutputStream; +import com.aventstack.extentreports.ExtentReports; +import com.aventstack.extentreports.ExtentTest; +import com.aventstack.extentreports.GherkinKeyword; +import com.aventstack.extentreports.markuputils.MarkupHelper; +import com.aventstack.extentreports.reporter.ExtentHtmlReporter; import gherkin.formatter.Formatter; import gherkin.formatter.Reporter; import gherkin.formatter.model.*; import java.io.File; -import java.io.IOException; -import java.io.OutputStream; -import java.net.URL; -import java.util.*; +import java.util.LinkedList; +import java.util.List; /** - * Cucumber custom format listener which generates ExtentsReport html file + * A cucumber based reporting listener which generates the Extent Report */ public class ExtentCucumberFormatter implements Reporter, Formatter { + private static ThreadLocal reportsThreadLocal = new ThreadLocal(); + private static ThreadLocal htmlReporterThreadLocal = + new ThreadLocal(); + private static ThreadLocal featureTestThreadLocal = new ThreadLocal(); + private static ThreadLocal scenarioOutlineThreadLocal = + new ThreadLocal(); + static ThreadLocal scenarioThreadLocal = new ThreadLocal(); + private static ThreadLocal> stepListThreadLocal = + new ThreadLocal>(); + static ThreadLocal stepTestThreadLocal = new ThreadLocal(); + private boolean scenarioOutlineFlag; - private static ExtentReports extent; - private ExtentTest featureTest; - private ExtentTest scenarioTest; - private LinkedList testSteps = new LinkedList(); - private static File htmlReportDir; - private static Map systemInfo; - private boolean scenarioOutlineTest; - - private static final Map MIME_TYPES_EXTENSIONS = new HashMap() { - { - this.put("image/bmp", "bmp"); - this.put("image/gif", "gif"); - this.put("image/jpeg", "jpg"); - this.put("image/png", "png"); - this.put("image/svg+xml", "svg"); - this.put("video/ogg", "ogg"); - } - }; - - public ExtentCucumberFormatter(File filePath) { - if (!filePath.getPath().equals("")) { - String reportPath = filePath.getPath(); - this.htmlReportDir = new File(reportPath); - this.extent = new ExtentReports(reportPath); - } else { - String reportDir = "output/Run_" + System.currentTimeMillis(); - this.htmlReportDir = new File(reportDir); - this.extent = new ExtentReports(reportDir + "/report.html"); - } - } - - public ExtentCucumberFormatter() { + public ExtentCucumberFormatter(File file) { + setExtentHtmlReport(new ExtentHtmlReporter(file)); + ExtentReports extentReports = new ExtentReports(); + extentReports.attachReporter(getExtentHtmlReport()); + setExtentReport(extentReports); + stepListThreadLocal.set(new LinkedList()); + scenarioOutlineFlag = false; } - public static void initiateExtentCucumberFormatter(File filePath, Boolean replaceExisting, - DisplayOrder displayOrder, NetworkMode networkMode, - Locale locale) { - htmlReportDir = filePath; - extent = new ExtentReports(filePath.getAbsolutePath(), replaceExisting, displayOrder, networkMode, locale); + private static void setExtentHtmlReport(ExtentHtmlReporter htmlReport) { + htmlReporterThreadLocal.set(htmlReport); } - public static void initiateExtentCucumberFormatter(File filePath, Boolean replaceExisting, - DisplayOrder displayOrder, NetworkMode networkMode) { - initiateExtentCucumberFormatter(filePath, replaceExisting, displayOrder, networkMode, null); + static ExtentHtmlReporter getExtentHtmlReport() { + return htmlReporterThreadLocal.get(); } - public static void initiateExtentCucumberFormatter(File filePath, Boolean replaceExisting, - DisplayOrder displayOrder, Locale locale) { - initiateExtentCucumberFormatter(filePath, replaceExisting, displayOrder, null, locale); + private static void setExtentReport(ExtentReports extentReports) { + reportsThreadLocal.set(extentReports); } - public static void initiateExtentCucumberFormatter(File filePath, Boolean replaceExisting, - DisplayOrder displayOrder) { - initiateExtentCucumberFormatter(filePath, replaceExisting, displayOrder, null, null); + static ExtentReports getExtentReport() { + return reportsThreadLocal.get(); } - public static void initiateExtentCucumberFormatter(File filePath, Boolean replaceExisting, NetworkMode networkMode, - Locale locale) { - initiateExtentCucumberFormatter(filePath, replaceExisting, null, networkMode, locale); - } + public void syntaxError(String state, String event, List legalEvents, String uri, + Integer line) { - public static void initiateExtentCucumberFormatter(File filePath, Boolean replaceExisting, - NetworkMode networkMode) { - initiateExtentCucumberFormatter(filePath, replaceExisting, null, networkMode, null); } - public static void initiateExtentCucumberFormatter(File filePath, NetworkMode networkMode) { - initiateExtentCucumberFormatter(filePath, null, null, networkMode, null); - } - - public static void initiateExtentCucumberFormatter(File filePath, Boolean replaceExisting, Locale locale) { - initiateExtentCucumberFormatter(filePath, replaceExisting, null, null, locale); - } + public void uri(String uri) { - public static void initiateExtentCucumberFormatter(File filePath, Boolean replaceExisting) { - initiateExtentCucumberFormatter(filePath, replaceExisting, null, null, null); } - public static void initiateExtentCucumberFormatter(File filePath, Locale locale) { - initiateExtentCucumberFormatter(filePath, null, null, null, locale); - } - - public static void initiateExtentCucumberFormatter(File filePath) { - initiateExtentCucumberFormatter(filePath, null, null, null, null); - } - - public static void initiateExtentCucumberFormatter() { - String reportFilePath = "output" + File.separator + "Run_" + System.currentTimeMillis() + File.separator + - "report.html"; - initiateExtentCucumberFormatter(new File(reportFilePath)); - } + public void feature(Feature feature) { + featureTestThreadLocal.set(getExtentReport().createTest(feature.getName())); + ExtentTest test = featureTestThreadLocal.get(); - public static void setTestRunnerOutput(String s) { - extent.setTestRunnerOutput(s); + for (Tag tag : feature.getTags()) { + test.assignCategory(tag.getName()); + } } - public static void loadConfig(File configFile) { - extent.loadConfig(configFile); + public void scenarioOutline(ScenarioOutline scenarioOutline) { + scenarioOutlineFlag = true; + ExtentTest node = featureTestThreadLocal.get() + .createNode(scenarioOutline.getKeyword() + ": " + scenarioOutline.getName()); + scenarioOutlineThreadLocal.set(node); } - public static void addSystemInfo(String param, String value) { - if (systemInfo == null) { - systemInfo = new HashMap(); + public void examples(Examples examples) { + ExtentTest test = scenarioOutlineThreadLocal.get(); + + String[][] data = null; + List rows = examples.getRows(); + int rowSize = rows.size(); + for (int i = 0; i < rowSize; i++) { + ExamplesTableRow examplesTableRow = rows.get(i); + List cells = examplesTableRow.getCells(); + int cellSize = cells.size(); + if (data == null) { + data = new String[rowSize][cellSize]; + } + for (int j = 0; j < cellSize; j++) { + data[i][j] = cells.get(j); + } } - systemInfo.put(param, value); + test.info(MarkupHelper.createTable(data)); } - public static void addSystemInfo(Map info) { - if (systemInfo == null) { - systemInfo = new HashMap(); + public void startOfScenarioLifeCycle(Scenario scenario) { + if (scenarioOutlineFlag) { + scenarioOutlineFlag = false; } - systemInfo.putAll(info); - } - public void before(Match match, Result result) { +// if (scenario.getKeyword().trim().equalsIgnoreCase("Scenario")) { +// scenarioOutlineThreadLocal.set(null); +// } - } + ExtentTest scenarioNode; + if (scenarioOutlineThreadLocal.get() != null && scenario.getKeyword().trim() + .equalsIgnoreCase("Scenario Outline")) { + scenarioNode = scenarioOutlineThreadLocal.get() + .createNode(com.aventstack.extentreports.gherkin.model.Scenario.class, + scenario.getName()); + } else { + scenarioNode = featureTestThreadLocal.get() + .createNode(com.aventstack.extentreports.gherkin.model.Scenario.class, + scenario.getName()); + } - public void result(Result result) { - if (!scenarioOutlineTest) { - Step step = testSteps.poll(); - if ("passed".equals(result.getStatus())) { - scenarioTest.log(LogStatus.PASS, step.getKeyword() + step.getName(), "PASSED"); - } else if ("failed".equals(result.getStatus())) { - scenarioTest.log(LogStatus.FAIL, step.getKeyword() + step.getName(), result.getError()); - } else if ("skipped".equals(result.getStatus())) { - scenarioTest.log(LogStatus.SKIP, step.getKeyword() + step.getName(), "SKIPPED"); - } else if ("undefined".equals(result.getStatus())) { - scenarioTest.log(LogStatus.UNKNOWN, step.getKeyword() + step.getName(), "UNDEFINED"); - } + for (Tag tag : scenario.getTags()) { + scenarioNode.assignCategory(tag.getName()); } + scenarioThreadLocal.set(scenarioNode); } - public void after(Match match, Result result) { + public void background(Background background) { } - public void match(Match match) { + public void scenario(Scenario scenario) { } - public void embedding(String s, byte[] bytes) { - if (!scenarioOutlineTest) { - String extension = (String)MIME_TYPES_EXTENSIONS.get(s); - String fileName = "screenshot-" + System.currentTimeMillis() + "." + extension; - this.writeBytesAndClose(bytes, this.reportFileOutputStream(fileName)); - scenarioTest.log(LogStatus.INFO, scenarioTest.addScreenCapture(fileName)); + public void step(Step step) { + if (scenarioOutlineFlag) { + return; } + stepListThreadLocal.get().add(step); } - public void write(String s) { - if (!scenarioOutlineTest) - scenarioTest.log(LogStatus.INFO, s); - } - - public void syntaxError(String s, String s1, List list, String s2, Integer integer) { - } + public void endOfScenarioLifeCycle(Scenario scenario) { - public void uri(String s) { } - public void feature(Feature feature) { - featureTest = extent.startTest("Feature: " + feature.getName()); - - for (Tag tag : feature.getTags()) { - featureTest.assignCategory(tag.getName()); - } + public void done() { + getExtentReport().flush(); } - public void scenarioOutline(ScenarioOutline scenarioOutline) { - scenarioOutlineTest = true; - } + public void close() { - public void examples(Examples examples) { } - public void startOfScenarioLifeCycle(Scenario scenario) { - scenarioTest = extent.startTest("Scenario: " + scenario.getName()); - - for (Tag tag : scenario.getTags()) { - scenarioTest.assignCategory(tag.getName()); - } - scenarioOutlineTest = false; - } + public void eof() { - public void background(Background background) { } - public void scenario(Scenario scenario) { - } + public void before(Match match, Result result) { - public void step(Step step) { - if (!scenarioOutlineTest) - testSteps.add(step); } - public void endOfScenarioLifeCycle(Scenario scenario) { - if (!scenarioOutlineTest) { - extent.endTest(scenarioTest); - featureTest.appendChild(scenarioTest); + public void result(Result result) { + if (scenarioOutlineFlag) { + return; } - } - public void done() { + if (Result.PASSED.equals(result.getStatus())) { + stepTestThreadLocal.get().pass(Result.PASSED); + } else if (Result.FAILED.equals(result.getStatus())) { + stepTestThreadLocal.get().fail(result.getError()); + } else if (Result.SKIPPED.equals(result)) { + stepTestThreadLocal.get().skip(Result.SKIPPED.getStatus()); + } else if (Result.UNDEFINED.equals(result)) { + stepTestThreadLocal.get().skip(Result.UNDEFINED.getStatus()); + } } - public void close() { - extent.addSystemInfo(systemInfo); - extent.close(); - } + public void after(Match match, Result result) { - public void eof() { - extent.endTest(featureTest); - extent.flush(); } - private OutputStream reportFileOutputStream(String fileName) { + public void match(Match match) { + Step step = stepListThreadLocal.get().poll(); + ExtentTest scenarioTest = scenarioThreadLocal.get(); + GherkinKeyword keyword = null; try { - return new URLOutputStream(new URL(this.htmlReportDir.toURI().toURL(), fileName)); - } catch (IOException var3) { - throw new CucumberException(var3); + keyword = new GherkinKeyword(step.getKeyword().trim()); + } catch (ClassNotFoundException e) { + e.printStackTrace(); } + ExtentTest stepTest = scenarioTest.createNode(keyword, step.getName()); + stepTestThreadLocal.set(stepTest); } - private void writeBytesAndClose(byte[] buf, OutputStream out) { - try { - out.write(buf); - } catch (IOException var4) { - throw new CucumberException("Unable to write to report file item: ", var4); - } + public void embedding(String mimeType, byte[] data) { + } + public void write(String text) { + + } } diff --git a/src/main/java/com/cucumber/listener/Reporter.java b/src/main/java/com/cucumber/listener/Reporter.java new file mode 100644 index 0000000..a88309c --- /dev/null +++ b/src/main/java/com/cucumber/listener/Reporter.java @@ -0,0 +1,137 @@ +package com.cucumber.listener; + +import com.aventstack.extentreports.ExtentReports; +import com.aventstack.extentreports.ExtentTest; +import com.aventstack.extentreports.reporter.ExtentHtmlReporter; + +import java.io.File; +import java.io.IOException; +import java.util.List; + +/** + * This class houses few utilities required for the report + */ +public class Reporter { + + private Reporter() { + // Defeat instantiation + } + + /** + * Gets the {@link ExtentHtmlReporter} instance created through listener + * + * @return The {@link ExtentHtmlReporter} instance + */ + public static ExtentHtmlReporter getExtentHtmlReport() { + return ExtentCucumberFormatter.getExtentHtmlReport(); + } + + /** + * Gets the {@link ExtentReports} instance created through the listener + * + * @return The {@link ExtentReports} instance + */ + public static ExtentReports getExtentReport() { + return ExtentCucumberFormatter.getExtentReport(); + } + + /** + * Loads the XML config file + * + * @param xmlPath The xml path in string + */ + public static void loadXMLConfig(String xmlPath) { + getExtentHtmlReport().loadXMLConfig(xmlPath); + } + + /** + * Loads the XML config file + * + * @param file The file path of the XML + */ + public static void loadXMLConfig(File file) { + getExtentHtmlReport().loadXMLConfig(file); + } + + /** + * Adds an info message to the current step + * + * @param message The message to be logged to the current step + */ + public static void addStepLog(String message) { + getCurrentStep().info(message); + } + + /** + * Adds an info message to the current scenario + * + * @param message The message to be logged to the current scenario + */ + public static void addScenarioLog(String message) { + getCurrentScenario().info(message); + } + + /** + * Adds the screenshot from the given path to the current step + * + * @param imagePath The image path + * @throws IOException Exception if imagePath is erroneous + */ + public static void addScreenCaptureFromPath(String imagePath) throws IOException { + getCurrentStep().addScreenCaptureFromPath(imagePath); + } + + /** + * Adds the screenshot from the given path with the given title to the current step + * + * @param imagePath The image path + * @param title The title for the image + * @throws IOException Exception if imagePath is erroneous + */ + public static void addScreenCaptureFromPath(String imagePath, String title) throws IOException { + getCurrentStep().addScreenCaptureFromPath(imagePath, title); + } + + /** + * Adds the screen cast from the given path to the current step + * + * @param screenCastPath The screen cast path + * @throws IOException Exception if imagePath is erroneous + */ + public static void addScreenCast(String screenCastPath) throws IOException { + getCurrentStep().addScreencastFromPath(screenCastPath); + } + + /** + * Sets the system information with the given key value pair + * @param key The name of the key + * @param value The value of the given key + */ + public static void setSystemInfo(String key, String value) { + getExtentReport().setSystemInfo(key, value); + } + + /** + * Sets the test runner output with the given list of strings + * @param log The list of string messages + */ + public static void setTestRunnerOutput(List log) { + getExtentReport().setTestRunnerOutput(log); + } + + /** + * Sets the test runner output with the given string + * @param outputMessage The message to be shown in the test runner output screen + */ + public static void setTestRunnerOutput(String outputMessage) { + getExtentReport().setTestRunnerOutput(outputMessage); + } + + private static ExtentTest getCurrentStep() { + return ExtentCucumberFormatter.stepTestThreadLocal.get(); + } + + private static ExtentTest getCurrentScenario() { + return ExtentCucumberFormatter.scenarioThreadLocal.get(); + } +} diff --git a/src/main/java/com/cucumber/listener/package-info.java b/src/main/java/com/cucumber/listener/package-info.java new file mode 100644 index 0000000..6876b3e --- /dev/null +++ b/src/main/java/com/cucumber/listener/package-info.java @@ -0,0 +1,4 @@ +/** + * This package houses the listener for cucumber reporting and few utilities + */ +package com.cucumber.listener; diff --git a/src/test/java/com/cucumber/runner/RunCukesTest.java b/src/test/java/com/cucumber/runner/RunCukesTest.java index e0c4ed1..3c412ad 100644 --- a/src/test/java/com/cucumber/runner/RunCukesTest.java +++ b/src/test/java/com/cucumber/runner/RunCukesTest.java @@ -1,36 +1,30 @@ package com.cucumber.runner; -import com.cucumber.listener.ExtentCucumberFormatter; +import com.cucumber.listener.Reporter; import cucumber.api.CucumberOptions; import cucumber.api.junit.Cucumber; -import org.junit.BeforeClass; +import org.junit.AfterClass; import org.junit.runner.RunWith; import java.io.File; -import java.util.HashMap; -import java.util.Map; /** - * Created by vimalraj on 11/02/16. + * A sample test to demonstrate */ @RunWith(Cucumber.class) -@CucumberOptions(features = {"src/test/resources/features/MyFeature.feature"}, glue = {"com.cucumber.stepdefinitions"}, - plugin = {"com.cucumber.listener.ExtentCucumberFormatter"}) +@CucumberOptions( + features = {"src/test/resources/features"}, + glue = {"com.cucumber.stepdefinitions"}, + plugin = {"com.cucumber.listener.ExtentCucumberFormatter:output/report.html"} +) public class RunCukesTest { - @BeforeClass + @AfterClass public static void setup() { - ExtentCucumberFormatter.initiateExtentCucumberFormatter(); - ExtentCucumberFormatter.loadConfig(new File("src/test/resources/extent-config.xml")); - - ExtentCucumberFormatter.addSystemInfo("Browser Name", "Firefox"); - ExtentCucumberFormatter.addSystemInfo("Browser version", "v31.0"); - ExtentCucumberFormatter.addSystemInfo("Selenium version", "v2.53.0"); - - Map systemInfo = new HashMap(); - systemInfo.put("Cucumber version", "v1.2.3"); - systemInfo.put("Extent Cucumber Reporter version", "v1.1.0"); - ExtentCucumberFormatter.addSystemInfo(systemInfo); + Reporter.loadXMLConfig(new File("src/test/resources/extent-config.xml")); + Reporter.setSystemInfo("user", System.getProperty("user.name")); + Reporter.setSystemInfo("os", "Mac OSX"); + Reporter.setTestRunnerOutput("Sample test runner output message"); } } diff --git a/src/test/java/com/cucumber/stepdefinitions/MyStepdefs.java b/src/test/java/com/cucumber/stepdefinitions/MyStepdefs.java index 119bc2a..f19c1c3 100644 --- a/src/test/java/com/cucumber/stepdefinitions/MyStepdefs.java +++ b/src/test/java/com/cucumber/stepdefinitions/MyStepdefs.java @@ -1,26 +1,27 @@ package com.cucumber.stepdefinitions; +import com.cucumber.listener.Reporter; import cucumber.api.java.en.Given; import cucumber.api.java.en.Then; +import org.junit.Assert; + +import java.io.IOException; -/** - * Created by vimalraj on 12/02/16. - */ public class MyStepdefs { - @Given("I have (\\d+) cukes in my belly") - public void I_have_cukes_in_my_belly(int cukes) { - System.out.format("Cukes: %n\n", cukes); -// Assert.assertTrue(false); + @Given("I have (\\d+) cukes in my belly") public void I_have_cukes_in_my_belly(int cukes) + throws IOException { + Reporter.addStepLog("My test addStepLog message"); + Reporter.addScenarioLog("This is scenario log"); +// Reporter.addScreenCaptureFromPath( +// "/Users/vimalrajselvam/Downloads/best-resume-template-2016-3.jpg", "My title"); } - @Given("I have (\\d+) cukes in my bellies") - public void I_have_cukes_in_my_bellies(int cukes) { + @Given("I have (\\d+) cukes in my bellies") public void I_have_cukes_in_my_bellies(int cukes) { System.out.format("Cukes: %n\n", cukes); } - @Then("^I print$") - public void iPrint() throws Throwable { - // Write code here that turns the phrase above into concrete actions + @Then("^I print$") public void iPrint() throws Throwable { + // Assert.assertTrue(false); } } diff --git a/src/test/java/com/cucumber/stepdefinitions/selenium/Google.java b/src/test/java/com/cucumber/stepdefinitions/selenium/Google.java deleted file mode 100644 index acb8d25..0000000 --- a/src/test/java/com/cucumber/stepdefinitions/selenium/Google.java +++ /dev/null @@ -1,48 +0,0 @@ -package com.cucumber.stepdefinitions.selenium; - -import cucumber.api.Scenario; -import cucumber.api.java.After; -import cucumber.api.java.Before; -import cucumber.api.java.en.Given; -import cucumber.api.java.en.Then; -import org.junit.Assert; -import org.openqa.selenium.OutputType; -import org.openqa.selenium.TakesScreenshot; -import org.openqa.selenium.WebDriver; -import org.openqa.selenium.firefox.FirefoxDriver; - -/** - * Created by vimalraj on 21/03/16. - */ -public class Google { - WebDriver driver; - - @Before - public void setup() { - driver = new FirefoxDriver(); - } - - @Given("^I am on Google home page$") - public void iAmOnGoogleHomePage() throws Throwable { - driver.get("http://www.google.com"); - } - - @Then("^I verify the title is \"([^\"]*)\"$") - public void iVerifyTheTitleIs(String arg0) throws Throwable { - Assert.assertEquals("Title not matches", arg0, driver.getTitle()); - } - - @After - public void tearDown(Scenario scenario) { - - if (scenario.isFailed()) { - byte[] screenshotBytes = ((TakesScreenshot) driver).getScreenshotAs(OutputType.BYTES); - scenario.embed(screenshotBytes, "image/png"); - } - - if (driver != null) { - driver.quit(); - } - - } -} diff --git a/src/test/resources/features/MyFeature.feature b/src/test/resources/features/MyFeature.feature index c457065..d80a218 100644 --- a/src/test/resources/features/MyFeature.feature +++ b/src/test/resources/features/MyFeature.feature @@ -11,6 +11,7 @@ Feature: My First Feature | 1 | | 2 | + @scenarioTag Scenario: My Second Scenario Given I have 7 cukes in my bellies - Then I print \ No newline at end of file + Then I print diff --git a/src/test/resources/features/MySecondFeature.feature b/src/test/resources/features/MySecondFeature.feature index 2e60348..3eaeaeb 100644 --- a/src/test/resources/features/MySecondFeature.feature +++ b/src/test/resources/features/MySecondFeature.feature @@ -5,4 +5,4 @@ Feature: My Second Feature Then I print Scenario: My Second Scenario - Given I have 7 cukes in my bellies \ No newline at end of file + Given I have 7 cukes in my bellies diff --git a/src/test/resources/features/selenium/google.feature b/src/test/resources/features/selenium/google.feature deleted file mode 100644 index 608f74a..0000000 --- a/src/test/resources/features/selenium/google.feature +++ /dev/null @@ -1,6 +0,0 @@ -@google -Feature: Google - - Scenario: Open google and check title - Given I am on Google home page - Then I verify the title is "Google" \ No newline at end of file