Giter Site home page Giter Site logo

prashant-ramcharan / courgette-jvm Goto Github PK

View Code? Open in Web Editor NEW
128.0 18.0 36.0 3.61 MB

Multiprocess | Parallel Cucumber-JVM | Parallelize your Java Cucumber tests on a feature level or on a scenario level.

License: MIT License

Java 90.87% Mustache 9.13%
parallel cucumber-jvm cucumber gherkin parallel-cucumber-jvm courgette-jvm failed-scenarios cucumber-features courgette-runner courgette-report

courgette-jvm's Introduction

Maven Central License: MIT

Courgette-JVM

Courgette-JVM is an extension of Cucumber-JVM with added capabilities to run cucumber tests in parallel on a feature level or on a scenario level. It also provides an option to automatically re-run failed scenarios.

Key Features

  • All features can be executed in parallel.
  • All scenarios can be executed in parallel.
  • Automatic re-run of failed scenarios.
  • Requires only 1 annotated class to run all feature files in parallel.
  • Single report generation for all executed features including embedded files (Json and Html reports)
  • Publishes a single Cucumber Report to https://reports.cucumber.io/ after parallel execution.
  • Single re-run file listing all failed scenarios that occurred during parallel execution.
  • Supports Cucumber-JVM 7
  • Supports JUnit and TestNG
  • Provides a Mobile Device Allocator to support parallel mobile testing on simulators and real devices.
  • Integrates with Slack to provide real time test results.
  • Integrates with Extent Reports to create interactive reports.
  • Integrates with Report Portal to support AI powered dashboards.
  • Integrates with Allure to generate test reports.
  • Can be used with Gradle and Maven.
  • Searchable and paginated Courgette-JVM Html Report which includes all step definitions, embedded screenshots, thrown exceptions, pie chart and Courgette run information. CourgetteJVM_Report.png

Minimum Requirements

  • Java 8

Installation

Maven

<dependency>
  <groupId>io.github.prashant-ramcharan</groupId>
  <artifactId>courgette-jvm</artifactId>
  <version>6.13.0</version>
</dependency>

Gradle

implementation group: 'io.github.prashant-ramcharan', name: 'courgette-jvm', version: '6.13.0'

Included Cucumber Dependencies

  • cucumber-core 7.16.1
  • cucumber-java 7.16.1
  • cucumber-java8 7.16.1
  • cucumber-junit 7.16.1
  • cucumber-testng 7.16.1

Usage

Example projects:

Courgette-JVM supports JUnit and TestNG to run cucumber features and scenarios in parallel. A JUnit runner class must be annotated with @RunWith(Courgette.class) and a TestNG runner class must extend TestNGCourgette.

  • threads : The number of concurrent threads to run cucumber features where each thread is started in an independant JVM process.

    • Example: If you have 10 cucumber features and you use 6 threads, 6 features would first run in parallel then the following 4 features would run in parallel.
  • runLevel : Options are CourgetteRunLevel.FEATURE or CourgetteRunLevel.SCENARIO

    • If set to feature level, all features would run in parallel. If set to scenario level, all scenarios would be run in parallel.
  • rerunFailedScenarios : If set to true, any failed scenario will be immediately re-run in the same thread. If the re-run succeeds, the initial failure will be ignored and not cause the build to fail.

    • When using CourgetteRunLevel.SCENARIO, only failed scenarios will be re-run.
    • When using CourgetteRunLevel.FEATURE, the entire feature (including all scenarios) will be re-run.
  • excludeFeatureFromRerun : If set, Courgette will prevent features from re-running when it fails.

    • Example: If excludeFeatureFromRerun = {Feature1.feature} and Feature1.feature and Feature2.feature both fail, Courgette will not re-run Feature1.feature but will re-run Feature2.feature. This is useful when you need to prevent a specific feature or scenario from re-running.
  • excludeTagFromRerun : If set, Courgette will prevent features and scenarios from re-running on failure when it finds a matching Cucumber tag.

    • Example: If excludeTagFromRerun = {@stable} and a test tagged with @stable fails, Courgette will not re-run that specific test but will continue to re-run other failing tests.
  • rerunAttempts : The number of re-run attempts for a failed scenario. (rerunFailedScenarios must be set to true)

  • testOutput : Redirects the output for each parallel test run.

    • CourgetteTestOutput.CONSOLE: Redirects the test output to the console.
    • CourgetteTestOutput.FILE: Redirects the test output to a file and saves it to ${reportTargetDir}/courgette-test-ouput
    • CourgetteTestOutput.DISCARD: All test output will be discarded.
  • reportTargetDir : Target directory where courgette-report is generated. Set to target by default.

  • generateCourgetteRunLog : If set to true, Courgette will generate a run log and save it to ${reportTargetDir}/courgette-run-{courgette_session_id}.json at the end of the test run.

  • plugin : Courgette supported plugins

    • reportportal: Allows the test results to be published to Report Portal at the end of the test run.
    • extentreports: Creates an interactive report based on the Extent Framework
    • mobile-device-allocator: Allows Courgette to track and allocate devices for mobile tests.
  • environmentInfo : Additional environment information that is displayed in the Courgette html report.

    • Each grouping must be separated by a ; character and adhere to the following format: key1=value1; key2=value2.
  • disableHtmlReport: If set, the Courgette and Cucumber html reports will not be generated at the end of the test run.

    • Options are HtmlReport.COURGETTE_HTML, HtmlReport.CUCUMBER_HTML and HtmlReport.COURGETTE_AND_CUCUMBER_HTML
  • persistParallelCucumberJsonReports: If set to true, Courgette will save the Cucumber json and ndjson reports for each parallel test to ${reportTargetDir}/session-reports/{session}

  • classPath: Allows a custom class path to be used when running tests.

    • The class path should point to: { "path-to-project-jars", "path-to-test-classes" }
  • slackWebhookUrl: The incoming webhook URL that Courgette uses to send messages to Slack.

  • slackChannel: The Slack channels that Courgette will post messages to.

  • slackTestId: A custom Slack identifier that will be sent with each message.

  • slackEventSubscription: The Courgette events to subscribe to that gets posted to Slack.

  • mobileDevice: The devices that Courgette will use to track and allocate for parallel mobile tests.

    • This option is required when using the CourgettePlugin.MOBILE_DEVICE_ALLOCATOR plugin.
  • mobileDeviceType: The mobile device types used for device allocation. This can be one of:

    • MobileDeviceType.SIMULATOR: Only simulator device names.
    • MobileDeviceType.REAL_DEVICE: Only real devices names, must match format deviceName:deviceUUID
    • MobileDeviceType.SIMULATOR_AND_REAL_DEVICE: Mixture of simulator and real device names.
  • realMobileDeviceTag: If set, Courgette will allocate a real mobile device for tests matching any one of the provided tags. To use this option, you must also specify mobileDeviceType as MobileDeviceType.REAL_DEVICE or MobileDeviceType.SIMULATOR_AND_REAL_DEVICE

  • fixedThreadDelay: A fixed time in milliseconds that Courgette will pause before the start of each feature or scenario.

  • randomThreadDelay: A random time in milliseconds that Courgette will pause before the start of each feature or scenario. Courgette will automatically set a random time between 0 and this value.

  • cucumberOptions : The standard cucumber options for specifying feature paths, glue, tags etc..

    • The publish cucumber option (supported from version 5.1.0) will publish a single cucumber report after parallel execution.
      • The published report link will be displayed in the console and saved to ${reportTargetDir}/cucumber-report-link.txt.
      • The published report link is also linked in the Courgette html report.
      • To keep the published report forever, provide a CUCUMBER_PUBLISH_TOKEN via a system property or an environment variable. You can get your token from https://reports.cucumber.io/profile

Additional

  • At the end of the test run, a single report ( if included in the cucumberOptions ) listing all executed features and scenarios will be created in the specified report path.

  • A courgette-rerun.txt file listing all failed scenarios will be created in the specified rerun plugin path or the target folder ( default )

  • A Courgette-JVM html report will be created in the reportTargetDir (defaulted to the target directory).

JUnit Runner
@RunWith(Courgette.class)
@CourgetteOptions(
        threads = 10,
        runLevel = CourgetteRunLevel.SCENARIO,
        rerunFailedScenarios = true,
        rerunAttempts = 1,
        testOutput = CourgetteTestOutput.CONSOLE,
        reportTitle = "Courgette-JVM Example",
        reportTargetDir = "build",
        environmentInfo = "browser=chrome; git_branch=master",
        cucumberOptions = @CucumberOptions(
                features = "src/test/resources/features",
                glue = "steps",
                tags = "@regression and not @bug",
                publish = true,
                plugin = {
                        "pretty",
                        "json:build/cucumber-report/cucumber.json",
                        "html:build/cucumber-report/cucumber.html",
                        "junit:build/cucumber-report/cucumber.xml"}
        ))
