├── .gitignore ├── LICENSE ├── README.adoc ├── build.gradle ├── deploy-to-openshift.sh ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat └── src ├── asciidoc ├── advanced-webdriver.adoc ├── basic-concepts.adoc ├── cucumber.adoc ├── favicon.ico ├── first-steps.adoc ├── gradle.adoc ├── images │ ├── aggregate-report.png │ ├── asciidoc_narrative.png │ ├── basic-concepts-detailed-features.png │ ├── basic-concepts-detailed-requirements.png │ ├── basic-concepts-detailed-stories.png │ ├── basic-concepts-detailed-test-count.png │ ├── basic-concepts-detailed-weighted-tests.png │ ├── console-colors-off.png │ ├── console-colors-on.png │ ├── cukes-feature-report.png │ ├── cukes-requirements.png │ ├── cukes-serenity-home.png │ ├── cukes-serenity-table-report.png │ ├── cukes-serenity-test-report.png │ ├── fig-steps-earning-status.png │ ├── filtered-tests-for-filtering.png │ ├── first-steps-test-report.png │ ├── frequent-flyer-story-card.png │ ├── heavy.png │ ├── jbehave-initial-project.png │ ├── jbehave-requirements-report.png │ ├── jbehave_all_conditions_commented.png │ ├── jbehave_comments_report.png │ ├── jbehave_one_condition_commented.png │ ├── jbehave_scenario_commented.png │ ├── jira-agile-board.png │ ├── jira-fix-versions.png │ ├── jira-integration-example.png │ ├── jira-serenity-comment.png │ ├── jira-serenity-report.png │ ├── jira-versions.png │ ├── journey-action-report.png │ ├── journey-actors.png │ ├── journey-breakdown.png │ ├── journey-command-pattern.png │ ├── journey-remaining-count.png │ ├── journey-report.png │ ├── journey-todo-app.png │ ├── junit-batches-all-test-cases.png │ ├── junit-feature-report.png │ ├── junit-ignored-and-pending-tests.png │ ├── junit-overall-test-results.png │ ├── light.png │ ├── manual-zephyr-tests.png │ ├── maven-search-report.png │ ├── maven-search-results.png │ ├── medium.png │ ├── parallel-webtests-aggregate.png │ ├── parallel-webtests-matrix-build.png │ ├── parallel-webtests-post-build.png │ ├── releases-tab.png │ ├── request_headers_body.png │ ├── response_headers_body_cookies.png │ ├── rest_query_in_report.png │ ├── retry_test_fail.png │ ├── retry_test_success.png │ ├── serenity-aggregate-report.png │ ├── serenity-jira-releases.png │ ├── serenity-jira-report-epic-details.png │ ├── serenity-jira-requirements-view.png │ ├── serenity-jira-story-report.png │ ├── serenity-logo.png │ ├── serenity-report-for-divide-by-test-count-batch-strategy-number-1.png │ ├── serenity-report-for-divide-by-test-count-batch-strategy-number-2.png │ ├── serenity-report-for-equally-batch-strategy-number-1.png │ ├── serenity-report-for-equally-batch-strategy-number-2.png │ ├── serenity-test-report.png │ ├── story-results-pending.png │ ├── story-with-narrative.png │ ├── subset-of-tests-for-filtering.png │ ├── tags-in-reports.png │ ├── test-report.png │ ├── tests_with_references_to_issues.png │ ├── thucydides-logo.png │ ├── thucydides-maven-reports.png │ └── thucydides-test-report.png ├── importing-test-outcomes.adoc ├── index.adoc ├── jbehave.adoc ├── jira.adoc ├── journey-pattern.adoc ├── junit.adoc ├── maven.adoc ├── page-objects.adoc ├── remote.adoc ├── retry.adoc ├── screenshots.adoc ├── serenity-batches.adoc ├── serenity-issues.adoc ├── serenity-rest.adoc ├── spring.adoc ├── steps.adoc ├── system-props.adoc └── tags.adoc └── samples ├── build-all.sh ├── build.gradle ├── cucumber-quick-start ├── .gitignore ├── LICENSE ├── README.md ├── build.gradle ├── gradle │ └── wrapper │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── pom.xml ├── serenity.properties └── src │ ├── main │ └── java │ │ └── net │ │ └── serenitybdd │ │ └── samples │ │ └── etsy │ │ └── package-info.java │ └── test │ ├── java │ └── net │ │ └── serenity_bdd │ │ └── samples │ │ └── etsy │ │ ├── features │ │ ├── AddingItemsToTheShoppingCart.java │ │ ├── SearchByKeyword.java │ │ ├── model │ │ │ ├── ListingItem.java │ │ │ ├── OrderCostSummary.java │ │ │ └── SessionVariables.java │ │ └── steps │ │ │ ├── SearchByKeywordStepDefinitions.java │ │ │ ├── ShoppingCartStepDefinitions.java │ │ │ └── serenity │ │ │ └── BuyerSteps.java │ │ └── pages │ │ ├── CartPage.java │ │ ├── HomePage.java │ │ ├── ItemDetailsPage.java │ │ ├── SearchResultsPage.java │ │ └── Spinners.java │ └── resources │ └── features │ ├── customers │ ├── display_customer_details.feature │ └── locating_customer.feature │ ├── search │ └── search_by_keyword.feature │ └── shopping_cart │ ├── adding_items_to_the_shopping_cart.feature │ └── russian.feature ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── jbehave-quick-start ├── build.gradle ├── pom.xml ├── serenity.properties └── src │ ├── main │ └── java │ │ └── net │ │ └── serenitybdd │ │ └── samples │ │ └── etsy │ │ └── package-info.java │ └── test │ ├── java │ └── net │ │ └── serenitybdd │ │ └── samples │ │ └── etsy │ │ ├── AcceptanceTests.java │ │ ├── features │ │ ├── AddingItemsToTheShoppingCart.java │ │ ├── SearchByKeyword.java │ │ ├── model │ │ │ ├── ListingItem.java │ │ │ ├── OrderCostSummary.java │ │ │ └── SessionVariables.java │ │ └── steps │ │ │ ├── SearchByKeywordStepDefinitions.java │ │ │ ├── ShoppingCartStepDefinitions.java │ │ │ └── serenity │ │ │ └── BuyerSteps.java │ │ └── pages │ │ ├── CartPage.java │ │ ├── HomePage.java │ │ ├── ItemDetailsPage.java │ │ ├── SearchResultsPage.java │ │ └── Spinners.java │ └── resources │ └── stories │ ├── search │ ├── narrative.txt │ └── search_by_keyword.story │ └── shopping_cart │ └── adding_items_to_the_shopping_cart.story ├── jira-integration-scenarios ├── sample-dependency.xml ├── sample-jbehabe-scenatio.story ├── sample-workflow-configuration.groovy ├── serenity-reporting-plugin-configuration.xml └── serenity.properties ├── journey-pattern-sample ├── README.md ├── build.gradle ├── pom.xml ├── serenity.properties └── src │ ├── main │ └── java │ │ └── net │ │ └── serenitybdd │ │ └── demos │ │ └── todos │ │ ├── action │ │ └── JSClick.java │ │ ├── model │ │ ├── ApplicationInformation.java │ │ ├── TodoStatus.java │ │ └── TodoStatusFilter.java │ │ ├── pages │ │ ├── ApplicationHomePage.java │ │ └── todolist │ │ │ ├── ClearCompleted.java │ │ │ ├── CompleteAll.java │ │ │ ├── ToDoList.java │ │ │ ├── counter │ │ │ └── TodoCounter.java │ │ │ ├── filter │ │ │ └── FilterSelection.java │ │ │ ├── items │ │ │ ├── CompleteItemButton.java │ │ │ ├── DeleteItemButton.java │ │ │ ├── ItemTextInlineInput.java │ │ │ ├── ItemTextLabel.java │ │ │ └── TodoListItem.java │ │ │ └── newitem │ │ │ └── NewTodoForm.java │ │ ├── questions │ │ ├── ApplicationDetails.java │ │ ├── ClearCompletedItemsOptionAvailability.java │ │ ├── CurrentFilter.java │ │ ├── DisplayedItems.java │ │ ├── ElementAvailability.java │ │ ├── PlaceholderText.java │ │ ├── TheItemStatus.java │ │ └── TheRemainingItemCount.java │ │ └── tasks │ │ ├── AddATodoItem.java │ │ ├── AddTodoItems.java │ │ ├── ClearCompletedItems.java │ │ ├── Complete.java │ │ ├── CompleteAllItems.java │ │ ├── CompleteItem.java │ │ ├── DeleteAnItem.java │ │ ├── FilterItems.java │ │ └── OpenTheApplication.java │ └── test │ ├── java │ └── net │ │ └── serenitybdd │ │ └── demos │ │ └── todos │ │ └── features │ │ ├── completing_todos │ │ ├── CompleteATodo.java │ │ └── CompleteAllTodos.java │ │ ├── maintain_my_todo_list │ │ ├── ClearCompletedTodos.java │ │ ├── DeleteTodos.java │ │ └── FilteringTodos.java │ │ └── record_todos │ │ └── AddNewTodos.java │ └── resources │ └── serenity.conf ├── junit-batch-configuration-example ├── build.gradle ├── serenity.properties └── src │ └── test │ └── java │ └── net │ └── serenity │ └── samples │ └── batch │ └── junit │ ├── features │ └── registration │ │ ├── LoginUserTest.java │ │ ├── RegisterUserTest.java │ │ └── UserActivationProcessTest.java │ ├── model │ ├── ActivationMail.java │ └── User.java │ └── steps │ └── serenity │ ├── MailActivationSteps.java │ └── UserActionSteps.java ├── junit-quick-start ├── build.gradle ├── build.xml ├── deps ├── ivy.xml ├── pom.xml ├── src │ ├── main │ │ └── java │ │ │ └── net │ │ │ └── serenitybdd │ │ │ └── samples │ │ │ └── junit │ │ │ └── model │ │ │ ├── FrequentFlyer.java │ │ │ └── Status.java │ └── test │ │ ├── java │ │ └── net │ │ │ └── serenitybdd │ │ │ └── samples │ │ │ └── junit │ │ │ ├── features │ │ │ ├── earning_points │ │ │ │ ├── WhenCalculatingFrequentFlyerPoints.java │ │ │ │ ├── WhenEarningFrequentFlyerStatus.java │ │ │ │ ├── WhenEarningFrequentFlyerStatusUpgrades.java │ │ │ │ └── WhenEarningFrequentFlyerStatusUpgradesUsingCSV.java │ │ │ ├── managing_member_accounts │ │ │ │ └── WhenUpdatingMemberAccounts.java │ │ │ └── searching │ │ │ │ ├── WhenSearchingFlights.java │ │ │ │ ├── WhenSearchingForDifferentTermsOnGoogle.java │ │ │ │ ├── WhenSearchingOnGoogle.java │ │ │ │ └── package-info.java │ │ │ ├── pages │ │ │ ├── FlightDetailsPage.java │ │ │ ├── FlightSearchPage.java │ │ │ ├── FlightSearchResultsPage.java │ │ │ └── GooglePage.java │ │ │ └── steps │ │ │ ├── FlightSearchSteps.java │ │ │ ├── MainframeStatus.java │ │ │ ├── TravellerHistorySteps.java │ │ │ ├── TravellerStatusSteps.java │ │ │ └── TravellerSteps.java │ │ └── resources │ │ └── testdata │ │ └── status-levels.csv └── thucydides.properties ├── junit-retries └── net │ └── serenity │ └── samples │ └── retries │ ├── SampleTest.java │ └── TestSteps.java ├── junit-tests-linked-to-issues ├── serenity.properties └── src │ └── test │ └── java │ └── net │ └── serenity │ └── samples │ └── retries │ ├── SampleTest.java │ └── TestSteps.java └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | test*.db 2 | .project 3 | .gradle 4 | .ignore 5 | .settings 6 | target 7 | .idea 8 | .classpath 9 | .checkstyle 10 | *.log 11 | *.log.* 12 | *.iml 13 | *.versionsBackup 14 | interpolated-*.xml 15 | *.iws 16 | *.ipr 17 | out 18 | *.ignore 19 | build 20 | bin 21 | lib 22 | thucydides-arquillian 23 | tools 24 | *.sublime-project 25 | *.sublime-workspace 26 | .hg* -------------------------------------------------------------------------------- /README.adoc: -------------------------------------------------------------------------------- 1 | = Serenity BDD Documentation 2 | 3 | This project contains the main Serenity BDD documentation. 4 | The documentation is broken up into chapters, so many people can contribute simultaneously. 5 | 6 | == Building and contributing 7 | 8 | The Serenity documentation is written in Asciidoc. 9 | The build uses Gradle and Asciidoctor. 10 | You can generate the documentation by running the `asciidoctor` task: 11 | 12 | $ gradle clean asciidoctor 13 | 14 | The documentation is generated in [path]_build/asciidoc_. 15 | 16 | The master document is [path]_index.asc_. 17 | All of the chapters are included into this document. 18 | 19 | All of the source code in the documentation is included as snippets from the sample projects in the [path]_src/sample_ directory. 20 | Look in [path]_src/ascidoc/first-steps.asc_ to see an example of how this is done. 21 | -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | repositories { 3 | jcenter() 4 | } 5 | 6 | dependencies { 7 | classpath 'org.asciidoctor:asciidoctor-gradle-plugin:1.5.2' 8 | } 9 | } 10 | 11 | apply plugin: 'org.asciidoctor.convert' 12 | 13 | version='2.1.0' 14 | 15 | asciidoctor { 16 | sourceDir 'src/asciidoc' 17 | sources { 18 | include 'index.adoc' 19 | } 20 | separateOutputDirs false 21 | } 22 | -------------------------------------------------------------------------------- /deploy-to-openshift.sh: -------------------------------------------------------------------------------- 1 | mkdir -p build/deploy 2 | cd build/deploy 3 | ssh-keyscan serenitydocs-wakaleo.rhcloud.com >> ~/.ssh/known_hosts 4 | git clone ${GIT_REPO} 5 | cp -Rf ../asciidoc/* serenitydocs/ 6 | cd serenitydocs 7 | git add . 8 | git commit -a -m"Automated release" 9 | git push -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/serenity-bdd/serenity-documentation/cf4fbdb8e3af38b060f98057190b4157145b0d8c/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Sun Nov 23 11:49:59 GMT 2014 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-2.2.1-bin.zip 7 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 12 | set DEFAULT_JVM_OPTS= 13 | 14 | set DIRNAME=%~dp0 15 | if "%DIRNAME%" == "" set DIRNAME=. 16 | set APP_BASE_NAME=%~n0 17 | set APP_HOME=%DIRNAME% 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windowz variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | if "%@eval[2+2]" == "4" goto 4NT_args 53 | 54 | :win9xME_args 55 | @rem Slurp the command line arguments. 56 | set CMD_LINE_ARGS= 57 | set _SKIP=2 58 | 59 | :win9xME_args_slurp 60 | if "x%~1" == "x" goto execute 61 | 62 | set CMD_LINE_ARGS=%* 63 | goto execute 64 | 65 | :4NT_args 66 | @rem Get arguments from the 4NT Shell from JP Software 67 | set CMD_LINE_ARGS=%$ 68 | 69 | :execute 70 | @rem Setup the command line 71 | 72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if "%ERRORLEVEL%"=="0" goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 85 | exit /b 1 86 | 87 | :mainEnd 88 | if "%OS%"=="Windows_NT" endlocal 89 | 90 | :omega 91 | -------------------------------------------------------------------------------- /src/asciidoc/advanced-webdriver.adoc: -------------------------------------------------------------------------------- 1 | === Restarting the browser between tests 2 | 3 | By default, Serenity will start a new browser for each test. This helps ensure that each test is isolated and independant, but it can result in slower test execution for test suites with large numbers of relatively fast-running tests. 4 | 5 | You can fine-tune this behavior with the `serenity.restart.browser.for.each` property. This property takes the following values: 6 | 7 | * never 8 | * feature 9 | * story 10 | * scenario 11 | * example 12 | 13 | These values work as follows: 14 | 15 | A value of **never** will open a single browser (or one browser per thread if the tests are being run in parallel), and use this browser for every test. Serenity will attempt to clear 16 | 17 | A value of **feature** and **story** (which are equivalent in this context) will cause Serenity to open a new browser for each test case (in JUnit), or each feature (in Cucumber) or story (in JBehave). 18 | 19 | A value of **scenario** will open a new browser for each test (in JUnit) or scenario (in Cucumber or JBehave). 20 | 21 | 22 | There are some caveats to this configuration. Browsers are managed per thread, so if the tests are run in parallel (and therefore on separate threads), several browsers will be opened. 23 | 24 | === Custom WebDriver implementations 25 | 26 | You can add your own custom WebDriver provider by implementing the DriverSource interface. First, you need to set up the following system properties (e.g. in your `serenity.properties` file): 27 | 28 | ----- 29 | webdriver.driver = provided 30 | webdriver.provided.type = mydriver 31 | webdriver.provided.mydriver = com.acme.MyPhantomJSDriver 32 | thucydides.driver.capabilities = mydriver 33 | ----- 34 | 35 | Your custom driver must implement the DriverSource interface, as shown here: 36 | 37 | [source,java] 38 | ----- 39 | public class MyPhantomJSDriver implements DriverSource { 40 | 41 | @Override 42 | public WebDriver newDriver() { 43 | try { 44 | DesiredCapabilities capabilities = DesiredCapabilities.phantomjs(); 45 | // Add 46 | return new PhantomJSDriver(ResolvingPhantomJSDriverService.createDefaultService(), capabilities); 47 | } 48 | catch (IOException e) { 49 | throw new Error(e); 50 | } 51 | } 52 | 53 | @Override 54 | public boolean takesScreenshots() { 55 | return true; 56 | } 57 | } 58 | ----- 59 | 60 | This driver will now take screenshots normally. 61 | -------------------------------------------------------------------------------- /src/asciidoc/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/serenity-bdd/serenity-documentation/cf4fbdb8e3af38b060f98057190b4157145b0d8c/src/asciidoc/favicon.ico -------------------------------------------------------------------------------- /src/asciidoc/first-steps.adoc: -------------------------------------------------------------------------------- 1 | In this section we will show you how to get started with Serenity BDD using a simple project using http://junit.org[JUnit] and http://gradle.org[Gradle]. 2 | 3 | Serenity BDD projects can be built using Gradle, http://maven.apache.org[Maven] or https://ant.apache.org[Ant]. Configuring a Java or http://groovy.codehaus.org[Groovy] build to use Serenity BDD is generally just a matter of adding the right dependencies, and a task or plugin to generate the aggregated reports. 4 | 5 | For example, a simple Gradle build for a Serenity BDD project could look like this: 6 | 7 | [source,groovy] 8 | ---- 9 | include::{srcdir}/junit-quick-start/build.gradle[tags=simple] 10 | ---- 11 | 12 | <1> Add the Serenity plugin to the Gradle build path 13 | <2> Adds the 'aggregate' and 'check' tasks to the Gradle build 14 | <3> The core Serenity BDD classes 15 | <4> The Serenity BDD JUnit integration 16 | 17 | Next, you would write a JUnit test to express the acceptance criteria that you want to automate. Suppose you are working on a Frequent Flyer website for an airline. You are implementing the feature that lets Frequent Flyer members earn points when they travel. The first acceptance criteria you need to cater for is the following: 18 | - Frequent Flyer members earn 100 points for every 1000 km travelled. 19 | 20 | Using Serenity BDD, you could write a unit test like the following: 21 | 22 | [source,java] 23 | ---- 24 | include::{srcdir}/junit-quick-start/src/test/java/net/serenitybdd/samples/junit/features/earning_points/WhenCalculatingFrequentFlyerPoints.java[tags=testcase] 25 | ---- 26 | <1> You run the JUnit test using the 'Serenity' test runner 27 | <2> The `@Steps` annotation marks a Serenity step library 28 | <3> The unit test is composed of logical steps, each of which will appear in the reports 29 | 30 | When you write acceptance tests this way, the JUnit test mainly orchestrates the order of the steps: the bulk of the testing logic goes in the step library methods themselves. 31 | 32 | [source,java] 33 | ---- 34 | include::{srcdir}/junit-quick-start/src/test/java/net/serenitybdd/samples/junit/steps/TravellerSteps.java[tags=classbody] 35 | ---- 36 | <1> This is the object under test. 37 | <2> The `@Step` annotation marks this as a method that will be recorded and will appear in the test report 38 | <3> Prepare the test data 39 | <4> The action under test 40 | <5> Check the outcome 41 | 42 | Note that, at this point, the `FrequentFlyer` class and the `flies()` method may not exist: you are using the acceptance test implementation to discover the services you need from your application code. This is very typical of a BDD/TDD approach to writing software, and as a result the acceptance tests not only test the application, they also illustrate how the application code is meant to work. 43 | 44 | These tests would initially fail, because the `FrequentFlyer.flies()` method hasn't been written. But once you have correctly implemented this method, you can run the tests and generate the reports from the command line like this: 45 | 46 | [source,bash] 47 | ---- 48 | $ gradle clean test aggregate 49 | ---- 50 | 51 | This will produce a report like the one below in the `target/site/serenity` directory. 52 | 53 | [[fig-test-report]] 54 | .The `@Step` methods appear as lines in the test report 55 | image::first-steps-test-report.png[] 56 | -------------------------------------------------------------------------------- /src/asciidoc/gradle.adoc: -------------------------------------------------------------------------------- 1 | Serenity BDD is easy to integrate with https://www.gradle.org/[Gradle], using the `serenity-gradle-plugin`. 2 | A simple example is shown here: 3 | 4 | [source,groovy] 5 | ---- 6 | include::{srcdir}/junit-quick-start/build.gradle[tags=simple;advanced] 7 | ---- 8 | <1> Add the Serenity plugin to the Gradle build path 9 | <2> Adds the aggregate and check tasks to the Gradle build 10 | <3> The core Serenity BDD classes 11 | <4> The Serenity BDD JUnit integration 12 | <5> Ensure that the Gradle build does not stop at the first test failure, but goes on to generate the Serenity reports 13 | 14 | First of all, add the Serenity BDD plugin entry to the Gradle build path in the `buildscript` section (1). This enables Gradle to find and apply the plugin to your project. You can check the latest version numbers on https://bintray.com/serenity/maven/[Bintray]. 15 | 16 | Next, you need to apply this plugin to your project (2) and add the Serenity BDD dependencies to your project. You will typically add `core` (3) and another dependency that correpsonds to the testing library you are using (JUnit in this example: (4)). 17 | 18 | The `serenity-gradle-plugin` adds below two tasks to your project: 19 | 20 | aggregate:: Generates the Serenity aggregate reports from the JSON test results produced when you run the Serenity BDD tests. 21 | checkOutcomes:: Check the test results in the output directory, and fail the build if there are errors or failures. 22 | 23 | A typical use case is to run the tests and to always produce the aggregate report, no matter what the test results are. To do this in one line, you need to tell Gradle not to stop if the tests fail. You can do this by setting `gradle.startParameter.continueOnFailure` to `true`, and then running the following: 24 | 25 | [source,bash] 26 | ---- 27 | gradle test aggregate 28 | ---- 29 | 30 | This will run the tests and generate an aggregate report in the `target/site/thucydides` directory. -------------------------------------------------------------------------------- /src/asciidoc/images/aggregate-report.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/serenity-bdd/serenity-documentation/cf4fbdb8e3af38b060f98057190b4157145b0d8c/src/asciidoc/images/aggregate-report.png -------------------------------------------------------------------------------- /src/asciidoc/images/asciidoc_narrative.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/serenity-bdd/serenity-documentation/cf4fbdb8e3af38b060f98057190b4157145b0d8c/src/asciidoc/images/asciidoc_narrative.png -------------------------------------------------------------------------------- /src/asciidoc/images/basic-concepts-detailed-features.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/serenity-bdd/serenity-documentation/cf4fbdb8e3af38b060f98057190b4157145b0d8c/src/asciidoc/images/basic-concepts-detailed-features.png -------------------------------------------------------------------------------- /src/asciidoc/images/basic-concepts-detailed-requirements.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/serenity-bdd/serenity-documentation/cf4fbdb8e3af38b060f98057190b4157145b0d8c/src/asciidoc/images/basic-concepts-detailed-requirements.png -------------------------------------------------------------------------------- /src/asciidoc/images/basic-concepts-detailed-stories.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/serenity-bdd/serenity-documentation/cf4fbdb8e3af38b060f98057190b4157145b0d8c/src/asciidoc/images/basic-concepts-detailed-stories.png -------------------------------------------------------------------------------- /src/asciidoc/images/basic-concepts-detailed-test-count.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/serenity-bdd/serenity-documentation/cf4fbdb8e3af38b060f98057190b4157145b0d8c/src/asciidoc/images/basic-concepts-detailed-test-count.png -------------------------------------------------------------------------------- /src/asciidoc/images/basic-concepts-detailed-weighted-tests.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/serenity-bdd/serenity-documentation/cf4fbdb8e3af38b060f98057190b4157145b0d8c/src/asciidoc/images/basic-concepts-detailed-weighted-tests.png -------------------------------------------------------------------------------- /src/asciidoc/images/console-colors-off.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/serenity-bdd/serenity-documentation/cf4fbdb8e3af38b060f98057190b4157145b0d8c/src/asciidoc/images/console-colors-off.png -------------------------------------------------------------------------------- /src/asciidoc/images/console-colors-on.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/serenity-bdd/serenity-documentation/cf4fbdb8e3af38b060f98057190b4157145b0d8c/src/asciidoc/images/console-colors-on.png -------------------------------------------------------------------------------- /src/asciidoc/images/cukes-feature-report.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/serenity-bdd/serenity-documentation/cf4fbdb8e3af38b060f98057190b4157145b0d8c/src/asciidoc/images/cukes-feature-report.png -------------------------------------------------------------------------------- /src/asciidoc/images/cukes-requirements.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/serenity-bdd/serenity-documentation/cf4fbdb8e3af38b060f98057190b4157145b0d8c/src/asciidoc/images/cukes-requirements.png -------------------------------------------------------------------------------- /src/asciidoc/images/cukes-serenity-home.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/serenity-bdd/serenity-documentation/cf4fbdb8e3af38b060f98057190b4157145b0d8c/src/asciidoc/images/cukes-serenity-home.png -------------------------------------------------------------------------------- /src/asciidoc/images/cukes-serenity-table-report.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/serenity-bdd/serenity-documentation/cf4fbdb8e3af38b060f98057190b4157145b0d8c/src/asciidoc/images/cukes-serenity-table-report.png -------------------------------------------------------------------------------- /src/asciidoc/images/cukes-serenity-test-report.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/serenity-bdd/serenity-documentation/cf4fbdb8e3af38b060f98057190b4157145b0d8c/src/asciidoc/images/cukes-serenity-test-report.png -------------------------------------------------------------------------------- /src/asciidoc/images/fig-steps-earning-status.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/serenity-bdd/serenity-documentation/cf4fbdb8e3af38b060f98057190b4157145b0d8c/src/asciidoc/images/fig-steps-earning-status.png -------------------------------------------------------------------------------- /src/asciidoc/images/filtered-tests-for-filtering.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/serenity-bdd/serenity-documentation/cf4fbdb8e3af38b060f98057190b4157145b0d8c/src/asciidoc/images/filtered-tests-for-filtering.png -------------------------------------------------------------------------------- /src/asciidoc/images/first-steps-test-report.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/serenity-bdd/serenity-documentation/cf4fbdb8e3af38b060f98057190b4157145b0d8c/src/asciidoc/images/first-steps-test-report.png -------------------------------------------------------------------------------- /src/asciidoc/images/frequent-flyer-story-card.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/serenity-bdd/serenity-documentation/cf4fbdb8e3af38b060f98057190b4157145b0d8c/src/asciidoc/images/frequent-flyer-story-card.png -------------------------------------------------------------------------------- /src/asciidoc/images/heavy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/serenity-bdd/serenity-documentation/cf4fbdb8e3af38b060f98057190b4157145b0d8c/src/asciidoc/images/heavy.png -------------------------------------------------------------------------------- /src/asciidoc/images/jbehave-initial-project.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/serenity-bdd/serenity-documentation/cf4fbdb8e3af38b060f98057190b4157145b0d8c/src/asciidoc/images/jbehave-initial-project.png -------------------------------------------------------------------------------- /src/asciidoc/images/jbehave-requirements-report.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/serenity-bdd/serenity-documentation/cf4fbdb8e3af38b060f98057190b4157145b0d8c/src/asciidoc/images/jbehave-requirements-report.png -------------------------------------------------------------------------------- /src/asciidoc/images/jbehave_all_conditions_commented.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/serenity-bdd/serenity-documentation/cf4fbdb8e3af38b060f98057190b4157145b0d8c/src/asciidoc/images/jbehave_all_conditions_commented.png -------------------------------------------------------------------------------- /src/asciidoc/images/jbehave_comments_report.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/serenity-bdd/serenity-documentation/cf4fbdb8e3af38b060f98057190b4157145b0d8c/src/asciidoc/images/jbehave_comments_report.png -------------------------------------------------------------------------------- /src/asciidoc/images/jbehave_one_condition_commented.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/serenity-bdd/serenity-documentation/cf4fbdb8e3af38b060f98057190b4157145b0d8c/src/asciidoc/images/jbehave_one_condition_commented.png -------------------------------------------------------------------------------- /src/asciidoc/images/jbehave_scenario_commented.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/serenity-bdd/serenity-documentation/cf4fbdb8e3af38b060f98057190b4157145b0d8c/src/asciidoc/images/jbehave_scenario_commented.png -------------------------------------------------------------------------------- /src/asciidoc/images/jira-agile-board.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/serenity-bdd/serenity-documentation/cf4fbdb8e3af38b060f98057190b4157145b0d8c/src/asciidoc/images/jira-agile-board.png -------------------------------------------------------------------------------- /src/asciidoc/images/jira-fix-versions.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/serenity-bdd/serenity-documentation/cf4fbdb8e3af38b060f98057190b4157145b0d8c/src/asciidoc/images/jira-fix-versions.png -------------------------------------------------------------------------------- /src/asciidoc/images/jira-integration-example.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/serenity-bdd/serenity-documentation/cf4fbdb8e3af38b060f98057190b4157145b0d8c/src/asciidoc/images/jira-integration-example.png -------------------------------------------------------------------------------- /src/asciidoc/images/jira-serenity-comment.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/serenity-bdd/serenity-documentation/cf4fbdb8e3af38b060f98057190b4157145b0d8c/src/asciidoc/images/jira-serenity-comment.png -------------------------------------------------------------------------------- /src/asciidoc/images/jira-serenity-report.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/serenity-bdd/serenity-documentation/cf4fbdb8e3af38b060f98057190b4157145b0d8c/src/asciidoc/images/jira-serenity-report.png -------------------------------------------------------------------------------- /src/asciidoc/images/jira-versions.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/serenity-bdd/serenity-documentation/cf4fbdb8e3af38b060f98057190b4157145b0d8c/src/asciidoc/images/jira-versions.png -------------------------------------------------------------------------------- /src/asciidoc/images/journey-action-report.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/serenity-bdd/serenity-documentation/cf4fbdb8e3af38b060f98057190b4157145b0d8c/src/asciidoc/images/journey-action-report.png -------------------------------------------------------------------------------- /src/asciidoc/images/journey-actors.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/serenity-bdd/serenity-documentation/cf4fbdb8e3af38b060f98057190b4157145b0d8c/src/asciidoc/images/journey-actors.png -------------------------------------------------------------------------------- /src/asciidoc/images/journey-breakdown.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/serenity-bdd/serenity-documentation/cf4fbdb8e3af38b060f98057190b4157145b0d8c/src/asciidoc/images/journey-breakdown.png -------------------------------------------------------------------------------- /src/asciidoc/images/journey-command-pattern.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/serenity-bdd/serenity-documentation/cf4fbdb8e3af38b060f98057190b4157145b0d8c/src/asciidoc/images/journey-command-pattern.png -------------------------------------------------------------------------------- /src/asciidoc/images/journey-remaining-count.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/serenity-bdd/serenity-documentation/cf4fbdb8e3af38b060f98057190b4157145b0d8c/src/asciidoc/images/journey-remaining-count.png -------------------------------------------------------------------------------- /src/asciidoc/images/journey-report.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/serenity-bdd/serenity-documentation/cf4fbdb8e3af38b060f98057190b4157145b0d8c/src/asciidoc/images/journey-report.png -------------------------------------------------------------------------------- /src/asciidoc/images/journey-todo-app.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/serenity-bdd/serenity-documentation/cf4fbdb8e3af38b060f98057190b4157145b0d8c/src/asciidoc/images/journey-todo-app.png -------------------------------------------------------------------------------- /src/asciidoc/images/junit-batches-all-test-cases.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/serenity-bdd/serenity-documentation/cf4fbdb8e3af38b060f98057190b4157145b0d8c/src/asciidoc/images/junit-batches-all-test-cases.png -------------------------------------------------------------------------------- /src/asciidoc/images/junit-feature-report.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/serenity-bdd/serenity-documentation/cf4fbdb8e3af38b060f98057190b4157145b0d8c/src/asciidoc/images/junit-feature-report.png -------------------------------------------------------------------------------- /src/asciidoc/images/junit-ignored-and-pending-tests.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/serenity-bdd/serenity-documentation/cf4fbdb8e3af38b060f98057190b4157145b0d8c/src/asciidoc/images/junit-ignored-and-pending-tests.png -------------------------------------------------------------------------------- /src/asciidoc/images/junit-overall-test-results.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/serenity-bdd/serenity-documentation/cf4fbdb8e3af38b060f98057190b4157145b0d8c/src/asciidoc/images/junit-overall-test-results.png -------------------------------------------------------------------------------- /src/asciidoc/images/light.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/serenity-bdd/serenity-documentation/cf4fbdb8e3af38b060f98057190b4157145b0d8c/src/asciidoc/images/light.png -------------------------------------------------------------------------------- /src/asciidoc/images/manual-zephyr-tests.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/serenity-bdd/serenity-documentation/cf4fbdb8e3af38b060f98057190b4157145b0d8c/src/asciidoc/images/manual-zephyr-tests.png -------------------------------------------------------------------------------- /src/asciidoc/images/maven-search-report.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/serenity-bdd/serenity-documentation/cf4fbdb8e3af38b060f98057190b4157145b0d8c/src/asciidoc/images/maven-search-report.png -------------------------------------------------------------------------------- /src/asciidoc/images/maven-search-results.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/serenity-bdd/serenity-documentation/cf4fbdb8e3af38b060f98057190b4157145b0d8c/src/asciidoc/images/maven-search-results.png -------------------------------------------------------------------------------- /src/asciidoc/images/medium.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/serenity-bdd/serenity-documentation/cf4fbdb8e3af38b060f98057190b4157145b0d8c/src/asciidoc/images/medium.png -------------------------------------------------------------------------------- /src/asciidoc/images/parallel-webtests-aggregate.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/serenity-bdd/serenity-documentation/cf4fbdb8e3af38b060f98057190b4157145b0d8c/src/asciidoc/images/parallel-webtests-aggregate.png -------------------------------------------------------------------------------- /src/asciidoc/images/parallel-webtests-matrix-build.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/serenity-bdd/serenity-documentation/cf4fbdb8e3af38b060f98057190b4157145b0d8c/src/asciidoc/images/parallel-webtests-matrix-build.png -------------------------------------------------------------------------------- /src/asciidoc/images/parallel-webtests-post-build.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/serenity-bdd/serenity-documentation/cf4fbdb8e3af38b060f98057190b4157145b0d8c/src/asciidoc/images/parallel-webtests-post-build.png -------------------------------------------------------------------------------- /src/asciidoc/images/releases-tab.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/serenity-bdd/serenity-documentation/cf4fbdb8e3af38b060f98057190b4157145b0d8c/src/asciidoc/images/releases-tab.png -------------------------------------------------------------------------------- /src/asciidoc/images/request_headers_body.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/serenity-bdd/serenity-documentation/cf4fbdb8e3af38b060f98057190b4157145b0d8c/src/asciidoc/images/request_headers_body.png -------------------------------------------------------------------------------- /src/asciidoc/images/response_headers_body_cookies.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/serenity-bdd/serenity-documentation/cf4fbdb8e3af38b060f98057190b4157145b0d8c/src/asciidoc/images/response_headers_body_cookies.png -------------------------------------------------------------------------------- /src/asciidoc/images/rest_query_in_report.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/serenity-bdd/serenity-documentation/cf4fbdb8e3af38b060f98057190b4157145b0d8c/src/asciidoc/images/rest_query_in_report.png -------------------------------------------------------------------------------- /src/asciidoc/images/retry_test_fail.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/serenity-bdd/serenity-documentation/cf4fbdb8e3af38b060f98057190b4157145b0d8c/src/asciidoc/images/retry_test_fail.png -------------------------------------------------------------------------------- /src/asciidoc/images/retry_test_success.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/serenity-bdd/serenity-documentation/cf4fbdb8e3af38b060f98057190b4157145b0d8c/src/asciidoc/images/retry_test_success.png -------------------------------------------------------------------------------- /src/asciidoc/images/serenity-aggregate-report.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/serenity-bdd/serenity-documentation/cf4fbdb8e3af38b060f98057190b4157145b0d8c/src/asciidoc/images/serenity-aggregate-report.png -------------------------------------------------------------------------------- /src/asciidoc/images/serenity-jira-releases.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/serenity-bdd/serenity-documentation/cf4fbdb8e3af38b060f98057190b4157145b0d8c/src/asciidoc/images/serenity-jira-releases.png -------------------------------------------------------------------------------- /src/asciidoc/images/serenity-jira-report-epic-details.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/serenity-bdd/serenity-documentation/cf4fbdb8e3af38b060f98057190b4157145b0d8c/src/asciidoc/images/serenity-jira-report-epic-details.png -------------------------------------------------------------------------------- /src/asciidoc/images/serenity-jira-requirements-view.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/serenity-bdd/serenity-documentation/cf4fbdb8e3af38b060f98057190b4157145b0d8c/src/asciidoc/images/serenity-jira-requirements-view.png -------------------------------------------------------------------------------- /src/asciidoc/images/serenity-jira-story-report.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/serenity-bdd/serenity-documentation/cf4fbdb8e3af38b060f98057190b4157145b0d8c/src/asciidoc/images/serenity-jira-story-report.png -------------------------------------------------------------------------------- /src/asciidoc/images/serenity-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/serenity-bdd/serenity-documentation/cf4fbdb8e3af38b060f98057190b4157145b0d8c/src/asciidoc/images/serenity-logo.png -------------------------------------------------------------------------------- /src/asciidoc/images/serenity-report-for-divide-by-test-count-batch-strategy-number-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/serenity-bdd/serenity-documentation/cf4fbdb8e3af38b060f98057190b4157145b0d8c/src/asciidoc/images/serenity-report-for-divide-by-test-count-batch-strategy-number-1.png -------------------------------------------------------------------------------- /src/asciidoc/images/serenity-report-for-divide-by-test-count-batch-strategy-number-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/serenity-bdd/serenity-documentation/cf4fbdb8e3af38b060f98057190b4157145b0d8c/src/asciidoc/images/serenity-report-for-divide-by-test-count-batch-strategy-number-2.png -------------------------------------------------------------------------------- /src/asciidoc/images/serenity-report-for-equally-batch-strategy-number-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/serenity-bdd/serenity-documentation/cf4fbdb8e3af38b060f98057190b4157145b0d8c/src/asciidoc/images/serenity-report-for-equally-batch-strategy-number-1.png -------------------------------------------------------------------------------- /src/asciidoc/images/serenity-report-for-equally-batch-strategy-number-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/serenity-bdd/serenity-documentation/cf4fbdb8e3af38b060f98057190b4157145b0d8c/src/asciidoc/images/serenity-report-for-equally-batch-strategy-number-2.png -------------------------------------------------------------------------------- /src/asciidoc/images/serenity-test-report.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/serenity-bdd/serenity-documentation/cf4fbdb8e3af38b060f98057190b4157145b0d8c/src/asciidoc/images/serenity-test-report.png -------------------------------------------------------------------------------- /src/asciidoc/images/story-results-pending.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/serenity-bdd/serenity-documentation/cf4fbdb8e3af38b060f98057190b4157145b0d8c/src/asciidoc/images/story-results-pending.png -------------------------------------------------------------------------------- /src/asciidoc/images/story-with-narrative.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/serenity-bdd/serenity-documentation/cf4fbdb8e3af38b060f98057190b4157145b0d8c/src/asciidoc/images/story-with-narrative.png -------------------------------------------------------------------------------- /src/asciidoc/images/subset-of-tests-for-filtering.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/serenity-bdd/serenity-documentation/cf4fbdb8e3af38b060f98057190b4157145b0d8c/src/asciidoc/images/subset-of-tests-for-filtering.png -------------------------------------------------------------------------------- /src/asciidoc/images/tags-in-reports.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/serenity-bdd/serenity-documentation/cf4fbdb8e3af38b060f98057190b4157145b0d8c/src/asciidoc/images/tags-in-reports.png -------------------------------------------------------------------------------- /src/asciidoc/images/test-report.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/serenity-bdd/serenity-documentation/cf4fbdb8e3af38b060f98057190b4157145b0d8c/src/asciidoc/images/test-report.png -------------------------------------------------------------------------------- /src/asciidoc/images/tests_with_references_to_issues.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/serenity-bdd/serenity-documentation/cf4fbdb8e3af38b060f98057190b4157145b0d8c/src/asciidoc/images/tests_with_references_to_issues.png -------------------------------------------------------------------------------- /src/asciidoc/images/thucydides-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/serenity-bdd/serenity-documentation/cf4fbdb8e3af38b060f98057190b4157145b0d8c/src/asciidoc/images/thucydides-logo.png -------------------------------------------------------------------------------- /src/asciidoc/images/thucydides-maven-reports.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/serenity-bdd/serenity-documentation/cf4fbdb8e3af38b060f98057190b4157145b0d8c/src/asciidoc/images/thucydides-maven-reports.png -------------------------------------------------------------------------------- /src/asciidoc/images/thucydides-test-report.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/serenity-bdd/serenity-documentation/cf4fbdb8e3af38b060f98057190b4157145b0d8c/src/asciidoc/images/thucydides-test-report.png -------------------------------------------------------------------------------- /src/asciidoc/importing-test-outcomes.adoc: -------------------------------------------------------------------------------- 1 | During execution of test Serenity BDD generate Test Outcomes and use them to build aggregated report. It is possible for some external tools load test outcomes and analise them. 2 | 3 | === Loading Test OutComes from folder 4 | 5 | Test outcomes by default are generated in XML and JSON format, both format contains same information - testcase, suites, test results, rest queries and so on. 6 | Serenity BDD uses recreation of these test result - 'TestOutcome' and some extra features available in 'TestOutcomes'. 7 | 8 | To load test outcome you should know their format and folder: 9 | 10 | [source,java] 11 | ---- 12 | .... 13 | OutcomeFormat format = OutcomeFormat.XML; 14 | TestOutcomes outcomes = TestOutcomeLoader.loadTestOutcomes().inFormat(format) 15 | .... 16 | ---- 17 | 18 | === Analysing Test OutComes 19 | 20 | It is easy to analise test outcomes, for example for getting all passed test you should: 21 | 22 | [source,java] 23 | ---- 24 | .... 25 | outcomes.getPassingTests(); 26 | .... 27 | ---- 28 | 29 | Also you can get a lot of information from test ourcomes about execute tests, for example: 30 | 31 | [source,java] 32 | ---- 33 | .... 34 | for (final TestOutcome outcome : outcomes.getOutcomes()) { 35 | System.out.println(outcome.getCompleteName()); 36 | System.out.println(outcome.getTestCaseName()); 37 | System.out.println(outcome.getResult()); 38 | System.out.println(outcome.getDurationInSeconds()); 39 | System.out.println(outcome.getDataTable()); // if test was with some data table 40 | System.out.println(outcome.getIssueKeys()); 41 | } 42 | .... 43 | ---- 44 | 45 | -------------------------------------------------------------------------------- /src/asciidoc/maven.adoc: -------------------------------------------------------------------------------- 1 | Serenity BDD integrates with http://maven.apache.org/[Maven] via the `serenity-maven-plugin`. 2 | An example of a `pom.xml` file using Serenity BDD is shown here: 3 | 4 | [source,xml] 5 | ---- 6 | include::{srcdir}/junit-quick-start/pom.xml[] 7 | ---- 8 | <1> Core Serenity dependency 9 | <2> JUnit Serenity dependency 10 | <3> The Maven Failsafe plugin 11 | <4> Include only tests in the `junit` directory 12 | <5> The Serenity Maven Plugin 13 | <6> Generate the aggregate reports during the post-integration test phase 14 | <7> Call the 'aggregate' goal to generate them 15 | <8> Pass the `webdriver.driver` system property to the tests. 16 | 17 | First, you need to add the Serenity BDD dependencies to your project. You will typically add `core` and another dependency that correpsonds to the testing library you are using (JUnit in this example). Other supported testing libraries include JBehave and Cucumber. 18 | 19 | You typically want the Serenity tests to run as integration tests (that is, during the 'integration-test' phase of the Maven build) rather than as unit tests. You also want the build not to immediately fail when a test fails, but to continue until it has generated the Serenity aggregate reports before failing at the end of the build. To do this, we use the `maven-failsafe-plugin` (3). This plugin runs your integration test in the `integration-test` phase without immediately failing the build when a test fails. Build failure is triggered later in the lifecycle, during the `verify` phase. Also it is good idea turn off failing build if some test was failed - just to allow maven execute all tests. 20 | 21 | [source,xml] 22 | ---- 23 | 24 | org.apache.maven.plugins 25 | maven-surefire-plugin 26 | xxxx 27 | 28 | true 29 | 30 | 31 | ---- 32 | 33 | Normal JUnit tests run from Maven need to start or end with `Test`. But for acceptance tests, a more flexible strategy is better, as it makes it easier to name test cases after scenarios or stories. In the `pom.xml` file shown above, we configure the `maven-failsafe-plugin` to run all of the tests in the `junit` directory, regardless of how they are named (4). 34 | 35 | Next, you need to add and configure the `serenity-maven-plugin`.Pt. 5 A useful technique is to bind the `aggregate` goal plugin to the `post-integration-test` phase. Pt.6 and Pt.7 This way, to run the tests and to generate the reports, you would run the following: 36 | 37 | [source,bash] 38 | ---- 39 | mvn verify 40 | ---- 41 | 42 | This will run the tests and generate an aggregate report in the `target/site/serenity` directory. 43 | 44 | Like the surefire plugin the `maven-failsafe-plugin` starts a new JVM instance to run the tests. For this reason, if you need to pass system parameters to the tests (for example, the `webdriver.driver` property shown here), you need to use the `` section 45 | 46 | Tip: It is possible to use a Junit Run Configuration to run a Serenity Testrunner. This will not generate an aggregate report. If you find your index.html file is missing, check that you are using a Maven build Run Configuration with goal verify to run your test and get the aggregate report. 47 | -------------------------------------------------------------------------------- /src/asciidoc/remote.adoc: -------------------------------------------------------------------------------- 1 | You can also use Serenity to run your WebDriver tests on a remote machine, such as a Selenium Grid or a remote service such as provided by http://www.saucelabs.com[SauceLabs] or https://www.browserstack.com[BrowserStack]. This allows you to run your web tests against a variety of different browsers and operating systems, and also benefit from faster test execution when running the tests in parallel. 2 | 3 | In all cases, you tell Serenity to run tests remotely by using the Selenium Remote driver, 4 | 5 | === Running tests against a Selenium Grid server 6 | 7 | https://code.google.com/p/selenium/wiki/Grid2[Selenium Grid] allows you to run tests on a number of remote machines. It is open source, and relatively easy to set up and configure. 8 | 9 | To run your Serenity tests on a Selenium Grid, you need to provide the URL of the Selenium Hub using the `webdriver.remote.url` property. You may also want to provide more information about how and where you want to run your tests, using the following properties: 10 | `webdriver.remote.driver`:: What driver to use remotely ('firefox','chrome','iexplorer' etc.) 11 | `webdriver.remote.browser.version`:: What version of the remote browser to use 12 | `webdriver.remote.os`:: What operating system the tests should be run on. 13 | 14 | For example, if you were running a Selenium Hub locally on port 4444 (the default), 15 | 16 | ----- 17 | mvn verify -Dwebdriver.remote.url=http://localhost:4444/wd/hub -Dwebdriver.remote.driver=chrome -Dwebdriver.remote.os=WINDOWS 18 | ----- 19 | 20 | If you are running PhantomJS remotely, you may need to specify what port PhantomJS is to run on using the `phantomjs.webdriver` property. 21 | 22 | ----- 23 | mvn verify -Dphantomjs.webdriver=5555 -Dwebdriver.remote.url=http://seleniumgrid:4444/wd/hub 24 | ----- 25 | 26 | You can also pass the usual driver-specific capabilities to the remote browser 27 | 28 | ----- 29 | mvn verify -Dwebdriver.remote.url=http://localhost:4444/wd/hub -Dwebdriver.remote.driver=chrome -Dwebdriver.remote.os=WINDOWS -Dchrome.switches="--no-sandbox,--ignore-certificate-errors,--homepage=about:blank,--no-first-run" 30 | ----- 31 | 32 | === Running tests on BrowserStack 33 | 34 | The setup for running tests on BrowserStack is similar to the one for SauceLabs. The following system properties are available: 35 | 36 | `browserstack.url`:: BrowserStack Hub URL if running the tests on BrowserStack Cloud 37 | `browserstack.os`:: OS type (e.g. WINDOWS, OS X) 38 | `browserstack.os_version`:: OS version (e.g. Windows: XP, 7, 8 and 8.1; OS X: Snow Leopard, Lion, Mountain Lion, Mavericks, Yosemite, El Capitan) 39 | `browserstack.browser`:: Browser type (e.g. Firefox, Safari, IE, Chrome, Opera) 40 | `browserstack.browser_version`:: Browser version (defaults to latest stable; check https://www.browserstack.com/list-of-browsers-and-platforms?product=automate[list of available browsers]) 41 | `browserstack.device`:: BrowserStack https://www.browserstack.com/list-of-browsers-and-platforms?product=automate[mobile device] name on which tests should be run 42 | `browserstack.deviceOrientation`:: Set the screen orientation of BrowserStack mobile device (portrait or landscape, default: portrait) 43 | `browserstack.project`:: Specify a name for a logical group of builds on BrowserStack 44 | `browserstack.build`:: Specify a name for a logical group of tests on BrowserStack 45 | `browserstack.name`:: Specify an identifier for the test run on BrowserStack 46 | `browserstack.local`:: For Testing against https://www.browserstack.com/local-testing[internal/local] servers on BrowserStack 47 | `browserstack.localIdentifier`:: Specify an identifier fot the local browserstack connection check https://www.browserstack.com/local-testing#multiple-connections 48 | `browserstack.debug`:: Generates screenshots at various steps in tests on BrowserStack 49 | `browserstack.resolution`:: Sets resolution of VM on BrowserStack 50 | `browserstack.selenium_version`:: 51 | `browserstack.ie.noFlash`:: Disable flash on Internet Explorer on BrowserStack 52 | `browserstack.ie.driver`:: Specify the Internet Explorer webdriver version on BrowserStack 53 | `browserstack.ie.enablePopups`:: Enable the popup blocker in Internet Explorer on BrowserStack 54 | -------------------------------------------------------------------------------- /src/asciidoc/retry.adoc: -------------------------------------------------------------------------------- 1 | Sometimes it is required to retry a failed test. For the Junit tests, this can be achieved by setting the system property +test.retry.count+ to the maximum number of times you want the failed tests to be retried. All method tests will be executed until first successful run, but not more than +test.retry.count+ times. 2 | 3 | For the Cucumber tests, there is an equivalent property +test.retry.count.cucumber+ 4 | 5 | Here is short example, for it we will use next test class: 6 | 7 | [source,java] 8 | ---- 9 | include::{srcdir}/junit-retries/net/serenity/samples/retries/SampleTest.java[] 10 | ---- 11 | 12 | Steps class: 13 | 14 | [source,java] 15 | ---- 16 | include::{srcdir}/junit-retries/net/serenity/samples/retries/TestSteps.java[] 17 | ---- 18 | 19 | If this test will be executed - it will fail: 20 | 21 | 22 | [[retry_test_fail]] 23 | .Report with failed scenario 24 | image::retry_test_fail.png[] 25 | 26 | If we set the property +test.retry.count=4+ in serenity.property file, the failing tests will be executed until they will be successful or the maximum number of tries will be reached: 27 | 28 | The same test execution with the +test.retry.count+ property set will be successfull - because the method +then_example_result_should_be+ fails only twice, and third execution will be successful: 29 | 30 | [[retry_test_fail]] 31 | .Report with successful unstable scenario 32 | image::retry_test_success_unstable.png[] 33 | 34 | If you're using Jenkins for aggregating your test results use this folder pattern for JUnit test results: 35 | 36 | ---- 37 | target/site/serenity/SERENITY-JUNIT-*.xml 38 | ---- 39 | 40 | This will exclude the previous failed tests from your report. 41 | 42 | Failed JUnit tests can also be recorded in files and rerun later. 43 | To activate recording of the failed tests, the property +record.failures+ must be set to true. 44 | By default, the failed tests are recorded in a directory called +rerun+ in the current directory. 45 | To change the directory where the tests are recorded, the property +rerun.failures.directory+ can be used. 46 | To rerun only the failed tests which are registered in the +rerun+ directory, the property +replay.failures+ must be set to true. 47 | 48 | 49 | 50 | -------------------------------------------------------------------------------- /src/asciidoc/serenity-issues.adoc: -------------------------------------------------------------------------------- 1 | Serenity BDD allows create links between stories/tests and issues. Sometimes it is useful for complex development workflow, and for organizing self-documented tests. 2 | 3 | Configuration of links is made by annotations and property `serenity.issue.tracker.url` that can be provided in serenity.params or using system variables. The URL provided by `serenity.issue.tracker.url` is used as "body of link", and issue name provided in annotations - last part of this link. 4 | 5 | Generally in annotations you should use name of issues according to mask #(NAME)(-)(NUMBER), link will be created to (NAME)(-)(NUMBER), below you can find example. 6 | 7 | ==== Linking with issues for JUnit 8 | When tests created with JUnit you can use annotations `@Issue`, `@Issues`, `@Title`. 9 | 10 | * `@Issue` used for linking single issue. It should be initialised with name of referenced issue, started with `#` 11 | * `@Issues` used for linking multiple issues. It should be initialised with array with names of referenced issues, started with `#` 12 | * `@Title` used for providing readable name of test case (more in <>), also it can be used to linking multiple issues to this scenario - in title should be included name of issue started with `#` 13 | 14 | Here is little example with test cases linked to issues: 15 | 16 | serenity.properties contains: 17 | 18 | [source,gherkin] 19 | ---- 20 | include::{srcdir}/junit-tests-linked-to-issues/serenity.properties[] 21 | ---- 22 | 23 | 24 | test class looks like: 25 | 26 | [source,java] 27 | ---- 28 | include::{srcdir}/junit-tests-linked-to-issues/src/test/java/net/serenity/samples/retries/SampleTest.java[] 29 | ---- 30 | 31 | In this case report will look like: 32 | 33 | [[jbehave-requirements-report]] 34 | .Report with test cases linked to issues 35 | image::tests_with_references_to_issues.png[] 36 | 37 | Also, all references clickable and will be : 38 | ---- 39 | #PN-97: https://example.server.com/cases/view/PN-97 40 | #KB-927: https://example.server.com/cases/view/KB-927 41 | #NO-97: https://example.server.com/cases/view/NO-97 42 | ---- 43 | 44 | ==== Linking with issues for JBehave 45 | Also you can use the `@issue` annotation or `#` in scenario name to link scenarios with issues when using JBehave, as illustrated here: 46 | 47 | [source,gherkin] 48 | ---- 49 | Meta: 50 | @issue #MYPROJ-1, #MYPROJ-2 51 | 52 | Scenario: A scenario that works according #MP-4 53 | Meta: 54 | @issues #MYPROJ-3,#MYPROJ-4 55 | @issue #MYPROJ-5 56 | 57 | Given I have an implemented JBehave scenario 58 | And the scenario works 59 | When I run the scenario 60 | Then I should get a successful result 61 | ---- 62 | 63 | In this case links will be created according same rules as for <> 64 | 65 | 66 | ==== Linking with issues for Cucumber 67 | The `@issue` or `@issues` annotations can be used in Cucumber `.feature` files to link scenarios with issues , as shown below: 68 | 69 | [source,gherkin] 70 | ---- 71 | 72 | @issues:ISSUE-123,ISSUE-789 73 | Feature: Basic Arithmetic 74 | Calculating Additions 75 | 76 | Background: A Calculator 77 | Given a calculator I just turned on 78 | 79 | @issues:ISSUE-456,ISSUE-001 80 | Scenario: Addition 81 | When I add 4 and 5 82 | Then the result is 9 83 | 84 | @issue:ISSUE-456 85 | Scenario: Another Addition 86 | When I add 4 and 7 87 | Then the result is 11 88 | 89 | ---- 90 | 91 | -------------------------------------------------------------------------------- /src/samples/build-all.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | function junit-quick-start { 3 | echo "Building junit-quick-start" 4 | cd junit-quick-start && ./gradlew clean build 5 | } 6 | 7 | junit-quick-start 8 | -------------------------------------------------------------------------------- /src/samples/build.gradle: -------------------------------------------------------------------------------- 1 | task wrapper(type: Wrapper) { 2 | gradleVersion = '2.1' 3 | } -------------------------------------------------------------------------------- /src/samples/cucumber-quick-start/.gitignore: -------------------------------------------------------------------------------- 1 | *.class 2 | 3 | # Mobile Tools for Java (J2ME) 4 | .mtj.tmp/ 5 | 6 | # Package Files # 7 | *.war 8 | *.ear 9 | 10 | target 11 | build 12 | *.ipr 13 | *.iml 14 | *.iws 15 | .project 16 | .classpath 17 | .settings 18 | -------------------------------------------------------------------------------- /src/samples/cucumber-quick-start/README.md: -------------------------------------------------------------------------------- 1 | Etsy Tester Project 2 | =========== 3 | 4 | This is a sample project used for the Parleys WebDriver online courses. It contains starting points and solutions for the exercises in this course. 5 | -------------------------------------------------------------------------------- /src/samples/cucumber-quick-start/build.gradle: -------------------------------------------------------------------------------- 1 | repositories { 2 | mavenLocal() 3 | jcenter() 4 | } 5 | 6 | buildscript { 7 | repositories { 8 | mavenLocal() 9 | jcenter() 10 | } 11 | dependencies { 12 | classpath("net.serenity-bdd:serenity-gradle-plugin:1.0.47") 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 | testCompile 'org.slf4j:slf4j-api:1.7.5' 26 | 27 | testCompile 'junit:junit:4.11' 28 | testCompile 'org.assertj:assertj-core:1.7.0' 29 | testCompile 'net.serenity-bdd:core:1.0.47' 30 | testCompile 'net.serenity-bdd:serenity-junit:1.0.47' 31 | testCompile 'net.serenity-bdd:serenity-cucumber:1.0.15' 32 | } 33 | 34 | tasks.withType(Test) { 35 | systemProperty 'tags', System.getProperty('tags', '') 36 | } 37 | 38 | task wrapper(type: Wrapper) { 39 | gradleVersion = '2.1' 40 | } -------------------------------------------------------------------------------- /src/samples/cucumber-quick-start/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/serenity-bdd/serenity-documentation/cf4fbdb8e3af38b060f98057190b4157145b0d8c/src/samples/cucumber-quick-start/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /src/samples/cucumber-quick-start/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Tue Nov 18 09:07:34 CET 2014 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-2.1-all.zip 7 | -------------------------------------------------------------------------------- /src/samples/cucumber-quick-start/gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 12 | set DEFAULT_JVM_OPTS= 13 | 14 | set DIRNAME=%~dp0 15 | if "%DIRNAME%" == "" set DIRNAME=. 16 | set APP_BASE_NAME=%~n0 17 | set APP_HOME=%DIRNAME% 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windowz variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | if "%@eval[2+2]" == "4" goto 4NT_args 53 | 54 | :win9xME_args 55 | @rem Slurp the command line arguments. 56 | set CMD_LINE_ARGS= 57 | set _SKIP=2 58 | 59 | :win9xME_args_slurp 60 | if "x%~1" == "x" goto execute 61 | 62 | set CMD_LINE_ARGS=%* 63 | goto execute 64 | 65 | :4NT_args 66 | @rem Get arguments from the 4NT Shell from JP Software 67 | set CMD_LINE_ARGS=%$ 68 | 69 | :execute 70 | @rem Setup the command line 71 | 72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if "%ERRORLEVEL%"=="0" goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 85 | exit /b 1 86 | 87 | :mainEnd 88 | if "%OS%"=="Windows_NT" endlocal 89 | 90 | :omega 91 | -------------------------------------------------------------------------------- /src/samples/cucumber-quick-start/serenity.properties: -------------------------------------------------------------------------------- 1 | webdriver.driver=firefox 2 | serenity.take.screenshots=AFTER_EACH_STEP 3 | -------------------------------------------------------------------------------- /src/samples/cucumber-quick-start/src/main/java/net/serenitybdd/samples/etsy/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * This package will contain any reusable web test components. 3 | */ 4 | package net.serenity_bdd.samples.etsy; -------------------------------------------------------------------------------- /src/samples/cucumber-quick-start/src/test/java/net/serenity_bdd/samples/etsy/features/AddingItemsToTheShoppingCart.java: -------------------------------------------------------------------------------- 1 | package net.serenity_bdd.samples.etsy.features; 2 | 3 | import cucumber.api.CucumberOptions; 4 | import net.serenitybdd.cucumber.CucumberWithSerenity; 5 | import org.junit.runner.RunWith; 6 | 7 | @RunWith(CucumberWithSerenity.class) 8 | @CucumberOptions(features="src/test/resources/features/shopping_cart/adding_items_to_the_shopping_cart.feature") 9 | public class AddingItemsToTheShoppingCart {} 10 | -------------------------------------------------------------------------------- /src/samples/cucumber-quick-start/src/test/java/net/serenity_bdd/samples/etsy/features/SearchByKeyword.java: -------------------------------------------------------------------------------- 1 | package net.serenity_bdd.samples.etsy.features; 2 | 3 | import cucumber.api.CucumberOptions; 4 | import net.serenitybdd.cucumber.CucumberWithSerenity; 5 | import org.junit.runner.RunWith; 6 | 7 | @RunWith(CucumberWithSerenity.class) 8 | @CucumberOptions(features="src/test/resources/features/search/search_by_keyword.feature") 9 | public class SearchByKeyword {} 10 | -------------------------------------------------------------------------------- /src/samples/cucumber-quick-start/src/test/java/net/serenity_bdd/samples/etsy/features/model/ListingItem.java: -------------------------------------------------------------------------------- 1 | package net.serenity_bdd.samples.etsy.features.model; 2 | 3 | /** 4 | * Created by john on 12/11/14. 5 | */ 6 | public class ListingItem { 7 | private final String name; 8 | private final double price; 9 | 10 | public ListingItem(String name, double price) { 11 | this.name = name; 12 | this.price = price; 13 | } 14 | 15 | public String getName() { 16 | return name; 17 | } 18 | 19 | public double getPrice() { 20 | return price; 21 | } 22 | 23 | @Override 24 | public boolean equals(Object o) { 25 | if (this == o) return true; 26 | if (!(o instanceof ListingItem)) return false; 27 | 28 | ListingItem listingItem = (ListingItem) o; 29 | 30 | if (Double.compare(listingItem.price, price) != 0) return false; 31 | if (name != null ? !name.equals(listingItem.name) : listingItem.name != null) return false; 32 | 33 | return true; 34 | } 35 | 36 | @Override 37 | public int hashCode() { 38 | int result; 39 | long temp; 40 | result = name != null ? name.hashCode() : 0; 41 | temp = Double.doubleToLongBits(price); 42 | result = 31 * result + (int) (temp ^ (temp >>> 32)); 43 | return result; 44 | } 45 | 46 | @Override 47 | public String toString() { 48 | return "Listing{" + 49 | "name='" + name + '\'' + 50 | ", price=" + price + 51 | '}'; 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/samples/cucumber-quick-start/src/test/java/net/serenity_bdd/samples/etsy/features/model/OrderCostSummary.java: -------------------------------------------------------------------------------- 1 | package net.serenity_bdd.samples.etsy.features.model; 2 | 3 | /** 4 | * Created by john on 13/11/14. 5 | */ 6 | public class OrderCostSummary { 7 | private final String name; 8 | private final double itemTotal; 9 | private final double shipping; 10 | private final double totalCost; 11 | 12 | public OrderCostSummary(String name, double itemTotal, double shipping, double totalCost) { 13 | this.name = name; 14 | this.itemTotal = itemTotal; 15 | this.shipping = shipping; 16 | this.totalCost = totalCost; 17 | } 18 | 19 | public String getName() { 20 | return name; 21 | } 22 | 23 | public double getItemTotal() { 24 | return itemTotal; 25 | } 26 | 27 | public double getShipping() { 28 | return shipping; 29 | } 30 | 31 | public double getTotalCost() { 32 | return totalCost; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/samples/cucumber-quick-start/src/test/java/net/serenity_bdd/samples/etsy/features/model/SessionVariables.java: -------------------------------------------------------------------------------- 1 | package net.serenity_bdd.samples.etsy.features.model; 2 | 3 | /** 4 | * Created by john on 12/11/14. 5 | */ 6 | public enum SessionVariables { 7 | SELECTED_LISTING 8 | } 9 | -------------------------------------------------------------------------------- /src/samples/cucumber-quick-start/src/test/java/net/serenity_bdd/samples/etsy/features/steps/SearchByKeywordStepDefinitions.java: -------------------------------------------------------------------------------- 1 | package net.serenity_bdd.samples.etsy.features.steps; 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.serenity_bdd.samples.etsy.features.steps.serenity.BuyerSteps; 7 | import net.thucydides.core.annotations.Steps; 8 | 9 | // tag::header[] 10 | public class SearchByKeywordStepDefinitions { 11 | @Steps 12 | BuyerSteps buyer; 13 | 14 | // end::header[] 15 | // tag::woolscenario[] 16 | @Given("I want to buy (.*)") 17 | public void buyerWantsToBuy(String article) { 18 | buyer.opens_etsy_home_page(); 19 | } 20 | 21 | @When("I search for items containing '(.*)'") 22 | public void searchByKeyword(String keyword) { 23 | buyer.searches_for_items_containing(keyword); 24 | } 25 | 26 | @Then("I should only see items related to '(.*)'") 27 | public void resultsForACategoryAndKeywordInARegion(String keyword) { 28 | buyer.should_see_items_related_to(keyword); 29 | } 30 | // end::woolscenario[] 31 | 32 | String searchTerm; 33 | 34 | @Given("I have searched for items containing '(.*)' in my region") 35 | public void buyerHasSearchedFor(String keyword) { 36 | searchTerm = keyword; 37 | buyer.opens_etsy_home_page(); 38 | buyer.searches_for_items_containing(keyword); 39 | buyer.filters_by_local_region(); 40 | } 41 | 42 | @Given("I have searched for items containing the word '(.*)'") 43 | public void buyerHasSearchedForWord(String keyword) { 44 | searchTerm = keyword; 45 | buyer.opens_etsy_home_page(); 46 | buyer.searches_for_items_containing(keyword); 47 | } 48 | 49 | 50 | @When("I filter results by type '(.*)'") 51 | public void filterResultsBy(String type) { 52 | buyer.filters_results_by_type(type); 53 | } 54 | 55 | @Then("I should only see items containing '(.*)' of type '(.*)'") 56 | public void shouldSeeMatchingFilteredResults(String keyword, String type) { 57 | buyer.should_see_items_related_to(keyword); 58 | buyer.should_see_items_of_type(type); 59 | } 60 | 61 | @When("I (?:select|have selected) an item") 62 | public void selectsAnItem() { 63 | buyer.selects_item_number(1); 64 | } 65 | 66 | @Then("I should see the corresponding item details") 67 | public void shouldSeeCorrespondingDetails() { 68 | buyer.should_see_matching_details(searchTerm); 69 | } 70 | // tag::tail[] 71 | } 72 | // end::tail[] 73 | -------------------------------------------------------------------------------- /src/samples/cucumber-quick-start/src/test/java/net/serenity_bdd/samples/etsy/features/steps/ShoppingCartStepDefinitions.java: -------------------------------------------------------------------------------- 1 | package net.serenity_bdd.samples.etsy.features.steps; 2 | 3 | import cucumber.api.java.en.Then; 4 | import cucumber.api.java.en.When; 5 | import net.serenitybdd.core.Serenity; 6 | import net.serenity_bdd.samples.etsy.features.model.ListingItem; 7 | import net.serenity_bdd.samples.etsy.features.steps.serenity.BuyerSteps; 8 | import net.thucydides.core.annotations.Steps; 9 | import static net.serenity_bdd.samples.etsy.features.model.SessionVariables.SELECTED_LISTING; 10 | 11 | public class ShoppingCartStepDefinitions { 12 | 13 | @Steps 14 | BuyerSteps buyer; 15 | 16 | @When("I add the item to the shopping cart") 17 | public void addCurrentItemToShoppingCart() { 18 | buyer.selects_any_product_variations(); 19 | buyer.adds_current_item_to_shopping_cart(); 20 | } 21 | 22 | @Then("the item should appear in the cart") 23 | public void shouldSeeSelectedItemInCart() { 24 | ListingItem selectedItem = (ListingItem) Serenity.sessionVariableCalled(SELECTED_LISTING); 25 | buyer.should_see_item_in_cart(selectedItem); 26 | } 27 | 28 | @Then("the shipping cost should be included in the total price") 29 | public void shouldIncludeShippingCost() { 30 | ListingItem selectedItem = (ListingItem) Serenity.sessionVariableCalled(SELECTED_LISTING); 31 | buyer.should_see_total_including_shipping_for(selectedItem); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/samples/cucumber-quick-start/src/test/java/net/serenity_bdd/samples/etsy/pages/CartPage.java: -------------------------------------------------------------------------------- 1 | package net.serenity_bdd.samples.etsy.pages; 2 | 3 | import net.serenity_bdd.samples.etsy.features.model.ListingItem; 4 | import net.serenity_bdd.samples.etsy.features.model.OrderCostSummary; 5 | import net.serenitybdd.core.pages.PageObject; 6 | import net.serenitybdd.core.pages.WebElementFacade; 7 | 8 | import java.util.List; 9 | import java.util.Optional; 10 | import java.util.stream.Collectors; 11 | 12 | public class CartPage extends PageObject { 13 | 14 | public List getOrderCostSummaries() { 15 | return findAll(".order-wrapper") 16 | .stream() 17 | .map(CartPage::convertToOrderCostSummary) 18 | .collect(Collectors.toList()); 19 | } 20 | 21 | public Optional getOrderCostSummaryFor(ListingItem selectedItem) { 22 | return getOrderCostSummaries() 23 | .stream() 24 | .filter(item -> item.getName().equals(selectedItem.getName())) 25 | .findFirst(); 26 | } 27 | 28 | public static OrderCostSummary convertToOrderCostSummary(WebElementFacade summaryElement) { 29 | String name = summaryElement.find(net.serenitybdd.core.annotations.findby.By.tagName("h3")).getText(); 30 | double itemTotal = Double.parseDouble(summaryElement.findBy(".item-total .currency-value").getText()); 31 | double shipping = summaryElement.containsElements(".shipping .currency-value") ? 32 | Double.parseDouble(summaryElement.findBy(".shipping .currency-value").getText()) : 0.0; 33 | 34 | double grandTotal = summaryElement.containsElements(".grand-total .currency-value") 35 | ? Double.parseDouble(summaryElement.findBy(".grand-total .currency-value").getText()) : 0.0; 36 | 37 | return new OrderCostSummary(name, itemTotal, shipping, grandTotal); 38 | } 39 | 40 | public boolean isShowingShippingCosts() { 41 | return containsElements(".shipping .currency-value"); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/samples/cucumber-quick-start/src/test/java/net/serenity_bdd/samples/etsy/pages/HomePage.java: -------------------------------------------------------------------------------- 1 | package net.serenity_bdd.samples.etsy.pages; 2 | 3 | import net.thucydides.core.annotations.DefaultUrl; 4 | import net.thucydides.core.pages.PageObject; 5 | import org.openqa.selenium.By; 6 | import org.openqa.selenium.WebElement; 7 | import org.openqa.selenium.support.FindBy; 8 | import org.openqa.selenium.support.ui.ExpectedConditions; 9 | 10 | // tag::header[] 11 | @DefaultUrl("http://www.etsy.com") // <1> 12 | public class HomePage extends PageObject { // <2> 13 | // end::header[] 14 | // tag::searchByKeyword[] 15 | 16 | @FindBy(css = "button[value='Search']") 17 | WebElement searchButton; 18 | 19 | public void searchFor(String keywords) { 20 | $("#search-query").sendKeys(keywords); // <3> 21 | searchButton.click(); // <4> 22 | } 23 | 24 | public void dismissLocationMessage() { 25 | if (!findAll(By.cssSelector("input[value='Okay']")).isEmpty()) { 26 | find(By.cssSelector("input[value='Okay']")).click(); 27 | } 28 | waitForAbsenceOf("Your preferences have been saved"); 29 | } 30 | // end::searchByKeyword[] 31 | // tag::tail[] 32 | } 33 | // end::tail[] -------------------------------------------------------------------------------- /src/samples/cucumber-quick-start/src/test/java/net/serenity_bdd/samples/etsy/pages/ItemDetailsPage.java: -------------------------------------------------------------------------------- 1 | package net.serenity_bdd.samples.etsy.pages; 2 | 3 | import net.serenitybdd.core.pages.PageObject; 4 | import net.serenitybdd.core.annotations.findby.By; 5 | import org.openqa.selenium.WebDriver; 6 | import org.openqa.selenium.WebElement; 7 | import org.openqa.selenium.interactions.Actions; 8 | import org.openqa.selenium.support.FindAll; 9 | import org.openqa.selenium.support.FindBy; 10 | import org.openqa.selenium.support.FindBys; 11 | import org.openqa.selenium.support.ui.ExpectedConditions; 12 | import org.openqa.selenium.support.ui.Wait; 13 | import org.openqa.selenium.support.ui.WebDriverWait; 14 | 15 | import java.util.List; 16 | 17 | import static java.util.stream.Collectors.toList; 18 | import static net.serenity_bdd.samples.etsy.pages.Spinners.noSpinnerToBeVisible; 19 | 20 | /** 21 | * Created by john on 18/11/14. 22 | */ 23 | public class ItemDetailsPage extends PageObject { 24 | 25 | @FindBys({@FindBy(id="listing-page-cart"), @FindBy(tagName = "h1")}) 26 | WebElement itemName; 27 | 28 | public String getItemName() { 29 | return itemName.getText(); 30 | } 31 | 32 | public String getItemDescription() { 33 | return $("#description-text").getText(); 34 | } 35 | 36 | public void addToCart() { 37 | withAction().moveToElement($("#item-tabs")).perform(); 38 | $(".buy-button button").click(); 39 | } 40 | 41 | public List getProductVariationIds() { 42 | return findAll(".variation") 43 | .stream() 44 | .map(elt -> elt.getAttribute("id")) 45 | .filter(id -> !id.isEmpty()) 46 | .collect(toList()); 47 | } 48 | 49 | public void selectVariation(String variationId, int optionIndex) { 50 | find(By.id(variationId)).selectByIndex(optionIndex); 51 | if (spinnerIsVisible()) { 52 | waitFor(noSpinnerToBeVisible()); 53 | } 54 | } 55 | 56 | private boolean spinnerIsVisible() { 57 | return containsElements(".spinner-small"); 58 | } 59 | 60 | } 61 | -------------------------------------------------------------------------------- /src/samples/cucumber-quick-start/src/test/java/net/serenity_bdd/samples/etsy/pages/SearchResultsPage.java: -------------------------------------------------------------------------------- 1 | package net.serenity_bdd.samples.etsy.pages; 2 | 3 | import com.google.common.base.Optional; 4 | import net.serenity_bdd.samples.etsy.features.model.ListingItem; 5 | import net.serenitybdd.core.pages.PageObject; 6 | import net.serenitybdd.core.pages.WebElementFacade; 7 | import org.openqa.selenium.By; 8 | import org.openqa.selenium.WebElement; 9 | import org.openqa.selenium.support.FindBy; 10 | import org.openqa.selenium.support.ui.ExpectedConditions; 11 | 12 | import java.text.NumberFormat; 13 | import java.text.ParseException; 14 | import java.util.List; 15 | import java.util.Locale; 16 | import java.util.concurrent.TimeUnit; 17 | import java.util.stream.Collectors; 18 | 19 | // tag::header[] 20 | public class SearchResultsPage extends PageObject { 21 | // end::header[] 22 | // tag::searchByKeyword[] 23 | 24 | @FindBy(css=".listing-card") 25 | List listingCards; 26 | 27 | public List getResultTitles() { 28 | return listingCards.stream() 29 | .map(element -> element.getText()) 30 | .collect(Collectors.toList()); 31 | } 32 | // end::searchByKeyword[] 33 | public ListingItem selectItem(int itemNumber) { 34 | ListingItem selectedItem = convertToListingItem(listingCards.get(itemNumber - 1)); 35 | listingCards.get(itemNumber - 1).findElement(By.tagName("a")).click(); 36 | return selectedItem; 37 | } 38 | 39 | private ListingItem convertToListingItem(WebElement itemElement) { 40 | NumberFormat format = NumberFormat.getInstance(); 41 | String price = itemElement.findElement(By.className("currency-value")).getText(); 42 | 43 | try { 44 | return new ListingItem(itemElement.findElement(By.className("title")).getText(), 45 | format.parse(price).doubleValue()); 46 | } catch (ParseException e) { 47 | throw new AssertionError("Failed to parse item price: ",e); 48 | } 49 | } 50 | 51 | // tag::withTimeout[] 52 | public void filterByType(String type) { 53 | withTimeoutOf(15, TimeUnit.SECONDS).find("#filter-marketplace").then(By.partialLinkText(type)).click(); 54 | } 55 | // end::withTimeout[] 56 | 57 | public int getItemCount() { 58 | String resultCount = $(".result-count").getText() 59 | .replace("We found ","") 60 | .replace(" item","") 61 | .replace("s","") 62 | .replace("!","") 63 | .replace(",","") 64 | ; 65 | return Integer.parseInt(resultCount); 66 | } 67 | 68 | public Optional getSelectedType() { 69 | List selectedTypes = findAll("#filter-marketplace a.selected"); 70 | return (selectedTypes.isEmpty()) ? Optional.absent() : Optional.of(selectedTypes.get(0).getText()); 71 | } 72 | 73 | public void filterByLocalRegion() { 74 | if (containsElements("#filter-location")) { 75 | withAction().moveToElement($("#filter-location")).perform(); 76 | findAll(".geoname-option a").get(1).click(); 77 | } 78 | } 79 | // tag::tail[] 80 | } 81 | // end:tail[] 82 | -------------------------------------------------------------------------------- /src/samples/cucumber-quick-start/src/test/java/net/serenity_bdd/samples/etsy/pages/Spinners.java: -------------------------------------------------------------------------------- 1 | package net.serenity_bdd.samples.etsy.pages; 2 | 3 | import net.serenitybdd.core.annotations.findby.By; 4 | import org.openqa.selenium.StaleElementReferenceException; 5 | import org.openqa.selenium.WebDriver; 6 | import org.openqa.selenium.WebElement; 7 | import org.openqa.selenium.support.ui.ExpectedCondition; 8 | 9 | import static java.util.stream.Collectors.toList; 10 | 11 | /** 12 | * Created by john on 19/12/14. 13 | */ 14 | public class Spinners { 15 | public static ExpectedCondition noSpinnerToBeVisible() { 16 | return new ExpectedCondition() { 17 | @Override 18 | public Boolean apply(WebDriver driver) { 19 | return driver.findElements(By.cssSelector(".spinner-small")) 20 | .stream() 21 | .filter(element -> isVisible(element)) 22 | .collect(toList()) 23 | .isEmpty(); 24 | } 25 | 26 | private boolean isVisible(WebElement element) { 27 | try { 28 | return !element.isDisplayed(); 29 | } catch (StaleElementReferenceException e) { 30 | // Returns true because stale element reference implies that element 31 | // is npo longer visible. 32 | return true; 33 | } 34 | } 35 | }; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/samples/cucumber-quick-start/src/test/resources/features/customers/display_customer_details.feature: -------------------------------------------------------------------------------- 1 | Feature: Display customer details 2 | In order to propose more relevant services to my customers 3 | As a financial adviser 4 | I want to view a customer's profile details 5 | 6 | Scenario: Search for customer by name 7 | Given I am logged into the application 8 | When I locate customer Sarah-Jane Smith 9 | Then I should see the following details in her Personal Profile: 10 | | Name | Sarah-Jane Smith | 11 | | Gender | Female | 12 | | Marital Status | Married | 13 | | Date of Birth | 25 May 1980 | 14 | | Dependents | 2 | 15 | | Residential Status | Resident | 16 | 17 | Scenario: Search for customer by name 18 | Given I am logged into the application 19 | And Sarah-Jane Smith is a customer with the following details: 20 | | Field | Value | 21 | | Surname | Smith | 22 | | First name | Sarah-Jane | 23 | | Gender | Female | 24 | | Marital Status | Married | 25 | | Date of Birth | 25-05-1980 | 26 | | Dependents | Joe, Jill | 27 | | Residential Status | Resident | 28 | When I locate customer Sarah-Jane Smith 29 | Then I should see the following details in her Personal Profile: 30 | | Name | Sarah-Jane Smith | 31 | | Gender | Female | 32 | | Marital Status | Married | 33 | | Date of Birth | 25 May 1980 | 34 | | Dependents | 2 | 35 | | Residential Status | Resident | 36 | 37 | 38 | -------------------------------------------------------------------------------- /src/samples/cucumber-quick-start/src/test/resources/features/customers/locating_customer.feature: -------------------------------------------------------------------------------- 1 | Feature: Locate a customer 2 | In order to provide assistance to customers more quickly 3 | As a financial adviser 4 | I want to be able to locate a customer using a variety of different criteria 5 | 6 | Background: 7 | Given I am logged into the application 8 | 9 | Scenario: Search for customer by name 10 | Given the following customers exist: 11 | | id | first name | last name | 12 | | 100 | Sarah-Jane | Smith | 13 | | 101 | Sarah | Smith | 14 | When I search for a customer using the following search criteria: 15 | | name | Sarah-Jane Smith | 16 | Then I should display the customer details for customer 100 17 | 18 | Scenario: Search for customer by name and date of birth 19 | Given the following customers exist: 20 | | id | first name | last name | date of birth | 21 | | 101 | Sarah | Smith | 10-May-1980 | 22 | | 102 | Sarah | Smith | 21-May-1950 | 23 | When I search for a customer using the following search criteria: 24 | | name | Sarah-Jane Smith | 25 | | date of birth | 10-May-1980 | 26 | Then I should display the customer details for customer 100 27 | 28 | -------------------------------------------------------------------------------- /src/samples/cucumber-quick-start/src/test/resources/features/search/search_by_keyword.feature: -------------------------------------------------------------------------------- 1 | # tag::header[] 2 | Feature: Searching by keyword 3 | 4 | In order to find items that I would like to purchase 5 | As a potential buyer 6 | I want to be able to search for items containing certain words 7 | 8 | # end::header[] 9 | # tag::woolscenario[] 10 | Scenario: Should list items related to a specified keyword 11 | Given I want to buy a wool scarf 12 | When I search for items containing 'wool' 13 | Then I should only see items related to 'wool' 14 | 15 | # end::woolscenario[] 16 | # tag::handmadescenario[] 17 | Scenario: Should be able to filter search results by item type 18 | Given I have searched for items containing 'wool' in my region 19 | When I filter results by type 'Handmade' 20 | Then I should only see items containing 'wool' of type 'Handmade' 21 | 22 | # end::handmadescenario[] 23 | # tag::handmadeoutline[] 24 | Scenario Outline: Filter by different item types 25 | Given I have searched for items containing the word '' 26 | When I filter results by type '' 27 | Then I should only see items containing '' of type '' 28 | Examples: 29 | | material | type | 30 | | silk | Handmade | 31 | | bronze | Vintage | 32 | 33 | # end::handmadeoutline[] 34 | # tag::viewdetails[] 35 | Scenario: Should be able to view details about a searched item 36 | Given I have searched for items containing the word 'wool' 37 | When I select an item 38 | Then I should see the corresponding item details 39 | # end::viewdetails[] 40 | -------------------------------------------------------------------------------- /src/samples/cucumber-quick-start/src/test/resources/features/shopping_cart/adding_items_to_the_shopping_cart.feature: -------------------------------------------------------------------------------- 1 | Feature: Adding items to the shopping cart 2 | In order to buy more than one item easily 3 | As a buyer 4 | I want to be able to add multiple items to the shopping cart 5 | 6 | Background: 7 | Given I have searched for items containing 'felt' in my region 8 | And I have selected an item 9 | 10 | Scenario: Should see total price including tax 11 | When I add the item to the shopping cart 12 | Then the item should appear in the cart 13 | And the shipping cost should be included in the total price 14 | 15 | -------------------------------------------------------------------------------- /src/samples/cucumber-quick-start/src/test/resources/features/shopping_cart/russian.feature: -------------------------------------------------------------------------------- 1 | # language: ru 2 | Функционал: Операции с картами 3 | 4 | @card1 5 | Сценарий: Просмотр краткой панели информации по карте 6 | Дано пользователь активировал демо-режим 7 | Когда пользователь выбирает карту "4276 **** **** -------------------------------------------------------------------------------- /src/samples/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/serenity-bdd/serenity-documentation/cf4fbdb8e3af38b060f98057190b4157145b0d8c/src/samples/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /src/samples/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Mon Dec 28 15:48:22 CET 2015 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-2.1-all.zip 7 | -------------------------------------------------------------------------------- /src/samples/gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 12 | set DEFAULT_JVM_OPTS= 13 | 14 | set DIRNAME=%~dp0 15 | if "%DIRNAME%" == "" set DIRNAME=. 16 | set APP_BASE_NAME=%~n0 17 | set APP_HOME=%DIRNAME% 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windowz variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | if "%@eval[2+2]" == "4" goto 4NT_args 53 | 54 | :win9xME_args 55 | @rem Slurp the command line arguments. 56 | set CMD_LINE_ARGS= 57 | set _SKIP=2 58 | 59 | :win9xME_args_slurp 60 | if "x%~1" == "x" goto execute 61 | 62 | set CMD_LINE_ARGS=%* 63 | goto execute 64 | 65 | :4NT_args 66 | @rem Get arguments from the 4NT Shell from JP Software 67 | set CMD_LINE_ARGS=%$ 68 | 69 | :execute 70 | @rem Setup the command line 71 | 72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if "%ERRORLEVEL%"=="0" goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 85 | exit /b 1 86 | 87 | :mainEnd 88 | if "%OS%"=="Windows_NT" endlocal 89 | 90 | :omega 91 | -------------------------------------------------------------------------------- /src/samples/jbehave-quick-start/build.gradle: -------------------------------------------------------------------------------- 1 | repositories { 2 | mavenLocal() 3 | jcenter() 4 | } 5 | 6 | buildscript { 7 | repositories { 8 | mavenLocal() 9 | jcenter() 10 | } 11 | dependencies { 12 | classpath("net.serenity-bdd:serenity-gradle-plugin:1.0.47") 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 | testCompile 'org.slf4j:slf4j-api:1.7.5' 26 | 27 | testCompile 'junit:junit:4.11' 28 | testCompile 'org.assertj:assertj-core:1.7.0' 29 | // tag::dependencies[] 30 | testCompile 'net.serenity-bdd:core:1.0.47' 31 | testCompile 'net.serenity-bdd:serenity-jbehave:1.0.21' 32 | // end::dependencies[] 33 | } 34 | 35 | tasks.withType(Test) { 36 | systemProperty 'webdriver.driver', System.getProperty('webdriver.driver', 'chrome') 37 | systemProperty 'tags', System.getProperty('tags', '') 38 | } 39 | 40 | task wrapper(type: Wrapper) { 41 | gradleVersion = '2.1' 42 | } -------------------------------------------------------------------------------- /src/samples/jbehave-quick-start/serenity.properties: -------------------------------------------------------------------------------- 1 | #thucydides.requirements.dir=src/test/resources/net/serenity_bdd/samples/etsy/features 2 | webdriver.driver=chrome 3 | dashboard.tag.list=capability, product, feature 4 | narrative.format=asciidoc -------------------------------------------------------------------------------- /src/samples/jbehave-quick-start/src/main/java/net/serenitybdd/samples/etsy/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * This package will contain any reusable web test components. 3 | */ 4 | package net.serenitybdd.samples.etsy; -------------------------------------------------------------------------------- /src/samples/jbehave-quick-start/src/test/java/net/serenitybdd/samples/etsy/AcceptanceTests.java: -------------------------------------------------------------------------------- 1 | package net.serenitybdd.samples.etsy; 2 | 3 | import net.serenitybdd.jbehave.SerenityStories; 4 | 5 | public class AcceptanceTests extends SerenityStories {} 6 | -------------------------------------------------------------------------------- /src/samples/jbehave-quick-start/src/test/java/net/serenitybdd/samples/etsy/features/AddingItemsToTheShoppingCart.java: -------------------------------------------------------------------------------- 1 | package net.serenitybdd.samples.etsy.features; 2 | 3 | import net.serenitybdd.jbehave.SerenityStory; 4 | 5 | /** 6 | * Created by john on 19/12/14. 7 | */ 8 | public class AddingItemsToTheShoppingCart extends SerenityStory { 9 | } 10 | -------------------------------------------------------------------------------- /src/samples/jbehave-quick-start/src/test/java/net/serenitybdd/samples/etsy/features/SearchByKeyword.java: -------------------------------------------------------------------------------- 1 | package net.serenitybdd.samples.etsy.features; 2 | 3 | import net.serenitybdd.jbehave.SerenityStory; 4 | 5 | /** 6 | * Created by john on 19/12/14. 7 | */ 8 | public class SearchByKeyword extends SerenityStory { 9 | } 10 | -------------------------------------------------------------------------------- /src/samples/jbehave-quick-start/src/test/java/net/serenitybdd/samples/etsy/features/model/ListingItem.java: -------------------------------------------------------------------------------- 1 | package net.serenitybdd.samples.etsy.features.model; 2 | 3 | /** 4 | * Created by john on 12/11/14. 5 | */ 6 | public class ListingItem { 7 | private final String name; 8 | private final double price; 9 | 10 | public ListingItem(String name, double price) { 11 | this.name = name; 12 | this.price = price; 13 | } 14 | 15 | public String getName() { 16 | return name; 17 | } 18 | 19 | public double getPrice() { 20 | return price; 21 | } 22 | 23 | @Override 24 | public boolean equals(Object o) { 25 | if (this == o) return true; 26 | if (!(o instanceof ListingItem)) return false; 27 | 28 | ListingItem listingItem = (ListingItem) o; 29 | 30 | if (Double.compare(listingItem.price, price) != 0) return false; 31 | if (name != null ? !name.equals(listingItem.name) : listingItem.name != null) return false; 32 | 33 | return true; 34 | } 35 | 36 | @Override 37 | public int hashCode() { 38 | int result; 39 | long temp; 40 | result = name != null ? name.hashCode() : 0; 41 | temp = Double.doubleToLongBits(price); 42 | result = 31 * result + (int) (temp ^ (temp >>> 32)); 43 | return result; 44 | } 45 | 46 | @Override 47 | public String toString() { 48 | return "Listing{" + 49 | "name='" + name + '\'' + 50 | ", price=" + price + 51 | '}'; 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/samples/jbehave-quick-start/src/test/java/net/serenitybdd/samples/etsy/features/model/OrderCostSummary.java: -------------------------------------------------------------------------------- 1 | package net.serenitybdd.samples.etsy.features.model; 2 | 3 | /** 4 | * Created by john on 13/11/14. 5 | */ 6 | public class OrderCostSummary { 7 | private final String name; 8 | private final double itemTotal; 9 | private final double shipping; 10 | private final double totalCost; 11 | 12 | public OrderCostSummary(String name, double itemTotal, double shipping, double totalCost) { 13 | this.name = name; 14 | this.itemTotal = itemTotal; 15 | this.shipping = shipping; 16 | this.totalCost = totalCost; 17 | } 18 | 19 | public String getName() { 20 | return name; 21 | } 22 | 23 | public double getItemTotal() { 24 | return itemTotal; 25 | } 26 | 27 | public double getShipping() { 28 | return shipping; 29 | } 30 | 31 | public double getTotalCost() { 32 | return totalCost; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/samples/jbehave-quick-start/src/test/java/net/serenitybdd/samples/etsy/features/model/SessionVariables.java: -------------------------------------------------------------------------------- 1 | package net.serenitybdd.samples.etsy.features.model; 2 | 3 | /** 4 | * Created by john on 12/11/14. 5 | */ 6 | public enum SessionVariables { 7 | SELECTED_LISTING 8 | } 9 | -------------------------------------------------------------------------------- /src/samples/jbehave-quick-start/src/test/java/net/serenitybdd/samples/etsy/features/steps/SearchByKeywordStepDefinitions.java: -------------------------------------------------------------------------------- 1 | package net.serenitybdd.samples.etsy.features.steps; 2 | 3 | import net.serenitybdd.samples.etsy.features.steps.serenity.BuyerSteps; 4 | import net.thucydides.core.annotations.Steps; 5 | import org.jbehave.core.annotations.Given; 6 | import org.jbehave.core.annotations.Then; 7 | import org.jbehave.core.annotations.When; 8 | 9 | // tag::header[] 10 | public class SearchByKeywordStepDefinitions { 11 | @Steps 12 | BuyerSteps buyer; 13 | 14 | // end::header[] 15 | // tag::woolscenario[] 16 | @Given("I want to buy $article") 17 | public void buyerWantsToBuy(String article) { 18 | buyer.opens_etsy_home_page(); 19 | } 20 | 21 | @When("I search for items containing '$keyword'") 22 | public void searchByKeyword(String keyword) { 23 | buyer.searches_for_items_containing(keyword); 24 | buyer.filters_results_to_local_region(); 25 | } 26 | 27 | 28 | @When("I search for local items containing '$keyword'") 29 | public void localSearchByKeyword(String keyword) { 30 | buyer.searches_for_items_containing(keyword); 31 | } 32 | 33 | @Then("I should only see items related to '$keyword'") 34 | public void resultsForACategoryAndKeywordInARegion(String keyword) { 35 | buyer.should_see_items_related_to(keyword); 36 | } 37 | // end::woolscenario[] 38 | 39 | String searchTerm; 40 | 41 | @Given("I have searched for items containing '$keyword'") 42 | public void buyerHasSearchedFor(String keyword) { 43 | searchTerm = keyword; 44 | buyer.opens_etsy_home_page(); 45 | buyer.searches_for_items_containing(keyword); 46 | } 47 | 48 | @When("I filter results by type '$type'") 49 | public void filterResultsBy(String type) { 50 | buyer.filters_results_by_type(type); 51 | } 52 | 53 | @Then("I should only see items containing '$keyword' of type '$type'") 54 | public void shouldSeeMatchingFilteredResults(String keyword, String type) { 55 | buyer.should_see_items_related_to(keyword); 56 | buyer.should_see_items_of_type(type); 57 | } 58 | 59 | @When("I select an item") 60 | public void selectsAnItem() { 61 | buyer.selects_item_number(1); 62 | } 63 | 64 | @Then("I should see the corresponding item details") 65 | public void shouldSeeCorrespondingDetails() { 66 | buyer.should_see_matching_details(searchTerm); 67 | } 68 | // tag::tail[] 69 | } 70 | // end::tail[] 71 | -------------------------------------------------------------------------------- /src/samples/jbehave-quick-start/src/test/java/net/serenitybdd/samples/etsy/features/steps/ShoppingCartStepDefinitions.java: -------------------------------------------------------------------------------- 1 | package net.serenitybdd.samples.etsy.features.steps; 2 | 3 | import net.serenitybdd.samples.etsy.features.model.ListingItem; 4 | import net.serenitybdd.samples.etsy.features.steps.serenity.BuyerSteps; 5 | import net.serenitybdd.core.Serenity; 6 | import net.serenitybdd.samples.etsy.features.model.SessionVariables; 7 | import net.thucydides.core.annotations.Steps; 8 | import org.jbehave.core.annotations.Given; 9 | import org.jbehave.core.annotations.Then; 10 | import org.jbehave.core.annotations.When; 11 | 12 | public class ShoppingCartStepDefinitions { 13 | @Steps 14 | BuyerSteps buyer; 15 | 16 | @Given("I have selected an item") 17 | @When("I select an item") 18 | public void selectsAnItem() { 19 | buyer.selects_item_number(1); 20 | } 21 | 22 | @When("I add the item to the shopping cart") 23 | public void addCurrentItemToShoppingCart() { 24 | buyer.selects_any_product_variations(); 25 | buyer.adds_current_item_to_shopping_cart(); 26 | } 27 | 28 | @Then("the item should appear in the cart") 29 | public void shouldSeeSelectedItemInCart() { 30 | ListingItem selectedItem = (ListingItem) Serenity.sessionVariableCalled(SessionVariables.SELECTED_LISTING); 31 | buyer.should_see_item_in_cart(selectedItem); 32 | } 33 | 34 | @Then("the shipping cost should be included in the total price") 35 | public void shouldIncludeShippingCost() { 36 | ListingItem selectedItem = (ListingItem) Serenity.sessionVariableCalled(SessionVariables.SELECTED_LISTING); 37 | buyer.should_see_total_including_shipping_for(selectedItem); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/samples/jbehave-quick-start/src/test/java/net/serenitybdd/samples/etsy/pages/CartPage.java: -------------------------------------------------------------------------------- 1 | package net.serenitybdd.samples.etsy.pages; 2 | 3 | import net.serenitybdd.samples.etsy.features.model.ListingItem; 4 | import net.serenitybdd.samples.etsy.features.model.OrderCostSummary; 5 | import net.serenitybdd.core.pages.PageObject; 6 | import net.serenitybdd.core.pages.WebElementFacade; 7 | 8 | import java.text.NumberFormat; 9 | import java.text.ParseException; 10 | import java.util.List; 11 | import java.util.Optional; 12 | import java.util.stream.Collectors; 13 | 14 | /** 15 | * Created by john on 12/11/14. 16 | */ 17 | public class CartPage extends PageObject { 18 | 19 | public List getOrderCostSummaries() { 20 | return findAll(".order-wrapper") 21 | .stream() 22 | .map(CartPage::convertToOrderCostSummary) 23 | .collect(Collectors.toList()); 24 | } 25 | 26 | public Optional getOrderCostSummaryFor(ListingItem selectedItem) { 27 | return getOrderCostSummaries() 28 | .stream() 29 | .filter(item -> item.getName().equals(selectedItem.getName())) 30 | .findFirst(); 31 | } 32 | 33 | public static OrderCostSummary convertToOrderCostSummary(WebElementFacade summaryElement) { 34 | String name = summaryElement.find(net.serenitybdd.core.annotations.findby.By.tagName("h3")).getText(); 35 | double itemTotal = Double.parseDouble(summaryElement.findBy(".item-total .currency-value").getText()); 36 | double shipping = summaryElement.containsElements(".shipping .currency-value") ? 37 | Double.parseDouble(summaryElement.findBy(".shipping .currency-value").getText()) : 0.0; 38 | 39 | double grandTotal = summaryElement.containsElements(".grand-total .currency-value") 40 | ? Double.parseDouble(summaryElement.findBy(".grand-total .currency-value").getText()) : 0.0; 41 | 42 | return new OrderCostSummary(name, itemTotal, shipping, grandTotal); 43 | } 44 | 45 | } 46 | -------------------------------------------------------------------------------- /src/samples/jbehave-quick-start/src/test/java/net/serenitybdd/samples/etsy/pages/HomePage.java: -------------------------------------------------------------------------------- 1 | package net.serenitybdd.samples.etsy.pages; 2 | 3 | import com.google.common.base.Function; 4 | import com.google.common.collect.Lists; 5 | import com.thoughtworks.selenium.webdriven.commands.WaitForCondition; 6 | import net.serenitybdd.core.Serenity; 7 | import net.thucydides.core.annotations.DefaultUrl; 8 | import net.thucydides.core.pages.PageObject; 9 | import org.openqa.selenium.By; 10 | import org.openqa.selenium.Keys; 11 | import org.openqa.selenium.WebDriver; 12 | import org.openqa.selenium.WebElement; 13 | import org.openqa.selenium.support.CacheLookup; 14 | import org.openqa.selenium.support.FindAll; 15 | import org.openqa.selenium.support.FindBy; 16 | import org.openqa.selenium.support.PageFactory; 17 | import org.openqa.selenium.support.ui.FluentWait; 18 | import org.openqa.selenium.support.ui.Wait; 19 | import org.openqa.selenium.support.ui.WebDriverWait; 20 | 21 | import java.util.List; 22 | import java.util.NoSuchElementException; 23 | import java.util.concurrent.TimeUnit; 24 | 25 | // tag::header[] 26 | @DefaultUrl("http://www.etsy.com") // <1> 27 | public class HomePage extends PageObject { // <2> 28 | // end::header[] 29 | // tag::searchByKeyword[] 30 | 31 | @FindBy(css = "button[value='Search']") 32 | WebElement searchButton; 33 | 34 | public void searchFor(String keywords) { 35 | $("#search-query").sendKeys(keywords); // <3> 36 | searchButton.click(); // <4> 37 | } 38 | 39 | public void dismissLocationMessage() { 40 | if (!findAll(By.cssSelector("input[value='Okay']")).isEmpty()) { 41 | find(By.cssSelector("input[value='Okay']")).click(); 42 | } 43 | } 44 | // end::searchByKeyword[] 45 | // tag::tail[] 46 | } 47 | // end::tail[] -------------------------------------------------------------------------------- /src/samples/jbehave-quick-start/src/test/java/net/serenitybdd/samples/etsy/pages/ItemDetailsPage.java: -------------------------------------------------------------------------------- 1 | package net.serenitybdd.samples.etsy.pages; 2 | 3 | import net.serenitybdd.core.pages.PageObject; 4 | import net.serenitybdd.core.annotations.findby.By; 5 | import org.openqa.selenium.WebDriver; 6 | import org.openqa.selenium.WebElement; 7 | import org.openqa.selenium.interactions.Actions; 8 | import org.openqa.selenium.support.FindAll; 9 | import org.openqa.selenium.support.FindBy; 10 | import org.openqa.selenium.support.FindBys; 11 | import org.openqa.selenium.support.ui.ExpectedConditions; 12 | import org.openqa.selenium.support.ui.Wait; 13 | import org.openqa.selenium.support.ui.WebDriverWait; 14 | 15 | import java.util.List; 16 | 17 | import static java.util.stream.Collectors.toList; 18 | import static net.serenitybdd.samples.etsy.pages.Spinners.noSpinnerToBeVisible; 19 | 20 | public class ItemDetailsPage extends PageObject { 21 | 22 | @FindBys({@FindBy(id="listing-page-cart"), @FindBy(tagName = "h1")}) 23 | WebElement itemName; 24 | 25 | public String getItemName() { 26 | return itemName.getText(); 27 | } 28 | 29 | public String getItemDescription() { 30 | return $("#description-text").getText(); 31 | } 32 | 33 | public void addToCart() { 34 | withAction().moveToElement($("#item-tabs")).perform(); 35 | $(".buy-button button").click(); 36 | } 37 | 38 | public List getProductVariationIds() { 39 | return findAll(".variation") 40 | .stream() 41 | .map(elt -> elt.getAttribute("id")) 42 | .filter(id -> !id.isEmpty()) 43 | .collect(toList()); 44 | } 45 | 46 | public void selectVariation(String variationId, int optionIndex) { 47 | find(By.id(variationId)).selectByIndex(optionIndex); 48 | if (spinnerIsVisible()) { 49 | waitFor(noSpinnerToBeVisible()); 50 | } 51 | } 52 | 53 | private boolean spinnerIsVisible() { 54 | return containsElements(".spinner-small"); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/samples/jbehave-quick-start/src/test/java/net/serenitybdd/samples/etsy/pages/SearchResultsPage.java: -------------------------------------------------------------------------------- 1 | package net.serenitybdd.samples.etsy.pages; 2 | 3 | import com.google.common.base.Optional; 4 | import net.serenitybdd.samples.etsy.features.model.ListingItem; 5 | import net.serenitybdd.core.pages.PageObject; 6 | import net.serenitybdd.core.pages.WebElementFacade; 7 | import org.openqa.selenium.By; 8 | import org.openqa.selenium.WebElement; 9 | import org.openqa.selenium.support.FindBy; 10 | import org.openqa.selenium.support.ui.ExpectedConditions; 11 | 12 | import java.text.NumberFormat; 13 | import java.text.ParseException; 14 | import java.util.List; 15 | import java.util.Locale; 16 | import java.util.concurrent.TimeUnit; 17 | import java.util.stream.Collectors; 18 | 19 | // tag::header[] 20 | public class SearchResultsPage extends PageObject { 21 | // end::header[] 22 | // tag::searchByKeyword[] 23 | 24 | @FindBy(css=".listing-card") 25 | List listingCards; 26 | 27 | public List getResultTitles() { 28 | return listingCards.stream() 29 | .map(element -> element.getText()) 30 | .collect(Collectors.toList()); 31 | } 32 | // end::searchByKeyword[] 33 | public ListingItem selectItem(int itemNumber) { 34 | ListingItem selectedItem = convertToListingItem(listingCards.get(itemNumber - 1)); 35 | listingCards.get(itemNumber - 1).findElement(By.tagName("a")).click(); 36 | return selectedItem; 37 | } 38 | 39 | private ListingItem convertToListingItem(WebElement itemElement) { 40 | NumberFormat format = NumberFormat.getInstance(); 41 | String price = itemElement.findElement(By.className("currency-value")).getText(); 42 | 43 | try { 44 | return new ListingItem(itemElement.findElement(By.className("title")).getText(), 45 | format.parse(price).doubleValue()); 46 | } catch (ParseException e) { 47 | throw new AssertionError("Failed to parse item price: ",e); 48 | } 49 | } 50 | 51 | public void filterByType(String type) { 52 | confirmLocaleIfNecessary(); 53 | withAction().moveToElement($("#filter-marketplace")).perform(); 54 | $("#filter-marketplace").then(By.partialLinkText(type)).click(); 55 | } 56 | 57 | private void confirmLocaleIfNecessary() { 58 | if (isElementVisible(By.id("locale-nag-confirm")) && isElementVisible(By.id("input[value='Okay']"))) { 59 | find(By.cssSelector("input[value='Okay']")).click(); 60 | waitFor(ExpectedConditions.invisibilityOfElementLocated(By.id("locale-nag-confirm"))); 61 | } 62 | } 63 | 64 | public int getItemCount() { 65 | String resultCount = $(".result-count").getText() 66 | .replace("We found ","") 67 | .replace(" item","") 68 | .replace("s","") 69 | .replace("!","") 70 | .replace(",","") 71 | ; 72 | return Integer.parseInt(resultCount); 73 | } 74 | 75 | public Optional getSelectedType() { 76 | List selectedTypes = findAll("#filter-marketplace a.selected"); 77 | return (selectedTypes.isEmpty()) ? Optional.absent() : Optional.of(selectedTypes.get(0).getText()); 78 | } 79 | 80 | public void filterByLocalRegion() { 81 | withAction().moveToElement($("#filter-location")).perform(); 82 | findAll(".geoname-option a").get(1).click(); 83 | } 84 | // tag::tail[] 85 | } 86 | // end:tail[] 87 | -------------------------------------------------------------------------------- /src/samples/jbehave-quick-start/src/test/java/net/serenitybdd/samples/etsy/pages/Spinners.java: -------------------------------------------------------------------------------- 1 | package net.serenitybdd.samples.etsy.pages; 2 | 3 | import net.serenitybdd.core.annotations.findby.By; 4 | import org.openqa.selenium.StaleElementReferenceException; 5 | import org.openqa.selenium.WebDriver; 6 | import org.openqa.selenium.WebElement; 7 | import org.openqa.selenium.support.ui.ExpectedCondition; 8 | 9 | import static java.util.stream.Collectors.toList; 10 | 11 | /** 12 | * Created by john on 19/12/14. 13 | */ 14 | public class Spinners { 15 | public static ExpectedCondition noSpinnerToBeVisible() { 16 | return new ExpectedCondition() { 17 | @Override 18 | public Boolean apply(WebDriver driver) { 19 | return driver.findElements(By.cssSelector(".spinner-small")) 20 | .stream() 21 | .filter(element -> isVisible(element)) 22 | .collect(toList()) 23 | .isEmpty(); 24 | } 25 | 26 | private boolean isVisible(WebElement element) { 27 | try { 28 | return !element.isDisplayed(); 29 | } catch (StaleElementReferenceException e) { 30 | // Returns true because stale element reference implies that element 31 | // is npo longer visible. 32 | return true; 33 | } 34 | } 35 | }; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/samples/jbehave-quick-start/src/test/resources/stories/search/narrative.txt: -------------------------------------------------------------------------------- 1 | Item search 2 | 3 | Narrative: 4 | In order to find the items I am interested in faster 5 | As a +buyer+ 6 | *I want to be able to list all the ads with a particular keyword in the description or title* -------------------------------------------------------------------------------- /src/samples/jbehave-quick-start/src/test/resources/stories/search/search_by_keyword.story: -------------------------------------------------------------------------------- 1 | Searching by keyword 2 | 3 | Meta: 4 | @tag product:search 5 | 6 | Narrative: 7 | In order to find items that I would like to purchase 8 | As a potential buyer 9 | I want to be able to search for items containing certain words 10 | 11 | Scenario: Should list items related to a specified keyword 12 | Given I want to buy a wool scarf 13 | When I search for items containing 'wool' 14 | Then I should only see items related to 'wool' 15 | 16 | Scenario: Should be able to filter search results by item type 17 | Given I have searched for items containing 'wool' 18 | When I filter results by type 'Handmade' 19 | Then I should only see items containing 'wool' of type 'Handmade' -------------------------------------------------------------------------------- /src/samples/jbehave-quick-start/src/test/resources/stories/shopping_cart/adding_items_to_the_shopping_cart.story: -------------------------------------------------------------------------------- 1 | Adding items to the shopping cart 2 | 3 | Meta: 4 | @driver phantomjs 5 | 6 | Narrative: 7 | In order to buy multiple items at the same time 8 | As a buyer 9 | I want to be able to add multiple items to the shopping cart 10 | 11 | Scenario: Should see total price including tax 12 | Given I have searched for local items containing 'wool' 13 | And I have selected an item 14 | When I add the item to the shopping cart 15 | Then the item should appear in the cart 16 | And the shipping cost should be included in the total price 17 | 18 | -------------------------------------------------------------------------------- /src/samples/jira-integration-scenarios/sample-dependency.xml: -------------------------------------------------------------------------------- 1 | 2 | ... 3 | 4 | net.serenity.plugins.jira 5 | serenity-jira-requirements-provider 6 | xxx 7 | 8 | -------------------------------------------------------------------------------- /src/samples/jira-integration-scenarios/sample-jbehabe-scenatio.story: -------------------------------------------------------------------------------- 1 | Frequent Flyer status is calculated based on points 2 | 3 | Meta: 4 | @issue #FH-17 5 | 6 | Scenario: New members should start out as Bronze members 7 | Given Jill Smith is not a Frequent Flyer member 8 | When she registers on the Frequent Flyer program 9 | Then she should have a status of Bronze 10 | 11 | Scenario: Members should get status updates based on status points earned 12 | Given a member has a status of 13 | And he has status points 14 | When he earns extra status points 15 | Then he should have a status of 16 | Examples: 17 | | initialStatus | initialStatusPoints | extraPoints | finalStatus | notes | 18 | | Bronze | 0 | 300 | Silver | 300 points for Silver | 19 | | Silver | 0 | 700 | Gold | 700 points for Gold | 20 | | Gold | 0 | 1500 | Platinum | 1500 points for Platinum | -------------------------------------------------------------------------------- /src/samples/jira-integration-scenarios/sample-workflow-configuration.groovy: -------------------------------------------------------------------------------- 1 | when 'Open', { 2 | 'success' should: 'Resolve Issue' 3 | } 4 | 5 | when 'Reopened', { 6 | 'success' should: 'Resolve Issue' 7 | } 8 | 9 | when 'Resolved', { 10 | 'failure' should: 'Reopen Issue' 11 | } 12 | 13 | when 'In Progress', { 14 | 'success' should: ['Stop Progress','Resolve Issue'] 15 | } 16 | 17 | when 'Closed', { 18 | 'failure' should: 'Reopen Issue' 19 | } -------------------------------------------------------------------------------- /src/samples/jira-integration-scenarios/serenity-reporting-plugin-configuration.xml: -------------------------------------------------------------------------------- 1 | 2 | ... 3 | 4 | ... 5 | 6 | net.serenity.maven.plugins 7 | maven-serenity-plugin 8 | xxx 9 | 10 | 11 | serenity-reports 12 | post-integration-test 13 | 14 | aggregate 15 | 16 | 17 | 18 | 19 | 20 | net.serenity.plugins.jira 21 | serenity-jira-requirements-provider 22 | xxx 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /src/samples/jira-integration-scenarios/serenity.properties: -------------------------------------------------------------------------------- 1 | jira.url=https://myserver.atlassian.net 2 | jira.project=FH 3 | jira.username=jirauser 4 | jira.password=t0psecret -------------------------------------------------------------------------------- /src/samples/journey-pattern-sample/README.md: -------------------------------------------------------------------------------- 1 | # Serenity Journey Pattern demo 2 | 3 | This application is a simple demonstration project using Serenity and the Journey Pattern with JUnit, running tests against the http://todomvc.com/examples/angularjs/#/ application. 4 | 5 | The project has a number of web tests, organised by feature in packages under `src/test/java/net/serenitybdd/demos/todos/features`. These tests use tasks, actions, questions and page elements defined in `src/main/java/net/serenitybdd/demos/todos`. 6 | The overall project structure is shown here: 7 | ```` 8 | + model 9 | Domain model classes 10 | + tasks 11 | Business-level tasks 12 | + action 13 | UI interactions 14 | + pages 15 | Page Objects and Page Elements 16 | + questions 17 | Objects used to query the application 18 | ```` 19 | 20 | The project runs using JDK 1.8 and Maven. To run the demo, run: 21 | 22 | ``` 23 | mvn clean verify 24 | ``` 25 | 26 | The Serenity reports will be generated in the `target/site/serenity` directory. 27 | -------------------------------------------------------------------------------- /src/samples/journey-pattern-sample/build.gradle: -------------------------------------------------------------------------------- 1 | // tag::simple[] 2 | repositories { 3 | mavenLocal() 4 | jcenter() 5 | } 6 | 7 | buildscript { 8 | repositories { 9 | mavenLocal() 10 | jcenter() 11 | } 12 | dependencies { 13 | classpath("net.serenity-bdd:serenity-gradle-plugin:1.1.22-rc.14") // <1> 14 | } 15 | } 16 | 17 | apply plugin: 'java' 18 | apply plugin: 'eclipse' 19 | apply plugin: 'idea' 20 | apply plugin: 'net.serenity-bdd.aggregator' // <2> 21 | 22 | dependencies { 23 | testCompile 'net.serenity-bdd:serenity-core:1.1.22-rc.14' // <3> 24 | testCompile 'net.serenity-bdd:serenity-junit:1.1.22-rc.14' // <4> 25 | testCompile('junit:junit:4.12') 26 | testCompile('org.assertj:assertj-core:1.7.0') 27 | testCompile('org.slf4j:slf4j-simple:1.7.7') 28 | } 29 | // end::simple[] 30 | // tag::advanced[] 31 | gradle.startParameter.continueOnFailure = true // <5> 32 | // end::advanced[] -------------------------------------------------------------------------------- /src/samples/journey-pattern-sample/serenity.properties: -------------------------------------------------------------------------------- 1 | serenity.test.root = net.serenitybdd.demos.todos.features 2 | serenity.linked.tags = issue 3 | webdriver.base.url=http://localhost:8080/examples 4 | -------------------------------------------------------------------------------- /src/samples/journey-pattern-sample/src/main/java/net/serenitybdd/demos/todos/action/JSClick.java: -------------------------------------------------------------------------------- 1 | package net.serenitybdd.demos.todos.action; 2 | 3 | import net.serenitybdd.screenplay.Action; 4 | import net.serenitybdd.screenplay.Actor; 5 | import net.serenitybdd.screenplay.abilities.BrowseTheWeb; 6 | import net.serenitybdd.screenplay.targets.Target; 7 | import net.thucydides.core.annotations.Step; 8 | import org.openqa.selenium.WebElement; 9 | 10 | import static net.serenitybdd.screenplay.Tasks.instrumented; 11 | 12 | /** 13 | * An example of a custom WebDriver Action. 14 | */ 15 | // tag::class[] 16 | public class JSClick implements Action { 17 | 18 | private final Target target; 19 | 20 | public JSClick(Target target) { 21 | this.target = target; 22 | } 23 | 24 | @Override 25 | @Step("{0} clicks on #target") 26 | public void performAs(T theActor) { 27 | WebElement targetElement = target.resolveFor(theActor); 28 | BrowseTheWeb.as(theActor).evaluateJavascript("arguments[0].click()", targetElement); 29 | } 30 | 31 | public static Action on(Target target) { 32 | return instrumented(JSClick.class, target); 33 | } 34 | 35 | private String pathTo(Target target) { 36 | return target.getCssOrXPathSelector(); 37 | } 38 | } 39 | // end::class[] 40 | -------------------------------------------------------------------------------- /src/samples/journey-pattern-sample/src/main/java/net/serenitybdd/demos/todos/model/ApplicationInformation.java: -------------------------------------------------------------------------------- 1 | package net.serenitybdd.demos.todos.model; 2 | 3 | public class ApplicationInformation { 4 | private final String title; 5 | private final String heading; 6 | private final String about; 7 | 8 | public ApplicationInformation(String title, String heading, String about) { 9 | this.title = title; 10 | this.heading = heading; 11 | this.about = about; 12 | } 13 | 14 | public String getTitle() { 15 | return title; 16 | } 17 | 18 | public String getHeading() { 19 | return heading; 20 | } 21 | 22 | public String getAbout() { 23 | return about; 24 | } 25 | 26 | @Override 27 | public String toString() { 28 | return "{" + 29 | "title='" + title + '\'' + 30 | ", heading='" + heading + '\'' + 31 | ", about='" + about + '\'' + 32 | '}'; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/samples/journey-pattern-sample/src/main/java/net/serenitybdd/demos/todos/model/TodoStatus.java: -------------------------------------------------------------------------------- 1 | package net.serenitybdd.demos.todos.model; 2 | 3 | public enum TodoStatus { 4 | Active, Completed 5 | } 6 | -------------------------------------------------------------------------------- /src/samples/journey-pattern-sample/src/main/java/net/serenitybdd/demos/todos/model/TodoStatusFilter.java: -------------------------------------------------------------------------------- 1 | package net.serenitybdd.demos.todos.model; 2 | 3 | public enum TodoStatusFilter { 4 | All, Active, Completed 5 | } 6 | -------------------------------------------------------------------------------- /src/samples/journey-pattern-sample/src/main/java/net/serenitybdd/demos/todos/pages/ApplicationHomePage.java: -------------------------------------------------------------------------------- 1 | package net.serenitybdd.demos.todos.pages; 2 | 3 | import net.serenitybdd.core.pages.PageObject; 4 | import net.serenitybdd.screenplay.targets.Target; 5 | import net.thucydides.core.annotations.DefaultUrl; 6 | 7 | @DefaultUrl("http://todomvc.com/examples/angularjs/#/") 8 | public class ApplicationHomePage extends PageObject { 9 | public static final Target TITLE = Target.the("application title").locatedBy("header h1"); 10 | } 11 | -------------------------------------------------------------------------------- /src/samples/journey-pattern-sample/src/main/java/net/serenitybdd/demos/todos/pages/todolist/ClearCompleted.java: -------------------------------------------------------------------------------- 1 | package net.serenitybdd.demos.todos.pages.todolist; 2 | 3 | import net.serenitybdd.core.pages.PageObject; 4 | import net.serenitybdd.screenplay.targets.Target; 5 | 6 | public class ClearCompleted extends PageObject { 7 | public static final Target BUTTON = Target.the("Clear completed button").locatedBy("#clear-completed"); 8 | } 9 | -------------------------------------------------------------------------------- /src/samples/journey-pattern-sample/src/main/java/net/serenitybdd/demos/todos/pages/todolist/CompleteAll.java: -------------------------------------------------------------------------------- 1 | package net.serenitybdd.demos.todos.pages.todolist; 2 | 3 | import net.serenitybdd.screenplay.targets.Target; 4 | 5 | public class CompleteAll { 6 | public static final Target BUTTON = Target.the("Complete all items").locatedBy("#toggle-all"); 7 | } 8 | -------------------------------------------------------------------------------- /src/samples/journey-pattern-sample/src/main/java/net/serenitybdd/demos/todos/pages/todolist/ToDoList.java: -------------------------------------------------------------------------------- 1 | package net.serenitybdd.demos.todos.pages.todolist; 2 | 3 | import net.serenitybdd.core.pages.PageObject; 4 | import net.serenitybdd.screenplay.targets.Target; 5 | 6 | public class ToDoList extends PageObject { 7 | public static Target TODO_ITEMS = Target.the("Todo items").locatedBy(".view label"); 8 | } 9 | -------------------------------------------------------------------------------- /src/samples/journey-pattern-sample/src/main/java/net/serenitybdd/demos/todos/pages/todolist/counter/TodoCounter.java: -------------------------------------------------------------------------------- 1 | package net.serenitybdd.demos.todos.pages.todolist.counter; 2 | 3 | import net.serenitybdd.core.pages.PageObject; 4 | import net.serenitybdd.screenplay.targets.Target; 5 | 6 | public class TodoCounter extends PageObject { 7 | public static Target ITEM_COUNT = Target.the("todo count").locatedBy("#todo-count strong"); 8 | } 9 | -------------------------------------------------------------------------------- /src/samples/journey-pattern-sample/src/main/java/net/serenitybdd/demos/todos/pages/todolist/filter/FilterSelection.java: -------------------------------------------------------------------------------- 1 | package net.serenitybdd.demos.todos.pages.todolist.filter; 2 | 3 | import net.serenitybdd.screenplay.targets.Target; 4 | 5 | public class FilterSelection { 6 | public static Target SELECTED_FILTER = Target.the("selected filter").locatedBy("#filters li .selected"); 7 | public static Target FILTER = Target.the("filter").locatedBy("//*[@id='filters']//a[.='{0}']"); 8 | } 9 | -------------------------------------------------------------------------------- /src/samples/journey-pattern-sample/src/main/java/net/serenitybdd/demos/todos/pages/todolist/items/CompleteItemButton.java: -------------------------------------------------------------------------------- 1 | package net.serenitybdd.demos.todos.pages.todolist.items; 2 | 3 | import net.serenitybdd.core.pages.PageObject; 4 | import net.serenitybdd.screenplay.targets.Target; 5 | 6 | class CompleteItemButton extends PageObject { 7 | 8 | private static String COMPLETE_BUTTON = "//*[@class='view' and contains(.,'%s')]//input[@type='checkbox']"; 9 | 10 | public static Target forItemCalled(String itemName) { 11 | return Target.the("Complete button").locatedBy(String.format(COMPLETE_BUTTON, itemName)); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/samples/journey-pattern-sample/src/main/java/net/serenitybdd/demos/todos/pages/todolist/items/DeleteItemButton.java: -------------------------------------------------------------------------------- 1 | package net.serenitybdd.demos.todos.pages.todolist.items; 2 | 3 | import net.serenitybdd.core.pages.PageObject; 4 | import net.serenitybdd.screenplay.targets.Target; 5 | 6 | class DeleteItemButton extends PageObject { 7 | 8 | private static String DELETE_BUTTON = "//*[@class='view' and contains(.,'%s')]//button[@class='destroy']"; 9 | 10 | public static Target forItemCalled(String itemName) { 11 | return Target.the("Delete button").locatedBy(String.format(DELETE_BUTTON, itemName)); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/samples/journey-pattern-sample/src/main/java/net/serenitybdd/demos/todos/pages/todolist/items/ItemTextInlineInput.java: -------------------------------------------------------------------------------- 1 | package net.serenitybdd.demos.todos.pages.todolist.items; 2 | 3 | import net.serenitybdd.core.pages.PageObject; 4 | import net.serenitybdd.screenplay.targets.Target; 5 | 6 | class ItemTextInlineInput extends PageObject { 7 | 8 | private static String ITEM_TEXT_INPUT = "//li[contains(.,'%s')]//form/input"; 9 | 10 | public static Target forItemCalled(String itemName) { 11 | return Target.the("Item text label").locatedBy(String.format(ITEM_TEXT_INPUT, itemName)); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/samples/journey-pattern-sample/src/main/java/net/serenitybdd/demos/todos/pages/todolist/items/ItemTextLabel.java: -------------------------------------------------------------------------------- 1 | package net.serenitybdd.demos.todos.pages.todolist.items; 2 | 3 | import net.serenitybdd.core.pages.PageObject; 4 | import net.serenitybdd.screenplay.targets.Target; 5 | 6 | class ItemTextLabel extends PageObject { 7 | 8 | private static String ITEM_TEXT_LABEL = "//*[@class='view' and contains(.,'%s')]//label"; 9 | 10 | public static Target forItemCalled(String itemName) { 11 | return Target.the("Item text label").locatedBy(String.format(ITEM_TEXT_LABEL, itemName)); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/samples/journey-pattern-sample/src/main/java/net/serenitybdd/demos/todos/pages/todolist/items/TodoListItem.java: -------------------------------------------------------------------------------- 1 | package net.serenitybdd.demos.todos.pages.todolist.items; 2 | 3 | import net.serenitybdd.screenplay.targets.Target; 4 | 5 | public class TodoListItem { 6 | 7 | public static Target COMPLETE_ITEM_BUTTON = Target.the("Complete button") 8 | .locatedBy( "//*[@class='view' and contains(.,'{0}')]//input[@type='checkbox']"); 9 | 10 | public static Target DELETE_ITEM_BUTTON = Target.the("Delete button") 11 | .locatedBy( "//*[@class='view' and contains(.,'{0}')]//button[@class='destroy']"); 12 | 13 | public static Target ITEM_TEXT_LABEL = Target.the("Item text label") 14 | .locatedBy("//*[@class='view' and contains(.,'{0}')]//label"); 15 | 16 | public static Target ITEM_TEXT_INPUT = Target.the("Item text label") 17 | .locatedBy("//li[contains(.,'{0}')]//form/input"); 18 | } -------------------------------------------------------------------------------- /src/samples/journey-pattern-sample/src/main/java/net/serenitybdd/demos/todos/pages/todolist/newitem/NewTodoForm.java: -------------------------------------------------------------------------------- 1 | package net.serenitybdd.demos.todos.pages.todolist.newitem; 2 | 3 | import net.serenitybdd.screenplay.targets.Target; 4 | 5 | public class NewTodoForm { 6 | public static Target NEW_TODO_FIELD = Target.the("New Todo Field").locatedBy("#new-todo"); 7 | } 8 | -------------------------------------------------------------------------------- /src/samples/journey-pattern-sample/src/main/java/net/serenitybdd/demos/todos/questions/ApplicationDetails.java: -------------------------------------------------------------------------------- 1 | package net.serenitybdd.demos.todos.questions; 2 | 3 | import net.serenitybdd.demos.todos.model.ApplicationInformation; 4 | import net.serenitybdd.screenplay.Actor; 5 | import net.serenitybdd.screenplay.Question; 6 | import net.serenitybdd.screenplay.abilities.BrowseTheWeb; 7 | import net.serenitybdd.screenplay.questions.Text; 8 | import net.serenitybdd.screenplay.targets.Target; 9 | 10 | public class ApplicationDetails implements Question { 11 | 12 | private final Target MAIN_HEADING = Target.the("main heading").locatedBy("css:h1"); 13 | private final Target FOOTER = Target.the("footer").locatedBy("#info"); 14 | 15 | @Override 16 | public ApplicationInformation answeredBy(Actor actor) { 17 | String title = BrowseTheWeb.as(actor).getTitle(); 18 | String heading = Text.of(MAIN_HEADING).viewedBy(actor).value(); 19 | String aboutInformation = Text.of(FOOTER).viewedBy(actor).value(); 20 | 21 | return new ApplicationInformation(title, heading, aboutInformation); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/samples/journey-pattern-sample/src/main/java/net/serenitybdd/demos/todos/questions/ClearCompletedItemsOptionAvailability.java: -------------------------------------------------------------------------------- 1 | package net.serenitybdd.demos.todos.questions; 2 | 3 | import com.google.common.collect.ImmutableMap; 4 | import net.serenitybdd.demos.todos.pages.todolist.ClearCompleted; 5 | import net.serenitybdd.screenplay.Actor; 6 | import net.serenitybdd.screenplay.Question; 7 | import net.serenitybdd.screenplay.annotations.Subject; 8 | import net.serenitybdd.screenplay.questions.Visibility; 9 | 10 | import java.util.Map; 11 | 12 | @Subject("the 'Clear Completed' option") 13 | public class ClearCompletedItemsOptionAvailability implements Question { 14 | 15 | private final Map ELEMENT_AVAILABILITY = 16 | ImmutableMap.of( 17 | Boolean.TRUE, ElementAvailability.Available, 18 | Boolean.FALSE, ElementAvailability.Unavailable 19 | ); 20 | 21 | @Override 22 | public ElementAvailability answeredBy(Actor actor) { 23 | Boolean clearCompleteButtonIsVisible = Visibility.of(ClearCompleted.BUTTON).viewedBy(actor).value(); 24 | return ELEMENT_AVAILABILITY.get(clearCompleteButtonIsVisible); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/samples/journey-pattern-sample/src/main/java/net/serenitybdd/demos/todos/questions/CurrentFilter.java: -------------------------------------------------------------------------------- 1 | package net.serenitybdd.demos.todos.questions; 2 | 3 | import net.serenitybdd.demos.todos.model.TodoStatusFilter; 4 | import net.serenitybdd.demos.todos.pages.todolist.filter.FilterSelection; 5 | import net.serenitybdd.screenplay.Actor; 6 | import net.serenitybdd.screenplay.Question; 7 | import net.serenitybdd.screenplay.annotations.Subject; 8 | import net.serenitybdd.screenplay.questions.Text; 9 | 10 | @Subject("the displayed todo items") 11 | public class CurrentFilter implements Question { 12 | 13 | @Override 14 | public TodoStatusFilter answeredBy(Actor actor) { 15 | return Text.of(FilterSelection.SELECTED_FILTER).viewedBy(actor).asEnum(TodoStatusFilter.class); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/samples/journey-pattern-sample/src/main/java/net/serenitybdd/demos/todos/questions/DisplayedItems.java: -------------------------------------------------------------------------------- 1 | package net.serenitybdd.demos.todos.questions; 2 | 3 | import net.serenitybdd.demos.todos.pages.todolist.ToDoList; 4 | import net.serenitybdd.screenplay.Actor; 5 | import net.serenitybdd.screenplay.Question; 6 | import net.serenitybdd.screenplay.annotations.Subject; 7 | import net.serenitybdd.screenplay.questions.Text; 8 | 9 | import java.util.List; 10 | 11 | @Subject("the displayed todo items") 12 | public class DisplayedItems implements Question> { 13 | 14 | @Override 15 | public List answeredBy(Actor actor) { 16 | return Text.of(ToDoList.TODO_ITEMS).viewedBy(actor).asList(); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/samples/journey-pattern-sample/src/main/java/net/serenitybdd/demos/todos/questions/ElementAvailability.java: -------------------------------------------------------------------------------- 1 | package net.serenitybdd.demos.todos.questions; 2 | 3 | public enum ElementAvailability { 4 | Available, Unavailable; 5 | } 6 | -------------------------------------------------------------------------------- /src/samples/journey-pattern-sample/src/main/java/net/serenitybdd/demos/todos/questions/PlaceholderText.java: -------------------------------------------------------------------------------- 1 | package net.serenitybdd.demos.todos.questions; 2 | 3 | import net.serenitybdd.demos.todos.pages.todolist.newitem.NewTodoForm; 4 | import net.serenitybdd.screenplay.Actor; 5 | import net.serenitybdd.screenplay.Question; 6 | import net.serenitybdd.screenplay.annotations.Subject; 7 | import net.serenitybdd.screenplay.questions.Attribute; 8 | 9 | @Subject("the ToDo placeholder text") 10 | public class PlaceholderText implements Question { 11 | 12 | @Override 13 | public String answeredBy(Actor actor) { 14 | return Attribute.of(NewTodoForm.NEW_TODO_FIELD).named("placeholder").viewedBy(actor).asString(); 15 | } 16 | } -------------------------------------------------------------------------------- /src/samples/journey-pattern-sample/src/main/java/net/serenitybdd/demos/todos/questions/TheItemStatus.java: -------------------------------------------------------------------------------- 1 | package net.serenitybdd.demos.todos.questions; 2 | 3 | import com.google.common.collect.ImmutableMap; 4 | import net.serenitybdd.core.steps.Instrumented; 5 | import net.serenitybdd.demos.todos.model.TodoStatus; 6 | import net.serenitybdd.demos.todos.pages.todolist.items.TodoListItem; 7 | import net.serenitybdd.screenplay.Actor; 8 | import net.serenitybdd.screenplay.Question; 9 | import net.serenitybdd.screenplay.questions.SelectedStatus; 10 | import net.serenitybdd.screenplay.targets.Target; 11 | 12 | import java.util.Map; 13 | 14 | import static java.lang.Boolean.FALSE; 15 | import static java.lang.Boolean.TRUE; 16 | import static net.serenitybdd.demos.todos.model.TodoStatus.Active; 17 | import static net.serenitybdd.demos.todos.model.TodoStatus.Completed; 18 | 19 | public class TheItemStatus implements Question { 20 | 21 | private final String itemName; 22 | 23 | private final Map CHECKED_STATUS = ImmutableMap.of( 24 | FALSE, Active, 25 | TRUE, Completed 26 | ); 27 | 28 | public TheItemStatus(String itemName) { 29 | this.itemName = itemName; 30 | } 31 | 32 | @Override 33 | public TodoStatus answeredBy(Actor actor) { 34 | Target completeItemButton = TodoListItem.COMPLETE_ITEM_BUTTON.of(itemName); 35 | 36 | Boolean itemChecked = SelectedStatus.of(completeItemButton).viewedBy(actor).as(Boolean.class); 37 | return statusFrom(itemChecked); 38 | } 39 | 40 | private TodoStatus statusFrom(Boolean checked) { 41 | return CHECKED_STATUS.get(checked); 42 | } 43 | 44 | public static Question forTheItemCalled(String itemName) { 45 | return Instrumented.instanceOf(TheItemStatus.class).withProperties(itemName); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/samples/journey-pattern-sample/src/main/java/net/serenitybdd/demos/todos/questions/TheRemainingItemCount.java: -------------------------------------------------------------------------------- 1 | package net.serenitybdd.demos.todos.questions; 2 | 3 | import net.serenitybdd.demos.todos.pages.todolist.counter.TodoCounter; 4 | import net.serenitybdd.screenplay.Actor; 5 | import net.serenitybdd.screenplay.Question; 6 | import net.serenitybdd.screenplay.questions.Text; 7 | 8 | public class TheRemainingItemCount implements Question { 9 | public static TheRemainingItemCount value() { 10 | return new TheRemainingItemCount(); 11 | } 12 | 13 | @Override 14 | public Integer answeredBy(Actor actor) { 15 | return Text.of(TodoCounter.ITEM_COUNT) 16 | .viewedBy(actor) 17 | .asInteger(); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/samples/journey-pattern-sample/src/main/java/net/serenitybdd/demos/todos/tasks/AddATodoItem.java: -------------------------------------------------------------------------------- 1 | package net.serenitybdd.demos.todos.tasks; 2 | 3 | import net.serenitybdd.core.steps.Instrumented; 4 | import net.serenitybdd.demos.todos.pages.todolist.newitem.NewTodoForm; 5 | import net.serenitybdd.screenplay.Actor; 6 | import net.serenitybdd.screenplay.Task; 7 | import net.serenitybdd.screenplay.actions.Enter; 8 | import net.serenitybdd.screenplay.actions.Hit; 9 | import net.thucydides.core.annotations.Step; 10 | 11 | import static org.openqa.selenium.Keys.RETURN; 12 | 13 | public class AddATodoItem implements Task { 14 | 15 | private final String thingToDo; 16 | 17 | protected AddATodoItem(String thingToDo) { this.thingToDo = thingToDo; } 18 | 19 | // tag::performAs[] 20 | @Step("{0} adds a todo item called #thingToDo") 21 | public void performAs(T actor) { 22 | actor.attemptsTo( 23 | Enter.theValue(thingToDo).into(NewTodoForm.NEW_TODO_FIELD), 24 | Hit.the(RETURN).keyIn(NewTodoForm.NEW_TODO_FIELD) 25 | ); 26 | } 27 | // end::performAs[] 28 | 29 | public static AddATodoItem called(String thingToDo) { 30 | return Instrumented.instanceOf(AddATodoItem.class).withProperties(thingToDo); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/samples/journey-pattern-sample/src/main/java/net/serenitybdd/demos/todos/tasks/AddTodoItems.java: -------------------------------------------------------------------------------- 1 | package net.serenitybdd.demos.todos.tasks; 2 | 3 | import com.google.common.collect.ImmutableList; 4 | import net.serenitybdd.core.steps.Instrumented; 5 | import net.serenitybdd.screenplay.Actor; 6 | import net.serenitybdd.screenplay.Task; 7 | import net.thucydides.core.annotations.Step; 8 | 9 | import java.util.List; 10 | 11 | import static java.util.Arrays.asList; 12 | 13 | // tag::class[] 14 | public class AddTodoItems implements Task { 15 | 16 | private final List todos; 17 | 18 | protected AddTodoItems(List items) { this.todos = ImmutableList.copyOf(items); } 19 | 20 | @Step("{0} adds the todo items called #todos") 21 | public void performAs(T actor) { 22 | todos.forEach( 23 | todo -> actor.attemptsTo(AddATodoItem.called(todo)) 24 | ); 25 | } 26 | 27 | public static AddTodoItems called(String... items) { 28 | return Instrumented.instanceOf(AddTodoItems.class).withProperties(asList(items)); 29 | } 30 | } 31 | // end::class[] 32 | -------------------------------------------------------------------------------- /src/samples/journey-pattern-sample/src/main/java/net/serenitybdd/demos/todos/tasks/ClearCompletedItems.java: -------------------------------------------------------------------------------- 1 | package net.serenitybdd.demos.todos.tasks; 2 | 3 | import net.serenitybdd.demos.todos.pages.todolist.ClearCompleted; 4 | import net.serenitybdd.screenplay.Actor; 5 | import net.serenitybdd.screenplay.Performable; 6 | import net.serenitybdd.screenplay.actions.Click; 7 | import net.thucydides.core.annotations.Step; 8 | 9 | public class ClearCompletedItems implements Performable { 10 | 11 | @Step("{0} clears all the completed items") 12 | public void performAs(T actor) { 13 | actor.attemptsTo(Click.on(ClearCompleted.BUTTON)); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/samples/journey-pattern-sample/src/main/java/net/serenitybdd/demos/todos/tasks/Complete.java: -------------------------------------------------------------------------------- 1 | package net.serenitybdd.demos.todos.tasks; 2 | 3 | import static net.serenitybdd.screenplay.Tasks.instrumented; 4 | 5 | public class Complete { 6 | 7 | public static CompleteItem itemCalled(String itemName) { 8 | return instrumented(CompleteItem.class, itemName); 9 | } 10 | public static CompleteAllItems allItems() { 11 | return instrumented(CompleteAllItems.class); 12 | } 13 | 14 | } 15 | -------------------------------------------------------------------------------- /src/samples/journey-pattern-sample/src/main/java/net/serenitybdd/demos/todos/tasks/CompleteAllItems.java: -------------------------------------------------------------------------------- 1 | package net.serenitybdd.demos.todos.tasks; 2 | 3 | import net.serenitybdd.demos.todos.pages.todolist.CompleteAll; 4 | import net.serenitybdd.screenplay.Actor; 5 | import net.serenitybdd.screenplay.Performable; 6 | import net.serenitybdd.screenplay.actions.Click; 7 | import net.thucydides.core.annotations.Step; 8 | 9 | public class CompleteAllItems implements Performable { 10 | 11 | @Override 12 | @Step("Completes item called #itemName") 13 | public void performAs(T theActor) { 14 | theActor.attemptsTo(Click.on(CompleteAll.BUTTON)); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/samples/journey-pattern-sample/src/main/java/net/serenitybdd/demos/todos/tasks/CompleteItem.java: -------------------------------------------------------------------------------- 1 | package net.serenitybdd.demos.todos.tasks; 2 | 3 | import net.serenitybdd.demos.todos.pages.todolist.items.TodoListItem; 4 | import net.serenitybdd.screenplay.Actor; 5 | import net.serenitybdd.screenplay.Task; 6 | import net.serenitybdd.screenplay.actions.Click; 7 | import net.serenitybdd.screenplay.targets.Target; 8 | import net.thucydides.core.annotations.Step; 9 | 10 | public class CompleteItem implements Task { 11 | 12 | private final String itemName; 13 | 14 | protected CompleteItem(String itemName) { 15 | this.itemName = itemName; 16 | } 17 | 18 | @Override 19 | @Step("{0} completes the item called #itemName") 20 | public void performAs(T theActor) { 21 | Target completeButton = TodoListItem.COMPLETE_ITEM_BUTTON.of(itemName); 22 | theActor.attemptsTo(Click.on(completeButton)); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/samples/journey-pattern-sample/src/main/java/net/serenitybdd/demos/todos/tasks/DeleteAnItem.java: -------------------------------------------------------------------------------- 1 | package net.serenitybdd.demos.todos.tasks; 2 | 3 | import net.serenitybdd.demos.todos.action.JSClick; 4 | import net.serenitybdd.demos.todos.pages.todolist.items.TodoListItem; 5 | import net.serenitybdd.screenplay.Actor; 6 | import net.serenitybdd.screenplay.Task; 7 | import net.serenitybdd.screenplay.targets.Target; 8 | import net.thucydides.core.annotations.Step; 9 | 10 | import static net.serenitybdd.screenplay.Tasks.instrumented; 11 | 12 | public class DeleteAnItem implements Task { 13 | 14 | private final String itemName; 15 | 16 | protected DeleteAnItem(String itemName) { 17 | this.itemName = itemName; 18 | } 19 | 20 | @Step("{0} deletes the item '#itemName'") 21 | public void performAs(T theActor) { 22 | Target deleteButton = TodoListItem.DELETE_ITEM_BUTTON.of(itemName); 23 | theActor.attemptsTo(JSClick.on(deleteButton)); 24 | } 25 | 26 | public static DeleteAnItem called(String itemName) { 27 | return instrumented(DeleteAnItem.class, itemName); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/samples/journey-pattern-sample/src/main/java/net/serenitybdd/demos/todos/tasks/FilterItems.java: -------------------------------------------------------------------------------- 1 | package net.serenitybdd.demos.todos.tasks; 2 | 3 | import net.serenitybdd.demos.todos.model.TodoStatusFilter; 4 | import net.serenitybdd.demos.todos.pages.todolist.filter.FilterSelection; 5 | import net.serenitybdd.screenplay.Actor; 6 | import net.serenitybdd.screenplay.Task; 7 | import net.serenitybdd.screenplay.actions.Click; 8 | import net.serenitybdd.screenplay.targets.Target; 9 | import net.thucydides.core.annotations.Step; 10 | 11 | import static net.serenitybdd.screenplay.Tasks.instrumented; 12 | 13 | public class FilterItems implements Task { 14 | 15 | public static FilterItems byStatus(TodoStatusFilter status) { 16 | return instrumented(FilterItems.class, status); 17 | } 18 | 19 | private final TodoStatusFilter filter; 20 | 21 | protected FilterItems(TodoStatusFilter filter) { 22 | this.filter = filter; 23 | } 24 | 25 | @Step("{0} filters items by #filter") 26 | public void performAs(T theActor) { 27 | Target filterSelection = FilterSelection.FILTER.of(filter.name()).called("filter by "+ filter); 28 | theActor.attemptsTo(Click.on(filterSelection)); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/samples/journey-pattern-sample/src/main/java/net/serenitybdd/demos/todos/tasks/OpenTheApplication.java: -------------------------------------------------------------------------------- 1 | package net.serenitybdd.demos.todos.tasks; 2 | 3 | import net.serenitybdd.demos.todos.pages.ApplicationHomePage; 4 | import net.serenitybdd.screenplay.Actor; 5 | import net.serenitybdd.screenplay.Task; 6 | import net.serenitybdd.screenplay.actions.Open; 7 | import net.thucydides.core.annotations.Step; 8 | 9 | import static net.serenitybdd.screenplay.Tasks.instrumented; 10 | 11 | public class OpenTheApplication implements Task { 12 | 13 | private ApplicationHomePage applicationHomePage; 14 | 15 | public static OpenTheApplication onTheHomePage() { 16 | return instrumented(OpenTheApplication.class); 17 | } 18 | @Step("{0} opens the application on the home page") 19 | public void performAs(T actor) { 20 | actor.attemptsTo(Open.browserOn().the(applicationHomePage)); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/samples/journey-pattern-sample/src/test/java/net/serenitybdd/demos/todos/features/completing_todos/CompleteATodo.java: -------------------------------------------------------------------------------- 1 | package net.serenitybdd.demos.todos.features.completing_todos; 2 | 3 | import net.serenitybdd.demos.todos.questions.DisplayedItems; 4 | import net.serenitybdd.demos.todos.questions.TheItemStatus; 5 | import net.serenitybdd.demos.todos.questions.TheRemainingItemCount; 6 | import net.serenitybdd.demos.todos.tasks.*; 7 | import net.serenitybdd.junit.runners.SerenityRunner; 8 | import net.serenitybdd.screenplay.Actor; 9 | import net.serenitybdd.screenplay.abilities.BrowseTheWeb; 10 | import net.thucydides.core.annotations.Managed; 11 | import net.thucydides.core.annotations.Steps; 12 | import org.junit.Before; 13 | import org.junit.Test; 14 | import org.junit.runner.RunWith; 15 | import org.openqa.selenium.WebDriver; 16 | 17 | import static net.serenitybdd.demos.todos.model.TodoStatus.Completed; 18 | import static net.serenitybdd.demos.todos.model.TodoStatusFilter.Active; 19 | import static net.serenitybdd.screenplay.GivenWhenThen.*; 20 | import static org.hamcrest.CoreMatchers.is; 21 | import static org.hamcrest.Matchers.contains; 22 | import static org.hamcrest.Matchers.not; 23 | 24 | @RunWith(SerenityRunner.class) 25 | public class CompleteATodo { 26 | 27 | @Managed 28 | private 29 | WebDriver hisBrowser; 30 | 31 | private Actor james = Actor.named("James"); 32 | 33 | @Steps 34 | ClearCompletedItems clearTheCompletedItems; 35 | 36 | @Steps 37 | private 38 | DisplayedItems theDisplayedItems; 39 | 40 | @Before 41 | public void jamesCanBrowseTheWeb() { 42 | james.can(BrowseTheWeb.with(hisBrowser)); 43 | } 44 | 45 | @Test 46 | public void completed_items_should_be_marked_as_completed_in_the_main_list() { 47 | 48 | givenThat(james).wasAbleTo(OpenTheApplication.onTheHomePage()); 49 | andThat(james).wasAbleTo(AddTodoItems.called("Walk the dog", "Put out the garbage")); 50 | 51 | when(james).attemptsTo( 52 | Complete.itemCalled("Walk the dog") 53 | ); 54 | 55 | then(james).should( 56 | seeThat(TheItemStatus.forTheItemCalled("Walk the dog"), is(Completed)), 57 | seeThat(TheRemainingItemCount.value(), is(1))); 58 | } 59 | 60 | // tag::items_left_counter_should_be_decremented_when_an_item_is_completed[] 61 | @Test 62 | public void items_left_counter_should_be_decremented_when_an_item_is_completed() { 63 | 64 | givenThat(james).wasAbleTo(OpenTheApplication.onTheHomePage()); 65 | andThat(james).wasAbleTo(AddTodoItems.called("Walk the dog", "Put out the garbage")); 66 | 67 | when(james).attemptsTo( 68 | Complete.itemCalled("Walk the dog") 69 | ); 70 | 71 | then(james).should(seeThat(TheRemainingItemCount.value(), is(1))); 72 | } 73 | // end::items_left_counter_should_be_decremented_when_an_item_is_completed 74 | 75 | @Test 76 | public void completed_items_should_not_appear_in_the_active_list() { 77 | 78 | givenThat(james).wasAbleTo(OpenTheApplication.onTheHomePage()); 79 | andThat(james).wasAbleTo(AddTodoItems.called("Walk the dog", "Put out the garbage")); 80 | 81 | when(james).attemptsTo( 82 | Complete.itemCalled("Walk the dog"), 83 | FilterItems.byStatus(Active) 84 | ); 85 | 86 | then(james).should(seeThat(theDisplayedItems, not(contains("Walk the dog")))); 87 | } 88 | 89 | } 90 | -------------------------------------------------------------------------------- /src/samples/journey-pattern-sample/src/test/java/net/serenitybdd/demos/todos/features/completing_todos/CompleteAllTodos.java: -------------------------------------------------------------------------------- 1 | package net.serenitybdd.demos.todos.features.completing_todos; 2 | 3 | import net.serenitybdd.demos.todos.questions.DisplayedItems; 4 | import net.serenitybdd.demos.todos.questions.TheItemStatus; 5 | import net.serenitybdd.demos.todos.questions.TheRemainingItemCount; 6 | import net.serenitybdd.demos.todos.tasks.AddTodoItems; 7 | import net.serenitybdd.demos.todos.tasks.ClearCompletedItems; 8 | import net.serenitybdd.demos.todos.tasks.Complete; 9 | import net.serenitybdd.demos.todos.tasks.OpenTheApplication; 10 | import net.serenitybdd.junit.runners.SerenityRunner; 11 | import net.serenitybdd.screenplay.Actor; 12 | import net.serenitybdd.screenplay.abilities.BrowseTheWeb; 13 | import net.thucydides.core.annotations.Managed; 14 | import net.thucydides.core.annotations.Steps; 15 | import org.junit.Before; 16 | import org.junit.Test; 17 | import org.junit.runner.RunWith; 18 | import org.openqa.selenium.WebDriver; 19 | 20 | import static net.serenitybdd.demos.todos.model.TodoStatus.Active; 21 | import static net.serenitybdd.demos.todos.model.TodoStatus.Completed; 22 | import static net.serenitybdd.screenplay.GivenWhenThen.*; 23 | import static org.hamcrest.CoreMatchers.is; 24 | 25 | @RunWith(SerenityRunner.class) 26 | public class CompleteAllTodos { 27 | 28 | @Managed 29 | private 30 | WebDriver hisBrowser; 31 | 32 | private Actor james = Actor.named("James"); 33 | 34 | @Steps 35 | ClearCompletedItems clearTheCompletedItems; 36 | 37 | @Steps 38 | private 39 | DisplayedItems theDisplayedItems; 40 | 41 | @Before 42 | public void jamesCanBrowseTheWeb() { 43 | james.can(BrowseTheWeb.with(hisBrowser)); 44 | } 45 | 46 | 47 | @Test 48 | public void should_be_able_to_complete_all_todos_with_a_single_action() { 49 | 50 | givenThat(james).wasAbleTo(OpenTheApplication.onTheHomePage()); 51 | andThat(james).wasAbleTo(AddTodoItems.called("Walk the dog", "Put out the garbage")); 52 | 53 | when(james).attemptsTo( 54 | Complete.allItems() 55 | ); 56 | 57 | then(james).should( 58 | seeThat(TheItemStatus.forTheItemCalled("Walk the dog"), is(Completed)), 59 | seeThat(TheItemStatus.forTheItemCalled("Put out the garbage"), is(Completed)) 60 | ); 61 | } 62 | 63 | 64 | @Test 65 | public void complete_todos_can_be_toggled() { 66 | 67 | givenThat(james).wasAbleTo(OpenTheApplication.onTheHomePage()); 68 | andThat(james).wasAbleTo(AddTodoItems.called("Walk the dog", "Put out the garbage")); 69 | 70 | when(james).attemptsTo( 71 | Complete.allItems(), 72 | Complete.allItems() 73 | ); 74 | 75 | then(james).should( 76 | seeThat(TheItemStatus.forTheItemCalled("Walk the dog"), is(Active)), 77 | seeThat(TheItemStatus.forTheItemCalled("Put out the garbage"), is(Active)) 78 | ); 79 | } 80 | 81 | 82 | @Test 83 | public void complete_all_todos_should_set_the_remaining_count_to_zero() { 84 | 85 | givenThat(james).wasAbleTo(OpenTheApplication.onTheHomePage()); 86 | andThat(james).wasAbleTo(AddTodoItems.called("Walk the dog", "Put out the garbage")); 87 | 88 | when(james).attemptsTo( 89 | Complete.allItems() 90 | ); 91 | 92 | then(james).should( 93 | seeThat(TheRemainingItemCount.value(), is(0)) 94 | ); 95 | } 96 | 97 | @Test 98 | public void when_complete_all_is_toggled_the_remaining_counter_should_be_restored() { 99 | 100 | givenThat(james).wasAbleTo(OpenTheApplication.onTheHomePage()); 101 | andThat(james).wasAbleTo(AddTodoItems.called("Walk the dog", "Put out the garbage")); 102 | 103 | when(james).attemptsTo( 104 | Complete.allItems(), 105 | Complete.allItems() 106 | ); 107 | 108 | then(james).should( 109 | seeThat(TheRemainingItemCount.value(), is(2)) 110 | ); 111 | } 112 | 113 | } 114 | -------------------------------------------------------------------------------- /src/samples/journey-pattern-sample/src/test/java/net/serenitybdd/demos/todos/features/maintain_my_todo_list/ClearCompletedTodos.java: -------------------------------------------------------------------------------- 1 | package net.serenitybdd.demos.todos.features.maintain_my_todo_list; 2 | 3 | import net.serenitybdd.demos.todos.questions.ClearCompletedItemsOptionAvailability; 4 | import net.serenitybdd.demos.todos.questions.DisplayedItems; 5 | import net.serenitybdd.demos.todos.tasks.AddTodoItems; 6 | import net.serenitybdd.demos.todos.tasks.ClearCompletedItems; 7 | import net.serenitybdd.demos.todos.tasks.Complete; 8 | import net.serenitybdd.demos.todos.tasks.OpenTheApplication; 9 | import net.serenitybdd.junit.runners.SerenityRunner; 10 | import net.serenitybdd.screenplay.Actor; 11 | import net.serenitybdd.screenplay.abilities.BrowseTheWeb; 12 | import net.thucydides.core.annotations.Managed; 13 | import net.thucydides.core.annotations.Steps; 14 | import org.junit.Before; 15 | import org.junit.Test; 16 | import org.junit.runner.RunWith; 17 | import org.openqa.selenium.WebDriver; 18 | 19 | import static net.serenitybdd.demos.todos.questions.ElementAvailability.Unavailable; 20 | import static net.serenitybdd.screenplay.GivenWhenThen.*; 21 | import static org.hamcrest.Matchers.contains; 22 | import static org.hamcrest.Matchers.equalTo; 23 | 24 | @RunWith(SerenityRunner.class) 25 | public class ClearCompletedTodos { 26 | 27 | @Managed 28 | private 29 | WebDriver hisBrowser; 30 | 31 | @Managed 32 | private 33 | WebDriver herBrowser; 34 | 35 | private Actor james = Actor.named("James"); 36 | private Actor jane = Actor.named("Jane"); 37 | 38 | @Steps 39 | private 40 | ClearCompletedItems clearTheCompletedItems; 41 | 42 | private DisplayedItems theDisplayedItems = new DisplayedItems(); 43 | 44 | private ClearCompletedItemsOptionAvailability theClearCompletedItemsOption = new ClearCompletedItemsOptionAvailability(); 45 | 46 | @Before 47 | public void jamesCanBrowseTheWeb() { 48 | james.can(BrowseTheWeb.with(hisBrowser)); 49 | jane.can(BrowseTheWeb.with(herBrowser)); 50 | } 51 | 52 | @Test 53 | public void cleared_completed_items_should_disappear_from_the_todo_list() { 54 | 55 | givenThat(james).wasAbleTo(OpenTheApplication.onTheHomePage()); 56 | andThat(james).wasAbleTo(AddTodoItems.called("Walk the dog", "Put out the garbage")); 57 | 58 | when(james).attemptsTo( 59 | Complete.itemCalled("Walk the dog"), 60 | clearTheCompletedItems); 61 | 62 | then(james).should(seeThat(theDisplayedItems, contains("Put out the garbage"))); 63 | } 64 | 65 | @Test 66 | public void cleared_completed_option_should_not_be_available_if_no_items_are_completed() { 67 | 68 | givenThat(james).wasAbleTo(OpenTheApplication.onTheHomePage()); 69 | andThat(james).wasAbleTo(AddTodoItems.called("Walk the dog", "Put out the garbage")); 70 | 71 | then(james).should(seeThat(theClearCompletedItemsOption, equalTo(Unavailable))); 72 | } 73 | 74 | @Test 75 | public void clearing_completed_items_should_not_affect_items_belonging_to_other_users() { 76 | givenThat(james).wasAbleTo(OpenTheApplication.onTheHomePage()); 77 | andThat(jane).wasAbleTo(OpenTheApplication.onTheHomePage()); 78 | 79 | givenThat(james).wasAbleTo(AddTodoItems.called("Walk the dog", "Put out the garbage")); 80 | andThat(jane).wasAbleTo(AddTodoItems.called("Walk the dog", "Feed the cat")); 81 | 82 | when(james).attemptsTo( 83 | Complete.itemCalled("Walk the dog"), 84 | clearTheCompletedItems); 85 | 86 | then(jane).should(seeThat(theDisplayedItems, contains("Walk the dog", "Feed the cat"))); 87 | } 88 | 89 | } 90 | -------------------------------------------------------------------------------- /src/samples/journey-pattern-sample/src/test/java/net/serenitybdd/demos/todos/features/maintain_my_todo_list/DeleteTodos.java: -------------------------------------------------------------------------------- 1 | package net.serenitybdd.demos.todos.features.maintain_my_todo_list; 2 | 3 | import net.serenitybdd.demos.todos.questions.DisplayedItems; 4 | import net.serenitybdd.demos.todos.questions.TheRemainingItemCount; 5 | import net.serenitybdd.demos.todos.tasks.AddTodoItems; 6 | import net.serenitybdd.demos.todos.tasks.DeleteAnItem; 7 | import net.serenitybdd.demos.todos.tasks.OpenTheApplication; 8 | import net.serenitybdd.junit.runners.SerenityRunner; 9 | import net.serenitybdd.screenplay.Actor; 10 | import net.serenitybdd.screenplay.abilities.BrowseTheWeb; 11 | import net.thucydides.core.annotations.Managed; 12 | import net.thucydides.core.annotations.Steps; 13 | import org.junit.Before; 14 | import org.junit.Test; 15 | import org.junit.runner.RunWith; 16 | import org.openqa.selenium.WebDriver; 17 | 18 | import static net.serenitybdd.screenplay.GivenWhenThen.*; 19 | import static org.hamcrest.CoreMatchers.is; 20 | import static org.hamcrest.Matchers.contains; 21 | 22 | @RunWith(SerenityRunner.class) 23 | public class DeleteTodos { 24 | 25 | @Managed 26 | private 27 | WebDriver hisBrowser; 28 | 29 | private Actor james = Actor.named("James"); 30 | 31 | @Steps 32 | private 33 | DisplayedItems theDisplayedItems; 34 | 35 | @Before 36 | public void jamesCanBrowseTheWeb() { 37 | james.can(BrowseTheWeb.with(hisBrowser)); 38 | } 39 | 40 | @Test 41 | public void deleted_items_should_be_removed_from_the_list() { 42 | 43 | 44 | givenThat(james).wasAbleTo(OpenTheApplication.onTheHomePage()); 45 | andThat(james).wasAbleTo(AddTodoItems.called("Walk the dog", "Put out the garbage")); 46 | 47 | when(james).attemptsTo( 48 | DeleteAnItem.called("Walk the dog") 49 | ); 50 | 51 | then(james).should(seeThat(theDisplayedItems, contains("Put out the garbage"))); 52 | } 53 | 54 | @Test 55 | public void deleting_an_item_should_decrease_the_item_count() { 56 | 57 | givenThat(james).wasAbleTo(OpenTheApplication.onTheHomePage()); 58 | andThat(james).wasAbleTo(AddTodoItems.called("Walk the dog", "Put out the garbage")); 59 | 60 | when(james).attemptsTo( 61 | DeleteAnItem.called("Walk the dog") 62 | ); 63 | 64 | then(james).should(seeThat(TheRemainingItemCount.value(), is(1))); 65 | } 66 | 67 | } 68 | -------------------------------------------------------------------------------- /src/samples/journey-pattern-sample/src/test/java/net/serenitybdd/demos/todos/features/maintain_my_todo_list/FilteringTodos.java: -------------------------------------------------------------------------------- 1 | package net.serenitybdd.demos.todos.features.maintain_my_todo_list; 2 | 3 | import net.serenitybdd.demos.todos.model.TodoStatusFilter; 4 | import net.serenitybdd.demos.todos.questions.CurrentFilter; 5 | import net.serenitybdd.demos.todos.questions.DisplayedItems; 6 | import net.serenitybdd.demos.todos.tasks.*; 7 | import net.serenitybdd.junit.runners.SerenityRunner; 8 | import net.serenitybdd.screenplay.Actor; 9 | import net.serenitybdd.screenplay.abilities.BrowseTheWeb; 10 | import net.thucydides.core.annotations.Managed; 11 | import net.thucydides.core.annotations.Steps; 12 | import org.junit.Before; 13 | import org.junit.Test; 14 | import org.junit.runner.RunWith; 15 | import org.openqa.selenium.WebDriver; 16 | 17 | import static net.serenitybdd.demos.todos.model.TodoStatusFilter.Active; 18 | import static net.serenitybdd.demos.todos.model.TodoStatusFilter.All; 19 | import static net.serenitybdd.screenplay.GivenWhenThen.*; 20 | import static org.hamcrest.Matchers.contains; 21 | import static org.hamcrest.Matchers.is; 22 | 23 | @RunWith(SerenityRunner.class) 24 | public class FilteringTodos { 25 | 26 | private Actor james = Actor.named("James"); 27 | @Managed 28 | private WebDriver hisBrowser; 29 | 30 | @Steps 31 | private 32 | DisplayedItems theDisplayedItems; 33 | 34 | private CurrentFilter theCurrentFilter = new CurrentFilter(); 35 | 36 | @Before 37 | public void jamesCanBrowseTheWeb() { 38 | james.can(BrowseTheWeb.with(hisBrowser)); 39 | } 40 | 41 | @Test 42 | public void filtering_by_completed() { 43 | 44 | givenThat(james).wasAbleTo(OpenTheApplication.onTheHomePage()); 45 | andThat(james).wasAbleTo(AddTodoItems.called("Walk the dog", "Put out the garbage")); 46 | 47 | when(james).attemptsTo( 48 | Complete.itemCalled("Walk the dog"), 49 | FilterItems.byStatus(TodoStatusFilter.Completed)); 50 | 51 | then(james).should(seeThat(theDisplayedItems, contains("Walk the dog"))); 52 | } 53 | 54 | @Test 55 | public void filtering_by_active() { 56 | 57 | givenThat(james).wasAbleTo(OpenTheApplication.onTheHomePage()); 58 | andThat(james).wasAbleTo(AddTodoItems.called("Walk the dog", "Put out the garbage")); 59 | 60 | when(james).attemptsTo( 61 | Complete.itemCalled("Walk the dog"), 62 | FilterItems.byStatus(Active)); 63 | 64 | then(james).should(seeThat(theDisplayedItems, contains("Put out the garbage"))); 65 | } 66 | 67 | @Test 68 | public void filtering_by_all() { 69 | 70 | givenThat(james).wasAbleTo(OpenTheApplication.onTheHomePage()); 71 | andThat(james).wasAbleTo(AddTodoItems.called("Walk the dog", "Put out the garbage")); 72 | 73 | when(james).attemptsTo( 74 | Complete.itemCalled("Walk the dog"), 75 | FilterItems.byStatus(Active), 76 | FilterItems.byStatus(All)); 77 | 78 | then(james).should(seeThat(theDisplayedItems, contains("Walk the dog", "Put out the garbage"))); 79 | } 80 | 81 | @Test 82 | public void should_indicate_what_filter_is_currently_being_used() { 83 | 84 | givenThat(james).wasAbleTo(OpenTheApplication.onTheHomePage()); 85 | 86 | when(james).wasAbleTo(AddTodoItems.called("Walk the dog", "Put out the garbage")); 87 | then(james).should(seeThat(theCurrentFilter, is(All))); 88 | 89 | when(james).attemptsTo(FilterItems.byStatus(Active)); 90 | then(james).should(seeThat(theCurrentFilter, is(Active))); 91 | } 92 | 93 | } 94 | -------------------------------------------------------------------------------- /src/samples/journey-pattern-sample/src/test/java/net/serenitybdd/demos/todos/features/record_todos/AddNewTodos.java: -------------------------------------------------------------------------------- 1 | package net.serenitybdd.demos.todos.features.record_todos; 2 | 3 | import net.serenitybdd.demos.todos.questions.DisplayedItems; 4 | import net.serenitybdd.demos.todos.questions.PlaceholderText; 5 | import net.serenitybdd.demos.todos.tasks.AddATodoItem; 6 | import net.serenitybdd.demos.todos.tasks.OpenTheApplication; 7 | import net.serenitybdd.junit.runners.SerenityRunner; 8 | import net.serenitybdd.screenplay.Actor; 9 | import net.serenitybdd.screenplay.abilities.BrowseTheWeb; 10 | import net.thucydides.core.annotations.Managed; 11 | import net.thucydides.core.annotations.Steps; 12 | import org.junit.Before; 13 | import org.junit.Test; 14 | import org.junit.runner.RunWith; 15 | import org.openqa.selenium.WebDriver; 16 | 17 | import static net.serenitybdd.screenplay.GivenWhenThen.*; 18 | import static org.hamcrest.Matchers.hasItem; 19 | import static org.hamcrest.core.Is.is; 20 | 21 | /** 22 | * This example illustrates using Serenity Steps with JUnit. 23 | */ 24 | // tag::add_new_todos_start[] 25 | @RunWith(SerenityRunner.class) 26 | public class AddNewTodos { 27 | 28 | private Actor james = Actor.named("James"); 29 | 30 | @Managed 31 | private WebDriver hisBrowser; 32 | 33 | @Steps 34 | private PlaceholderText thePlaceholderText; 35 | 36 | private DisplayedItems theDisplayedItems = new DisplayedItems(); 37 | 38 | @Before 39 | public void jamesCanBrowseTheWeb() { 40 | james.can(BrowseTheWeb.with(hisBrowser)); 41 | } 42 | 43 | // end::add_new_todos_start[] 44 | // tag::should_be_able_to_add_a_todo_item[] 45 | @Test 46 | public void should_be_able_to_add_a_todo_item() { 47 | 48 | givenThat(james).wasAbleTo(OpenTheApplication.onTheHomePage()); 49 | 50 | when(james).attemptsTo(AddATodoItem.called("Buy some milk")); 51 | 52 | then(james).should(seeThat(theDisplayedItems, hasItem("Buy some milk"))); 53 | } 54 | // end::should_be_able_to_add_a_todo_item[] 55 | 56 | @Test 57 | public void should_display_a_meaningful_placeholder() { 58 | 59 | givenThat(james).wasAbleTo(OpenTheApplication.onTheHomePage()); 60 | 61 | then(james).should(seeThat(thePlaceholderText, is("What needs to be done?"))); 62 | } 63 | // tag::add_new_todos_end[] 64 | } 65 | // end::add_new_todos_end[] 66 | -------------------------------------------------------------------------------- /src/samples/journey-pattern-sample/src/test/resources/serenity.conf: -------------------------------------------------------------------------------- 1 | webdriver { 2 | driver = firefox 3 | base.url = "http://localhost:8080/" 4 | # driver = remote 5 | # remote.url = "http://192.168.80.154:4444/wd/hub" 6 | # remote.driver = firefox 7 | } 8 | 9 | 10 | 11 | serenity { 12 | project.name = "Demo Project using Serenity and Cucumber" 13 | take.screenshots = BEFORE_AND_AFTER_EACH_STEP 14 | test.root = "net.serenitybdd.demos.todos.features" 15 | tag.failures = "true" 16 | linked.tags = "issue" 17 | logging = "NORMAL" 18 | } 19 | 20 | -------------------------------------------------------------------------------- /src/samples/junit-batch-configuration-example/build.gradle: -------------------------------------------------------------------------------- 1 | repositories { 2 | mavenLocal() 3 | jcenter() 4 | } 5 | 6 | ext{ 7 | serenity_version = "1.1.21" 8 | } 9 | 10 | buildscript { 11 | repositories { 12 | mavenLocal() 13 | jcenter() 14 | } 15 | dependencies { 16 | classpath("net.serenity-bdd:serenity-gradle-plugin:1.1.21") 17 | } 18 | } 19 | 20 | apply plugin: "java" 21 | apply plugin: "eclipse" 22 | apply plugin: "idea" 23 | apply plugin: "net.serenity-bdd.aggregator" 24 | 25 | dependencies { 26 | compile localGroovy() 27 | compile "net.serenity-bdd:serenity-core:$serenity_version" 28 | compile "net.serenity-bdd:serenity-junit:$serenity_version" 29 | compile("net.serenity-bdd:serenity-rest-assured:$serenity_version") 30 | compile 'org.slf4j:slf4j-simple:1.7.12' 31 | compile 'org.codehaus.groovy:groovy-all:2.3.10' 32 | compile 'junit:junit:4.12' 33 | compile 'com.googlecode.lambdaj:lambdaj:2.3.3' 34 | compile 'org.assertj:assertj-core:3.1.0' 35 | } 36 | 37 | test { 38 | testLogging { 39 | showStandardStreams = true 40 | } 41 | /* Pass all system properties: */ 42 | systemProperties System.getProperties() 43 | } 44 | 45 | task copyDeps(type: Copy) { 46 | from configurations.runtime 47 | into project.projectDir.path+"/lib" 48 | } 49 | 50 | gradle.startParameter.continueOnFailure = true -------------------------------------------------------------------------------- /src/samples/junit-batch-configuration-example/serenity.properties: -------------------------------------------------------------------------------- 1 | serenity.batch.strategy=DIVIDE_BY_TEST_COUNT 2 | serenity.batch.number=1 3 | serenity.batch.size=2 -------------------------------------------------------------------------------- /src/samples/junit-batch-configuration-example/src/test/java/net/serenity/samples/batch/junit/features/registration/LoginUserTest.java: -------------------------------------------------------------------------------- 1 | @RunWith(SerenityRunner.class) 2 | public class LoginUserTest { 3 | @Steps 4 | UserActionSteps steps; 5 | 6 | @Test 7 | public void should_create_login_record_after_login() { 8 | // GIVEN 9 | final User user = new User("user.login", "user@mail.com"); 10 | steps.given_registered_user(user); 11 | // WHEN 12 | steps.when_user_login(); 13 | // THEN 14 | steps.then_one_login_record_should_exist(); 15 | } 16 | 17 | @Test 18 | public void should_clean_login_records_after_logout() { 19 | // GIVEN 20 | final User user = new User("user.login", "user@mail.com"); 21 | steps.given_registered_user(user); 22 | // WHEN 23 | steps.when_user_login(); 24 | steps.when_user_logout(); 25 | // THEN 26 | steps.then_login_record_should_not_exist(); 27 | } 28 | 29 | @Test 30 | public void should_not_create_duplicate_records_during_parallel_login() { 31 | // GIVEN 32 | final User user = new User("user.login", "user@mail.com"); 33 | steps.given_registered_user(user); 34 | // WHEN 35 | steps.when_user_login(); 36 | steps.when_user_login(); 37 | // THEN 38 | steps.then_one_login_record_should_exist(); 39 | } 40 | 41 | @Test 42 | public void should_clean_login_records_after_session_expired() { 43 | // GIVEN 44 | final User user = new User("user.login", "user@mail.com"); 45 | steps.given_registered_user(user); 46 | // WHEN 47 | steps.when_user_login(); 48 | steps.when_user_session_expired(); 49 | // THEN 50 | steps.then_login_record_should_not_exist(); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/samples/junit-batch-configuration-example/src/test/java/net/serenity/samples/batch/junit/features/registration/RegisterUserTest.java: -------------------------------------------------------------------------------- 1 | @RunWith(SerenityRunner.class) 2 | public class RegisterUserTest { 3 | @Steps 4 | UserActionSteps steps; 5 | 6 | @Test 7 | public void should_be_available_after_finishing_registration() { 8 | // GIVEN 9 | final User user = new User("user.login", "user@mail.com"); 10 | steps.given_started_registration_process(user); 11 | // WHEN 12 | steps.when_user_activate_registration(); 13 | // THEN 14 | steps.then_user_should_be_available(); 15 | } 16 | 17 | @Test 18 | public void should_be_not_available_before_finishing_registration() { 19 | // GIVEN 20 | final User user = new User("user.login", "user@mail.com"); 21 | steps.given_started_registration_process(user); 22 | // WHEN 23 | steps.when_user_not_finished_registration(); 24 | // THEN 25 | steps.then_user_should_be_not_available(); 26 | } 27 | } -------------------------------------------------------------------------------- /src/samples/junit-batch-configuration-example/src/test/java/net/serenity/samples/batch/junit/features/registration/UserActivationProcessTest.java: -------------------------------------------------------------------------------- 1 | @RunWith(SerenityRunner.class) 2 | public class UserActivationProcessTest { 3 | @Steps 4 | MailActivationSteps steps; 5 | 6 | @Test 7 | public void should_activate_user_account() { 8 | // GIVEN 9 | final User user = new User("user.login", "user@mail.com"); 10 | final ActivationMail activation = new ActivationMail(user.getEmail() 11 | , String.valueOf(ThreadLocalRandom.current().nextLong())); 12 | steps.given_activation_send(activation, user); 13 | // WHEN 14 | steps.when_user_enter_activation_code(); 15 | // THEN 16 | steps.then_user_account_activated(); 17 | } 18 | 19 | @Test 20 | public void should_send_notification_to_user() { 21 | // GIVEN 22 | final User user = new User("user.login", "user@mail.com"); 23 | final ActivationMail activation = new ActivationMail(user.getEmail() 24 | , String.valueOf(ThreadLocalRandom.current().nextLong())); 25 | steps.given_activation_send(activation, user); 26 | // WHEN 27 | steps.when_activation_code_expired(); 28 | // THEN 29 | steps.then_user_received_notification(); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/samples/junit-batch-configuration-example/src/test/java/net/serenity/samples/batch/junit/model/ActivationMail.java: -------------------------------------------------------------------------------- 1 | package net.serenity.samples.batch.junit.model; 2 | 3 | /** 4 | * User: YamStranger 5 | * Date: 11/13/15 6 | * Time: 2:02 AM 7 | */ 8 | public class ActivationMail { 9 | private final String mail; 10 | private final String id; 11 | 12 | public ActivationMail(final String mail, final String id) { 13 | this.mail = mail; 14 | this.id = id; 15 | } 16 | 17 | public String getMail() { 18 | return this.mail; 19 | } 20 | 21 | public String getId() { 22 | return this.id; 23 | } 24 | 25 | @Override 26 | public boolean equals(Object o) { 27 | if (this == o) return true; 28 | if (o == null || this.getClass() != o.getClass()) return false; 29 | 30 | ActivationMail that = (ActivationMail) o; 31 | 32 | if (this.mail != null ? 33 | !this.mail.equals(that.mail) 34 | : that.mail != null) 35 | return false; 36 | return !(this.id != null ? 37 | !this.id.equals(that.id) 38 | : that.id != null); 39 | } 40 | 41 | @Override 42 | public int hashCode() { 43 | int result = this.mail != null ? this.mail.hashCode() : 0; 44 | result = 31 * result + (this.id != null ? this.id.hashCode() : 0); 45 | return result; 46 | } 47 | 48 | @Override 49 | public String toString() { 50 | return "ActivationMail{" + 51 | "mail='" + mail + '\'' + 52 | ", id=" + id + 53 | '}'; 54 | } 55 | } -------------------------------------------------------------------------------- /src/samples/junit-batch-configuration-example/src/test/java/net/serenity/samples/batch/junit/model/User.java: -------------------------------------------------------------------------------- 1 | package net.serenity.samples.batch.junit.model; 2 | 3 | /** 4 | * User: YamStranger 5 | * Date: 11/12/15 6 | * Time: 3:51 PM 7 | */ 8 | public class User { 9 | private final String login; 10 | private final String email; 11 | 12 | public User(final String login, final String email) { 13 | this.login = login; 14 | this.email = email; 15 | } 16 | 17 | public String getLogin() { 18 | return this.login; 19 | } 20 | 21 | public String getEmail() { 22 | return this.email; 23 | } 24 | 25 | @Override 26 | public boolean equals(final Object object) { 27 | if (this == object) return true; 28 | if (object == null || this.getClass() != object.getClass()) return false; 29 | 30 | User user = (User) object; 31 | 32 | if (this.login != null ? 33 | !this.login.equals(user.login) 34 | : user.login != null) 35 | return false; 36 | return !(this.email != null ? 37 | !this.email.equals(user.email) 38 | : user.email != null); 39 | } 40 | 41 | @Override 42 | public int hashCode() { 43 | int result = this.login != null ? this.login.hashCode() : 0; 44 | result = 31 * result + (this.email != null ? this.email.hashCode() : 0); 45 | return result; 46 | } 47 | 48 | @Override 49 | public String toString() { 50 | return "User{" + 51 | "login='" + login + '\'' + 52 | ", email=" + email + 53 | '}'; 54 | } 55 | } -------------------------------------------------------------------------------- /src/samples/junit-batch-configuration-example/src/test/java/net/serenity/samples/batch/junit/steps/serenity/MailActivationSteps.java: -------------------------------------------------------------------------------- 1 | package net.serenity.samples.batch.junit.steps.serenity; 2 | 3 | import net.serenity.samples.batch.junit.model.ActivationMail; 4 | import net.serenity.samples.batch.junit.model.User; 5 | import net.thucydides.core.annotations.Step; 6 | 7 | import java.util.concurrent.ThreadLocalRandom; 8 | 9 | /** 10 | * User: YamStranger 11 | * Date: 11/13/15 12 | * Time: 2:01 AM 13 | */ 14 | public class MailActivationSteps { 15 | 16 | @Step 17 | public void given_activation_send(final ActivationMail activation, final User user) { 18 | action(); 19 | } 20 | 21 | @Step 22 | public void when_user_enter_activation_code() { 23 | action(); 24 | } 25 | 26 | @Step 27 | public void when_activation_code_expired() { 28 | action(); 29 | } 30 | 31 | @Step 32 | public void then_user_account_activated() { 33 | action(); 34 | } 35 | 36 | @Step 37 | public void then_user_received_notification() { 38 | action(); 39 | } 40 | 41 | private void action() { 42 | try { 43 | Thread.sleep(ThreadLocalRandom.current().nextInt(50, 200)); 44 | } catch (InterruptedException e) { 45 | Thread.currentThread().interrupt(); 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/samples/junit-batch-configuration-example/src/test/java/net/serenity/samples/batch/junit/steps/serenity/UserActionSteps.java: -------------------------------------------------------------------------------- 1 | package net.serenity.samples.batch.junit.steps.serenity; 2 | 3 | import net.serenity.samples.batch.junit.model.User; 4 | import net.thucydides.core.annotations.Step; 5 | import net.thucydides.core.util.EnvironmentVariables; 6 | import net.thucydides.core.util.SystemEnvironmentVariables; 7 | import net.thucydides.core.webdriver.Configuration; 8 | import net.thucydides.core.webdriver.SystemPropertiesConfiguration; 9 | 10 | import java.util.concurrent.ThreadLocalRandom; 11 | 12 | import static org.assertj.core.api.Assertions.assertThat; 13 | import static net.thucydides.core.ThucydidesSystemProperty.THUCYDIDES_BATCH_SIZE; 14 | 15 | /** 16 | * User: YamStranger 17 | * Date: 11/12/15 18 | * Time: 3:51 PM 19 | */ 20 | public class UserActionSteps { 21 | 22 | @Step 23 | public void given_started_registration_process(final User user) { 24 | Configuration configuration = new SystemPropertiesConfiguration(SystemEnvironmentVariables.createEnvironmentVariables()); 25 | EnvironmentVariables environmentVariables = configuration.getEnvironmentVariables(); 26 | assertThat(THUCYDIDES_BATCH_SIZE.integerFrom(environmentVariables, 0)).isGreaterThan(0); 27 | } 28 | 29 | @Step 30 | public void given_registered_user(final User user) { 31 | action(); 32 | } 33 | 34 | @Step 35 | public void when_user_activate_registration() { 36 | action(); 37 | } 38 | 39 | @Step 40 | public void when_user_login() { 41 | action(); 42 | } 43 | 44 | @Step 45 | public void when_user_session_expired() { 46 | action(); 47 | } 48 | 49 | @Step 50 | public void when_user_logout() { 51 | action(); 52 | } 53 | 54 | @Step 55 | public void when_user_not_finished_registration() { 56 | action(); 57 | } 58 | 59 | @Step 60 | public void then_user_should_be_available() { 61 | action(); 62 | } 63 | 64 | 65 | @Step 66 | public void then_user_should_be_not_available() { 67 | action(); 68 | } 69 | 70 | @Step 71 | public void then_one_login_record_should_exist() { 72 | action(); 73 | } 74 | 75 | @Step 76 | public void then_login_record_should_not_exist() { 77 | action(); 78 | } 79 | 80 | private void action() { 81 | try { 82 | Thread.sleep(ThreadLocalRandom.current().nextInt(50, 200)); 83 | } catch (InterruptedException e) { 84 | Thread.currentThread().interrupt(); 85 | } 86 | } 87 | } -------------------------------------------------------------------------------- /src/samples/junit-quick-start/build.gradle: -------------------------------------------------------------------------------- 1 | // tag::simple[] 2 | repositories { 3 | mavenLocal() 4 | jcenter() 5 | } 6 | 7 | buildscript { 8 | repositories { 9 | mavenLocal() 10 | jcenter() 11 | } 12 | dependencies { 13 | classpath("net.serenity-bdd:serenity-gradle-plugin:1.1.1") // <1> 14 | } 15 | } 16 | 17 | apply plugin: 'java' 18 | apply plugin: 'eclipse' 19 | apply plugin: 'idea' 20 | apply plugin: 'net.serenity-bdd.aggregator' // <2> 21 | 22 | dependencies { 23 | testCompile 'net.serenity-bdd:serenity-core:1.1.1' // <3> 24 | testCompile 'net.serenity-bdd:serenity-junit:1.1.1' // <4> 25 | testCompile('junit:junit:4.12') 26 | testCompile('org.assertj:assertj-core:1.7.0') 27 | testCompile('org.slf4j:slf4j-simple:1.7.7') 28 | } 29 | // end::simple[] 30 | // tag::advanced[] 31 | gradle.startParameter.continueOnFailure = true // <5> 32 | // end::advanced[] -------------------------------------------------------------------------------- /src/samples/junit-quick-start/build.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 33 | 34 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 92 | 93 | 94 | -------------------------------------------------------------------------------- /src/samples/junit-quick-start/ivy.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /src/samples/junit-quick-start/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | net.serenity_bdd.samples.junit 7 | junit-quick-start 8 | 0.0.1-SNAPSHOT 9 | jar 10 | 11 | Serenity JUnit Quick Start Project 12 | 13 | 14 | UTF-8 15 | 1.8.1 16 | 1.8.1 17 | firefox 18 | 19 | 20 | 21 | 22 | net.serenity-bdd 23 | serenity-core 24 | ${serenity.version} 25 | 26 | 27 | net.serenity-bdd 28 | serenity-junit 29 | ${serenity.version} 30 | 31 | 32 | org.slf4j 33 | slf4j-simple 34 | 1.7.25 35 | 36 | 37 | junit 38 | junit 39 | 4.12 40 | test 41 | 42 | 43 | org.assertj 44 | assertj-core 45 | 3.8.0 46 | test 47 | 48 | 49 | 50 | 51 | 52 | maven-failsafe-plugin 53 | 2.20.1 54 | 55 | 56 | **/features/**/When*.java 57 | 58 | 59 | ${webdriver.driver} 60 | ${surefire.rerunFailingTestsCount} 61 | ${surefire.rerunFailingTestsCount} 62 | 63 | 64 | 65 | 66 | net.serenity-bdd.maven.plugins 67 | serenity-maven-plugin 68 | ${serenity.maven.version} 69 | 70 | 71 | net.serenity-bdd 72 | serenity-core 73 | ${serenity.version} 74 | 75 | 76 | 77 | 78 | serenity-reports 79 | post-integration-test 80 | 81 | aggregate 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | -------------------------------------------------------------------------------- /src/samples/junit-quick-start/src/main/java/net/serenitybdd/samples/junit/model/FrequentFlyer.java: -------------------------------------------------------------------------------- 1 | package net.serenitybdd.samples.junit.model; 2 | 3 | /** 4 | * Created by john on 22/11/14. 5 | */ 6 | public class FrequentFlyer { 7 | 8 | private int balance; 9 | private Status status = Status.Bronze; 10 | 11 | public static FrequentFlyer withInitialBalanceOf(int initialBalance) { 12 | return new FrequentFlyer(initialBalance); 13 | } 14 | 15 | public FrequentFlyer(int balance) { 16 | this.balance = balance; 17 | } 18 | 19 | public PointCumulator flies(int distance) { 20 | return new PointCumulator(distance); 21 | } 22 | 23 | public int getBalance() { 24 | return balance; 25 | } 26 | 27 | public Status getStatus() { 28 | return status; 29 | } 30 | 31 | public void setStatus(Status status) { 32 | this.status = status; 33 | } 34 | 35 | public class PointCumulator { 36 | int distance; 37 | 38 | public PointCumulator(int distance) { 39 | this.distance = distance; 40 | } 41 | 42 | public void kilometers() { 43 | incrementBalanceBy(distance / 10); 44 | updateStatus(); 45 | } 46 | } 47 | 48 | private void updateStatus() { 49 | if (balance >= 5000) { 50 | setStatus(Status.Gold); 51 | } else if (balance >= 1000) { 52 | setStatus(Status.Silver); 53 | } 54 | } 55 | 56 | protected void incrementBalanceBy(int points) { 57 | this.balance += points; 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/samples/junit-quick-start/src/main/java/net/serenitybdd/samples/junit/model/Status.java: -------------------------------------------------------------------------------- 1 | package net.serenitybdd.samples.junit.model; 2 | 3 | public enum Status { 4 | Bronze, 5 | Silver, 6 | Gold, 7 | Platinum 8 | } 9 | -------------------------------------------------------------------------------- /src/samples/junit-quick-start/src/test/java/net/serenitybdd/samples/junit/features/earning_points/WhenCalculatingFrequentFlyerPoints.java: -------------------------------------------------------------------------------- 1 | package net.serenitybdd.samples.junit.features.earning_points; 2 | 3 | import net.serenitybdd.junit.runners.SerenityRunner; 4 | import net.serenitybdd.samples.junit.steps.TravellerSteps; 5 | import net.thucydides.core.annotations.Steps; 6 | import org.junit.Test; 7 | import org.junit.runner.RunWith; 8 | 9 | // tag::testcase[] 10 | @RunWith(SerenityRunner.class) // <1> 11 | public class WhenCalculatingFrequentFlyerPoints { 12 | 13 | @Steps // <2> 14 | TravellerSteps travellerSteps; 15 | 16 | @Test 17 | public void shouldCalculatePointsBasedOnDistance() { 18 | // GIVEN 19 | travellerSteps.a_traveller_has_a_frequent_flyer_account_with_balance(10000); // <3> 20 | 21 | // WHEN 22 | travellerSteps.the_traveller_flies(1000); // <3> 23 | 24 | // THEN 25 | travellerSteps.traveller_should_have_a_balance_of(10100); // <3> 26 | 27 | } 28 | } 29 | // end::testcase[] 30 | 31 | -------------------------------------------------------------------------------- /src/samples/junit-quick-start/src/test/java/net/serenitybdd/samples/junit/features/earning_points/WhenEarningFrequentFlyerStatus.java: -------------------------------------------------------------------------------- 1 | package net.serenitybdd.samples.junit.features.earning_points; 2 | 3 | import net.serenitybdd.junit.runners.SerenityRunner; 4 | import net.serenitybdd.samples.junit.steps.TravellerStatusSteps; 5 | import net.thucydides.core.annotations.Pending; 6 | import net.thucydides.core.annotations.Steps; 7 | import net.thucydides.core.annotations.Title; 8 | import org.junit.Ignore; 9 | import org.junit.Test; 10 | import org.junit.runner.RunWith; 11 | 12 | import static net.serenitybdd.samples.junit.model.Status.*; 13 | 14 | // tag::header[] 15 | @RunWith(SerenityRunner.class) 16 | public class WhenEarningFrequentFlyerStatus { 17 | 18 | @Steps 19 | TravellerStatusSteps travellerSteps; 20 | // end::header[] 21 | // tag::membersShouldStartWithBronzeStatus[] 22 | 23 | @Test 24 | public void membersShouldStartWithBronzeStatus() { 25 | // GIVEN 26 | travellerSteps.a_traveller_joins_the_frequent_flyer_program(); 27 | 28 | // THEN 29 | travellerSteps.traveller_should_have_a_status_of(Bronze); 30 | } 31 | // end::membersShouldStartWithBronzeStatus[] 32 | // tag::earnSilverAfter1000Points[] 33 | 34 | @Test 35 | public void earnSilverAfter1000Points() { 36 | // GIVEN 37 | travellerSteps.a_traveller_joins_the_frequent_flyer_program(); 38 | 39 | // WHEN 40 | travellerSteps.the_traveller_flies(10000); 41 | 42 | // THEN 43 | travellerSteps.traveller_should_have_a_status_of(Silver); 44 | } 45 | //end::earnSilverAfter1000Points[] 46 | // tag::earnGoldAfter5000Points[] 47 | 48 | @Test 49 | @Title("Members earn Gold status after 5000 points (50000 km)") //<1> 50 | public void earnGoldAfter5000Points() { 51 | // GIVEN 52 | travellerSteps.a_traveller_joins_the_frequent_flyer_program(); 53 | 54 | // WHEN 55 | travellerSteps.the_traveller_flies(50000); 56 | 57 | // THEN 58 | travellerSteps.traveller_should_have_a_status_of(Gold); 59 | } 60 | //end::earnGoldAfter5000Points[] 61 | // tag::pendingTest[] 62 | 63 | @Test 64 | @Pending 65 | public void dropsBackToSilverIfLessThan8000PointsEarnedInAYear() { 66 | } 67 | //end::pendingTest[] 68 | //tag::ignoredTest[] 69 | 70 | @Test 71 | @Ignore 72 | public void earnPlatinumAfter10000Points() { 73 | // GIVEN 74 | travellerSteps.a_traveller_joins_the_frequent_flyer_program(); 75 | 76 | // WHEN 77 | travellerSteps.the_traveller_flies(500000); 78 | 79 | // THEN 80 | travellerSteps.traveller_should_have_a_status_of(Platinum); 81 | } 82 | //end::ignoredTest[] 83 | 84 | // tag::endTest[] 85 | } 86 | // end::endTest[] 87 | 88 | -------------------------------------------------------------------------------- /src/samples/junit-quick-start/src/test/java/net/serenitybdd/samples/junit/features/earning_points/WhenEarningFrequentFlyerStatusUpgrades.java: -------------------------------------------------------------------------------- 1 | package net.serenitybdd.samples.junit.features.earning_points; 2 | 3 | import net.serenitybdd.junit.runners.SerenityParameterizedRunner; 4 | import net.serenitybdd.samples.junit.model.Status; 5 | import net.serenitybdd.samples.junit.steps.TravellerStatusSteps; 6 | import net.thucydides.core.annotations.Steps; 7 | import net.thucydides.junit.annotations.TestData; 8 | import org.junit.Test; 9 | import org.junit.runner.RunWith; 10 | 11 | import java.util.Arrays; 12 | import java.util.Collection; 13 | 14 | import static net.serenitybdd.samples.junit.model.Status.*; 15 | 16 | // tag::testcase[] 17 | @RunWith(SerenityParameterizedRunner.class) 18 | public class WhenEarningFrequentFlyerStatusUpgrades { 19 | 20 | @TestData //<1> 21 | public static Collection testData(){ 22 | return Arrays.asList(new Object[][]{ 23 | {0, Bronze}, 24 | {9999, Bronze}, 25 | {10000, Silver}, 26 | {49999, Silver}, 27 | {50000, Gold} 28 | }); 29 | } 30 | 31 | private final int kilometersTravelled; //<2> 32 | private final Status expectedStatus; //<2> 33 | 34 | public WhenEarningFrequentFlyerStatusUpgrades(int kilometersTravelled, //<3> 35 | Status expectedStatus) { //<3> 36 | this.kilometersTravelled = kilometersTravelled; 37 | this.expectedStatus = expectedStatus; 38 | } 39 | 40 | @Steps 41 | TravellerStatusSteps travellerSteps; 42 | 43 | @Test 44 | public void shouldEarnNextStatusWithEnoughPoints() { //<4> 45 | // GIVEN 46 | travellerSteps.a_traveller_joins_the_frequent_flyer_program(); 47 | 48 | // WHEN 49 | travellerSteps.the_traveller_flies(kilometersTravelled); 50 | 51 | // THEN 52 | travellerSteps.traveller_should_have_a_status_of(expectedStatus); 53 | } 54 | } 55 | // end::testcase[] 56 | 57 | -------------------------------------------------------------------------------- /src/samples/junit-quick-start/src/test/java/net/serenitybdd/samples/junit/features/earning_points/WhenEarningFrequentFlyerStatusUpgradesUsingCSV.java: -------------------------------------------------------------------------------- 1 | package net.serenitybdd.samples.junit.features.earning_points; 2 | 3 | import net.serenitybdd.junit.runners.SerenityParameterizedRunner; 4 | import net.serenitybdd.samples.junit.model.Status; 5 | import net.serenitybdd.samples.junit.steps.TravellerStatusSteps; 6 | import net.thucydides.core.annotations.Steps; 7 | import net.thucydides.junit.annotations.Qualifier; 8 | import net.thucydides.junit.annotations.UseTestDataFrom; 9 | import org.junit.Test; 10 | import org.junit.runner.RunWith; 11 | 12 | 13 | // tag::testcase[] 14 | @RunWith(SerenityParameterizedRunner.class) 15 | @UseTestDataFrom(value="testdata/status-levels.csv") //<1> 16 | public class WhenEarningFrequentFlyerStatusUpgradesUsingCSV { 17 | 18 | private int kilometersTravelled; 19 | private Status expectedStatus; 20 | 21 | public void setKilometersTravelled(int kilometersTravelled) { 22 | this.kilometersTravelled = kilometersTravelled; 23 | } 24 | 25 | public void setExpectedStatus(String expectedStatus) { 26 | this.expectedStatus = Status.valueOf(expectedStatus); 27 | } 28 | 29 | @Qualifier 30 | public String qualifier() { 31 | return kilometersTravelled + "=>" + expectedStatus; 32 | } 33 | @Steps 34 | TravellerStatusSteps travellerSteps; 35 | 36 | @Test 37 | public void reallyhouldEarnNextStatusWithEnoughPoints() { 38 | // GIVEN 39 | travellerSteps.a_traveller_joins_the_frequent_flyer_program(); 40 | 41 | // WHEN 42 | travellerSteps.the_traveller_flies(kilometersTravelled); 43 | 44 | // THEN 45 | travellerSteps.traveller_should_have_a_status_of(expectedStatus); 46 | } 47 | } 48 | // end::testcase[] 49 | 50 | -------------------------------------------------------------------------------- /src/samples/junit-quick-start/src/test/java/net/serenitybdd/samples/junit/features/managing_member_accounts/WhenUpdatingMemberAccounts.java: -------------------------------------------------------------------------------- 1 | package net.serenitybdd.samples.junit.features.managing_member_accounts; 2 | 3 | import net.serenitybdd.junit.runners.SerenityRunner; 4 | import net.serenitybdd.samples.junit.steps.TravellerHistorySteps; 5 | import net.thucydides.core.annotations.Steps; 6 | import org.junit.Test; 7 | import org.junit.runner.RunWith; 8 | 9 | import static net.serenitybdd.samples.junit.model.Status.*; 10 | 11 | // tag::testcase[] 12 | @RunWith(SerenityRunner.class) 13 | public class WhenUpdatingMemberAccounts { 14 | 15 | @Steps 16 | TravellerHistorySteps travellerSteps; 17 | 18 | @Test 19 | public void shouldFetchFlightHistoryFromMainframe() { 20 | // ASSUMPTION 21 | travellerSteps.assuming_the_mainframe_is_available(); 22 | 23 | // WHEN 24 | travellerSteps.we_fetch_the_latest_flight_history_for_a_traveller(); 25 | 26 | // THEN 27 | travellerSteps.traveller_should_see_the_latest_flights(); 28 | } 29 | } 30 | // end::testcase[] 31 | 32 | -------------------------------------------------------------------------------- /src/samples/junit-quick-start/src/test/java/net/serenitybdd/samples/junit/features/searching/WhenSearchingFlights.java: -------------------------------------------------------------------------------- 1 | package net.serenitybdd.samples.junit.features.searching; 2 | 3 | import net.serenitybdd.junit.runners.SerenityRunner; 4 | import net.serenitybdd.samples.junit.steps.FlightSearchSteps; 5 | import net.thucydides.core.annotations.Managed; 6 | import net.thucydides.core.annotations.Narrative; 7 | import net.thucydides.core.annotations.Steps; 8 | import org.junit.Test; 9 | import org.junit.runner.RunWith; 10 | import org.openqa.selenium.WebDriver; 11 | 12 | // tag::narrative[] 13 | @Narrative(text={"In order to choose the best flight for my travels", //<1> 14 | "As a traveller", 15 | "I want to be able to search for flights between specific destinations"}) 16 | // end::narrative[] 17 | // tag::testcase[] 18 | @RunWith(SerenityRunner.class) 19 | public class WhenSearchingFlights { 20 | 21 | @Managed(driver = "chrome") 22 | WebDriver driver; 23 | 24 | @Steps 25 | FlightSearchSteps theCustomer; 26 | 27 | @Test 28 | public void should_display_selected_flight_details() { 29 | // GIVEN 30 | theCustomer.searches_for_flights_between("Sydney", "London"); 31 | // WHEN 32 | theCustomer.view_flight_details_for_flight(1); 33 | // THEN 34 | theCustomer.should_see_the_destination_city_in_the_summary(); 35 | } 36 | } 37 | // end::testcase[] -------------------------------------------------------------------------------- /src/samples/junit-quick-start/src/test/java/net/serenitybdd/samples/junit/features/searching/WhenSearchingForDifferentTermsOnGoogle.java: -------------------------------------------------------------------------------- 1 | package net.serenitybdd.samples.junit.features.searching; 2 | 3 | import net.serenitybdd.junit.runners.SerenityParameterizedRunner; 4 | import net.serenitybdd.samples.junit.pages.GooglePage; 5 | import net.thucydides.core.annotations.Managed; 6 | import net.thucydides.junit.annotations.Concurrent; 7 | import net.thucydides.junit.annotations.TestData; 8 | import org.junit.Test; 9 | import org.junit.runner.RunWith; 10 | import org.openqa.selenium.WebDriver; 11 | 12 | import java.util.Arrays; 13 | import java.util.Collection; 14 | 15 | import static org.assertj.core.api.Assertions.assertThat; 16 | 17 | // tag::testcase[] 18 | @RunWith(SerenityParameterizedRunner.class) 19 | @Concurrent //<1> 20 | public class WhenSearchingForDifferentTermsOnGoogle { 21 | 22 | @Managed(driver = "chrome") 23 | WebDriver driver; 24 | 25 | GooglePage googlePage; 26 | 27 | @TestData //<2> 28 | public static Collection testData(){ 29 | return Arrays.asList(new Object[][]{ 30 | {"cats"}, 31 | {"dogs"}, 32 | {"ferrets"}, 33 | {"rabbits"}, 34 | {"canaries"} 35 | }); 36 | } 37 | 38 | private final String searchTerm; //<3> 39 | 40 | public WhenSearchingForDifferentTermsOnGoogle(String searchTerm) { 41 | this.searchTerm = searchTerm; 42 | } 43 | 44 | @Test 45 | public void shouldInstantiatedPageObjectsForADataDrivenWebTest() { 46 | 47 | googlePage.open(); 48 | 49 | googlePage.searchFor(searchTerm); 50 | 51 | assertThat(googlePage.getTitle()).isEqualTo(searchTerm + " - Google Search"); 52 | } 53 | } 54 | // end::testcase[] 55 | 56 | -------------------------------------------------------------------------------- /src/samples/junit-quick-start/src/test/java/net/serenitybdd/samples/junit/features/searching/WhenSearchingOnGoogle.java: -------------------------------------------------------------------------------- 1 | package net.serenitybdd.samples.junit.features.searching; 2 | 3 | import net.serenitybdd.junit.runners.SerenityRunner; 4 | import net.serenitybdd.samples.junit.pages.GooglePage; 5 | import net.thucydides.core.annotations.Managed; 6 | import net.thucydides.core.annotations.findby.By; 7 | import org.junit.Test; 8 | import org.junit.runner.RunWith; 9 | import org.openqa.selenium.Keys; 10 | import org.openqa.selenium.WebDriver; 11 | import org.openqa.selenium.support.ui.WebDriverWait; 12 | 13 | import static org.assertj.core.api.Assertions.assertThat; 14 | import static org.openqa.selenium.support.ui.ExpectedConditions.titleContains; 15 | 16 | // tag::header[] 17 | @RunWith(SerenityRunner.class) 18 | public class WhenSearchingOnGoogle { 19 | 20 | @Managed //<1> 21 | WebDriver driver; 22 | // end::header[] 23 | // tag::pageObjects[] 24 | 25 | GooglePage googlePage; 26 | // end::pageObjects[] 27 | // tag::simpletest[] 28 | 29 | @Test 30 | public void shouldInstantiateAWebDriverInstanceForAWebTest() { 31 | driver.get("http://www.google.com"); //<2> 32 | 33 | driver.findElement(By.name("q")).sendKeys("firefly", Keys.ENTER); 34 | 35 | new WebDriverWait(driver,5).until(titleContains("Google Search")); 36 | 37 | assertThat(driver.getTitle()).isEqualTo("firefly - Google Search"); 38 | } 39 | // end::simpletest[] 40 | // tag::pageObjectTest[] 41 | 42 | @Test 43 | public void shouldInstantiatedPageObjectsForAWebTest() { 44 | 45 | googlePage.open(); 46 | 47 | googlePage.searchFor("firefly"); 48 | 49 | assertThat(googlePage.getTitle()).isEqualTo("firefly - Google Search"); 50 | } 51 | // end::pageObjectTest[] 52 | // tag::endTest[] 53 | } 54 | // end::endTest[] 55 | 56 | -------------------------------------------------------------------------------- /src/samples/junit-quick-start/src/test/java/net/serenitybdd/samples/junit/features/searching/package-info.java: -------------------------------------------------------------------------------- 1 | @Narrative( 2 | text = {"Search-related functionality"} 3 | ) 4 | package net.serenitybdd.samples.junit.features.searching; 5 | 6 | import net.thucydides.core.annotations.Narrative; -------------------------------------------------------------------------------- /src/samples/junit-quick-start/src/test/java/net/serenitybdd/samples/junit/pages/FlightDetailsPage.java: -------------------------------------------------------------------------------- 1 | package net.serenitybdd.samples.junit.pages; 2 | 3 | import net.thucydides.core.pages.PageObject; 4 | 5 | /** 6 | * Created by john on 6/12/14. 7 | */ 8 | public class FlightDetailsPage extends PageObject { 9 | public String getDepartureCity() { 10 | return "Sydney"; 11 | } 12 | 13 | public String getDestinationCity() { 14 | return "London"; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/samples/junit-quick-start/src/test/java/net/serenitybdd/samples/junit/pages/FlightSearchPage.java: -------------------------------------------------------------------------------- 1 | package net.serenitybdd.samples.junit.pages; 2 | 3 | import net.thucydides.core.pages.PageObject; 4 | 5 | /** 6 | * Created by john on 6/12/14. 7 | */ 8 | public class FlightSearchPage extends PageObject { 9 | public FlightSearchBuilder searchForFlightsFrom(String departure) { 10 | return new FlightSearchBuilder(); 11 | } 12 | 13 | public class FlightSearchBuilder { 14 | public void to(String destination) { 15 | 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/samples/junit-quick-start/src/test/java/net/serenitybdd/samples/junit/pages/FlightSearchResultsPage.java: -------------------------------------------------------------------------------- 1 | package net.serenitybdd.samples.junit.pages; 2 | 3 | import net.thucydides.core.pages.PageObject; 4 | 5 | /** 6 | * Created by john on 6/12/14. 7 | */ 8 | public class FlightSearchResultsPage extends PageObject { 9 | public void selectFlightNumber(int flightNumber) { 10 | 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/samples/junit-quick-start/src/test/java/net/serenitybdd/samples/junit/pages/GooglePage.java: -------------------------------------------------------------------------------- 1 | package net.serenitybdd.samples.junit.pages; 2 | 3 | import net.thucydides.core.annotations.DefaultUrl; 4 | import net.thucydides.core.pages.PageObject; 5 | import org.openqa.selenium.Keys; 6 | import org.openqa.selenium.WebElement; 7 | import org.openqa.selenium.support.FindBy; 8 | 9 | import static org.openqa.selenium.support.ui.ExpectedConditions.titleContains; 10 | 11 | @DefaultUrl("http://www.google.com") 12 | public class GooglePage extends PageObject { 13 | 14 | @FindBy(name="q") 15 | WebElement search; 16 | 17 | public void searchFor(String keywords) { 18 | search.sendKeys(keywords, Keys.ENTER); 19 | waitFor(titleContains("Google Search")); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/samples/junit-quick-start/src/test/java/net/serenitybdd/samples/junit/steps/FlightSearchSteps.java: -------------------------------------------------------------------------------- 1 | package net.serenitybdd.samples.junit.steps; 2 | 3 | import net.serenitybdd.core.Serenity; 4 | import net.serenitybdd.samples.junit.pages.FlightDetailsPage; 5 | import net.serenitybdd.samples.junit.pages.FlightSearchPage; 6 | import net.serenitybdd.samples.junit.pages.FlightSearchResultsPage; 7 | import net.thucydides.core.annotations.Step; 8 | import net.thucydides.core.steps.ScenarioSteps; 9 | 10 | import static org.assertj.core.api.Assertions.assertThat; 11 | 12 | // tag::classbody[] 13 | public class FlightSearchSteps extends ScenarioSteps { 14 | 15 | FlightSearchPage flightSearchPage; 16 | FlightSearchResultsPage flightSearchResultsPage; 17 | FlightDetailsPage flightDetailsPage; 18 | 19 | @Step("A customer searchers for flights between {0} and {1}") 20 | public void searches_for_flights_between(String departure, String destination) { 21 | Serenity.setSessionVariable("destinationCity").to(destination); //<1> 22 | 23 | flightSearchPage.searchForFlightsFrom(departure).to(destination); 24 | } 25 | 26 | @Step 27 | public void view_flight_details_for_flight(int flightNumber) { 28 | flightSearchResultsPage.selectFlightNumber(flightNumber); 29 | } 30 | 31 | @Step 32 | public void should_see_the_destination_city_in_the_summary() { 33 | String expectedDestinationCity 34 | = Serenity.sessionVariableCalled("destinationCity").toString(); //<2> 35 | 36 | assertThat(flightDetailsPage.getDestinationCity()).isEqualTo(expectedDestinationCity); 37 | } 38 | } 39 | // end::classbody[] -------------------------------------------------------------------------------- /src/samples/junit-quick-start/src/test/java/net/serenitybdd/samples/junit/steps/MainframeStatus.java: -------------------------------------------------------------------------------- 1 | package net.serenitybdd.samples.junit.steps; 2 | 3 | /** 4 | * Created by john on 5/12/14. 5 | */ 6 | public enum MainframeStatus { 7 | ONLINE, OFFLINE 8 | } 9 | -------------------------------------------------------------------------------- /src/samples/junit-quick-start/src/test/java/net/serenitybdd/samples/junit/steps/TravellerHistorySteps.java: -------------------------------------------------------------------------------- 1 | package net.serenitybdd.samples.junit.steps; 2 | 3 | import net.thucydides.core.annotations.Step; 4 | import net.thucydides.core.steps.ScenarioSteps; 5 | 6 | import static net.serenitybdd.samples.junit.steps.MainframeStatus.OFFLINE; 7 | import static net.serenitybdd.samples.junit.steps.MainframeStatus.ONLINE; 8 | // tag::header[] 9 | import static org.hamcrest.Matchers.is; 10 | import static org.junit.Assume.assumeThat; 11 | 12 | public class TravellerHistorySteps extends ScenarioSteps { 13 | // end::header[] 14 | 15 | //tag::assumptionSteps[] 16 | @Step 17 | public void assuming_the_mainframe_is_available() { 18 | assumeThat(mainframe(), is(ONLINE)); // <1> 19 | } 20 | 21 | private MainframeStatus mainframe() { 22 | return OFFLINE; // <2> 23 | } 24 | //end::assumptionSteps[] 25 | 26 | @Step 27 | public void we_fetch_the_latest_flight_history_for_a_traveller() { 28 | // Interact with the mainframe 29 | } 30 | 31 | @Step 32 | public void traveller_should_see_the_latest_flights() { 33 | // Check the latest accounts 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/samples/junit-quick-start/src/test/java/net/serenitybdd/samples/junit/steps/TravellerStatusSteps.java: -------------------------------------------------------------------------------- 1 | package net.serenitybdd.samples.junit.steps; 2 | 3 | import net.serenitybdd.samples.junit.model.FrequentFlyer; 4 | import net.serenitybdd.samples.junit.model.Status; 5 | import net.thucydides.core.annotations.Step; 6 | 7 | import static org.assertj.core.api.Assertions.assertThat; 8 | 9 | // tag::testcase[] 10 | public class TravellerStatusSteps extends TravellerSteps { // <1> 11 | 12 | @Step // <2> 13 | public void a_traveller_joins_the_frequent_flyer_program() { 14 | frequentFlyer = FrequentFlyer.withInitialBalanceOf(0); 15 | } 16 | 17 | @Step("The traveller should have {0} status") // <3> 18 | public void traveller_should_have_a_status_of(Status expectedStatus) { 19 | assertThat(frequentFlyer.getStatus()).isEqualTo(expectedStatus); 20 | } 21 | } 22 | // end::testcase[] -------------------------------------------------------------------------------- /src/samples/junit-quick-start/src/test/java/net/serenitybdd/samples/junit/steps/TravellerSteps.java: -------------------------------------------------------------------------------- 1 | package net.serenitybdd.samples.junit.steps; 2 | 3 | import net.serenitybdd.samples.junit.model.FrequentFlyer; 4 | import net.serenitybdd.samples.junit.model.Status; 5 | import net.thucydides.core.annotations.Step; 6 | 7 | import static org.assertj.core.api.Assertions.assertThat; 8 | 9 | // tag::classbody[] 10 | public class TravellerSteps { 11 | 12 | FrequentFlyer frequentFlyer; // <1> 13 | 14 | @Step("Given a traveller has a frequent flyer account with {0} points") // <2> 15 | public void a_traveller_has_a_frequent_flyer_account_with_balance(int initialBalance) { 16 | frequentFlyer = FrequentFlyer.withInitialBalanceOf(initialBalance); // <3> 17 | } 18 | 19 | @Step("When the traveller flies {0} km") 20 | public void the_traveller_flies(int distance) { 21 | frequentFlyer.flies(distance).kilometers(); // <4> 22 | 23 | } 24 | 25 | @Step("Then the traveller should have a balance of {0} points") 26 | public void traveller_should_have_a_balance_of(int expectedBalance ) { 27 | assertThat(frequentFlyer.getBalance()).isEqualTo(expectedBalance); // <5> 28 | } 29 | 30 | @Step 31 | public void a_traveller_joins_the_frequent_flyer_program() { 32 | frequentFlyer = FrequentFlyer.withInitialBalanceOf(0); 33 | } 34 | 35 | @Step 36 | public void traveller_should_have_a_status_of(Status expectedStatus) { 37 | assertThat(frequentFlyer.getStatus()).isEqualTo(expectedStatus); 38 | } 39 | } 40 | // end::classbody[] 41 | -------------------------------------------------------------------------------- /src/samples/junit-quick-start/src/test/resources/testdata/status-levels.csv: -------------------------------------------------------------------------------- 1 | KILOMETERS TRAVELLED, EXPECTED STATUS 2 | 0, Bronze 3 | 9999, Bronze 4 | 10000, Silver 5 | 49999, Silver 6 | 50000, Gold -------------------------------------------------------------------------------- /src/samples/junit-quick-start/thucydides.properties: -------------------------------------------------------------------------------- 1 | serenity.test.root=net.serenitybdd.samples.junit.features 2 | -------------------------------------------------------------------------------- /src/samples/junit-retries/net/serenity/samples/retries/SampleTest.java: -------------------------------------------------------------------------------- 1 | @RunWith(SerenityRunner.class) 2 | public class SampleTest { 3 | 4 | @Steps 5 | TestSteps steps; 6 | 7 | @Test 8 | public void shouldExecuteThisTest() { 9 | steps.initialization(2); 10 | steps.when_example_action_for(1); 11 | steps.then_example_result_should_be(2); 12 | } 13 | } -------------------------------------------------------------------------------- /src/samples/junit-retries/net/serenity/samples/retries/TestSteps.java: -------------------------------------------------------------------------------- 1 | public class TestSteps { 2 | 3 | private static Integer counter = 2; 4 | 5 | @Step 6 | public void initialization(final int value) { 7 | action(); 8 | } 9 | 10 | @Step 11 | public void when_example_action_for(final int value) { 12 | action(); 13 | Assert.assertTrue(true); 14 | } 15 | 16 | @Step 17 | public void then_example_result_should_be(final int value) { 18 | action(); 19 | Assert.assertTrue(--counter <= 0); 20 | } 21 | 22 | private void action() { 23 | //some action 24 | } 25 | } -------------------------------------------------------------------------------- /src/samples/junit-tests-linked-to-issues/serenity.properties: -------------------------------------------------------------------------------- 1 | serenity.issue.tracker.url = https://example.server.com/cases/view/{0} -------------------------------------------------------------------------------- /src/samples/junit-tests-linked-to-issues/src/test/java/net/serenity/samples/retries/SampleTest.java: -------------------------------------------------------------------------------- 1 | @RunWith(SerenityRunner.class) 2 | public class SampleTest { 3 | 4 | @Steps 5 | TestSteps steps; 6 | 7 | @Test 8 | @Title("Test case for some issue #BP-64 ") 9 | public void shouldExecuteThisTest() { 10 | steps.initialization(); 11 | steps.when_example_action_for(1); 12 | steps.then_example_result_should_be(2); 13 | } 14 | 15 | @Test 16 | @Title("Tests important bugs : #BP-64,#IS-84") 17 | public void shouldExecuteThisTestTwo() { 18 | steps.initialization(); 19 | steps.when_example_action_for(1); 20 | steps.then_example_result_should_be(2); 21 | } 22 | 23 | @Test 24 | @Issue("#NO-97") 25 | public void shouldExecuteThisTestThree() { 26 | steps.initialization(); 27 | steps.when_example_action_for(1); 28 | steps.then_example_result_should_be(2); 29 | } 30 | 31 | @Test 32 | @Issues({"#PN-97", "#KB-927"}) 33 | public void shouldExecuteThisTestLast() { 34 | steps.initialization(); 35 | steps.when_example_action_for(1); 36 | steps.then_example_result_should_be(2); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/samples/junit-tests-linked-to-issues/src/test/java/net/serenity/samples/retries/TestSteps.java: -------------------------------------------------------------------------------- 1 | public class TestSteps { 2 | 3 | @Step 4 | public void initialization() { 5 | action(); 6 | } 7 | 8 | @Step 9 | public void when_example_action_for(final int value) { 10 | action(); 11 | Assert.assertTrue(true); 12 | } 13 | 14 | @Step 15 | public void then_example_result_should_be(final int value) { 16 | action(); 17 | Assert.assertTrue(true); 18 | } 19 | 20 | private void action() { 21 | try { 22 | Thread.sleep(ThreadLocalRandom.current().nextInt(50, 200)); 23 | } catch (InterruptedException e) { 24 | Thread.currentThread().interrupt(); 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/samples/settings.gradle: -------------------------------------------------------------------------------- 1 | include 'junit-quick-start','cucumber-quick-start','jbehave-quick-start','journey-pattern-sample' --------------------------------------------------------------------------------