How to get the Gherkin feature description runtime in java - cucumber

I need to report the feature description for the scenario that is being executes to report to other system.
Was able to get the scenario name from cucumber.api.Scenario; how I can the feature description ?
Is there any interface that I can use?
Using cucumber-Jvm, get the feature description runtime; as each scenario being executed might be from different feature files.

You can get the description of a feature by retrieving the Gherkin feature from CucumberFeature:
List<CucumberFeature> cucumberFeatures = new ArrayList<>();
FeatureBuilder featureBuilder = new FeatureBuilder(cucumberFeatures);
featureBuilder.parse(new FileResource(featureFile.getParentFile(), featureFile), new ArrayList());
for (CucumberFeature feature: cucumberFeatures) {
// Here we retrieve the Gherkin model
Feature f = feature.getGherkinFeature();
// Here we get name and description of the feature.
System.out.format("%s: %s%n", f.getName(), f.getDescription());
}
Another solution is to implement your own formatter, and do the parsing with Gherkin directly:
public class MyFormatter implements Formatter {
private List<Feature> features = new ArrayList<>();
public static void main(String... args) throws Exception {
OutputStreamWriter out = new OutputStreamWriter(System.out, "UTF-8");
// Read the feature file into a string.
File f = new File("/path/to/file.feature");
String input = FixJava.readReader(new FileReader(f));
// Parse the gherkin string with our own formatter.
MyFormatter formatter = new MyFormatter();
Parser parser = new Parser(formatter);
parser.parse(input, f.getPath(), 0);
for (Feature feature: formatter.features) {
System.out.format("%s: %s%n", feature.getName(), feature.getDescription());
}
}
#Override
public void feature(Feature feature) {
features.add(feature);
}
// ...
// follow all the Formatter methods to implement.
}

Related

BDD-JAVA- Is it possible to generate cucumber html reports with only scenario titles with out steps

I am currently using an HTML formatter to generate the Cucumber HTML report. The report is pretty, but I want the reports to be generated with all scenarios only with the title so that my report is not huge and easy to know which scenarios failed.
To clarify more, when cucumber HTML report is generated. I am seeing headers are divided into Steps (Passed, Failed, Skipped, Pending, Undefined), Scenarios(Passed, Failed, Skipped, Pending, Undefined), Feature. I just wanted to customize and print only Scenarios and remove steps section
enter image description here
public class HtmlFormatter extends CucumberJSONFormatter {
private static final String TIMESTAMP_FORMAT = "d MMM yyyy HH:mm:ss:SSS z";
public HtmlFormatter(Appendable out) {
super(out);
}
#Override
public void done() {
super.done();
final List<String> jsonFiles = new ArrayList<>();
final ConfigReader configReader = new ConfigReader();
final File reportOutputDirectory = new File("reports/html");
final int numThreads = Integer.valueOf(configReader.getProperty("maxThreads", "4"));
//in case running from single feature file
if (Main.isFeatureFileExecution()) {
final String singleFeatureFileExecutionReportPath = "reports/"+configReader.getProperty( "repo","RepoNameNotFound" ) +"/json/report.json";
if (new File(singleFeatureFileExecutionReportPath).exists()) {
jsonFiles.add(singleFeatureFileExecutionReportPath);
}
}
String projectName = “X”;
boolean runWithJenkins = true;
boolean parallelTesting = true;
Configuration configuration = new Configuration(reportOutputDirectory, projectName);
configuration.setParallelTesting(parallelTesting);
configuration.setRunWithJenkins(runWithJenkins);
if (!jsonFiles.isEmpty()) {
ReportBuilder reportBuilder = new ReportBuilder(jsonFiles, configuration);
Reportable result = reportBuilder.generateReports();
}
}
Write your own custom reporter based on the HTML reporter. As you are just trying to remove a small bit of functionality from the reporter this shouldn't be to difficult. Then use your reporter when running cucumber.

how to get current Cucumber feature file name at runtime using Java

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;
}

Lost headers when using UnZipResultSplitter