public class RegressionTestSuite {
}
TestNG Runner
@Test
@CourgetteOptions(
        threads = 10,
        runLevel = CourgetteRunLevel.SCENARIO,
        rerunFailedScenarios = true,
        rerunAttempts = 1,
        testOutput = CourgetteTestOutput.CONSOLE,
        reportTitle = "Courgette-JVM Example",
        reportTargetDir = "build",
        environmentInfo = "browser=chrome; git_branch=master",
        cucumberOptions = @CucumberOptions(
                features = "src/test/resources/features",
                glue = "steps",
                tags = "@regression and not @bug",
                publish = true,
                plugin = {
                        "pretty",
                        "json:build/cucumber-report/cucumber.json",
                        "html:build/cucumber-report/cucumber.html"}
        ))
public class RegressionTestSuite extends TestNGCourgette {
}

Gradle Build Task

tasks.withType(Test) {
    systemProperties = System.getProperties()
}

// JUnit
task regressionSuite(type: Test) {
    include '**/RegressionTestSuite.class'
    outputs.upToDateWhen { false }
}

// TestNG
task regressionSuite(type: Test) {
    useTestNG()
    include '**/RegressionTestSuite.class'
    outputs.upToDateWhen { false }
}

Override Runner Options

To override the hard-coded courgette options (threads, runLevel, rerunFailedScenarios, reportTargetDir, environmentInfo) set in the runner class, you can provide system properties to the gradle or maven task.

[gradle | mvn] test -Dcourgette.threads=2 -Dcourgette.runLevel=FEATURE -Dcourgette.rerunFailedScenarios=false -Dcourgette.reportTargetDir=build -Dcourgette.environmentInfo="git_branch=master; platform=ci"

To override the hard-coded cucumber options (tags, glue, plugin, name, junit) set in the runner class, you can provide comma separated system properties to the gradle task.

[gradle | mvn] test -Dcucumber.tags="@regression and not @bug" -Dcucumber.glue="steps, hooks"

To specify non standard VM options (-X options)

[gradle | mvn] test -Dcourgette.vmoptions="-Xms256m -Xmx512m"

JUnit Callbacks

You can add global setup and tear-down code to your Courgette test runner using the @CourgetteBeforeAll and @CourgetteAfterAll annotations. For example:

@RunWith(Courgette.class)
@CourgetteOptions(/* Your Courgette options here... */)
public class RegressionTestSuite {
    @CourgetteBeforeAll
    public static void setUp() {
        System.out.println("I will run before any tests execute");
    }
    
    @CourgetteAfterAll
    public static void tearDown() {
        System.out.println("I will run after all of the tests execute");
    }
}

You can add any number of annotated methods to your test suite class. If you need your callbacks to run in a specific order, pass order to the annotation: @CourgetteBeforeAll(order = 2).

Courgette Run Information

You can access test statistics and additional run information if you need to analyze or perform extra tasks before or after the parallel test run.

Note: CourgetteRunInfo can only be accessed from a Courgette runner class.

JUnit Runner

@RunWith(Courgette.class)
@CourgetteOptions(/* Your Courgette options here... */)
public class RegressionTestSuite {

    @CourgetteBeforeAll
    public static void beforeRun() {
        System.out.println("Starting Courgette parallel run: " + CourgetteRunInfo.sessionId());
    }

    @CourgetteAfterAll
    public static void afterRun() {
      if (CourgetteRunInfo.testStatistics().hasFailures()) {
        // do something extra here
      }
    }
}

TestNG Runner

@Test
@CourgetteOptions(/* Your Courgette options here... */)
public class RegressionTestSuite extends TestNGCourgette {

    @BeforeTest
    public static void beforeRun() {
        System.out.println("Starting Courgette parallel run: " + CourgetteRunInfo.sessionId());
    }

    @AfterTest
    public static void afterRun() {
        if (CourgetteRunInfo.testStatistics().hasFailures()) {
            // do something extra here
        }
    }
}

Retrieve the Courgette Thread ID and Name

System.getProperty("courgette.threadId")
        
System.getProperty("courgette.threadName")

Slack Integration

Courgette allows real time test results and events to be posted to Slack as tests are run.

To enable this feature, add the following Courgette options to the Courgette runner:

@CourgetteOptions(
      ...
      slackWebhookUrl = "https://hooks.slack.com/services/your-slack-url",
      slackChannel = {"channel1", "channel2"},
      slackTestId = "Production test - Build 1.0.0",
      slackEventSubscription = {CourgetteEvent.ALL},
      cucumberOptions = @CucumberOptions(
      // cucumber options here
      )
)

Slack Incoming Webhook URL

You need to create an incoming webhook URL to allow Courgette to post messages to your Slack application.

https://api.slack.com/messaging/webhooks#create_a_webhook

Event Subscription

You can subscribe to single or multiple Courgette events. When events are triggered as the tests run, Courgette will post a message to the Slack channels defined in the runner.

  • ALL
  • TEST_RUN_STARTED
  • TEST_RUN_FINISHED
  • TEST_PASSED
  • TEST_PASSED_AFTER_RERUN
  • TEST_FAILED
  • TEST_RERUN
  • TEST_RUN_SUMMARY

CourgetteJVM_Slack.png

Report Portal Integration

Courgette allows test results to be published in real time to the Report Portal server as tests run.

To enable this feature, add the following Courgette option to the Courgette runner:

@CourgetteOptions(
      ...  
      plugin = { CourgettePlugin.REPORT_PORTAL },
      cucumberOptions = @CucumberOptions(
      // cucumber options here
      )
)

You must have the reportportal.properties file in your classpath and the following properties must be defined:

# Report Portal server (mandatory)
rp.endpoint = http://localhost:8080

# Report Portal project (mandatory)
rp.project = courgette_example

# Report Portal API access token (mandatory)
rp.apitoken = a1e5ee78-317c-477d-b27e-f174c562aedc

# Report Portal launch name (optional)
rp.launch = My Demo Project

# Report Portal test suite (optional)
rp.testsuite = Regression Test Suite

# Report Portal launch attributes (optional)
# Each attribute must be separated by ';'
rp.attributes = suite:regression;build:12345

Note: Any property other than those defined above will be ignored by Courgette.

An API access token is required to allow Courgette to publish the report. To obtain an API access token, log in to Report Portal UI and navigate to http://localhost:8080/ui/#api -> UAT -> sso-endpoint -> Get api token

After the test run is complete, the test results will be published to the Report Portal server.

CourgetteJVM_ReportPortal.png

Extent Reports Integration

Courgette allows the creation of interactive reports using the Extent Reports Courgette plugin.

To enable this feature, add the following Courgette option to the Courgette runner:

@CourgetteOptions(
      ...  
      plugin = { CourgettePlugin.EXTENT_REPORTS },
      cucumberOptions = @CucumberOptions(
      // cucumber options here
      )
)

At the end of the test run the report will be saved to ${reportTargetDir}/courgette-extentreports

To configure custom reports (i.e. change the report name or theme) you should create the extent-config.xml file in the classpath. Courgette will load this XML config when it builds the report. If this file is not provided then default values will be used. View an example here

CourgetteJVM_ExtentReports.png

Allure Integration

Courgette allows the generation of Allure reports using the Allure Cucumber plugin.

@CourgetteOptions(
      ...
      cucumberOptions = @CucumberOptions(
         plugin = {
            "io.qameta.allure.cucumber7jvm.AllureCucumber7Jvm"
         }
      )
)

CourgetteJVM-AllureReport.png

Courgette Mobile Device Allocator

Courgette provides a mobile device allocator to allocate and keep track of devices for parallel mobile testing. Courgette keeps track of devices that are currently in use and automatically allocates a free device for each test.

@CourgetteOptions(
        ...
        plugin = { CourgettePlugin.MOBILE_DEVICE_ALLOCATOR },
        mobileDeviceType = MobileDeviceType.SIMULATOR,
        mobileDevice = {
                "iPhone 8",
                "iPhone 12",
                "iPhone 13"
        },
        cucumberOptions = @CucumberOptions(
        // cucumber options here
        )
)

The Courgette mobile device allocator plugin will:

  • Create a pool of devices based on mobileDevice and will automatically allocate a randomly selected available device for each parallel test.
  • Determine the optimal parallel threads based on the sum of devices defined in mobileDevice. The sum of mobileDevice will take precedence over threads defined in the Courgette runner.
  • Expose the device name, parallel port and uuid (if provided) during the runtime of each parallel test.
  • If mobileDeviceType is SIMULATOR_AND_REAL_DEVICE then Courgette will allocate a real device for tests tagged with any matching tag defined in Courgette option realMobileDeviceTag and allocate a simulator for all other tests.

Notes:

  • Each mobileDevice must be unique unless using real devices where a UUID is also required.
  • Courgette will remove any duplicate devices if detected.
  • Courgette will allocate a randomly selected device for every test run. Specific device allocation cannot be guaranteed per test.

How to integrate Courgette Mobile Device Allocator

  • CourgetteMobileDeviceAllocator.DEVICE_NAME returns one of the available devices from the mobileDevice list.
  • CourgetteMobileDeviceAllocator.UDID returns the UUID for the device (only required for real devices).
  • CourgetteMobileDeviceAllocator.PARALLEL_PORT returns a free local port (required for parallel device testing).

