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;
}
Related
I'm trying to make Solr search phone numbers which are stored like this +79876543210 using a query like these:
+79876543210
79876543210
89876543210 <-- '+7' is replaced with region specific code '8'
9876543210 <-- '+7' entirely removed
This is just an example. Another one is wired line phone numbers:
+78662123456 <-- '+78662' is a specific region code
78662123456
88662123456
8662123456
123456 <-- region code entirely removed
One way I could manage this is using a separate field which is filled with these variants and used solely during search.
But this has issues with highlighting (it returns <em>123456</em> to be highlighted whereas the real value shown to user is +78662123456).
I thought that maybe it's best to make these indices using just Solr, but how?
First thought was to use managed synonyms filter and pass them along with each added record. But the docs explicitly states:
Changes made to managed resources via this REST API are not applied to the active Solr components until the Solr collection (or Solr core in single server mode) is reloaded.
So reloading a core every time after adding a record is not the way to go.
Other issues involve keeping these synonyms up to date with records.
Could there be another way to solve this?
Thanks to this comment (by MatsLindh) I've managed to assemble a simple filter based on bult-in EdgeNGramTokenFilter:
package com.step4;
import org.apache.lucene.analysis.TokenFilter;
import org.apache.lucene.analysis.TokenStream;
import org.apache.lucene.analysis.tokenattributes.CharTermAttribute;
import org.apache.lucene.analysis.tokenattributes.PositionIncrementAttribute;
import java.io.IOException;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class ReverseCustomFilter extends TokenFilter {
private static final PatternReplacementPair[] phonePatterns = {
new PatternReplacementPair("\\+7", "7"),
new PatternReplacementPair("\\+7", "8"),
new PatternReplacementPair("\\+7", ""),
new PatternReplacementPair("\\+78662", ""),
new PatternReplacementPair("\\+78663", ""),
};
private final CharTermAttribute termAtt = addAttribute(CharTermAttribute.class);
private final PositionIncrementAttribute posIncrAtt = addAttribute(PositionIncrementAttribute.class);
private int curPatternIndex;
private int curPosIncr;
private State curState;
public ReverseCustomFilter(TokenStream input) {
super(input);
}
#Override
public final boolean incrementToken() throws IOException {
while (true) {
if (curPatternIndex == 0) {
if (!input.incrementToken()) {
return false;
}
curState = captureState();
curPosIncr += posIncrAtt.getPositionIncrement();
curPatternIndex = 1;
}
if (curPatternIndex <= phonePatterns.length) {
PatternReplacementPair replacementPair = phonePatterns[curPatternIndex - 1];
curPatternIndex++;
restoreState(curState);
Matcher matcher = replacementPair.getPattern().matcher(termAtt);
if (matcher.find()) {
posIncrAtt.setPositionIncrement(curPosIncr);
curPosIncr = 0;
String replaced = matcher.replaceFirst(replacementPair.getReplacement());
termAtt.setEmpty().append(replaced);
return true;
}
}
else {
restoreState(curState);
posIncrAtt.setPositionIncrement(0);
curPatternIndex = 0;
return true;
}
}
}
#Override
public void reset() throws IOException {
super.reset();
curPatternIndex = 0;
curPosIncr = 0;
}
#Override
public void end() throws IOException {
super.end();
posIncrAtt.setPositionIncrement(curPosIncr);
}
private static class PatternReplacementPair {
private final Pattern pattern;
private final String replacement;
public PatternReplacementPair(String pattern, String replacement) {
this.pattern = Pattern.compile(pattern);
this.replacement = replacement;
}
public Pattern getPattern() {
return pattern;
}
public String getReplacement() {
return replacement;
}
}
}
I'm using v5 of web driver io and a cucumber framework. I have scenario outlines with multiple examples. I would like to close the browser and reopen it in between the examples so I have a clean webpage. But I can't find a way to do this. I'm sure I've seen anything about this but I can't find it.
I've looked through the webdriverio docs and the last things I can find was from 2016 which said it wasn't possible but there was a discussion about implementing something but I can't find any more detail.
Are you looking for this:
browser.reloadSession()
https://webdriver.io/docs/api/browser/reloadSession.html
You can use hooks, I share an example below.
UiHooks.java :
import cucumber.api.Scenario;
import cucumber.api.java.After;
import cucumber.api.java.Before;
public class UiHooks {
public static final String BASE_URL = "https://baseURL/";
private Scenario scenario;
#Before
public void beforeScenario(Scenario scenario) {
this.scenario = scenario;
}
#After(order = 1) //This will run first
public void afterScenario() {
if (scenario.isFailed()){
//do something like Secreen Shot or logger
}
}
#After(order = 0)//This will run second
public void afterTest() {
if (HookUtil.driver != null) {
HookUtil.driver.close();
}
if (HookUtil.seleniumBase != null) {
HookUtil.seleniumBase.stopService();
}
}
}
HookUtil.java :
public class HookUtil {
public static WebDriver driver = null;
public static SeleniumBase seleniumBase = null;
}
And then you can create a setup and call in the first step :
private void Setup() {
seleniumBase = new SeleniumBase(UiHooks.BASE_URL);
driver = seleniumBase.getDriver();
HookUtil.driver = driver;
HookUtil.seleniumBase = seleniumBase;
}
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.
}
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.
I am using spring security 3.1.3 for authentication via LDAP, code is working fine.Now, I want to get group of authenticated user. I've developed my custom LdapAuthoritiesPopulator in my application.Below is my code.
public Collection<? extends GrantedAuthority> getGrantedAuthorities(DirContextOperations userData, String username) {
List<GrantedAuthority> grantedAuthorities = null;
Object[] objects = userData.getObjectAttributes("memberOf");
for(Object object: objects){
System.out.println((String)object + "---------"+object.getClass());
}
}
console output : CN=Administrators,CN=Builtin,DC=example,DC=in
I don't want to perform string parsing, Is there any inbuilt function so that I can get group of authenticated user in my above implementation?
Have you considered using ActiveDirectoryLdapAuthenticationProvider instead of a customized LdapAuthenticationProvider? It's tailor made to deal with AD, e.g. the mapping from group memberships to authorities is already implemented in its loadUserAuthorities() method.
Refer to 19.5. Active Directory Authentication in the reference docs for more details.
Your question is really not clear about what you really want to do. I'm assuming based on whatever has been discussed so far that you want to extract (i.e., parse out) the name of the group from the DN you get. In your example, you want to extract the "CN=Administrators" RDN from "CN=Administrators,CN=Builtin,DC=example,DC=in" ??! Again, this is my assumption based on what I read and I understood (sort of).
If you don't want to do the parsing, you can perhaps use JNDI's CompoundnName class with your own syntax definition, but I'm not sure if using this class will give you any dramatic advantage over your own string parsing, which actually should not be complicated. But, here's how you can use CompoundName:
import java.util.Properties;
import javax.naming.CompoundName;
public class NameTestSimple {
public static void main(String[] args) throws Exception{
Properties syntax = new Properties();
syntax.setProperty("jndi.syntax.direction", "left_to_right");
syntax.setProperty("jndi.syntax.separator", ",");
syntax.setProperty("jndi.syntax.ignorecase", "true");
syntax.setProperty("jndi.syntax.escape", "\\");
syntax.setProperty("jndi.syntax.trimblanks", "true");
// syntax.setProperty("jndi.syntax.separator.ava", ",");
syntax.setProperty("jndi.syntax.separator.typeval", "=");
syntax.setProperty("jndi.syntax.beginquote", "\"");
String name = "CN=Administrators,CN=Builtin,DC=example,DC=in";
CompoundName cn = new CompoundName(name, syntax);
System.out.println("DN: " + cn);
System.out.println("\nCompoundName details:\n");
for (int i = 0; i < cn.size(); i++) {
System.out.println(" " + i + " --> " + cn.get(i));
}
}
}
Even with this, you will still need to parse the individual RDNs to get the attribute values (e.g., parse "CN=Administrators" to extract the value of 'Administrators').