I'm using the Spring Integration Zip extension and it appears that I'm losing headers I've added upstream in the flow. I'm guessing that they are being lost in UnZipResultSplitter.splitUnzippedMap() as I don't see anything that explicitly copies them over.
I seem to recall that this is not unusual with splitters but I can't determine what strategy one should use in such a case.
Yep!
It looks like a bug.
The splitter contract is like this:
if (item instanceof Message) {
builder = this.getMessageBuilderFactory().fromMessage((Message<?>) item);
}
else {
builder = this.getMessageBuilderFactory().withPayload(item);
builder.copyHeaders(headers);
}
So, if those splitted items are messages already, like in case of our UnZipResultSplitter, we just use message as is without copying headers from upstream.
Please, raise a JIRA ticket (https://jira.spring.io/browse/INTEXT) on the matter.
Meanwhile let's consider some workaround:
public class MyUnZipResultSplitter {
public List<Message<Object>> splitUnzipped(Message<Map<String, Object>> unzippedEntries) {
final List<Message<Object>> messages = new ArrayList<Message<Object>>(unzippedEntries.size());
for (Map.Entry<String, Object> entry : unzippedEntries.getPayload().entrySet()) {
final String path = FilenameUtils.getPath(entry.getKey());
final String filename = FilenameUtils.getName(entry.getKey());
final Message<Object> splitMessage = MessageBuilder.withPayload(entry.getValue())
.setHeader(FileHeaders.FILENAME, filename)
.setHeader(ZipHeaders.ZIP_ENTRY_PATH, path)
.copyHeaders(unzippedEntries/getHeaders())
.build();
messages.add(splitMessage);
}
return messages;
}
}

dynamic template generation and formatting using freemarker

My goal is to format a collection of java map to a string (basically a csv) using free marker or anything else that would do smartly. I want to generate the template using a configuration data stored in database and managed from an admin application.
The configuration will tell me at what position a given data (key in hash map) need to go and also if any script need to run on this data before applying it at a given position. Several positions may be blank if the data in not in map.
I am thinking to use free-marker to build this generic tool and would appreciate if you could share how I should go about this.
Also would like to know if there is any built is support in spring-integration for building such process as the application is a SI application.
I am no freemarker expert, but a quick look at their quick start docs led me here...
public class FreemarkerTransformerPojo {
private final Configuration configuration;
private final Template template;
public FreemarkerTransformerPojo(String ftl) throws Exception {
this.configuration = new Configuration(Configuration.VERSION_2_3_23);
this.configuration.setDirectoryForTemplateLoading(new File("/"));
this.configuration.setDefaultEncoding("UTF-8");
this.template = this.configuration.getTemplate(ftl);
}
public String transform(Map<?, ?> map) throws Exception {
StringWriter writer = new StringWriter();
this.template.process(map, writer);
return writer.toString();
}
}
and
public class FreemarkerTransformerPojoTests {
#Test
public void test() throws Exception {
String template = System.getProperty("user.home") + "/Development/tmp/test.ftl";
OutputStream os = new FileOutputStream(new File(template));
os.write("foo=${foo}, bar=${bar}".getBytes());
os.close();
FreemarkerTransformerPojo transformer = new FreemarkerTransformerPojo(template);
Map<String, String> map = new HashMap<String, String>();
map.put("foo", "baz");
map.put("bar", "qux");
String result = transformer.transform(map);
assertEquals("foo=baz, bar=qux", result);
}
}
From a Spring Integration flow, send a message with a Map payload to
<int:transformer ... ref="fmTransformer" method="transform" />
Or you could do it with a groovy script (or other supported scripting language) using Spring Integration's existing scripting support without writing any code (except the script).

Using RazorEngine with TextWriter

I want to use RazorEngine to generate some html files. It's easy to generate strings first, then write them to files. But if the generated strings are too large, that will cause memory issues.
So I wonder is there a non-cached way to use RazorEngine, like using StreamWriter as its output rather than a string.
I google this for a while, but with no luck.
I think use a custom base template should be the right way, but the documents are so few(even out of date) on the offcial homepage of RazorEngine.
Any hint will be helpful!
OK. I figured it out.
Create a class that inherits TemplateBase<T>, and take a TextWrite parameter in the constructor.
public class TextWriterTemplate<T> : TemplateBase<T>
{
private readonly TextWriter _tw;
public TextWriterTemplate(TextWriter tw)
{
_tw = tw;
}
// override Write and WriteLiteral methods, write text using the TextWriter.
public override void Write(object value)
{
_tw.Write(value);
}
public override void WriteLiteral(string literal)
{
_tw.Write(literal);
}
}
Then use the template as this:
private static void Main(string[] args)
{
using (var sw = new StreamWriter(#"output.txt"))
{
var config = new FluentTemplateServiceConfiguration(c =>
c.WithBaseTemplateType(typeof(TextWriterTemplate<>))
.ActivateUsing(context => (ITemplate)Activator.CreateInstance(context.TemplateType, sw))
);
using (var service = new TemplateService(config))
{
service.Parse("Hello #Model.Name", new {Name = "Waku"}, null, null);
}
}
}
The content of output.txt should be Hello WAKU.

Resources