The above properties are only available when running tests using a Courgette runner with the CourgettePlugin.MOBILE_DEVICE_ALLOCATOR plugin.

iOS Appium Test Configuration

DesiredCapabilities capabilities = new DesiredCapabilities();
capabilities.setCapability("deviceName", CourgetteMobileDeviceAllocator.DEVICE_NAME); 
capabilities.setCapability("udid", CourgetteMobileDeviceAllocator.UDID); 
capabilities.setCapability("wdaLocalPort", CourgetteMobileDeviceAllocator.PARALLEL_PORT);

Android Appium Test Configuration

DesiredCapabilities capabilities = new DesiredCapabilities();
capabilities.setCapability("avd", CourgetteMobileDeviceAllocator.DEVICE_NAME); 
capabilities.setCapability("udid", CourgetteMobileDeviceAllocator.UDID); 
capabilities.setCapability("systemPort", CourgetteMobileDeviceAllocator.PARALLEL_PORT);

SauceLabs Appium Test Configuration

MutableCapabilities capabilities = new MutableCapabilities();
capabilities.setCapability("appium:deviceName", CourgetteMobileDeviceAllocator.DEVICE_NAME);

BrowserStack Appium Test Configuration

DesiredCapabilities capabilities = new DesiredCapabilities();
capabilities.setCapability("device", CourgetteMobileDeviceAllocator.DEVICE_NAME);

Pass Mobile Devices at Runtime

[mvn | gradle] test -Dcourgette.mobileDevice="iPhone X, iPhone 12, iPhone 13"

Using Real Devices

Unlike simulators where the device name must be unique, on real devices you can specify the same device name as long as the UUIDs are different for each device.

Format: deviceName:deviceUUID

mobileDevice = {
     "iPhone 8:00000000-000-0000-0000-000000000001",
     "iPhone 8:00000000-000-0000-0000-000000000002",
     "iPhone 8:00000000-000-0000-0000-000000000003"
}

Limitations and Known Issues

  • Each feature / scenario is run using the Cucumber CLI and because of this JUnit is not notified off the result whilst the tests are being executed.

Submitting Issues

For any issues or requests, please submit here

courgette-jvm's People

Contributors

prashant-ramcharan avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

courgette-jvm's Issues

Tests not running in parallel, and provided tags are ignored

Hi,

I'm not able to run the scenarios in parallel. And while running sequentially, the tags I've provided is neglected. Below is my runner class.

import courgette.api.CourgetteOptions;
import courgette.api.CourgetteRunLevel;
import courgette.api.junit.Courgette;
import cucumber.api.CucumberOptions;
import org.junit.runner.RunWith;

@RunWith(Courgette.class)
@CourgetteOptions(
        threads = 3,
        runLevel = CourgetteRunLevel.SCENARIO,
        rerunFailedScenarios = true,
        showTestOutput = true,
        reportTargetDir = "results/reports",
        cucumberOptions = @CucumberOptions(
                features = "src/test/features"
                , tags = {"@id=login01"}
                , glue = "com.org.steps"
                , plugin = {
                        "pretty",
                        "html:results/reports/html",
                        "json:results/reports/json/cucumber.json"}
        ))
public class ScenarioRunner {
}

Is there anyway I could know 3 threads are running, because I want to make sure the issue is not on my Selenium Grid.
With the above runner configuration, only the login scenario should be run, but the whole suite is run instead.
Let me know if you need more details.

buid.gradle file

group 'qb'
version '1.0-SNAPSHOT'

apply plugin: 'java'

sourceCompatibility = 1.8

repositories {
    mavenCentral()
    jcenter()
}

dependencies {
    compile 'org.codehaus.groovy:groovy-all:2.3.11'
    testCompile group: 'junit', name: 'junit', version: '4.12'
    // https://mvnrepository.com/artifact/io.appium/java-client
    compile group: 'io.appium', name: 'java-client', version: '5.0.4'
    // https://mvnrepository.com/artifact/org.seleniumhq.selenium/selenium-java
    compile group: 'org.seleniumhq.selenium', name: 'selenium-java', version: '3.11.0'
    compile group: 'org.seleniumhq.selenium', name: 'selenium-server', version: '3.6.0'
    // https://mvnrepository.com/artifact/commons-io/commons-io
    compile group: 'commons-io', name: 'commons-io', version: '2.6'
    // https://mvnrepository.com/artifact/org.apache.logging.log4j/log4j-core
    compile group: 'org.apache.logging.log4j', name: 'log4j-core', version: '2.10.0'

    // Courgette
    testCompile 'io.github.prashant-ramcharan:courgette-jvm:2.4.0'
    testCompile 'io.github.prashant-ramcharan:webdriver-binary-downloader:1.2.2'
}

tasks.withType(Test) {
    systemProperties = System.getProperties()
}

task runScenarios(type: Test) {
    include '**/suites/ScenarioRunner.class'
    outputs.upToDateWhen { false }
}

There seems to be just one thread running.

In your example project, I observed that there is always just 1 thread running.
I added this line of code in your step definition -

@when("I navigate to Stack Overflow question page (\d+)")
public void navigateToStackOverflowQuestionPage(Integer page) {
System.out.println("THREAD NUMBER " + Thread.currentThread().getId());
driver.navigate().to("https://stackoverflow.com/questions?page=" + page);
}

In the output, I always see THREAD NUMBER: 1 for all scenarios. I thought if the project uses multiple threads for execution, if we set threads to 10.

Am I missing anything?

P. S. I need to access the different thread IDs for some processing.

JUnit Progress?

Hi Prashant,

I am wondering how much progress you've made integrating courgette-jvm with JUnit notifier, if you have any plans to tackle it at all?
I'm looking to use your tool but am lacking for a summary view with more detail than the feature level view that is already included. Before I begin looking at solutions, I was curious which avenues you may have already explored.
Thanks for your hard work!

CourgetteRunner throws exception when no features/scenarios match the provided tag

The behavior of the default CucumberRunner is to return success when no features/scenarios are run for the provided tags; however, the CourgetteRunner throws an IllegalArgumentException when no scenarios/features match the provided tags and causes the test run to fail.

Specifically, the problem is in the following line in the CourgetteRunner run() method:

final ExecutorService executor = Executors.newFixedThreadPool(optimizedThreadCount());

In this case, the optimizedThreadCount() method is returning 0 Threads, which causes the exception.

Ideally the ExecutorService would only be initialized if there are tests that need to be run (e.g. there are features/scenarios that match the provided tags)

initializationError

Hi prashant,
I just upgraded to version 2.3.2 and my scenarios are passing but at the end of the run
I get the following error
java.lang.StringIndexOutOfBoundsException: start 0, end -1, length 0 at java.base/java.lang.AbstractStringBuilder.checkRangeSIOOBE(AbstractStringBuilder.java:1698) at java.base/java.lang.AbstractStringBuilder.substring(AbstractStringBuilder.java:991) at java.base/java.lang.StringBuilder.substring(StringBuilder.java:77) at courgette.runtime.report.JsonReportParser.addStepRowData(JsonReportParser.java:218) at courgette.runtime.report.JsonReportParser.lambda$addSteps$2(JsonReportParser.java:163) at java.base/java.util.ArrayList$Itr.forEachRemaining(ArrayList.java:927) at courgette.runtime.report.JsonReportParser.addSteps(JsonReportParser.java:144) at courgette.runtime.report.JsonReportParser.lambda$parseJsonReport$1(JsonReportParser.java:135) at java.base/java.util.ArrayList.forEach(ArrayList.java:1378) at courgette.runtime.report.JsonReportParser.parseJsonReport(JsonReportParser.java:135) at courgette.runtime.report.JsonReportParser.getReportFeatures(JsonReportParser.java:49) at courgette.runtime.CourgetteHtmlReporter.generateHtmlReport(CourgetteHtmlReporter.java:59) at courgette.runtime.CourgetteHtmlReporter.create(CourgetteHtmlReporter.java:51) at courgette.runtime.CourgetteRunner.createCourgetteReport(CourgetteRunner.java:129) at courgette.api.junit.Courgette.run(Courgette.java:89) at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassExecutor.runTestClass(JUnitTestClassExecutor.java:116) at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassExecutor.execute(JUnitTestClassExecutor.java:59) at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassExecutor.execute(JUnitTestClassExecutor.java:39) at org.gradle.api.internal.tasks.testing.junit.AbstractJUnitTestClassProcessor.processTestClass(AbstractJUnitTestClassProcessor.java:66) at org.gradle.api.internal.tasks.testing.SuiteTestClassProcessor.processTestClass(SuiteTestClassProcessor.java:51) at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.base/java.lang.reflect.Method.invoke(Method.java:564) at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:35) at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24) at org.gradle.internal.dispatch.ContextClassLoaderDispatch.dispatch(ContextClassLoaderDispatch.java:32) at org.gradle.internal.dispatch.ProxyDispatchAdapter$DispatchingInvocationHandler.invoke(ProxyDispatchAdapter.java:93) at com.sun.proxy.$Proxy1.processTestClass(Unknown Source) at org.gradle.api.internal.tasks.testing.worker.TestWorker.processTestClass(TestWorker.java:109) at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.base/java.lang.reflect.Method.invoke(Method.java:564) at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:35) at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24) at org.gradle.internal.remote.internal.hub.MessageHubBackedObjectConnection$DispatchWrapper.dispatch(MessageHubBackedObjectConnection.java:146) at org.gradle.internal.remote.internal.hub.MessageHubBackedObjectConnection$DispatchWrapper.dispatch(MessageHubBackedObjectConnection.java:128) at org.gradle.internal.remote.internal.hub.MessageHub$Handler.run(MessageHub.java:404) at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:63) at org.gradle.internal.concurrent.ManagedExecutorImpl$1.run(ManagedExecutorImpl.java:46) at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1135) at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635) at org.gradle.internal.concurrent.ThreadFactoryImpl$ManagedThreadRunnable.run(ThreadFactoryImpl.java:55) at java.base/java.lang.Thread.run(Thread.java:844)

