prashant-ramcharan / courgette-jvm

Multiprocess | Parallel Cucumber-JVM | Parallelize your Java Cucumber tests on a feature level or on a scenario level.
MIT License
130 stars 38 forks source link

Execute Courgette having test suite in a FAT JAR #398

Closed albertolopez55 closed 3 weeks ago

albertolopez55 commented 4 months ago

Hi prashant-ramcharan, I’ve been using the courgette extension as my daily basis for a while now, but I still can’t find a way to execute my test suite in a FAT JAR correctly. My biggest problem is that when I try to pass classpath:features as the path to find my feature files like we usually do with cucumber cli.main, it fails to recognize the path when running inside the JAR, can you please provide a solution or include this as part of later releases?

prashant-ramcharan commented 3 months ago

Hi @albertolopez55 , can you provide a sample project to demonstrate this?

FranciscoAAR commented 2 months ago

Hi @prashant-ramcharan, I'm facing the same issue when trying to execute my test suite from within a JAR. I've created a small project with just one feature and one test scenario in it, the path to the feature files that I'm using is the same as recommended by "java io.cucumber.core.cli.Main" using the "classpath:resources/" format. The problem happens when courgette tries to check feature re-runs, at this point the classpath URI does not contain any path and when the condition tries to retrieve that value fails.

Feature URI with no path

image

Attempt to retrieve path from URI

image

Below is my runner and main configuration trying to emulate the cucumber CLI feature:

package com.test.courgette;

import courgette.api.CourgetteOptions;
import courgette.api.CucumberOptions;
import org.junit.runner.RunWith;
import courgette.api.CourgetteTestOutput;
import courgette.api.CourgetteRunLevel;
import courgette.api.junit.Courgette;
import org.junit.runner.notification.RunNotifier;
import org.junit.runners.model.InitializationError;

@RunWith(Courgette.class)
@CourgetteOptions(
    threads = 1,
    runLevel = CourgetteRunLevel.SCENARIO,
    testOutput = CourgetteTestOutput.CONSOLE,
    rerunFailedScenarios = true,
    rerunAttempts = 1,
    excludeFeatureFromRerun = "",
    excludeTagFromRerun = "",
    reportTitle = "Courgette test execution",
    reportTargetDir = "build/reports/html/chartReport",
    environmentInfo = "",
    cucumberOptions =
    @CucumberOptions(
        features = "src/test/resources/features/",
        glue = "com.test.courgette.steps",
        tags = "@test",
        plugin = {
            "pretty",
            "json:build/reports/json/cucumber.json",
            "html:build/reports/html/cucumber.html",
            "junit:build/reports/cucumber.xml"
        }))
public class TestRunner {

  public static void main(String[] args) throws InitializationError {
    System.setProperty("cucumber.features", "classpath:features/");
    new Courgette(TestRunner.class).run(new RunNotifier());
    System.out.println("\n+++++++++++++++++++++++++\n");
    System.out.println("\n++++EXECUTION FINISHED+++\n");
    System.out.println("\n+++++++++++++++++++++++++\n");
  }
}

Project directory tree

image

I don't know if more problems will arise beyond this point, thanks!

prashant-ramcharan commented 2 months ago

Hi @FranciscoAAR Thanks for that.

Do you mind sharing the project so I can debug further, please?

FranciscoAAR commented 2 months ago

Courgette jar runner sample

FranciscoAAR commented 1 month ago

Hi @prashant-ramcharan - Just following up to see if you need anything else from my side to continue working on this.

prashant-ramcharan commented 1 month ago

@FranciscoAAR Just had a look into your sample project.

This seems to work however you should not set the cucumber.features to a classpath.

Courgette and Cucumber should resolve the features using the file system instead.

Screenshot 2024-06-01 at 10 00 30
FranciscoAAR commented 1 month ago

@prashant-ramcharan - Thanks for reviewing this. The issue with using the file system is that the feature files need to be outside the JAR for it to find them, thus ignoring the internal resources and failing if not provided.

image

Cucumber already supports this out of the box, but I'm noticing that Courgette tries to perform this operation inside CourgetteRunnerInfo.checkRerunCondition() :

Arrays.stream(excludedRerunFeatures)
                .map(String::trim)
                .map(String::toLowerCase)
                .noneMatch(featureName -> feature.getUri().getPath().toLowerCase().contains(featureName))

Here feature.getUri().getPath() returns "null" when the classpath value is used e.g: "classpath:features//CourgetteTest.feature"

prashant-ramcharan commented 1 month ago

Hi @FranciscoAAR ,

I will release an update to the library to support this.

I've tested a version locally with a change to support this.

Attached jar below:

java -jar CourgetteJarProject-1.0-SNAPSHOT-all.jar

CourgetteJarProject-1.0-SNAPSHOT-all.jar.zip

Let me know if it runs for you.

FranciscoAAR commented 1 month ago

@prashant-ramcharan - I just ran the jar and it's working as expected!

prashant-ramcharan commented 1 month ago

@albertolopez55 @FranciscoAAR This is now released in 6.14.0

https://github.com/prashant-ramcharan/courgette-jvm/blob/master/CHANGELOG.md#changes-in-version-6140