3

I want to access all the cucumber scenario steps in @before hook. Is there a way to do this?

I have tried passing the cucumber scenario object in the before hook method but it only provides the basic info like scenario.getName(), scenario.getId(). What I require is something like getSteps() which give me the List<String> of all the steps of that particular scenario.

What I am looking for is something like this

    @Before("@dev")
public void testcase(Scenario scenario){

    for (Step a : scenario.getSteps()) {
        System.out.println("scenario step = " + a.getText());
    }
}

Basically I want the complete scenario information at the beginning of the test execution itself.

If I pass the argument of class cucumber.api.TestCase in the before method then I can access the getTestSteps() method but that leads to below exception.

cucumber.runtime.CucumberException: When a hook declares an argument it must be of type cucumber.api.Scenario. public void com.thermofisher.bid.spa.kingfisher.ui.steps.Hooks.poc(cucumber.api.TestCase)
double-beep
  • 5,031
  • 17
  • 33
  • 41
  • What's the full name of Scenario class? – Qingfei Yuan May 24 '19 at 16:28
  • cucumber.api.Scenario.class – DEVYANSH MITTAL May 24 '19 at 16:30
  • Have you tried with `TestCase.getTestSteps`? – supputuri May 24 '19 at 19:59
  • Have tried with it but the problem is that the before hook takes only Scenario as agrument. Else it with throw the above mentioned exception. Is there a way i can pass testcase as an argument – DEVYANSH MITTAL May 24 '19 at 22:03
  • 2
    Cucumber will not give you this information. Serenity may have the information available but it would be non-trivial to obtain. What problem are you trying to solve? – John Smart May 25 '19 at 08:45
  • 1
    I am going so second John on this. If it's for reporting purposes have a look at the plugin infra structure. – M.P. Korstanje May 25 '19 at 21:21
  • Hi john, so the problem i am trying to solve is to create a manual test case out of the gherkin scenario/feature file and push it to confluence/JIRA using atlassian API's to reduce the manual efforts in our workflow. Could you please let me know how to get the information that you are mentioning from serenity ? – DEVYANSH MITTAL May 26 '19 at 11:01
  • @JohnSmart, think about this: the `Before` hook is used to be called before a scenario is executed. This can be done to log what scenario is being executed. Cucumber also provides a `BeforeStep` hook, but instead of allowing access to the `PickleStepTestStep`, it forces you to either use no arguments or one argument which must also be a Scenario object. This is useless in the context of a Step. One would assume that, if I want to log Step-related information, one would use this hook with a PickleStep argument, so that you can log the step text, line number, etc. – hfontanez Aug 26 '19 at 21:22

5 Answers5

1

Try something like this:

@Before
public void setUp(Scenario scenario) throws Exception{

    tags = (ArrayList<String>) scenario.getSourceTagNames();
    System.out.println("At Hooks: " + scenario.getId());
    Iterator ite = tags.iterator();

    while (ite.hasNext()) {

        String buffer = ite.next().toString();
        if (buffer.startsWith("<tagOfATestCase>")) {

            Field f = scenario.getClass().getDeclaredField("testCase");
            f.setAccessible(true);
            TestCase r = (TestCase) f.get(scenario);

            List<PickleStepTestStep> testSteps = r.getTestSteps().stream().filter(x -> x instanceof PickleStepTestStep)
                    .map(x -> (PickleStepTestStep) x).collect(Collectors.toList());

            for (PickleStepTestStep ts : testSteps) {

                System.out.println(ts.getStepText());//will print your test case steps

            }

        }

    }
ghovat
  • 1,033
  • 1
  • 12
  • 38
atrinil
  • 26
  • 1
0

Java:

Refer to the TestCase interface under cucumber-jvm/core/src/main/java/io/cucumber/core/runner/TestCase.java

https://github.com/cucumber/cucumber-jvm/blob/main/core/src/main/java/io/cucumber/core/runner/TestCase.java

testcase.getTestSteps();

I know the question is not related to ruby, but want to provide the solution in ruby too so that it might help someone looking for the solution in ruby.

Ruby: Will give all the list of steps.

scenario.source[1].steps
hertzsprung
  • 9,445
  • 4
  • 42
  • 77
supputuri
  • 13,644
  • 2
  • 21
  • 39
  • The problem is that you can't get direct access to the Step data (PickeStepTestStep) because the Cucumber hooks limits your access to the Scenario object, even when using @BeforeStep. – hfontanez Aug 26 '19 at 21:16
0

With Cucumber 6.10.3 it is possible to do it, with the following code:

Field f = scenario.getClass().getDeclaredField("delegate");
f.setAccessible(true);
io.cucumber.core.backend.TestCaseState sc = (io.cucumber.core.backend.TestCaseState) f.get(scenario);          
Field f1 = sc.getClass().getDeclaredField("testCase");
f1.setAccessible(true);
io.cucumber.plugin.event.TestCase testCase = (io.cucumber.plugin.event.TestCase) f1.get(sc);
        
List<PickleStepTestStep> testSteps = testCase.getTestSteps().stream().filter(x -> x instanceof PickleStepTestStep).map(x -> (PickleStepTestStep) x).collect(Collectors.toList());

for (PickleStepTestStep ts : testSteps) {
       System.out.println(ts.getStep().getKeyword() + ts.getStep().getText());
}

Imports:

import io.cucumber.java8.Scenario;
import io.cucumber.plugin.event.PickleStepTestStep;
import io.cucumber.core.backend.TestCaseState;
import java.lang.reflect.Field;
import java.util.stream.Collectors;

Dependencies: (you only need 'cucumber-java8' or 'cucumber-java')

compile group: 'io.cucumber', name: 'cucumber-java8', version: '6.10.3'
compile group: 'io.cucumber', name: 'cucumber-java', version: '6.10.3'
compile group: 'io.cucumber', name: 'cucumber-core', version: '6.10.3'
0

Ugly but does the job for me:

    @Before
    public void beforeScenario(Scenario scenario) throws Exception {
        Field delegate = scenario.getClass().getDeclaredField("delegate");
        delegate.setAccessible(true);
        TestCaseState state = (TestCaseState) delegate.get(scenario);
        Field testCaseF = state.getClass().getDeclaredField("testCase");
        testCaseF.setAccessible(true);
        TestCase testCase = (TestCase) testCaseF.get(state);
        Field pickle = testCase.getClass().getDeclaredField("pickle");
        pickle.setAccessible(true);
        Pickle pickleState = (Pickle) pickle.get(testCase);
        List<Step> steps = pickleState.getSteps();
        //... your logic here
    }

In case the imports are needed:

import io.cucumber.core.backend.TestCaseState;
import io.cucumber.core.gherkin.Pickle;
import io.cucumber.core.gherkin.Step;
import io.cucumber.java.Before;
import io.cucumber.java.Scenario;
import io.cucumber.plugin.event.TestCase;

import java.lang.reflect.Field;
import java.util.List;
Dmytro Chaban
  • 1,106
  • 1
  • 11
  • 19
-1

Cucumber does not provide you any direct method which grab complete information of a scenario inside the Hook. There is Scenario interface which can give you very limited information like scenario name and below are the rest direct methods of this interface.

public interface Scenario {
    Collection<String> getSourceTagNames();
    Result.Type getStatus();
    boolean isFailed();
    void embed(byte[] data, String mimeType);
    void write(String text);
    String getName();
    String getId();
    String getUri();
    List<Integer> getLines();
}

enter image description here

TheSociety
  • 1,936
  • 2
  • 8
  • 20
  • 1
    Thanks for the answer, scenario interface i am already aware of and have tried using it. But that is not solving my purpose as you mentioned, it provides very limited information that's why i posted the question to have a workaround. There are other classes which provides the details of the scenario like cucumber.api.TestCase but the problem is hwo to use them in hooks method. – DEVYANSH MITTAL May 24 '19 at 18:34