it looks this occurs during the generation of the report. Any idea how to fix this?

Failed Assertions are not marking the scenario step as failed when put within try/catch block.

I want my tests to continue even when the assertion fails so that rest of them could be validated. So I put them within the try/catch block as shown below:

try {
Assert.assertEquals(actualProjectName.toLowerCase(), projectName.toLowerCase(), "Verifying project approver on projects page "+"Actual: "+actualProjectName+"|| Expected: "+projectName);
}
catch(AssertionError e) {
logger.error("Failed to verify project name");
e.printStackTrace(); }

BUT the Courgette-JVM report shows as the step as Passed, even when there is a failure.

Debug

maybe I'm doing something wrong, but how can I debug mvn test project when Courgett runner is connected? For example in IDEA

each scenario runs twice courgette-jvm

apply plugin: 'groovy'
apply plugin: 'java'
apply plugin: 'idea'
apply plugin: 'maven'

buildscript {
repositories {
mavenCentral()
}

}

sourceSets {
main {
java {
srcDirs = ['src/acceptance_test_framework']
}
resources {}
}

test {
    java {
        srcDirs = ['src/acceptance_tests']
    }
    resources {}
}

}

repositories {
mavenCentral()
jcenter()
}

dependencies {

compile 'io.github.prashant-ramcharan:courgette-jvm:2.4.0'

compile group: 'org.seleniumhq.selenium', name: 'selenium-java', version: '2.41.0'
compile group: 'io.rest-assured', name: 'rest-assured', version: '3.1.0'
compile group: 'com.googlecode.json-simple', name: 'json-simple', version: '1.1'

}
tasks.withType(Test) {
systemProperties = System.getProperties()
}

// JUnit
task regressionSuite(type: Test) {
include 'ScenarioSuite.class'

outputs.upToDateWhen { false }

}

Getting following error in jenkins for publish selenium html reports

Publishing Selenium report...
Copying the reports.
parsing resultFile courgette-report/courgette.html/index.html
Unable to parse courgette-report/courgette.html/index.html: java.io.IOException: org.xml.sax.SAXParseException; systemId: file:/jenkins/jobs/***/builds/156/seleniumReports/courgette-report/courgette.html/index.html; lineNumber: 10; columnNumber: 5; The element type "link" must be terminated by the matching end-tag "".
parsing resultFile reports/tests/index.html
Unable to parse reports/tests/index.html: java.io.IOException: org.xml.sax.SAXParseExceptionpublicId: -//W3C//DTD HTML 4.01//EN; systemId: http://www.w3.org/TR/html4/strict.dtd; lineNumber: 81; columnNumber: 5; The declaration for the entity "ContentType" must end with '>'.
Set result to FAILURE

Android App Build gradle, task won't run

System information
High Sierra 10.13.5
Gradle Wrapper 4.4
Android Studio 3.1.3

Hello, great work, I appreciate your plugin.

I am trying to run this in the build.gradle of the app to do unit testing inside the Android app in Android Studio, but I keep running into this issue.

Could not determine the dependencies of task ':app:runAndroid8inchTestsUsingJUnit'.

java.lang.NullPointerException (no error message)

I have the task setup inside the Gradle file just like your example, it worked well on regular InteliJ but it is not working in Android studio, is this do the fact that it needs the Java plugin to work?

