I have a Feature file which is as below:
Scenario Outline: Create ABC
Given I open the application
When I enter username as <username>
And I enter password as <password>
Then I enter title as <title>
And press submit
Examples:
| username | password | title |
| Rob | xyz1 | title1 |
| Bob | xyz1 | title2 |
This mandates me to have step definitions for each of these values. Can i instead have a
generic step definition that can be mapped for every username or password or title values in
the examples section.
i.e instead of saying
#When("^I enter username as Rob$")
public void I_enter_username_as_Rob() throws Throwable {
// Express the Regexp above with the code you wish you had
throw new PendingException();
}
can i enter
#When("^I enter username as <username>$")
public void I_enter_username_as_username(<something to use the value passed>) throws Throwable {
// Express the Regexp above with the code you wish you had
throw new PendingException();
}
You should use this format
Scenario Outline: Create ABC
Given I open the application
When I enter username as "<username>"
And I enter password as "<password>"
Then I enter title as "<title>"
And press submit
Which would produce
#When("^I enter username as \"([^\"]*)\"$")
public void I_enter_username_as(String arg1) throws Throwable {
// Express the Regexp above with the code you wish you had
throw new PendingException();
}
arg1 will now have your username/value passed.
Cucumber would give the missing steps in console automatically. Just make a dry run and missing steps would be shown in console.
#RunWith(Cucumber.class)
#CucumberOptions(plugin = { "pretty" }, features = { "<path_to_feature>" },
glue = { "<optional_steps_location_java_file>" }, dryRun = true,
tags = { "<optional_NOT_req_for_now>" })
public class RunMyCucumberTest {
}
See for more Cucumber options
Related
I am trying to print the current step being executed in Cucumber. I am using a custom formatter to print the step definition. However, I also want to print the current adverb (Given, When, Then, And...) that is being executed. I might be missing something as well, is it possible in Cucumber? Here is my code:
Formatter:
public class MyCucumberFormatter implements ConcurrentEventListener {
#Override
public void setEventPublisher(EventPublisher publisher) {
publisher.registerHandlerFor(TestStepStarted.class, runStartedHandler);
}
private EventHandler<TestStepStarted> runStartedHandler = new EventHandler<TestStepStarted>() {
#Override
public void receive(TestStepStarted event) {
startReport(event);
}
};
private void startReport(TestStepStarted event) {
if (!(event.testStep instanceof PickleStepTestStep)) {
return;
}
PickleStepTestStep testStep = (PickleStepTestStep) event.testStep;
log("Step: " + testStep.getStepText());
}
}
Example scenario:
Scenario: Test user life cycle: create user, activate and delete
Given A valid admin logs in
When Admin creates new user
And User is activated
Then User should successfully login
Right now, it prints as:
A valid admin logs in
Admin creates new user
User is activated
User should successfully login
I want it to print as:
Given A valid admin logs in
When Admin creates new user
And User is activated
Then User should successfully login
You can't do this in v4.x yet but you can do this in v5.0.0-RC1 by going through pickleStepTestStep.getStep().getKeyWord()
I am writing Gherkin test cases and Java step definitions in my project. I am new to Gherkin and trying to understand the meaning of nested steps. Can you please help me to understand if the 2nd scenario given involves nested steps?
In my example, I would like to reuse 1st scenario code in 2nd scenario given statement logic. Is there a best way to reuse or rewrite the logic?
Note: Below example is written just to explain my question. It may not be a good Gherkin.
Background:
Given The application is opened
Scenario: Successful Login
Given the user name and password are entered
When login button is clicked
Then user login is successful
Scenario: Add Address Successful
Given user login is successful
And Add Address button is clicked
And user city, country are entered
when Submit button is clicked
Nested steps refer to calling defined steps inside a "main" one. In your example, the first scenario has the login functionality, which will / can be used in all other scenarios that require the user to be logged in.
So, the second scenario will have a Given step which calls the login action / steps of the first scenario. There are multiple ways to do this:
1. If you are defining those steps in the same class, it's just a matter of calling the same methods inside a different step / method.
Like so:
public class TestStepsOne {
// Steps from first scenario
#Given("^the user name and password are entered$")
public void enterUsernamePassword() throws Throwable {
System.out.println("User and password entered");
}
#When("^login button is clicked$")
public void clickLoginButton() throws Throwable {
System.out.println("Clicked login button");
}
#Then("^user login is successful$")
public void isLoggedIn() throws Throwable {
System.out.println("Logged in!");
}
// All together
#Given("the user is logged in")
public void loginSuccessfully() throws Throwable {
enterUsernamePassword();
clickLoginButton();
isLoggedIn();
}
}
Now you can use the Given the user is logged in in any scenario, and it will perform the login action.
2. Using Picocontainer -> details here
First you need to add these dependencies to your pom.xml:
<dependency>
<groupId>org.picocontainer</groupId>
<artifactId>picocontainer</artifactId>
<version>2.15</version>
</dependency>
<dependency>
<groupId>info.cukes</groupId>
<artifactId>cucumber-picocontainer</artifactId>
<version>1.2.5</version>
</dependency>
You can separate your step definitions.
Like so:
public class TestStepsOne {
// Same as above, without the nested one
}
and second class:
public class TestStepsTwo {
private final TestStepsOne testStepsOne;
public TestStepsTwo(TestStepsOne testStepsOne) {
this.testStepsOne = testStepsOne;
}
#Given("the user is logged in")
public void loginSuccessfully() throws Throwable {
testStepsOne.enterUsernamePassword();
testStepsOne.clickLoginButton();
testStepsOne.isLoggedIn();
}
}
3. Using cuke4duke -> details here , includes examples
Like so:
public class CallingSteps extends Steps {
public CallingSteps(StepMother stepMother) {
super(stepMother);
}
#When("^I call another step$")
public void iCallAnotherStep() {
Given("the user is logged in"); // This will call a step defined somewhere else.
}
}
Hope this helps
I want get current feature file name at runtime using Java. I have scenario info in hook but unable to get feature file
#Before
public void before(final Scenario scenario) {
this.scenario = scenario;
}
Do we have any similar thing to get current Feature file name ??
i am using cucumber version 1.2.4
UPDATE:
This is my implementation for feature names starting with an uppercase letter like in the example:
private String getFeatureFileNameFromScenarioId(Scenario scenario) {
String featureName = "Feature ";
String rawFeatureName = scenario.getId().split(";")[0].replace("-"," ");
featureName = featureName + rawFeatureName.substring(0, 1).toUpperCase() + rawFeatureName.substring(1);
return featureName;
}
ORIGINAL:
I don't know if this is useful for you, but I would suggest to use scenario.getId()
This will give you the feature file name and scenario name, for example:
Feature: Login to the app
Scenario: Login to the app with password
Given I am on the login screen
When I enter my passcode
Then I press the ok button
with scenario.getId() you would get the following:
login-to-the-app;login-to-the-app-with-password
Hope this helps you!
Kotlin 1.5, cucumber-java 6.10.0:
#Before
fun beforeScenario(scenario: Scenario) {
println(scenario.uri)
}
In my case prints:
file:///C:/Users/K.H/git/JvmClient/src/jvmTest/resources/features/C197544.feature
There is an easier way to extract the feature name (without .feature postfix) from Scenario if you can add Apache commons-io on your classpath:
String featureName = FilenameUtils.getBaseName(scenario.getUri().toString());
If you need the full feature file name with postfix you should use the getName(...) method instead:
String fullFeatureName = FilenameUtils.getName(scenario.getUri().toString());
I used the below method at Hooks class
#Before
public void beforeScenario(Scenario scenario){
// scenarioId = "file:///**/src/test/resources/features/namefeature.feature:99"
String scenarioId=scenario.getId();
int start=scenarioId.indexOf(File.separator+"features"+File.separator);
int end=scenarioId.indexOf(".");
String[] featureName=scenarioId.substring(start,end).split(File.separator+"features"+File.separator);
System.out.println("featureName ="+featureName[1]);
}
You can use Reporter to get the current running instance and then extract our the actual feature name from the feature file like so:
Object[] paramNames = Reporter.getCurrentTestResult().getParameters();
String featureName = paramNames[1].toString().replaceAll("^\"+|\"+$", "");
System.out.println("Feature file name: " + featureName);
Create a listener as below
import io.cucumber.plugin.ConcurrentEventListener;
import io.cucumber.plugin.event.EventHandler;
import io.cucumber.plugin.event.EventPublisher;
import io.cucumber.plugin.event.TestCaseStarted;
public class Listener implements ConcurrentEventListener {
#Override
public void setEventPublisher(EventPublisher eventPublisher) {
eventPublisher.registerHandlerFor(TestCaseStarted.class, testCaseStartedEventHandler);
}
private final EventHandler<TestCaseStarted> testCaseStartedEventHandler = event -> {
System.out.println("Current file fame : " + event.getTestCase().getUri().toString());
};
}
And then supply your listener to cucumber as below
"-p", "com.myProject.listener.Listener"
This will give you feature file name !
maybe like this, its return only filename:
private String getFeatureFileNameFromScenarioId(Scenario scenario) {
String[] tab = scenario.getId().split("/");
int rawFeatureNameLength = tab.length;
String featureName = tab[rawFeatureNameLength - 1].split(":")[0];
System.out.println("featureName: " + featureName);
return featureName;
}
I am using Scenario Outline with Examples. Examples have many rows. E.g. 10 rows. I have an After hook where I check the outcome of scenario passsed or failed and write it to a file. Now I need to save and close that file after executing the final row. How can I determine if the current scenario is the last one?
One option would be to tag the last example explicitly and have an After hook for that tag, as follows:
#others
Examples:
|input|
| abc |
| xyz |
#last
Examples:
|input|
| pqr |
#After("#last")
public void afterScenario() {
}
You would need something like an #AfterAll Hook, this is currently not supported in cucumber, but you can use this workaround which uses a jvm shutdown hook. :
static void addShutdownHook(WebDriver driver) {
Runtime.getRuntime().addShutdownHook(new Thread() {
#Override
public void run() {
// DO STUFF LIKE SAVING YOUR FILE
driver.quit();
}
});
}
Full example included in the shared driver example: https://github.com/cucumber/cucumber-jvm/blob/master/examples/java-webbit-websockets-selenium/src/test/java/cucumber/examples/java/websockets/SharedDriver.java
I have following scenario outline
Background:
Given customer is in hot or not page
Scenario Outline: Hot article
And customer enters <name>
And submits
And customer clicks thumbs up
Then ensure the TBD
Examples:
| name |
| Elliot |
| Florian |
and following step implementation -
#And("customer enters <name>")
public void customer_enters_name(String name) throws Throwable {
// Express the Regexp above with the code you wish you had
Thread.sleep(10000);
}
But when I execute test then I get following error -
You can implement missing steps with the snippets below:
#Given("^customer enters Elliot$")
public void customer_enters_Elliot() throws Throwable {
// Express the Regexp above with the code you wish you had
throw new PendingException();
}
#Given("^customer enters Florian$")
public void customer_enters_Florian() throws Throwable {
// Express the Regexp above with the code you wish you had
throw new PendingException();
}
Did I implement test steps wrong?
Instead of
Scenario Outline: ...
And customer enters <name>
...
Do this (Note the double quotes)
Scenario Outline: ...
And customer enters "<name>"
...
Just to add, The same error arise when in the runner class ,we put the wrong package of the step class
#CucumberOptions(glue = {"com.wrongpackage.step"})
public class TestRunner{
}
Step class should be present and the package should be correct.