├── .gitignore ├── README.md ├── docker-compose.yml ├── docker-images-build.sh ├── docker ├── README.md ├── tomcat-users.xml ├── tomcat7-jdk8.dockerfile └── ui-tests.dockerfile ├── pippo-demo.war ├── pom.xml ├── restart.sh ├── serenity.properties ├── src └── main │ ├── java │ └── ro │ │ └── fortsoft │ │ └── pippo │ │ └── demo │ │ └── bdd │ │ ├── config │ │ ├── Locators.java │ │ └── Messages.java │ │ ├── cucumber │ │ ├── ContactsStepDefs.java │ │ ├── LoginStepDefs.java │ │ └── hook │ │ │ └── CucumberHooks.java │ │ ├── pages │ │ ├── ContactsPage.java │ │ └── LoginPage.java │ │ ├── runner │ │ └── PippoCrudDemoRunner.java │ │ └── serenity │ │ ├── ContactsSteps.java │ │ └── LoginSteps.java │ └── resources │ ├── features │ ├── contacts │ │ └── contacts.feature │ └── login │ │ └── login.feature │ ├── locators.conf │ ├── messages.conf │ └── simplelogger.properties ├── start.sh └── stop.sh /.gitignore: -------------------------------------------------------------------------------- 1 | target 2 | out 3 | *.iml 4 | .idea -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # BDD testing - Cucumber and Serenity setup running on docker containers 2 | BDD testing of [pippo](http://www.pippo.ro/) [demo angular-crud-app](https://github.com/decebals/pippo-demo/tree/master/pippo-demo-crudng) with [Cucumber](https://cucumber.io/docs/reference/jvm#java) and [Serenity](http://thucydides.info/docs/serenity-staging/) 3 | 4 | Sources for the blog posts [Using docker for orchestrating a reusable BDD web testing setup with Selenium grid - Part I](http://balamaci.ro/using-docker-and-docker-compose-for-orchestrating-a-full-bdd/) 5 | and [BDD web testing setup - Docker, Cucumber and Serenity - Part II](http://balamaci.ro/orchestrating-a-reusable-bdd-web-testing-setup-part-ii/) 6 | 7 | ## Prerequisites 8 | - Install Docker and [Docker-compose](http://docs.docker.com/compose/install/) 9 | - Clone this repository 10 | ````bash 11 | $ git clone git@github.com:balamaci/blog-ui-bdd-testing.git 12 | ```` 13 | - Create the docker images locally 14 | There is a one time run of 15 | ````bash 16 | $ ./docker-images-build.sh 17 | ```` 18 | which will create the docker images locally. Normally you'd have them pushed to a repository, but I wanted to show there are no "hidden tricks", or you can use them as example to build your own. So instead we use the script to build locally the required images. 19 | 20 | ## Code run 21 | To run the bdd tests anytime just do 22 | ````bash 23 | $ ./restart.sh 24 | ```` 25 | 26 | which basically does **docker-compose run uitests mvn clean verify** 27 | 28 | 29 | This would execute the **Cucumber tests** and produce the **Serenity reports** which can be accessed at **./target/site/index.html** 30 | 31 | 32 | [![BDD preview](http://balamaci.ro/content/images/2015/10/bdd_preview.png)](http://balamaci.ro/static/serenity/index.html) 33 | 34 | 35 | 36 | We included **pippo-demo.war** -the application we run our tests against- on the repo to have a single command to run the job. Normally you'd have it provided by another build job that would trigger the testing job. 37 | -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | tomcat: 2 | image: balamaci/tomcat7-jdk8 3 | ports: 4 | - 8080:8080 5 | volumes: 6 | - ./out/tomcat:/opt/tomcat/logs 7 | 8 | hub: 9 | image: selenium/hub:2.48.1 10 | expose: 11 | - 4444:4444 12 | links: 13 | - tomcat 14 | 15 | nodeff: 16 | image: selenium/node-firefox:2.48.1 17 | volumes: 18 | - ./out/ff/e2e/uploads:/e2e/uploads 19 | links: 20 | - hub 21 | - tomcat 22 | 23 | uitests: 24 | image: balamaci/ui-tests 25 | volumes: 26 | - .:/usr/src/app 27 | - ~/.m2:/root/.m2 28 | links: 29 | - tomcat 30 | - hub 31 | - nodeff 32 | -------------------------------------------------------------------------------- /docker-images-build.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | cd docker 4 | 5 | docker build --rm -t balamaci/oracle-jdk8 -f oracle-jdk8.dockerfile . 6 | 7 | docker build --rm -t balamaci/tomcat7-jdk8 -f tomcat7-jdk8.dockerfile . 8 | 9 | docker build --rm -t balamaci/mvn3-jdk8 -f mvn3-jdk8.dockerfile . 10 | 11 | docker build --rm -t balamaci/ui-tests -f ui-tests.dockerfile . -------------------------------------------------------------------------------- /docker/README.md: -------------------------------------------------------------------------------- 1 | # Docker file recipes 2 | Contains all the necesary dockerfiles which are required to run the project. 3 | They can be used as example to inspire to build your own images. 4 | Otherwise some of them might already be available on the docker repo. 5 | 6 | The script **docker-images-build.sh** can be used to build locally the container images. 7 | -------------------------------------------------------------------------------- /docker/tomcat-users.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /docker/tomcat7-jdk8.dockerfile: -------------------------------------------------------------------------------- 1 | FROM maven:3.3.3-jdk-8 2 | ENV TOMCAT_VERSION 7.0.63 3 | 4 | VOLUME ["/var/log/tomcat7"] 5 | 6 | # Get and Unpack Tomcat 7 | RUN wget http://archive.apache.org/dist/tomcat/tomcat-7/v${TOMCAT_VERSION}/bin/apache-tomcat-${TOMCAT_VERSION}.tar.gz -O /tmp/catalina.tar.gz && \ 8 | tar xzf /tmp/catalina.tar.gz -C /opt && \ 9 | ln -s /opt/apache-tomcat-${TOMCAT_VERSION}/ /opt/tomcat && \ 10 | rm /tmp/catalina.tar.gz 11 | 12 | ADD tomcat-users.xml /opt/tomcat/conf/ 13 | CMD CATALINA_BASE=/opt/tomcat CATALINA_HOME=/opt/tomcat /opt/tomcat/bin/catalina.sh run 14 | EXPOSE 8080 -------------------------------------------------------------------------------- /docker/ui-tests.dockerfile: -------------------------------------------------------------------------------- 1 | FROM maven:3.3.3-jdk-8 2 | 3 | VOLUME ["/usr/src/app"] 4 | WORKDIR /usr/src/app 5 | -------------------------------------------------------------------------------- /pippo-demo.war: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balamaci/blog-ui-bdd-testing/2860518acd37b8b5f30bd960c68824c471c44291/pippo-demo.war -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 4.0.0 7 | ro.fortsoft.pippo.demo.bdd 8 | pippo-bdd 9 | jar 10 | 1.0-SNAPSHOT 11 | BDD testing of pippo demo with Cucumber and Serenity 12 | 13 | 14 | tomcat 15 | pippo 16 | pippo-demo.war 17 | 18 | 1.7.7 19 | 1.3.0 20 | 1.1.14 21 | 1.1.1 22 | 1.7.0 23 | 24 | 25 | 26 | 27 | 28 | com.typesafe 29 | config 30 | ${typesafe.config} 31 | 32 | 33 | 34 | 35 | org.slf4j 36 | slf4j-simple 37 | ${slf4j.version} 38 | 39 | 40 | 41 | 42 | 43 | net.serenity-bdd 44 | serenity-core 45 | ${serenity.core.version} 46 | 47 | 48 | 49 | net.serenity-bdd 50 | serenity-cucumber 51 | ${serenity.cucumber.version} 52 | 53 | 54 | 55 | org.assertj 56 | assertj-core 57 | ${assertj-core.version} 58 | 59 | 60 | 61 | 62 | src/main/java 63 | 64 | 65 | 66 | true 67 | org.apache.maven.plugins 68 | maven-compiler-plugin 69 | 3.1 70 | 71 | 1.8 72 | 1.8 73 | UTF-8 74 | true 75 | true 76 | 77 | 78 | 79 | 80 | org.codehaus.cargo 81 | cargo-maven2-plugin 82 | 1.4.11 83 | 84 | 85 | tomcat7x 86 | remote 87 | 88 | 89 | runtime 90 | 91 | ${tomcat.hostname} 92 | 8080 93 | admin 94 | admin 95 | 96 | 97 | 98 | remote 99 | 100 | 101 | 102 | war 103 | ${war.file.location} 104 | 105 | ${webapp.deploy.context} 106 | 107 | 108 | 109 | 110 | 111 | 112 | war-deploy 113 | pre-integration-test 114 | 115 | deploy 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | org.apache.maven.plugins 124 | maven-surefire-plugin 125 | 2.18 126 | 127 | true 128 | 129 | 130 | 131 | maven-failsafe-plugin 132 | 2.18 133 | 134 | 135 | **/runner/*.java 136 | 137 | true 138 | 139 | 140 | 141 | 142 | integration-test 143 | verify 144 | 145 | 146 | 147 | 148 | 149 | net.serenity-bdd.maven.plugins 150 | serenity-maven-plugin 151 | ${serenity.core.version} 152 | 153 | 154 | serenity-reports 155 | post-integration-test 156 | 157 | aggregate 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | -------------------------------------------------------------------------------- /restart.sh: -------------------------------------------------------------------------------- 1 | ./stop.sh 2 | ./start.sh 3 | -------------------------------------------------------------------------------- /serenity.properties: -------------------------------------------------------------------------------- 1 | serenity.project.name = Pippo CRUD Demo Functional Tests 2 | 3 | webdriver.remote.driver = firefox 4 | 5 | webdriver.base.url=http://tomcat:8080/pippo/ 6 | webdriver.remote.url = http://hub:4444/wd/hub 7 | 8 | # Only for firefox 9 | #webdriver.load.strategy = unstable 10 | 11 | webdriver.timeouts.implicitlywait = 5000 12 | webdriver.wait.for.timeout = 10000 13 | 14 | serenity.browser.width = 1280 15 | serenity.resized.image.width = 1024 16 | json.pretty.printing = true 17 | story.timeout.in.secs = 3600 18 | serenity.console.headings = normal 19 | 20 | serenity.step.delay = 500 21 | serenity.timeout = 10 22 | 23 | serenity.use.unique.browser = true 24 | serenity.take.screenshots = BEFORE_AND_AFTER_EACH_STEP 25 | serenity.requirements.dir = src/main/resources/features 26 | serenity.requirement.types = epic,story,feature 27 | serenity.dry.run = false 28 | -------------------------------------------------------------------------------- /src/main/java/ro/fortsoft/pippo/demo/bdd/config/Locators.java: -------------------------------------------------------------------------------- 1 | package ro.fortsoft.pippo.demo.bdd.config; 2 | 3 | import com.typesafe.config.Config; 4 | import com.typesafe.config.ConfigFactory; 5 | 6 | /** 7 | * @author sbalamaci 8 | */ 9 | public class Locators { 10 | 11 | private static Config locatorsConfig = ConfigFactory.load("locators"); 12 | 13 | private Locators() { 14 | } 15 | 16 | public static String getValue(String key) { 17 | return locatorsConfig.getString(key); 18 | } 19 | 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/ro/fortsoft/pippo/demo/bdd/config/Messages.java: -------------------------------------------------------------------------------- 1 | package ro.fortsoft.pippo.demo.bdd.config; 2 | 3 | import com.typesafe.config.Config; 4 | import com.typesafe.config.ConfigFactory; 5 | 6 | /** 7 | * @author Serban Balamaci 8 | */ 9 | public class Messages { 10 | 11 | private static Config messagesConfig = ConfigFactory.load("messages"); 12 | 13 | private Messages() { 14 | } 15 | 16 | public static String getValue(String key) { 17 | return messagesConfig.getString(key); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/ro/fortsoft/pippo/demo/bdd/cucumber/ContactsStepDefs.java: -------------------------------------------------------------------------------- 1 | package ro.fortsoft.pippo.demo.bdd.cucumber; 2 | 3 | import cucumber.api.java.en.Given; 4 | import cucumber.api.java.en.Then; 5 | import cucumber.api.java.en.When; 6 | import net.thucydides.core.annotations.Steps; 7 | import ro.fortsoft.pippo.demo.bdd.serenity.ContactsSteps; 8 | 9 | /** 10 | * @author sbalamaci 11 | */ 12 | public class ContactsStepDefs { 13 | 14 | @Steps 15 | private ContactsSteps contactsSteps; 16 | 17 | @Given("^(?:I try to access|I open) the 'Contacts' page$") 18 | public void navigate_contacts_page() { 19 | contactsSteps.openContactsPage(); 20 | } 21 | 22 | @When("^I click on 'Add'$") 23 | public void click_on_add() { 24 | contactsSteps.clickOnAdd(); 25 | } 26 | 27 | @Then("^I click 'Submit' button$") 28 | public void click_submit() { 29 | contactsSteps.clickOnSubmit(); 30 | } 31 | 32 | @When("^I enter '(.*)' '(.*)' and '(.*)' in the Edit panel$") 33 | public void fill_contact_info(String name, String phone, String address) { 34 | contactsSteps.fillContactInfo(name, phone, address); 35 | } 36 | 37 | @Then("^I should see the 'Contacts' page$") 38 | public void is_contacts_page() { 39 | contactsSteps.isContactsPage(); 40 | } 41 | 42 | 43 | @Then("^I should see '(.*)' in the list of contacts$") 44 | public void contact_name_is_present_in_contacts_table(String name) { 45 | contactsSteps.isContactWithNamePresentInList(name); 46 | } 47 | 48 | } 49 | -------------------------------------------------------------------------------- /src/main/java/ro/fortsoft/pippo/demo/bdd/cucumber/LoginStepDefs.java: -------------------------------------------------------------------------------- 1 | package ro.fortsoft.pippo.demo.bdd.cucumber; 2 | 3 | import cucumber.api.java.en.Given; 4 | import cucumber.api.java.en.Then; 5 | import cucumber.api.java.en.When; 6 | import net.thucydides.core.annotations.Steps; 7 | import ro.fortsoft.pippo.demo.bdd.serenity.ContactsSteps; 8 | import ro.fortsoft.pippo.demo.bdd.serenity.LoginSteps; 9 | 10 | /** 11 | * @author sbalamaci 12 | */ 13 | public class LoginStepDefs { 14 | 15 | @Steps 16 | private LoginSteps loginSteps; 17 | private ContactsSteps contactsSteps; 18 | 19 | 20 | @When("^I login with user '(.*)' and with password '(.*)'$") 21 | public void login_user(String username, String password) { 22 | loginSteps.enterUsernameAndPassword(username, password); 23 | loginSteps.clickOnSubmit(); 24 | } 25 | 26 | @Then("^I see the 'Login' page$") 27 | public void login_page_is_shown() { 28 | loginSteps.isLoginPage(); 29 | } 30 | 31 | @Then("^I should see a failed login warning message with key '(.*)'$") 32 | public void failed_login_warn_message_is_shown(String key) { 33 | loginSteps.warnMessageWithKeyIsShown(key); 34 | } 35 | 36 | 37 | @Given("^I am logged in as admin$") 38 | public void login_admin_user() { 39 | loginSteps.openLoginPage(); 40 | loginSteps.enterUsernameAndPassword("admin", "admin"); 41 | loginSteps.clickOnSubmit(); 42 | } 43 | 44 | } 45 | -------------------------------------------------------------------------------- /src/main/java/ro/fortsoft/pippo/demo/bdd/cucumber/hook/CucumberHooks.java: -------------------------------------------------------------------------------- 1 | package ro.fortsoft.pippo.demo.bdd.cucumber.hook; 2 | 3 | import cucumber.api.java.Before; 4 | import net.thucydides.core.annotations.ManagedPages; 5 | import net.thucydides.core.pages.Pages; 6 | 7 | /** 8 | * @author sbalamaci 9 | */ 10 | public class CucumberHooks { 11 | 12 | @ManagedPages 13 | private Pages pages; 14 | 15 | @Before 16 | public void openBrowser() { 17 | // Serenity.useFirefoxProfile(customFirefoxProfile()); 18 | /* 19 | pages.getConfiguration().getEnvironmentVariables() 20 | .setProperty(ThucydidesSystemProperty.WEBDRIVER_BASE_URL.getPropertyName(), 21 | "http://tomcat:8080/pippo/"); 22 | */ 23 | pages.getDriver().manage().deleteAllCookies(); 24 | pages.getDriver().manage().window().maximize(); 25 | } 26 | 27 | 28 | 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/ro/fortsoft/pippo/demo/bdd/pages/ContactsPage.java: -------------------------------------------------------------------------------- 1 | package ro.fortsoft.pippo.demo.bdd.pages; 2 | 3 | import net.serenitybdd.core.pages.PageObject; 4 | import net.thucydides.core.annotations.DefaultUrl; 5 | import org.openqa.selenium.By; 6 | import org.openqa.selenium.WebElement; 7 | import ro.fortsoft.pippo.demo.bdd.config.Locators; 8 | 9 | /** 10 | * @author sbalamaci 11 | */ 12 | @DefaultUrl("http://localhost/contacts") 13 | public class ContactsPage extends PageObject { 14 | 15 | public void clickOnAddContactLink() { 16 | WebElement lnkAdd = find(By.id(Locators.getValue("contacts.lnkAdd.id"))); 17 | clickOn(lnkAdd); 18 | } 19 | 20 | public void fillContactInfo(String name, String phone, String address) { 21 | WebElement txtName = find(By.name(Locators.getValue("contacts.txtName.name"))); 22 | WebElement txtPhone = find(By.name(Locators.getValue("contacts.txtPhone.name"))); 23 | WebElement txtAddress = find(By.name(Locators.getValue("contacts.txtAddress.name"))); 24 | 25 | typeInto(txtName, name); 26 | typeInto(txtPhone, phone); 27 | typeInto(txtAddress, address); 28 | } 29 | 30 | public void clickSubmit() { 31 | WebElement btnSubmit = find(By.id(Locators.getValue("contacts.btnSubmit.id"))); 32 | clickOn(btnSubmit); 33 | } 34 | 35 | public String getContactsTableSource() { 36 | WebElement tblContacts = find(By.id(Locators.getValue("contacts.table.id"))); 37 | return tblContacts.getText(); 38 | } 39 | 40 | 41 | } 42 | -------------------------------------------------------------------------------- /src/main/java/ro/fortsoft/pippo/demo/bdd/pages/LoginPage.java: -------------------------------------------------------------------------------- 1 | package ro.fortsoft.pippo.demo.bdd.pages; 2 | 3 | import net.serenitybdd.core.annotations.findby.By; 4 | import net.serenitybdd.core.pages.PageObject; 5 | import net.thucydides.core.annotations.DefaultUrl; 6 | import org.openqa.selenium.WebElement; 7 | import ro.fortsoft.pippo.demo.bdd.config.Locators; 8 | 9 | /** 10 | * @author sbalamaci 11 | */ 12 | @DefaultUrl("http://localhost/login") 13 | public class LoginPage extends PageObject { 14 | 15 | public void enterUsernameAndPassword(String username, String password) { 16 | WebElement txtUsername = find(By.name(Locators.getValue("login.txtUsername.name"))); 17 | WebElement txtPassword = find(By.name(Locators.getValue("login.txtPassword.name"))); 18 | 19 | typeInto(txtUsername, username); 20 | typeInto(txtPassword, password); 21 | } 22 | 23 | public void clickOnSubmit() { 24 | WebElement btnSubmit = find(By.name(Locators.getValue("login.btnSubmit.name"))); 25 | clickOn(btnSubmit); 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/ro/fortsoft/pippo/demo/bdd/runner/PippoCrudDemoRunner.java: -------------------------------------------------------------------------------- 1 | package ro.fortsoft.pippo.demo.bdd.runner; 2 | 3 | import cucumber.api.CucumberOptions; 4 | import net.serenitybdd.cucumber.CucumberWithSerenity; 5 | import org.junit.runner.RunWith; 6 | 7 | /** 8 | * @author sbalamaci 9 | */ 10 | @RunWith(CucumberWithSerenity.class) 11 | @CucumberOptions( 12 | format = { "pretty", "html:target/pippo", "json:target/cucumber.json" }, 13 | features = {"src/main/resources/features/"}, 14 | glue = "ro.fortsoft.pippo.demo.bdd.cucumber") 15 | public class PippoCrudDemoRunner { 16 | 17 | 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/ro/fortsoft/pippo/demo/bdd/serenity/ContactsSteps.java: -------------------------------------------------------------------------------- 1 | package ro.fortsoft.pippo.demo.bdd.serenity; 2 | 3 | import net.thucydides.core.steps.ScenarioSteps; 4 | import ro.fortsoft.pippo.demo.bdd.pages.ContactsPage; 5 | 6 | import static org.assertj.core.api.Assertions.assertThat; 7 | 8 | /** 9 | * @author sbalamaci 10 | */ 11 | public class ContactsSteps extends ScenarioSteps { 12 | 13 | private ContactsPage contactsPage; 14 | 15 | public void openContactsPage() { 16 | contactsPage.open(); 17 | } 18 | 19 | public void isContactsPage() { 20 | assertThat(getDriver().getTitle()).startsWith("Contacts"); 21 | } 22 | 23 | public void clickOnAdd() { 24 | contactsPage.clickOnAddContactLink(); 25 | } 26 | 27 | public void fillContactInfo(String name, String phone, String address) { 28 | contactsPage.fillContactInfo(name, phone, address); 29 | } 30 | 31 | public void clickOnSubmit() { 32 | contactsPage.clickSubmit(); 33 | } 34 | 35 | public void isContactWithNamePresentInList(String name) { 36 | assertThat(contactsPage.getContactsTableSource()).contains(name); 37 | } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /src/main/java/ro/fortsoft/pippo/demo/bdd/serenity/LoginSteps.java: -------------------------------------------------------------------------------- 1 | package ro.fortsoft.pippo.demo.bdd.serenity; 2 | 3 | import net.thucydides.core.annotations.Step; 4 | import net.thucydides.core.steps.ScenarioSteps; 5 | import ro.fortsoft.pippo.demo.bdd.config.Messages; 6 | import ro.fortsoft.pippo.demo.bdd.pages.LoginPage; 7 | 8 | import static org.assertj.core.api.Assertions.assertThat; 9 | 10 | /** 11 | * @author sbalamaci 12 | */ 13 | public class LoginSteps extends ScenarioSteps { 14 | 15 | private LoginPage loginPage; 16 | 17 | @Step 18 | public void enterUsernameAndPassword(String username, String password) { 19 | loginPage.enterUsernameAndPassword(username, password); 20 | } 21 | 22 | @Step 23 | public void clickOnSubmit() { 24 | loginPage.clickOnSubmit(); 25 | } 26 | 27 | @Step 28 | public void openLoginPage() { 29 | loginPage.open(); 30 | } 31 | 32 | @Step 33 | public void isLoginPage() { 34 | assertThat(loginPage.getTitle()).startsWith("Login"); 35 | } 36 | 37 | @Step 38 | public void warnMessageWithKeyIsShown(String key) { 39 | assertThat(loginPage.getDriver().getPageSource()).contains(Messages.getValue(key)); 40 | } 41 | 42 | } -------------------------------------------------------------------------------- /src/main/resources/features/contacts/contacts.feature: -------------------------------------------------------------------------------- 1 | @ui 2 | Feature: Create Contacts functionality 3 | 4 | Background: 5 | Given I am logged in as admin 6 | And I open the 'Contacts' page 7 | 8 | Scenario: I am warned when trying to create a new contact with a short phone number 9 | When I click on 'Add' 10 | And I enter 'TestUser' '+40723' and 'Some address' in the Edit panel 11 | Then I should see a warning that the phone number is too short 12 | And The 'Submit' button is disabled 13 | 14 | Scenario Outline: I can add a new contact 15 | When I click on 'Add' 16 | And I enter '' '' and '
' in the Edit panel 17 | And I click 'Submit' button 18 | Then I should see '' in the list of contacts 19 | 20 | Examples: 21 | | name | address | phone | 22 | | Serban | Str. Some street nr. 2 | +4077235653 | 23 | | Decebal | Str. Burebista nr. 3 | +4077235655 | 24 | 25 | -------------------------------------------------------------------------------- /src/main/resources/features/login/login.feature: -------------------------------------------------------------------------------- 1 | @ui 2 | Feature: Login functionality 3 | Unauthorized users first need to login into the application. 4 | Users who enter right credentials should be able to login into the application. 5 | Users who enter wrong credentials are shown an error message. 6 | 7 | Background: 8 | Given I try to access the 'Contacts' page 9 | And I see the 'Login' page 10 | 11 | Scenario: Entering valid credentials I am able to login and see 'Contacts' page 12 | When I login with user 'admin' and with password 'admin' 13 | Then I should see the 'Contacts' page 14 | 15 | Scenario: Entering invalid credentials I am warned that login has failed 16 | When I login with user 'hacker' and with password '' 17 | Then I should see a failed login warning message with key 'login.warnLoginFailed' -------------------------------------------------------------------------------- /src/main/resources/locators.conf: -------------------------------------------------------------------------------- 1 | login { 2 | txtUsername.name=username 3 | txtPassword.name=password 4 | btnSubmit.name=login 5 | } 6 | 7 | contacts { 8 | txtName.name=name 9 | txtPhone.name=phone 10 | txtAddress.name=address 11 | lnkAdd.id=addContactButton 12 | 13 | btnSubmit.id=submit 14 | table.id=contacts 15 | } -------------------------------------------------------------------------------- /src/main/resources/messages.conf: -------------------------------------------------------------------------------- 1 | login { 2 | warnLoginFailed=Authentication failed 3 | } 4 | 5 | contacts { 6 | 7 | } -------------------------------------------------------------------------------- /src/main/resources/simplelogger.properties: -------------------------------------------------------------------------------- 1 | # SLF4J's SimpleLogger configuration file 2 | # Simple implementation of Logger that sends all enabled log messages, for all defined loggers, to System.err. 3 | 4 | # Default logging detail level for all instances of SimpleLogger. 5 | # Must be one of ("trace", "debug", "info", "warn", or "error"). 6 | # If not specified, defaults to "info". 7 | org.slf4j.simpleLogger.defaultLogLevel=warn 8 | 9 | # Logging detail level for a SimpleLogger instance named "xxxxx". 10 | # Must be one of ("trace", "debug", "info", "warn", or "error"). 11 | # If not specified, the default logging detail level is used. 12 | #org.slf4j.simpleLogger.log.xxxxx= 13 | org.slf4j.simpleLogger.log.ro.fortsoft.pippo.demo.bdd=info 14 | 15 | # Set to true if you want the current date and time to be included in output messages. 16 | # Default is false, and will output the number of milliseconds elapsed since startup. 17 | #org.slf4j.simpleLogger.showDateTime=false 18 | org.slf4j.simpleLogger.showDateTime=true 19 | 20 | # The date and time format to be used in the output messages. 21 | # The pattern describing the date and time format is the same that is used in java.text.SimpleDateFormat. 22 | # If the format is not specified or is invalid, the default format is used. 23 | # The default format is yyyy-MM-dd HH:mm:ss:SSS Z. 24 | #org.slf4j.simpleLogger.dateTimeFormat=yyyy-MM-dd HH:mm:ss:SSS Z 25 | org.slf4j.simpleLogger.dateTimeFormat=HH:mm:ss 26 | 27 | # Set to true if you want to output the current thread name. 28 | # Defaults to true. 29 | #org.slf4j.simpleLogger.showThreadName=true 30 | 31 | # Set to true if you want the Logger instance name to be included in output messages. 32 | # Defaults to true. 33 | #org.slf4j.simpleLogger.showLogName=true 34 | 35 | # Set to true if you want the last component of the name to be included in output messages. 36 | # Defaults to false. 37 | #org.slf4j.simpleLogger.showShortLogName=false -------------------------------------------------------------------------------- /start.sh: -------------------------------------------------------------------------------- 1 | docker-compose run uitests mvn clean verify 2 | -------------------------------------------------------------------------------- /stop.sh: -------------------------------------------------------------------------------- 1 | docker-compose stop 2 | docker-compose rm -f 3 | --------------------------------------------------------------------------------