StackTrace

  • Exception is:
    org.gradle.api.internal.tasks.TaskDependencyResolveException: Could not determine the dependencies of task ':app:runAndroid8inchTestsUsingJUnit'.
    at org.gradle.api.internal.tasks.CachingTaskDependencyResolveContext.getDependencies(CachingTaskDependencyResolveContext.java:62)
    at org.gradle.execution.taskgraph.DefaultTaskExecutionPlan.addToTaskGraph(DefaultTaskExecutionPlan.java:168)
    at org.gradle.execution.taskgraph.DefaultTaskExecutionGraph.addTasks(DefaultTaskExecutionGraph.java:114)
    at org.gradle.execution.TaskNameResolvingBuildConfigurationAction.configure(TaskNameResolvingBuildConfigurationAction.java:47)
    at org.gradle.execution.DefaultBuildConfigurationActionExecuter.configure(DefaultBuildConfigurationActionExecuter.java:48)
    at org.gradle.execution.DefaultBuildConfigurationActionExecuter.access$000(DefaultBuildConfigurationActionExecuter.java:25)
    at org.gradle.execution.DefaultBuildConfigurationActionExecuter$1.proceed(DefaultBuildConfigurationActionExecuter.java:54)
    at org.gradle.execution.DefaultTasksBuildExecutionAction.configure(DefaultTasksBuildExecutionAction.java:44)
    at org.gradle.execution.DefaultBuildConfigurationActionExecuter.configure(DefaultBuildConfigurationActionExecuter.java:48)
    at org.gradle.execution.DefaultBuildConfigurationActionExecuter.access$000(DefaultBuildConfigurationActionExecuter.java:25)
    at org.gradle.execution.DefaultBuildConfigurationActionExecuter$1.proceed(DefaultBuildConfigurationActionExecuter.java:54)
    at org.gradle.execution.ExcludedTaskFilteringBuildConfigurationAction.configure(ExcludedTaskFilteringBuildConfigurationAction.java:47)
    at org.gradle.execution.DefaultBuildConfigurationActionExecuter.configure(DefaultBuildConfigurationActionExecuter.java:48)
    at org.gradle.execution.DefaultBuildConfigurationActionExecuter.select(DefaultBuildConfigurationActionExecuter.java:36)
    at org.gradle.initialization.DefaultGradleLauncher$CalculateTaskGraph.run(DefaultGradleLauncher.java:287)
    at org.gradle.internal.operations.DefaultBuildOperationExecutor$RunnableBuildOperationWorker.execute(DefaultBuildOperationExecutor.java:317)
    at org.gradle.internal.operations.DefaultBuildOperationExecutor$RunnableBuildOperationWorker.execute(DefaultBuildOperationExecutor.java:309)
    at org.gradle.internal.operations.DefaultBuildOperationExecutor.execute(DefaultBuildOperationExecutor.java:185)
    at org.gradle.internal.operations.DefaultBuildOperationExecutor.run(DefaultBuildOperationExecutor.java:97)
    at org.gradle.internal.operations.DelegatingBuildOperationExecutor.run(DelegatingBuildOperationExecutor.java:31)
    at org.gradle.initialization.DefaultGradleLauncher.constructTaskGraph(DefaultGradleLauncher.java:183)
    at org.gradle.initialization.DefaultGradleLauncher.doBuildStages(DefaultGradleLauncher.java:136)
    at org.gradle.initialization.DefaultGradleLauncher.executeTasks(DefaultGradleLauncher.java:115)
    at org.gradle.internal.invocation.GradleBuildController$1.call(GradleBuildController.java:77)
    at org.gradle.internal.invocation.GradleBuildController$1.call(GradleBuildController.java:74)
    at org.gradle.internal.work.DefaultWorkerLeaseService.withLocks(DefaultWorkerLeaseService.java:152)
    at org.gradle.internal.work.StopShieldingWorkerLeaseService.withLocks(StopShieldingWorkerLeaseService.java:38)
    at org.gradle.internal.invocation.GradleBuildController.doBuild(GradleBuildController.java:96)
    at org.gradle.internal.invocation.GradleBuildController.run(GradleBuildController.java:74)
    at org.gradle.tooling.internal.provider.ExecuteBuildActionRunner.run(ExecuteBuildActionRunner.java:28)
    at org.gradle.launcher.exec.ChainingBuildActionRunner.run(ChainingBuildActionRunner.java:35)
    at org.gradle.tooling.internal.provider.ValidatingBuildActionRunner.run(ValidatingBuildActionRunner.java:32)
    at org.gradle.launcher.exec.RunAsBuildOperationBuildActionRunner$3.run(RunAsBuildOperationBuildActionRunner.java:47)
    at org.gradle.internal.operations.DefaultBuildOperationExecutor$RunnableBuildOperationWorker.execute(DefaultBuildOperationExecutor.java:317)
    at org.gradle.internal.operations.DefaultBuildOperationExecutor$RunnableBuildOperationWorker.execute(DefaultBuildOperationExecutor.java:309)
    at org.gradle.internal.operations.DefaultBuildOperationExecutor.execute(DefaultBuildOperationExecutor.java:185)
    at org.gradle.internal.operations.DefaultBuildOperationExecutor.run(DefaultBuildOperationExecutor.java:97)
    at org.gradle.internal.operations.DelegatingBuildOperationExecutor.run(DelegatingBuildOperationExecutor.java:31)
    at org.gradle.launcher.exec.RunAsBuildOperationBuildActionRunner.run(RunAsBuildOperationBuildActionRunner.java:43)
    at org.gradle.tooling.internal.provider.SubscribableBuildActionRunner.run(SubscribableBuildActionRunner.java:51)
    at org.gradle.launcher.exec.InProcessBuildActionExecuter$1.transform(InProcessBuildActionExecuter.java:50)
    at org.gradle.launcher.exec.InProcessBuildActionExecuter$1.transform(InProcessBuildActionExecuter.java:46)
    at org.gradle.composite.internal.DefaultRootBuildState.run(DefaultRootBuildState.java:65)
    at org.gradle.launcher.exec.InProcessBuildActionExecuter.execute(InProcessBuildActionExecuter.java:46)
    at org.gradle.launcher.exec.InProcessBuildActionExecuter.execute(InProcessBuildActionExecuter.java:32)
    at org.gradle.launcher.exec.BuildTreeScopeBuildActionExecuter.execute(BuildTreeScopeBuildActionExecuter.java:39)
    at org.gradle.launcher.exec.BuildTreeScopeBuildActionExecuter.execute(BuildTreeScopeBuildActionExecuter.java:25)
    at org.gradle.tooling.internal.provider.ContinuousBuildActionExecuter.execute(ContinuousBuildActionExecuter.java:80)
    at org.gradle.tooling.internal.provider.ContinuousBuildActionExecuter.execute(ContinuousBuildActionExecuter.java:53)
    at org.gradle.tooling.internal.provider.ServicesSetupBuildActionExecuter.execute(ServicesSetupBuildActionExecuter.java:62)
    at org.gradle.tooling.internal.provider.ServicesSetupBuildActionExecuter.execute(ServicesSetupBuildActionExecuter.java:34)
    at org.gradle.tooling.internal.provider.GradleThreadBuildActionExecuter.execute(GradleThreadBuildActionExecuter.java:36)
    at org.gradle.tooling.internal.provider.GradleThreadBuildActionExecuter.execute(GradleThreadBuildActionExecuter.java:25)
    at org.gradle.tooling.internal.provider.ParallelismConfigurationBuildActionExecuter.execute(ParallelismConfigurationBuildActionExecuter.java:43)
    at org.gradle.tooling.internal.provider.ParallelismConfigurationBuildActionExecuter.execute(ParallelismConfigurationBuildActionExecuter.java:29)
    at org.gradle.tooling.internal.provider.StartParamsValidatingActionExecuter.execute(StartParamsValidatingActionExecuter.java:59)
    at org.gradle.tooling.internal.provider.StartParamsValidatingActionExecuter.execute(StartParamsValidatingActionExecuter.java:31)
    at org.gradle.tooling.internal.provider.SessionFailureReportingActionExecuter.execute(SessionFailureReportingActionExecuter.java:59)
    at org.gradle.tooling.internal.provider.SessionFailureReportingActionExecuter.execute(SessionFailureReportingActionExecuter.java:44)
    at org.gradle.tooling.internal.provider.SetupLoggingActionExecuter.execute(SetupLoggingActionExecuter.java:46)
    at org.gradle.tooling.internal.provider.SetupLoggingActionExecuter.execute(SetupLoggingActionExecuter.java:30)
    at org.gradle.launcher.daemon.server.exec.ExecuteBuild.doBuild(ExecuteBuild.java:67)
    at org.gradle.launcher.daemon.server.exec.BuildCommandOnly.execute(BuildCommandOnly.java:36)
    at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:122)
    at org.gradle.launcher.daemon.server.exec.WatchForDisconnection.execute(WatchForDisconnection.java:37)
    at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:122)
    at org.gradle.launcher.daemon.server.exec.ResetDeprecationLogger.execute(ResetDeprecationLogger.java:26)
    at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:122)
    at org.gradle.launcher.daemon.server.exec.RequestStopIfSingleUsedDaemon.execute(RequestStopIfSingleUsedDaemon.java:34)
    at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:122)
    at org.gradle.launcher.daemon.server.exec.ForwardClientInput$2.call(ForwardClientInput.java:74)
    at org.gradle.launcher.daemon.server.exec.ForwardClientInput$2.call(ForwardClientInput.java:72)
    at org.gradle.util.Swapper.swap(Swapper.java:38)
    at org.gradle.launcher.daemon.server.exec.ForwardClientInput.execute(ForwardClientInput.java:72)
    at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:122)
    at org.gradle.launcher.daemon.server.exec.LogAndCheckHealth.execute(LogAndCheckHealth.java:55)
    at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:122)
    at org.gradle.launcher.daemon.server.exec.LogToClient.doBuild(LogToClient.java:62)
    at org.gradle.launcher.daemon.server.exec.BuildCommandOnly.execute(BuildCommandOnly.java:36)
    at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:122)
    at org.gradle.launcher.daemon.server.exec.EstablishBuildEnvironment.doBuild(EstablishBuildEnvironment.java:82)
    at org.gradle.launcher.daemon.server.exec.BuildCommandOnly.execute(BuildCommandOnly.java:36)
    at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:122)
    at org.gradle.launcher.daemon.server.exec.StartBuildOrRespondWithBusy$1.run(StartBuildOrRespondWithBusy.java:50)
    at org.gradle.launcher.daemon.server.DaemonStateCoordinator$1.run(DaemonStateCoordinator.java:295)
    at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:63)
    at org.gradle.internal.concurrent.ManagedExecutorImpl$1.run(ManagedExecutorImpl.java:46)
    at org.gradle.internal.concurrent.ThreadFactoryImpl$ManagedThreadRunnable.run(ThreadFactoryImpl.java:55)
    Caused by: java.lang.NullPointerException
    at org.gradle.api.tasks.testing.Test.getCandidateClassFiles(Test.java:1059)
    at org.gradle.api.tasks.testing.Test_Decorated.getCandidateClassFiles(Unknown Source)
    at org.gradle.api.tasks.testing.Test$1.call(Test.java:164)
    at org.gradle.api.tasks.testing.Test$1.call(Test.java:161)
    at org.gradle.util.GUtil.uncheckedCall(GUtil.java:458)
    at org.gradle.api.internal.file.collections.BuildDependenciesOnlyFileCollectionResolveContext.add(BuildDependenciesOnlyFileCollectionResolveContext.java:73)
    at org.gradle.api.internal.file.collections.BuildDependenciesOnlyFileCollectionResolveContext.add(BuildDependenciesOnlyFileCollectionResolveContext.java:75)
    at org.gradle.api.internal.tasks.TaskPropertyFileCollection.visitContents(TaskPropertyFileCollection.java:53)
    at org.gradle.api.internal.file.CompositeFileCollection.visitDependencies(CompositeFileCollection.java:187)
    at org.gradle.api.internal.tasks.CachingTaskDependencyResolveContext$TaskGraphImpl.getNodeValues(CachingTaskDependencyResolveContext.java:89)
    at org.gradle.internal.graph.CachingDirectedGraphWalker$GraphWithEmpyEdges.getNodeValues(CachingDirectedGraphWalker.java:211)
    at org.gradle.internal.graph.CachingDirectedGraphWalker.doSearch(CachingDirectedGraphWalker.java:121)
    at org.gradle.internal.graph.CachingDirectedGraphWalker.findValues(CachingDirectedGraphWalker.java:73)
    at org.gradle.api.internal.tasks.CachingTaskDependencyResolveContext.doGetDependencies(CachingTaskDependencyResolveContext.java:76)
    at org.gradle.api.internal.tasks.CachingTaskDependencyResolveContext.getDependencies(CachingTaskDependencyResolveContext.java:60)
    ... 87 more

Thank you.

Unable to specify multiple tags

No tests being executed if multiple tags are specified.
Tried with your example project. For this command

gradle clean runFeatures -Dcucumber.tags="@regression and @excluded"

I got this output

> Task :clean
> Task :compileJava NO-SOURCE
> Task :processResources NO-SOURCE
> Task :classes UP-TO-DATE
> Task :compileTestJava
> Task :processTestResources
> Task :testClasses
> Task :runFeatures

BUILD SUCCESSFUL in 1s
4 actionable tasks: 4 executed

Though it does work if you specify only one tag

