io.cucumber.core.plugin.SerenityReporterParallel Maven / Gradle / Ivy
The newest version!
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.plugin.event.TestCase;
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.events.SetTestManualEvent;
import net.serenitybdd.cucumber.events.StepFinishedWithResultEvent;
import net.serenitybdd.cucumber.formatting.ScenarioOutlineDescription;
import net.serenitybdd.cucumber.util.PathUtils;
import net.serenitybdd.cucumber.util.StepDefinitionAnnotationReader;
import net.serenitybdd.model.exceptions.SerenityManagedException;
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.reports.ReportService;
import net.thucydides.model.requirements.FeatureFilePath;
import net.thucydides.model.requirements.model.cucumber.InvalidFeatureFileException;
import net.thucydides.model.screenshots.ScreenshotAndHtmlSource;
import net.thucydides.core.steps.*;
import net.thucydides.core.steps.events.*;
import net.thucydides.core.steps.session.TestSession;
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.SerenityWebdriverManager;
import net.thucydides.core.webdriver.ThucydidesWebDriverSupport;
import net.thucydides.core.webdriver.WebDriverFacade;
import org.apache.commons.lang3.StringUtils;
import org.openqa.selenium.WebDriver;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.net.URI;
import java.net.URLDecoder;
import java.nio.charset.StandardCharsets;
import java.time.ZonedDateTime;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
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 parallel reporter for Serenity.
*
* @author L.Carausu ([email protected])
*/
public class SerenityReporterParallel 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 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 static final Logger LOGGER = LoggerFactory.getLogger(SerenityReporter.class);
private final Set contextURISet = new CopyOnWriteArraySet<>();
/**
* key = feature URI; value = ScenarioContextParallel
*/
private final Map localContexts = Collections.synchronizedMap(new HashMap<>());
protected ScenarioContextParallel getContext(URI featureURI) {
synchronized (localContexts) {
return localContexts.computeIfAbsent(featureURI, uri -> new ScenarioContextParallel(featureURI));
}
}
/**
* Constructor automatically called by cucumber when class is specified as plugin
* in @CucumberOptions.
*/
public SerenityReporterParallel() {
this.systemConfiguration = SerenityInfrastructure.getConfiguration();
}
public SerenityReporterParallel(Configuration systemConfiguration) {
this.systemConfiguration = systemConfiguration;
}
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) {
StepEventBus stepEventBus = getStepEventBus(featurePath);
if (stepEventBus.isBaseStepListenerRegistered()) {
return;
}
SerenityListeners listeners = new SerenityListeners(stepEventBus, systemConfiguration);
getContext(featurePath).setStepEventBus(stepEventBus);
getContext(featurePath).addBaseStepListener(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) {
LOGGER.debug("SRP:handleTestRunStarted {} ", Thread.currentThread());
}
@Override
public void setEventPublisher(EventPublisher publisher) {
publisher.registerHandlerFor(TestSourceRead.class, testSourceReadHandler);
publisher.registerHandlerFor(TestRunStarted.class, runStartedHandler);
publisher.registerHandlerFor(TestRunFinished.class, runFinishedHandler);
publisher.registerHandlerFor(TestCaseStarted.class, caseStartedHandler);
publisher.registerHandlerFor(TestCaseFinished.class, caseFinishedHandler);
publisher.registerHandlerFor(TestStepStarted.class, stepStartedHandler);
publisher.registerHandlerFor(TestStepFinished.class, stepFinishedHandler);
publisher.registerHandlerFor(WriteEvent.class, writeEventHandler);
}
protected void handleTestSourceRead(TestSourceRead event) {
LOGGER.debug("SRP:handleTestSourceRead {}", Thread.currentThread());
featureLoader.addTestSourceReadEvent(event);
URI featurePath = event.getUri();
featureFrom(featurePath).ifPresent(
feature -> {
getContext(featurePath).setFeatureTags(feature.getTags());
resetEventBusFor(featurePath);
initialiseListenersFor(featurePath);
configureDriver(feature, featurePath);
Story userStory = userStoryFrom(feature, relativeUriFrom(event.getUri()));
getContext(featurePath).stepEventBus().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);
String id = relativePath.replace(".feature", "");
Story userStory = Story.withIdAndPath(id, feature.getName(), featureFileUri).asFeature();
if (!isEmpty(feature.getDescription())) {
userStory = userStory.withNarrative(feature.getDescription());
}
return userStory;
}
protected void handleTestCaseStarted(TestCaseStarted event) {
try {
TestCase testCase = event.getTestCase();
LOGGER.debug("SRP:handleTestCaseStarted {} {} {} at line {}", testCase.getUri(), Thread.currentThread(),
testCase.getId(), testCase.getLocation().getLine());
TestSession.startSession(testCase.getId().toString(), getStepEventBus(event.getTestCase().getUri()));
URI featurePath = testCase.getUri();
contextURISet.add(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);
}
ConfigureDriverFromTags.forTags(event.getTestCase().getTags());
String scenarioName = event.getTestCase().getName();
TestSourcesModel.AstNode astNode = featureLoader.getAstNode(featurePath, event.getTestCase().getLocation().getLine());
Optional currentFeature = featureFrom(featurePath);
String scenarioId = "";
ScenarioContextParallel context = getContext(featurePath);
if ((astNode != null) && currentFeature.isPresent()) {
Scenario currentScenarioDefinition = TestSourcesModel.getScenarioDefinition(astNode);
//initialiseListenersFor(featurePath,event.getTestCase(),getContext(featurePath).isAScenarioOutline());
//the sources are read in parallel, global current feature cannot be used
scenarioId = scenarioIdFrom(currentFeature.get().getName(), TestSourcesModel.convertToId(currentScenarioDefinition.getName()));
context.setCurrentScenarioDefinitionFrom(scenarioId, astNode);
boolean newScenario = !scenarioId.equals(context.getCurrentScenario(scenarioId));
if (newScenario) {
configureDriver(currentFeature.get(), event.getTestCase().getUri());
if (!currentScenarioDefinition.getExamples().isEmpty()) {
TestSession.getTestSessionContext().setInDataDrivenTest(true);
context.startNewExample(scenarioId);
LOGGER.debug("SRP:startNewExample {} {} {} at line {} ", event.getTestCase().getUri(), Thread.currentThread(),
event.getTestCase().getId(), event.getTestCase().getLocation().getLine());
handleExamples(scenarioId, featurePath, currentFeature.get(),
context.currentScenarioOutline(scenarioId).getTags(),
context.currentScenarioOutline(scenarioId).getName(),
context.currentScenarioOutline(scenarioId).getExamples());
}
startOfScenarioLifeCycle(scenarioId, featurePath, event.getTestCase(), currentFeature.get(), scenarioName, context.getCurrentScenarioDefinition(scenarioId), event.getTestCase().getLocation().getLine());
context.setCurrentScenario(scenarioId, scenarioId);
} else {
if (context.isAScenarioOutline(scenarioId)) {
startProcessingExampleLine(scenarioId, featurePath, event.getTestCase(), Long.valueOf(event.getTestCase().getLocation().getLine()), scenarioName);
}
}
final String scenarioIdForBackground = scenarioId;
TestSourcesModel.getBackgroundForTestCase(astNode).ifPresent(background -> handleBackground(featurePath, scenarioIdForBackground, background));
//
// Check for tags
//
if (astNode.node instanceof Scenario) {
List tags = ((Scenario) astNode.node).getTags();
TestResult annotatedTestResult = ScenarioTagProcessor.processScenarioTags(tags, event.getTestCase().getUri());
if (TaggedScenario.isManual(tags)) {
MANUAL_TEST_RESULTS_CACHE.put(testCase.getId(), annotatedTestResult);
}
}
}
io.cucumber.messages.types.Rule rule = getRuleForTestCase(astNode);
if (rule != null) {
context.addStepEventBusEvent(new SetRuleEvent(Rule.from(rule)));
}
} catch (Throwable t) {
LOGGER.error("Test case started failed with error ", t);
throw t;
}
}
private final static Map MANUAL_TEST_RESULTS_CACHE = new HashMap<>();
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) {
LOGGER.debug("SRP:handleTestCaseFinished " + " " + event.getTestCase().getUri()
+ " " + Thread.currentThread() + " " + event.getTestCase().getId() + " at line " + event.getTestCase().getLocation().getLine());
URI featurePath = event.getTestCase().getUri();
Optional currentFeature = featureFrom(featurePath);
TestSourcesModel.AstNode astNode = featureLoader.getAstNode(featurePath, event.getTestCase().getLocation().getLine());
Scenario currentScenarioDefinition = TestSourcesModel.getScenarioDefinition(astNode);
String scenarioId = scenarioIdFrom(currentFeature.get().getName(), TestSourcesModel.convertToId(currentScenarioDefinition.getName()));
if (getContext(featurePath).examplesAreRunning(scenarioId)) {
handleResult(scenarioId, featurePath, event.getTestCase(), event.getResult(), true);
finishProcessingExampleLine(scenarioId, featurePath, event.getTestCase());
}
Status eventStatus = eventStatusFor(event);
if (Status.FAILED.equals(eventStatus) && noAnnotatedResultIdDefinedFor(event)) {
getContext(featurePath).addStepEventBusEvent(
new TestFailedEvent(scenarioId, event.getResult().getError())
);
} else {
getContext(featurePath).addStepEventBusEvent(
new TestFinishedEvent(scenarioId, getContext(featurePath).examplesAreRunning(scenarioId))
);
}
getContext(featurePath).storeAllStepEventBusEventsForLine(event.getTestCase().getLocation().getLine(), event.getTestCase());
getContext(featurePath).clearStepQueue(event.getTestCase());
getContext(featurePath).stepEventBus().clear();
// We don't have the TestOutcome object ready yet, so we need to create a temporary one based on the event
// The feature name is the first part of getContext(featurePath).getCurrentScenario(scenarioId) up to the first semicolon
// The scenario name is the second part of getContext(featurePath).getCurrentScenario(scenarioId) after the first semicolon
String featureName = getContext(featurePath).getCurrentScenario(scenarioId).split(";")[0];
TestOutcome testOutcome = TestOutcome.forTestInStory(event.getTestCase().getName(),
Story.called(featureName));
testOutcome.setResult(serenityTestResultFrom(event.getResult().getStatus()));
if (event.getResult().getError() != null) {
testOutcome.testFailedWith(event.getResult().getError());
}
// We need to close the driver here to avoid wasting resources and causing timeouts with Selenium Grid services
getContext(featurePath)
.stepEventBus()
.getBaseStepListener()
.cleanupWebdriverInstance(getContext(featurePath).stepEventBus().isCurrentTestDataDriven(), testOutcome);
// Update external links cache
String key = featureName + "/" + testOutcome.getName();
if (testOutcome.getExternalLink() != null) {
EXTERNAL_LINK_CACHE.put(key, testOutcome.getExternalLink());
}
if (testOutcome.getSessionId() != null) {
SESSION_ID_CACHE.put(key, testOutcome.getSessionId());
}
}
private static final Map TEST_RESULT_MAP = Map.of(
Status.PASSED, TestResult.SUCCESS,
Status.FAILED, TestResult.FAILURE, Status.SKIPPED, TestResult.SKIPPED,
Status.PENDING, TestResult.PENDING,
Status.UNDEFINED, TestResult.UNDEFINED,
Status.AMBIGUOUS, TestResult.UNDEFINED);
private TestResult serenityTestResultFrom(Status status) {
// Use a map to convert the Status enum to a Serenity TestResult value
return TEST_RESULT_MAP.get(status);
}
private Status eventStatusFor(TestCaseFinished event) {
if (MANUAL_TEST_RESULTS_CACHE.containsKey(event.getTestCase().getId())) {
switch (MANUAL_TEST_RESULTS_CACHE.get(event.getTestCase().getId())) {
case SUCCESS:
return Status.PASSED;
case ABORTED:
case FAILURE:
case COMPROMISED:
case ERROR:
return Status.FAILED;
case PENDING:
return Status.PENDING;
case SKIPPED:
case IGNORED:
return Status.SKIPPED;
default:
return Status.UNDEFINED;
}
} else {
return event.getResult().getStatus();
}
}
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) {
ZonedDateTime startTime = ZonedDateTime.now();
URI featurePath = event.getTestCase().getUri();
TestSourcesModel.AstNode mainAstNode = featureLoader.getAstNode(featurePath, event.getTestCase().getLocation().getLine());
Scenario currentScenarioDefinition = TestSourcesModel.getScenarioDefinition(mainAstNode);
Optional currentFeature = featureFrom(featurePath);
if (currentFeature.isEmpty()) {
throw new InvalidFeatureFileException("Unable to run scenario '" + event.getTestCase().getName() + "': No feature name found in " + featurePath);
}
String scenarioId = scenarioIdFrom(currentFeature.get().getName(), TestSourcesModel.convertToId(currentScenarioDefinition.getName()));
LOGGER.debug("SRP:handleTestStepStarted " + " " + event.getTestCase().getUri() + " " + Thread.currentThread()
+ " " + event.getTestCase().getId() + " at line " + event.getTestCase().getLocation().getLine());
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(event.getTestCase().getUri(), 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(featurePath).isAddingScenarioOutlineSteps(scenarioId)) {
getContext(featurePath).queueStep(event.getTestCase(), step);
getContext(featurePath).queueTestStep(event.getTestCase(), event.getTestStep());
}
if (getContext(featurePath).isAScenarioOutline(scenarioId)) {
int lineNumber = event.getTestCase().getLocation().getLine();
getContext(featurePath).addStepEventBusEvent(new UpdateExampleLineNumberEvent(lineNumber));
}
io.cucumber.messages.types.Step currentStep = getContext(featurePath).getCurrentStep(event.getTestCase());
String stepTitle = stepTitleFrom(currentStep, pickleTestStep);
getContext(featurePath).addStepEventBusEvent(
new StepStartedEvent(ExecutedStepDescription.withTitle(stepTitle), startTime));
getContext(featurePath).addStepEventBusEvent(
new UpdateCurrentStepTitleEvent(normalized(stepTitle)));
}
}
}
}
public void handleWrite(WriteEvent event) {
LOGGER.debug("SRP:handleWrite " + " " + event.getTestCase().getUri());
URI featurePath = event.getTestCase().getUri();
getContext(featurePath).stepEventBus().stepStarted(ExecutedStepDescription.withTitle(event.getText()));
getContext(featurePath).stepEventBus().stepFinished();
}
protected void handleTestStepFinished(TestStepFinished event) {
LOGGER.debug("SRP:handleTestStepFinished " + " " + event.getTestCase().getUri() +
" " + Thread.currentThread() + " " + event.getTestCase().getId() +
" at line " + event.getTestCase().getLocation().getLine());
if (!(event.getTestStep() instanceof HookTestStep)) {
URI featurePath = event.getTestCase().getUri();
TestSourcesModel.AstNode astNode = featureLoader.getAstNode(featurePath, event.getTestCase().getLocation().getLine());
Optional currentFeature = featureFrom(featurePath);
String scenarioId = "";
if ((astNode != null) && currentFeature.isPresent()) {
Scenario currentScenarioDefinition = TestSourcesModel.getScenarioDefinition(astNode);
scenarioId = scenarioIdFrom(currentFeature.get().getName(), TestSourcesModel.convertToId(currentScenarioDefinition.getName()));
handleResult(scenarioId, event.getTestCase().getUri(), event.getTestCase(), event.getResult(), false);
}
StepDefinitionAnnotations.clear();
}
}
protected void handleTestRunFinished(TestRunFinished event) {
LOGGER.debug("SRP:handleTestRunFinished " + Thread.currentThread() + " " + contextURISet);
for (URI featurePath : contextURISet) {
getContext(featurePath).playAllTestEvents();
}
enrichOutcomes();
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(String mainScenarioId, URI featurePath, Feature currentFeature, List scenarioOutlineTags, String id, List examplesList) {
lineFilters = LineFilters.forCurrentContext();
String featureName = currentFeature.getName();
List currentFeatureTags = currentFeature.getTags();
getContext(featurePath).doneAddingScenarioOutlineSteps(mainScenarioId);
initializeExamples(mainScenarioId, featurePath);
for (Examples examples : examplesList) {
if (examplesAreNotExcludedByTags(examples, scenarioOutlineTags, currentFeatureTags)
&& lineFilters.examplesAreNotExcluded(examples, featurePath)) {
List examplesTableRows = examples
.getTableBody()
.stream()
.filter(tableRow -> lineFilters.tableRowIsNotExcludedBy(tableRow, featurePath))
.collect(Collectors.toList());
List headers = getHeadersFrom(examples.getTableHeader().get());
List
© 2015 - 2025 Weber Informatics LLC | Privacy Policy