├── CHANGELOG.md ├── README.md ├── src ├── test │ ├── resources │ │ ├── samples │ │ │ ├── empty │ │ │ │ └── empty.feature │ │ │ ├── feature_with_no_name.feature │ │ │ ├── pending_scenario.feature │ │ │ ├── simple_scenario.feature │ │ │ ├── web │ │ │ │ ├── dataDrivenBehavior.feature │ │ │ │ ├── aBehaviorWithSeleniumPageObjects.feature │ │ │ │ ├── aPassingWebTestSampleWithNestedSteps.feature │ │ │ │ ├── aPassingBehaviorWithSeleniumAndSeveralScenarios.feature │ │ │ │ ├── aPassingBehaviorWithSelenium.feature │ │ │ │ ├── aFailingBehaviorWithSelenium.feature │ │ │ │ ├── aBehaviorWithSeleniumUsingADifferentBrowser.feature │ │ │ │ ├── aPassingBehaviorWithSeleniumAndFirefox.feature │ │ │ │ ├── failingAndPassingBehaviorsWithSelenium.feature │ │ │ │ └── lookupAScenarioSuite.feature │ │ │ ├── numbers.feature │ │ │ ├── simple_scenario_with_a_long_name.feature │ │ │ ├── scenario_with_a_broken_step_definition_class.feature │ │ │ ├── scenario_with_invalid_step_definition_class.feature │ │ │ ├── pending_table_based_numbers.feature │ │ │ ├── simple_scenario_with_narrative_text.feature │ │ │ ├── simple_scenario_with_tags.feature │ │ │ ├── manual_table_based_numbers.feature │ │ │ ├── table_based_numbers.feature │ │ │ ├── failing_scenario_outline.feature │ │ │ ├── simple_tagged_pending_feature.feature │ │ │ ├── simple_tagged_pending_scenario.feature │ │ │ ├── multiple_scenarios_pending_tag.feature │ │ │ ├── multiple_scenarios_skipped_tag.feature │ │ │ ├── multiple_scenarios.feature │ │ │ ├── screenplay_table_based_scenario_with_errors.feature │ │ │ ├── screenplay_table_based_scenario_with_failures.feature │ │ │ ├── screenplay_table_based_scenario_with_failures_and_errors.feature │ │ │ ├── data_driven_scenario.feature │ │ │ ├── tagged_example_tables.feature │ │ │ ├── failing_scenario.feature │ │ │ ├── calculator │ │ │ │ ├── basic_arithmetic.feature │ │ │ │ ├── basic_arithmetic_with_tables.feature │ │ │ │ └── basic_arithmetic_with_tables_and_background.feature │ │ │ ├── multiple_jira_issues.feature │ │ │ ├── table_based_scenario_with_failures.feature │ │ │ ├── feature_pending_tag.feature │ │ │ ├── scenarios_skipped_tag.feature │ │ │ ├── scenarios_pending_tag.feature │ │ │ ├── simple_table_based_scenario.feature │ │ │ └── scenario_with_table_in_background_steps.feature │ │ ├── .directory │ │ ├── data │ │ │ └── names-data.csv │ │ ├── README.txt │ │ ├── smoketests │ │ │ ├── using_background_steps.feature │ │ │ ├── undefined_scenarios.feature │ │ │ ├── using_fixture_methods.feature │ │ │ ├── skipping_scenarios.feature │ │ │ └── step_libraries.feature │ │ ├── features │ │ │ └── calculator │ │ │ │ ├── basic_arithmetic.feature │ │ │ │ ├── complex_arithmetic.feature │ │ │ │ ├── basic_arithmetic_with_tables_and_errors.feature │ │ │ │ ├── basic_arithmetic_with_tables.feature │ │ │ │ ├── basic_arithmetic_with_tables_and_background.feature │ │ │ │ ├── basic_arithmetic_with_tables_and_examples_tags.feature │ │ │ │ └── basic_arithmetic_with_tables_and_examples_no_tags.feature │ │ ├── net │ │ │ └── serenitybdd │ │ │ │ └── cucumber │ │ │ │ └── integration │ │ │ │ └── instantiating_thucyides_annotated_fields.feature │ │ └── statistics │ │ │ └── smoke-test-results-run-1.csv │ ├── groovy │ │ └── net │ │ │ └── serenitybdd │ │ │ └── cucumber │ │ │ ├── .directory │ │ │ ├── reports │ │ │ ├── WhenGeneratingThucydidesReports.groovy │ │ │ └── WhenGeneratingReportsForLineFilteredScenarioOutline.groovy │ │ │ ├── screenplay │ │ │ ├── WhenScreenplayActorsGoOnStage.groovy │ │ │ └── WhenManagingScreenplayActorsInCucumber.groovy │ │ │ ├── outcomes │ │ │ ├── WhenUsingAnIllegalStepLibrary.groovy │ │ │ └── WhenWorkingWithTaggedExampleTables.groovy │ │ │ └── bootstrap │ │ │ └── WhenInstantiatingStepLibraries.groovy │ └── java │ │ ├── net │ │ └── serenitybdd │ │ │ └── cucumber │ │ │ ├── integration │ │ │ ├── steps │ │ │ │ ├── thucydides │ │ │ │ │ ├── GizmoBuyerSteps.java │ │ │ │ │ ├── SamplePageObject.java │ │ │ │ │ ├── SampleSteps.java │ │ │ │ │ ├── WidgetSteps.java │ │ │ │ │ ├── SomeNormalSteps.java │ │ │ │ │ ├── SomeNestedSeleniumSteps.java │ │ │ │ │ ├── SampleWebSteps.java │ │ │ │ │ ├── CheckValuesStep.java │ │ │ │ │ └── SomeNonWebDataDrivenSteps.java │ │ │ │ ├── CoreSteps.java │ │ │ │ ├── BrokenStepInstantiationSteps.java │ │ │ │ ├── SimpleExampleSteps.java │ │ │ │ ├── WebEnabledStepInstantiationSteps.java │ │ │ │ ├── IllegalStepInstantiationSteps.java │ │ │ │ ├── StepInstantiationSteps.java │ │ │ │ ├── SimpleCalculatorSteps.java │ │ │ │ └── RpnCalculatorStepdefs.java │ │ │ ├── WhenIntegratingThucydidesWithCucumber.java │ │ │ ├── FeatureWithMoreIssuesTag.java │ │ │ ├── GizmoBuyer.java │ │ │ ├── ScenarioThrowingPendingException.java │ │ │ ├── SimpleSeleniumScenario.java │ │ │ ├── SimpleTaggedPendingFeature.java │ │ │ ├── SimpleTaggedPendingScenario.java │ │ │ ├── SimpleSeleniumFailingScenario.java │ │ │ ├── SimpleSeleniumPageObjects.java │ │ │ ├── TableScenarioMarkedAsManual.java │ │ │ ├── TableScenarioMarkedAsPending.java │ │ │ ├── ScenariosWithPendingTag.java │ │ │ ├── TableScenarioThrowingPendingException.java │ │ │ ├── BasicArithmeticScenario.java │ │ │ ├── FailingScenario.java │ │ │ ├── PendingScenario.java │ │ │ ├── SimpleTableScenarioWithLineFilters.java │ │ │ ├── MultipleScenarios.java │ │ │ ├── ScenarioSuite.java │ │ │ ├── SimpleScenario.java │ │ │ ├── DataDrivenScenario.java │ │ │ ├── FeatureWithNoName.java │ │ │ ├── SimpleSeleniumSeveralScenarios.java │ │ │ ├── PassingWebTestSampleWithNestedSteps.java │ │ │ ├── SimpleSeleniumFailingAndPassingScenario.java │ │ │ ├── FailingScenarioOutline.java │ │ │ ├── SampleDataDrivenScenario.java │ │ │ ├── ScenariosWithSkippedTag.java │ │ │ ├── SimpleSeleniumDifferentBrowserScenario.java │ │ │ ├── SimpleTableScenario.java │ │ │ ├── MultipleScenariosWithWIPTag.java │ │ │ ├── SimpleScenarioWithTags.java │ │ │ ├── RunExamplesWithoutTags.java │ │ │ ├── ScenariosWithTableInBackgroundSteps.java │ │ │ ├── FeatureWithPendingTag.java │ │ │ ├── SimpleScenarioWithALongName.java │ │ │ ├── MultipleScenariosWithIgnoreTag.java │ │ │ ├── MultipleScenariosWithPendingTag.java │ │ │ ├── MultipleScenariosWithSkippedTag.java │ │ │ ├── BrokenStepLibraryScenario.java │ │ │ ├── IllegalStepLibraryScenario.java │ │ │ ├── TaggedExampleTablesScenarios.java │ │ │ ├── SimpleScenarioWithNarrativeTexts.java │ │ │ ├── SimpleTableScenarioWithFailures.java │ │ │ ├── BasicArithmeticWithTablesScenario.java │ │ │ ├── WhenRunningAnEmptyFeatureFile.java │ │ │ ├── WhenRunningPassingCucumberSampleTests.java │ │ │ ├── SimpleSeleniumTestWithASpecifiedBrowser.java │ │ │ ├── ScenarioWithOnlyFeatureFileRootDirectoryPath.java │ │ │ ├── BasicArithmeticWithTablesScenarioWithErrors.java │ │ │ ├── RunOnlyFirstExampleTableRows.java │ │ │ ├── SimpleScreenplayTableScenarioWithFailures.java │ │ │ ├── RunOnlySecondExampleTableRows.java │ │ │ ├── SimpleScreenplayTableScenarioWithErrors.java │ │ │ ├── BasicArithmeticWithTablesAndBackgroundScenario.java │ │ │ ├── SimpleScreenplayTableScenarioWithFailuresAndErrors.java │ │ │ ├── RunAllExamplesThatInheritsFeatureTag.java │ │ │ ├── RunAllExamplesThatInheritsScenarioOutlineTagOnly.java │ │ │ ├── RunExamplesMatchingFeatureAndExampleTags.java │ │ │ ├── RunExamplesMatchingFeatureOrExampleTags.java │ │ │ ├── RunExamplesMatchingFeatureTagButNotAnExampleTag.java │ │ │ ├── RunExamplesMatchingFeatureLevelAndOutlineLevelTags.java │ │ │ ├── RunExamplesMatchingFeatureLevelOrOutlineLevelTags.java │ │ │ ├── RunExampleMatchingBothScenarioOutlineAndSecondExampleTagOnly.java │ │ │ ├── RunExamplesMatchingExampleOrScenarioOutlineTagAndAnExampleTag.java │ │ │ ├── RunExamplesMatchingExampleOrScenarioOutlineTagButNotAnExampleTag.java │ │ │ └── TypeRegistryConfiguration.java │ │ │ ├── smoketests │ │ │ ├── WhenUsingBackgroundSteps.java │ │ │ ├── WhenUsingStepLibraries.java │ │ │ ├── WhenSkippingScenarios.java │ │ │ ├── WhenUsingFixtureMethods.java │ │ │ └── WhenUsingUndefinedScenarios.java │ │ │ ├── suiteslicing │ │ │ ├── DummyStatsOfWeightingOne.java │ │ │ ├── SlicedTestRunner.java │ │ │ ├── MultiRunTestStatisticsTest.java │ │ │ ├── SingleRunTestStatisticsTest.java │ │ │ ├── WeightedCucumberScenariosTest.java │ │ │ ├── MatchingCucumberScenario.java │ │ │ ├── ScenarioLineCountStatisticsTest.java │ │ │ └── CucumberSuiteSlicerTest.java │ │ │ └── util │ │ │ ├── SampleStepDefinitions.java │ │ │ ├── TagParserFromEnvironmentVariablesTest.java │ │ │ └── StepDefinitionAnnotationReaderTest.java │ │ ├── samples │ │ └── calculator │ │ │ ├── DateCalculator.java │ │ │ └── RpnCalculator.java │ │ └── io │ │ └── cucumber │ │ └── junit │ │ └── FeatureRunnerExtractorsTest.java ├── smoketests │ ├── src │ │ └── test │ │ │ ├── resources │ │ │ ├── assets │ │ │ │ └── an_image.txt │ │ │ └── features │ │ │ │ ├── backgrounds │ │ │ │ ├── narrative.md │ │ │ │ ├── when_using_simple_lifecycle_steps.feature │ │ │ │ └── when_using_lifecycles_with_web_tests.feature │ │ │ │ ├── understanding_serenity_steps │ │ │ │ ├── narrative.txt │ │ │ │ └── when_using_step_libraries.feature │ │ │ │ ├── .directory │ │ │ │ ├── skipped_pending_and_manual_scenarios │ │ │ │ ├── overview.md │ │ │ │ ├── when_declaring_manual_scenarios.feature │ │ │ │ └── when_skipping_scenarios.feature │ │ │ │ ├── overview.md │ │ │ │ ├── tags_and_report │ │ │ │ └── serenity_report_when_using_tags_at_all_level.feature │ │ │ │ └── when_using_tables │ │ │ │ └── when_using_tables.feature │ │ │ └── java │ │ │ └── smoketests │ │ │ ├── WhenUsingStepLibraries.java │ │ │ ├── stepdefinitions │ │ │ ├── Hooks.java │ │ │ └── LifecycleStepDefinitions.java │ │ │ ├── WhenUsingBackgrounds.java │ │ │ ├── WhenUsingTables.java │ │ │ ├── RunASingleScenario.java │ │ │ ├── WhenUsingSkipPendingAndManualAnnotations.java │ │ │ ├── WhenRootFolderOfFeaturesAloneProvided.java │ │ │ ├── WhenUsingScenarioOutlineAndTagsAtAllLevels.java │ │ │ ├── SlicedTestRunner2.java │ │ │ ├── SlicedTestRunner3.java │ │ │ ├── SlicedTestRunner4.java │ │ │ └── SlicedTestRunner.java │ ├── gradle.properties │ ├── serenity.properties │ ├── README.md │ └── build.gradle └── main │ ├── resources │ └── META-INF │ │ └── services │ │ ├── io.cucumber.core.backend.Backend │ │ ├── io.cucumber.core.backend.ObjectFactory │ │ └── net.thucydides.core.statistics.service.TagProviderStrategy │ └── java │ ├── net │ └── serenitybdd │ │ └── cucumber │ │ ├── .directory │ │ ├── actors │ │ └── StageDirector.java │ │ ├── suiteslicing │ │ ├── SerenityCSVHeader.java │ │ ├── SliceBuilder.java │ │ ├── TestStatistics.java │ │ ├── CucumberSuiteSlicer.java │ │ ├── VisualisableCucumberScenarios.java │ │ ├── TestScenarioResult.java │ │ ├── WeightedCucumberScenario.java │ │ ├── TestScenarioResults.java │ │ ├── ScenarioFilter.java │ │ ├── SerenityTags.java │ │ └── CucumberScenarioVisualiser.java │ │ ├── CucumberWithSerenity.java │ │ ├── util │ │ ├── PathUtils.java │ │ ├── Splitter.java │ │ ├── TagParser.java │ │ └── BigDecimalAverageCollector.java │ │ ├── cli │ │ └── Main.java │ │ ├── service │ │ └── CucumberTagProviderStrategy.java │ │ ├── CucumberWithSerenityRuntime.java │ │ ├── formatting │ │ └── ScenarioOutlineDescription.java │ │ ├── model │ │ └── StoredFeatureFile.java │ │ └── integration │ │ └── intellij │ │ └── CucumberWithSerenityRuntimeMain.java │ ├── io │ └── cucumber │ │ ├── junit │ │ └── FeatureRunnerExtractors.java │ │ └── core │ │ └── plugin │ │ ├── FeaturePathFormatter.java │ │ ├── FeatureFileLoader.java │ │ └── LineFilters.java │ └── cucumber │ └── runtime │ └── SerenityBackend.java ├── settings.gradle ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── .github └── workflows │ └── gradle.yml ├── .gitignore ├── gradle.properties └── LICENSE.md /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # serenity-cucumber5 2 | -------------------------------------------------------------------------------- /src/test/resources/samples/empty/empty.feature: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/smoketests/src/test/resources/assets/an_image.txt: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | rootProject.name = 'serenity-cucumber5' 2 | -------------------------------------------------------------------------------- /src/main/resources/META-INF/services/io.cucumber.core.backend.Backend: -------------------------------------------------------------------------------- 1 | cucumber.runtime.SerenityBackend -------------------------------------------------------------------------------- /src/test/resources/.directory: -------------------------------------------------------------------------------- 1 | [Dolphin] 2 | Timestamp=2018,12,31,15,31,36 3 | Version=4 4 | ViewMode=1 5 | -------------------------------------------------------------------------------- /src/main/resources/META-INF/services/io.cucumber.core.backend.ObjectFactory: -------------------------------------------------------------------------------- 1 | cucumber.runtime.SerenityObjectFactory -------------------------------------------------------------------------------- /src/smoketests/src/test/resources/features/backgrounds/narrative.md: -------------------------------------------------------------------------------- 1 | ## Backgrounds are cool 2 | 3 | Use backgrounds. -------------------------------------------------------------------------------- /src/test/resources/data/names-data.csv: -------------------------------------------------------------------------------- 1 | firstname,lastname,expectedFirstname, expectedLastname 2 | Joe,Smith,Will,Smith 3 | -------------------------------------------------------------------------------- /src/main/java/net/serenitybdd/cucumber/.directory: -------------------------------------------------------------------------------- 1 | [Dolphin] 2 | Timestamp=2018,12,31,15,17,50 3 | Version=4 4 | ViewMode=1 5 | -------------------------------------------------------------------------------- /src/smoketests/src/test/resources/features/understanding_serenity_steps/narrative.txt: -------------------------------------------------------------------------------- 1 | ## Understanding how step libraries work -------------------------------------------------------------------------------- /src/test/groovy/net/serenitybdd/cucumber/.directory: -------------------------------------------------------------------------------- 1 | [Dolphin] 2 | Timestamp=2018,12,31,15,26,35 3 | Version=4 4 | ViewMode=1 5 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/serenity-bdd/serenity-cucumber5/HEAD/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /src/smoketests/src/test/resources/features/.directory: -------------------------------------------------------------------------------- 1 | [Dolphin] 2 | Timestamp=2018,12,31,15,23,54 3 | Version=4 4 | ViewMode=1 5 | -------------------------------------------------------------------------------- /src/smoketests/src/test/resources/features/skipped_pending_and_manual_scenarios/overview.md: -------------------------------------------------------------------------------- 1 | ## Don't miss out on anything 2 | 3 | It might be important. -------------------------------------------------------------------------------- /src/main/resources/META-INF/services/net.thucydides.core.statistics.service.TagProviderStrategy: -------------------------------------------------------------------------------- 1 | net.serenitybdd.cucumber.service.CucumberTagProviderStrategy -------------------------------------------------------------------------------- /src/smoketests/src/test/resources/features/overview.md: -------------------------------------------------------------------------------- 1 | ## This is a cool application! 2 | 3 | It does a stack of cool stuff 4 | 5 | * Stuff 6 | * Stuff 7 | * And more stuff -------------------------------------------------------------------------------- /src/smoketests/gradle.properties: -------------------------------------------------------------------------------- 1 | serenityCoreVersion = 2.1.17 2 | serenityCucumberVersion = 5.0.1 3 | junitVersion = 4.12 4 | assertjVersion = 3.6.2 5 | slf4jVersion = 1.7.25 6 | -------------------------------------------------------------------------------- /src/smoketests/serenity.properties: -------------------------------------------------------------------------------- 1 | # Default webdriver 2 | webdriver.driver=firefox 3 | 4 | serenity.restart.browser.for.each=feature 5 | #dashboard.excluded.tag.list=tag 6 | 7 | -------------------------------------------------------------------------------- /src/test/java/net/serenitybdd/cucumber/integration/steps/thucydides/GizmoBuyerSteps.java: -------------------------------------------------------------------------------- 1 | package net.serenitybdd.cucumber.integration.steps.thucydides; 2 | 3 | /** 4 | * Created by john on 19/08/2015. 5 | */ 6 | public class GizmoBuyerSteps { 7 | } 8 | -------------------------------------------------------------------------------- /src/test/resources/samples/feature_with_no_name.feature: -------------------------------------------------------------------------------- 1 | Feature: 2 | @shouldPass 3 | Scenario: A simple scenario 4 | Given I want to purchase 2 widgets 5 | And a widget costs $5 6 | When I buy the widgets 7 | Then I should be billed $10 8 | 9 | -------------------------------------------------------------------------------- /src/test/java/net/serenitybdd/cucumber/integration/steps/thucydides/SamplePageObject.java: -------------------------------------------------------------------------------- 1 | package net.serenitybdd.cucumber.integration.steps.thucydides; 2 | 3 | import net.thucydides.core.pages.PageObject; 4 | 5 | public class SamplePageObject extends PageObject {} 6 | -------------------------------------------------------------------------------- /src/test/resources/samples/pending_scenario.feature: -------------------------------------------------------------------------------- 1 | Feature: A pending feature 2 | 3 | Scenario: A pending scenario 4 | Given I want to purchase 2 widgets 5 | And a widget costs $5 6 | When I buy the blue widgets 7 | Then I should be billed $10 8 | 9 | -------------------------------------------------------------------------------- /src/test/resources/samples/simple_scenario.feature: -------------------------------------------------------------------------------- 1 | Feature: A simple feature 2 | @shouldPass 3 | Scenario: A simple scenario 4 | Given I want to purchase 2 widgets 5 | And a widget costs $5 6 | When I buy the widgets 7 | Then I should be billed $10 8 | 9 | -------------------------------------------------------------------------------- /src/test/resources/samples/web/dataDrivenBehavior.feature: -------------------------------------------------------------------------------- 1 | Feature: Data-driven testing 2 | 3 | Scenario: Non-web Data-driven testing from an external CSV file 4 | 5 | Given the data in data/names-data.csv 6 | When we enter this data 7 | Then the values should be correct 8 | -------------------------------------------------------------------------------- /src/test/resources/samples/numbers.feature: -------------------------------------------------------------------------------- 1 | Feature: Add two numbers 2 | 3 | Scenario: This scenario should be marked as pending 4 | 5 | Given the number 1 and the number 4 6 | When 1 plus 4 7 | Then the result is equals to 5 8 | And a PendingException should be thrown 9 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Wed Dec 11 16:17:52 GMT 2019 2 | distributionUrl=https\://services.gradle.org/distributions/gradle-5.3.1-all.zip 3 | distributionBase=GRADLE_USER_HOME 4 | distributionPath=wrapper/dists 5 | zipStorePath=wrapper/dists 6 | zipStoreBase=GRADLE_USER_HOME 7 | -------------------------------------------------------------------------------- /src/test/resources/samples/simple_scenario_with_a_long_name.feature: -------------------------------------------------------------------------------- 1 | Feature: A simple feature showing how features can have long names 2 | @shouldPass 3 | Scenario: A simple scenario 4 | Given I want to purchase 2 widgets 5 | And a widget costs $5 6 | When I buy the widgets 7 | Then I should be billed $10 8 | 9 | -------------------------------------------------------------------------------- /src/test/java/net/serenitybdd/cucumber/integration/WhenIntegratingThucydidesWithCucumber.java: -------------------------------------------------------------------------------- 1 | package net.serenitybdd.cucumber.integration; 2 | 3 | import net.serenitybdd.cucumber.CucumberWithSerenity; 4 | import org.junit.runner.RunWith; 5 | 6 | @RunWith(CucumberWithSerenity.class) 7 | public class WhenIntegratingThucydidesWithCucumber { 8 | } -------------------------------------------------------------------------------- /src/main/java/net/serenitybdd/cucumber/actors/StageDirector.java: -------------------------------------------------------------------------------- 1 | package net.serenitybdd.cucumber.actors; 2 | 3 | import io.cucumber.java.After; 4 | import net.serenitybdd.screenplay.actors.OnStage; 5 | 6 | public class StageDirector { 7 | @After 8 | public void endTheAct() { 9 | OnStage.drawTheCurtain(); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/test/resources/README.txt: -------------------------------------------------------------------------------- 1 | High-level requirements that need to be implemented/verified: 2 | [] Generate HTML and JSON test outcomes for each executed scenario 3 | [] Generated test outcome should have a feature tag matching the name of the feature file 4 | [] Generated test outcomes should have epic or capability tags based on the directory structure -------------------------------------------------------------------------------- /.github/workflows/gradle.yml: -------------------------------------------------------------------------------- 1 | name: Java CI 2 | 3 | on: [push] 4 | 5 | jobs: 6 | build: 7 | 8 | runs-on: ubuntu-latest 9 | 10 | steps: 11 | - uses: actions/checkout@v1 12 | - name: Set up JDK 1.8 13 | uses: actions/setup-java@v1 14 | with: 15 | java-version: 1.8 16 | - name: Build with Gradle 17 | run: ./gradlew test 18 | -------------------------------------------------------------------------------- /src/smoketests/src/test/java/smoketests/WhenUsingStepLibraries.java: -------------------------------------------------------------------------------- 1 | package smoketests; 2 | 3 | import io.cucumber.junit.CucumberOptions; 4 | import io.cucumber.junit.CucumberWithSerenity; 5 | import org.junit.runner.RunWith; 6 | 7 | @RunWith(CucumberWithSerenity.class) 8 | @CucumberOptions(features="src/test/resources/features") 9 | public class WhenUsingStepLibraries {} 10 | -------------------------------------------------------------------------------- /src/smoketests/src/test/java/smoketests/stepdefinitions/Hooks.java: -------------------------------------------------------------------------------- 1 | package smoketests.stepdefinitions; 2 | 3 | import cucumber.api.java.Before; 4 | import net.serenitybdd.cucumber.suiteslicing.SerenityTags; 5 | 6 | public class Hooks { 7 | 8 | @Before 9 | public void before() { 10 | SerenityTags.create().tagScenarioWithBatchingInfo(); 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/net/serenitybdd/cucumber/suiteslicing/SerenityCSVHeader.java: -------------------------------------------------------------------------------- 1 | package net.serenitybdd.cucumber.suiteslicing; 2 | 3 | public interface SerenityCSVHeader { 4 | String STORY = "Story"; 5 | String TITLE = "Title"; 6 | String RESULT = "Result"; 7 | String DATE = "Date"; 8 | String STABILITY = "Stability"; 9 | String DURATION = "Duration (s)"; 10 | } 11 | -------------------------------------------------------------------------------- /src/smoketests/src/test/java/smoketests/WhenUsingBackgrounds.java: -------------------------------------------------------------------------------- 1 | package smoketests; 2 | 3 | import io.cucumber.junit.CucumberOptions; 4 | import io.cucumber.junit.CucumberWithSerenity; 5 | import org.junit.runner.RunWith; 6 | 7 | @RunWith(CucumberWithSerenity.class) 8 | @CucumberOptions(features="src/test/resources/features/backgrounds") 9 | public class WhenUsingBackgrounds {} 10 | -------------------------------------------------------------------------------- /src/smoketests/src/test/java/smoketests/WhenUsingTables.java: -------------------------------------------------------------------------------- 1 | package smoketests; 2 | 3 | import io.cucumber.junit.CucumberOptions; 4 | import io.cucumber.junit.CucumberWithSerenity; 5 | import org.junit.runner.RunWith; 6 | 7 | @RunWith(CucumberWithSerenity.class) 8 | @CucumberOptions(features="src/test/resources/features/when_using_tables") 9 | public class WhenUsingTables {} 10 | -------------------------------------------------------------------------------- /src/test/resources/samples/scenario_with_a_broken_step_definition_class.feature: -------------------------------------------------------------------------------- 1 | Feature: Illegal step definition libraries 2 | 3 | @shouldFail 4 | Scenario: A scenario using a step definition library without a default constructor 5 | Given I have a step library that fails to instantiate 6 | When I run it using Thucydides 7 | Then the tests should fail with an exception 8 | 9 | -------------------------------------------------------------------------------- /src/smoketests/src/test/java/smoketests/RunASingleScenario.java: -------------------------------------------------------------------------------- 1 | package smoketests; 2 | 3 | import io.cucumber.junit.CucumberOptions; 4 | import io.cucumber.junit.CucumberWithSerenity; 5 | import org.junit.runner.RunWith; 6 | 7 | @RunWith(CucumberWithSerenity.class) 8 | @CucumberOptions(features="src/test/resources/features", tags = "@current") 9 | public class RunASingleScenario {} 10 | -------------------------------------------------------------------------------- /src/test/resources/samples/scenario_with_invalid_step_definition_class.feature: -------------------------------------------------------------------------------- 1 | Feature: Illegal step definition libraries 2 | 3 | @shouldFail 4 | Scenario: A scenario using a step definition library without a default constructor 5 | Given I have a step library without a default constructor 6 | When I run it using Thucydides 7 | Then the tests should fail with an exception 8 | 9 | -------------------------------------------------------------------------------- /src/test/java/samples/calculator/DateCalculator.java: -------------------------------------------------------------------------------- 1 | package samples.calculator; 2 | 3 | import java.util.Date; 4 | 5 | public class DateCalculator { 6 | private Date now; 7 | 8 | public DateCalculator(Date now) { 9 | this.now = now; 10 | } 11 | 12 | public String isDateInThePast(Date date) { 13 | return (date.before(now)) ? "yes" : "no"; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/test/resources/samples/pending_table_based_numbers.feature: -------------------------------------------------------------------------------- 1 | Feature: Add two numbers 2 | 3 | @pending 4 | Scenario Outline: This scenario should be marked as pending 5 | 6 | Given the number and the number 7 | When plus 8 | Then the result is equals to 9 | 10 | 11 | Examples: 12 | | a | b | c | 13 | | 1 | 4 | 5 | 14 | | 2 | 7 | 9 | -------------------------------------------------------------------------------- /src/test/resources/smoketests/using_background_steps.feature: -------------------------------------------------------------------------------- 1 | Feature: Using Background Steps 2 | 3 | Background: 4 | Given I want to add two numbers 5 | 6 | Scenario: Skipping a scenario 7 | When the first number is 1 8 | Then the running total should be 1 9 | 10 | Scenario: Running a scenario 11 | When the first number is 1 12 | Then the running total should be 1 13 | -------------------------------------------------------------------------------- /src/test/resources/samples/simple_scenario_with_narrative_text.feature: -------------------------------------------------------------------------------- 1 | Feature: A simple feature 2 | This is about selling widgets 3 | @shouldPass 4 | Scenario: A simple scenario 5 | A description of this scenario 6 | It goes for two lines 7 | Given I want to purchase 2 widgets 8 | And a widget costs $5 9 | When I buy the widgets 10 | Then I should be billed $10 11 | 12 | -------------------------------------------------------------------------------- /src/test/resources/samples/simple_scenario_with_tags.feature: -------------------------------------------------------------------------------- 1 | @flavor:strawberry 2 | Feature: A simple feature with tags 3 | This is about selling widgets 4 | @shouldPass 5 | @color:red 6 | @in-progress 7 | Scenario: A simple scenario with tags 8 | Given I want to purchase 2 widgets 9 | And a widget costs $5 10 | When I buy the widgets 11 | Then I should be billed $10 12 | 13 | -------------------------------------------------------------------------------- /src/test/resources/samples/manual_table_based_numbers.feature: -------------------------------------------------------------------------------- 1 | Feature: Add two numbers 2 | 3 | @manual-passed:2018-10-10 4 | Scenario Outline: This scenario should be marked as pending 5 | 6 | Given the amount and the amount 7 | When minus 8 | Then the result should be 9 | 10 | 11 | Examples: 12 | | a | b | c | 13 | | 1 | 4 | 5 | 14 | | 2 | 7 | 9 | -------------------------------------------------------------------------------- /src/main/java/net/serenitybdd/cucumber/CucumberWithSerenity.java: -------------------------------------------------------------------------------- 1 | package net.serenitybdd.cucumber; 2 | 3 | import io.cucumber.junit.CucumberSerenityRunner; 4 | import org.junit.runners.model.InitializationError; 5 | 6 | public class CucumberWithSerenity extends CucumberSerenityRunner { 7 | 8 | public CucumberWithSerenity(Class clazz) throws InitializationError { 9 | super(clazz); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/test/resources/samples/table_based_numbers.feature: -------------------------------------------------------------------------------- 1 | Feature: Add two numbers 2 | 3 | Scenario Outline: This scenario should be marked as pending 4 | 5 | Given the number and the number 6 | When plus 7 | Then the result is equals to 8 | And this step should throw a PendingException 9 | 10 | Examples: 11 | | a | b | c | 12 | | 1 | 4 | 5 | 13 | | 2 | 7 | 9 | -------------------------------------------------------------------------------- /src/test/java/net/serenitybdd/cucumber/integration/FeatureWithMoreIssuesTag.java: -------------------------------------------------------------------------------- 1 | package net.serenitybdd.cucumber.integration; 2 | 3 | import io.cucumber.junit.Cucumber; 4 | import io.cucumber.junit.CucumberOptions; 5 | import org.junit.runner.RunWith; 6 | 7 | 8 | @RunWith(Cucumber.class) 9 | @CucumberOptions(features="src/test/resources/samples/multiple_jira_issues.feature") 10 | public class FeatureWithMoreIssuesTag {} 11 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .classpath 2 | .project 3 | .settings/ 4 | src/smoketests/.classpath 5 | src/smoketests/.project 6 | src/smoketests/.settings/ 7 | src/smoketests/out/test/classes/ 8 | src/smoketests/target 9 | .gradle/ 10 | buildSrc/.gradle/ 11 | buildSrc/build/ 12 | lib/ 13 | target/ 14 | build/ 15 | /out/ 16 | .idea/ 17 | serenity-cucumber.iml 18 | src/smoketests/.idea/ 19 | src/smoketests/history/ 20 | src/smoketests/smoketests.iml 21 | *.iml -------------------------------------------------------------------------------- /src/test/resources/samples/failing_scenario_outline.feature: -------------------------------------------------------------------------------- 1 | Feature: A simple feature that fails 2 | 3 | @shouldFail 4 | Scenario Outline: A simple failing scenario outline 5 | Given I want to purchase widgets 6 | And at a cost of 7 | When I buy the widgets 8 | Then I should be billed $10 9 | Examples: 10 | | count | cost | total 11 | | 1 | 5 | 20 12 | | 2 | 5 | 10 13 | -------------------------------------------------------------------------------- /src/smoketests/src/test/java/smoketests/WhenUsingSkipPendingAndManualAnnotations.java: -------------------------------------------------------------------------------- 1 | package smoketests; 2 | 3 | import io.cucumber.junit.CucumberOptions; 4 | import io.cucumber.junit.CucumberWithSerenity; 5 | import org.junit.runner.RunWith; 6 | 7 | @RunWith(CucumberWithSerenity.class) 8 | @CucumberOptions(features="src/test/resources/features/skipped_pending_and_manual_scenarios") 9 | public class WhenUsingSkipPendingAndManualAnnotations {} 10 | -------------------------------------------------------------------------------- /src/test/java/net/serenitybdd/cucumber/smoketests/WhenUsingBackgroundSteps.java: -------------------------------------------------------------------------------- 1 | package net.serenitybdd.cucumber.smoketests; 2 | 3 | import io.cucumber.junit.CucumberOptions; 4 | import net.serenitybdd.cucumber.CucumberWithSerenity; 5 | import org.junit.runner.RunWith; 6 | 7 | @RunWith(CucumberWithSerenity.class) 8 | @CucumberOptions(features="classpath:smoketests/using_background_steps.feature") 9 | public class WhenUsingBackgroundSteps {} 10 | -------------------------------------------------------------------------------- /src/test/java/net/serenitybdd/cucumber/smoketests/WhenUsingStepLibraries.java: -------------------------------------------------------------------------------- 1 | package net.serenitybdd.cucumber.smoketests; 2 | 3 | import io.cucumber.junit.CucumberOptions; 4 | import net.serenitybdd.cucumber.CucumberWithSerenity; 5 | import org.junit.runner.RunWith; 6 | 7 | @RunWith(CucumberWithSerenity.class) 8 | @CucumberOptions(features="src/test/resources/smoketests/step_libraries.feature") 9 | public class WhenUsingStepLibraries { 10 | } 11 | -------------------------------------------------------------------------------- /src/test/resources/smoketests/undefined_scenarios.feature: -------------------------------------------------------------------------------- 1 | Feature: Using Undefined Scenarios 2 | 3 | Scenario: With steps that haven't been implemented yet 4 | Given I am Deep Thought 5 | When I discover the answer 6 | Then the answer should be 42 7 | 8 | Scenario: Another scenario with no defined steps 9 | Given I am Deep Thought 10 | When I discover the question 11 | Then the question should be what is 6 time 9 12 | -------------------------------------------------------------------------------- /src/test/java/net/serenitybdd/cucumber/integration/GizmoBuyer.java: -------------------------------------------------------------------------------- 1 | package net.serenitybdd.cucumber.integration; 2 | 3 | import io.cucumber.junit.Cucumber; 4 | import io.cucumber.junit.CucumberOptions; 5 | import org.junit.runner.RunWith; 6 | 7 | /** 8 | * Created by john on 23/07/2014. 9 | */ 10 | @RunWith(Cucumber.class) 11 | @CucumberOptions(features="src/test/resources/samples/data_driven_scenario.feature") 12 | public class GizmoBuyer {} 13 | -------------------------------------------------------------------------------- /src/test/java/net/serenitybdd/cucumber/smoketests/WhenSkippingScenarios.java: -------------------------------------------------------------------------------- 1 | package net.serenitybdd.cucumber.smoketests; 2 | 3 | import io.cucumber.junit.CucumberOptions; 4 | import net.serenitybdd.cucumber.CucumberWithSerenity; 5 | import org.junit.runner.RunWith; 6 | 7 | @RunWith(CucumberWithSerenity.class) 8 | @CucumberOptions(features="src/test/resources/smoketests/skipping_scenarios.feature") 9 | public class WhenSkippingScenarios { 10 | } 11 | -------------------------------------------------------------------------------- /src/test/java/net/serenitybdd/cucumber/smoketests/WhenUsingFixtureMethods.java: -------------------------------------------------------------------------------- 1 | package net.serenitybdd.cucumber.smoketests; 2 | 3 | import io.cucumber.junit.CucumberOptions; 4 | import net.serenitybdd.cucumber.CucumberWithSerenity; 5 | import org.junit.runner.RunWith; 6 | 7 | @RunWith(CucumberWithSerenity.class) 8 | @CucumberOptions(features="src/test/resources/smoketests/using_fixture_methods.feature") 9 | public class WhenUsingFixtureMethods { 10 | } 11 | -------------------------------------------------------------------------------- /src/test/java/net/serenitybdd/cucumber/smoketests/WhenUsingUndefinedScenarios.java: -------------------------------------------------------------------------------- 1 | package net.serenitybdd.cucumber.smoketests; 2 | 3 | import io.cucumber.junit.CucumberOptions; 4 | import net.serenitybdd.cucumber.CucumberWithSerenity; 5 | import org.junit.runner.RunWith; 6 | 7 | @RunWith(CucumberWithSerenity.class) 8 | @CucumberOptions(features="src/test/resources/smoketests/undefined_scenarios.feature") 9 | public class WhenUsingUndefinedScenarios {} 10 | -------------------------------------------------------------------------------- /src/test/resources/samples/web/aBehaviorWithSeleniumPageObjects.feature: -------------------------------------------------------------------------------- 1 | @driver:htmlunit 2 | Feature: Use page objects 3 | 4 | Scenario Outline: A scenario that uses selenium 5 | 6 | Given I am on the test page 7 | When I enter a first name 8 | And I enter a last name 9 | Then I should see the and in the names fields 10 | 11 | Examples: 12 | |firstname|lastname| 13 | |Joe | Bloggs| 14 | |John | Doe | -------------------------------------------------------------------------------- /src/test/java/net/serenitybdd/cucumber/integration/ScenarioThrowingPendingException.java: -------------------------------------------------------------------------------- 1 | package net.serenitybdd.cucumber.integration; 2 | 3 | import io.cucumber.junit.CucumberOptions; 4 | import net.serenitybdd.cucumber.CucumberWithSerenity; 5 | import org.junit.runner.RunWith; 6 | 7 | 8 | @RunWith(CucumberWithSerenity.class) 9 | @CucumberOptions(features="src/test/resources/samples/numbers.feature") 10 | public class ScenarioThrowingPendingException {} 11 | -------------------------------------------------------------------------------- /src/test/java/net/serenitybdd/cucumber/integration/SimpleSeleniumScenario.java: -------------------------------------------------------------------------------- 1 | package net.serenitybdd.cucumber.integration; 2 | 3 | import io.cucumber.junit.CucumberOptions; 4 | import net.serenitybdd.cucumber.CucumberWithSerenity; 5 | import org.junit.runner.RunWith; 6 | 7 | @RunWith(CucumberWithSerenity.class) 8 | @CucumberOptions(features="src/test/resources/samples/web/aPassingBehaviorWithSelenium.feature") 9 | public class SimpleSeleniumScenario {} 10 | -------------------------------------------------------------------------------- /src/test/resources/samples/simple_tagged_pending_feature.feature: -------------------------------------------------------------------------------- 1 | @wip 2 | Feature: A simple feature 3 | Scenario: A simple scenario 4 | Given I want to purchase 2 widgets 5 | And a widget costs $5 6 | When I buy the widgets 7 | Then I should be billed $10 8 | 9 | Scenario: Another simple scenario 10 | Given I want to purchase 2 widgets 11 | And a widget costs $5 12 | When I buy the widgets 13 | Then I should be billed $10 14 | -------------------------------------------------------------------------------- /src/test/java/net/serenitybdd/cucumber/integration/SimpleTaggedPendingFeature.java: -------------------------------------------------------------------------------- 1 | package net.serenitybdd.cucumber.integration; 2 | 3 | import io.cucumber.junit.CucumberOptions; 4 | import net.serenitybdd.cucumber.CucumberWithSerenity; 5 | import org.junit.runner.RunWith; 6 | 7 | @RunWith(CucumberWithSerenity.class) 8 | @CucumberOptions(features="src/test/resources/samples/simple_tagged_pending_feature.feature") 9 | public class SimpleTaggedPendingFeature {} 10 | -------------------------------------------------------------------------------- /src/test/java/net/serenitybdd/cucumber/integration/SimpleTaggedPendingScenario.java: -------------------------------------------------------------------------------- 1 | package net.serenitybdd.cucumber.integration; 2 | 3 | import io.cucumber.junit.CucumberOptions; 4 | import net.serenitybdd.cucumber.CucumberWithSerenity; 5 | import org.junit.runner.RunWith; 6 | 7 | @RunWith(CucumberWithSerenity.class) 8 | @CucumberOptions(features="src/test/resources/samples/simple_tagged_pending_scenario.feature") 9 | public class SimpleTaggedPendingScenario {} 10 | -------------------------------------------------------------------------------- /src/test/resources/samples/simple_tagged_pending_scenario.feature: -------------------------------------------------------------------------------- 1 | Feature: A simple feature 2 | @wip 3 | Scenario: A simple scenario 4 | Given I want to purchase 2 widgets 5 | And a widget costs $5 6 | When I buy the widgets 7 | Then I should be billed $10 8 | 9 | Scenario: Another simple scenario 10 | Given I want to purchase 2 widgets 11 | And a widget costs $5 12 | When I buy the widgets 13 | Then I should be billed $10 14 | -------------------------------------------------------------------------------- /src/test/java/net/serenitybdd/cucumber/integration/SimpleSeleniumFailingScenario.java: -------------------------------------------------------------------------------- 1 | package net.serenitybdd.cucumber.integration; 2 | 3 | import io.cucumber.junit.CucumberOptions; 4 | import net.serenitybdd.cucumber.CucumberWithSerenity; 5 | import org.junit.runner.RunWith; 6 | 7 | @RunWith(CucumberWithSerenity.class) 8 | @CucumberOptions(features="src/test/resources/samples/web/aFailingBehaviorWithSelenium.feature") 9 | public class SimpleSeleniumFailingScenario {} 10 | -------------------------------------------------------------------------------- /src/test/java/net/serenitybdd/cucumber/integration/SimpleSeleniumPageObjects.java: -------------------------------------------------------------------------------- 1 | package net.serenitybdd.cucumber.integration; 2 | 3 | import io.cucumber.junit.CucumberOptions; 4 | import net.serenitybdd.cucumber.CucumberWithSerenity; 5 | import org.junit.runner.RunWith; 6 | 7 | @RunWith(CucumberWithSerenity.class) 8 | @CucumberOptions(features="src/test/resources/samples/web/aBehaviorWithSeleniumPageObjects.feature") 9 | public class SimpleSeleniumPageObjects {} 10 | -------------------------------------------------------------------------------- /src/test/java/net/serenitybdd/cucumber/integration/TableScenarioMarkedAsManual.java: -------------------------------------------------------------------------------- 1 | package net.serenitybdd.cucumber.integration; 2 | 3 | import io.cucumber.junit.CucumberOptions; 4 | import net.serenitybdd.cucumber.CucumberWithSerenity; 5 | import org.junit.runner.RunWith; 6 | 7 | 8 | @RunWith(CucumberWithSerenity.class) 9 | @CucumberOptions(features="src/test/resources/samples/manual_table_based_numbers.feature") 10 | public class TableScenarioMarkedAsManual {} 11 | -------------------------------------------------------------------------------- /src/test/java/net/serenitybdd/cucumber/integration/TableScenarioMarkedAsPending.java: -------------------------------------------------------------------------------- 1 | package net.serenitybdd.cucumber.integration; 2 | 3 | import io.cucumber.junit.CucumberOptions; 4 | import net.serenitybdd.cucumber.CucumberWithSerenity; 5 | import org.junit.runner.RunWith; 6 | 7 | 8 | @RunWith(CucumberWithSerenity.class) 9 | @CucumberOptions(features="src/test/resources/samples/pending_table_based_numbers.feature") 10 | public class TableScenarioMarkedAsPending {} 11 | -------------------------------------------------------------------------------- /src/test/java/net/serenitybdd/cucumber/integration/steps/thucydides/SampleSteps.java: -------------------------------------------------------------------------------- 1 | package net.serenitybdd.cucumber.integration.steps.thucydides; 2 | 3 | import net.thucydides.core.annotations.Step; 4 | 5 | /** 6 | * Created by john on 15/07/2014. 7 | */ 8 | public class SampleSteps { 9 | 10 | public SamplePageObject pageObject; 11 | 12 | @Step 13 | public void aSimpleStep() { } 14 | 15 | @Step 16 | public void anotherSimpleStep() {} 17 | } 18 | -------------------------------------------------------------------------------- /src/test/java/net/serenitybdd/cucumber/integration/ScenariosWithPendingTag.java: -------------------------------------------------------------------------------- 1 | package net.serenitybdd.cucumber.integration; 2 | 3 | import io.cucumber.junit.Cucumber; 4 | import io.cucumber.junit.CucumberOptions; 5 | import org.junit.runner.RunWith; 6 | 7 | /** 8 | * Created by john on 23/07/2014. 9 | */ 10 | @RunWith(Cucumber.class) 11 | @CucumberOptions(features="src/test/resources/samples/scenarios_pending_tag.feature") 12 | public class ScenariosWithPendingTag {} 13 | -------------------------------------------------------------------------------- /src/test/resources/samples/multiple_scenarios_pending_tag.feature: -------------------------------------------------------------------------------- 1 | @pending 2 | Feature: A feature with multiple scenarios 3 | 4 | Scenario: Simple scenario 1 5 | Given I want to purchase 2 widgets 6 | And a widget costs $5 7 | When I buy the widgets 8 | Then I should be billed $50 9 | 10 | Scenario: Simple scenario 2 11 | Given I want to purchase 4 widgets 12 | And a widget costs $3 13 | When I buy the widgets 14 | Then I should be billed $12 -------------------------------------------------------------------------------- /src/test/resources/samples/multiple_scenarios_skipped_tag.feature: -------------------------------------------------------------------------------- 1 | @skip 2 | Feature: A feature with multiple scenarios 3 | 4 | Scenario: Simple scenario 1 5 | Given I want to purchase 2 widgets 6 | And a widget costs $5 7 | When I buy the widgets 8 | Then I should be billed $50 9 | 10 | Scenario: Simple scenario 2 11 | Given I want to purchase 4 widgets 12 | And a widget costs $3 13 | When I buy the widgets 14 | Then I should be billed $12 -------------------------------------------------------------------------------- /src/test/java/net/serenitybdd/cucumber/integration/TableScenarioThrowingPendingException.java: -------------------------------------------------------------------------------- 1 | package net.serenitybdd.cucumber.integration; 2 | 3 | import io.cucumber.junit.CucumberOptions; 4 | import net.serenitybdd.cucumber.CucumberWithSerenity; 5 | import org.junit.runner.RunWith; 6 | 7 | 8 | @RunWith(CucumberWithSerenity.class) 9 | @CucumberOptions(features="src/test/resources/samples/table_based_numbers.feature") 10 | public class TableScenarioThrowingPendingException {} 11 | -------------------------------------------------------------------------------- /src/test/java/net/serenitybdd/cucumber/integration/BasicArithmeticScenario.java: -------------------------------------------------------------------------------- 1 | package net.serenitybdd.cucumber.integration; 2 | 3 | import io.cucumber.junit.CucumberOptions; 4 | import net.serenitybdd.cucumber.CucumberWithSerenity; 5 | import org.junit.runner.RunWith; 6 | 7 | /** 8 | * Created by john on 23/07/2014. 9 | */ 10 | @RunWith(CucumberWithSerenity.class) 11 | @CucumberOptions(features="src/test/resources/samples/calculator") 12 | public class BasicArithmeticScenario {} 13 | -------------------------------------------------------------------------------- /src/test/java/net/serenitybdd/cucumber/integration/FailingScenario.java: -------------------------------------------------------------------------------- 1 | package net.serenitybdd.cucumber.integration; 2 | 3 | import io.cucumber.junit.CucumberOptions; 4 | import net.serenitybdd.cucumber.CucumberWithSerenity; 5 | import org.junit.runner.RunWith; 6 | 7 | /** 8 | * Created by john on 23/07/2014. 9 | */ 10 | @RunWith(CucumberWithSerenity.class) 11 | @CucumberOptions(features="src/test/resources/samples/failing_scenario.feature") 12 | public class FailingScenario {} 13 | -------------------------------------------------------------------------------- /src/test/java/net/serenitybdd/cucumber/integration/PendingScenario.java: -------------------------------------------------------------------------------- 1 | package net.serenitybdd.cucumber.integration; 2 | 3 | import io.cucumber.junit.CucumberOptions; 4 | import net.serenitybdd.cucumber.CucumberWithSerenity; 5 | import org.junit.runner.RunWith; 6 | 7 | /** 8 | * Created by john on 23/07/2014. 9 | */ 10 | @RunWith(CucumberWithSerenity.class) 11 | @CucumberOptions(features="src/test/resources/samples/pending_scenario.feature") 12 | public class PendingScenario {} 13 | -------------------------------------------------------------------------------- /src/test/java/net/serenitybdd/cucumber/integration/SimpleTableScenarioWithLineFilters.java: -------------------------------------------------------------------------------- 1 | package net.serenitybdd.cucumber.integration; 2 | 3 | import io.cucumber.junit.CucumberOptions; 4 | import net.serenitybdd.cucumber.CucumberWithSerenity; 5 | import org.junit.runner.RunWith; 6 | 7 | @RunWith(CucumberWithSerenity.class) 8 | @CucumberOptions(features="src/test/resources/samples/simple_table_based_scenario.feature:15:17") 9 | public class SimpleTableScenarioWithLineFilters {} 10 | -------------------------------------------------------------------------------- /src/test/java/net/serenitybdd/cucumber/integration/MultipleScenarios.java: -------------------------------------------------------------------------------- 1 | package net.serenitybdd.cucumber.integration; 2 | 3 | import io.cucumber.junit.CucumberOptions; 4 | import net.serenitybdd.cucumber.CucumberWithSerenity; 5 | import org.junit.runner.RunWith; 6 | 7 | /** 8 | * Created by john on 23/07/2014. 9 | */ 10 | @RunWith(CucumberWithSerenity.class) 11 | @CucumberOptions(features="src/test/resources/samples/multiple_scenarios.feature") 12 | public class MultipleScenarios {} 13 | -------------------------------------------------------------------------------- /src/test/java/net/serenitybdd/cucumber/integration/ScenarioSuite.java: -------------------------------------------------------------------------------- 1 | package net.serenitybdd.cucumber.integration; 2 | 3 | import io.cucumber.junit.CucumberOptions; 4 | import net.serenitybdd.cucumber.CucumberWithSerenity; 5 | import org.junit.runner.RunWith; 6 | 7 | /** 8 | * Created by john on 23/07/2014. 9 | */ 10 | @RunWith(CucumberWithSerenity.class) 11 | @CucumberOptions(features="src/test/resources/samples/web/lookupAScenarioSuite.feature") 12 | public class ScenarioSuite {} 13 | -------------------------------------------------------------------------------- /src/test/java/net/serenitybdd/cucumber/integration/SimpleScenario.java: -------------------------------------------------------------------------------- 1 | package net.serenitybdd.cucumber.integration; 2 | 3 | 4 | import io.cucumber.junit.CucumberOptions; 5 | import net.serenitybdd.cucumber.CucumberWithSerenity; 6 | import org.junit.runner.RunWith; 7 | 8 | /** 9 | * Created by john on 23/07/2014. 10 | */ 11 | @RunWith(CucumberWithSerenity.class) 12 | @CucumberOptions(features="src/test/resources/samples/simple_scenario.feature") 13 | public class SimpleScenario {} 14 | -------------------------------------------------------------------------------- /src/test/resources/samples/multiple_scenarios.feature: -------------------------------------------------------------------------------- 1 | Feature: A feature with multiple scenarios 2 | 3 | @shouldFail 4 | Scenario: Simple scenario 1 5 | Given I want to purchase 2 widgets 6 | And a widget costs $5 7 | When I buy the widgets 8 | Then I should be billed $50 9 | 10 | @shouldPass 11 | Scenario: Simple scenario 2 12 | Given I want to purchase 4 widgets 13 | And a widget costs $3 14 | When I buy the widgets 15 | Then I should be billed $12 -------------------------------------------------------------------------------- /src/test/java/net/serenitybdd/cucumber/integration/DataDrivenScenario.java: -------------------------------------------------------------------------------- 1 | package net.serenitybdd.cucumber.integration; 2 | 3 | import io.cucumber.junit.CucumberOptions; 4 | import net.serenitybdd.cucumber.CucumberWithSerenity; 5 | import org.junit.runner.RunWith; 6 | 7 | /** 8 | * Created by john on 23/07/2014. 9 | */ 10 | @RunWith(CucumberWithSerenity.class) 11 | @CucumberOptions(features="src/test/resources/samples/web/dataDrivenBehavior.feature") 12 | public class DataDrivenScenario {} 13 | -------------------------------------------------------------------------------- /src/test/java/net/serenitybdd/cucumber/integration/FeatureWithNoName.java: -------------------------------------------------------------------------------- 1 | package net.serenitybdd.cucumber.integration; 2 | 3 | import io.cucumber.junit.CucumberOptions; 4 | import net.serenitybdd.cucumber.CucumberWithSerenity; 5 | import org.junit.runner.RunWith; 6 | 7 | /** 8 | * Created by john on 23/07/2014. 9 | */ 10 | @RunWith(CucumberWithSerenity.class) 11 | @CucumberOptions(features="src/test/resources/samples/feature_with_no_name.feature") 12 | public class FeatureWithNoName {} 13 | -------------------------------------------------------------------------------- /src/test/java/net/serenitybdd/cucumber/integration/SimpleSeleniumSeveralScenarios.java: -------------------------------------------------------------------------------- 1 | package net.serenitybdd.cucumber.integration; 2 | 3 | import io.cucumber.junit.CucumberOptions; 4 | import net.serenitybdd.cucumber.CucumberWithSerenity; 5 | import org.junit.runner.RunWith; 6 | 7 | @RunWith(CucumberWithSerenity.class) 8 | @CucumberOptions(features="src/test/resources/samples/web/aPassingBehaviorWithSeleniumAndSeveralScenarios.feature") 9 | public class SimpleSeleniumSeveralScenarios {} 10 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | serenityCoreVersion = 2.2.9 2 | cucumberJVMVersion = 5.6.0 3 | cucumberDatatableMatchers = 3.3.0 4 | junitVersion = 4.12 5 | logbackVersion=1.0.13 6 | assertjVersion = 3.6.2 7 | groovyVersion=2.4.11 8 | spockVersion = 1.1-groovy-2.4 9 | spockExtensionsVersion = 0.1.4 10 | commonsCollectionsVersion = 3.2.2 11 | xmlApiVersion=1.4.01 12 | commonsCodecVersion = 1.10 13 | commonsLoggingVersion = 1.2 14 | commonsCsvVersion = 1.5 15 | gsonVersion = 2.8.4 16 | jacksonDatabindVersion=2.10.2 17 | -------------------------------------------------------------------------------- /src/test/java/net/serenitybdd/cucumber/integration/PassingWebTestSampleWithNestedSteps.java: -------------------------------------------------------------------------------- 1 | package net.serenitybdd.cucumber.integration; 2 | 3 | import io.cucumber.junit.CucumberOptions; 4 | import net.serenitybdd.cucumber.CucumberWithSerenity; 5 | import org.junit.runner.RunWith; 6 | 7 | 8 | @RunWith(CucumberWithSerenity.class) 9 | @CucumberOptions(features="src/test/resources/samples/web/aPassingWebTestSampleWithNestedSteps.feature") 10 | public class PassingWebTestSampleWithNestedSteps {} 11 | -------------------------------------------------------------------------------- /src/test/java/net/serenitybdd/cucumber/integration/SimpleSeleniumFailingAndPassingScenario.java: -------------------------------------------------------------------------------- 1 | package net.serenitybdd.cucumber.integration; 2 | 3 | import io.cucumber.junit.CucumberOptions; 4 | import net.serenitybdd.cucumber.CucumberWithSerenity; 5 | import org.junit.runner.RunWith; 6 | 7 | @RunWith(CucumberWithSerenity.class) 8 | @CucumberOptions(features="src/test/resources/samples/web/failingAndPassingBehaviorsWithSelenium.feature") 9 | public class SimpleSeleniumFailingAndPassingScenario {} 10 | -------------------------------------------------------------------------------- /src/test/resources/smoketests/using_fixture_methods.feature: -------------------------------------------------------------------------------- 1 | Feature: Using Fixture Methods 2 | 3 | @start-at-two 4 | Scenario: Running a scenario with a Before clause 5 | Given I want to add two numbers 6 | When the first number is 1 7 | Then the running total should be 3 8 | 9 | @multiply-result-by-two 10 | Scenario: Running a scenario with an After clause 11 | Given I want to add two numbers 12 | When the first number is 1 13 | Then the running total should be 1 14 | -------------------------------------------------------------------------------- /src/test/java/net/serenitybdd/cucumber/integration/FailingScenarioOutline.java: -------------------------------------------------------------------------------- 1 | package net.serenitybdd.cucumber.integration; 2 | 3 | import io.cucumber.junit.CucumberOptions; 4 | import net.serenitybdd.cucumber.CucumberWithSerenity; 5 | import org.junit.runner.RunWith; 6 | 7 | /** 8 | * Created by john on 23/07/2014. 9 | */ 10 | @RunWith(CucumberWithSerenity.class) 11 | @CucumberOptions(features="src/test/resources/samples/failing_scenario_outline.feature") 12 | public class FailingScenarioOutline {} 13 | -------------------------------------------------------------------------------- /src/test/java/net/serenitybdd/cucumber/integration/SampleDataDrivenScenario.java: -------------------------------------------------------------------------------- 1 | package net.serenitybdd.cucumber.integration; 2 | 3 | import io.cucumber.junit.CucumberOptions; 4 | import net.serenitybdd.cucumber.CucumberWithSerenity; 5 | import org.junit.runner.RunWith; 6 | 7 | /** 8 | * Created by john on 23/07/2014. 9 | */ 10 | @RunWith(CucumberWithSerenity.class) 11 | @CucumberOptions(features="src/test/resources/samples/data_driven_scenario.feature") 12 | public class SampleDataDrivenScenario {} 13 | -------------------------------------------------------------------------------- /src/test/java/net/serenitybdd/cucumber/integration/ScenariosWithSkippedTag.java: -------------------------------------------------------------------------------- 1 | package net.serenitybdd.cucumber.integration; 2 | 3 | import io.cucumber.junit.CucumberOptions; 4 | import net.serenitybdd.cucumber.CucumberWithSerenity; 5 | import org.junit.runner.RunWith; 6 | 7 | /** 8 | * Created by john on 23/07/2014. 9 | */ 10 | @RunWith(CucumberWithSerenity.class) 11 | @CucumberOptions(features="src/test/resources/samples/scenarios_skipped_tag.feature") 12 | public class ScenariosWithSkippedTag {} 13 | -------------------------------------------------------------------------------- /src/test/java/net/serenitybdd/cucumber/integration/SimpleSeleniumDifferentBrowserScenario.java: -------------------------------------------------------------------------------- 1 | package net.serenitybdd.cucumber.integration; 2 | 3 | import io.cucumber.junit.CucumberOptions; 4 | import net.serenitybdd.cucumber.CucumberWithSerenity; 5 | import org.junit.runner.RunWith; 6 | 7 | @RunWith(CucumberWithSerenity.class) 8 | @CucumberOptions(features="src/test/resources/samples/web/aBehaviorWithSeleniumUsingADifferentBrowser.feature") 9 | public class SimpleSeleniumDifferentBrowserScenario {} 10 | -------------------------------------------------------------------------------- /src/test/java/net/serenitybdd/cucumber/integration/SimpleTableScenario.java: -------------------------------------------------------------------------------- 1 | package net.serenitybdd.cucumber.integration; 2 | 3 | import io.cucumber.junit.CucumberOptions; 4 | import net.serenitybdd.cucumber.CucumberWithSerenity; 5 | import org.junit.runner.RunWith; 6 | 7 | /** 8 | * Created by john on 23/07/2014. 9 | */ 10 | @RunWith(CucumberWithSerenity.class) 11 | @CucumberOptions(features="src/test/resources/samples/simple_table_based_scenario.feature") 12 | public class SimpleTableScenario {} 13 | -------------------------------------------------------------------------------- /src/test/java/net/serenitybdd/cucumber/integration/MultipleScenariosWithWIPTag.java: -------------------------------------------------------------------------------- 1 | package net.serenitybdd.cucumber.integration; 2 | 3 | import io.cucumber.junit.CucumberOptions; 4 | import net.serenitybdd.cucumber.CucumberWithSerenity; 5 | import org.junit.runner.RunWith; 6 | 7 | /** 8 | * Created by john on 23/07/2014. 9 | */ 10 | @RunWith(CucumberWithSerenity.class) 11 | @CucumberOptions(features="src/test/resources/samples/multiple_scenarios.feature") 12 | public class MultipleScenariosWithWIPTag {} 13 | -------------------------------------------------------------------------------- /src/test/java/net/serenitybdd/cucumber/integration/SimpleScenarioWithTags.java: -------------------------------------------------------------------------------- 1 | package net.serenitybdd.cucumber.integration; 2 | 3 | import io.cucumber.junit.CucumberOptions; 4 | import net.serenitybdd.cucumber.CucumberWithSerenity; 5 | import org.junit.runner.RunWith; 6 | 7 | /** 8 | * Created by john on 23/07/2014. 9 | */ 10 | @RunWith(CucumberWithSerenity.class) 11 | @CucumberOptions(features="src/test/resources/samples/simple_scenario_with_tags.feature") 12 | public class SimpleScenarioWithTags {} 13 | -------------------------------------------------------------------------------- /src/test/resources/samples/screenplay_table_based_scenario_with_errors.feature: -------------------------------------------------------------------------------- 1 | Feature: Buying things - with tables and errors 2 | 3 | Scenario Outline: Buying lots of widgets 4 | Given I want to purchase gizmos 5 | And a gizmo costs $ 6 | When I order the gizmos 7 | Then I should pay $ 8 | Examples: 9 | | amount | cost | total | 10 | | 0 | 10 | 0 | 11 | | -1 | 10 | 10 | 12 | | 2 | 10 | 50 | 13 | | 2 | 0 | 0 | 14 | 15 | -------------------------------------------------------------------------------- /src/test/java/net/serenitybdd/cucumber/integration/RunExamplesWithoutTags.java: -------------------------------------------------------------------------------- 1 | package net.serenitybdd.cucumber.integration; 2 | 3 | import io.cucumber.junit.CucumberOptions; 4 | import net.serenitybdd.cucumber.CucumberWithSerenity; 5 | import org.junit.runner.RunWith; 6 | 7 | 8 | @RunWith(CucumberWithSerenity.class) 9 | @CucumberOptions(features="src/test/resources/features/calculator/basic_arithmetic_with_tables_and_examples_no_tags.feature",tags = {"not @example_two"}) 10 | public class RunExamplesWithoutTags {} -------------------------------------------------------------------------------- /src/test/java/net/serenitybdd/cucumber/integration/ScenariosWithTableInBackgroundSteps.java: -------------------------------------------------------------------------------- 1 | package net.serenitybdd.cucumber.integration; 2 | 3 | import io.cucumber.junit.Cucumber; 4 | import io.cucumber.junit.CucumberOptions; 5 | import org.junit.runner.RunWith; 6 | 7 | /** 8 | * Created by john on 23/07/2014. 9 | */ 10 | @RunWith(Cucumber.class) 11 | @CucumberOptions(features="src/test/resources/samples/scenario_with_table_in_background_steps.feature") 12 | public class ScenariosWithTableInBackgroundSteps {} 13 | -------------------------------------------------------------------------------- /src/test/java/net/serenitybdd/cucumber/integration/FeatureWithPendingTag.java: -------------------------------------------------------------------------------- 1 | package net.serenitybdd.cucumber.integration; 2 | 3 | import io.cucumber.junit.Cucumber; 4 | import io.cucumber.junit.CucumberOptions; 5 | import org.junit.runner.RunWith; 6 | 7 | //import cucumber.api.junit.Cucumber; 8 | 9 | /** 10 | * Created by john on 23/07/2014. 11 | */ 12 | @RunWith(Cucumber.class) 13 | @CucumberOptions(features="src/test/resources/samples/feature_pending_tag.feature") 14 | public class FeatureWithPendingTag {} 15 | -------------------------------------------------------------------------------- /src/test/java/net/serenitybdd/cucumber/integration/SimpleScenarioWithALongName.java: -------------------------------------------------------------------------------- 1 | package net.serenitybdd.cucumber.integration; 2 | 3 | import io.cucumber.junit.CucumberOptions; 4 | import net.serenitybdd.cucumber.CucumberWithSerenity; 5 | import org.junit.runner.RunWith; 6 | 7 | /** 8 | * Created by john on 23/07/2014. 9 | */ 10 | @RunWith(CucumberWithSerenity.class) 11 | @CucumberOptions(features="src/test/resources/samples/simple_scenario_with_a_long_name.feature") 12 | public class SimpleScenarioWithALongName {} 13 | -------------------------------------------------------------------------------- /src/test/java/net/serenitybdd/cucumber/integration/MultipleScenariosWithIgnoreTag.java: -------------------------------------------------------------------------------- 1 | package net.serenitybdd.cucumber.integration; 2 | 3 | import io.cucumber.junit.CucumberOptions; 4 | import net.serenitybdd.cucumber.CucumberWithSerenity; 5 | import org.junit.runner.RunWith; 6 | 7 | /** 8 | * Created by john on 23/07/2014. 9 | */ 10 | @RunWith(CucumberWithSerenity.class) 11 | @CucumberOptions(features="src/test/resources/samples/multiple_scenarios_pending_tag.feature") 12 | public class MultipleScenariosWithIgnoreTag {} 13 | -------------------------------------------------------------------------------- /src/test/java/net/serenitybdd/cucumber/integration/MultipleScenariosWithPendingTag.java: -------------------------------------------------------------------------------- 1 | package net.serenitybdd.cucumber.integration; 2 | 3 | import io.cucumber.junit.CucumberOptions; 4 | import net.serenitybdd.cucumber.CucumberWithSerenity; 5 | import org.junit.runner.RunWith; 6 | 7 | /** 8 | * Created by john on 23/07/2014. 9 | */ 10 | @RunWith(CucumberWithSerenity.class) 11 | @CucumberOptions(features="src/test/resources/samples/multiple_scenarios_pending_tag.feature") 12 | public class MultipleScenariosWithPendingTag {} 13 | -------------------------------------------------------------------------------- /src/test/java/net/serenitybdd/cucumber/integration/MultipleScenariosWithSkippedTag.java: -------------------------------------------------------------------------------- 1 | package net.serenitybdd.cucumber.integration; 2 | 3 | import io.cucumber.junit.CucumberOptions; 4 | import net.serenitybdd.cucumber.CucumberWithSerenity; 5 | import org.junit.runner.RunWith; 6 | 7 | /** 8 | * Created by john on 23/07/2014. 9 | */ 10 | @RunWith(CucumberWithSerenity.class) 11 | @CucumberOptions(features="src/test/resources/samples/multiple_scenarios_skipped_tag.feature") 12 | public class MultipleScenariosWithSkippedTag {} 13 | -------------------------------------------------------------------------------- /src/test/java/net/serenitybdd/cucumber/integration/steps/thucydides/WidgetSteps.java: -------------------------------------------------------------------------------- 1 | package net.serenitybdd.cucumber.integration.steps.thucydides; 2 | 3 | import net.thucydides.core.annotations.Step; 4 | 5 | import static org.assertj.core.api.Assertions.assertThat; 6 | 7 | /** 8 | * Created by john on 20/01/15. 9 | */ 10 | public class WidgetSteps { 11 | 12 | @Step 13 | public void shouldBeBilled(int billedPrice, int totalPrice) { 14 | assertThat(billedPrice).isEqualTo(totalPrice); 15 | } 16 | 17 | } 18 | -------------------------------------------------------------------------------- /src/test/resources/samples/web/aPassingWebTestSampleWithNestedSteps.feature: -------------------------------------------------------------------------------- 1 | @driver:phantomjs 2 | @driver-options:--headless 3 | 4 | Feature: Passing web test sample with nested steps 5 | 6 | Scenario Outline: A scenario that uses selenium 7 | 8 | Given I am on the test page 9 | When I type in the first name 10 | And I type in the last name 11 | Then I should see and in the names fields 12 | 13 | Examples: 14 | |firstname|lastname| 15 | |Joe | Blanc | 16 | |John | Doe | -------------------------------------------------------------------------------- /src/test/java/net/serenitybdd/cucumber/integration/BrokenStepLibraryScenario.java: -------------------------------------------------------------------------------- 1 | package net.serenitybdd.cucumber.integration; 2 | 3 | import io.cucumber.junit.CucumberOptions; 4 | import net.serenitybdd.cucumber.CucumberWithSerenity; 5 | import org.junit.runner.RunWith; 6 | 7 | /** 8 | * Created by john on 23/07/2014. 9 | */ 10 | @RunWith(CucumberWithSerenity.class) 11 | @CucumberOptions(features="src/test/resources/samples/scenario_with_a_broken_step_definition_class.feature") 12 | public class BrokenStepLibraryScenario {} 13 | -------------------------------------------------------------------------------- /src/test/java/net/serenitybdd/cucumber/integration/IllegalStepLibraryScenario.java: -------------------------------------------------------------------------------- 1 | package net.serenitybdd.cucumber.integration; 2 | 3 | import io.cucumber.junit.CucumberOptions; 4 | import net.serenitybdd.cucumber.CucumberWithSerenity; 5 | import org.junit.runner.RunWith; 6 | 7 | /** 8 | * Created by john on 23/07/2014. 9 | */ 10 | @RunWith(CucumberWithSerenity.class) 11 | @CucumberOptions(features="src/test/resources/samples/scenario_with_invalid_step_definition_class.feature") 12 | public class IllegalStepLibraryScenario {} 13 | -------------------------------------------------------------------------------- /src/test/java/net/serenitybdd/cucumber/integration/TaggedExampleTablesScenarios.java: -------------------------------------------------------------------------------- 1 | package net.serenitybdd.cucumber.integration; 2 | 3 | import io.cucumber.junit.CucumberOptions; 4 | import net.serenitybdd.cucumber.CucumberWithSerenity; 5 | import org.junit.runner.RunWith; 6 | 7 | /** 8 | * Created by john on 23/07/2014. 9 | */ 10 | @RunWith(CucumberWithSerenity.class) 11 | @CucumberOptions(features="src/test/resources/samples/tagged_example_tables.feature")//, tags = "@big") 12 | public class TaggedExampleTablesScenarios {} 13 | -------------------------------------------------------------------------------- /src/test/java/net/serenitybdd/cucumber/integration/steps/CoreSteps.java: -------------------------------------------------------------------------------- 1 | package net.serenitybdd.cucumber.integration.steps; 2 | 3 | import io.cucumber.java.en.Then; 4 | import io.cucumber.java.en.When; 5 | 6 | 7 | public class CoreSteps { 8 | 9 | @When("^I run it using Thucydides$") 10 | public void I_run_it_using_Thucydides() throws Throwable {} 11 | 12 | @Then("^Thucydides should record a test outcome in the target directory$") 13 | public void should_record_test_outcome() throws Throwable { 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/test/resources/samples/screenplay_table_based_scenario_with_failures.feature: -------------------------------------------------------------------------------- 1 | Feature: Buying things - with tables and failures 2 | 3 | Scenario Outline: Buying lots of widgets 4 | Given I want to purchase gizmos 5 | And a gizmo costs $ 6 | When I buy said gizmos 7 | Then I should pay $ 8 | Examples: 9 | | amount | cost | total | 10 | | 0 | 10 | 0 | 11 | | 1 | 10 | 10 | 12 | | 2 | 11 | 50 | 13 | | 2 | 0 | 0 | 14 | 15 | -------------------------------------------------------------------------------- /src/test/resources/samples/screenplay_table_based_scenario_with_failures_and_errors.feature: -------------------------------------------------------------------------------- 1 | Feature: Buying things - with tables failures and errors 2 | 3 | Scenario Outline: Buying lots of widgets 4 | Given I want to purchase gizmos 5 | And a gizmo costs $ 6 | When I order the gizmos 7 | Then I should pay $ 8 | Examples: 9 | | amount | cost | total | 10 | | 0 | 10 | 0 | 11 | | 2 | 10 | 50 | 12 | | -1 | 10 | 10 | 13 | | 2 | 0 | 0 | 14 | 15 | -------------------------------------------------------------------------------- /src/test/java/net/serenitybdd/cucumber/integration/SimpleScenarioWithNarrativeTexts.java: -------------------------------------------------------------------------------- 1 | package net.serenitybdd.cucumber.integration; 2 | 3 | import io.cucumber.junit.CucumberOptions; 4 | import net.serenitybdd.cucumber.CucumberWithSerenity; 5 | import org.junit.runner.RunWith; 6 | 7 | /** 8 | * Created by john on 23/07/2014. 9 | */ 10 | @RunWith(CucumberWithSerenity.class) 11 | @CucumberOptions(features="src/test/resources/samples/simple_scenario_with_narrative_text.feature") 12 | public class SimpleScenarioWithNarrativeTexts {} 13 | -------------------------------------------------------------------------------- /src/test/java/net/serenitybdd/cucumber/integration/SimpleTableScenarioWithFailures.java: -------------------------------------------------------------------------------- 1 | package net.serenitybdd.cucumber.integration; 2 | 3 | import io.cucumber.junit.CucumberOptions; 4 | import net.serenitybdd.cucumber.CucumberWithSerenity; 5 | import org.junit.runner.RunWith; 6 | 7 | /** 8 | * Created by john on 23/07/2014. 9 | */ 10 | @RunWith(CucumberWithSerenity.class) 11 | @CucumberOptions(features= "src/test/resources/samples/table_based_scenario_with_failures.feature") 12 | public class SimpleTableScenarioWithFailures { 13 | } 14 | -------------------------------------------------------------------------------- /src/test/resources/samples/data_driven_scenario.feature: -------------------------------------------------------------------------------- 1 | Feature: Buying things - data driven 2 | 3 | Scenario: Buying lots of widgets 4 | Given I want to purchase the following gizmos: 5 | | item | quantity | price | 6 | | A1 | 10 | 10 | 7 | | B2 | 5 | 40 | 8 | | C3 | 60 | 5 | 9 | When I buy the gizmos 10 | Then I should be billed the following for each item: 11 | | item | total | 12 | | A1 | 100 | 13 | | B2 | 200 | 14 | | C3 | 300 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /src/test/resources/samples/tagged_example_tables.feature: -------------------------------------------------------------------------------- 1 | Feature: Tagged Tables 2 | 3 | Scenario Outline: This scenario should have two tables 4 | 5 | Given the number and the number 6 | When plus 7 | Then the result is equals to 8 | 9 | @small 10 | Examples: Small numbers 11 | | a | b | c | 12 | | 1 | 4 | 5 | 13 | | 2 | 7 | 9 | 14 | | 3 | 6 | 9 | 15 | 16 | @big 17 | Examples: Big numbers 18 | | a | b | c | 19 | | 11 | 4 | 15 | 20 | | 12 | 7 | 19 | -------------------------------------------------------------------------------- /src/smoketests/src/test/java/smoketests/WhenRootFolderOfFeaturesAloneProvided.java: -------------------------------------------------------------------------------- 1 | package smoketests; 2 | 3 | import io.cucumber.junit.CucumberOptions; 4 | import io.cucumber.junit.CucumberWithSerenity; 5 | import org.junit.runner.RunWith; 6 | 7 | /** 8 | * Created by Ramanathan Raghunathan on 18/12/2014. 9 | */ 10 | @RunWith(CucumberWithSerenity.class) 11 | @CucumberOptions(features="src/test/resources/features", 12 | glue= {"smoketests.stepdefinitions"},tags = {"@tag_test"}) 13 | public class WhenRootFolderOfFeaturesAloneProvided {} 14 | -------------------------------------------------------------------------------- /src/test/java/net/serenitybdd/cucumber/integration/BasicArithmeticWithTablesScenario.java: -------------------------------------------------------------------------------- 1 | package net.serenitybdd.cucumber.integration; 2 | 3 | import io.cucumber.junit.CucumberOptions; 4 | import net.serenitybdd.cucumber.CucumberWithSerenity; 5 | import org.junit.runner.RunWith; 6 | 7 | /** 8 | * Created by john on 23/07/2014. 9 | */ 10 | @RunWith(CucumberWithSerenity.class) 11 | @CucumberOptions(features="src/test/resources/samples/calculator/basic_arithmetic_with_tables.feature") 12 | public class BasicArithmeticWithTablesScenario {} 13 | -------------------------------------------------------------------------------- /src/test/java/net/serenitybdd/cucumber/integration/steps/thucydides/SomeNormalSteps.java: -------------------------------------------------------------------------------- 1 | package net.serenitybdd.cucumber.integration.steps.thucydides; 2 | 3 | import net.thucydides.core.annotations.Step; 4 | 5 | public class SomeNormalSteps { 6 | 7 | @Step 8 | public void processFirstName(String firstname) { 9 | } 10 | 11 | @Step 12 | public void processSecondName(String lastname) { 13 | } 14 | 15 | @Step 16 | public void checkResults(String expectedFirstname, String expectedLastname) { 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/test/java/net/serenitybdd/cucumber/integration/WhenRunningAnEmptyFeatureFile.java: -------------------------------------------------------------------------------- 1 | package net.serenitybdd.cucumber.integration; 2 | 3 | import io.cucumber.junit.CucumberOptions; 4 | import net.serenitybdd.cucumber.CucumberWithSerenity; 5 | import org.junit.runner.RunWith; 6 | 7 | /** 8 | * Run all of the passing sample scenarios - a quick smoke test 9 | */ 10 | @RunWith(CucumberWithSerenity.class) 11 | @CucumberOptions(features = {"src/test/resources/samples/empty"}, tags = "@shouldPass") 12 | public class WhenRunningAnEmptyFeatureFile { 13 | } -------------------------------------------------------------------------------- /src/smoketests/README.md: -------------------------------------------------------------------------------- 1 | ## Serenity Cucumber Smoke tests 2 | 3 | This sub-project contains a range of self-documenting tests that illustrate Serenity-JBehave features. 4 | 5 | Running the tests as follows should always pass: 6 | ``` 7 | $ mvn clean verify 8 | ``` 9 | or 10 | ``` 11 | $ gradle clean test aggregate 12 | ``` 13 | 14 | Running in the failure mode will intentionally fail with self-documenting errors. 15 | ``` 16 | $ mvn clean verify -PincludingFailures 17 | ``` 18 | or 19 | ``` 20 | gradle clean test aggregate -DincludingFailures 21 | ``` 22 | -------------------------------------------------------------------------------- /src/test/java/net/serenitybdd/cucumber/integration/WhenRunningPassingCucumberSampleTests.java: -------------------------------------------------------------------------------- 1 | package net.serenitybdd.cucumber.integration; 2 | 3 | import io.cucumber.junit.CucumberOptions; 4 | import net.serenitybdd.cucumber.CucumberWithSerenity; 5 | import org.junit.runner.RunWith; 6 | 7 | /** 8 | * Run all of the passing sample scenarios - a quick smoke test 9 | */ 10 | @RunWith(CucumberWithSerenity.class) 11 | @CucumberOptions(features = {"src/test/resources/samples"}, tags = "@shouldPass") 12 | public class WhenRunningPassingCucumberSampleTests { 13 | } -------------------------------------------------------------------------------- /src/test/java/net/serenitybdd/cucumber/integration/SimpleSeleniumTestWithASpecifiedBrowser.java: -------------------------------------------------------------------------------- 1 | package net.serenitybdd.cucumber.integration; 2 | 3 | import io.cucumber.junit.CucumberOptions; 4 | import net.serenitybdd.cucumber.CucumberWithSerenity; 5 | import org.junit.runner.RunWith; 6 | 7 | /** 8 | * Created by lcarausu on 09.08.14. 9 | */ 10 | @RunWith(CucumberWithSerenity.class) 11 | @CucumberOptions(features="src/test/resources/samples/web/aPassingBehaviorWithSeleniumAndFirefox.feature") 12 | public class SimpleSeleniumTestWithASpecifiedBrowser { 13 | } 14 | -------------------------------------------------------------------------------- /src/test/resources/samples/failing_scenario.feature: -------------------------------------------------------------------------------- 1 | Feature: A simple feature that fails 2 | 3 | @shouldFail 4 | Scenario: A simple failing scenario 5 | Given I want to purchase 2 widgets 6 | And a widget costs $5 7 | When I buy the widgets 8 | Then I should be billed $20 9 | And I want to purchase 5 widgets 10 | 11 | Scenario: A simple passing scenario 12 | Given I want to purchase 2 widgets 13 | And a widget costs $5 14 | When I buy the widgets 15 | Then I should be billed $10 16 | And I want to purchase 5 widgets 17 | -------------------------------------------------------------------------------- /src/smoketests/src/test/resources/features/backgrounds/when_using_simple_lifecycle_steps.feature: -------------------------------------------------------------------------------- 1 | Feature: Lifecycle phases can be used to run steps before and after a scenario 2 | 3 | Background: 4 | Given I have a calculator 5 | And I add 1 6 | 7 | @current 8 | @expected-outcome:success 9 | Scenario: A scenario with before and after phases 10 | When I add 2 11 | Then the total should be 3 12 | 13 | @expected-outcome:success 14 | Scenario: Another scenario with before and after phases 15 | When I add 3 16 | Then the total should be 4 -------------------------------------------------------------------------------- /src/test/java/net/serenitybdd/cucumber/integration/ScenarioWithOnlyFeatureFileRootDirectoryPath.java: -------------------------------------------------------------------------------- 1 | package net.serenitybdd.cucumber.integration; 2 | 3 | import io.cucumber.junit.CucumberOptions; 4 | import net.serenitybdd.cucumber.CucumberWithSerenity; 5 | import org.junit.runner.RunWith; 6 | 7 | /** 8 | * Created by Ramanathan Raghunathan on 06/01/2018. 9 | */ 10 | @RunWith(CucumberWithSerenity.class) 11 | @CucumberOptions(features="src/test/resources/features",tags = {"@feature and @example_one"}) 12 | public class ScenarioWithOnlyFeatureFileRootDirectoryPath {} -------------------------------------------------------------------------------- /src/test/java/net/serenitybdd/cucumber/integration/steps/thucydides/SomeNestedSeleniumSteps.java: -------------------------------------------------------------------------------- 1 | package net.serenitybdd.cucumber.integration.steps.thucydides; 2 | 3 | import net.thucydides.core.annotations.Step; 4 | 5 | public class SomeNestedSeleniumSteps { 6 | 7 | StaticSitePage page; 8 | 9 | @Step 10 | public void enters_the_first_name(String firstname) { 11 | page.setFirstName(firstname); 12 | } 13 | 14 | @Step 15 | public void enters_the_last_name(String lastname) { 16 | page.setLastName(lastname); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/test/resources/features/calculator/basic_arithmetic.feature: -------------------------------------------------------------------------------- 1 | @foo 2 | @issue:ISSUE-123 3 | Feature: Basic Arithmetic 4 | Calculing additions 5 | 6 | Background: A Calculator 7 | Given a calculator I just turned on 8 | 9 | @issue:ISSUE-456 10 | Scenario: Addition 11 | # Try to change one of the values below to provoke a failure 12 | When I add 4 and 5 13 | Then the result is 9 14 | 15 | Scenario: Another Addition 16 | # Try to change one of the values below to provoke a failure 17 | When I add 4 and 7 18 | Then the result is 11 19 | -------------------------------------------------------------------------------- /src/test/resources/samples/calculator/basic_arithmetic.feature: -------------------------------------------------------------------------------- 1 | @foo 2 | @issue:ISSUE-123 3 | Feature: Basic Arithmetic 4 | Calculing additions 5 | 6 | Background: A Calculator 7 | Given a calculator I just turned on 8 | 9 | @issue:ISSUE-456 10 | Scenario: Addition 11 | # Try to change one of the values below to provoke a failure 12 | When I add 4 and 5 13 | Then the result is 9 14 | 15 | Scenario: Another Addition 16 | # Try to change one of the values below to provoke a failure 17 | When I add 4 and 7 18 | Then the result is 11 19 | -------------------------------------------------------------------------------- /src/test/java/net/serenitybdd/cucumber/integration/BasicArithmeticWithTablesScenarioWithErrors.java: -------------------------------------------------------------------------------- 1 | package net.serenitybdd.cucumber.integration; 2 | 3 | import io.cucumber.junit.CucumberOptions; 4 | import net.serenitybdd.cucumber.CucumberWithSerenity; 5 | import org.junit.runner.RunWith; 6 | 7 | /** 8 | * Created by john on 23/07/2014. 9 | */ 10 | @RunWith(CucumberWithSerenity.class) 11 | @CucumberOptions(features="src/test/resources/features/calculator/basic_arithmetic_with_tables_and_errors.feature") 12 | public class BasicArithmeticWithTablesScenarioWithErrors {} 13 | -------------------------------------------------------------------------------- /src/test/java/net/serenitybdd/cucumber/integration/RunOnlyFirstExampleTableRows.java: -------------------------------------------------------------------------------- 1 | package net.serenitybdd.cucumber.integration; 2 | 3 | import io.cucumber.junit.CucumberOptions; 4 | import net.serenitybdd.cucumber.CucumberWithSerenity; 5 | import org.junit.runner.RunWith; 6 | 7 | /** 8 | * Created by john on 23/07/2014. 9 | */ 10 | @RunWith(CucumberWithSerenity.class) 11 | @CucumberOptions(features="src/test/resources/features/calculator/basic_arithmetic_with_tables_and_examples_tags.feature",tags = {"@example_one"}) 12 | public class RunOnlyFirstExampleTableRows {} 13 | -------------------------------------------------------------------------------- /src/test/java/net/serenitybdd/cucumber/integration/SimpleScreenplayTableScenarioWithFailures.java: -------------------------------------------------------------------------------- 1 | package net.serenitybdd.cucumber.integration; 2 | 3 | import io.cucumber.junit.CucumberOptions; 4 | import net.serenitybdd.cucumber.CucumberWithSerenity; 5 | import org.junit.runner.RunWith; 6 | 7 | /** 8 | * Created by john on 23/07/2014. 9 | */ 10 | @RunWith(CucumberWithSerenity.class) 11 | @CucumberOptions(features= "src/test/resources/samples/screenplay_table_based_scenario_with_failures.feature") 12 | public class SimpleScreenplayTableScenarioWithFailures { 13 | } 14 | -------------------------------------------------------------------------------- /src/test/resources/samples/web/aPassingBehaviorWithSeleniumAndSeveralScenarios.feature: -------------------------------------------------------------------------------- 1 | @driver:phantomjs 2 | @driver-options:--headless 3 | @UniqueBrowser 4 | Feature: A feature that uses two selenium scenarios 5 | 6 | Scenario: A web scenario that uses selenium 7 | 8 | Given I am on the test page 9 | When I type in the first name Jack 10 | Then I should see first name Jack on the screen 11 | 12 | Scenario: A web scenario that uses selenium v2 13 | 14 | Given I am on the test page 15 | When I type in the first name Jill 16 | Then I should see first name Jill on the screen -------------------------------------------------------------------------------- /src/test/java/net/serenitybdd/cucumber/integration/RunOnlySecondExampleTableRows.java: -------------------------------------------------------------------------------- 1 | package net.serenitybdd.cucumber.integration; 2 | 3 | import io.cucumber.junit.CucumberOptions; 4 | import net.serenitybdd.cucumber.CucumberWithSerenity; 5 | import org.junit.runner.RunWith; 6 | 7 | /** 8 | * Created by john on 23/07/2014. 9 | */ 10 | @RunWith(CucumberWithSerenity.class) 11 | @CucumberOptions(features="src/test/resources/features/calculator/basic_arithmetic_with_tables_and_examples_tags.feature",tags = {"@example_two"}) 12 | public class RunOnlySecondExampleTableRows {} 13 | -------------------------------------------------------------------------------- /src/test/java/net/serenitybdd/cucumber/integration/SimpleScreenplayTableScenarioWithErrors.java: -------------------------------------------------------------------------------- 1 | package net.serenitybdd.cucumber.integration; 2 | 3 | import io.cucumber.junit.CucumberOptions; 4 | import net.serenitybdd.cucumber.CucumberWithSerenity; 5 | import org.junit.runner.RunWith; 6 | 7 | /** 8 | * Created by john on 23/07/2014. 9 | */ 10 | @RunWith(CucumberWithSerenity.class) 11 | @CucumberOptions(features= "src/test/resources/samples/screenplay_table_based_scenario_with_failures_and_errors.feature") 12 | public class SimpleScreenplayTableScenarioWithErrors { 13 | } 14 | -------------------------------------------------------------------------------- /src/test/resources/features/calculator/complex_arithmetic.feature: -------------------------------------------------------------------------------- 1 | @foo 2 | @issue:ISSUE-123 3 | Feature: More complex Arithmetic 4 | Calculing additions 5 | 6 | Background: A Calculator 7 | Given a calculator I just turned on 8 | 9 | @issue:ISSUE-456 10 | Scenario: Addition 11 | # Try to change one of the values below to provoke a failure 12 | When I add 4 and 5 13 | Then the result is 9 14 | 15 | Scenario: Another Addition 16 | # Try to change one of the values below to provoke a failure 17 | When I add 4 and 7 18 | Then the result is 11 19 | -------------------------------------------------------------------------------- /src/smoketests/src/test/resources/features/backgrounds/when_using_lifecycles_with_web_tests.feature: -------------------------------------------------------------------------------- 1 | @driver:htmlunit 2 | Feature: Hooks can be used with web tests as well 3 | 4 | @web 5 | @expected-outcome:success 6 | Scenario: A simple passing scenario 7 | Given I want to search for something 8 | When I lookup pear 9 | Then I should see "pear at DuckDuckGo" in the page title 10 | 11 | Scenario: Another simple passing scenario 12 | Given I want to search for something 13 | When I lookup pear 14 | Then I should see "pear at DuckDuckGo" in the page title -------------------------------------------------------------------------------- /src/test/java/net/serenitybdd/cucumber/integration/BasicArithmeticWithTablesAndBackgroundScenario.java: -------------------------------------------------------------------------------- 1 | package net.serenitybdd.cucumber.integration; 2 | 3 | import io.cucumber.junit.CucumberOptions; 4 | import net.serenitybdd.cucumber.CucumberWithSerenity; 5 | import org.junit.runner.RunWith; 6 | 7 | /** 8 | * Created by john on 23/07/2014. 9 | */ 10 | @RunWith(CucumberWithSerenity.class) 11 | @CucumberOptions(features="src/test/resources/samples/calculator/basic_arithmetic_with_tables_and_background.feature") 12 | public class BasicArithmeticWithTablesAndBackgroundScenario {} 13 | -------------------------------------------------------------------------------- /src/test/resources/samples/multiple_jira_issues.feature: -------------------------------------------------------------------------------- 1 | @foo 2 | @issues:ISSUE-123,ISSUE-789 3 | Feature: Basic Arithmetic 4 | Calculing additions 5 | 6 | Background: A Calculator 7 | Given a calculator I just turned on 8 | 9 | @issues:ISSUE-456,ISSUE-001 10 | Scenario: Addition 11 | # Try to change one of the values below to provoke a failure 12 | When I add 4 and 5 13 | Then the result is 9 14 | 15 | Scenario: Another Addition 16 | # Try to change one of the values below to provoke a failure 17 | When I add 4 and 7 18 | Then the result is 11 19 | -------------------------------------------------------------------------------- /src/test/resources/samples/table_based_scenario_with_failures.feature: -------------------------------------------------------------------------------- 1 | Feature: Buying things - with tables and failures screenplay 2 | 3 | Scenario Outline: Buying lots of widgets 4 | An error is thrown when the cost is negative 5 | 6 | Given I want to purchase widgets 7 | And a widget costs $ 8 | When I buy the widgets 9 | Then I should be billed $ 10 | Examples: 11 | | amount | cost | total | 12 | | 0 | 10 | 0 | 13 | | 1 | -1 | 10 | 14 | | 2 | 10 | 50 | 15 | | 2 | 0 | 0 | 16 | 17 | -------------------------------------------------------------------------------- /src/test/java/net/serenitybdd/cucumber/integration/SimpleScreenplayTableScenarioWithFailuresAndErrors.java: -------------------------------------------------------------------------------- 1 | package net.serenitybdd.cucumber.integration; 2 | 3 | import io.cucumber.junit.CucumberOptions; 4 | import net.serenitybdd.cucumber.CucumberWithSerenity; 5 | import org.junit.runner.RunWith; 6 | 7 | /** 8 | * Created by john on 23/07/2014. 9 | */ 10 | @RunWith(CucumberWithSerenity.class) 11 | @CucumberOptions(features= "src/test/resources/samples/screenplay_table_based_scenario_with_errors.feature") 12 | public class SimpleScreenplayTableScenarioWithFailuresAndErrors { 13 | } 14 | -------------------------------------------------------------------------------- /src/test/java/net/serenitybdd/cucumber/integration/RunAllExamplesThatInheritsFeatureTag.java: -------------------------------------------------------------------------------- 1 | package net.serenitybdd.cucumber.integration; 2 | 3 | import io.cucumber.junit.CucumberOptions; 4 | import net.serenitybdd.cucumber.CucumberWithSerenity; 5 | import org.junit.runner.RunWith; 6 | 7 | /** 8 | * Created by Ramanathan Raghunathan on 18/12/2017. 9 | */ 10 | @RunWith(CucumberWithSerenity.class) 11 | @CucumberOptions(features="src/test/resources/features/calculator/basic_arithmetic_with_tables_and_examples_tags.feature",tags = {"@feature"}) 12 | public class RunAllExamplesThatInheritsFeatureTag {} -------------------------------------------------------------------------------- /src/test/java/net/serenitybdd/cucumber/integration/steps/BrokenStepInstantiationSteps.java: -------------------------------------------------------------------------------- 1 | package net.serenitybdd.cucumber.integration.steps; 2 | 3 | import io.cucumber.java.en.Given; 4 | 5 | 6 | /** 7 | * Created by john on 15/07/2014. 8 | */ 9 | public class BrokenStepInstantiationSteps { 10 | 11 | public BrokenStepInstantiationSteps() throws InstantiationException { 12 | throw new InstantiationException("Oh crap!"); 13 | } 14 | 15 | @Given("I have a step library that fails to instantiate") 16 | public void featureFileContainsStepsFields() { 17 | } 18 | 19 | } 20 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | Copyright 2014 John Ferguson Smart 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this software except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. -------------------------------------------------------------------------------- /src/test/java/net/serenitybdd/cucumber/integration/RunAllExamplesThatInheritsScenarioOutlineTagOnly.java: -------------------------------------------------------------------------------- 1 | package net.serenitybdd.cucumber.integration; 2 | 3 | import io.cucumber.junit.CucumberOptions; 4 | import net.serenitybdd.cucumber.CucumberWithSerenity; 5 | import org.junit.runner.RunWith; 6 | 7 | /** 8 | * Created by john on 23/07/2014. 9 | */ 10 | @RunWith(CucumberWithSerenity.class) 11 | @CucumberOptions(features="src/test/resources/features/calculator/basic_arithmetic_with_tables_and_examples_tags.feature",tags = {"@scenario_outline"}) 12 | public class RunAllExamplesThatInheritsScenarioOutlineTagOnly {} 13 | -------------------------------------------------------------------------------- /src/test/resources/samples/web/aPassingBehaviorWithSelenium.feature: -------------------------------------------------------------------------------- 1 | @driver:htmlunit 2 | Feature: A scenario that uses selenium 3 | 4 | Scenario Outline: A scenario that uses selenium 5 | Given I am on the test page 6 | When I type in the first name 7 | And I type in the last name 8 | Then I should see entered values of and 9 | 10 | Examples: 11 | |firstname|lastname| expectedFirstname | expectedLastname | 12 | |Joe | Blanc | Joe | Blanc | 13 | |John | Doe | John | Doe | 14 | 15 | -------------------------------------------------------------------------------- /src/test/java/net/serenitybdd/cucumber/integration/RunExamplesMatchingFeatureAndExampleTags.java: -------------------------------------------------------------------------------- 1 | package net.serenitybdd.cucumber.integration; 2 | 3 | import io.cucumber.junit.CucumberOptions; 4 | import net.serenitybdd.cucumber.CucumberWithSerenity; 5 | import org.junit.runner.RunWith; 6 | 7 | /** 8 | * Created by Ramanathan Raghunathan on 18/12/2017. 9 | */ 10 | @RunWith(CucumberWithSerenity.class) 11 | @CucumberOptions(features="src/test/resources/features/calculator/basic_arithmetic_with_tables_and_examples_tags.feature",tags = {"@feature and @example_one"}) 12 | public class RunExamplesMatchingFeatureAndExampleTags {} -------------------------------------------------------------------------------- /src/test/java/net/serenitybdd/cucumber/integration/RunExamplesMatchingFeatureOrExampleTags.java: -------------------------------------------------------------------------------- 1 | package net.serenitybdd.cucumber.integration; 2 | 3 | import io.cucumber.junit.CucumberOptions; 4 | import net.serenitybdd.cucumber.CucumberWithSerenity; 5 | import org.junit.runner.RunWith; 6 | 7 | /** 8 | * Created by Ramanathan Raghunathan on 18/12/2017. 9 | */ 10 | @RunWith(CucumberWithSerenity.class) 11 | @CucumberOptions(features="src/test/resources/features/calculator/basic_arithmetic_with_tables_and_examples_tags.feature",tags = {"@feature or @example_one"}) 12 | public class RunExamplesMatchingFeatureOrExampleTags {} -------------------------------------------------------------------------------- /src/test/java/net/serenitybdd/cucumber/suiteslicing/DummyStatsOfWeightingOne.java: -------------------------------------------------------------------------------- 1 | package net.serenitybdd.cucumber.suiteslicing; 2 | 3 | import java.math.BigDecimal; 4 | import java.util.ArrayList; 5 | import java.util.List; 6 | 7 | import static java.math.BigDecimal.ONE; 8 | 9 | public class DummyStatsOfWeightingOne implements TestStatistics { 10 | 11 | @Override 12 | public BigDecimal scenarioWeightFor(String feature, String scenario) { 13 | return ONE; 14 | } 15 | 16 | @Override 17 | public List records() { 18 | return new ArrayList<>(); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/test/resources/samples/web/aFailingBehaviorWithSelenium.feature: -------------------------------------------------------------------------------- 1 | @driver:htmlunit 2 | Feature: A failing scenario that uses selenium 3 | 4 | Scenario Outline: A failing scenario that uses selenium 5 | Given I am on the test page 6 | When I type in the first name 7 | And I type in the last name 8 | Then I should see entered values of and 9 | 10 | Examples: 11 | |firstname|lastname| expectedFirstname | expectedLastname | 12 | |Joe | Blanc | Jack | Black | 13 | |John | Doe | John | Doe | 14 | -------------------------------------------------------------------------------- /src/test/java/net/serenitybdd/cucumber/integration/steps/SimpleExampleSteps.java: -------------------------------------------------------------------------------- 1 | package net.serenitybdd.cucumber.integration.steps; 2 | 3 | import io.cucumber.java.en.Given; 4 | import io.cucumber.java.en.Then; 5 | 6 | 7 | public class SimpleExampleSteps { 8 | 9 | 10 | public SimpleExampleSteps() { 11 | } 12 | 13 | @Given("^I have a Cucumber feature file$") 14 | public void I_have_a_Cucumber_feature_file() throws Throwable { 15 | } 16 | 17 | @Then("^I should obtain a Thucydides report$") 18 | public void I_should_obtain_a_Thucydides_report() throws Throwable { 19 | 20 | } 21 | 22 | } 23 | -------------------------------------------------------------------------------- /src/test/resources/features/calculator/basic_arithmetic_with_tables_and_errors.feature: -------------------------------------------------------------------------------- 1 | @foo 2 | Feature: Basic Arithmetic with tables 3 | In order to do my maths homework 4 | As a maths student 5 | I want to be able to add sums 6 | 7 | Scenario Outline: Many additions 8 | Given a calculator I just turned on 9 | And I enter and 10 | And I press 11 | Then the result is 12 | 13 | Examples: 14 | | a | b | op | c | 15 | | 10 | 20 | + | 30 | 16 | | 20 | 5 | - | 15 | 17 | | 25 | 0 | / | 0 | 18 | | 6 | 9 | * | 42 | 19 | | 2 | 2 | + | 4 | 20 | -------------------------------------------------------------------------------- /src/test/java/net/serenitybdd/cucumber/integration/steps/thucydides/SampleWebSteps.java: -------------------------------------------------------------------------------- 1 | package net.serenitybdd.cucumber.integration.steps.thucydides; 2 | 3 | import net.thucydides.core.annotations.Step; 4 | import net.thucydides.core.pages.Pages; 5 | import net.thucydides.core.steps.ScenarioSteps; 6 | 7 | /** 8 | * Created by john on 15/07/2014. 9 | */ 10 | public class SampleWebSteps extends ScenarioSteps { 11 | 12 | 13 | public SampleWebSteps(Pages pages) { 14 | super(pages); 15 | } 16 | 17 | @Step 18 | public void aSimpleStep() { } 19 | 20 | @Step 21 | public void anotherSimpleStep() {} 22 | } 23 | -------------------------------------------------------------------------------- /src/test/java/net/serenitybdd/cucumber/integration/RunExamplesMatchingFeatureTagButNotAnExampleTag.java: -------------------------------------------------------------------------------- 1 | package net.serenitybdd.cucumber.integration; 2 | 3 | import io.cucumber.junit.CucumberOptions; 4 | import net.serenitybdd.cucumber.CucumberWithSerenity; 5 | import org.junit.runner.RunWith; 6 | 7 | /** 8 | * Created by Ramanathan Raghunathan on 18/12/2017. 9 | */ 10 | @RunWith(CucumberWithSerenity.class) 11 | @CucumberOptions(features="src/test/resources/features/calculator/basic_arithmetic_with_tables_and_examples_tags.feature",tags = {"@feature and not @example_two"}) 12 | public class RunExamplesMatchingFeatureTagButNotAnExampleTag {} -------------------------------------------------------------------------------- /src/test/java/net/serenitybdd/cucumber/integration/RunExamplesMatchingFeatureLevelAndOutlineLevelTags.java: -------------------------------------------------------------------------------- 1 | package net.serenitybdd.cucumber.integration; 2 | 3 | import io.cucumber.junit.CucumberOptions; 4 | import net.serenitybdd.cucumber.CucumberWithSerenity; 5 | import org.junit.runner.RunWith; 6 | 7 | /** 8 | * Created by Ramanathan Raghunathan on 18/12/2017. 9 | */ 10 | @RunWith(CucumberWithSerenity.class) 11 | @CucumberOptions(features="src/test/resources/features/calculator/basic_arithmetic_with_tables_and_examples_tags.feature",tags = {"@feature and @scenario_outline"}) 12 | public class RunExamplesMatchingFeatureLevelAndOutlineLevelTags {} -------------------------------------------------------------------------------- /src/test/java/net/serenitybdd/cucumber/integration/RunExamplesMatchingFeatureLevelOrOutlineLevelTags.java: -------------------------------------------------------------------------------- 1 | package net.serenitybdd.cucumber.integration; 2 | 3 | import io.cucumber.junit.CucumberOptions; 4 | import net.serenitybdd.cucumber.CucumberWithSerenity; 5 | import org.junit.runner.RunWith; 6 | 7 | /** 8 | * Created by Ramanathan Raghunathan on 18/12/2017. 9 | */ 10 | @RunWith(CucumberWithSerenity.class) 11 | @CucumberOptions(features="src/test/resources/features/calculator/basic_arithmetic_with_tables_and_examples_tags.feature",tags = {"@feature or @scenario_outline"}) 12 | public class RunExamplesMatchingFeatureLevelOrOutlineLevelTags {} -------------------------------------------------------------------------------- /src/test/resources/samples/feature_pending_tag.feature: -------------------------------------------------------------------------------- 1 | @pending 2 | Feature: A feature with pending scenarios 3 | 4 | Scenario: Simple scenario 1 5 | Given I want to purchase 2 widgets 6 | And a widget costs $5 7 | When I buy the widgets 8 | Then I should be billed $10 9 | 10 | Scenario: Simple scenario 2 11 | Given I want to purchase 4 widgets 12 | And a widget costs $3 13 | When I buy the widgets 14 | Then I should be billed $12 15 | 16 | Scenario: Simple scenario 3 17 | Given I want to purchase 5 widgets 18 | And a widget costs $3 19 | When I buy the widgets 20 | Then I should be billed $15 -------------------------------------------------------------------------------- /src/test/resources/samples/scenarios_skipped_tag.feature: -------------------------------------------------------------------------------- 1 | Feature: A feature with multiple scenarios 2 | 3 | Scenario: Simple scenario 1 4 | Given I want to purchase 2 widgets 5 | And a widget costs $5 6 | When I buy the widgets 7 | Then I should be billed $10 8 | 9 | @wip 10 | Scenario: Simple scenario 2 11 | Given I want to purchase 4 widgets 12 | And a widget costs $3 13 | When I buy the widgets 14 | Then I should be billed $12 15 | 16 | Scenario: Simple scenario 3 17 | Given I want to purchase 5 widgets 18 | And a widget costs $3 19 | When I buy the widgets 20 | Then I should be billed $15 -------------------------------------------------------------------------------- /src/smoketests/src/test/java/smoketests/WhenUsingScenarioOutlineAndTagsAtAllLevels.java: -------------------------------------------------------------------------------- 1 | package smoketests; 2 | 3 | import io.cucumber.junit.CucumberOptions; 4 | import io.cucumber.junit.CucumberWithSerenity; 5 | import org.junit.runner.RunWith; 6 | 7 | /** 8 | * Created by Ramanathan Raghunathan on 18/12/2014. 9 | */ 10 | @RunWith(CucumberWithSerenity.class) 11 | @CucumberOptions(features="src/test/resources/features/tags_and_report/serenity_report_when_using_tags_at_all_level.feature", 12 | glue= {"smoketests.stepdefinitions"},tags = {"(@tag_test or @doing_maths) and @single_red"}) 13 | public class WhenUsingScenarioOutlineAndTagsAtAllLevels {} 14 | -------------------------------------------------------------------------------- /src/test/resources/samples/scenarios_pending_tag.feature: -------------------------------------------------------------------------------- 1 | Feature: A feature with pending scenarios 2 | 3 | Scenario: Simple scenario 1 4 | Given I want to purchase 2 widgets 5 | And a widget costs $5 6 | When I buy the widgets 7 | Then I should be billed $10 8 | 9 | @pending 10 | Scenario: Simple scenario 2 11 | Given I want to purchase 4 widgets 12 | And a widget costs $3 13 | When I buy the widgets 14 | Then I should be billed $12 15 | 16 | Scenario: Simple scenario 3 17 | Given I want to purchase 5 widgets 18 | And a widget costs $3 19 | When I buy the widgets 20 | Then I should be billed $15 -------------------------------------------------------------------------------- /src/test/java/net/serenitybdd/cucumber/integration/RunExampleMatchingBothScenarioOutlineAndSecondExampleTagOnly.java: -------------------------------------------------------------------------------- 1 | package net.serenitybdd.cucumber.integration; 2 | 3 | import io.cucumber.junit.CucumberOptions; 4 | import net.serenitybdd.cucumber.CucumberWithSerenity; 5 | import org.junit.runner.RunWith; 6 | 7 | /** 8 | * Created by john on 23/07/2014. 9 | */ 10 | @RunWith(CucumberWithSerenity.class) 11 | @CucumberOptions(features="src/test/resources/features/calculator/basic_arithmetic_with_tables_and_examples_tags.feature",tags = {"@scenario_outline and @example_two"}) 12 | public class RunExampleMatchingBothScenarioOutlineAndSecondExampleTagOnly {} 13 | -------------------------------------------------------------------------------- /src/main/java/net/serenitybdd/cucumber/suiteslicing/SliceBuilder.java: -------------------------------------------------------------------------------- 1 | package net.serenitybdd.cucumber.suiteslicing; 2 | 3 | public class SliceBuilder { 4 | 5 | private int sliceNumber; 6 | private WeightedCucumberScenarios weightedCucumberScenarios; 7 | 8 | public SliceBuilder(int sliceNumber, WeightedCucumberScenarios weightedCucumberScenarios) { 9 | this.sliceNumber = sliceNumber; 10 | this.weightedCucumberScenarios = weightedCucumberScenarios; 11 | } 12 | 13 | public WeightedCucumberScenarios of(int sliceCount) { 14 | return weightedCucumberScenarios.sliceInto(sliceCount).get(sliceNumber - 1); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/test/resources/samples/web/aBehaviorWithSeleniumUsingADifferentBrowser.feature: -------------------------------------------------------------------------------- 1 | @driver:htmlunit 2 | Feature: Use other browser 3 | 4 | Scenario Outline: A scenario that uses selenium 5 | 6 | Given I am on the test page 7 | When I type in the first name 8 | And I type in the last name 9 | Then I should see entered values of and 10 | And I should be using HtmlUnit 11 | 12 | Examples: 13 | |firstname|lastname| expectedFirstname | expectedLastname | 14 | |Joe | Blanc | Joe | Blanc | 15 | |John | Doe | John | Doe | -------------------------------------------------------------------------------- /src/smoketests/src/test/java/smoketests/SlicedTestRunner2.java: -------------------------------------------------------------------------------- 1 | package smoketests; 2 | 3 | import io.cucumber.junit.CucumberOptions; 4 | import io.cucumber.junit.CucumberWithSerenity; 5 | import org.junit.runner.RunWith; 6 | 7 | @RunWith(CucumberWithSerenity.class) 8 | @CucumberOptions(glue = "smoketests.stepdefinitions", features = "classpath:features") 9 | public class SlicedTestRunner2 { 10 | 11 | /* 12 | 13 | This is test runner is automatically used when the suite is run using the maven profile useTheForks 14 | See SlicedTestRunner.java or full documentation on https://serenity-bdd.github.io/theserenitybook/0.1.0/serenity-parallel.html 15 | 16 | */ 17 | 18 | } 19 | -------------------------------------------------------------------------------- /src/test/java/net/serenitybdd/cucumber/integration/RunExamplesMatchingExampleOrScenarioOutlineTagAndAnExampleTag.java: -------------------------------------------------------------------------------- 1 | package net.serenitybdd.cucumber.integration; 2 | 3 | import io.cucumber.junit.CucumberOptions; 4 | import net.serenitybdd.cucumber.CucumberWithSerenity; 5 | import org.junit.runner.RunWith; 6 | 7 | /** 8 | * Created by Ramanathan Raghunathan on 18/12/2017. 9 | */ 10 | @RunWith(CucumberWithSerenity.class) 11 | @CucumberOptions(features="src/test/resources/features/calculator/basic_arithmetic_with_tables_and_examples_tags.feature",tags = {"(@feature or @scenario_outline) and @example_two"}) 12 | public class RunExamplesMatchingExampleOrScenarioOutlineTagAndAnExampleTag {} -------------------------------------------------------------------------------- /src/smoketests/src/test/java/smoketests/SlicedTestRunner3.java: -------------------------------------------------------------------------------- 1 | package smoketests; 2 | 3 | import io.cucumber.junit.CucumberOptions; 4 | import io.cucumber.junit.CucumberWithSerenity; 5 | import org.junit.runner.RunWith; 6 | 7 | @RunWith(CucumberWithSerenity.class) 8 | @CucumberOptions(glue = "smoketests.stepdefinitions", features="classpath:features") 9 | public class SlicedTestRunner3 { 10 | 11 | /* 12 | 13 | This is test runner is automatically used when the suite is run using the maven profile useTheForks 14 | See SlicedTestRunner.java or full documentation on https://serenity-bdd.github.io/theserenitybook/0.1.0/serenity-parallel.html 15 | 16 | */ 17 | 18 | 19 | } 20 | -------------------------------------------------------------------------------- /src/smoketests/src/test/java/smoketests/SlicedTestRunner4.java: -------------------------------------------------------------------------------- 1 | package smoketests; 2 | 3 | import io.cucumber.junit.CucumberOptions; 4 | import io.cucumber.junit.CucumberWithSerenity; 5 | import org.junit.runner.RunWith; 6 | 7 | @RunWith(CucumberWithSerenity.class) 8 | @CucumberOptions(glue = "smoketests.stepdefinitions", features = "classpath:features") 9 | public class SlicedTestRunner4 { 10 | 11 | /* 12 | 13 | This is test runner is automatically used when the suite is run using the maven profile useTheForks 14 | See SlicedTestRunner.java or full documentation on https://serenity-bdd.github.io/theserenitybook/0.1.0/serenity-parallel.html 15 | 16 | */ 17 | 18 | 19 | } 20 | -------------------------------------------------------------------------------- /src/smoketests/src/test/resources/features/tags_and_report/serenity_report_when_using_tags_at_all_level.feature: -------------------------------------------------------------------------------- 1 | @tag_test 2 | Feature: Serenity automatically instantiates step libraries 3 | 4 | 5 | @doing_maths 6 | Scenario Outline: Doing more maths 7 | Given I have a calculator 8 | When I add 9 | And I add 10 | Then the total should be 11 | 12 | @single_red 13 | Examples: Single digits 14 | | a | b | c | 15 | | 1 | 1 | 2 | 16 | | 1 | 2 | 3 | 17 | | 2 | 3 | 5 | 18 | 19 | @double_blue 20 | Examples: Double digits 21 | | a | b | c | 22 | | 10 | 1 | 11 | 23 | | 10 | 2 | 12 | 24 | | 20 | 3 | 23 | -------------------------------------------------------------------------------- /src/test/java/net/serenitybdd/cucumber/integration/RunExamplesMatchingExampleOrScenarioOutlineTagButNotAnExampleTag.java: -------------------------------------------------------------------------------- 1 | package net.serenitybdd.cucumber.integration; 2 | 3 | import io.cucumber.junit.CucumberOptions; 4 | import net.serenitybdd.cucumber.CucumberWithSerenity; 5 | import org.junit.runner.RunWith; 6 | 7 | /** 8 | * Created by Ramanathan Raghunathan on 18/12/2017. 9 | */ 10 | @RunWith(CucumberWithSerenity.class) 11 | @CucumberOptions(features="src/test/resources/features/calculator/basic_arithmetic_with_tables_and_examples_tags.feature",tags = {"(@feature or @scenario_outline) and not @example_one"}) 12 | public class RunExamplesMatchingExampleOrScenarioOutlineTagButNotAnExampleTag {} -------------------------------------------------------------------------------- /src/test/resources/samples/web/aPassingBehaviorWithSeleniumAndFirefox.feature: -------------------------------------------------------------------------------- 1 | @driver:htmlunit 2 | @driver-options:--headless 3 | Feature: A scenario that uses selenium 4 | 5 | @UniqueBrowser 6 | Scenario Outline: A scenario that uses selenium 7 | 8 | Given I am on the test page 9 | When I type in the first name 10 | And I type in the last name 11 | Then I should see entered values of and 12 | 13 | Examples: 14 | | firstname | lastname | expectedFirstname | expectedLastname | 15 | | Joe | Blanc | Joe | Blanc | 16 | | John | Doe | John | Doe | -------------------------------------------------------------------------------- /src/test/resources/samples/web/failingAndPassingBehaviorsWithSelenium.feature: -------------------------------------------------------------------------------- 1 | @driver:phantomjs 2 | @driver-options:--headless 3 | Feature: Failing and Passing Behaviors With Selenium 4 | 5 | Scenario: A failing scenario that uses selenium 6 | 7 | Given I am on the test page 8 | When I enter a first name Joe 9 | And I enter a last name Smith 10 | Then I should see first name Joe on the screen 11 | Then I should see last name Black on the screen 12 | 13 | Scenario: A passing scenario that uses selenium 14 | 15 | Given I am on the test page 16 | When I enter a first name Joe 17 | And I enter a last name Smith 18 | Then I should see first name Joe on the screen 19 | Then I should see last name Smith on the screen 20 | -------------------------------------------------------------------------------- /src/test/java/net/serenitybdd/cucumber/integration/steps/thucydides/CheckValuesStep.java: -------------------------------------------------------------------------------- 1 | package net.serenitybdd.cucumber.integration.steps.thucydides; 2 | 3 | import net.thucydides.core.annotations.Step; 4 | import net.thucydides.core.annotations.Steps; 5 | 6 | public class CheckValuesStep { 7 | String firstname; 8 | String lastname; 9 | String expectedFirstname; 10 | String expectedLastname; 11 | 12 | @Steps 13 | SomeNormalSteps normalSteps; 14 | 15 | @Step 16 | public void checkValues() { 17 | normalSteps.processFirstName(firstname); 18 | normalSteps.processSecondName(lastname); 19 | normalSteps.checkResults(expectedFirstname, expectedLastname); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/test/resources/samples/web/lookupAScenarioSuite.feature: -------------------------------------------------------------------------------- 1 | @driver:htmlunit 2 | @driver-options:--headless 3 | Feature: Looking up a scenario suite 4 | 5 | Scenario: Looking up the definition of 'apple' 6 | GivenStories: stories/precondition/aPreconditionToLookUpADefinition.story 7 | When the user looks up the definition of the word 'apple' 8 | Then they should see the definition 'A common, round fruit produced by the tree Malus domestica, cultivated in temperate climates.' 9 | 10 | 11 | Scenario: Looking up the definition of 'pear' 12 | GivenStories: stories/precondition/aPreconditionToLookUpADefinition.story 13 | When the user looks up the definition of the word 'pear' 14 | Then they should see the definition 'A common, round fruit produced by the tree Malus domestica, cultivated in temperate climates.' -------------------------------------------------------------------------------- /src/test/java/net/serenitybdd/cucumber/util/SampleStepDefinitions.java: -------------------------------------------------------------------------------- 1 | package net.serenitybdd.cucumber.util; 2 | 3 | import io.cucumber.java.en.Given; 4 | import net.thucydides.core.annotations.Screenshots; 5 | 6 | public class SampleStepDefinitions { 7 | 8 | @Given("some precondition") 9 | public void aStepDefinitionWithNoScreenshotAnnotation() {} 10 | 11 | @Given("some precondition") 12 | @Screenshots(disabled = true) 13 | public void aStepDefinitionWithAScreenshotAnnotation() {} 14 | 15 | @Given("some precondition") 16 | @Screenshots(disabled = true) 17 | public void aStepDefinitionWithAParameter(String parameter) {} 18 | 19 | @Given("some precondition") 20 | @Screenshots 21 | public void aStepDefinitionWithAScreenshotAnnotationWithNoAttribute() {} 22 | 23 | 24 | } 25 | -------------------------------------------------------------------------------- /src/test/resources/features/calculator/basic_arithmetic_with_tables.feature: -------------------------------------------------------------------------------- 1 | @foo 2 | Feature: Basic Arithmetic with tables 3 | In order to do my maths homework 4 | As a maths student 5 | I want to be able to add sums 6 | 7 | 8 | Scenario Outline: Many additions 9 | Given a calculator I just turned on 10 | And the previous entries: 11 | | first | second | operation | 12 | | 1 | 1 | + | 13 | | 2 | 1 | + | 14 | When I press + 15 | And I add and 16 | And I press + 17 | Then the result is 18 | 19 | Examples: Single digits 20 | With just one digit 21 | | a | b | c | 22 | | 1 | 2 | 8 | 23 | | 2 | 3 | 10 | 24 | 25 | Examples: Double digits 26 | With more digits than one 27 | | a | b | c | 28 | | 10 | 20 | 35 | 29 | | 20 | 30 | 55 | 30 | | 25 | 35 | 65 | 31 | -------------------------------------------------------------------------------- /src/test/resources/net/serenitybdd/cucumber/integration/instantiating_thucyides_annotated_fields.feature: -------------------------------------------------------------------------------- 1 | Feature: Using Cucumber with Thucydides 2 | 3 | Scenario: Instantiating Thucydides step fields 4 | Given I have a Cucumber feature file containing Thucydides @Steps fields 5 | When I run it using Thucydides 6 | Then the step fields should be instantiated 7 | 8 | Scenario: Instantiating web-enabled Thucydides step fields 9 | Given I have a Cucumber feature file containing a web-enabled Thucydides @Steps fields 10 | When I run it using Thucydides 11 | Then the web-enabled step fields should be instantiated 12 | 13 | Scenario: Instantiating Thucydides Page Objects 14 | Given I have a Cucumber feature file containing Thucydides @Steps fields 15 | When I run it using Thucydides 16 | Then the nested pages objects should be instantiated 17 | 18 | -------------------------------------------------------------------------------- /src/test/resources/samples/calculator/basic_arithmetic_with_tables.feature: -------------------------------------------------------------------------------- 1 | @foo 2 | Feature: Basic Arithmetic with several tables 3 | In order to do my maths homework 4 | As a maths student 5 | I want to be able to add sums 6 | 7 | Scenario Outline: Many additions 8 | Given a calculator I just turned on 9 | And the previous entries: 10 | | first | second | operation | 11 | | 1 | 1 | + | 12 | | 2 | 1 | + | 13 | When I press + 14 | And I add and 15 | And I press + 16 | Then the result is 17 | 18 | Examples: Single digits 19 | With just one digit 20 | | a | b | c | 21 | | 1 | 2 | 8 | 22 | | 2 | 3 | 10 | 23 | 24 | Examples: Double digits 25 | With more digits than one 26 | | a | b | c | 27 | | 10 | 20 | 35 | 28 | | 20 | 30 | 55 | 29 | | 25 | 35 | 65 | 30 | -------------------------------------------------------------------------------- /src/main/java/io/cucumber/junit/FeatureRunnerExtractors.java: -------------------------------------------------------------------------------- 1 | package io.cucumber.junit; 2 | 3 | import org.junit.runners.ParentRunner; 4 | 5 | import java.lang.reflect.Field; 6 | 7 | 8 | public class FeatureRunnerExtractors { 9 | 10 | public static String extractFeatureName(ParentRunner runner) { 11 | String displayName = runner.getDescription().getDisplayName(); 12 | return displayName.substring(displayName.indexOf(":") + 1).trim(); 13 | } 14 | 15 | public static String featurePathFor(ParentRunner featureRunner) { 16 | try { 17 | Field field = featureRunner.getDescription().getClass().getDeclaredField("fUniqueId"); 18 | field.setAccessible(true); 19 | return field.get(featureRunner.getDescription()).toString(); 20 | } catch (Exception e) { 21 | throw new RuntimeException(e); 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/test/resources/features/calculator/basic_arithmetic_with_tables_and_background.feature: -------------------------------------------------------------------------------- 1 | @foo 2 | Feature: Basic Arithmetic with background features 3 | Calculing additions 4 | 5 | Background: A Calculator 6 | The calculator should be set up and all that 7 | Given a calculator I just turned on 8 | Given the previous entries: 9 | | first | second | operation | 10 | | 1 | 1 | + | 11 | | 2 | 1 | + | 12 | 13 | Scenario Outline: Many additions 14 | When I press + 15 | And I add and 16 | And I press + 17 | Then the result is 18 | 19 | Examples: Single digits 20 | With just one digit 21 | | a | b | c | 22 | | 1 | 2 | 8 | 23 | | 2 | 3 | 10 | 24 | 25 | Examples: Double digits 26 | With more digits than one 27 | | a | b | c | 28 | | 10 | 20 | 35 | 29 | | 20 | 30 | 55 | 30 | | 25 | 35 | 65 | 31 | -------------------------------------------------------------------------------- /src/test/resources/samples/calculator/basic_arithmetic_with_tables_and_background.feature: -------------------------------------------------------------------------------- 1 | @foo 2 | Feature: Basic Arithmetic with more complex tables 3 | Calculing additions 4 | 5 | Background: A Calculator 6 | The calculator should be set up and all that 7 | Given a calculator I just turned on 8 | Given the previous entries: 9 | | first | second | operation | 10 | | 1 | 1 | + | 11 | | 2 | 1 | + | 12 | 13 | Scenario Outline: Many additions 14 | When I press + 15 | And I add and 16 | And I press + 17 | Then the result is 18 | 19 | Examples: Single digits 20 | With just one digit 21 | | a | b | c | 22 | | 1 | 2 | 8 | 23 | | 2 | 3 | 10 | 24 | 25 | Examples: Double digits 26 | With more digits than one 27 | | a | b | c | 28 | | 10 | 20 | 35 | 29 | | 20 | 30 | 55 | 30 | | 25 | 35 | 65 | 31 | -------------------------------------------------------------------------------- /src/test/resources/features/calculator/basic_arithmetic_with_tables_and_examples_tags.feature: -------------------------------------------------------------------------------- 1 | @feature 2 | Feature: Basic Arithmetic with tables 3 | In order to do my maths homework 4 | As a maths student 5 | I want to be able to add sums 6 | 7 | @scenario_outline 8 | Scenario Outline: Many additions 9 | Given a calculator I just turned on 10 | And the previous entries: 11 | | first | second | operation | 12 | | 1 | 1 | + | 13 | | 2 | 1 | + | 14 | When I press + 15 | And I add and 16 | And I press + 17 | Then the result is 18 | 19 | @example_one 20 | Examples: Single digits 21 | With just one digit 22 | | a | b | c | 23 | | 1 | 2 | 8 | 24 | | 2 | 3 | 10 | 25 | 26 | @example_two 27 | Examples: Double digits 28 | With more digits than one 29 | | a | b | c | 30 | | 10 | 20 | 35 | 31 | | 20 | 30 | 55 | 32 | | 25 | 35 | 65 | 33 | -------------------------------------------------------------------------------- /src/test/java/net/serenitybdd/cucumber/integration/steps/WebEnabledStepInstantiationSteps.java: -------------------------------------------------------------------------------- 1 | package net.serenitybdd.cucumber.integration.steps; 2 | 3 | import io.cucumber.java.en.Given; 4 | import io.cucumber.java.en.Then; 5 | import net.serenitybdd.cucumber.integration.steps.thucydides.SampleWebSteps; 6 | import net.thucydides.core.annotations.Steps; 7 | 8 | import static org.assertj.core.api.Assertions.assertThat; 9 | 10 | ; 11 | 12 | /** 13 | * Created by john on 15/07/2014. 14 | */ 15 | public class WebEnabledStepInstantiationSteps { 16 | 17 | @Steps 18 | SampleWebSteps sampleSteps; 19 | 20 | @Given("I have a Cucumber feature file containing a web-enabled Thucydides @Steps field") 21 | public void featureFileContainsStepsFields() { 22 | } 23 | 24 | @Then("the web-enabled step fields should be instantiated") 25 | public void theStepFieldsShouldBeInstantiated() { 26 | assertThat(sampleSteps).isNotNull(); 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/net/serenitybdd/cucumber/suiteslicing/TestStatistics.java: -------------------------------------------------------------------------------- 1 | package net.serenitybdd.cucumber.suiteslicing; 2 | 3 | import net.thucydides.core.util.EnvironmentVariables; 4 | 5 | import java.math.BigDecimal; 6 | import java.net.URI; 7 | import java.util.List; 8 | 9 | import static net.thucydides.core.ThucydidesSystemProperty.SERENITY_TEST_STATISTICS_DIR; 10 | 11 | public interface TestStatistics { 12 | 13 | BigDecimal scenarioWeightFor(String feature, String scenario); 14 | 15 | List records(); 16 | 17 | 18 | public static TestStatistics from(EnvironmentVariables environmentVariables, List featurePaths) { 19 | String directory = environmentVariables.getProperty(SERENITY_TEST_STATISTICS_DIR); 20 | if (directory == null) { 21 | return ScenarioLineCountStatistics.fromFeaturePaths(featurePaths); 22 | } else { 23 | return MultiRunTestStatistics.fromRelativePath(directory); 24 | } 25 | } 26 | 27 | 28 | } 29 | -------------------------------------------------------------------------------- /src/test/java/net/serenitybdd/cucumber/integration/steps/thucydides/SomeNonWebDataDrivenSteps.java: -------------------------------------------------------------------------------- 1 | package net.serenitybdd.cucumber.integration.steps.thucydides; 2 | 3 | import io.cucumber.java.en.Given; 4 | import io.cucumber.java.en.Then; 5 | import io.cucumber.java.en.When; 6 | import net.thucydides.core.annotations.Steps; 7 | 8 | import java.io.IOException; 9 | 10 | import static net.thucydides.core.steps.stepdata.StepData.withTestDataFrom; 11 | 12 | public class SomeNonWebDataDrivenSteps { 13 | 14 | @Steps 15 | CheckValuesStep checkValueSteps; 16 | 17 | String dataSource; 18 | 19 | @Given("^the data in (.*)$") 20 | public void givenTheNamesIn(String dataSource) { 21 | this.dataSource = dataSource; 22 | } 23 | 24 | @When("^we enter this data$") 25 | public void whenWeEnterThisData() {} 26 | 27 | @Then("^the values should be correct$") 28 | public void thenTheValuesShouldBeCorrect() throws IOException { 29 | withTestDataFrom(dataSource).run(checkValueSteps).checkValues(); 30 | } 31 | 32 | } 33 | -------------------------------------------------------------------------------- /src/test/java/net/serenitybdd/cucumber/integration/steps/IllegalStepInstantiationSteps.java: -------------------------------------------------------------------------------- 1 | package net.serenitybdd.cucumber.integration.steps; 2 | 3 | import io.cucumber.java.en.Given; 4 | import io.cucumber.java.en.Then; 5 | import net.serenitybdd.cucumber.integration.steps.thucydides.SampleSteps; 6 | import net.thucydides.core.annotations.Steps; 7 | 8 | import static org.assertj.core.api.Assertions.assertThat; 9 | 10 | ; 11 | 12 | /** 13 | * Created by john on 15/07/2014. 14 | */ 15 | public class IllegalStepInstantiationSteps { 16 | 17 | @Steps 18 | SampleSteps sampleSteps; 19 | 20 | public IllegalStepInstantiationSteps(SampleSteps sampleSteps) { 21 | this.sampleSteps = sampleSteps; 22 | } 23 | 24 | @Given("I have a step library without a default constructor") 25 | public void featureFileContainsStepsFields() { 26 | } 27 | 28 | @Then("the tests should fail with an exception") 29 | public void thePageObjectsShouldBeInstantiated() { 30 | assertThat(sampleSteps.pageObject).isNotNull(); 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /src/smoketests/build.gradle: -------------------------------------------------------------------------------- 1 | repositories { 2 | jcenter() 3 | mavenLocal() 4 | } 5 | 6 | buildscript { 7 | repositories { 8 | mavenLocal() 9 | jcenter() 10 | } 11 | dependencies { 12 | classpath("net.serenity-bdd:serenity-gradle-plugin:${serenityCoreVersion}") 13 | } 14 | } 15 | 16 | apply plugin: 'java' 17 | apply plugin: 'eclipse' 18 | apply plugin: 'idea' 19 | apply plugin: 'net.serenity-bdd.aggregator' 20 | 21 | sourceCompatibility = 1.8 22 | targetCompatibility = 1.8 23 | 24 | dependencies { 25 | compile "net.serenity-bdd:serenity-core:${serenityCoreVersion}" 26 | compile "net.serenity-bdd:serenity-cucumber:${serenityCucumberVersion}" 27 | testCompile("junit:junit:${junitVersion}") 28 | compile("org.assertj:assertj-core:${assertjVersion}") 29 | compile("org.slf4j:slf4j-simple:${slf4jVersion}") 30 | compile 'junit:junit:4.12' 31 | } 32 | 33 | test { 34 | testLogging.showStandardStreams = true 35 | systemProperties System.getProperties() 36 | } 37 | 38 | gradle.startParameter.continueOnFailure = true 39 | -------------------------------------------------------------------------------- /src/smoketests/src/test/resources/features/skipped_pending_and_manual_scenarios/when_declaring_manual_scenarios.feature: -------------------------------------------------------------------------------- 1 | Feature: Marking scenarios as 'manual' using metadata 2 | 3 | @expected-outcome:pending 4 | @manual 5 | Scenario: A manual scenario 6 | Given I want to indicate that a scenario should be performed manually 7 | When I tag it as @manual 8 | Then it should be reported as manual pending 9 | 10 | @expected-outcome:skip 11 | @manual 12 | @skip 13 | Scenario: A skipped manual scenario 14 | Given I want to indicate that a scenario should be performed manually 15 | And I also want it appearing in the skipped scenarios 16 | When I tag it as @manual and @skipped 17 | Then it should be reported as manual skipped 18 | 19 | 20 | @expected-outcome:pending 21 | @manual 22 | Scenario: A manual scenario scenario with undefined steps 23 | Given I want to indicate that a scenario should be performed manually 24 | When I tag it as @manual 25 | And the steps are undefined 26 | Then it should be reported as manual pending 27 | 28 | -------------------------------------------------------------------------------- /src/test/resources/samples/simple_table_based_scenario.feature: -------------------------------------------------------------------------------- 1 | Feature: Buying things - with tables 2 | 3 | Background: I already have some cash 4 | Given I have $100 5 | 6 | @shouldPass 7 | Scenario Outline: Buying lots of widgets 8 | Given I want to purchase widgets 9 | And a widget costs $ 10 | When I buy the widgets 11 | Then I should be billed $ 12 | Examples: 13 | | amount | cost | total | 14 | | 0 | 10 | 0 | 15 | | 1 | 10 | 10 | 16 | | 2 | 10 | 20 | 17 | | 3 | 10 | 30 | 18 | | 4 | 0 | 0 | 19 | 20 | Examples: 21 | | amount | cost | total | 22 | | 50 | 10 | 500 | 23 | | 60 | 10 | 600 | 24 | 25 | Scenario Outline: Buying more widgets 26 | Given I want to purchase widgets 27 | And a widget costs $ 28 | When I buy the widgets 29 | Then I should be billed $ 30 | Examples: 31 | | amount | cost | total | 32 | | 6 | 10 | 0 | 33 | | 8 | 10 | 80 | 34 | | 10 | 10 | 100 | 35 | -------------------------------------------------------------------------------- /src/test/java/net/serenitybdd/cucumber/integration/steps/StepInstantiationSteps.java: -------------------------------------------------------------------------------- 1 | package net.serenitybdd.cucumber.integration.steps; 2 | 3 | import io.cucumber.java.en.Given; 4 | import io.cucumber.java.en.Then; 5 | import net.serenitybdd.cucumber.integration.steps.thucydides.SampleSteps; 6 | import net.thucydides.core.annotations.Steps; 7 | 8 | import static org.assertj.core.api.Assertions.assertThat; 9 | 10 | ; 11 | 12 | /** 13 | * Created by john on 15/07/2014. 14 | */ 15 | public class StepInstantiationSteps { 16 | 17 | @Steps 18 | SampleSteps sampleSteps; 19 | 20 | @Given("I have a Cucumber feature file containing Thucydides @Steps fields") 21 | public void featureFileContainsStepsFields() { 22 | } 23 | 24 | @Then("the step fields should be instantiated") 25 | public void theStepFieldsShouldBeInstantiated() { 26 | assertThat(sampleSteps).isNotNull(); 27 | } 28 | 29 | @Then("the nested pages objects should be instantiated") 30 | public void thePageObjectsShouldBeInstantiated() { 31 | assertThat(sampleSteps.pageObject).isNotNull(); 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /src/test/java/samples/calculator/RpnCalculator.java: -------------------------------------------------------------------------------- 1 | package samples.calculator; 2 | 3 | import java.util.Deque; 4 | import java.util.LinkedList; 5 | import java.util.List; 6 | 7 | import static java.util.Arrays.asList; 8 | 9 | public class RpnCalculator { 10 | private final Deque stack = new LinkedList<>(); 11 | private static final List OPS = asList("-", "+", "*", "/"); 12 | 13 | public void push(Object arg) { 14 | if (OPS.contains(arg)) { 15 | Integer y = stack.removeLast(); 16 | Integer x = (stack.isEmpty() ? 0 : stack.removeLast()); 17 | Integer val = null; 18 | if (arg.equals("-")) { 19 | val = x - y; 20 | } else if (arg.equals("+")) { 21 | val = x + y; 22 | } else if (arg.equals("*")) { 23 | val = x * y; 24 | } else if (arg.equals("/")) { 25 | val = x / y; 26 | } 27 | push(val); 28 | } else { 29 | stack.add((Integer) arg); 30 | } 31 | } 32 | 33 | public Integer value() { 34 | return stack.getLast(); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/test/java/net/serenitybdd/cucumber/suiteslicing/SlicedTestRunner.java: -------------------------------------------------------------------------------- 1 | package net.serenitybdd.cucumber.suiteslicing; 2 | 3 | import io.cucumber.junit.CucumberOptions; 4 | import net.serenitybdd.cucumber.CucumberWithSerenity; 5 | import org.junit.Ignore; 6 | import org.junit.runner.RunWith; 7 | 8 | 9 | 10 | @Ignore 11 | @RunWith(CucumberWithSerenity.class) 12 | @CucumberOptions(glue = "net.serenitybdd.cucumber.smoketests", features="classpath:smoketests") 13 | public class SlicedTestRunner { 14 | 15 | /* 16 | 17 | Experimental test runner where parameters can changed in order to run specific portions of the test suite. For instance create a run configuration and paste the following into the VM Options: 18 | 19 | -Dserenity.batch.count=3 -Dserenity.batch.number=2 -Dserenity.fork.number=1 -Dserenity.fork.count=2 -Dserenity.test.statistics.dir=/statistics 20 | 21 | And you should see the following logged in the console: 22 | 23 | 16:49:18.551 [main] INFO n.s.cucumber.CucumberWithSerenity - Running slice 2 of 3 using fork 1 of 2 from feature paths [classpath:smoketests] 24 | 25 | The Test output should show some features selected and some scenarios run and some not run. This is expected! 26 | 27 | */ 28 | 29 | } 30 | -------------------------------------------------------------------------------- /src/test/java/net/serenitybdd/cucumber/suiteslicing/MultiRunTestStatisticsTest.java: -------------------------------------------------------------------------------- 1 | package net.serenitybdd.cucumber.suiteslicing; 2 | 3 | import org.junit.Before; 4 | import org.junit.Test; 5 | 6 | import java.math.BigDecimal; 7 | 8 | import static org.hamcrest.collection.IsCollectionWithSize.hasSize; 9 | import static org.hamcrest.core.Is.is; 10 | import static org.junit.Assert.assertThat; 11 | 12 | public class MultiRunTestStatisticsTest { 13 | 14 | TestStatistics statistics; 15 | 16 | @Before 17 | public void setup() { 18 | statistics = MultiRunTestStatistics.fromRelativePath("/statistics"); 19 | } 20 | 21 | @Test 22 | public void recordCountShouldBeCorrect() { 23 | assertThat(statistics.records(), hasSize(19)); 24 | } 25 | 26 | @Test 27 | public void scenarioWeightForShouldReturnAverageOfDurationsForKnownScenario() { 28 | assertThat(statistics.scenarioWeightFor("Using Background Steps", "Running a scenario with a Before clause"), is(new BigDecimal("34.03"))); 29 | } 30 | 31 | @Test 32 | public void scenarioWeightForShouldReturnAverageAllDurationsForUnknownScenario() { 33 | assertThat(statistics.scenarioWeightFor("Yo", "I don't exist matey"), is(new BigDecimal("5.53"))); 34 | } 35 | 36 | } -------------------------------------------------------------------------------- /src/main/java/net/serenitybdd/cucumber/suiteslicing/CucumberSuiteSlicer.java: -------------------------------------------------------------------------------- 1 | package net.serenitybdd.cucumber.suiteslicing; 2 | 3 | import net.serenitybdd.cucumber.util.TagParser; 4 | 5 | import java.net.URI; 6 | import java.util.List; 7 | import java.util.function.Predicate; 8 | 9 | import static com.google.common.collect.Lists.newArrayList; 10 | 11 | public class CucumberSuiteSlicer { 12 | 13 | private final List featurePaths; 14 | private final TestStatistics statistics; 15 | 16 | public CucumberSuiteSlicer(List featurePaths, TestStatistics statistics) { 17 | this.featurePaths = featurePaths; 18 | this.statistics = statistics; 19 | } 20 | 21 | public WeightedCucumberScenarios scenarios(int batchNumber, int batchCount, int forkNumber, int forkCount, List tagFilters) { 22 | return new CucumberScenarioLoader(featurePaths, statistics).load() 23 | .filter(forSuppliedTags(tagFilters)) 24 | .slice(batchNumber).of(batchCount).slice(forkNumber).of(forkCount); 25 | } 26 | 27 | private Predicate forSuppliedTags(List tagFilters) { 28 | return cucumberScenario -> TagParser.parseFromTagFilters(tagFilters).evaluate(newArrayList(cucumberScenario.tags)); 29 | } 30 | 31 | } -------------------------------------------------------------------------------- /src/test/resources/smoketests/skipping_scenarios.feature: -------------------------------------------------------------------------------- 1 | @driver:phantomjs 2 | @driver-options:--headless 3 | Feature: Skipping Scenarios 4 | 5 | @pending 6 | Scenario: Pending scenario 7 | Given I want to search for something 8 | When I lookup apple 9 | Then I should see "apple at DuckDuckGo" in the page title 10 | 11 | @wip 12 | Scenario: WIP scenario 13 | Given I want to search for something 14 | When I lookup apple 15 | Then I should see "apple at DuckDuckGo" in the page title 16 | 17 | @skip 18 | Scenario: Skipping a scenario 19 | Given I want to search for something 20 | When I lookup apple 21 | Then I should see "apple at DuckDuckGo" in the page title 22 | 23 | @manual 24 | Scenario: A manual scenario 25 | Given I want to search for something 26 | When I lookup apple 27 | Then I should see "apple at DuckDuckGo" in the page title 28 | 29 | @ignore 30 | Scenario: An ignored scenario 31 | Given I want to search for something 32 | When I lookup apple 33 | Then I should see "apple at DuckDuckGo" in the page title 34 | 35 | @manual 36 | @skip 37 | Scenario: A skipped manual scenario 38 | Given I want to search for something 39 | When I lookup apple 40 | Then I should see "apple at DuckDuckGo" in the page title 41 | -------------------------------------------------------------------------------- /src/test/java/net/serenitybdd/cucumber/suiteslicing/SingleRunTestStatisticsTest.java: -------------------------------------------------------------------------------- 1 | package net.serenitybdd.cucumber.suiteslicing; 2 | 3 | import org.junit.Before; 4 | import org.junit.Test; 5 | 6 | import java.math.BigDecimal; 7 | 8 | import static org.hamcrest.collection.IsCollectionWithSize.hasSize; 9 | import static org.hamcrest.core.Is.is; 10 | import static org.junit.Assert.assertThat; 11 | 12 | public class SingleRunTestStatisticsTest { 13 | 14 | TestStatistics statistics; 15 | 16 | @Before 17 | public void setup() { 18 | statistics = SingleRunTestStatistics.fromFileName("/statistics/smoke-test-results-run-1.csv"); 19 | } 20 | 21 | @Test 22 | public void recordCountShouldBeCorrect() throws Exception { 23 | assertThat(statistics.records(), hasSize(19)); 24 | } 25 | 26 | @Test 27 | public void scenarioWeightForShouldReturnExactDurationForKnownScenario() throws Exception { 28 | assertThat(statistics.scenarioWeightFor("Using Background Steps", "Running a scenario with a Before clause"), is(new BigDecimal("38.49"))); 29 | } 30 | 31 | @Test(expected = IllegalArgumentException.class) 32 | public void scenarioWeightForShouldReturnAverageDurationForUnknownScenario() throws Exception { 33 | statistics.scenarioWeightFor("Yo", "I don't exist matey"); 34 | } 35 | 36 | } -------------------------------------------------------------------------------- /src/test/groovy/net/serenitybdd/cucumber/reports/WhenGeneratingThucydidesReports.groovy: -------------------------------------------------------------------------------- 1 | package net.serenitybdd.cucumber.reports 2 | 3 | import io.cucumber.junit.CucumberRunner 4 | import io.cucumber.plugin.event.Status 5 | import net.serenitybdd.cucumber.integration.SimpleScenario 6 | import net.thucydides.core.reports.OutcomeFormat 7 | import net.thucydides.core.reports.TestOutcomeLoader 8 | import org.junit.Rule 9 | import org.junit.rules.TemporaryFolder 10 | import spock.lang.Specification 11 | 12 | /** 13 | * Created by john on 23/07/2014. 14 | */ 15 | class WhenGeneratingThucydidesReports extends Specification { 16 | 17 | @Rule 18 | TemporaryFolder temporaryFolder 19 | 20 | File outputDirectory 21 | 22 | def setup() { 23 | outputDirectory = temporaryFolder.newFolder() 24 | } 25 | 26 | def "should generate a Thucydides report for each executed Cucumber scenario"() { 27 | given: 28 | def runtime = CucumberRunner.serenityRunnerForCucumberTestRunner(SimpleScenario.class, outputDirectory); 29 | 30 | when: 31 | runtime.run(); 32 | def recordedTestOutcomes = new TestOutcomeLoader().forFormat(OutcomeFormat.JSON).loadFrom(outputDirectory); 33 | 34 | then: 35 | runtime.exitStatus.results[0].status.is(Status.PASSED) 36 | 37 | and: 38 | !recordedTestOutcomes.isEmpty() 39 | } 40 | 41 | 42 | } -------------------------------------------------------------------------------- /src/test/resources/samples/scenario_with_table_in_background_steps.feature: -------------------------------------------------------------------------------- 1 | Feature: Locate a customer by personal details and Reg Number 2 | In order to find information relevant to a specific customer 3 | As a financial advisor 4 | I want to be able to locate a customer by personal details, registration number 5 | 6 | Background: 7 | # Set up the customer in the test data, or ensure that this data is available 8 | Given the following customers exist: 9 | | Name | DOB | Mobile Phone | Home Phone | Work Phone | Address Line 1 | Address Line 2 | 10 | | SEAN PAUL | 30/05/1978 | 860123334 | 1234567899 | 16422132 | ONE BBI ACC | BEACON SOUTH | 11 | | TONY SMITH | 10/10/1975 | 86123335 | 11255555 | 16422132 | 1 MAIN STREET | BANKCENTRE | 12 | | PETE FORD | 12/03/1970 | 865555551 | 15555551 | 15555551 | Q6B HILL ST | BLACKROCK | 13 | | JOHN B JOVI | 22/08/1957 | 871274762 | | 16422132 | BLAKBURN | TALLAGHT | 14 | | JOHN ANFIELD | 20/05/1970 | 876565656 | 015555551 | 214555555 | DUBLIN | DUBLIN | 15 | And I am logged into the OneView app 16 | 17 | @layer:ui 18 | Scenario: Locating a customer using a unique criterion 19 | When I locate a customer with a Reg Number of 80862061 20 | Then I should see the customer profile for TONY SMITH 21 | -------------------------------------------------------------------------------- /src/test/groovy/net/serenitybdd/cucumber/reports/WhenGeneratingReportsForLineFilteredScenarioOutline.groovy: -------------------------------------------------------------------------------- 1 | package net.serenitybdd.cucumber.reports 2 | 3 | import io.cucumber.junit.CucumberRunner 4 | import io.cucumber.plugin.event.Status 5 | import net.serenitybdd.cucumber.integration.SimpleTableScenarioWithLineFilters 6 | import net.thucydides.core.reports.OutcomeFormat 7 | import net.thucydides.core.reports.TestOutcomeLoader 8 | import org.junit.Rule 9 | import org.junit.rules.TemporaryFolder 10 | import spock.lang.Specification 11 | 12 | class WhenGeneratingReportsForLineFilteredScenarioOutline extends Specification { 13 | 14 | @Rule 15 | TemporaryFolder temporaryFolder 16 | 17 | File outputDirectory 18 | 19 | def setup() { 20 | outputDirectory = temporaryFolder.newFolder() 21 | } 22 | 23 | def "should generate a Thucydides report for each executed Cucumber scenario"() { 24 | given: 25 | def runtime = CucumberRunner.serenityRunnerForCucumberTestRunner(SimpleTableScenarioWithLineFilters.class, outputDirectory) 26 | 27 | when: 28 | runtime.run() 29 | def recordedTestOutcomes = new TestOutcomeLoader().forFormat(OutcomeFormat.JSON).loadFrom(outputDirectory) 30 | 31 | then: 32 | runtime.exitStatus.results[0].getStatus().is(Status.PASSED) 33 | 34 | and: 35 | !recordedTestOutcomes.isEmpty() 36 | } 37 | 38 | 39 | } -------------------------------------------------------------------------------- /src/main/java/net/serenitybdd/cucumber/suiteslicing/VisualisableCucumberScenarios.java: -------------------------------------------------------------------------------- 1 | package net.serenitybdd.cucumber.suiteslicing; 2 | 3 | import org.apache.commons.lang3.builder.HashCodeBuilder; 4 | import org.apache.commons.lang3.builder.ToStringBuilder; 5 | 6 | import static org.apache.commons.lang3.builder.EqualsBuilder.reflectionEquals; 7 | 8 | public class VisualisableCucumberScenarios extends WeightedCucumberScenarios { 9 | 10 | public final Integer slice; 11 | public final Integer forkNumber; 12 | 13 | private VisualisableCucumberScenarios(Integer slice, Integer forkNumber, WeightedCucumberScenarios WeightedCucumberScenarios) { 14 | super(WeightedCucumberScenarios.scenarios); 15 | this.forkNumber = forkNumber; 16 | this.slice = slice; 17 | } 18 | 19 | public static VisualisableCucumberScenarios create(Integer slice, Integer forkNumber, WeightedCucumberScenarios WeightedCucumberScenarios) { 20 | return new VisualisableCucumberScenarios(slice, forkNumber, WeightedCucumberScenarios); 21 | } 22 | 23 | @Override 24 | public int hashCode() { 25 | return HashCodeBuilder.reflectionHashCode(this); 26 | } 27 | 28 | @Override 29 | public boolean equals(Object obj) { 30 | return reflectionEquals(this, obj); 31 | } 32 | 33 | @Override 34 | public String toString() { 35 | return ToStringBuilder.reflectionToString(this); 36 | } 37 | 38 | } 39 | -------------------------------------------------------------------------------- /src/smoketests/src/test/java/smoketests/SlicedTestRunner.java: -------------------------------------------------------------------------------- 1 | package smoketests; 2 | 3 | import io.cucumber.junit.CucumberOptions; 4 | import io.cucumber.junit.CucumberWithSerenity; 5 | import org.junit.runner.RunWith; 6 | 7 | @RunWith(CucumberWithSerenity.class) 8 | @CucumberOptions(glue = "smoketests.stepdefinitions", features = "classpath:features") 9 | public class SlicedTestRunner { 10 | 11 | /* 12 | 13 | Experimental test runner where parameters can changed in order to run specific portions of the test suite. For instance create a run configuration and paste the following into the VM Options: 14 | 15 | -Dserenity.batch.count=3 -Dserenity.batch.number=2 -Dserenity.fork.number=1 -Dserenity.fork.count=2 -Dserenity.test.statistics.dir=/statistics 16 | 17 | And you should see the following logged in the console: 18 | 19 | 16:49:18.551 [main] INFO n.s.cucumber.CucumberWithSerenity - Running slice 2 of 3 using fork 1 of 2 from feature paths [classpath:smoketests] 20 | 21 | The Test output should show some features selected and some scenarios run and some not run. This is expected! 22 | 23 | */ 24 | 25 | /* 26 | 27 | Alternatively, the tests can be run in maven with or without test forking as follows: 28 | 29 | clean verify -Dserenity.batch.count=1 -Dserenity.batch.number=1 -P dontUseTheForks 30 | clean verify -Dserenity.batch.count=1 -Dserenity.batch.number=1 -Dserenity.test.statistics.dir=/statistics -P useTheForks 31 | 32 | */ 33 | 34 | } 35 | -------------------------------------------------------------------------------- /src/main/java/net/serenitybdd/cucumber/util/PathUtils.java: -------------------------------------------------------------------------------- 1 | package net.serenitybdd.cucumber.util; 2 | 3 | import io.cucumber.core.resource.ClasspathSupport; 4 | 5 | import java.io.File; 6 | import java.net.MalformedURLException; 7 | import java.net.URI; 8 | import java.util.Objects; 9 | 10 | public class PathUtils { 11 | 12 | private PathUtils() { 13 | } 14 | 15 | public static File getAsFile(URI cucumberFeatureUri) { 16 | Objects.requireNonNull(cucumberFeatureUri, "cucumber feature URI cannot be null"); 17 | String featureFilePath; 18 | switch (cucumberFeatureUri.getScheme()) { 19 | case "file": { 20 | try { 21 | featureFilePath = cucumberFeatureUri.toURL().getPath(); 22 | break; 23 | } catch (MalformedURLException e) { 24 | throw new IllegalArgumentException("Cannot convert cucumber feature URI to URL", e); 25 | } 26 | } 27 | case "classpath": { 28 | featureFilePath = ClasspathSupport.resourceName(cucumberFeatureUri); 29 | break; 30 | } 31 | default: 32 | throw new IllegalArgumentException("Cannot get cucumber feature file from URI"); 33 | } 34 | return new File(featureFilePath); 35 | } 36 | 37 | public static File getAsFile(String cucumberFeatureUri) { 38 | return getAsFile(URI.create(cucumberFeatureUri)); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/main/java/net/serenitybdd/cucumber/suiteslicing/TestScenarioResult.java: -------------------------------------------------------------------------------- 1 | package net.serenitybdd.cucumber.suiteslicing; 2 | 3 | import org.apache.commons.csv.CSVRecord; 4 | 5 | 6 | import java.math.BigDecimal; 7 | 8 | import static net.serenitybdd.cucumber.suiteslicing.SerenityCSVHeader.DURATION; 9 | import static net.serenitybdd.cucumber.suiteslicing.SerenityCSVHeader.STORY; 10 | import static net.serenitybdd.cucumber.suiteslicing.SerenityCSVHeader.TITLE; 11 | import static org.apache.commons.lang3.builder.ToStringBuilder.reflectionToString; 12 | 13 | 14 | public class TestScenarioResult { 15 | 16 | public final String feature; 17 | public final String scenario; 18 | public final BigDecimal duration; 19 | public final String scenarioKey; 20 | 21 | public static TestScenarioResult createFromCSV(CSVRecord csvRecord) { 22 | return new TestScenarioResult( 23 | csvRecord.get(STORY), 24 | csvRecord.get(TITLE), 25 | new BigDecimal(csvRecord.get(DURATION))); 26 | } 27 | 28 | public BigDecimal duration() { 29 | return duration; 30 | } 31 | 32 | public TestScenarioResult(String feature, String scenario, BigDecimal duration) { 33 | this.feature = feature; 34 | this.scenario = scenario; 35 | this.scenarioKey = feature + ":" + scenario; 36 | this.duration = duration; 37 | } 38 | 39 | @Override 40 | public String toString() { 41 | return reflectionToString(this); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/main/java/net/serenitybdd/cucumber/suiteslicing/WeightedCucumberScenario.java: -------------------------------------------------------------------------------- 1 | package net.serenitybdd.cucumber.suiteslicing; 2 | 3 | import org.apache.commons.lang3.builder.HashCodeBuilder; 4 | 5 | import java.math.BigDecimal; 6 | import java.util.Set; 7 | 8 | import static org.apache.commons.lang3.builder.EqualsBuilder.reflectionEquals; 9 | import static org.apache.commons.lang3.builder.ToStringBuilder.reflectionToString; 10 | 11 | public class WeightedCucumberScenario { 12 | 13 | public final String featurePath; 14 | public final String feature; 15 | public final String scenario; 16 | public final int scenarioCount; 17 | public final BigDecimal weighting; 18 | public final Set tags; 19 | 20 | public WeightedCucumberScenario(String featurePath, String feature, String scenario, BigDecimal weighting, Set tags, int scenarioCount) { 21 | this.featurePath = featurePath; 22 | this.feature = feature; 23 | this.scenario = scenario; 24 | this.weighting = weighting; 25 | this.tags = tags; 26 | this.scenarioCount = scenarioCount; 27 | } 28 | 29 | public BigDecimal weighting() { 30 | return weighting; 31 | } 32 | 33 | @Override 34 | public int hashCode() { 35 | return HashCodeBuilder.reflectionHashCode(this); 36 | } 37 | 38 | @Override 39 | public boolean equals(Object obj) { 40 | return reflectionEquals(this, obj); 41 | } 42 | 43 | @Override 44 | public String toString() { 45 | return reflectionToString(this); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/test/java/net/serenitybdd/cucumber/integration/steps/SimpleCalculatorSteps.java: -------------------------------------------------------------------------------- 1 | package net.serenitybdd.cucumber.integration.steps; 2 | 3 | import io.cucumber.java.PendingException; 4 | import io.cucumber.java.en.Given; 5 | import io.cucumber.java.en.Then; 6 | import io.cucumber.java.en.When; 7 | 8 | import static org.assertj.core.api.Assertions.assertThat; 9 | 10 | public class SimpleCalculatorSteps { 11 | 12 | int a; 13 | int b; 14 | @Given("^the number ([0-9]*) and the number ([0-9]*)$") 15 | public void theNumberAAndTheNumberB(Integer a, Integer b) throws Throwable { 16 | this.a = a; 17 | this.b = b; 18 | } 19 | 20 | int result; 21 | @When("^([0-9]*) plus ([0-9]*)$") 22 | public void aPlusB(Integer a, Integer b) throws Throwable { 23 | result = a + b; 24 | } 25 | 26 | @Then("^the result is equals to ([0-9]*)$") 27 | public void theResultIsEqualsToC(Integer expectedResult) throws Throwable { 28 | assertThat(result).isEqualTo(expectedResult); 29 | } 30 | 31 | @Then("a PendingException should be thrown") 32 | public void throwPending() { 33 | throw new PendingException(); 34 | } 35 | 36 | @Given("^the amount ([0-9]*) and the amount ([0-9]*)$") 37 | public void theAmounts(Integer a, Integer b) throws Throwable { 38 | } 39 | 40 | @When("^([0-9]*) minus ([0-9]*)$") 41 | public void aMinusB(Integer a, Integer b) throws Throwable { 42 | } 43 | 44 | @Then("^the result should be ([0-9]*)$") 45 | public void theResultShouldBe(Integer b) throws Throwable { 46 | } 47 | } -------------------------------------------------------------------------------- /src/test/java/io/cucumber/junit/FeatureRunnerExtractorsTest.java: -------------------------------------------------------------------------------- 1 | package io.cucumber.junit; 2 | 3 | import io.cucumber.junit.FeatureRunnerExtractors; 4 | import org.junit.Test; 5 | import org.junit.runner.Description; 6 | 7 | 8 | 9 | import static org.hamcrest.core.Is.is; 10 | import static org.junit.Assert.*; 11 | import static org.mockito.Mockito.mock; 12 | import static org.mockito.Mockito.when; 13 | 14 | public class FeatureRunnerExtractorsTest { 15 | 16 | @Test 17 | public void extractFeatureNameShouldReturnTheNameOfTheFeatureWithSloppyNamingConvention() { 18 | performExpectationsWith("Feature : my super feature", "my super feature"); 19 | } 20 | 21 | @Test 22 | public void extractFeatureNameShouldReturnTheNameOfANormallyNamedFeature() { 23 | performExpectationsWith("Feature: my super feature", "my super feature"); 24 | } 25 | 26 | @Test 27 | public void extractFeatureNameShouldReturnTheNameOfTheFeatureThatHasAColon() { 28 | performExpectationsWith("Feature: my super feature: is with colon", "my super feature: is with colon"); 29 | } 30 | 31 | private void performExpectationsWith(String displayName, String expectation) { 32 | FeatureRunner runner = mock(FeatureRunner.class); 33 | Description description = mock(Description.class); 34 | when(description.getDisplayName()).thenReturn(displayName); 35 | when(runner.getDescription()).thenReturn(description); 36 | String name = FeatureRunnerExtractors.extractFeatureName(runner); 37 | assertThat(name, is(expectation)); 38 | } 39 | 40 | 41 | } -------------------------------------------------------------------------------- /src/main/java/cucumber/runtime/SerenityBackend.java: -------------------------------------------------------------------------------- 1 | package cucumber.runtime; 2 | 3 | import io.cucumber.core.backend.Backend; 4 | import io.cucumber.core.backend.Glue; 5 | import io.cucumber.core.backend.Snippet; 6 | import net.thucydides.core.steps.StepEventBus; 7 | import org.slf4j.Logger; 8 | import org.slf4j.LoggerFactory; 9 | 10 | import java.net.URI; 11 | import java.util.List; 12 | 13 | public class SerenityBackend implements Backend { 14 | 15 | private static final Logger LOGGER = LoggerFactory.getLogger(SerenityBackend.class); 16 | 17 | public SerenityBackend() { 18 | 19 | } 20 | 21 | /** 22 | * Invoked once before all features. This is where stepdefs and hooks should be loaded. 23 | */ 24 | 25 | @Override 26 | public void loadGlue(Glue glue, List gluePaths){ 27 | 28 | } 29 | 30 | /** 31 | * Invoked before a new scenario starts. Implementations should do any necessary 32 | * setup of new, isolated state here. 33 | */ 34 | @Override 35 | public void buildWorld(){} 36 | 37 | 38 | 39 | 40 | /** 41 | * Invoked at the end of a scenario, after hooks 42 | */ 43 | @Override 44 | public void disposeWorld() { 45 | if (!StepEventBus.getEventBus().isBaseStepListenerRegistered()) { 46 | LOGGER.warn("It looks like you are running a feature using @RunWith(Cucumber.class) instead of @RunWith(CucumberWithSerenity.class). Are you sure this is what you meant to do?"); 47 | } 48 | } 49 | 50 | @Override 51 | public Snippet getSnippet() { 52 | return null; 53 | } 54 | 55 | 56 | } 57 | -------------------------------------------------------------------------------- /src/test/resources/features/calculator/basic_arithmetic_with_tables_and_examples_no_tags.feature: -------------------------------------------------------------------------------- 1 | Feature: Basic Arithmetic with tables 2 | In order to do my maths homework 3 | As a maths student 4 | I want to be able to add sums 5 | 6 | @scenario_outline 7 | Scenario Outline: Many additions 8 | Given a calculator I just turned on 9 | And the previous entries: 10 | | first | second | operation | 11 | | 1 | 1 | + | 12 | | 2 | 1 | + | 13 | When I press + 14 | And I add and 15 | And I press + 16 | Then the result is 17 | 18 | @example_one 19 | Examples: Single digits 20 | With just one digit 21 | | a | b | c | 22 | | 1 | 2 | 8 | 23 | | 2 | 3 | 10 | 24 | 25 | @example_two 26 | Examples: Double digits 27 | With more digits than one 28 | | a | b | c | 29 | | 10 | 20 | 35 | 30 | | 20 | 30 | 55 | 31 | | 25 | 35 | 65 | 32 | 33 | 34 | Scenario Outline: Should be executed 35 | Given a calculator I just turned on 36 | And the previous entries: 37 | | first | second | operation | 38 | | 1 | 1 | + | 39 | | 2 | 1 | + | 40 | When I press + 41 | And I add and 42 | And I press + 43 | Then the result is 44 | 45 | Examples: Single digits 46 | With just one digit 47 | | a | b | c | 48 | | 1 | 2 | 8 | 49 | | 2 | 3 | 10 | 50 | 51 | Examples: Double digits 52 | With more digits than one 53 | | a | b | c | 54 | | 10 | 20 | 35 | 55 | | 20 | 30 | 55 | 56 | | 25 | 35 | 65 | 57 | -------------------------------------------------------------------------------- /src/main/java/net/serenitybdd/cucumber/cli/Main.java: -------------------------------------------------------------------------------- 1 | package net.serenitybdd.cucumber.cli; 2 | 3 | import io.cucumber.core.options.CommandlineOptionsParser; 4 | import io.cucumber.core.options.RuntimeOptions; 5 | import io.cucumber.core.resource.ClassLoaders; 6 | import io.cucumber.core.runtime.Runtime; 7 | import net.serenitybdd.cucumber.CucumberWithSerenity; 8 | import net.serenitybdd.cucumber.CucumberWithSerenityRuntime; 9 | 10 | import java.io.IOException; 11 | import java.util.function.Supplier; 12 | 13 | 14 | public class Main { 15 | 16 | public static void main(String[] argv) throws Throwable { 17 | Supplier classLoaderSupplier = ClassLoaders::getDefaultClassLoader; 18 | //byte exitstatus = run(argv, Thread.currentThread().getContextClassLoader()); 19 | byte exitstatus = run(argv,classLoaderSupplier ); 20 | System.exit(exitstatus); 21 | } 22 | 23 | public static byte run(String[] argv, Supplier classLoaderSupplier) throws IOException { 24 | RuntimeOptions runtimeOptions = new CommandlineOptionsParser().parse(argv).build() ; 25 | //ResourceLoader resourceLoader = new MultiLoader(classLoader); 26 | //ClassFinder classFinder = new ResourceLoaderClassFinder(resourceLoader, classLoader); 27 | CucumberWithSerenity.setRuntimeOptions(runtimeOptions); 28 | //Runtime runtime = CucumberWithSerenityRuntime.using(resourceLoader, classLoader, classFinder, runtimeOptions); 29 | Runtime runtime = CucumberWithSerenityRuntime.using(classLoaderSupplier, runtimeOptions); 30 | 31 | runtime.run(); 32 | return runtime.exitStatus(); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/smoketests/src/test/resources/features/when_using_tables/when_using_tables.feature: -------------------------------------------------------------------------------- 1 | Feature: Serenity and Cucumber let you do cool stuff with tables 2 | 3 | Tables are used for data-driven testing. 4 | You can use more than one table in a scenario outline, and tables can be tagged individually. 5 | 6 | @expected-outcome:success 7 | Scenario: Doing basic maths 8 | Given I have a calculator 9 | When I add 1 10 | And I add 2 11 | Then the total should be 3 12 | 13 | @tables 14 | @expected-outcome:success 15 | Scenario Outline: Doing maths 16 | Given I have a calculator 17 | When I add 18 | And I add 19 | Then the total should be 20 | 21 | @isolated 22 | Examples: 23 | | a | b | c | 24 | | 1 | 1 | 2 | 25 | | 1 | 2 | 3 | 26 | | 2 | 3 | 5 | 27 | 28 | @tables 29 | @expected-outcome:success 30 | Scenario Outline: Doing more maths 31 | Given I have a calculator 32 | When I add 33 | And I add 34 | Then the total should be 35 | 36 | @single @red 37 | Examples: Single digits 38 | | a | b | c | 39 | | 1 | 1 | 2 | 40 | | 1 | 2 | 3 | 41 | | 2 | 3 | 5 | 42 | 43 | @double @blue 44 | Examples: Double digits 45 | | a | b | c | 46 | | 10 | 1 | 11 | 47 | | 10 | 2 | 12 | 48 | | 20 | 3 | 23 | 49 | 50 | @tables 51 | @expected-outcome:failure 52 | Scenario Outline: Doing maths wrong 53 | Given I have a calculator 54 | When I add 55 | And I add 56 | Then the total should be 57 | @isolated 58 | Examples: 59 | | a | b | c | 60 | | 1 | 1 | 2 | 61 | | 1 | 2 | 3 | 62 | | 2 | 3 | 5 | -------------------------------------------------------------------------------- /src/main/java/io/cucumber/core/plugin/FeaturePathFormatter.java: -------------------------------------------------------------------------------- 1 | package io.cucumber.core.plugin; 2 | 3 | import java.net.URI; 4 | import java.net.URISyntaxException; 5 | import java.util.ArrayList; 6 | import java.util.List; 7 | import java.util.Map; 8 | import java.util.Set; 9 | 10 | public class FeaturePathFormatter { 11 | 12 | private LineFilters lineFilters; 13 | 14 | public FeaturePathFormatter() { 15 | this.lineFilters = LineFilters.forCurrentContext(); 16 | } 17 | 18 | public URI featurePathWithPrefixIfNecessary(final URI featurePath) { 19 | return lineFilters 20 | .getURIForFeaturePath(featurePath) 21 | .map(matchingURI -> featurePathWithPrefix(matchingURI, featurePath)) 22 | .orElse(featurePath); 23 | } 24 | 25 | private URI featurePathWithPrefix(URI featurePathUri, URI featurePath) { 26 | Set allLineNumbersSet = lineFilters.getLineNumbersFor(featurePathUri); 27 | List allLineNumbersList = new ArrayList<>(allLineNumbersSet); 28 | long featurePathPrefix = allLineNumbersList.get(0); 29 | URI featureURIWithPrefix = featurePathUri; 30 | try { 31 | featureURIWithPrefix = new URI(featurePath.toString() + ":" + featurePathPrefix); 32 | } catch (URISyntaxException e) { 33 | e.printStackTrace(); 34 | } 35 | return featureURIWithPrefix; 36 | 37 | } 38 | 39 | private URI getURIForFeaturePath(Map> map, URI featurePath) { 40 | for (URI currentURI : map.keySet()) { 41 | if (featurePath.equals(currentURI)) { 42 | return currentURI; 43 | } 44 | } 45 | return null; 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/test/groovy/net/serenitybdd/cucumber/screenplay/WhenScreenplayActorsGoOnStage.groovy: -------------------------------------------------------------------------------- 1 | package net.serenitybdd.cucumber.screenplay 2 | 3 | import net.serenitybdd.cucumber.actors.StageDirector 4 | import net.serenitybdd.screenplay.actors.Cast 5 | import net.serenitybdd.screenplay.actors.OnStage 6 | import spock.lang.Specification 7 | 8 | public class WhenScreenplayActorsGoOnStage extends Specification { 9 | 10 | def "When an actor is called he is placed in the spotlight"() { 11 | given: 12 | Cast cast = new Cast() 13 | OnStage.setTheStage(cast); 14 | when: 15 | def jamesDean = OnStage.theActorCalled("James Dean") 16 | then: 17 | OnStage.theActorInTheSpotlight() == jamesDean 18 | } 19 | 20 | def "When a new actor is placed in the spotlight the previous actor is no longer in the spotlight"() { 21 | given: 22 | Cast cast = new Cast() 23 | OnStage.setTheStage(cast); 24 | and: 25 | def jamesDean = OnStage.theActorCalled("James Dean") 26 | when: 27 | def bradPitt = OnStage.theActorCalled("Brad Pitt") 28 | then: 29 | OnStage.theActorInTheSpotlight() == bradPitt 30 | } 31 | 32 | def "At the end of the act we remove all of the actors"() { 33 | given: 34 | Cast cast = new Cast() 35 | OnStage.setTheStage(cast); 36 | and: 37 | OnStage.theActorCalled("James Dean") 38 | OnStage.theActorCalled("Brad Pitt") 39 | and: 40 | StageDirector stageDirector = new StageDirector(); 41 | when: 42 | stageDirector.endTheAct() 43 | then: 44 | cast.actors.isEmpty() 45 | } 46 | 47 | } 48 | -------------------------------------------------------------------------------- /src/main/java/net/serenitybdd/cucumber/service/CucumberTagProviderStrategy.java: -------------------------------------------------------------------------------- 1 | package net.serenitybdd.cucumber.service; 2 | 3 | 4 | import net.thucydides.core.guice.Injectors; 5 | import net.thucydides.core.requirements.FileSystemRequirementsTagProvider; 6 | import net.thucydides.core.statistics.service.ContextTagProvider; 7 | import net.thucydides.core.statistics.service.InjectedTagProvider; 8 | import net.thucydides.core.statistics.service.TagProvider; 9 | import net.thucydides.core.statistics.service.TagProviderStrategy; 10 | import net.thucydides.core.steps.TestSourceType; 11 | import net.thucydides.core.util.EnvironmentVariables; 12 | 13 | import java.util.Arrays; 14 | 15 | public class CucumberTagProviderStrategy implements TagProviderStrategy { 16 | 17 | private final EnvironmentVariables environmentVariables; 18 | 19 | public CucumberTagProviderStrategy(EnvironmentVariables environmentVariables) { 20 | this.environmentVariables = environmentVariables; 21 | } 22 | 23 | public CucumberTagProviderStrategy() { 24 | this(Injectors.getInjector().getInstance(EnvironmentVariables.class)); 25 | } 26 | 27 | @Override 28 | public boolean canHandleTestSource(String testType) { 29 | return TestSourceType.TEST_SOURCE_CUCUMBER.getValue().equalsIgnoreCase(testType); 30 | } 31 | 32 | @Override 33 | public Iterable getTagProviders() { 34 | return Arrays.asList( 35 | new FileSystemRequirementsTagProvider(environmentVariables), 36 | new InjectedTagProvider(environmentVariables), 37 | new ContextTagProvider()); 38 | } 39 | 40 | @Override 41 | public boolean hasHighPriority() { 42 | return false; 43 | } 44 | 45 | } 46 | -------------------------------------------------------------------------------- /src/test/groovy/net/serenitybdd/cucumber/outcomes/WhenUsingAnIllegalStepLibrary.groovy: -------------------------------------------------------------------------------- 1 | package net.serenitybdd.cucumber.outcomes 2 | 3 | import io.cucumber.junit.CucumberRunner 4 | import net.serenitybdd.cucumber.integration.BrokenStepLibraryScenario 5 | import net.serenitybdd.cucumber.integration.IllegalStepLibraryScenario 6 | import org.junit.Rule 7 | import org.junit.rules.TemporaryFolder 8 | import spock.lang.Specification 9 | 10 | /** 11 | * Created by john on 23/07/2014. 12 | */ 13 | class WhenUsingAnIllegalStepLibrary extends Specification { 14 | 15 | @Rule 16 | TemporaryFolder temporaryFolder 17 | 18 | File outputDirectory 19 | 20 | def setup() { 21 | outputDirectory = temporaryFolder.newFolder() 22 | } 23 | 24 | def "should throw a meaningful exception if a step library with no default constructor is used"() { 25 | given: 26 | def runtime = CucumberRunner.serenityRunnerForCucumberTestRunner(IllegalStepLibraryScenario.class, outputDirectory); 27 | 28 | when: 29 | runtime.run(); 30 | 31 | then: 32 | runtime.exitStatus.results 33 | 34 | and: 35 | runtime.exitStatus.results[0].error.getMessage().contains("this class doesn't have an empty or a page enabled constructor") 36 | } 37 | 38 | def "should throw a meaningful exception if a step library if the step library could not be instantiated"() { 39 | given: 40 | def runtime = CucumberRunner.serenityRunnerForCucumberTestRunner(BrokenStepLibraryScenario.class, outputDirectory); 41 | 42 | when: 43 | runtime.run(); 44 | 45 | then: 46 | runtime.exitStatus.results 47 | 48 | and: 49 | runtime.exitStatus.results[0].error.getMessage().contains("Failed to instantiate class") 50 | } 51 | 52 | 53 | } -------------------------------------------------------------------------------- /src/test/resources/smoketests/step_libraries.feature: -------------------------------------------------------------------------------- 1 | Feature: Using Serenity step libraries in Cucumber step definitions 2 | 3 | Scenario: Serenity instantiates step library fields in the Cucumber step definitions 4 | Given I want to use a step library 5 | When I add a step library field annotated with @Steps 6 | Then Serenity should instantiate the field 7 | 8 | Scenario: Serenity instantiates different step libraries for each field by default 9 | Given I want to use several step library fields of the same type 10 | When I add a step library fields to each of them 11 | Then Serenity should instantiate a different library for each field 12 | 13 | Scenario: Serenity preserves the state of a step library instance during a scenario 14 | Given I have a Serenity step library 15 | When I do something with the library 16 | Then the state of the library should be updated 17 | 18 | Scenario: Serenity refreshes the step libraries for each new scenario 19 | Given I have a Serenity step library 20 | When I start a new scenario 21 | Then the step library should be reinitialised 22 | 23 | Scenario: Shared step libraries refer to the same instance 24 | Given I have two Serenity step libraries 25 | When they are annotated with @Steps(shared=true) 26 | Then both should refer to the same instance 27 | 28 | Scenario: Storig information in the Serenity session state 29 | Given I have a Serenity step library 30 | When I store information the session state 31 | Then the session state information should be available in subsequent steps 32 | 33 | Scenario: Serenity session state should be reset for each scenario 34 | Given I have a Serenity step library 35 | When I start a new scenario 36 | Then the session state information from previous scenarios should be cleared 37 | -------------------------------------------------------------------------------- /src/test/groovy/net/serenitybdd/cucumber/screenplay/WhenManagingScreenplayActorsInCucumber.groovy: -------------------------------------------------------------------------------- 1 | package net.serenitybdd.cucumber.screenplay 2 | 3 | import net.serenitybdd.screenplay.actors.Cast 4 | import net.serenitybdd.screenplay.actors.OnStage 5 | import net.serenitybdd.screenplay.actors.OnlineCast 6 | import spock.lang.Specification 7 | 8 | public class WhenManagingScreenplayActorsInCucumber extends Specification { 9 | 10 | def "Actors are identified by their names"() { 11 | given: 12 | Cast cast = new Cast() 13 | OnStage.setTheStage(cast) 14 | when: 15 | def jamesDean = cast.actorNamed("James Dean") 16 | then: 17 | cast.actorNamed("James Dean") == jamesDean 18 | } 19 | 20 | def "Actors can be assigned a webdriver type"() { 21 | given: 22 | OnlineCast cast = new OnlineCast(); 23 | OnStage.setTheStage(cast) 24 | when: 25 | def jamesDean = cast.actorUsingBrowser("chrome").named("James Dean") 26 | then: 27 | cast.actorNamed("James Dean") == jamesDean 28 | } 29 | 30 | 31 | def "An actor is only cast once"() { 32 | given: 33 | Cast cast = new Cast(); 34 | OnStage.setTheStage(cast) 35 | when: 36 | def jamesDean = cast.actorNamed("James Dean") 37 | and: 38 | cast.actorNamed("James Dean") 39 | then: 40 | cast.actorNamed("James Dean") == jamesDean 41 | } 42 | 43 | def "Cast can be dismissed"() { 44 | given: 45 | Cast cast = new Cast(); 46 | OnStage.setTheStage(cast) 47 | cast.actorNamed("James Dean") 48 | when: 49 | cast.dismissAll() 50 | then: 51 | cast.actors.isEmpty() 52 | } 53 | 54 | 55 | 56 | } 57 | -------------------------------------------------------------------------------- /src/test/java/net/serenitybdd/cucumber/util/TagParserFromEnvironmentVariablesTest.java: -------------------------------------------------------------------------------- 1 | package net.serenitybdd.cucumber.util; 2 | 3 | import net.thucydides.core.util.EnvironmentVariables; 4 | import net.thucydides.core.util.MockEnvironmentVariables; 5 | 6 | import org.junit.Test; 7 | 8 | import static java.util.Arrays.asList; 9 | import static org.hamcrest.Matchers.containsInAnyOrder; 10 | import static org.hamcrest.Matchers.hasSize; 11 | import static org.junit.Assert.assertThat; 12 | 13 | public class TagParserFromEnvironmentVariablesTest { 14 | 15 | @Test 16 | public void commandLineTagsNotInRunTimeTags() { 17 | EnvironmentVariables environmentVariables = new MockEnvironmentVariables(); 18 | environmentVariables.setProperty("tags", "@my_tag_from_command_line, @my_health_coc,@another_tag_from_command_line"); 19 | assertThat(TagParser.additionalTagsSuppliedFrom(environmentVariables, asList("@smoke", "@my_health_coc", "@ManageFeatureToggles")), 20 | containsInAnyOrder("@my_tag_from_command_line", "@another_tag_from_command_line")); 21 | } 22 | 23 | @Test 24 | public void commandLineTagsAllInRunTimeTags() { 25 | EnvironmentVariables environmentVariables = new MockEnvironmentVariables(); 26 | environmentVariables.setProperty("tags", "@my_health_coc"); 27 | assertThat(TagParser.additionalTagsSuppliedFrom(environmentVariables, asList("@smoke", "@my_health_coc", "@ManageFeatureToggles")), 28 | hasSize(0)); 29 | } 30 | 31 | @Test 32 | public void noCommandLineTagsProvided() { 33 | EnvironmentVariables environmentVariables = new MockEnvironmentVariables(); 34 | assertThat(TagParser.additionalTagsSuppliedFrom(environmentVariables, asList("@smoke", "@my_health_coc", "@ManageFeatureToggles")), 35 | hasSize(0)); 36 | } 37 | } -------------------------------------------------------------------------------- /src/main/java/net/serenitybdd/cucumber/CucumberWithSerenityRuntime.java: -------------------------------------------------------------------------------- 1 | package net.serenitybdd.cucumber; 2 | 3 | 4 | import io.cucumber.core.options.RuntimeOptions; 5 | import io.cucumber.core.plugin.SerenityReporter; 6 | import io.cucumber.core.runtime.Runtime; 7 | import net.thucydides.core.guice.Injectors; 8 | import net.thucydides.core.webdriver.Configuration; 9 | 10 | import java.util.function.Supplier; 11 | 12 | 13 | public class CucumberWithSerenityRuntime { 14 | 15 | public static Runtime using(Supplier classLoaderSupplier, 16 | RuntimeOptions runtimeOptions) { 17 | Configuration systemConfiguration = Injectors.getInjector().getInstance(Configuration.class); 18 | return createSerenityEnabledRuntime(classLoaderSupplier, runtimeOptions, systemConfiguration); 19 | } 20 | 21 | 22 | private static Runtime createSerenityEnabledRuntime(Supplier classLoaderSupplier, 23 | RuntimeOptions runtimeOptions, 24 | Configuration systemConfiguration) { 25 | //ClassFinder resolvedClassFinder = Optional.ofNullable(classFinder).orElse(new ResourceLoaderClassFinder(resourceLoader, classLoader)); 26 | SerenityReporter reporter = new SerenityReporter(systemConfiguration); 27 | //Runtime runtime = Runtime.builder().withResourceLoader(resourceLoader).withClassFinder(resolvedClassFinder). 28 | // withClassLoader(classLoader).withRuntimeOptions(runtimeOptions).withAdditionalPlugins(reporter).build(); 29 | 30 | Runtime runtime = Runtime.builder(). 31 | withClassLoader(classLoaderSupplier). 32 | withRuntimeOptions(runtimeOptions). 33 | withAdditionalPlugins(reporter).build(); 34 | return runtime; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/test/groovy/net/serenitybdd/cucumber/bootstrap/WhenInstantiatingStepLibraries.groovy: -------------------------------------------------------------------------------- 1 | package net.serenitybdd.cucumber.bootstrap 2 | 3 | import net.serenitybdd.core.Serenity 4 | import net.thucydides.core.Thucydides 5 | import net.thucydides.core.annotations.Step 6 | import net.thucydides.core.annotations.Steps 7 | import net.thucydides.core.pages.PageObject 8 | import spock.lang.Specification 9 | 10 | class WhenInstantiatingStepLibraries extends Specification { 11 | 12 | 13 | static class SampleStepDefinitions { 14 | 15 | @Steps 16 | SampleSteps stepLibrary 17 | 18 | } 19 | 20 | static class SampleSteps { 21 | 22 | public SamplePageObject pageObject; 23 | 24 | @Step 25 | public void aSimpleStep() { } 26 | 27 | @Step 28 | public void anotherSimpleStep() {} 29 | } 30 | 31 | static class SamplePageObject extends PageObject {} 32 | 33 | def "the Thucydides bootstrap classes can be used to instantiate step library variables"() { 34 | given: "a step definition class containing a step library" 35 | def sampleStepDefinitions = new SampleStepDefinitions() 36 | when: "we inject the step libraries" 37 | Serenity.initialize(sampleStepDefinitions) 38 | then: "the step library field should be initialized" 39 | sampleStepDefinitions.stepLibrary != null 40 | } 41 | 42 | def "the Thucydides bootstrap classes can be used to instantiate nested page objects variables"() { 43 | given: "a step definition class containing a step library" 44 | def sampleStepDefinitions = new SampleStepDefinitions() 45 | when: "we inject the step libraries" 46 | Serenity.initialize(sampleStepDefinitions) 47 | then: "the page object field in the step library should be initialized" 48 | sampleStepDefinitions.stepLibrary.pageObject != null 49 | } 50 | } -------------------------------------------------------------------------------- /src/main/java/net/serenitybdd/cucumber/util/Splitter.java: -------------------------------------------------------------------------------- 1 | package net.serenitybdd.cucumber.util; 2 | 3 | import org.apache.commons.lang3.StringUtils; 4 | 5 | import java.util.Arrays; 6 | import java.util.List; 7 | import java.util.stream.Collectors; 8 | 9 | public class Splitter { 10 | private String separator; 11 | private boolean omitEmptyStrings = false; 12 | private boolean trimResults = false; 13 | private String trimmable = null; 14 | 15 | public Splitter(String separator) { 16 | this.separator = separator; 17 | } 18 | 19 | public static Splitter on(String separator) { 20 | return new Splitter(separator); 21 | } 22 | 23 | public Splitter omitEmptyStrings() { 24 | omitEmptyStrings = true; 25 | return this; 26 | } 27 | 28 | public Splitter trimResults() { 29 | this.trimResults = true; 30 | return this; 31 | } 32 | 33 | public Splitter trimResults(String trimmable) { 34 | this.trimResults = true; 35 | this.trimmable = trimmable; 36 | return this; 37 | } 38 | 39 | public List splitToList(String value) { 40 | String[] separatedElements = StringUtils.split(value, separator); 41 | List result = Arrays.asList(separatedElements); 42 | 43 | if (omitEmptyStrings) { 44 | result = result.stream() 45 | .filter(element -> !element.trim().equals("")) 46 | .collect(Collectors.toList()); 47 | } 48 | 49 | if (trimResults) { 50 | result = result.stream() 51 | .map(v -> StringUtils.strip(v, trimmable)) 52 | .collect(Collectors.toList()); 53 | } 54 | 55 | return result; 56 | } 57 | 58 | public static Splitter on(char separator) { 59 | return on(Character.toString(separator)); 60 | } 61 | 62 | } 63 | -------------------------------------------------------------------------------- /src/main/java/net/serenitybdd/cucumber/util/TagParser.java: -------------------------------------------------------------------------------- 1 | package net.serenitybdd.cucumber.util; 2 | 3 | import net.thucydides.core.ThucydidesSystemProperty; 4 | import net.thucydides.core.util.EnvironmentVariables; 5 | 6 | import org.apache.commons.lang3.StringUtils; 7 | 8 | import java.util.Collection; 9 | import java.util.List; 10 | import java.util.stream.Stream; 11 | 12 | import io.cucumber.tagexpressions.Expression; 13 | import io.cucumber.tagexpressions.TagExpressionParser; 14 | 15 | import static java.util.stream.Collectors.joining; 16 | import static java.util.stream.Collectors.toList; 17 | 18 | public class TagParser { 19 | 20 | public static Expression parseFromTagFilters(List stringList) { 21 | String combinedExpression = stringList.isEmpty() ? "" : stringList.stream() 22 | .filter(StringUtils::isNotEmpty) 23 | .map(tagExpression -> tagExpression.replace("~", "not ")) 24 | .collect(joining(") and (", "(", ")")); 25 | 26 | return new TagExpressionParser().parse(combinedExpression); 27 | } 28 | 29 | public static Collection additionalTagsSuppliedFrom(EnvironmentVariables environmentVariables, List existingTags) { 30 | String tagsExpression = ThucydidesSystemProperty.TAGS.from(environmentVariables, ""); 31 | return Stream.of(StringUtils.split(tagsExpression, ",")) 32 | .map(TagParser::toCucumberTag) 33 | .filter(tag -> !existingTags.contains(tag)).collect(toList()); 34 | } 35 | 36 | private static String toCucumberTag(String from) { 37 | String tag = from.trim().replaceAll(":", "="); 38 | if (tag.startsWith("~@") || tag.startsWith("@")) { 39 | return tag; 40 | } 41 | if (tag.startsWith("~")) { 42 | return "~@" + tag.substring(1); 43 | } 44 | 45 | return "@" + tag; 46 | } 47 | 48 | 49 | } 50 | -------------------------------------------------------------------------------- /src/main/java/net/serenitybdd/cucumber/suiteslicing/TestScenarioResults.java: -------------------------------------------------------------------------------- 1 | package net.serenitybdd.cucumber.suiteslicing; 2 | 3 | import net.serenitybdd.cucumber.util.BigDecimalAverageCollector; 4 | 5 | import java.math.BigDecimal; 6 | import java.util.List; 7 | 8 | import static com.google.common.collect.Lists.newArrayList; 9 | import static org.apache.commons.lang3.builder.EqualsBuilder.reflectionEquals; 10 | import static org.apache.commons.lang3.builder.HashCodeBuilder.reflectionHashCode; 11 | import static org.apache.commons.lang3.builder.ToStringBuilder.reflectionToString; 12 | 13 | public class TestScenarioResults { 14 | 15 | public final String scenarioKey; 16 | public final List durations; 17 | private final String feature; 18 | private final String scenario; 19 | 20 | public static TestScenarioResults create(TestScenarioResult testScenarioDuration) { 21 | return new TestScenarioResults(testScenarioDuration); 22 | } 23 | 24 | public void addDuration(BigDecimal duration) { 25 | durations.add(duration); 26 | } 27 | 28 | private TestScenarioResults(TestScenarioResult testScenarioResult) { 29 | this.durations = newArrayList(testScenarioResult.duration); 30 | this.scenarioKey = testScenarioResult.scenarioKey; 31 | this.feature = testScenarioResult.feature; 32 | this.scenario = testScenarioResult.scenario; 33 | } 34 | 35 | public TestScenarioResult average() { 36 | return new TestScenarioResult(feature, scenario, durations.stream().collect(BigDecimalAverageCollector.create())); 37 | } 38 | 39 | @Override 40 | public boolean equals(Object o) { 41 | return reflectionEquals(this, o); 42 | } 43 | 44 | @Override 45 | public int hashCode() { 46 | return reflectionHashCode(this); 47 | } 48 | 49 | @Override 50 | public String toString() { 51 | return reflectionToString(this); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/main/java/net/serenitybdd/cucumber/formatting/ScenarioOutlineDescription.java: -------------------------------------------------------------------------------- 1 | package net.serenitybdd.cucumber.formatting; 2 | 3 | import io.cucumber.core.internal.gherkin.ast.ScenarioDefinition; 4 | import io.cucumber.core.internal.gherkin.ast.Step; 5 | import io.cucumber.core.internal.gherkin.ast.TableCell; 6 | import io.cucumber.core.internal.gherkin.ast.TableRow; 7 | 8 | import java.util.stream.Collectors; 9 | 10 | public class ScenarioOutlineDescription { 11 | private final ScenarioDefinition scenario; 12 | 13 | public ScenarioOutlineDescription(ScenarioDefinition scenario) { 14 | this.scenario = scenario; 15 | } 16 | 17 | public static ScenarioOutlineDescription from(ScenarioDefinition scenario) { 18 | return new ScenarioOutlineDescription(scenario); 19 | } 20 | 21 | public String getDescription() { 22 | return scenario.getSteps().stream().map( 23 | step -> stepToString(step) 24 | ).collect(Collectors.joining(System.lineSeparator())); 25 | } 26 | 27 | private String stepToString(Step step) { 28 | String phrase = step.getKeyword() + step.getText(); 29 | 30 | if ((step.getArgument() != null) && (step.getArgument().getClass().isAssignableFrom(io.cucumber.core.internal.gherkin.ast.DataTable.class))) { 31 | io.cucumber.core.internal.gherkin.ast.DataTable table = (io.cucumber.core.internal.gherkin.ast.DataTable) step.getArgument(); 32 | String tableAsString = ""; 33 | for (TableRow row : table.getRows()) { 34 | tableAsString += "|"; 35 | tableAsString += row.getCells().stream() 36 | .map(TableCell::getValue) 37 | .collect(Collectors.joining(" | ")); 38 | tableAsString += "|" + System.lineSeparator(); 39 | } 40 | 41 | phrase = phrase + System.lineSeparator() + tableAsString.trim(); 42 | } 43 | 44 | return phrase; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/main/java/net/serenitybdd/cucumber/suiteslicing/ScenarioFilter.java: -------------------------------------------------------------------------------- 1 | package net.serenitybdd.cucumber.suiteslicing; 2 | 3 | import org.junit.runner.Description; 4 | import org.junit.runner.manipulation.Filter; 5 | import org.slf4j.Logger; 6 | import org.slf4j.LoggerFactory; 7 | 8 | import java.util.List; 9 | 10 | import static com.google.common.collect.Lists.newArrayList; 11 | 12 | public class ScenarioFilter extends Filter { 13 | 14 | private static final Logger LOGGER = LoggerFactory.getLogger(ScenarioFilter.class); 15 | private List scenarios; 16 | private List scenariosIncluded = newArrayList(); 17 | private List scenariosExcluded = newArrayList(); 18 | 19 | private ScenarioFilter(List scenarios) { 20 | this.scenarios = scenarios; 21 | } 22 | 23 | public static ScenarioFilter onScenarios(List scenarios) { 24 | return new ScenarioFilter(scenarios); 25 | } 26 | 27 | @Override 28 | public String describe() { 29 | return String.format("Filters out all test steps except those in the list of scenarios: %s", scenarios); 30 | } 31 | 32 | @Override 33 | public boolean shouldRun(Description description) { 34 | String displayName = description.getDisplayName(); 35 | String methodName = description.getMethodName(); 36 | boolean shouldRun = scenarios.stream().anyMatch(methodName::equals) || displayName.startsWith("Examples") || displayName.contains("|"); 37 | LOGGER.debug("Test should run: {} step: {}", shouldRun, description.getDisplayName()); 38 | if (shouldRun) { 39 | scenariosIncluded.add(displayName); 40 | } else { 41 | scenariosExcluded.add(displayName); 42 | } 43 | return shouldRun; 44 | } 45 | 46 | public List scenariosExcluded() { 47 | return scenariosExcluded; 48 | } 49 | 50 | public List scenariosIncluded() { 51 | return scenariosIncluded; 52 | } 53 | } -------------------------------------------------------------------------------- /src/smoketests/src/test/resources/features/skipped_pending_and_manual_scenarios/when_skipping_scenarios.feature: -------------------------------------------------------------------------------- 1 | @driver:htmlunit 2 | Feature: Marking scenarios as pending, skipped or ignored 3 | 4 | @expected-outcome:success 5 | Scenario: A simple passing scenario 6 | Given I want to search for something 7 | When I lookup pear 8 | Then I should see "pear at DuckDuckGo" in the page title 9 | 10 | @skip 11 | @expected-outcome:skip 12 | Scenario: Skipping a scenario using the @skip annotation 13 | Steps in the scenario will be reported as 'ignored' 14 | 15 | Given I want to search for something 16 | When I lookup apple 17 | Then I should see "apple at DuckDuckGo" in the page title 18 | 19 | @ignore 20 | @expected-outcome:ignore 21 | Scenario: Ignoring a scenario 22 | You can also ignore an entire scenario, which is a bit like skipping it 23 | Given I want to search for something 24 | When I lookup apple 25 | Then I should see "apple at DuckDuckGo" in the page title 26 | 27 | @pending 28 | @expected-outcome:pending 29 | Scenario: You mark a scenario as pending using the @pending annotation 30 | Pending scenarios are meant to indicate a scenario that has not been completed yet. 31 | Given I want to search for something 32 | When I lookup apple 33 | Then I should see "apple at DuckDuckGo" in the page title 34 | 35 | @expected-outcome:pending 36 | Scenario: A scenario with no step definitions will be marked as pending by default 37 | When I use a step that has no step definition 38 | Then the step without a step definition should be pending 39 | And subsequent steps should be ignored 40 | 41 | @skip 42 | @expected-outcome:skip 43 | Scenario: You can mark a scenario with no step definitions as @skipped 44 | When I use a step that has no step definition 45 | And I tag the scenario with @Skip 46 | Then the overall result should be skipped 47 | Then the steps without a step definition should be pending 48 | And subsequent steps should be ignored 49 | -------------------------------------------------------------------------------- /src/smoketests/src/test/java/smoketests/stepdefinitions/LifecycleStepDefinitions.java: -------------------------------------------------------------------------------- 1 | package smoketests.stepdefinitions; 2 | 3 | import cucumber.api.java.en.Given; 4 | import cucumber.api.java.en.Then; 5 | import cucumber.api.java.en.When; 6 | import net.thucydides.core.annotations.Step; 7 | import net.thucydides.core.annotations.Steps; 8 | 9 | import static org.assertj.core.api.Assertions.assertThat; 10 | 11 | public class LifecycleStepDefinitions { 12 | 13 | static class Calculations { 14 | 15 | @Steps 16 | Prep prep; 17 | 18 | int total = 0; 19 | 20 | @Step 21 | public void add(int amount) { 22 | prep.prepareTheCalculator(); 23 | total += amount; 24 | } 25 | 26 | @Step 27 | public void substract(int amount) { 28 | total -= amount; 29 | } 30 | 31 | public int getTotal() { return total; } 32 | 33 | } 34 | 35 | 36 | static class Prep { 37 | @Step 38 | public void prepareTheCalculator() {} 39 | } 40 | 41 | @Steps 42 | Calculations calculations; 43 | 44 | @Given("I have a calculator") 45 | public void givenIHaveACalculator() { 46 | } 47 | 48 | @Given("I have an odd number") 49 | public void givenIHaveAnOddNumber() { 50 | } 51 | 52 | @Then("the result should be should be odd: (.*)") 53 | public void shouldBeOdd(boolean isOdd) { 54 | 55 | } 56 | 57 | @Given("I add {int}") 58 | public void givenIAdd(int amount) { 59 | calculations.add(amount); 60 | } 61 | 62 | @When("I substract {int}") 63 | public void whenISubstract(int amount) { 64 | calculations.substract(amount); 65 | } 66 | 67 | @Then("the total should be {int}") 68 | public void thenTheTotalShouldBe(int total) { 69 | assertThat(calculations.total).isEqualTo(total); 70 | } 71 | 72 | @Then("the total should not be zero") 73 | public void thenTheTotalShouldNotBeZero() { 74 | assertThat(calculations.total).isNotZero(); 75 | } 76 | 77 | } 78 | -------------------------------------------------------------------------------- /src/test/java/net/serenitybdd/cucumber/suiteslicing/WeightedCucumberScenariosTest.java: -------------------------------------------------------------------------------- 1 | package net.serenitybdd.cucumber.suiteslicing; 2 | 3 | import org.junit.Test; 4 | 5 | import java.math.BigDecimal; 6 | import java.util.Collections; 7 | import java.util.List; 8 | 9 | import static java.util.Collections.emptySet; 10 | import static org.hamcrest.collection.IsCollectionWithSize.hasSize; 11 | import static org.hamcrest.core.Is.is; 12 | import static org.junit.Assert.assertThat; 13 | import static org.junit.Assert.fail; 14 | 15 | public class WeightedCucumberScenariosTest { 16 | 17 | @Test 18 | public void slicingMoreThinlyThanTheNumberOfScenariosShouldResultInSomeEmptySlices() { 19 | WeightedCucumberScenario weightedCucumberScenario = new WeightedCucumberScenario("test.feature", "featurename", "scenarioname", BigDecimal.ONE, emptySet(), 0); 20 | List scenarios = Collections.singletonList(weightedCucumberScenario); 21 | WeightedCucumberScenarios oneScenario = new WeightedCucumberScenarios(scenarios); 22 | List weightedCucumberScenarios = oneScenario.sliceInto(100); 23 | assertThat(weightedCucumberScenarios, hasSize(100)); 24 | assertThat(weightedCucumberScenarios.get(0).scenarios, hasSize(1)); 25 | assertThat(weightedCucumberScenarios.get(0).scenarios.get(0), is(weightedCucumberScenario)); 26 | assertThat(weightedCucumberScenarios.get(1).scenarios, hasSize(0)); 27 | assertThat(weightedCucumberScenarios.get(99).scenarios, hasSize(0)); 28 | } 29 | 30 | @Test 31 | public void slicingASliceIntoOneSliceOfOneShouldBeTheSameAsAllScenarios() { 32 | List scenarios = Collections.singletonList(new WeightedCucumberScenario("test.feature", "featurename", "scenarioname", BigDecimal.ONE, emptySet(), 0)); 33 | WeightedCucumberScenarios oneScenario = new WeightedCucumberScenarios(scenarios); 34 | WeightedCucumberScenarios fork1 = oneScenario.slice(1).of(1); 35 | assertThat(oneScenario, is(fork1)); 36 | } 37 | 38 | } -------------------------------------------------------------------------------- /src/main/java/net/serenitybdd/cucumber/model/StoredFeatureFile.java: -------------------------------------------------------------------------------- 1 | package net.serenitybdd.cucumber.model; 2 | 3 | import net.serenitybdd.cucumber.CucumberWithSerenity; 4 | 5 | import java.io.File; 6 | import java.io.IOException; 7 | import java.net.URI; 8 | import java.net.URL; 9 | import java.nio.file.Files; 10 | import java.nio.file.Path; 11 | import java.nio.file.Paths; 12 | import java.util.stream.Collectors; 13 | import java.util.stream.Stream; 14 | 15 | public class StoredFeatureFile { 16 | 17 | private final String featureFileName; 18 | 19 | public StoredFeatureFile(String featureFileName) { 20 | 21 | this.featureFileName = featureFileName; 22 | } 23 | 24 | public URL asAClasspathResource() { 25 | return StoredFeatureFile.class.getClassLoader().getResource(featureFileName); 26 | } 27 | 28 | public boolean existsOnTheClasspath() { 29 | return (asAClasspathResource() != null); 30 | } 31 | 32 | public static StoredFeatureFile withName(String featureFileName) { 33 | return new StoredFeatureFile(featureFileName); 34 | } 35 | 36 | public File onTheClasspath() { 37 | return new File(asAClasspathResource().getFile()); 38 | } 39 | 40 | public boolean existsOnTheFileSystem() { 41 | return Files.exists(Paths.get(featureFileName)); 42 | } 43 | 44 | public File onTheFileSystem() { 45 | return Paths.get(featureFileName).toFile(); 46 | } 47 | 48 | 49 | public File fromTheConfiguredPaths() throws IOException { 50 | for(URI uri : CucumberWithSerenity.currentRuntimeOptions().getFeaturePaths()) { 51 | if (Files.exists(candidatePath(uri, featureFileName))) { 52 | return candidatePath(uri, featureFileName).toFile(); 53 | } 54 | } 55 | throw new IOException("No such feature file found for " + featureFileName); 56 | } 57 | 58 | private Path candidatePath(URI uri, String featureFileName) { 59 | return Paths.get(Stream.of(uri.getPath(), featureFileName).collect(Collectors.joining(File.separator))); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/test/java/net/serenitybdd/cucumber/suiteslicing/MatchingCucumberScenario.java: -------------------------------------------------------------------------------- 1 | package net.serenitybdd.cucumber.suiteslicing; 2 | 3 | import org.hamcrest.Description; 4 | import org.hamcrest.TypeSafeMatcher; 5 | 6 | import java.util.HashSet; 7 | import java.util.Set; 8 | 9 | import static java.util.Arrays.asList; 10 | 11 | 12 | public class MatchingCucumberScenario extends TypeSafeMatcher { 13 | 14 | private String featurePath; 15 | private String feature; 16 | private String scenario; 17 | private Set tags; 18 | 19 | private MatchingCucumberScenario() { 20 | } 21 | 22 | public static MatchingCucumberScenario with() { 23 | return new MatchingCucumberScenario(); 24 | } 25 | 26 | public MatchingCucumberScenario featurePath(String featurePath) { 27 | this.featurePath = featurePath; 28 | return this; 29 | } 30 | 31 | public MatchingCucumberScenario feature(String feature) { 32 | this.feature = feature; 33 | return this; 34 | } 35 | 36 | public MatchingCucumberScenario scenario(String scenario) { 37 | this.scenario = scenario; 38 | return this; 39 | } 40 | 41 | @Override 42 | protected boolean matchesSafely(WeightedCucumberScenario weightedCucumberScenario) { 43 | return (feature == null || feature.equals(weightedCucumberScenario.feature)) && 44 | (featurePath == null || featurePath.equals(weightedCucumberScenario.featurePath)) && 45 | (scenario == null || scenario.equals(weightedCucumberScenario.scenario)) && 46 | (tags == null || tags.equals(weightedCucumberScenario.tags)); 47 | } 48 | 49 | @Override 50 | public void describeTo(Description description) { 51 | description.appendText("A WeightedCucumberScenario matching: featurePath: " + featurePath + 52 | ", feature: " + feature); 53 | } 54 | 55 | public MatchingCucumberScenario tags(String... tags) { 56 | this.tags = new HashSet<>(asList(tags)); 57 | return this; 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/test/java/net/serenitybdd/cucumber/util/StepDefinitionAnnotationReaderTest.java: -------------------------------------------------------------------------------- 1 | package net.serenitybdd.cucumber.util; 2 | 3 | import net.thucydides.core.model.TakeScreenshots; 4 | import org.junit.Test; 5 | 6 | import static org.assertj.core.api.Assertions.assertThat; 7 | 8 | public class StepDefinitionAnnotationReaderTest { 9 | 10 | @Test 11 | public void should_read_annotations_from_a_step_definition_method_name() { 12 | assertThat( 13 | StepDefinitionAnnotationReader 14 | .forStepDefinition("net.serenitybdd.cucumber.util.SampleStepDefinitions.aStepDefinitionWithAScreenshotAnnotation()") 15 | .getScreenshotPreferences() 16 | ).isEqualTo(TakeScreenshots.DISABLED); 17 | } 18 | 19 | @Test 20 | public void should_read_annotations_from_a_parameterised_step_definition_method_name() { 21 | assertThat( 22 | StepDefinitionAnnotationReader 23 | .forStepDefinition("net.serenitybdd.cucumber.util.SampleStepDefinitions.aStepDefinitionWithAParameter(java.lang.String)") 24 | .getScreenshotPreferences() 25 | ).isEqualTo(TakeScreenshots.DISABLED); 26 | } 27 | 28 | @Test 29 | public void screenshot_preference_is_undefined_if_no_annotation_is_present() { 30 | assertThat( 31 | StepDefinitionAnnotationReader 32 | .forStepDefinition("net.serenitybdd.cucumber.util.SampleStepDefinitions.aStepDefinitionWithNoScreenshotAnnotation()") 33 | .getScreenshotPreferences() 34 | ).isEqualTo(TakeScreenshots.UNDEFINED); 35 | } 36 | @Test 37 | public void screenshot_preference_is_before_and_after_each_step_by_default_if_no_annotation_is_present() { 38 | assertThat( 39 | StepDefinitionAnnotationReader 40 | .forStepDefinition("net.serenitybdd.cucumber.util.SampleStepDefinitions.aStepDefinitionWithAScreenshotAnnotationWithNoAttribute()") 41 | .getScreenshotPreferences() 42 | ).isEqualTo(TakeScreenshots.BEFORE_AND_AFTER_EACH_STEP); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/test/groovy/net/serenitybdd/cucumber/outcomes/WhenWorkingWithTaggedExampleTables.groovy: -------------------------------------------------------------------------------- 1 | package net.serenitybdd.cucumber.outcomes 2 | 3 | import net.serenitybdd.cucumber.integration.* 4 | import net.thucydides.core.model.TestOutcome 5 | import net.thucydides.core.model.TestResult 6 | import net.thucydides.core.reports.OutcomeFormat 7 | import net.thucydides.core.reports.TestOutcomeLoader 8 | import org.junit.Rule 9 | import org.junit.rules.TemporaryFolder 10 | import spock.lang.Specification 11 | 12 | import static io.cucumber.junit.CucumberRunner.serenityRunnerForCucumberTestRunner 13 | import static net.thucydides.core.model.TestResult.* 14 | 15 | class WhenWorkingWithTaggedExampleTables extends Specification { 16 | 17 | @Rule 18 | TemporaryFolder temporaryFolder 19 | 20 | File outputDirectory 21 | 22 | def setup() { 23 | outputDirectory = temporaryFolder.newFolder() 24 | } 25 | 26 | /* 27 | Scenario Outline: Buying lots of widgets 28 | Given I want to purchase widgets 29 | And a widget costs $ 30 | When I buy the widgets 31 | Then I should be billed $ 32 | Examples: 33 | | amount | cost | total | 34 | | 0 | 10 | 0 | 35 | | 1 | 10 | 10 | 36 | | 2 | 10 | 20 | 37 | | 2 | 0 | 0 | 38 | */ 39 | def "should run table-driven scenarios with tagged example tables"() { 40 | given: 41 | def runtime = serenityRunnerForCucumberTestRunner(TaggedExampleTablesScenarios.class, outputDirectory); 42 | 43 | when: 44 | runtime.run(); 45 | def recordedTestOutcomes = new TestOutcomeLoader().forFormat(OutcomeFormat.JSON).loadFrom(outputDirectory); 46 | 47 | then: "there should a test outcome for each scenario" 48 | recordedTestOutcomes.size() == 1 49 | and: "line numbers should be recorded for each executed example" 50 | def testOutcome = recordedTestOutcomes[0] 51 | testOutcome.testSteps[0].lineNumber == 12 && testOutcome.testSteps[1].lineNumber == 13 52 | } 53 | 54 | 55 | } -------------------------------------------------------------------------------- /src/smoketests/src/test/resources/features/understanding_serenity_steps/when_using_step_libraries.feature: -------------------------------------------------------------------------------- 1 | Feature: Serenity automatically instantiates step libraries 2 | 3 | @expected-outcome:success 4 | Scenario: Serenity automatically instantiates step library fields in step definition classes 5 | Given I want to use a step library 6 | When I use a step library field annotated with @Steps 7 | Then Serenity should instantiate the field 8 | 9 | @expected-outcome:success 10 | Scenario: Serenity instantiates different step libraries for each field by default 11 | Given I want to use several step library fields of the same type 12 | When I use a step library fields to each of them 13 | Then Serenity should instantiate a different library for each field 14 | 15 | @expected-outcome:success 16 | Scenario: Serenity creates new step library instances for each new scenario 17 | Given I have a Serenity step library 18 | When I start a new scenario 19 | Then the step library should be reinitialised 20 | 21 | @expected-outcome:success 22 | Scenario: You can share step library instances using @Steps with shared=true 23 | Given I have two Serenity step libraries 24 | When they are annotated with @Steps(shared=true) 25 | Then both should refer to the same instance 26 | 27 | @expected-outcome:success 28 | Scenario: You can share step library instances using @Shared 29 | Given I have two @Shared Serenity step libraries 30 | When they are annotated with @Shared 31 | Then they should be reset between scenarios 32 | 33 | @expected-outcome:success 34 | Scenario: Shared scenarios should be reset between scenarios 35 | Given I have two @Shared Serenity step libraries 36 | When they are annotated with @Shared 37 | Then they should be reset between scenarios 38 | 39 | @expected-outcome:success 40 | Scenario Outline: You can share step library instances using @Shared in scenario outlines 41 | Given I have two @Shared Serenity step libraries 42 | When they are annotated with @Shared 43 | Then they should be reset between scenario examples 44 | Examples: 45 | | example | 46 | | 1 | 47 | | 2 | 48 | | 3 | -------------------------------------------------------------------------------- /src/test/java/net/serenitybdd/cucumber/suiteslicing/ScenarioLineCountStatisticsTest.java: -------------------------------------------------------------------------------- 1 | package net.serenitybdd.cucumber.suiteslicing; 2 | 3 | import org.junit.Before; 4 | import org.junit.Test; 5 | 6 | import java.math.BigDecimal; 7 | import java.net.URI; 8 | import java.net.URISyntaxException; 9 | 10 | import static com.google.common.collect.Lists.newArrayList; 11 | import static org.hamcrest.Matchers.is; 12 | import static org.junit.Assert.assertThat; 13 | 14 | public class ScenarioLineCountStatisticsTest { 15 | 16 | ScenarioLineCountStatistics stats; 17 | 18 | @Before 19 | public void setup() { 20 | try { 21 | stats = ScenarioLineCountStatistics.fromFeaturePath(new URI("classpath:samples")); 22 | } catch (URISyntaxException e) { 23 | e.printStackTrace(); 24 | } 25 | 26 | } 27 | 28 | @Test 29 | public void scenarioWeightForScenario() { 30 | assertThat(stats.scenarioWeightFor("A simple feature", "A simple scenario"), is(new BigDecimal("4"))); 31 | } 32 | 33 | @Test 34 | public void scenarioWeightForScenarioOutline() { 35 | assertThat(stats.scenarioWeightFor("A simple feature that fails", "A simple failing scenario outline"), is(new BigDecimal("8"))); 36 | } 37 | 38 | @Test 39 | public void scenarioWeightForScenarioWithBackground() { 40 | assertThat(stats.scenarioWeightFor("Locate a customer by personal details and Reg Number", "Locating a customer using a unique criterion"), is(new BigDecimal("4"))); 41 | } 42 | 43 | @Test 44 | public void scenarioWeightForScenarioWithBackgroundAndScenarioOutline() { 45 | assertThat(stats.scenarioWeightFor("Buying things - with tables", "Buying more widgets"), is(new BigDecimal("15"))); 46 | } 47 | 48 | @Test 49 | public void scenarioWeightForScenarioOutlineWithMultipleExamples() { 50 | assertThat(stats.scenarioWeightFor("Buying things - with tables", "Buying lots of widgets"), is(new BigDecimal("35"))); 51 | } 52 | 53 | @Test 54 | public void scenarioWeightForScenarioWithBackgroundAndScenario() { 55 | assertThat(stats.scenarioWeightFor("Locate a customer by personal details and Reg Number", "Locating a customer using a unique criterion"), is(new BigDecimal("4"))); 56 | } 57 | 58 | } -------------------------------------------------------------------------------- /src/test/java/net/serenitybdd/cucumber/suiteslicing/CucumberSuiteSlicerTest.java: -------------------------------------------------------------------------------- 1 | package net.serenitybdd.cucumber.suiteslicing; 2 | 3 | 4 | import org.junit.Before; 5 | import org.junit.Test; 6 | 7 | import java.net.URI; 8 | 9 | import static java.util.Arrays.asList; 10 | import static org.hamcrest.Matchers.contains; 11 | import static org.junit.Assert.assertThat; 12 | 13 | public class CucumberSuiteSlicerTest { 14 | 15 | private TestStatistics testStatistics; 16 | private CucumberSuiteSlicer cucumberSuiteSlicer; 17 | MatchingCucumberScenario expectedScenario1; 18 | MatchingCucumberScenario expectedScenario2; 19 | 20 | @Before 21 | public void setup() throws Exception { 22 | testStatistics = new DummyStatsOfWeightingOne(); 23 | cucumberSuiteSlicer = new CucumberSuiteSlicer(asList(new URI("classpath:samples/simple_table_based_scenario.feature")), testStatistics); 24 | expectedScenario1 = MatchingCucumberScenario.with() 25 | .featurePath("simple_table_based_scenario.feature") 26 | .feature("Buying things - with tables") 27 | .scenario("Buying lots of widgets") 28 | .tags("@shouldPass"); 29 | 30 | expectedScenario2 = MatchingCucumberScenario.with() 31 | .featurePath("simple_table_based_scenario.feature") 32 | .feature("Buying things - with tables") 33 | .scenario("Buying more widgets"); 34 | } 35 | 36 | @Test 37 | public void shouldReturnOnlyScenariosWithSpecifiedTags() { 38 | assertThat(cucumberSuiteSlicer.scenarios(1, 1, 1, 1, asList("@shouldPass")).scenarios, contains(expectedScenario1)); 39 | } 40 | 41 | @Test 42 | public void noSuppliedTagsMeansReturnAllScenarios() { 43 | assertThat(cucumberSuiteSlicer.scenarios(1, 1, 1, 1, asList()).scenarios, contains(expectedScenario1, expectedScenario2)); 44 | } 45 | 46 | @Test 47 | public void shouldSupportNotInTheTagExpression() { 48 | assertThat(cucumberSuiteSlicer.scenarios(1, 1, 1, 1, asList("not @shouldPass")).scenarios, contains(expectedScenario2)); 49 | } 50 | @Test 51 | public void shouldSupportOldExclusionSyntaxInTheTagExpression() { 52 | assertThat(cucumberSuiteSlicer.scenarios(1, 1, 1, 1, asList("~@shouldPass")).scenarios, contains(expectedScenario2)); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/test/java/net/serenitybdd/cucumber/integration/steps/RpnCalculatorStepdefs.java: -------------------------------------------------------------------------------- 1 | package net.serenitybdd.cucumber.integration.steps; 2 | 3 | import io.cucumber.java.After; 4 | import io.cucumber.java.Before; 5 | import io.cucumber.java.Scenario; 6 | import io.cucumber.java.en.Given; 7 | import io.cucumber.java.en.Then; 8 | import io.cucumber.java.en.When; 9 | import samples.calculator.RpnCalculator; 10 | 11 | import java.util.List; 12 | 13 | import static org.junit.Assert.assertEquals; 14 | 15 | public class RpnCalculatorStepdefs { 16 | private RpnCalculator calc; 17 | 18 | @Given("^a calculator I just turned on$") 19 | public void a_calculator_I_just_turned_on() { 20 | calc = new RpnCalculator(); 21 | } 22 | 23 | @When("^I add (\\d+) and (\\d+)$") 24 | public void adding(int arg1, int arg2) { 25 | calc.push(arg1); 26 | calc.push(arg2); 27 | calc.push("+"); 28 | } 29 | 30 | @Given("^I press (.+)$") 31 | public void I_press(String what) { 32 | calc.push(what); 33 | } 34 | 35 | @Then("^the result is (\\d+)$") 36 | public void the_result_is(Integer expected) { 37 | System.out.println("Expecting a result of " + expected); 38 | assertEquals(expected, calc.value()); 39 | } 40 | 41 | // @Before({"~@foo"}) 42 | @Before 43 | public void before(Scenario scenario) { 44 | // scenario.write("Some special text"); 45 | // int i = 0; 46 | } 47 | 48 | @After 49 | public void after(Scenario scenario) { 50 | } 51 | 52 | @Given("^the previous entries:$") 53 | public void thePreviousEntries(List entries) { 54 | for (Entry entry : entries) { 55 | calc.push(entry.first); 56 | calc.push(entry.second); 57 | calc.push(entry.operation); 58 | } 59 | } 60 | 61 | @When("^I enter (\\d+) and (\\d+)$") 62 | public void entering(int arg1, int arg2) { 63 | calc.push(arg1); 64 | calc.push(arg2); 65 | } 66 | 67 | 68 | public static class Entry { 69 | Integer first; 70 | Integer second; 71 | String operation; 72 | 73 | public Entry(Integer first, Integer second, String operation){ 74 | this.first = first; 75 | this.second = second; 76 | this.operation = operation; 77 | } 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /src/main/java/net/serenitybdd/cucumber/integration/intellij/CucumberWithSerenityRuntimeMain.java: -------------------------------------------------------------------------------- 1 | package net.serenitybdd.cucumber.integration.intellij; 2 | 3 | import io.cucumber.core.options.CommandlineOptionsParser; 4 | import io.cucumber.core.options.RuntimeOptions; 5 | import io.cucumber.core.resource.ClassLoaders; 6 | import io.cucumber.core.runtime.Runtime; 7 | import net.serenitybdd.cucumber.CucumberWithSerenity; 8 | import net.thucydides.core.guice.Injectors; 9 | import net.thucydides.core.webdriver.Configuration; 10 | 11 | import java.io.IOException; 12 | import java.util.function.Supplier; 13 | 14 | 15 | /** 16 | * A test runner that allows you to run feature files directly from IntelliJ. 17 | * This avoids having to write specific runners for each feature file. 18 | * Contributed by Vladimir Ivanov 19 | * Deprecated: Replaced with cucumber.runtime.cli.Main 20 | */ 21 | @Deprecated 22 | public class CucumberWithSerenityRuntimeMain { 23 | public static void main(String[] argv) throws Throwable { 24 | 25 | Supplier classLoader = ClassLoaders::getDefaultClassLoader; 26 | //byte exitStatus = run(argv, Thread.currentThread().getContextClassLoader()); 27 | byte exitStatus = run(argv, classLoader); 28 | System.exit(exitStatus); 29 | } 30 | 31 | /** 32 | * Launches the Cucumber-JVM command line 33 | * @param argv runtime options. See details in the {@code cucumber.api.cli.Usage.txt} resource 34 | * @param classLoaderSupplier classloader used to load the runtime 35 | * @return 0 if execution was successful, 1 if not (there were test failures) 36 | * @throws IOException if resources couldn't be loaded during execution 37 | */ 38 | public static byte run(String[] argv, Supplier classLoaderSupplier) throws IOException { 39 | 40 | RuntimeOptions runtimeOptions = new CommandlineOptionsParser().parse(argv).build() ; 41 | 42 | //ResourceLoader resourceLoader = new MultiLoader(classLoader); 43 | Configuration systemConfiguration = Injectors.getInjector().getInstance(Configuration.class); 44 | //Supplier classLoader = ClassLoaders::getDefaultClassLoader; 45 | Runtime serenityRuntime = CucumberWithSerenity.createSerenityEnabledRuntime(/*resourceLoader,*/ 46 | classLoaderSupplier, 47 | runtimeOptions, 48 | systemConfiguration); 49 | 50 | serenityRuntime.run(); 51 | 52 | return serenityRuntime.exitStatus(); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/main/java/net/serenitybdd/cucumber/suiteslicing/SerenityTags.java: -------------------------------------------------------------------------------- 1 | package net.serenitybdd.cucumber.suiteslicing; 2 | 3 | import net.thucydides.core.guice.Injectors; 4 | import net.thucydides.core.model.TestTag; 5 | import net.thucydides.core.steps.StepEventBus; 6 | 7 | import net.thucydides.core.util.EnvironmentVariables; 8 | import org.slf4j.Logger; 9 | import org.slf4j.LoggerFactory; 10 | 11 | import java.util.Optional; 12 | import java.util.function.Consumer; 13 | 14 | import static com.google.common.collect.Lists.newArrayList; 15 | import static java.util.Optional.empty; 16 | import static net.thucydides.core.ThucydidesSystemProperty.*; 17 | 18 | public class SerenityTags { 19 | 20 | private static final Logger LOGGER = LoggerFactory.getLogger(SerenityTags.class); 21 | 22 | private final String TEST_BATCH = "test batch"; 23 | private final String TEST_FORK = "test fork"; 24 | 25 | private final EnvironmentVariables environmentVariables; 26 | 27 | private SerenityTags() { 28 | environmentVariables = Injectors.getInjector().getInstance(EnvironmentVariables.class); 29 | } 30 | 31 | public static SerenityTags create() { 32 | return new SerenityTags(); 33 | } 34 | 35 | public Optional batches() { 36 | Integer batchNumber = environmentVariables.getPropertyAsInteger(SERENITY_BATCH_NUMBER, 0); 37 | return numberedTagFor(batchNumber, "batch", TEST_BATCH); 38 | } 39 | 40 | public Optional forks() { 41 | Integer forkNumber = environmentVariables.getPropertyAsInteger(SERENITY_FORK_NUMBER, 0); 42 | return numberedTagFor(forkNumber, "fork", TEST_FORK); 43 | } 44 | 45 | private static Optional numberedTagFor(Integer value, String shardType, String tagType) { 46 | return (shardType.isEmpty() || (value == 0)) ? empty() : Optional.of(TestTag.withName(String.format("%s %s", shardType, value)).andType(tagType)); 47 | } 48 | 49 | public void tagScenarioWithBatchingInfo() { 50 | batches().ifPresent(addTag()); 51 | forks().ifPresent(addTag()); 52 | } 53 | 54 | private Consumer addTag() { 55 | return this::addTagWith; 56 | } 57 | 58 | public void addTagWith(TestTag tag) { 59 | LOGGER.info("adding tag to {} scenario", tag); 60 | StepEventBus.getEventBus().addTagsToCurrentStory(newArrayList(tag)); 61 | } 62 | 63 | public void addTagWith(String tagName, String tagType) { 64 | addTagWith(TestTag.withName(tagName).andType(tagType)); 65 | } 66 | 67 | } -------------------------------------------------------------------------------- /src/main/java/io/cucumber/core/plugin/FeatureFileLoader.java: -------------------------------------------------------------------------------- 1 | package io.cucumber.core.plugin; 2 | 3 | import io.cucumber.core.internal.gherkin.ast.Feature; 4 | import io.cucumber.plugin.event.TestSourceRead; 5 | import net.thucydides.core.util.Inflector; 6 | import org.slf4j.Logger; 7 | import org.slf4j.LoggerFactory; 8 | 9 | import java.io.File; 10 | import java.net.URI; 11 | import java.util.Optional; 12 | 13 | import static org.apache.commons.lang3.StringUtils.isEmpty; 14 | 15 | public class FeatureFileLoader { 16 | 17 | private final TestSourcesModel testSources = new TestSourcesModel(); 18 | 19 | private static final Logger LOGGER = LoggerFactory.getLogger(FeatureFileLoader.class); 20 | 21 | private Optional featureFrom(URI featureFileUri) { 22 | 23 | String defaultFeatureId = new File(featureFileUri).getName().replace(".feature", ""); 24 | String defaultFeatureName = Inflector.getInstance().humanize(defaultFeatureId); 25 | 26 | parseGherkinIn(featureFileUri); 27 | 28 | if (isEmpty(testSources.getFeature(featureFileUri).getName())) { 29 | return Optional.empty(); 30 | } 31 | 32 | Feature feature = testSources.getFeature(featureFileUri); 33 | if (feature.getName().isEmpty()) { 34 | feature = featureWithDefaultName(feature, defaultFeatureName); 35 | } 36 | return Optional.of(feature); 37 | } 38 | 39 | private void parseGherkinIn(URI featureFileUri) { 40 | try { 41 | testSources.getFeature(featureFileUri); 42 | } catch (Throwable ignoreParsingErrors) { 43 | LOGGER.warn("Could not parse the Gherkin in feature file " + featureFileUri + ": file ignored"); 44 | } 45 | } 46 | 47 | public Feature featureWithDefaultName(Feature feature, String defaultName) { 48 | return new Feature(feature.getTags(), 49 | feature.getLocation(), 50 | feature.getLanguage(), 51 | feature.getKeyword(), 52 | defaultName, 53 | feature.getDescription(), 54 | feature.getChildren()); 55 | } 56 | 57 | public void addTestSourceReadEvent(TestSourceRead event) { 58 | testSources.addTestSourceReadEvent(event.getUri(), event); 59 | } 60 | 61 | public String getFeatureName(URI featureFileUri) { 62 | return testSources.getFeature(featureFileUri).getName(); 63 | } 64 | 65 | public Feature getFeature(URI featureFileUri) { 66 | return testSources.getFeature(featureFileUri); 67 | } 68 | 69 | TestSourcesModel.AstNode getAstNode(URI path, int line) { 70 | return testSources.getAstNode(path,line); 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /src/main/java/net/serenitybdd/cucumber/util/BigDecimalAverageCollector.java: -------------------------------------------------------------------------------- 1 | package net.serenitybdd.cucumber.util; 2 | 3 | import java.math.BigDecimal; 4 | import java.util.Collections; 5 | import java.util.Set; 6 | import java.util.function.BiConsumer; 7 | import java.util.function.BinaryOperator; 8 | import java.util.function.Function; 9 | import java.util.function.Supplier; 10 | import java.util.stream.Collector; 11 | 12 | public class BigDecimalAverageCollector implements Collector { 13 | 14 | private BigDecimalAverageCollector() { 15 | } 16 | 17 | public static BigDecimalAverageCollector create() { 18 | return new BigDecimalAverageCollector(); 19 | } 20 | 21 | @Override 22 | public Supplier supplier() { 23 | return BigDecimalAccumulator::new; 24 | } 25 | 26 | @Override 27 | public BiConsumer accumulator() { 28 | return BigDecimalAccumulator::add; 29 | } 30 | 31 | @Override 32 | public BinaryOperator combiner() { 33 | return BigDecimalAccumulator::combine; 34 | } 35 | 36 | @Override 37 | public Function finisher() { 38 | return BigDecimalAccumulator::getAverage; 39 | } 40 | 41 | @Override 42 | public Set characteristics() { 43 | return Collections.emptySet(); 44 | } 45 | 46 | static class BigDecimalAccumulator { 47 | 48 | public BigDecimal sum = BigDecimal.ZERO; 49 | public BigDecimal count = BigDecimal.ZERO; 50 | 51 | public BigDecimalAccumulator() { 52 | } 53 | 54 | 55 | private BigDecimalAccumulator(BigDecimal sum, BigDecimal count) { 56 | sum.add(sum); 57 | count.add(count); 58 | } 59 | 60 | public static BigDecimalAccumulator accumulateWith(BigDecimal sum, BigDecimal count) { 61 | return new BigDecimalAccumulator(sum, count); 62 | } 63 | 64 | BigDecimal getAverage() { 65 | return BigDecimal.ZERO.compareTo(count) == 0 ? 66 | BigDecimal.ZERO : 67 | sum.divide(count, 2, BigDecimal.ROUND_HALF_UP); 68 | } 69 | 70 | BigDecimalAccumulator combine(BigDecimalAccumulator another) { 71 | return accumulateWith( 72 | sum.add(another.sum), 73 | count.add(another.count) 74 | ); 75 | } 76 | 77 | void add(BigDecimal successRate) { 78 | count = count.add(BigDecimal.ONE); 79 | sum = sum.add(successRate); 80 | } 81 | } 82 | } -------------------------------------------------------------------------------- /src/main/java/io/cucumber/core/plugin/LineFilters.java: -------------------------------------------------------------------------------- 1 | package io.cucumber.core.plugin; 2 | 3 | import io.cucumber.core.internal.gherkin.ast.Examples; 4 | import io.cucumber.core.internal.gherkin.ast.TableRow; 5 | import net.serenitybdd.cucumber.CucumberWithSerenity; 6 | 7 | import java.net.URI; 8 | import java.util.HashMap; 9 | import java.util.Map; 10 | import java.util.Optional; 11 | import java.util.Set; 12 | 13 | public class LineFilters { 14 | 15 | private Map> lineFilters; 16 | 17 | public LineFilters() { 18 | lineFilters = newLineFilters(); 19 | } 20 | 21 | public static LineFilters forCurrentContext() { 22 | return new LineFilters(); 23 | } 24 | 25 | public Optional getURIForFeaturePath(URI featurePath) { 26 | return lineFilters.keySet().stream() 27 | .filter(uri -> featurePath.equals(uri)) 28 | .findFirst(); 29 | } 30 | 31 | private Map> newLineFilters() { 32 | Map> lineFiltersFromRuntime = CucumberWithSerenity.currentRuntimeOptions().getLineFilters(); 33 | if (lineFiltersFromRuntime == null) { 34 | return new HashMap<>(); 35 | } else { 36 | return lineFiltersFromRuntime; 37 | } 38 | } 39 | 40 | public Set getLineNumbersFor(URI featurePath) { 41 | return lineFilters.get(featurePath); 42 | } 43 | 44 | 45 | public boolean examplesAreNotExcluded(Examples examples, URI featurePath) { 46 | if (lineFilters.isEmpty()) { 47 | return true; 48 | } 49 | if (lineFiltersContainFeaturePath(featurePath)) { 50 | Optional uriForFeaturePath = getURIForFeaturePath(featurePath); 51 | return uriForFeaturePath.filter( 52 | uri -> examples.getTableBody().stream() 53 | .anyMatch( 54 | row -> lineFilters.get(uri).contains(row.getLocation().getLine())) 55 | ).isPresent(); 56 | } 57 | return false; 58 | } 59 | 60 | public boolean tableRowIsNotExcludedBy(TableRow tableRow, URI featurePath) { 61 | if (lineFilters.isEmpty()) { 62 | return true; 63 | } 64 | if (lineFiltersContainFeaturePath(featurePath)) { 65 | Optional uriForFeaturePath = getURIForFeaturePath(featurePath); 66 | return uriForFeaturePath.filter(uri -> lineFilters.get(uri).contains(tableRow.getLocation().getLine())).isPresent(); 67 | } 68 | return false; 69 | } 70 | 71 | private boolean lineFiltersContainFeaturePath(URI featurePath) { 72 | return getURIForFeaturePath(featurePath) != null; 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /src/test/java/net/serenitybdd/cucumber/integration/TypeRegistryConfiguration.java: -------------------------------------------------------------------------------- 1 | package net.serenitybdd.cucumber.integration; 2 | 3 | import com.fasterxml.jackson.databind.ObjectMapper; 4 | import io.cucumber.core.api.TypeRegistry; 5 | import io.cucumber.core.api.TypeRegistryConfigurer; 6 | import io.cucumber.cucumberexpressions.ParameterByTypeTransformer; 7 | import io.cucumber.datatable.DataTableType; 8 | import io.cucumber.datatable.TableCellByTypeTransformer; 9 | import io.cucumber.datatable.TableEntryByTypeTransformer; 10 | import net.serenitybdd.cucumber.integration.steps.RpnCalculatorStepdefs; 11 | 12 | import java.lang.reflect.Type; 13 | import java.util.Locale; 14 | import java.util.Map; 15 | 16 | //import io.cucumber.datatable.dependency.com.fasterxml.jackson.databind.ObjectMapper; 17 | 18 | public class TypeRegistryConfiguration implements TypeRegistryConfigurer { 19 | 20 | @Override 21 | public Locale locale() { 22 | return Locale.ENGLISH; 23 | } 24 | 25 | @Override 26 | public void configureTypeRegistry(TypeRegistry typeRegistry) { 27 | Transformer transformer = new Transformer(); 28 | typeRegistry.setDefaultDataTableCellTransformer(transformer); 29 | typeRegistry.setDefaultDataTableEntryTransformer(transformer); 30 | typeRegistry.setDefaultParameterTransformer(transformer); 31 | typeRegistry.defineDataTableType(new DataTableType( 32 | RpnCalculatorStepdefs.Entry.class, 33 | (Map row) -> new RpnCalculatorStepdefs.Entry( 34 | Integer.parseInt(row.get("first")), 35 | Integer.parseInt(row.get("second")), 36 | row.get("operation")) 37 | ) 38 | ); 39 | } 40 | 41 | private class Transformer implements ParameterByTypeTransformer, TableEntryByTypeTransformer, TableCellByTypeTransformer { 42 | ObjectMapper objectMapper = new ObjectMapper(); 43 | 44 | @Override 45 | public Object transform(String s, Type type) { 46 | return objectMapper.convertValue(s, objectMapper.constructType(type)); 47 | } 48 | 49 | /*@Override 50 | public T transform(Map map, Class aClass, TableCellByTypeTransformer tableCellByTypeTransformer) { 51 | return objectMapper.convertValue(map, aClass); 52 | } 53 | 54 | @Override 55 | public T transform(String s, Class aClass) { 56 | return objectMapper.convertValue(s, aClass); 57 | }*/ 58 | 59 | 60 | 61 | @Override 62 | public Object transform(Map entryValue, Type toValueType, TableCellByTypeTransformer cellTransformer) 63 | throws Throwable { 64 | return null; 65 | } 66 | } 67 | 68 | } 69 | -------------------------------------------------------------------------------- /src/main/java/net/serenitybdd/cucumber/suiteslicing/CucumberScenarioVisualiser.java: -------------------------------------------------------------------------------- 1 | package net.serenitybdd.cucumber.suiteslicing; 2 | 3 | import com.google.gson.GsonBuilder; 4 | 5 | import net.serenitybdd.cucumber.util.PathUtils; 6 | import net.thucydides.core.util.EnvironmentVariables; 7 | import org.slf4j.Logger; 8 | import org.slf4j.LoggerFactory; 9 | 10 | import java.net.URI; 11 | import java.nio.file.Files; 12 | import java.nio.file.Paths; 13 | import java.util.List; 14 | import java.util.stream.IntStream; 15 | 16 | import static com.google.common.collect.Lists.newArrayList; 17 | import static java.util.stream.Collectors.toList; 18 | import static net.thucydides.core.ThucydidesSystemProperty.SERENITY_OUTPUT_DIRECTORY; 19 | 20 | public class CucumberScenarioVisualiser { 21 | 22 | private final Logger LOGGER = LoggerFactory.getLogger(CucumberScenarioVisualiser.class); 23 | private final EnvironmentVariables environmentVariables; 24 | 25 | public CucumberScenarioVisualiser(EnvironmentVariables environmentVariables) { 26 | this.environmentVariables = environmentVariables; 27 | } 28 | 29 | 30 | private String outputDirectory() { 31 | return environmentVariables.getProperty(SERENITY_OUTPUT_DIRECTORY, "target/site/serenity"); 32 | } 33 | 34 | public static List sliceIntoForks(int forkCount, List slices) { 35 | return slices.stream() 36 | .map(slice -> IntStream.rangeClosed(1, forkCount).mapToObj(forkNumber -> VisualisableCucumberScenarios.create(slices.indexOf(slice) + 1, forkNumber, slice.slice(forkNumber).of(forkCount))) 37 | .collect(toList())).flatMap(List::stream).collect(toList()); 38 | } 39 | 40 | public void visualise(URI rootFolderURI, int sliceCount, int forkCount, TestStatistics testStatistics) { 41 | try { 42 | Files.createDirectories(Paths.get(outputDirectory())); 43 | List slices = new CucumberScenarioLoader(newArrayList(rootFolderURI), testStatistics).load().sliceInto(sliceCount); 44 | List visualisedSlices = CucumberScenarioVisualiser.sliceIntoForks(forkCount, slices); 45 | String jsonFile = String.format("%s/%s-slice-config-%s-forks-in-each-of-%s-slices-using-%s.json", outputDirectory(), PathUtils 46 | .getAsFile(rootFolderURI).getPath().replaceAll("[:/]", "-"), forkCount, sliceCount, testStatistics); 47 | Files.write(Paths.get(jsonFile), new GsonBuilder().setPrettyPrinting().create().toJson(visualisedSlices).getBytes()); 48 | LOGGER.info("Wrote visualisation as JSON for {} slices -> {}", visualisedSlices.size(), jsonFile); 49 | } catch (Exception e) { 50 | throw new RuntimeException("failed to visualise scenarios", e); 51 | } 52 | } 53 | 54 | } -------------------------------------------------------------------------------- /src/test/resources/statistics/smoke-test-results-run-1.csv: -------------------------------------------------------------------------------- 1 | "Story","Title","Result","Date","Stability","Duration (s)" 2 | "Skipping Scenarios","Pending scenario","PENDING","2018-08-17T13:01:50.193+01:00[Europe/London]","0.0","6.62" 3 | "Skipping Scenarios","WIP scenario","SKIPPED","2018-08-17T13:01:56.936+01:00[Europe/London]","0.0","0.21" 4 | "Skipping Scenarios","Skipping a scenario","SKIPPED","2018-08-17T13:01:57.179+01:00[Europe/London]","0.0","0.23" 5 | "Skipping Scenarios","A manual scenario","PENDING","2018-08-17T13:01:57.411+01:00[Europe/London]","0.0","0.34" 6 | "Skipping Scenarios","An ignored scenario","IGNORED","2018-08-17T13:01:57.8+01:00[Europe/London]","0.0","0.26" 7 | "Skipping Scenarios","A skipped manual scenario","SKIPPED","2018-08-17T13:01:58.06+01:00[Europe/London]","0.0","0.21" 8 | "Using Serenity step libraries in Cucumber step definitions","Serenity instantiates step library fields in the Cucumber step definitions","SUCCESS","2018-08-17T13:01:50.237+01:00[Europe/London]","0.0","5.37" 9 | "Using Serenity step libraries in Cucumber step definitions","Serenity instantiates different step libraries for each field by default","SUCCESS","2018-08-17T13:01:55.619+01:00[Europe/London]","0.0","0.14" 10 | "Using Serenity step libraries in Cucumber step definitions","Serenity preserves the state of a step library instance during a scenario","SUCCESS","2018-08-17T13:01:55.768+01:00[Europe/London]","0.0","0.56" 11 | "Using Serenity step libraries in Cucumber step definitions","Serenity refreshes the step libraries for each new scenario","SUCCESS","2018-08-17T13:01:56.331+01:00[Europe/London]","0.0","0.12" 12 | "Using Serenity step libraries in Cucumber step definitions","Shared step libraries refer to the same instance","SUCCESS","2018-08-17T13:01:56.453+01:00[Europe/London]","0.0","0.13" 13 | "Using Serenity step libraries in Cucumber step definitions","Storig information in the Serenity session state","SUCCESS","2018-08-17T13:01:56.591+01:00[Europe/London]","0.0","0.02" 14 | "Using Serenity step libraries in Cucumber step definitions","Serenity session state should be reset for each scenario","SUCCESS","2018-08-17T13:01:56.61+01:00[Europe/London]","0.0","0.14" 15 | "Using Undefined Scenarios","With steps that haven't been implemented yet","PENDING","2018-08-17T13:01:49.403+01:00[Europe/London]","0.0","3.84" 16 | "Using Undefined Scenarios","Another scenario with no defined steps","PENDING","2018-08-17T13:01:53.44+01:00[Europe/London]","0.0","0.07" 17 | "Using Background Steps","Skipping a scenario","FAILURE","2018-08-17T13:01:49.536+01:00[Europe/London]","0.0","24.56" 18 | "Using Background Steps","Running a scenario","FAILURE","2018-08-17T13:02:14.535+01:00[Europe/London]","0.0","9.51" 19 | "Using Background Steps","Running a scenario with a Before clause","SUCCESS","2018-08-17T13:01:49.755+01:00[Europe/London]","0.0","38.49" 20 | "Using Background Steps","Running a scenario with an After clause","SUCCESS","2018-08-17T13:02:28.527+01:00[Europe/London]","0.0","21.94" 21 | --------------------------------------------------------------------------------