Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
io.cucumber.core.plugin.SerenityReporter Maven / Gradle / Ivy
package io.cucumber.core.plugin;
import com.google.common.collect.Lists;
import io.cucumber.messages.types.*;
import io.cucumber.plugin.ConcurrentEventListener;
import io.cucumber.plugin.Plugin;
import io.cucumber.plugin.event.TestCaseFinished;
import io.cucumber.plugin.event.TestCaseStarted;
import io.cucumber.plugin.event.TestRunFinished;
import io.cucumber.plugin.event.TestRunStarted;
import io.cucumber.plugin.event.TestStep;
import io.cucumber.plugin.event.TestStepFinished;
import io.cucumber.plugin.event.TestStepStarted;
import io.cucumber.plugin.event.*;
import io.cucumber.tagexpressions.Expression;
import net.serenitybdd.core.Serenity;
import net.serenitybdd.core.SerenityListeners;
import net.serenitybdd.core.SerenityReports;
import net.serenitybdd.core.di.SerenityInfrastructure;
import net.serenitybdd.core.webdriver.configuration.RestartBrowserForEach;
import net.serenitybdd.cucumber.CucumberWithSerenity;
import net.serenitybdd.cucumber.formatting.ScenarioOutlineDescription;
import net.serenitybdd.cucumber.util.PathUtils;
import net.serenitybdd.cucumber.util.StepDefinitionAnnotationReader;
import net.thucydides.core.model.screenshots.StepDefinitionAnnotations;
import net.thucydides.model.domain.DataTable;
import net.thucydides.model.domain.Rule;
import net.thucydides.model.domain.*;
import net.thucydides.model.domain.stacktrace.RootCauseAnalyzer;
import net.thucydides.model.reports.ReportService;
import net.thucydides.model.requirements.FeatureFilePath;
import net.thucydides.core.steps.*;
import net.thucydides.model.steps.ExecutedStepDescription;
import net.thucydides.model.steps.StepFailure;
import net.thucydides.model.steps.TestSourceType;
import net.thucydides.model.util.Inflector;
import net.thucydides.model.webdriver.Configuration;
import net.thucydides.core.webdriver.ThucydidesWebDriverSupport;
import org.apache.commons.lang3.StringUtils;
import org.jetbrains.annotations.NotNull;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.net.URI;
import java.net.URLDecoder;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.concurrent.CopyOnWriteArraySet;
import java.util.stream.Collectors;
import static io.cucumber.core.plugin.TaggedScenario.*;
import static java.util.stream.Collectors.toList;
import static net.serenitybdd.core.webdriver.configuration.RestartBrowserForEach.FEATURE;
import static org.apache.commons.lang3.StringUtils.isEmpty;
import static org.apache.commons.lang3.StringUtils.isNotEmpty;
/**
* Cucumber Formatter for Serenity.
* @deprecated - use the SerenityParallelReporter now
*
* @author L.Carausu ([email protected] )
*/
@Deprecated(since="4.0.50")
public class SerenityReporter implements Plugin, ConcurrentEventListener {
private static final String OPEN_PARAM_CHAR = "\uff5f";
private static final String CLOSE_PARAM_CHAR = "\uff60";
private static final String SCENARIO_OUTLINE_NOT_KNOWN_YET = "";
private final Configuration systemConfiguration;
private final List baseStepListeners;
private final static String FEATURES_ROOT_PATH = "/features/";
private final static String FEATURES_CLASSPATH_ROOT_PATH = ":features/";
private final FeatureFileLoader featureLoader = new FeatureFileLoader();
private LineFilters lineFilters;
private List scenarioTags;
private static final Logger LOGGER = LoggerFactory.getLogger(SerenityReporter.class);
private final ManualScenarioChecker manualScenarioDateChecker;
private final ThreadLocal localContext = ThreadLocal.withInitial(ScenarioContext::new);
private final Set contextURISet = new CopyOnWriteArraySet<>();
protected ScenarioContext getContext() {
return localContext.get();
}
/**
* Constructor automatically called by cucumber when class is specified as plugin
* in @CucumberOptions.
*/
public SerenityReporter() {
this.systemConfiguration = SerenityInfrastructure.getConfiguration();
this.manualScenarioDateChecker = new ManualScenarioChecker(systemConfiguration.getEnvironmentVariables());
baseStepListeners = Collections.synchronizedList(new ArrayList<>());
}
public SerenityReporter(Configuration systemConfiguration) {
this.systemConfiguration = systemConfiguration;
this.manualScenarioDateChecker = new ManualScenarioChecker(systemConfiguration.getEnvironmentVariables());
baseStepListeners = Collections.synchronizedList(new ArrayList<>());
}
private final FeaturePathFormatter featurePathFormatter = new FeaturePathFormatter();
private StepEventBus getStepEventBus(URI featurePath) {
URI prefixedPath = featurePathFormatter.featurePathWithPrefixIfNecessary(featurePath);
return StepEventBus.eventBusFor(prefixedPath);
}
private void setStepEventBus(URI featurePath) {
URI prefixedPath = featurePathFormatter.featurePathWithPrefixIfNecessary(featurePath);
StepEventBus.setCurrentBusToEventBusFor(prefixedPath);
}
private void initialiseListenersFor(URI featurePath) {
if (getStepEventBus(featurePath).isBaseStepListenerRegistered()) {
return;
}
SerenityListeners listeners = new SerenityListeners(getStepEventBus(featurePath), systemConfiguration);
baseStepListeners.add(listeners.getBaseStepListener());
}
private final EventHandler testSourceReadHandler = this::handleTestSourceRead;
private final EventHandler caseStartedHandler = this::handleTestCaseStarted;
private final EventHandler caseFinishedHandler = this::handleTestCaseFinished;
private final EventHandler stepStartedHandler = this::handleTestStepStarted;
private final EventHandler stepFinishedHandler = this::handleTestStepFinished;
private final EventHandler runStartedHandler = this::handleTestRunStarted;
private final EventHandler runFinishedHandler = this::handleTestRunFinished;
private final EventHandler writeEventHandler = this::handleWrite;
protected void handleTestRunStarted(TestRunStarted event) {
}
@Override
public void setEventPublisher(EventPublisher publisher) {
publisher.registerHandlerFor(TestRunStarted.class, runStartedHandler);
publisher.registerHandlerFor(TestSourceRead.class, testSourceReadHandler);
publisher.registerHandlerFor(TestCaseStarted.class, caseStartedHandler);
publisher.registerHandlerFor(TestStepStarted.class, stepStartedHandler);
publisher.registerHandlerFor(TestStepFinished.class, stepFinishedHandler);
publisher.registerHandlerFor(TestCaseFinished.class, caseFinishedHandler);
publisher.registerHandlerFor(TestRunFinished.class, runFinishedHandler);
publisher.registerHandlerFor(WriteEvent.class, writeEventHandler);
}
protected void handleTestSourceRead(TestSourceRead event) {
featureLoader.addTestSourceReadEvent(event);
URI featurePath = event.getUri();
featureFrom(featurePath).ifPresent(
feature -> {
getContext().setFeatureTags(feature.getTags());
resetEventBusFor(featurePath);
initialiseListenersFor(featurePath);
configureDriver(feature, featurePath);
Story userStory = userStoryFrom(feature, relativeUriFrom(event.getUri()));
getStepEventBus(event.getUri()).testSuiteStarted(userStory);
}
);
}
private void resetEventBusFor(URI featurePath) {
StepEventBus.clearEventBusFor(featurePath);
}
private String relativeUriFrom(URI fullPathUri) {
boolean useDecodedURI = systemConfiguration.getEnvironmentVariables().getPropertyAsBoolean("use.decoded.url", false);
String pathURIAsString;
if (useDecodedURI) {
pathURIAsString = URLDecoder.decode(fullPathUri.toString(), StandardCharsets.UTF_8);
} else {
pathURIAsString = fullPathUri.toString();
}
if (pathURIAsString.contains(FEATURES_ROOT_PATH)) {
return StringUtils.substringAfterLast(pathURIAsString, FEATURES_ROOT_PATH);
} else {
return pathURIAsString;
}
}
protected Optional featureFrom(URI featureFileUri) {
LOGGER.debug("Running feature from " + featureFileUri.toString());
if (!featureFileUri.toString().contains(FEATURES_ROOT_PATH) && !featureFileUri.toString().contains(FEATURES_CLASSPATH_ROOT_PATH)) {
LOGGER.warn("Feature from " + featureFileUri + " is not under the 'features' directory. Requirements report will not be correctly generated!");
}
String defaultFeatureId = PathUtils.getAsFile(featureFileUri).getName().replace(".feature", "");
String defaultFeatureName = Inflector.getInstance().humanize(defaultFeatureId);
parseGherkinIn(featureFileUri);
if (isEmpty(featureLoader.getFeatureName(featureFileUri))) {
return Optional.empty();
}
Feature feature = featureLoader.getFeature(featureFileUri);
if (feature.getName().isEmpty()) {
feature = featureLoader.featureWithDefaultName(feature, defaultFeatureName);
}
return Optional.of(feature);
}
private void parseGherkinIn(URI featureFileUri) {
try {
featureLoader.getFeature(featureFileUri);
} catch (Throwable ignoreParsingErrors) {
LOGGER.warn("Could not parse the Gherkin in feature file " + featureFileUri + ": file ignored");
}
}
private Story userStoryFrom(Feature feature, String featureFileUri) {
String relativePath = new FeatureFilePath(systemConfiguration.getEnvironmentVariables()).relativePathFor(featureFileUri);
// obtain an id by removing the ".feature" extension and replacing illegal characters with underscores
String id = relativePath.replace(".feature", "");
Story userStory = Story.withIdAndPath(id, feature.getName(), relativePath).asFeature();
if (!isEmpty(feature.getDescription())) {
userStory = userStory.withNarrative(feature.getDescription());
}
return userStory;
}
protected void handleTestCaseStarted(TestCaseStarted event) {
URI featurePath = event.getTestCase().getUri();
getContext().currentFeaturePathIs(featurePath);
contextURISet.add(featurePath);
setStepEventBus(featurePath);
if (FeatureTracker.isNewFeature(event)) {
// Shut down any drivers remaining open from a previous feature, if @singlebrowser is used.
// Cucumber has no event to mark the start and end of a feature, so we need to do this here.
if (RestartBrowserForEach.configuredIn(systemConfiguration.getEnvironmentVariables()).restartBrowserForANew(FEATURE)) {
ThucydidesWebDriverSupport.closeCurrentDrivers();
}
FeatureTracker.startNewFeature(event);
}
String scenarioName = event.getTestCase().getName();
TestSourcesModel.AstNode astNode = featureLoader.getAstNode(getContext().currentFeaturePath(), event.getTestCase().getLocation().getLine());
Optional currentFeature = featureFrom(featurePath);
if ((astNode != null) && currentFeature.isPresent()) {
getContext().setCurrentScenarioDefinitionFrom(astNode);
//the sources are read in parallel, global current feature cannot be used
String scenarioId = scenarioIdFrom(currentFeature.get().getName(), TestSourcesModel.convertToId(getContext().currentScenarioDefinition.getName()));
boolean newScenario = !scenarioId.equals(getContext().getCurrentScenario());
if (newScenario) {
configureDriver(currentFeature.get(), getContext().currentFeaturePath());
if (getContext().isAScenarioOutline()) {
getContext().startNewExample();
handleExamples(currentFeature.get(),
getContext().currentScenarioOutline().getTags(),
getContext().currentScenarioOutline().getName(),
getContext().currentScenarioOutline().getExamples());
}
startOfScenarioLifeCycle(currentFeature.get(), scenarioName, getContext().currentScenarioDefinition, event.getTestCase().getLocation().getLine());
getContext().currentScenario = scenarioIdFrom(currentFeature.get().getName(), TestSourcesModel.convertToId(getContext().currentScenarioDefinition.getName()));
} else {
if (getContext().isAScenarioOutline()) {
startExample(Long.valueOf(event.getTestCase().getLocation().getLine()), scenarioName);
}
}
TestSourcesModel.getBackgroundForTestCase(astNode).ifPresent(this::handleBackground);
}
io.cucumber.messages.types.Rule rule = getRuleForTestCase(astNode);
if (rule != null) {
getContext().stepEventBus().setRule(Rule.from(rule));
}
}
private io.cucumber.messages.types.Rule getRuleForTestCase(TestSourcesModel.AstNode astNode) {
Feature feature = getFeatureForTestCase(astNode);
Scenario existingScenario = TestSourcesModel.getScenarioDefinition(astNode);
List childrenList = feature.getChildren();
for (FeatureChild featureChild : childrenList) {
if (scenarioIsIncludedInARule(existingScenario, featureChild)) {
return featureChild.getRule().get();
}
}
return null;
}
private boolean scenarioIsIncludedInARule(Scenario existingScenario, FeatureChild featureChild) {
return featureChild.getRule() != null && featureChild.getRule().isPresent()
&& featureChild.getRule().get().getChildren().stream().
filter(rc -> rc.getScenario().isPresent()).
map(rc -> rc.getScenario().get()).collect(Collectors.toList()).contains(existingScenario);
}
private Feature getFeatureForTestCase(TestSourcesModel.AstNode astNode) {
while (astNode.parent != null) {
astNode = astNode.parent;
}
return (Feature) astNode.node;
}
protected void handleTestCaseFinished(TestCaseFinished event) {
if (getContext().examplesAreRunning()) {
handleResult(event.getResult());
finishExample();
}
if (Status.FAILED.equals(event.getResult().getStatus()) && noAnnotatedResultIdDefinedFor(event)) {
getStepEventBus(event.getTestCase().getUri()).testFailed(event.getResult().getError());
} else {
getStepEventBus(event.getTestCase().getUri()).testFinished(getContext().examplesAreRunning());
}
getContext().clearStepQueue();
}
private boolean noAnnotatedResultIdDefinedFor(TestCaseFinished event) {
BaseStepListener baseStepListener = getStepEventBus(event.getTestCase().getUri()).getBaseStepListener();
return (baseStepListener.getTestOutcomes().isEmpty() || (latestOf(baseStepListener.getTestOutcomes()).getAnnotatedResult() == null));
}
private TestOutcome latestOf(List testOutcomes) {
return testOutcomes.get(testOutcomes.size() - 1);
}
protected void handleTestStepStarted(TestStepStarted event) {
StepDefinitionAnnotations.setScreenshotPreferencesTo(
StepDefinitionAnnotationReader
.withScreenshotLevel((TakeScreenshots) systemConfiguration.getScreenshotLevel()
.orElse(TakeScreenshots.UNDEFINED))
.forStepDefinition(event.getTestStep().getCodeLocation())
.getScreenshotPreferences());
if (!(event.getTestStep() instanceof HookTestStep)) {
if (event.getTestStep() instanceof PickleStepTestStep) {
PickleStepTestStep pickleTestStep = (PickleStepTestStep) event.getTestStep();
TestSourcesModel.AstNode astNode = featureLoader.getAstNode(getContext().currentFeaturePath(), pickleTestStep.getStepLine());
if (astNode != null) {
//io.cucumber.core.internal.gherkin.ast.Step step = (io.cucumber.core.internal.gherkin.ast.Step) astNode.node;
io.cucumber.messages.types.Step step = (io.cucumber.messages.types.Step) astNode.node;
if (!getContext().isAddingScenarioOutlineSteps()) {
getContext().queueStep(step);
getContext().queueTestStep(event.getTestStep());
}
if (getContext().isAScenarioOutline()) {
int lineNumber = event.getTestCase().getLocation().getLine();
getContext().stepEventBus().updateExampleLineNumber(lineNumber);
}
io.cucumber.messages.types.Step currentStep = getContext().getCurrentStep();
String stepTitle = stepTitleFrom(currentStep, pickleTestStep);
getContext().stepEventBus().stepStarted(ExecutedStepDescription.withTitle(stepTitle));
getContext().stepEventBus().updateCurrentStepTitle(normalized(stepTitle));
}
}
}
}
protected void handleWrite(WriteEvent event) {
getContext().stepEventBus().stepStarted(ExecutedStepDescription.withTitle(event.getText()));
getContext().stepEventBus().stepFinished();
}
protected void handleTestStepFinished(TestStepFinished event) {
if (!(event.getTestStep() instanceof HookTestStep)) {
handleResult(event.getResult());
StepDefinitionAnnotations.clear();
}
}
protected void handleTestRunFinished(TestRunFinished event) {
generateReports();
assureTestSuiteFinished();
}
private ReportService getReportService() {
return SerenityReports.getReportService(systemConfiguration);
}
private void configureDriver(Feature feature, URI featurePath) {
getStepEventBus(featurePath).setUniqueSession(systemConfiguration.shouldUseAUniqueBrowser());
List tags = getTagNamesFrom(feature.getTags());
String requestedDriver = getDriverFrom(tags);
String requestedDriverOptions = getDriverOptionsFrom(tags);
if (isNotEmpty(requestedDriver)) {
ThucydidesWebDriverSupport.useDefaultDriver(requestedDriver);
ThucydidesWebDriverSupport.useDriverOptions(requestedDriverOptions);
}
}
private List getTagNamesFrom(List tags) {
List tagNames = new ArrayList<>();
for (Tag tag : tags) {
tagNames.add(tag.getName());
}
return tagNames;
}
private String getDriverFrom(List tags) {
String requestedDriver = null;
for (String tag : tags) {
if (tag.startsWith("@driver:")) {
requestedDriver = tag.substring(8);
}
}
return requestedDriver;
}
private String getDriverOptionsFrom(List tags) {
String requestedDriver = null;
for (String tag : tags) {
if (tag.startsWith("@driver-options:")) {
requestedDriver = tag.substring(16);
}
}
return requestedDriver;
}
private void handleExamples(Feature currentFeature, List scenarioOutlineTags, String id, List examplesList) {
lineFilters = LineFilters.forCurrentContext();
String featureName = currentFeature.getName();
List currentFeatureTags = currentFeature.getTags();
getContext().doneAddingScenarioOutlineSteps();
initializeExamples();
for (Examples examples : examplesList) {
if (examplesAreNotExcludedByTags(examples, scenarioOutlineTags, currentFeatureTags)
&& lineFilters.examplesAreNotExcluded(examples, getContext().currentFeaturePath())) {
List examplesTableRows = examples
.getTableBody()
.stream()
.filter(tableRow -> lineFilters.tableRowIsNotExcludedBy(tableRow, getContext().currentFeaturePath()))
.collect(Collectors.toList());
List headers = getHeadersFrom(examples.getTableHeader().get());
List> rows = getValuesFrom(examplesTableRows, headers);
Map lineNumbersOfEachRow = new HashMap<>();
for (int i = 0; i < examplesTableRows.size(); i++) {
TableRow tableRow = examplesTableRows.get(i);
lineNumbersOfEachRow.put(i, tableRow.getLocation().getLine());
addRow(exampleRows(), headers, tableRow);
if (examples.getTags() != null) {
exampleTags().put(examplesTableRows.get(i).getLocation().getLine(), examples.getTags());
}
}
String scenarioId = scenarioIdFrom(featureName, id);
boolean newScenario = !getContext().hasScenarioId(scenarioId);
String exampleTableName = trim(examples.getName());
String exampleTableDescription = trim(examples.getDescription());
if (newScenario) {
getContext().setTable(
dataTableFrom(SCENARIO_OUTLINE_NOT_KNOWN_YET,
headers,
rows,
exampleTableName,
exampleTableDescription,
lineNumbersOfEachRow));
} else {
getContext().addTableRows(headers,
rows,
exampleTableName,
exampleTableDescription,
lineNumbersOfEachRow);
}
getContext().addTableTags(tagsIn(examples));
getContext().setCurrentScenarioId(scenarioId);
}
}
}
@NotNull
private List tagsIn(Examples examples) {
return examples.getTags().stream().map(tag -> TestTag.withValue(tag.getName().substring(1))).collect(Collectors.toList());
}
private boolean examplesAreNotExcludedByTags(Examples examples, List scenarioOutlineTags, List currentFeatureTags) {
if (testRunHasFilterTags()) {
return examplesMatchFilter(examples, scenarioOutlineTags, currentFeatureTags);
}
return true;
}
private boolean examplesMatchFilter(Examples examples, List scenarioOutlineTags, List currentFeatureTags) {
List allExampleTags = getExampleAllTags(examples, scenarioOutlineTags, currentFeatureTags);
List allTagsForAnExampleScenario = allExampleTags.stream().map(Tag::getName).collect(Collectors.toList());
Expression tagValuesFromCucumberOptions = getCucumberRuntimeTags().get(0);
// Expression expressionNode = TagExpressionParser.parse(tagValuesFromCucumberOptions);
// return expressionNode.evaluate(allTagsForAnExampleScenario);
return tagValuesFromCucumberOptions.evaluate(allTagsForAnExampleScenario);
}
private boolean testRunHasFilterTags() {
List tagFilters = getCucumberRuntimeTags();
return (tagFilters != null) && tagFilters.size() > 0;
}
private List getCucumberRuntimeTags() {
if (CucumberWithSerenity.currentRuntimeOptions() == null) {
return new ArrayList<>();
} else {
return CucumberWithSerenity.currentRuntimeOptions().getTagExpressions();
}
}
private List getExampleAllTags(Examples examples, List scenarioOutlineTags, List currentFeatureTags) {
List exampleTags = examples.getTags();
List allTags = new ArrayList<>();
if (exampleTags != null)
allTags.addAll(exampleTags);
if (scenarioOutlineTags != null)
allTags.addAll(scenarioOutlineTags);
if (currentFeatureTags != null)
allTags.addAll(currentFeatureTags);
return allTags;
}
private List getHeadersFrom(TableRow headerRow) {
return headerRow.getCells().stream().map(TableCell::getValue).collect(Collectors.toList());
}
private List> getValuesFrom(List examplesTableRows, List headers) {
List> rows = new ArrayList<>();
for (int row = 0; row < examplesTableRows.size(); row++) {
Map rowValues = new HashMap<>();
int column = 0;
List cells = examplesTableRows.get(row).getCells().stream().map(TableCell::getValue).collect(Collectors.toList());
for (String cellValue : cells) {
String columnName = headers.get(column++);
rowValues.put(columnName, cellValue);
}
rows.add(rowValues);
}
return rows;
}
private void addRow(Map> exampleRows,
List headers,
TableRow currentTableRow) {
Map row = new LinkedHashMap<>();
for (int j = 0; j < headers.size(); j++) {
List cells = currentTableRow.getCells().stream().map(TableCell::getValue).collect(Collectors.toList());
row.put(headers.get(j), cells.get(j));
}
exampleRows().put(currentTableRow.getLocation().getLine(), row);
}
private String scenarioIdFrom(String featureId, String scenarioIdOrExampleId) {
return (featureId != null && scenarioIdOrExampleId != null) ? String.format("%s;%s", featureId, scenarioIdOrExampleId) : "";
}
private void initializeExamples() {
getContext().setExamplesRunning(true);
}
private Map> exampleRows() {
if (getContext().exampleRows == null) {
getContext().exampleRows = Collections.synchronizedMap(new HashMap<>());
}
return getContext().exampleRows;
}
private Map> exampleTags() {
if (getContext().exampleTags == null) {
getContext().exampleTags = Collections.synchronizedMap(new HashMap<>());
}
return getContext().exampleTags;
}
private DataTable dataTableFrom(String scenarioOutline,
List headers,
List> rows,
String name,
String description,
Map lineNumbersOfEachRow) {
return DataTable.withHeaders(headers)
.andScenarioOutline(scenarioOutline)
.andMappedRows(rows, lineNumbersOfEachRow)
.andTitle(name)
.andDescription(description)
.build();
}
private DataTable addTableRowsTo(DataTable table, List headers,
List> rows,
String name,
String description) {
table.startNewDataSet(name, description);
for (Map row : rows) {
table.appendRow(rowValuesFrom(headers, row));
}
return table;
}
private List rowValuesFrom(List headers, Map row) {
return headers.stream()
.map(header -> row.get(header))
.collect(toList());
}
private void startOfScenarioLifeCycle(Feature feature, String scenarioName, Scenario scenario, Integer currentLine) {
boolean newScenario = !scenarioIdFrom(TestSourcesModel.convertToId(feature.getName()), TestSourcesModel.convertToId(scenario.getName())).equals(getContext().currentScenario);
getContext().currentScenario = scenarioIdFrom(TestSourcesModel.convertToId(feature.getName()), TestSourcesModel.convertToId(scenario.getName()));
if (getContext().examplesAreRunning()) {
if (newScenario) {
startScenario(feature, scenario, scenario.getName());
getContext().stepEventBus().useExamplesFrom(getContext().getTable());
getContext().stepEventBus().useScenarioOutline(ScenarioOutlineDescription.from(scenario).getDescription());
} else {
getContext().stepEventBus().addNewExamplesFrom(getContext().getTable());
}
startExample(Long.valueOf(currentLine), scenarioName);
} else {
startScenario(feature, scenario, scenarioName);
}
}
private void startScenario(Feature currentFeature, Scenario scenarioDefinition, String scenarioName) {
getContext().stepEventBus().setTestSource(TestSourceType.TEST_SOURCE_CUCUMBER.getValue());
getContext().stepEventBus()
.testStarted(scenarioName,
scenarioIdFrom(TestSourcesModel.convertToId(currentFeature.getName()),
TestSourcesModel.convertToId(scenarioName)));
getContext().stepEventBus().addDescriptionToCurrentTest(scenarioDefinition.getDescription());
getContext().stepEventBus().addTagsToCurrentTest(convertCucumberTags(currentFeature.getTags()));
getContext().stepEventBus().addTagsToCurrentTest(tagsInEnclosingRule(currentFeature, scenarioDefinition));
if (isScenario(scenarioDefinition)) {
getContext().stepEventBus().addTagsToCurrentTest(convertCucumberTags(scenarioDefinition.getTags()));
} else if (isScenarioOutline(scenarioDefinition)) {
getContext().stepEventBus().addTagsToCurrentTest(convertCucumberTags(scenarioDefinition.getTags()));
}
registerFeatureJiraIssues(currentFeature.getTags());
List tags = getTagsOfScenarioDefinition(scenarioDefinition);
registerScenarioJiraIssues(tags);
scenarioTags = tagsForScenario(scenarioDefinition);
updateResultFromTags(scenarioTags);
}
private List tagsInEnclosingRule(Feature feature, Scenario scenario) {
List nestedRules = feature.getChildren().stream()
.filter(fc -> fc.getRule().isPresent())
.map(fc -> fc.getRule().get())
.filter(Objects::nonNull)
.collect(toList());
return nestedRules.stream()
.filter(rule -> containsScenario(rule, scenario))
.flatMap(rule -> convertCucumberTags(rule.getTags()).stream())
.collect(toList());
}
private boolean containsScenario(io.cucumber.messages.types.Rule rule, Scenario scenario) {
return rule.getChildren().stream().anyMatch(child -> child.getScenario().isPresent() && child.getScenario().get() == scenario);
}
private List tagsForScenario(Scenario scenarioDefinition) {
List scenarioTags = new ArrayList<>(getContext().featureTags);
scenarioTags.addAll(getTagsOfScenarioDefinition(scenarioDefinition));
return scenarioTags;
}
private boolean isScenario(Scenario scenarioDefinition) {
return scenarioDefinition.getExamples().isEmpty();
}
private boolean isScenarioOutline(Scenario scenarioDefinition) {
return scenarioDefinition.getExamples().size() > 0;
}
private List getTagsOfScenarioDefinition(Scenario scenarioDefinition) {
List tags = new ArrayList<>();
if (isScenario(scenarioDefinition)) {
tags = scenarioDefinition.getTags();
} else if (isScenarioOutline(scenarioDefinition)) {
tags = scenarioDefinition.getTags();
}
return tags;
}
private void registerFeatureJiraIssues(List tags) {
List issues = extractJiraIssueTags(tags);
if (!issues.isEmpty()) {
getContext().stepEventBus().addIssuesToCurrentStory(issues);
}
}
private void registerScenarioJiraIssues(List tags) {
List issues = extractJiraIssueTags(tags);
if (!issues.isEmpty()) {
getContext().stepEventBus().addIssuesToCurrentTest(issues);
}
}
private List convertCucumberTags(List cucumberTags) {
cucumberTags = completeManualTagsIn(cucumberTags);
return cucumberTags.stream()
.map(tag -> TestTag.withValue(tag.getName().substring(1)))
.collect(toList());
}
private List completeManualTagsIn(List cucumberTags) {
if (unqualifiedManualTag(cucumberTags).isPresent() && doesNotContainResultTag(cucumberTags)) {
List updatedTags = Lists.newArrayList(cucumberTags);
Tag newManualTag = new Tag(unqualifiedManualTag(cucumberTags).get().getLocation(),
"@manual:pending",
UUID.randomUUID().toString());
updatedTags.add(newManualTag);
return updatedTags;
} else {
return cucumberTags;
}
}
private boolean doesNotContainResultTag(List tags) {
return !tags.stream().noneMatch(tag -> tag.getName().startsWith("@manual:"));
}
private Optional unqualifiedManualTag(List tags) {
return tags.stream().filter(tag -> tag.getName().equalsIgnoreCase("@manual")).findFirst();
}
private List extractJiraIssueTags(List cucumberTags) {
List issues = new ArrayList<>();
for (Tag tag : cucumberTags) {
if (tag.getName().startsWith("@issue:")) {
String tagIssueValue = tag.getName().substring("@issue:".length());
issues.addAll(Arrays.asList(tagIssueValue.split(",")));
}
if (tag.getName().startsWith("@issues:")) {
String tagIssuesValues = tag.getName().substring("@issues:".length());
issues.addAll(Arrays.asList(tagIssuesValues.split(",")));
}
}
return issues;
}
private void startExample(Long lineNumber, String scenarioName) {
Map data = exampleRows().get(lineNumber);
getContext().stepEventBus().clearStepFailures();
getContext().stepEventBus().exampleStarted(data, scenarioName);
if (exampleTags().containsKey(lineNumber)) {
List currentExampleTags = exampleTags().get(lineNumber);
getContext().stepEventBus().addTagsToCurrentTest(convertCucumberTags(currentExampleTags));
}
}
private void finishExample() {
getContext().stepEventBus().exampleFinished();
getContext().exampleCount--;
if (getContext().exampleCount == 0) {
getContext().setExamplesRunning(false);
setTableScenarioOutline();
} else {
getContext().setExamplesRunning(true);
}
}
private void setTableScenarioOutline() {
List steps = getContext().currentScenarioDefinition.getSteps();
StringBuffer scenarioOutlineBuffer = new StringBuffer();
for (io.cucumber.messages.types.Step step : steps) {
scenarioOutlineBuffer.append(step.getKeyword()).append(step.getText()).append("\n\r");
}
String scenarioOutline = scenarioOutlineBuffer.toString();
if (getContext().getTable() != null) {
getContext().getTable().setScenarioOutline(scenarioOutline);
}
}
private void handleBackground(Background background) {
getContext().waitingToProcessBackgroundSteps = true;
String backgroundName = background.getName();
if (backgroundName != null) {
getContext().stepEventBus().setBackgroundTitle(backgroundName);
}
String backgroundDescription = background.getDescription();
if (backgroundDescription == null) {
backgroundDescription = "";
}
getContext().stepEventBus().setBackgroundDescription(backgroundDescription);
}
private void assureTestSuiteFinished() {
getContext().clearStepQueue();
getContext().clearTestStepQueue();
contextURISet.forEach(this::cleanupTestResourcesForURI);
contextURISet.clear();
Serenity.done();
getContext().clearTable();
getContext().setCurrentScenarioId(null);
}
private void cleanupTestResourcesForURI(URI uri) {
getStepEventBus(uri).testSuiteFinished();
getStepEventBus(uri).dropAllListeners();
getStepEventBus(uri).clear();
StepEventBus.clearEventBusFor(uri);
}
private void handleResult(Result result) {
io.cucumber.messages.types.Step currentStep = getContext().nextStep();
TestStep currentTestStep = getContext().nextTestStep();
recordStepResult(result, currentStep, currentTestStep);
if (getContext().noStepsAreQueued()) {
recordFinalResult();
}
}
private void recordStepResult(Result result, io.cucumber.messages.types.Step currentStep, TestStep currentTestStep) {
if (Status.SKIPPED.equals(result.getStatus())) {
skipped(stepTitleFrom(currentStep, currentTestStep), result.getError());
} else if (Status.PENDING.equals(result.getStatus())) {
getContext().stepEventBus().stepPending();
} else if (Status.UNDEFINED.equals(result.getStatus())) {
getContext().stepEventBus().stepPending();
} else if (getContext().stepEventBus().currentTestIsSuspended()) {
getContext().stepEventBus().stepIgnored();
} else if (Status.PASSED.equals(result.getStatus())) {
getContext().stepEventBus().stepFinished();
} else if (Status.FAILED.equals(result.getStatus())) {
failed(stepTitleFrom(currentStep, currentTestStep), result.getError());
}
}
private void recordFinalResult() {
if (getContext().waitingToProcessBackgroundSteps) {
getContext().waitingToProcessBackgroundSteps = false;
} else {
updateResultFromTags(scenarioTags);
}
}
private void updateResultFromTags(List scenarioTags) {
if (isManual(scenarioTags)) {
updateManualResultsFrom(scenarioTags);
} else if (isPending(scenarioTags)) {
getContext().stepEventBus().testPending();
} else if (isSkippedOrWIP(scenarioTags)) {
getContext().stepEventBus().testSkipped();
updateCurrentScenarioResultTo(TestResult.SKIPPED);
} else if (isIgnored(scenarioTags)) {
getContext().stepEventBus().testIgnored();
updateCurrentScenarioResultTo(TestResult.IGNORED);
}
}
private void updateManualResultsFrom(List scenarioTags) {
getContext().stepEventBus().testIsManual();
manualResultDefinedIn(scenarioTags).ifPresent(
testResult ->
UpdateManualScenario.forScenario(getContext().currentScenarioDefinition.getDescription())
.inContext(getContext().stepEventBus().getBaseStepListener(), systemConfiguration.getEnvironmentVariables())
.updateManualScenario(testResult, scenarioTags)
);
}
private void updateCurrentScenarioResultTo(TestResult pending) {
getContext().stepEventBus().getBaseStepListener().overrideResultTo(pending);
}
private void failed(String stepTitle, Throwable cause) {
if (!errorOrFailureRecordedForStep(stepTitle, cause)) {
if (!isEmpty(stepTitle)) {
getContext().stepEventBus().updateCurrentStepTitle(stepTitle);
}
Throwable rootCause = new RootCauseAnalyzer(cause).getRootCause().toException();
if (isAssumptionFailure(rootCause)) {
getContext().stepEventBus().assumptionViolated(rootCause.getMessage());
} else {
getContext().stepEventBus().stepFailed(new StepFailure(ExecutedStepDescription.withTitle(normalized(currentStepTitle())), rootCause));
}
}
}
private void skipped(String stepTitle, Throwable cause) {
if (!errorOrFailureRecordedForStep(stepTitle, cause)) {
if (!isEmpty(stepTitle)) {
getContext().stepEventBus().updateCurrentStepTitle(stepTitle);
}
if (cause == null) {
getContext().stepEventBus().stepIgnored();
} else {
Throwable rootCause = new RootCauseAnalyzer(cause).getRootCause().toException();
if (isAssumptionFailure(rootCause)) {
getContext().stepEventBus().assumptionViolated(rootCause.getMessage());
} else {
getContext().stepEventBus().stepIgnored();
}
}
}
}
private String currentStepTitle() {
return getContext().stepEventBus().getCurrentStep().isPresent()
? getContext().stepEventBus().getCurrentStep().get().getDescription() : "";
}
private boolean errorOrFailureRecordedForStep(String stepTitle, Throwable cause) {
if (!latestTestOutcome().isPresent()) {
return false;
}
if (!latestTestOutcome().get().testStepWithDescription(stepTitle).isPresent()) {
return false;
}
Optional matchingTestStep = latestTestOutcome().get().testStepWithDescription(stepTitle);
if (matchingTestStep.isPresent() && matchingTestStep.get().getNestedException() != null) {
return (matchingTestStep.get().getNestedException().getOriginalCause() == cause);
}
return false;
}
private Optional latestTestOutcome() {
if (!getContext().stepEventBus().isBaseStepListenerRegistered()) {
return Optional.empty();
}
List recordedOutcomes = getContext().stepEventBus().getBaseStepListener().getTestOutcomes();
return (recordedOutcomes.isEmpty()) ? Optional.empty()
: Optional.of(recordedOutcomes.get(recordedOutcomes.size() - 1));
}
private boolean isAssumptionFailure(Throwable rootCause) {
try {
Class> assumptionViolationException = Class.forName("org.junit.AssumptionViolatedException");
return assumptionViolationException.isAssignableFrom(rootCause.getClass());
} catch (ClassNotFoundException var3) {
return false;
}
}
private String stepTitleFrom(io.cucumber.messages.types.Step currentStep, TestStep testStep) {
if (currentStep != null && testStep instanceof PickleStepTestStep)
return currentStep.getKeyword()
+ ((PickleStepTestStep) testStep).getStep().getText()
+ embeddedTableDataIn((PickleStepTestStep) testStep);
return "";
}
private String embeddedTableDataIn(PickleStepTestStep currentStep) {
if (currentStep.getStep().getArgument() != null) {
StepArgument stepArgument = currentStep.getStep().getArgument();
if (stepArgument instanceof DataTableArgument) {
List> rowList = new ArrayList>();
for (List row : ((DataTableArgument) stepArgument).cells()) {
Map rowMap = new HashMap();
rowMap.put("cells", row);
rowList.add(rowMap);
}
return convertToTextTable(rowList);
}
}
return "";
}
private String convertToTextTable(List> rows) {
StringBuilder textTable = new StringBuilder();
textTable.append(System.lineSeparator());
for (Map row : rows) {
textTable.append("|");
for (String cell : (List) row.get("cells")) {
textTable.append(" ");
textTable.append(cell);
textTable.append(" |");
}
if (row != rows.get(rows.size() - 1)) {
textTable.append(System.lineSeparator());
}
}
return textTable.toString();
}
private void generateReports() {
getReportService().generateReportsFor(getAllTestOutcomes());
}
public List getAllTestOutcomes() {
return baseStepListeners.stream().map(BaseStepListener::getTestOutcomes).flatMap(List::stream)
.collect(Collectors.toList());
}
private String normalized(String value) {
return value.replaceAll(OPEN_PARAM_CHAR, "{").replaceAll(CLOSE_PARAM_CHAR, "}");
}
private String trim(String stringToBeTrimmed) {
return (stringToBeTrimmed == null) ? null : stringToBeTrimmed.trim();
}
}