Scenario: As a user, I want to login to the system
Given I am on my website
When I enter valid credentials
Then I am taken to the home page
The sce
I solved it using @BeforeStep & @AfterStep. It is a bit hacky, so use it only if you are know what you are doing.
public class StepDefBeginEndLogger {
private int currentStepDefIndex = 0;
@BeforeStep
public void doSomethingBeforeStep(Scenario scenario) throws Exception {
Field f = scenario.getClass().getDeclaredField("testCase");
f.setAccessible(true);
TestCase r = (TestCase) f.get(scenario);
//You need to filter out before/after hooks
List<PickleStepTestStep> stepDefs = r.getTestSteps()
.stream()
.filter(x -> x instanceof PickleStepTestStep)
.map(x -> (PickleStepTestStep) x)
.collect(Collectors.toList());
//This object now holds the information about the current step definition
//If you are using pico container
//just store it somewhere in your world state object
//and to make it available in your step definitions.
PickleStepTestStep currentStepDef = stepDefs
.get(currentStepDefIndex);
}
@AfterStep
public void doSomethingAfterStep(Scenario scenario) {
currentStepDefIndex += 1;
}
}
Just leaving this here for future reference...
The current version of Cucumber (4.2.5) has the BeforeStep hook, but only provides access to the current running scenario.
What I did to extract the current step, was using reflection to access the steps within that scenario;
@BeforeStep
public void beforeStep(Scenario scn) throws Exception {
currentStepIndex++;
Field testCaseField = scn.getClass().getDeclaredField("testCase");
testCaseField.setAccessible(true);
TestCase tc = (TestCase) testCaseField.get(scn);
Field testSteps = tc.getClass().getDeclaredField("testSteps");
testSteps.setAccessible(true);
List<TestStep> teststeps = tc.getTestSteps();
try {
PickleStepTestStep pts = (PickleStepTestStep) teststeps.get(currentStepIndex);
getLog().info("########################");
getLog().info("##########STEP##########");
getLog().info(pts.getStepText());
getLog().info("########################");
currentStepIndex++;
} catch (Exception ignore) {
}
}
The only downside is, that you require a int currentStepIndex at class level, and need to add 1 with every @Before
or @BeforeStep
.
BE WARNED that the use of this type of reflection may fail to work in future releases of Cucumber, as the Cucumber team can decide to change their internals.
Here's an update to handle the framework changes. The "testCase" field is hidden under the "delegate". I got this working with io.cucumber.java version 5.7.0
public String getStepText(io.cucumber.java.Scenario scenario){
String currentStepDescr = null;
//value currentStepDefIndex is tracked in the another class
int currentStepDefIndex = OtherClass.getStepIndex();
Field f = scenario.getClass().getDeclaredField("delegate");
f.setAccessible(true);
TestCaseState tcs = (TestCaseState) f.get(scenario);
Field f2 = tcs.getClass().getDeclaredField("testCase");
f2.setAccessible(true);
TestCase r = (TestCase) f2.get(tcs);
List<PickleStepTestStep> stepDefs = r.getTestSteps()
.stream()
.filter(x -> x instanceof PickleStepTestStep)
.map(x -> (PickleStepTestStep) x)
.collect(Collectors.toList());
PickleStepTestStep currentStepDef = stepDefs
.get(currentStepDefIndex);
currentStepDescr = currentStepDef.getStep().getText();
currentStepDefIndex += 1;
OtherClass.setStepIndex(currentStepDefIndex);
return currentStepDescr ;
}
Below are the dependencies in my pom.xml
<!-- https://mvnrepository.com/artifact/io.cucumber/cucumber-core -->
<dependency>
<groupId>io.cucumber</groupId>
<artifactId>cucumber-core</artifactId>
<version>5.7.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/io.cucumber/cucumber-testng -->
<dependency>
<groupId>io.cucumber</groupId>
<artifactId>cucumber-testng</artifactId>
<version>5.7.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/io.cucumber/cucumber-java -->
<dependency>
<groupId>io.cucumber</groupId>
<artifactId>cucumber-java</artifactId>
<version>5.7.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/io.cucumber/cucumber-jvm-deps -->
<dependency>
<groupId>io.cucumber</groupId>
<artifactId>cucumber-jvm-deps</artifactId>
<version>1.0.6</version>
<scope>provided</scope>
</dependency>
I had this same question. I attempted to use rs79's answer but either I don't know what I'm actually doing with it or it doesn't work. Java gives me an "AmbiguousStepDefinitionException" or something like that. So I did it a different way. It takes a little work if you have a slew of step definitions but it works and is pretty simple:
@Then(value = "^The page should navigate to url \"([^\"])\"$", timeout = MAX_TIME)
public void the_page_should_navigate_to_url(String url) {
//below I use a custom class with a static method setStepName() which just sets a string field in the class
CustomClass.setStepName("Then The page should navigate to url " + url);
//Assert
}
Now you have access to the step name without needing any kind of complicated tool. Just use a get method to access the step variable in your custom class. Hope that helps.
These hooks will help:
@BeforeStep
public void beforeStep(Scenario scenario){
System.out.println(scenario.toString());
}
@AfterStep
public void afterStep(Scenario scenario){
System.out.println(scenario.toString());
}
Being a newbie m not allowed to comment so here is some info, assuming you are using cucumber-jvm.
Short answer, No, Cucumber by itself doesnt have the option to read step names. You could use the method names to identify what was called.
Also, @BEFORE STEP / @AFTER STEP tags are not yet available so you will have to define the call for each step.
https://github.com/cucumber/cucumber-jvm/pull/838#issuecomment-234110573
or the testing framework like junit or testng could let you access the execution details - something like this: http://junit.org/junit4/javadoc/4.12/org/junit/rules/TestWatcher.html.
And if you really need the step names only for reporting purposes, you can simply parse the xml report that the testing framework generates.