Best Serenity Cucumber code snippet using net.serenitybdd.cucumber.Annotation Type SerenityOptions
Source:CucumberSerenityRunner.java  
1package io.cucumber.junit;2import io.cucumber.core.eventbus.EventBus;3import io.cucumber.core.feature.FeatureParser;4import io.cucumber.core.filter.Filters;5import io.cucumber.core.gherkin.Feature;6import io.cucumber.core.gherkin.Pickle;7import io.cucumber.core.options.*;8import io.cucumber.core.plugin.PluginFactory;9import io.cucumber.core.plugin.Plugins;10import io.cucumber.core.plugin.SerenityReporter;11import io.cucumber.core.resource.ClassLoaders;12import io.cucumber.core.runtime.Runtime;13import io.cucumber.core.runtime.*;14import io.cucumber.plugin.Plugin;15import io.cucumber.tagexpressions.Expression;16import net.serenitybdd.cucumber.SerenityOptions;17import net.serenitybdd.cucumber.suiteslicing.CucumberSuiteSlicer;18import net.serenitybdd.cucumber.suiteslicing.ScenarioFilter;19import net.serenitybdd.cucumber.suiteslicing.TestStatistics;20import net.serenitybdd.cucumber.suiteslicing.WeightedCucumberScenarios;21import net.serenitybdd.cucumber.util.PathUtils;22import net.serenitybdd.cucumber.util.Splitter;23import net.thucydides.core.ThucydidesSystemProperty;24import net.thucydides.core.guice.Injectors;25import net.thucydides.core.steps.StepEventBus;26import net.thucydides.core.util.EnvironmentVariables;27import net.thucydides.core.webdriver.Configuration;28import org.junit.runner.Description;29import org.junit.runner.manipulation.NoTestsRemainException;30import org.junit.runner.notification.RunNotifier;31import org.junit.runners.ParentRunner;32import org.junit.runners.model.InitializationError;33import org.junit.runners.model.RunnerScheduler;34import org.junit.runners.model.Statement;35import org.slf4j.Logger;36import org.slf4j.LoggerFactory;37import java.net.URI;38import java.time.Clock;39import java.util.*;40import java.util.concurrent.atomic.AtomicInteger;41import java.util.function.Function;42import java.util.function.Predicate;43import java.util.function.Supplier;44import static io.cucumber.junit.FileNameCompatibleNames.uniqueSuffix;45import static java.util.Arrays.stream;46import static java.util.stream.Collectors.groupingBy;47import static java.util.stream.Collectors.toList;48import static net.thucydides.core.ThucydidesSystemProperty.*;49/**50 * Glue code for running Cucumber via Serenity.51 * Sets up Serenity reporting and instrumentation.52 */53public class CucumberSerenityRunner extends ParentRunner<ParentRunner<?>> {54    private static final Logger LOGGER = LoggerFactory.getLogger(CucumberSerenityRunner.class);55    private List<ParentRunner<?>> children = new ArrayList<ParentRunner<?>>();56    private final EventBus bus;57    private static ThreadLocal<RuntimeOptions> RUNTIME_OPTIONS = new ThreadLocal<>();58    private final List<Feature> features;59    private final Plugins plugins;60    private final CucumberExecutionContext context;61    private boolean multiThreadingAssumed = false;62    /**63     * Constructor called by JUnit.64     *65     * @param clazz the class with the @RunWith annotation.66     * @throws InitializationError if there is another problem67     */68    public CucumberSerenityRunner(Class clazz) throws InitializationError {69        super(clazz);70        Assertions.assertNoCucumberAnnotatedMethods(clazz);71        // Parse the options early to provide fast feedback about invalid options72        RuntimeOptions propertiesFileOptions = new CucumberPropertiesParser()73                .parse(CucumberProperties.fromPropertiesFile())74                .build();75        RuntimeOptions annotationOptions = new CucumberOptionsAnnotationParser()76                .withOptionsProvider(new JUnitCucumberOptionsProvider())77                .parse(clazz)78                .build(propertiesFileOptions);79        RuntimeOptions environmentOptions = new CucumberPropertiesParser()80                .parse(CucumberProperties.fromEnvironment())81                .build(annotationOptions);82        RuntimeOptions runtimeOptions = new CucumberPropertiesParser()83                .parse(CucumberProperties.fromSystemProperties())84                .addDefaultSummaryPrinterIfAbsent()85                .build(environmentOptions);86        RuntimeOptionsBuilder runtimeOptionsBuilder = new RuntimeOptionsBuilder();87        Collection<String> tagFilters = environmentSpecifiedTags(runtimeOptions.getTagExpressions());88        for (String tagFilter : tagFilters) {89            runtimeOptionsBuilder.addTagFilter(new LiteralExpression(tagFilter));90        }91        runtimeOptionsBuilder.build(runtimeOptions);92        // Next parse the junit options93        JUnitOptions junitPropertiesFileOptions = new JUnitOptionsParser()94                .parse(CucumberProperties.fromPropertiesFile())95                .build();96        JUnitOptions junitAnnotationOptions = new JUnitOptionsParser()97                .parse(clazz)98                .build(junitPropertiesFileOptions);99        JUnitOptions junitEnvironmentOptions = new JUnitOptionsParser()100                .parse(CucumberProperties.fromEnvironment())101                .build(junitAnnotationOptions);102        JUnitOptions junitOptions = new JUnitOptionsParser()103                .parse(fromSystemPropertiesAndOptionsAnnotationIn(clazz))104                //.setStrict(runtimeOptions.isStrict())105                .build(junitEnvironmentOptions);106        this.bus = new TimeServiceEventBus(Clock.systemUTC(), UUID::randomUUID);107        setRuntimeOptions(runtimeOptions);108        // Parse the features early. Don't proceed when there are lexer errors109        FeatureParser parser = new FeatureParser(bus::generateId);110        Supplier<ClassLoader> classLoader = ClassLoaders::getDefaultClassLoader;111        FeaturePathFeatureSupplier featureSupplier = new FeaturePathFeatureSupplier(classLoader, runtimeOptions, parser);112        this.features = featureSupplier.get();113        // Create plugins after feature parsing to avoid the creation of empty files on lexer errors.114        this.plugins = new Plugins(new PluginFactory(), runtimeOptions);115        ExitStatus exitStatus = new ExitStatus(runtimeOptions);116        this.plugins.addPlugin(exitStatus);117        Configuration systemConfiguration = Injectors.getInjector().getInstance(Configuration.class);118        SerenityReporter reporter = new SerenityReporter(systemConfiguration);119        addSerenityReporterPlugin(plugins, reporter);120        ObjectFactoryServiceLoader objectFactoryServiceLoader = new ObjectFactoryServiceLoader(runtimeOptions);121        ObjectFactorySupplier objectFactorySupplier = new ThreadLocalObjectFactorySupplier(objectFactoryServiceLoader);122        BackendSupplier backendSupplier = new BackendServiceLoader(clazz::getClassLoader, objectFactorySupplier);123        TypeRegistryConfigurerSupplier typeRegistryConfigurerSupplier = new ScanningTypeRegistryConfigurerSupplier(classLoader, runtimeOptions);124        ThreadLocalRunnerSupplier runnerSupplier = new ThreadLocalRunnerSupplier(runtimeOptions, bus, backendSupplier, objectFactorySupplier, typeRegistryConfigurerSupplier);125        this.context = new CucumberExecutionContext(bus, exitStatus, runnerSupplier);126        Predicate<Pickle> filters = new Filters(runtimeOptions);127        Map<Optional<String>, List<Feature>> groupedByName = features.stream()128                .collect(groupingBy(Feature::getName));129        children = features.stream()130                .map(feature -> {131                    Integer uniqueSuffix = uniqueSuffix(groupedByName, feature, Feature::getName);132                    return FeatureRunner.create(feature, uniqueSuffix, filters, runnerSupplier, junitOptions);133                })134                .filter(runner -> !runner.isEmpty())135                .collect(toList());136    }137    private Map<String,String> fromSystemPropertiesAndOptionsAnnotationIn(Class clazz) {138        if (clazz.getAnnotation(SerenityOptions.class) == null) {139            return CucumberProperties.fromSystemProperties();140        } else {141            Map<String, String> systemProperties = new HashMap<>(CucumberProperties.fromSystemProperties());142            SerenityOptions options = (SerenityOptions) clazz.getAnnotation(SerenityOptions.class);143            stream(options.value().split(",")).forEach(144                    option -> {145                        String[] optionParts = option.split("=");146                        String key = optionParts[0].trim();147                        String value = (optionParts.length == 1) ? "true" : optionParts[1].trim();148                        systemProperties.put(key,value);149                    }150            );151            return systemProperties;152        }153    }154    private static RuntimeOptions DEFAULT_RUNTIME_OPTIONS;155    public static void setRuntimeOptions(RuntimeOptions runtimeOptions) {156        RUNTIME_OPTIONS.set(runtimeOptions);157        DEFAULT_RUNTIME_OPTIONS = runtimeOptions;158    }159    public static RuntimeOptions currentRuntimeOptions() {160        return (RUNTIME_OPTIONS.get() != null) ? RUNTIME_OPTIONS.get() : DEFAULT_RUNTIME_OPTIONS;161    }162    private static Collection<String> environmentSpecifiedTags(List<?> existingTags) {163        EnvironmentVariables environmentVariables = Injectors.getInjector().getInstance(EnvironmentVariables.class);164        String tagsExpression = ThucydidesSystemProperty.TAGS.from(environmentVariables, "");165        List<String> existingTagsValues = existingTags.stream().map(Object::toString).collect(toList());166        return Splitter.on(",").trimResults().omitEmptyStrings().splitToList(tagsExpression).stream()167                .map(CucumberSerenityRunner::toCucumberTag).filter(t -> !existingTagsValues.contains(t)).collect(toList());168    }169    private static String toCucumberTag(String from) {170        String tag = from.replaceAll(":", "=");171        if (tag.startsWith("~@") || tag.startsWith("@")) {172            return tag;173        }174        if (tag.startsWith("~")) {175            return "~@" + tag.substring(1);176        }177        return "@" + tag;178    }179    public static Runtime createSerenityEnabledRuntime(/*ResourceLoader resourceLoader,*/180            Supplier<ClassLoader> classLoaderSupplier,181            RuntimeOptions runtimeOptions,182            Configuration systemConfiguration) {183        RuntimeOptionsBuilder runtimeOptionsBuilder = new RuntimeOptionsBuilder();184        Collection<String> allTagFilters = environmentSpecifiedTags(runtimeOptions.getTagExpressions());185        for (String tagFilter : allTagFilters) {186            runtimeOptionsBuilder.addTagFilter(new LiteralExpression(tagFilter));187        }188        runtimeOptionsBuilder.build(runtimeOptions);189        setRuntimeOptions(runtimeOptions);190        EventBus bus = new TimeServiceEventBus(Clock.systemUTC(), UUID::randomUUID);191        FeatureParser parser = new FeatureParser(bus::generateId);192        FeaturePathFeatureSupplier featureSupplier = new FeaturePathFeatureSupplier(classLoaderSupplier, runtimeOptions, parser);193        SerenityReporter serenityReporter = new SerenityReporter(systemConfiguration);194        Runtime runtime = Runtime.builder().withClassLoader(classLoaderSupplier).withRuntimeOptions(runtimeOptions).195                withAdditionalPlugins(serenityReporter).196                withEventBus(bus).withFeatureSupplier(featureSupplier).197                build();198        return runtime;199    }200    private static void addSerenityReporterPlugin(Plugins plugins, SerenityReporter plugin) {201        for (Plugin currentPlugin : plugins.getPlugins()) {202            if (currentPlugin instanceof SerenityReporter) {203                return;204            }205        }206        plugins.addPlugin(plugin);207    }208    @Override209    protected Description describeChild(ParentRunner<?> child) {210        return child.getDescription();211    }212    @Override213    protected void runChild(ParentRunner<?> child, RunNotifier notifier) {214        child.run(notifier);215    }216    @Override217    protected Statement childrenInvoker(RunNotifier notifier) {218        Statement runFeatures = super.childrenInvoker(notifier);219        return new RunCucumber(runFeatures);220    }221    class RunCucumber extends Statement {222        private final Statement runFeatures;223        RunCucumber(Statement runFeatures) {224            this.runFeatures = runFeatures;225        }226        @Override227        public void evaluate() throws Throwable {228            if (multiThreadingAssumed) {229                plugins.setSerialEventBusOnEventListenerPlugins(bus);230            } else {231                plugins.setEventBusOnEventListenerPlugins(bus);232            }233            context.startTestRun();234            features.forEach(context::beforeFeature);235            try {236                runFeatures.evaluate();237            } finally {238                context.finishTestRun();239                StepEventBus.getEventBus().testRunFinished();240            }241        }242    }243    @Override244    public void setScheduler(RunnerScheduler scheduler) {245        super.setScheduler(scheduler);246        multiThreadingAssumed = true;247    }248    @Override249    public List<ParentRunner<?>> getChildren() {250        try {251            EnvironmentVariables environmentVariables = Injectors.getInjector().getInstance(EnvironmentVariables.class);252            RuntimeOptions runtimeOptions = currentRuntimeOptions();253            List<Expression> tagFilters = runtimeOptions.getTagExpressions();254            List<URI> featurePaths = runtimeOptions.getFeaturePaths();255            int batchNumber = environmentVariables.getPropertyAsInteger(SERENITY_BATCH_NUMBER, 1);256            int batchCount = environmentVariables.getPropertyAsInteger(SERENITY_BATCH_COUNT, 1);257            int forkNumber = environmentVariables.getPropertyAsInteger(SERENITY_FORK_NUMBER, 1);258            int forkCount = environmentVariables.getPropertyAsInteger(SERENITY_FORK_COUNT, 1);259            if ((batchCount == 1) && (forkCount == 1)) {260                return children;261            } else {262                LOGGER.info("Running slice {} of {} using fork {} of {} from feature paths {}", batchNumber, batchCount, forkNumber, forkCount, featurePaths);263                List<String> tagFiltersAsString = tagFilters.stream().map(Expression::toString).collect(toList());264                WeightedCucumberScenarios weightedCucumberScenarios = new CucumberSuiteSlicer(featurePaths, TestStatistics.from(environmentVariables, featurePaths))265                        .scenarios(batchNumber, batchCount, forkNumber, forkCount, tagFiltersAsString);266                List<ParentRunner<?>> unfilteredChildren = children;267                AtomicInteger filteredInScenarioCount = new AtomicInteger();268                List<ParentRunner<?>> filteredChildren = unfilteredChildren.stream()269                        .filter(forIncludedFeatures(weightedCucumberScenarios))270                        .map(toPossibleFeatureRunner(weightedCucumberScenarios, filteredInScenarioCount))271                        .filter(Optional::isPresent)272                        .map(Optional::get)273                        .collect(toList());274                if (filteredInScenarioCount.get() != weightedCucumberScenarios.totalScenarioCount()) {275                    LOGGER.warn(276                            "There is a mismatch between the number of scenarios included in this test run ({}) and the expected number of scenarios loaded ({}). This suggests that the scenario filtering is not working correctly or feature file(s) of an unexpected structure are being run",277                            filteredInScenarioCount.get(),278                            weightedCucumberScenarios.scenarios.size());279                }280                LOGGER.info("Running {} of {} features", filteredChildren.size(), unfilteredChildren.size());281                return filteredChildren;282            }283        } catch (Exception e) {284            LOGGER.error("Test failed to start", e);285            throw e;286        }287    }288    private Function<ParentRunner<?>, Optional<ParentRunner<?>>> toPossibleFeatureRunner(WeightedCucumberScenarios weightedCucumberScenarios, AtomicInteger filteredInScenarioCount) {289        return featureRunner -> {290            int initialScenarioCount = featureRunner.getDescription().getChildren().size();291            String featureName = FeatureRunnerExtractors.extractFeatureName(featureRunner);292            try {293                ScenarioFilter filter = weightedCucumberScenarios.createFilterContainingScenariosIn(featureName);294                String featurePath = FeatureRunnerExtractors.featurePathFor(featureRunner);295                featureRunner.filter(filter);296                if (!filter.scenariosIncluded().isEmpty()) {297                    LOGGER.info("{} scenario(s) included for '{}' in {}", filter.scenariosIncluded().size(), featureName, featurePath);298                    filter.scenariosIncluded().forEach(scenario -> {299                        LOGGER.info("Included scenario '{}'", scenario);300                        filteredInScenarioCount.getAndIncrement();301                    });302                }303                if (!filter.scenariosExcluded().isEmpty()) {304                    LOGGER.debug("{} scenario(s) excluded for '{}' in {}", filter.scenariosExcluded().size(), featureName, featurePath);305                    filter.scenariosExcluded().forEach(scenario -> LOGGER.debug("Excluded scenario '{}'", scenario));306                }307                return Optional.of(featureRunner);308            } catch (NoTestsRemainException e) {309                LOGGER.info("Filtered out all {} scenarios for feature '{}'", initialScenarioCount, featureName);310                return Optional.empty();311            }312        };313    }314    private Predicate<ParentRunner<?>> forIncludedFeatures(WeightedCucumberScenarios weightedCucumberScenarios) {315        return featureRunner -> {316            String featureName = FeatureRunnerExtractors.extractFeatureName(featureRunner);317            String featurePath = PathUtils.getAsFile(FeatureRunnerExtractors.featurePathFor(featureRunner)).getName();318            boolean matches = weightedCucumberScenarios.scenarios.stream().anyMatch(scenario -> featurePath.equals(scenario.featurePath));319            LOGGER.debug("{} in filtering '{}' in {}", matches ? "Including" : "Not including", featureName, featurePath);320            return matches;321        };322    }323}...Source:SerenityOptions.java  
1package net.serenitybdd.cucumber;2import java.lang.annotation.ElementType;3import java.lang.annotation.Retention;4import java.lang.annotation.RetentionPolicy;5import java.lang.annotation.Target;6/**7 * Set environment configuration options for this test runner.8 * For example:9 * @SerenityOptions("webdriver.driver=chrome")10 */11@Retention(RetentionPolicy.RUNTIME)12@Target(ElementType.TYPE)13public @interface SerenityOptions {14    String value();15}...Annotation Type SerenityOptions
Using AI Code Generation
1package com.automationpractice.test;2import cucumber.api.CucumberOptions;3import net.serenitybdd.cucumber.CucumberWithSerenity;4import org.junit.runner.RunWith;5@RunWith(CucumberWithSerenity.class)6@CucumberOptions(7public class CucumberTestSuite {8}9package com.automationpractice.test;10import cucumber.api.java.en.Given;11import cucumber.api.java.en.Then;12import cucumber.api.java.en.When;13public class MyFirstFeatureSteps {14    @Given("^I have a scenario$")15    public void iHaveAScenario() {16    }17    @When("^I run it$")18    public void iRunIt() {19    }20    @Then("^it should work$")21    public void itShouldWork() {22    }23}Annotation Type SerenityOptions
Using AI Code Generation
1package com.automationpractice.tests;2import cucumber.api.CucumberOptions;3import cucumber.api.junit.Cucumber;4import net.serenitybdd.cucumber.CucumberWithSerenity;5import org.junit.runner.RunWith;6@RunWith(CucumberWithSerenity.class)7@CucumberOptions(8        plugin = {"pretty",9                "junit:target/cucumber.xml"},10        tags = {"@smoke"},11public class Runner {12}13package com.automationpractice.stepdefinitions;14import com.automationpractice.pageobjects.LoginPage;15import com.automationpractice.utils.ConfigReader;16import com.automationAnnotation Type SerenityOptions
Using AI Code Generation
1@SerenityOptions( format = { "pretty", "html:target/cucumber-html-report" } )2package stepdefinitions;3import cucumber.api.java.en.Given;4import cucumber.api.java.en.Then;5import cucumber.api.java.en.When;6public class SearchStepDefinitions {7	@Given("^I am on the google search page$")8	public void i_am_on_the_google_search_page() throws Throwable {9	    throw new PendingException();10	}11	@When("^I search for \"([^\"]*)\"$")12	public void i_search_for(String arg1) throws Throwable {13	    throw new PendingException();14	}15	@Then("^the page title should start with \"([^\"]*)\"$")16	public void the_page_title_should_start_with(String arg1) throws Throwable {17	    throw new PendingException();18	}19}20package stepdefinitions;21import cucumber.api.java.en.Given;22import cucumber.api.java.en.Then;23import cucumber.api.java.en.When;24public class SearchStepDefinitions {25	@Given("^I am on the google search page$")26	public void i_am_on_the_google_search_page() throws Throwable {27	    throw new PendingException();28	}29	@When("^I search for \"([^\"]*)\"$")30	public void i_search_for(String arg1) throws Throwable {31	    throw new PendingException();32	}33	@Then("^the page title should start with \"([^\"]*)\"$")34	public void the_page_title_should_start_with(String arg1) throws Throwable {35	    throw new PendingException();Learn to execute automation testing from scratch with LambdaTest Learning Hub. Right from setting up the prerequisites to run your first automation test, to following best practices and diving deeper into advanced test scenarios. LambdaTest Learning Hubs compile a list of step-by-step guides to help you be proficient with different test automation frameworks i.e. Selenium, Cypress, TestNG etc.
You could also refer to video tutorials over LambdaTest YouTube channel to get step by step demonstration from industry experts.
Get 100 minutes of automation test minutes FREE!!
