├── .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