├── .github └── workflows │ └── build.yml ├── .gitignore ├── README.md ├── pom.xml └── src └── main └── java └── net └── masterthought └── cucumber └── sandwich ├── CucumberReportMonitor.java └── SandwichParameters.java /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: build 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | pull_request: 8 | types: 9 | - opened 10 | - synchronize 11 | - reopened 12 | 13 | jobs: 14 | build: 15 | strategy: 16 | matrix: 17 | java: [ '11', '17' ] 18 | os: [ 'ubuntu-latest', 'windows-latest', 'macos-latest' ] 19 | 20 | runs-on: ${{ matrix.os }} 21 | 22 | steps: 23 | - uses: actions/checkout@v3 24 | 25 | - uses: actions/setup-java@v3 26 | with: 27 | java-version: ${{ matrix.java }} 28 | distribution: adopt 29 | 30 | - run: mvn --batch-mode verify 31 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | target 2 | velocity.log 3 | .idea 4 | .classpath 5 | .project 6 | .settings/ 7 | *.autosave 8 | *.iml 9 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Github build](https://github.com/damianszczepanik/cucumber-sandwich/actions/workflows/build.yml/badge.svg?branch=master)](https://github.com/damianszczepanik/cucumber-sandwich/actions/workflows/build.yml) 2 | 3 | [![Maven Central](https://img.shields.io/maven-central/v/net.masterthought/cucumber-sandwich.svg)](http://search.maven.org/#search|gav|1|g%3A%22net.masterthought%22%20AND%20a%3A%22cucumber-sandwich%22) 4 | 5 | [![Live Demo](https://img.shields.io/badge/Live%20Demo-Online-blue.svg)](https://damianszczepanik.github.io/cucumber-html-reports/overview-features.html) 6 | 7 | # Generate Pretty HTML Reports For Cucumber On The Fly 8 | 9 | This project generates pretty cucumber html reports on the fly. It monitors your cucumber json report directory for change and then publishes a new report if your report json files change. 10 | 11 | ## Background 12 | 13 | I wanted a way of quickly seeing my cucumber reports results when running locally where we didn't have maven available so the maven mojo could not be used. 14 | 15 | ## Install 16 | 17 | 1. download/clone this project 18 | 2. mvn clean install 19 | 20 | You should see a file like this: cucumber-sandwich-0.0.1-SNAPSHOT-jar-with-dependencies.jar 21 | rename this file to cucumber-sandwich.jar 22 | 23 | ## Use 24 | 25 | Use the cucumber-sandwich.jar like this: 26 | 27 | java -jar cucumber-sandwich.jar -f path/to/the/folder/containing/cucumber.json -o /path/to/generate/html/reports/into 28 | 29 | It's probably best to stick that in a .bat or .sh script for easy running. Also note there is no checking done to verify if the json files are cucumber ones and it picks up any json files in the input directory. So make sure you generate your cucumber.json files in a directory without other json files. 30 | 31 | You can also add an option -n flag to just run once instead of listening for changes: 32 | 33 | java -jar cucumber-sandwich.jar -n -f path/to/the/folder/containing/json -o path/to/folder/to/generate/reports/into 34 | 35 | An example with real paths would be: 36 | 37 | java -jar cucumber-sandwich.jar -f /home/kings/cucumber/json -o /home/kings/cucumber/reports -n 38 | 39 | 40 | 41 | You can specify where the cucumber.json goes in your runner e.g. 42 | 43 | import cucumber.junit.Cucumber; 44 | import org.junit.runner.RunWith; 45 | 46 | @RunWith(Cucumber.class) 47 | @CucumberOptions(plugin = {"json:path/to/cucumber.json"}) 48 | public class SomeTest { 49 | } 50 | 51 | 52 | ## Develop 53 | 54 | Interested in contributing to the cucumber-reporting? Just contact me or send a pull request. 55 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4.0.0 3 | net.masterthought 4 | cucumber-sandwich 5 | jar 6 | 5.8.1-SNAPSHOT 7 | cucumber-sandwich 8 | https://github.com/damianszczepanik/cucumber-sandwich 9 | 10 | 11 | org.sonatype.oss 12 | oss-parent 13 | 9 14 | 15 | 16 | 17 | 18 | ossrh 19 | https://oss.sonatype.org/content/repositories/snapshots 20 | 21 | 22 | ossrh 23 | https://oss.sonatype.org/service/local/staging/deploy/maven2/ 24 | 25 | 26 | 27 | 28 | scm:git:https://github.com/damianszczepanik/cucumber-sandwich.git 29 | scm:git:git@github.com:damianszczepanik/cucumber-sandwich.git 30 | git@github.com:damianszczepanik/cucumber-sandwich.git 31 | 32 | 33 | GitHub Actions 34 | https://github.com/damianszczepanik/cucumber-sandwich/actions 35 | 36 | 37 | 38 | This project displays a report locally 39 | 40 | 41 | 42 | 43 | LGPL 2.1 44 | http://www.gnu.org/licenses/lgpl-2.1.html 45 | 46 | 47 | 48 | 49 | 50 | kingsleyh 51 | Kingsley Hendrickse 52 | kingsley.hendrickse@gmail.com 53 | 54 | 55 | damianszczepanik 56 | Damian Szczepanik 57 | damianszczepanik@github 58 | 59 | 60 | 61 | 62 | 63 | release-sign-artifacts 64 | 65 | 66 | 67 | 69 | performRelease 70 | true 71 | 72 | 73 | 74 | 75 | 0738FA8F 76 | Damian Szczepanik 77 | 78 | 79 | 80 | 81 | 82 | 83 | org.apache.maven.plugins 84 | maven-gpg-plugin 85 | 3.1.0 86 | 87 | 88 | sign-artifacts 89 | verify 90 | 91 | sign 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | org.apache.maven.plugins 107 | maven-compiler-plugin 108 | 3.12.0 109 | 110 | 11 111 | 11 112 | UTF-8 113 | 114 | 115 | 116 | maven-assembly-plugin 117 | 3.1.0 118 | 119 | 120 | jar-with-dependencies 121 | 122 | 123 | 124 | net.masterthought.cucumber.sandwich.CucumberReportMonitor 125 | 126 | 127 | 128 | 129 | 130 | package 131 | 132 | single 133 | 134 | 135 | 136 | 137 | 138 | org.apache.maven.plugins 139 | maven-source-plugin 140 | 3.3.0 141 | 142 | 143 | attach-sources 144 | 145 | jar-no-fork 146 | 147 | 148 | 149 | 150 | 151 | org.apache.maven.plugins 152 | maven-javadoc-plugin 153 | 3.6.3 154 | 155 | 11 156 | 157 | 158 | 159 | attach-javadocs 160 | 161 | jar 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | com.beust 172 | jcommander 173 | 1.82 174 | 175 | 176 | net.masterthought 177 | cucumber-reporting 178 | 5.8.4 179 | 180 | 181 | 182 | -------------------------------------------------------------------------------- /src/main/java/net/masterthought/cucumber/sandwich/CucumberReportMonitor.java: -------------------------------------------------------------------------------- 1 | package net.masterthought.cucumber.sandwich; 2 | 3 | import java.io.File; 4 | import java.io.IOException; 5 | import java.util.ArrayList; 6 | import java.util.Arrays; 7 | import java.util.List; 8 | import java.util.stream.Collectors; 9 | 10 | import com.beust.jcommander.JCommander; 11 | import com.beust.jcommander.ParameterException; 12 | import org.apache.commons.io.monitor.FileAlterationListener; 13 | import org.apache.commons.io.monitor.FileAlterationListenerAdaptor; 14 | import org.apache.commons.io.monitor.FileAlterationMonitor; 15 | import org.apache.commons.io.monitor.FileAlterationObserver; 16 | 17 | import net.masterthought.cucumber.Configuration; 18 | import net.masterthought.cucumber.ReportBuilder; 19 | 20 | public class CucumberReportMonitor { 21 | 22 | public static void main(String[] args) throws Exception { 23 | 24 | SandwichParameters params = new SandwichParameters(); 25 | JCommander cmd = new JCommander(params); 26 | final long pollingInterval = 5 * 1000; 27 | 28 | try { 29 | cmd.parse(args); 30 | final File reportFolder = new File(params.getFolder()); 31 | final File outputFolder = new File(params.getOutDir()); 32 | createMonitorFolder(reportFolder); 33 | 34 | System.out.println("Starting Cucumber Sandwich....."); 35 | 36 | if (params.getWithoutListener()) { 37 | System.out.println("Running once only as -n flag supplied....."); 38 | generateReport(reportFolder, outputFolder); 39 | } else { 40 | System.out.println("Listening for change in folder: " + reportFolder.getAbsoluteFile()); 41 | FileAlterationObserver observer = new FileAlterationObserver(reportFolder); 42 | FileAlterationMonitor monitor = new FileAlterationMonitor(pollingInterval); 43 | FileAlterationListener listener = new FileAlterationListenerAdaptor() { 44 | 45 | @Override 46 | public void onFileCreate(File file) { 47 | try { 48 | System.out.println("File created: " + file.getCanonicalPath()); 49 | generateReport(reportFolder, outputFolder); 50 | } catch (Exception e) { 51 | e.printStackTrace(System.err); 52 | } 53 | } 54 | 55 | @Override 56 | public void onFileChange(File file) { 57 | try { 58 | System.out.println("File changed: " + file.getCanonicalPath()); 59 | generateReport(reportFolder, outputFolder); 60 | } catch (IOException e) { 61 | e.printStackTrace(System.err); 62 | } catch (Exception e) { 63 | e.printStackTrace(); 64 | } 65 | } 66 | }; 67 | 68 | observer.addListener(listener); 69 | monitor.addObserver(observer); 70 | monitor.start(); 71 | } 72 | } catch (ParameterException ex) { 73 | System.out.println(ex.getMessage()); 74 | cmd.usage(); 75 | } 76 | 77 | } 78 | 79 | private static List findJsonFiles(File targetDirectory) { 80 | File[] files = targetDirectory.listFiles(file -> file.isFile()); 81 | 82 | return Arrays.stream(files).map(File::getName).collect(Collectors.toList()); 83 | } 84 | 85 | private static void generateReport(File reportFolder, File outputFolder) throws Exception { 86 | File rd = new File(outputFolder + "/cucumber-html-reports"); 87 | List jsonFileList = findJsonReports(reportFolder); 88 | 89 | System.out.println("About to generate Cucumber Report into: " + rd.getAbsoluteFile()); 90 | 91 | Configuration configuration = new Configuration(rd, "cucumber-jvm"); 92 | 93 | ReportBuilder reportBuilder = new ReportBuilder(jsonFileList, configuration); 94 | reportBuilder.generateReports(); 95 | System.out.println("Finished generating Cucumber Report into: " + rd.getAbsoluteFile()); 96 | } 97 | 98 | private static List findJsonReports(File reportFolder) { 99 | List jsonFiles = findJsonFiles(reportFolder); 100 | List reports = new ArrayList<>(); 101 | 102 | System.out.println("Found json reports: " + jsonFiles.size()); 103 | String reportPath = reportFolder.getAbsolutePath(); 104 | for (String file : jsonFiles) { 105 | String reportJson = reportPath + "/" + file; 106 | System.out.println(reportJson); 107 | reports.add(reportJson); 108 | } 109 | return reports; 110 | } 111 | 112 | private static void createMonitorFolder(File reportFolder) { 113 | if (!reportFolder.exists()) { 114 | System.out.println("creating report directory: " + reportFolder.getAbsolutePath()); 115 | boolean result = reportFolder.mkdirs(); 116 | if (result) { 117 | System.out.println("created report directory: " + reportFolder.getAbsoluteFile()); 118 | } 119 | } 120 | } 121 | } 122 | -------------------------------------------------------------------------------- /src/main/java/net/masterthought/cucumber/sandwich/SandwichParameters.java: -------------------------------------------------------------------------------- 1 | package net.masterthought.cucumber.sandwich; 2 | 3 | import com.beust.jcommander.Parameter; 4 | 5 | /** 6 | * Collects parameters for the report generation. 7 | */ 8 | public class SandwichParameters { 9 | 10 | @Parameter(names = "-f", required = true, description = "Folder to monitor for cucumber.json report files") 11 | private String folder; 12 | 13 | @Parameter(names = "-o", required = true, description = "Output directory to generate the cucumber-html-reports into") 14 | private String outDir; 15 | 16 | @Parameter(names = "-n", required = false, description = "run once without file change listener") 17 | private Boolean withoutListener = false; 18 | 19 | public String getFolder() { 20 | return folder; 21 | } 22 | 23 | /** 24 | * Returns output directory. 25 | */ 26 | public String getOutDir() { 27 | return outDir; 28 | } 29 | 30 | /** 31 | * 32 | * @return 33 | */ 34 | public Boolean getWithoutListener() { 35 | return withoutListener; 36 | } 37 | } 38 | --------------------------------------------------------------------------------