Search code examples
javacucumberhtml-reports-jenkins

Run cucumber and generate html report without maven/gradle plugins


I am currently using cucumber and the masterthought plugin to generate html reports on test executions. I want to enable future flexibility to configure the cucumber options when running my tests from a gradle script as well as running the cucumber from java code without the need of using plugins on build script.

I have previously used the surefire plugin to run the cucumber and the masterthought plugin to generate the cucumber report


Solution

  • package com.my.domain;
    
    import java.io.File;
    import java.io.IOException;
    import java.nio.file.Files;
    import java.nio.file.Path;
    import java.nio.file.Paths;
    import java.util.ArrayList;
    import java.util.List;
    import java.util.Optional;
    
    import org.apache.commons.io.FileUtils;
    import org.apache.commons.io.FilenameUtils;
    import org.junit.runner.RunWith;
    import org.junit.runners.model.InitializationError;
    
    import cucumber.api.CucumberOptions;
    import cucumber.api.junit.Cucumber;
    import cucumber.runtime.RuntimeOptions;
    import cucumber.runtime.RuntimeOptionsFactory;
    import net.masterthought.cucumber.Configuration;
    import net.masterthought.cucumber.ReportBuilder;
    import net.masterthought.cucumber.Reportable;
    
    @RunWith(Cucumber.class)
    @CucumberOptions(
            plugin = {
                "json:build/path/cucumber.json" }, 
            features = {
                "src/main/resources/features" }, 
            glue = {
                "com.my.domain.stepdefinitions" }, 
            dryRun = false, 
            tags = {"@tag"}
    
    )
    public class CucumberJunitRunner {
        // TODO: Make Tags, Features, Glue, plugin runtime, and path configurable
        private static final String JSON_PLUGIN_PREFIX = "json:";
        private static final String PRECONFIGURED_REPORT_OUTPUT_FOLDER_NAME = "cucumber-html-reports";
        private static final Optional<String> REPORT_OUTPUT_FOLDER_LOCATION = Optional.ofNullable(null);
        private static final boolean SKIP_REPORT_GENERATION = false;
    
        public static void main(String[] args) throws InitializationError {
            RuntimeOptions cucumberRuntimeOptions = null;
            Optional<String> jsonPluginOutputLocation = Optional.empty();
            if(args.length > 0) {
                //TODO: USE ARGUMENTS TO INITIALIZE cucumberRuntimeOptions AND jsonPluginOutputLocation
            } else {
                RuntimeOptionsFactory cucumberRuntimeOptionsFactory = new RuntimeOptionsFactory(CucumberJunitRunner.class);
                cucumberRuntimeOptions = cucumberRuntimeOptionsFactory.create();
    
                jsonPluginOutputLocation = cucumberRuntimeOptions.getPluginFormatterNames().stream()
                        .filter(s -> s.startsWith(JSON_PLUGIN_PREFIX))
                        .map(s -> s.substring(JSON_PLUGIN_PREFIX.length())).findFirst();
                if( ! jsonPluginOutputLocation.isPresent() ) {
                    throw new RuntimeException(String.format(
                            "Could not find jsonPluginOutputLocation in plugins from cucumber options: %s",
                            cucumberRuntimeOptions.getPluginFormatterNames()));
                }
            }
    
            deletePreviousData(jsonPluginOutputLocation);
            runCucumber(cucumberRuntimeOptions, Thread.currentThread().getContextClassLoader());
    
            if (SKIP_REPORT_GENERATION) {
                System.out.println("Report generation skipped. No HTML report was built.");
            } else {
                if (cucumberRuntimeOptions.isDryRun()) {
                    System.out.println("Cucumber DryRun executed. No HTML report was built.");
                } else {
                    if (jsonPluginOutputLocation.isPresent()) {
                        Path jsonPluginOutputPath = Paths.get(jsonPluginOutputLocation.get());
                        if (Files.exists(jsonPluginOutputPath)) {
                            generateCucumberReport(
                                    REPORT_OUTPUT_FOLDER_LOCATION.orElse(
                                            FilenameUtils.getFullPathNoEndSeparator(jsonPluginOutputLocation.get())),
                                    jsonPluginOutputLocation.get(), "1", "My Project");
                        } else {
                            System.out.println("Cucumber JSON report was missing. No HTML report was built.");
                        }
                    } else {
                        System.out.println("Cucumber JSON plugin was missing. No HTML report was built.");
                    }
                }
            }
        }
    
        private static void deletePreviousData(Optional<String> jsonPluginOutputLocation) {
            Path jsonPluginOutputPath = Paths.get(jsonPluginOutputLocation.get());
            if (Files.exists(jsonPluginOutputPath)) {
                try {
                    Files.delete(jsonPluginOutputPath);
                    System.out.println("Cucumber JSON file was deleted: " +
                            jsonPluginOutputPath.toAbsolutePath().toString());
                } catch (IOException e) {
                    e.printStackTrace();
                }
            } else {
                System.out.println("Cucumber JSON file from previous execution was not detected: "
                        + jsonPluginOutputPath.toAbsolutePath().toString());
            }
    
            Path cucumberReportsFolder = jsonPluginOutputPath.resolveSibling(PRECONFIGURED_REPORT_OUTPUT_FOLDER_NAME);
            if (Files.exists(cucumberReportsFolder)) {
                try {
                    FileUtils.deleteDirectory(cucumberReportsFolder.toFile());
                    System.out.println("Cucumber JSON report was deleted: " + 
                            cucumberReportsFolder.toAbsolutePath().toString());
                } catch (IOException e) {
                    e.printStackTrace();
                }
            } else {
                System.out.println("Cucumber JSON report from previous execution was not detected: "
                        + cucumberReportsFolder.toAbsolutePath().toString());
            }
    
        }
    
        /**
         * Launches the Cucumber-JVM command line.
         *
         * @param argv        runtime options. See details in the
         *                    {@code cucumber.api.cli.Usage.txt} resource.
         * @param classLoader classloader used to load the runtime
         * @return 0 if execution was successful, 1 if it was not (test failures)
         */
        public static byte runCucumber(RuntimeOptions cucumberRuntimeOptions, ClassLoader classLoader) {
    
            final cucumber.runtime.Runtime runtime = cucumber.runtime.Runtime.builder()
                    .withRuntimeOptions(cucumberRuntimeOptions).withClassLoader(classLoader).build();
    
            runtime.run();
    
            return runtime.exitStatus();
        }
    
        private static void generateCucumberReport(String reportOutputDirectoryLocation, String cucumberJsonFile,
                String buildNumber, String projectName) {
    
            File reportOutputDirectory = new File(reportOutputDirectoryLocation);
            List<String> jsonFiles = new ArrayList<>();
            jsonFiles.add(cucumberJsonFile);
            // jsonFiles.add("cucumber-report-2.json");
    
            // String buildNumber = "1";
            // String projectName = "cucumberProject";
            boolean runWithJenkins = false;
    
            Configuration configuration = new Configuration(reportOutputDirectory, projectName);
            // optional configuration - check javadoc
            configuration.setRunWithJenkins(runWithJenkins);
            configuration.setBuildNumber(buildNumber);
            // addidtional metadata presented on main page
            // configuration.addClassifications("Platform", "Windows");
            // configuration.addClassifications("Browser", "Firefox");
            // configuration.addClassifications("Branch", "release/1.0");
    
            // optionally add metadata presented on main page via properties file
            //List<String> classificationFiles = new ArrayList<>();
            //classificationFiles.add("properties-1.properties");
            //classificationFiles.add("properties-2.properties");
            // configuration.addClassificationFiles(classificationFiles);
    
            ReportBuilder reportBuilder = new ReportBuilder(jsonFiles, configuration);
            Reportable result = reportBuilder.generateReports();
            // and here validate 'result' to decide what to do if report has failed
    
            if (result == null) {
                System.out.println("There was an isssue while building the report");
                System.exit(1);
            }
            System.out.println(result);
        }
    }