IncompatibleClassChangeError: Implementing class error thrown

Hi,
Im getting below error when using Courgette

java.lang.IncompatibleClassChangeError: Implementing class

at java.lang.ClassLoader.defineClass1(Native Method)
at java.lang.ClassLoader.defineClass(ClassLoader.java:763)
at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:142)
at java.net.URLClassLoader.defineClass(URLClassLoader.java:467)
at java.net.URLClassLoader.access$100(URLClassLoader.java:73)
at java.net.URLClassLoader$1.run(URLClassLoader.java:368)
at java.net.URLClassLoader$1.run(URLClassLoader.java:362)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:361)
at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:349)
at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
at cucumber.runtime.io.ResourceLoaderClassFinder.loadClass(ResourceLoaderClassFinder.java:38)
at cucumber.runtime.io.ResourceLoaderClassFinder.getDescendants(ResourceLoaderClassFinder.java:26)
at cucumber.runtime.Reflections.instantiateSubclasses(Reflections.java:28)
at cucumber.runtime.Runtime.loadBackends(Runtime.java:99)
at cucumber.runtime.Runtime.(Runtime.java:66)
at courgette.runtime.CourgetteFeatureLoader.createRuntime(CourgetteFeatureLoader.java:60)
at courgette.runtime.CourgetteFeatureLoader.(CourgetteFeatureLoader.java:30)
at courgette.api.junit.Courgette.(Courgette.java:36)
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
at org.junit.internal.builders.AnnotatedBuilder.buildRunner(AnnotatedBuilder.java:104)
at org.junit.internal.builders.AnnotatedBuilder.runnerForClass(AnnotatedBuilder.java:86)
at org.junit.runners.model.RunnerBuilder.safeRunnerForClass(RunnerBuilder.java:59)
at org.junit.internal.builders.AllDefaultPossibilitiesBuilder.runnerForClass(AllDefaultPossibilitiesBuilder.java:26)
at org.junit.runners.model.RunnerBuilder.safeRunnerForClass(RunnerBuilder.java:59)
at org.junit.internal.requests.ClassRequest.getRunner(ClassRequest.java:33)
at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:49)
at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:47)
at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242)
at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)

Below is the feature runner class
import courgette.api.CourgetteOptions;
import courgette.api.CourgetteRunLevel;
import courgette.api.junit.Courgette;
import cucumber.api.CucumberOptions;
import org.junit.runner.RunWith;

@RunWith(Courgette.class)
@CourgetteOptions(
        threads = 3,
        runLevel = CourgetteRunLevel.SCENARIO,
        rerunFailedScenarios = true,
        showTestOutput = true,
        reportTargetDir = "results/reports",
        cucumberOptions = @CucumberOptions(
                features = "src/test/features/"
                , tags = {""~@blocked"}
                , format = {"pretty", "html:results/reports/html", "json:results/reports/json/cucumber.json"}
        )
)

public class ScenarioRunner {
}

Gradle snippet:
```
testCompile 'io.github.prashant-ramcharan:courgette-jvm:2.4.0'
testCompile 'io.github.prashant-ramcharan:webdriver-binary-downloader:1.2.2'


I think Im missing something very obvious :( 
Please help.

Issue while trying to run courgette-jvm example

I'm having this issue while I tried to run the Courgette-JVM Example or my tests runners

Exception in thread "main" cucumber.runtime.CucumberException: java.io.FileNotFoundException: /tmp7ccaa3ac150143b1af0477dd4cb036b5_thread_report_profile-tests-1670854404.json (Permission non accordรฉe)
at cucumber.runtime.formatter.PluginFactory.create(PluginFactory.java:89)
at cucumber.runtime.RuntimeOptions.getPlugins(RuntimeOptions.java:245)
at cucumber.runtime.RuntimeOptions$1.invoke(RuntimeOptions.java:291)
at com.sun.proxy.$Proxy0.uri(Unknown Source)
at cucumber.runtime.model.CucumberFeature.run(CucumberFeature.java:160)
at cucumber.runtime.Runtime.run(Runtime.java:122)
at cucumber.api.cli.Main.run(Main.java:36)
at cucumber.api.cli.Main.main(Main.java:18)
Caused by: java.io.FileNotFoundException: /tmp7ccaa3ac150143b1af0477dd4cb036b5_thread_report_profile-tests-1670854404.json (Permission non accordรฉe)
at java.io.FileOutputStream.open0(Native Method)
at java.io.FileOutputStream.open(FileOutputStream.java:270)
at java.io.FileOutputStream.(FileOutputStream.java:213)
at java.io.FileOutputStream.(FileOutputStream.java:162)
at cucumber.runtime.io.URLOutputStream.(URLOutputStream.java:34)
at cucumber.runtime.io.URLOutputStream.(URLOutputStream.java:24)
at cucumber.runtime.formatter.PluginFactory.convertOrNull(PluginFactory.java:142)
at cucumber.runtime.formatter.PluginFactory.instantiate(PluginFactory.java:99)
at cucumber.runtime.formatter.PluginFactory.create(PluginFactory.java:87)

Unable to run scenarios

Hello, I recently incorporated courgette-jvm into my project, I am sure it's user error/ I am missing something. But I cannot seem to get any scenarios to run whether I have the runLevel set to FEATURE or SCENARIO.
gradle simply gives a "BUILD SUCCESSFUL" output and nothing gets run. Previously I was using JUnit test configurations in IntelliJ to run my Feature files.

`
class CourgetteRunner {

@RunWith(Courgette.class)
@CourgetteOptions(
        threads = 1,
        runLevel = CourgetteRunLevel.FEATURE,
        rerunFailedScenarios = true,
        showTestOutput = true,
        cucumberOptions = @CucumberOptions(
                features = "src/test/resources/features/CommandConsole/UI_Tests/Partner/Admin",
                glue = "steps",
                tags = ["@partnerRegressionA"],
                plugin = [ "pretty", "json:target/cucumber-report/cucumber.json", "html:target/cucumber-report/cucumber.html"]
        ))
class RegressionTestSuite {

}

}
`

Duplicate scenarios running in parallel

Hi Prashant,

So the situation I have is somewhat unique. I'm trying to run each scenario in parallel on different browsers. Pictured below:
.........Chrome...Firefox
Sc1...Sc1_Ch...Sc1_FF
Sc2...Sc2_Ch...Sc2_FF

I'm able to successfully invoke the courgette runner with the scenarios, however, if I run 2 scenarios on 2 browsers. The number of actual scenarios that are supposed to run are 4, however 16 threads get kicked off. And I have duplicate scenarios running in parallel. If I run 2 scenarios on a single browser then 4 threads get kicked off, when in fact it is supposed to be only 2. The reports shows as seen here:
image.

I'm sorry if my problem is a little confusing. Please let me know if you need more information from me.

Your runner invokes the correct number of threads the first time. It just invokes it by a factor of the number of scenarios. So if I am running 2 scenarios on 2 browsers. It kicks off 4 threads 4 times.

Is it compatible with Serenity BDD?

Hi, what i want to do is run several scenarios of one feature at the same time (parallel) and with Courgette i can do that.

But i create my automated test with Serenity BDD framework. What i want to know is if COURGETTE and SERENITY are compatible. And that questions is because Courgette generate its own reports but i need the report of Serenity runing scenarios parallel.

I hope that you can help me. Thanks.

Incorrect JSON Output (decimal and scientific)

I'm seeing line values with decimal points and durations with decimal points and scientific notation when using this runner. This contrasts with the numbers in the example documentation (https://relishapp.com/cucumber/cucumber/docs/formatters/json-output-formatter).

For example, I believe that this:

       "line": 11.0,
       ......
          {
            "result": {
              "duration": 1.0702718E7,
              "status": "passed"
            },
           .......
          }
        ],

Should look like this:

       "line": 11,
       ......
          {
            "result": {
              "duration": 10702718,
              "status": "passed"
            },
           .......
          }
        ],

When running tests across multiple feature files, each scenario is run as many times as threads

Given this scenario:

Feature file a.feature (containing: scenario 1 and scenario 2)
Feature file b.feature (containing: scenario 3 and scenario 4)

When I run with concurrency as FEATURE level and rerunFailed=FALSE, each test is run twice, so I end up with 8 executions.

So, each test is triggered once per thread. Do you have any idea why this may be happening?

This is the config I'm using:

@RunWith(Courgette.class)
@CourgetteOptions(
threads = 10,
runLevel = CourgetteRunLevel.FEATURE,
rerunFailedScenarios = false,
showTestOutput = true,
cucumberOptions = @CucumberOptions(
features = "src/test/resources/features",
glue = "steps",
plugin = {
"pretty",
"json:src/test-report/some_results.json",
"html:src/test-report/some_results.html"}
))
public class CourgetteRunner {
}

Running at scenario level ignores tags; Duplicate features running

Hi, I'm running into an odd issue with JUnit tests. I'm using the following runner:

@RunWith(Courgette.class) 

@CourgetteOptions(
		threads = 2,
		runLevel = CourgetteRunLevel.FEATURE,
		rerunFailedScenarios = false,
		showTestOutput = true,
		reportTargetDir = "output",
		cucumberOptions = @CucumberOptions(
				features ="classpath:features",
				glue ={"com.cmp.site1.stepDefinitions","com.cmp.site2.stepDefinitions", "com.cmp.site3.stepDefinitions"},
				plugin = { "rerun:target/rerunSmoke.txt", "pretty", "html:target/cucumber-html-report", 
				"json:output/cucumber-report/cucumber.json"},
				tags = {"@Current"},
				monochrome = true,
				dryRun = false,
				strict = true
		))
public class ParallelFeaturesTest {
}

If runLevel is CourgetteRunLevel.FEATURE as shown, this runs the single feature tagged Current as it should. If it is changed to CourgetteRunLevel.SCENARIO, then it runs every scenario in the project regardless of tags. Tagging at the feature level or the scenario level makes no difference. Is this intended?

This is probably a separate issue, but when running features, it is running each feature once for each feature file. So if only one feature is tagged, it runs once. If two features are tagged, each runs twice for a total of four features. If six are tagged, each runs six times for a total of 36 features. I can't easily check if it's working the same for scenarios without the ability to run only a specific tag.

I have looked at the other issues involving duplicate tests, but as far as I can tell none of those solutions apply. I'm using Maven, have removed the included dependencies, there are no references to the Current tag anywhere else in the project, and I am not overriding any properties via the command line.

Thank you!

Can't get this working with a @SpringBootTest

When using this plugin my spring boot container will not load.

Normally it will load before the tests start running so I can @Autowire appropriate beans into my Steps.

Now I am getting Exception in thread "main" org.picocontainer.injectors.AbstractInjector$UnsatisfiableDependenciesException

  • code is in Kotlin by the way
@RunWith(Courgette::class)
@CourgetteOptions(
        threads = 10,
        runLevel = CourgetteRunLevel.SCENARIO,
        rerunFailedScenarios = true,
        showTestOutput = true,
        cucumberOptions = CucumberOptions(
                features = arrayOf("src/cucumber/resources"),
                glue = ["com.test.steps"], 
                plugin = ["pretty", "json:target/cucumber-report/cucumber.json", "html:target/cucumber-report/cucumber.html"],
                strict = true
        )
)
open class ParallelCucumberTestSuite

In my glue I have the following defined:

    @RunWith(org.mockito.junit.MockitoJUnitRunner::class)
    @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
    @ContextConfiguration(classes = [Application::class, CucumberConfig::class], loader = SpringBootContextLoader::class)
    @ActiveProfiles("cucumber")
    class Hooks { ... }

The original configuration works fine

@RunWith(Cucumber::class)
@CucumberOptions(glue = ["com.test.steps"], features = ["src/cucumber/resources"], format = ["pretty"])
open class CucumberTest

Multiple time execution of test scenarios

Hi Prashant,
I am facing rather an unusual issue here. When I tried to execute my whole regression suite, All the test scenarios executes multiple times, In my case three times exactly. And when I tried it with a single tag to run one particular scenario, It workes fine. Can you help me with this?

Thank you,

Odd duration in JSON report

The duration of steps in the JSON report is being reported as numbers on the order of 1e8 to 1e10. The sum of all the steps is 2,148,534,163,031. The test took 573 seconds. I don't see any relationship between those numbers. If those are nanoseconds then that's 36 minutes, almost four times as long as it actually took.

I'm not sure what format are the duration numbers are supposed to be in. I don't see any obvious transformations to get a meaningful number. Am I missing something, or have I run into a bug?

Maven surefire plugin is not notified about the result

Running the tests from maven surefire plugin the plugin is not updated with the result (such as the JUnit notifier) with output:
Failed to execute goal org.apache.maven.plugins:maven-failsafe-plugin:2.19.1:integration-test (integration-test-singlethreaded) on project qa-automation-web: Execution integration-test-singlethreaded of goal org.apache.maven.plugins:maven-failsafe-plugin:2.19.1:integration-test failed: The forked VM terminated without properly saying goodbye. VM crash or System.exit called?

Is there any way to pass exit status to maven surefire?

Cucumber-JVM report

Hi,
I am using Courgette Runner to execute my cucumber script in gradle. I am facing some issue with courgette report. Tabs on html report are not clickable.

Thank you.

Only Working on Windows 8.1

I have courgette running perfectly on two computers running Windows 8.1, but when I tried to run a project using courgette on Windows Server 2012 or on three different computers running Windows 10, it fails. Seems like it might be generating a classpath that's too long?

java.io.IOException: Cannot run program "java": CreateProcess error=206, The filename or extension is too long
    at java.lang.ProcessBuilder.start(Unknown Source)
    at courgette.runtime.CourgetteFeatureRunner.run(CourgetteFeatureRunner.java:27)
    at courgette.runtime.CourgetteRunner.runFeature(CourgetteRunner.java:143)
    at courgette.runtime.CourgetteRunner.lambda$run$1(CourgetteRunner.java:47)
    at java.util.concurrent.FutureTask.run(Unknown Source)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
    at java.lang.Thread.run(Unknown Source)
Caused by: java.io.IOException: CreateProcess error=206, The filename or extension is too long
    at java.lang.ProcessImpl.create(Native Method)
    at java.lang.ProcessImpl.<init>(Unknown Source)
    at java.lang.ProcessImpl.start(Unknown Source)
    ... 8 more

Non reporting plugins are not added to runtime options

It seems that all non reporting plugins are not added to final runtime options.
Looks like the problem is in this if statement which only executes and adds plugins when plugin starts with either html: or json::

asList(plugins).forEach(plugin -> {
            if (isReportPlugin.test(plugin)) {
                if (cucumberFeature != null) {
                    pluginList.add(plugin);

                    String extension = plugin.substring(0, plugin.indexOf(":"));

                    if (!extension.equals("")) {
                        final String reportPath = String.format("%s:%s.%s", extension, getMultiThreadReportFile(), extension);
                        pluginList.add(reportPath);
                    }
                } else {
                    pluginList.add(plugin);
                }
            }
        });

When debugging, I also see that command doesn't even contain pretty plugin even though it is provided in options.

Running example locally via gradle task gives error

getting the below error when executing the gradle tasks in the example:

Unexpected exception thrown.
org.gradle.internal.remote.internal.MessageIOException: Could not write '/127.0.0.1:58542'.
	at org.gradle.internal.remote.internal.inet.SocketConnection.flush(SocketConnection.java:134)
	at org.gradle.internal.remote.internal.hub.MessageHub$ConnectionDispatch.run(MessageHub.java:325)
	at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:63)
	at org.gradle.internal.concurrent.ManagedExecutorImpl$1.run(ManagedExecutorImpl.java:46)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
	at org.gradle.internal.concurrent.ThreadFactoryImpl$ManagedThreadRunnable.run(ThreadFactoryImpl.java:55)
	at java.lang.Thread.run(Thread.java:745)
Caused by: java.io.IOException: An existing connection was forcibly closed by the remote host
	at sun.nio.ch.SocketDispatcher.write0(Native Method)
	at sun.nio.ch.SocketDispatcher.write(SocketDispatcher.java:51)
	at sun.nio.ch.IOUtil.writeFromNativeBuffer(IOUtil.java:93)
	at sun.nio.ch.IOUtil.write(IOUtil.java:51)
	at sun.nio.ch.SocketChannelImpl.write(SocketChannelImpl.java:471)
	at org.gradle.internal.remote.internal.inet.SocketConnection$SocketOutputStream.writeWithNonBlockingRetry(SocketConnection.java:272)
	at org.gradle.internal.remote.internal.inet.SocketConnection$SocketOutputStream.writeBufferToChannel(SocketConnection.java:260)
	at org.gradle.internal.remote.internal.inet.SocketConnection$SocketOutputStream.flush(SocketConnection.java:254)
	at org.gradle.internal.remote.internal.inet.SocketConnection.flush(SocketConnection.java:132)
	... 7 more

It runs fine using the junit runner within an IDE without any issue, so the issue does seem to be in the gradle execution of this.

have you seen this issue?

Extend cucumber options with "strict" flag

Will be nice to have possibility to pass --strict into cucumber options to cause cucumber to fail unless all the step definitions have been defined.
The quick solution is to add something like this into courgette.runtime.CourgetteRuntimeOptions#createRuntimeOptions
if (cucumberOptions.strict()) { runtimeOptions.put("--strict", Collections.singletonList("--strict")); }

JDK 9 support

Given that java 10 is already out, I think it is worth to think about at least java 9 support. Currently execution will fail with error:

Caused by: java.lang.ClassCastException: java.base/jdk.internal.loader.ClassLoaders$AppClassLoader cannot be cast to java.base/java.net.URLClassLoader
        at courgette.runtime.CourgetteFeatureRunner.<clinit>(CourgetteFeatureRunner.java:56)

https://blog.codefx.org/java/java-9-migration-guide/#Casting-To-URL-Class-Loader

No feature information in hooks

In classic cucumber runner, I can access current Feature object via Scenario instance in a @before hook.
With courgette the Scenario.reporter field is null
I want to get current feature name and its lang iso code at runtime. Is it possible to implement?

Singleton created before Courgette runner nulled

Hi Prashant,

I ran into an issue over the weekend. I created a singleton class which will in charge of gather all of the configurations needed during runtime and set it to a Suite object which the entire application should be able to use through out. However, once the Testng Courgette runner kicks off the suite singleton object becomes null.

Here is the singleton:

public class Suite {
  private static Suite ourInstance = new Suite();

  private Suite() {
    configFile = new ConfigFileReader(Resources.getFilePath(Resources.CONFIG_FILE));
  }
  
  public static synchronized Suite getInstance() {
    if (ourInstance == null) {
      synchronized (Suite.class) {
        if (ourInstance == null) {
          ourInstance = new Suite();
        }
      }
    }
    return ourInstance;
  }
}

Here is the courgette runner:

@Test
@CourgetteOptions(
  threads = 10,
  runLevel = CourgetteRunLevel.SCENARIO,
  rerunFailedScenarios = true,
  showTestOutput = true,
  reportTargetDir = "build",
  cucumberOptions =
      @CucumberOptions(
        features = "src/test/resources/Tmpf",
        glue = "Application.StepDefinitions",
        tags = {"@healthCheck"},
        plugin = {
          "progress",
          "json:build/cucumber-report/cucumber.json",
          "html:build/cucumber-report/cucumber.html"
        },
        strict = true
      )
)
public class TestSuiteRunner extends TestNGCourgette {
  private static Suite suite;
  public static Suite getSuite() { return suite; }
  private Log logger = new Log(TestSuiteRunner.class);

  @BeforeSuite(alwaysRun = true)
  public void initializeSuite() {
    Suite suite = Suite.getInstance();
    logger.info("Initialize Suite");
    suite.setSuiteProperties();
  }

  @AfterSuite
  public void afterSuite() {
    logger.info("End Suite");
  }
}

Is there anything that I am missing? I want to be able to initialize a few things before the threads are kicked off i.e. setup configurations for the entire suite, start appium server, possibly the BMP proxy server.

cucumber report rewriting

Hi,
I want to use cucumber report, but courgette rewrite all cucumber reports by scenario or feature. Can i set to not rewrite it or it's impossible?
Why i want to use cucumber report? Because they have a screenshots and steps in report.

Thanks for your answer

Scenarios within feature files are being run twice when running features in parallel

Hi, I need help understanding what I am doing wrong with my setup.
So I have 2 feature files. Each file contains 1 scenario. When I try to run the features in parallel (using 2 threads), first 2 browsers that opened up run the scenario in feature 1 (twice) followed by scenario 1 in feature 2. So basically the scenarios are executed 4 times.

attached is my build.gradle
build.gradle.zip

here is Feature suite
`
import courgette.api.CourgetteOptions;
import courgette.api.CourgetteRunLevel;
import courgette.api.junit.Courgette;
import cucumber.api.CucumberOptions;
import org.junit.runner.RunWith;

@RunWith(Courgette.class)
@CourgetteOptions(
threads = 2,
runLevel = CourgetteRunLevel.FEATURE,
// rerunFailedScenarios = true,
showTestOutput = true,
cucumberOptions = @CucumberOptions(
features = "src/cucumber/resources/features/reporting",
glue = "src/cucumber/resources",
tags = {"@regression"},
plugin = {
"pretty",
"json:target/cucumber-report/cucumber.json",
"html:target/cucumber-report/cucumber.html"},
strict = true
))
public class FeatureSuite {
}
`

Multiple time execution of test scenarios

Hi Prashant,
I am facing rather an unusual issue here. When I tried to execute my whole regression suite, All the test scenarios executes multiple times, In my case three times exactly. And when I tried it with a single tag to run one particular scenario, It workes fine. Can you help me with this?

Thank you,

report

The report in the readme file looks really good, mine does not look like that
screen shot 2018-02-02 at 3 20 56 pm

Gradle MessageIOException and build failure

Because Maven Surefire isn't compatible with libraries that call System.exit(), I'm switching my project from Maven to Gradle, but I'm still having difficulty running Courgette. I can run Cucumber runners normally with Gradle, so it isn't the Gradle installation. To make sure it wasn't an issue with my project, I cloned your example project. If I go into that directory and run gradle runScenariosUsingJUnit, the test runs and at the end throws the following exception.

The build also fails after the exception, and seems to be indicating it's due to Courgette's use of System.exit(1) when not every scenario passes. If I remove the example scenario that is meant to fail, the exception is still thrown but the build does not fail.

I am running Gradle 4.8.1 on Windows 8.1

gradle : Unexpected exception thrown.
At line:1 char:1
+ gradle runScenariosUsingJUnit 2>&1 > log.txt
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (Unexpected exception thrown.:String) [], RemoteException
    + FullyQualifiedErrorId : NativeCommandError
 
org.gradle.internal.remote.internal.MessageIOException: Could not write '/127.0.0.1:60069'.

    at org.gradle.internal.remote.internal.inet.SocketConnection.flush(SocketConnection.java:134)

    at org.gradle.internal.remote.internal.hub.MessageHub$ConnectionDispatch.run(MessageHub.java:325)

    at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:63)

    at org.gradle.internal.concurrent.ManagedExecutorImpl$1.run(ManagedExecutorImpl.java:46)

    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)

    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)

    at org.gradle.internal.concurrent.ThreadFactoryImpl$ManagedThreadRunnable.run(ThreadFactoryImpl.java:55)

    at java.lang.Thread.run(Thread.java:748)

Caused by: java.io.IOException: An existing connection was forcibly closed by the remote host

    at sun.nio.ch.SocketDispatcher.write0(Native Method)

    at sun.nio.ch.SocketDispatcher.write(SocketDispatcher.java:51)

    at sun.nio.ch.IOUtil.writeFromNativeBuffer(IOUtil.java:93)

    at sun.nio.ch.IOUtil.write(IOUtil.java:51)

    at sun.nio.ch.SocketChannelImpl.write(SocketChannelImpl.java:471)

    at org.gradle.internal.remote.internal.inet.SocketConnection$SocketOutputStream.writeWithNonBlockingRetry(SocketCon
nection.java:272)

    at org.gradle.internal.remote.internal.inet.SocketConnection$SocketOutputStream.writeBufferToChannel(SocketConnecti
on.java:260)

    at org.gradle.internal.remote.internal.inet.SocketConnection$SocketOutputStream.flush(SocketConnection.java:254)

    at org.gradle.internal.remote.internal.inet.SocketConnection.flush(SocketConnection.java:132)

    ... 7 more


> Task :runScenariosUsingJUnit FAILED

FAILURE: 
Build failed with an exception.


* What went wrong:

Execution failed for task ':runScenariosUsingJUnit'.

> 
Process 'Gradle Test Executor 6' finished with non-zero exit value 1

  This problem might be caused by incorrect test process configuration.

  Please refer to the test execution section in the user guide at 
https://docs.gradle.org/4.8.1/userguide/java_plugin.html#sec:test_execution

* Try:

Run with 
--stacktrace
 option to get the stack trace. Run with 
--info
 or 
--debug
 option to get more log output. Run with 
--scan
 to get full insights.

* Get more help at 
https://help.gradle.org

BUILD FAILED
 in 33s

3 actionable tasks: 1 executed, 2 up-to-date

```

Cant use with Maven project

When I try using this with Maven project, I get the following errors:

Class<Courgette> cannot be resolved to a type

CourgetteRunLevel cannot be resolved to a variable

I have added the repository and dependency specified but I don't get it working.

With Courgette 1.4.0 unable to see report with all features

@RunWith(Courgette.class) @CourgetteOptions( runLevel = CourgetteRunLevel.FEATURE, showTestOutput = true, cucumberOptions = @CucumberOptions( features = "src/test/resources/com.abc.feature", tags = "@abc", dryRun = false, strict = true, monochrome=true, glue = "com.abc.stepdefinition", plugin = {"pretty", "html:build/reports/cucumberreport/cucumber", "json:build/reports/cucumberreport/cucumber.json" } ))

With above setup, and 4 feature files under testing it is observed that the final report only contains only details of one feature file. Seemingly the last feature file that completes is the one that is reflecting in the final report. Does courgette manage reporting in a threadsafe way automatically? I mean how does the cucumber.json gets written to disk when there are multiple threads generating the test output?
I see an issue in case of ours where the output of one thread that completes first gets overwritten by the subsequent one.

Missing execution of test scenarios in feature??

I've been using courgette-JVM in my project for a while, recently I've found out that it's sometimes missing execution of some test scenarios in the feature.

For Ex:
If my first test scenario failed in the feature, which contains 6 scenarios in total. courgette-jvm is immediately or trying to re-run failed test scenario instead of executing rest of the scenarios in the feature. by this way sometimes it's missing execution of some test scenarios in the feature.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.