diff --git a/README.md b/README.md index 3d44df97bbd5ddf6faaa6487782d6abd43245470..7b3ef26669073c9a0b60e381b23c8cc178c5bb52 100644 --- a/README.md +++ b/README.md @@ -30,8 +30,8 @@ src + java Test runners and supporting code + resources + features Feature files - + search Feature file subdirectories - search_by_keyword.feature + + veterinarian Feature file subdirectories + manage_specialties.feature ``` Serenity 2.2.13 introduced integration with [WebDriverManager](https://bonigarcia.dev/webdrivermanager/) to download webdriver binaries. diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000000000000000000000000000000000000..2aefcdec70a96556b8cba4ce0874c593b608ad02 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,10 @@ +--- +services: + api: + image: docker.io/springcommunity/spring-petclinic-rest:3.0.2 + ports: + - "127.0.0.1:9966:9966" + app: + image: docker.io/addianto/spring-petclinic-angular:latest + ports: + - "127.0.0.1:80:8080" diff --git a/src/test/java/starter/CucumberTestSuite.java b/src/test/java/starter/CucumberTestSuite.java index cdac1f7e5e03839df695b1e74c7ed9205b0058f2..da9bb37ab9ef690f2fe5ee6c962487babf322e50 100644 --- a/src/test/java/starter/CucumberTestSuite.java +++ b/src/test/java/starter/CucumberTestSuite.java @@ -12,4 +12,4 @@ import static io.cucumber.junit.platform.engine.Constants.PLUGIN_PROPERTY_NAME; @SelectClasspathResource("/features") @ConfigurationParameter(key = PLUGIN_PROPERTY_NAME, value = "io.cucumber.core.plugin.SerenityReporterParallel,pretty,timeline:build/test-results/timeline") public class CucumberTestSuite { -} +} \ No newline at end of file diff --git a/src/test/java/starter/navigation/DuckDuckGoHomePage.java b/src/test/java/starter/navigation/DuckDuckGoHomePage.java deleted file mode 100644 index d54895b9348c2ae3e78c7292932ee4d6a2a5b63e..0000000000000000000000000000000000000000 --- a/src/test/java/starter/navigation/DuckDuckGoHomePage.java +++ /dev/null @@ -1,8 +0,0 @@ -package starter.navigation; - -import net.serenitybdd.annotations.DefaultUrl; -import net.thucydides.core.pages.PageObject; - -@DefaultUrl("https://duckduckgo.com") -public class DuckDuckGoHomePage extends PageObject { -} diff --git a/src/test/java/starter/navigation/NavigateTo.java b/src/test/java/starter/navigation/NavigateTo.java index 7292a40e7acaacfbd25b698b740143c0247fbb3c..ed2172bb8875d4064ffe850b98a4283cd5cae2a6 100644 --- a/src/test/java/starter/navigation/NavigateTo.java +++ b/src/test/java/starter/navigation/NavigateTo.java @@ -5,8 +5,9 @@ import net.serenitybdd.screenplay.Task; import net.serenitybdd.screenplay.actions.Open; public class NavigateTo { - public static Performable theSearchHomePage() { - return Task.where("{0} opens the DuckDuckGo home page", - Open.browserOn().the(DuckDuckGoHomePage.class)); + + public static Performable theSpringPetclinicHomePage() { + return Task.where("{0} opens the Spring Petclinic home page", + Open.browserOn().the(SpringPetclinicHomePage.class)); } } diff --git a/src/test/java/starter/navigation/SpringPetclinicHomePage.java b/src/test/java/starter/navigation/SpringPetclinicHomePage.java new file mode 100644 index 0000000000000000000000000000000000000000..de53d1793582714bf6e510851c6a1a12517a238e --- /dev/null +++ b/src/test/java/starter/navigation/SpringPetclinicHomePage.java @@ -0,0 +1,8 @@ +package starter.navigation; + +import net.serenitybdd.annotations.DefaultUrl; +import net.serenitybdd.core.pages.PageObject; + +@DefaultUrl("http://127.0.0.1") +public class SpringPetclinicHomePage extends PageObject { +} diff --git a/src/test/java/starter/search/LookForInformation.java b/src/test/java/starter/search/LookForInformation.java deleted file mode 100644 index d17fa05983af41c0f976b3b78cf89111269c7ebc..0000000000000000000000000000000000000000 --- a/src/test/java/starter/search/LookForInformation.java +++ /dev/null @@ -1,16 +0,0 @@ -package starter.search; - -import net.serenitybdd.screenplay.Performable; -import net.serenitybdd.screenplay.Task; -import net.serenitybdd.screenplay.actions.Enter; -import org.openqa.selenium.Keys; - -public class LookForInformation { - public static Performable about(String searchTerm) { - return Task.where("{0} searches for '" + searchTerm + "'", - Enter.theValue(searchTerm) - .into(SearchForm.SEARCH_FIELD) - .thenHit(Keys.ENTER) - ); - } -} diff --git a/src/test/java/starter/search/SearchArticle.java b/src/test/java/starter/search/SearchArticle.java deleted file mode 100644 index e510ffc01edb78978be7fb83d9caddde65f36716..0000000000000000000000000000000000000000 --- a/src/test/java/starter/search/SearchArticle.java +++ /dev/null @@ -1,7 +0,0 @@ -package starter.search; - -import net.serenitybdd.screenplay.targets.Target; - -public class SearchArticle { - public static final Target BODY = Target.the("article identifier").locatedBy("//article"); -} diff --git a/src/test/java/starter/search/SearchForm.java b/src/test/java/starter/search/SearchForm.java deleted file mode 100644 index 404636cd7c55eeff1fdad5c49810d34bfb095715..0000000000000000000000000000000000000000 --- a/src/test/java/starter/search/SearchForm.java +++ /dev/null @@ -1,8 +0,0 @@ -package starter.search; - -import net.serenitybdd.screenplay.targets.Target; - -class SearchForm { - static Target SEARCH_FIELD = Target.the("search field").locatedBy("#searchbox_input"); - -} diff --git a/src/test/java/starter/stepdefinitions/PetTypeStepDefinitions.java b/src/test/java/starter/stepdefinitions/PetTypeStepDefinitions.java new file mode 100644 index 0000000000000000000000000000000000000000..1fee08f823e9872bcb26898e9f15709fcc1baad5 --- /dev/null +++ b/src/test/java/starter/stepdefinitions/PetTypeStepDefinitions.java @@ -0,0 +1,69 @@ +package starter.stepdefinitions; + +import io.cucumber.datatable.DataTable; +import io.cucumber.java.en.And; +import io.cucumber.java.en.Given; +import io.cucumber.java.en.Then; +import io.cucumber.java.en.When; +import net.serenitybdd.core.pages.WebElementFacade; +import net.serenitybdd.screenplay.Actor; +import net.serenitybdd.screenplay.actions.Click; +import net.serenitybdd.screenplay.actions.Enter; +import net.serenitybdd.screenplay.actions.HoverOverBy; +import net.serenitybdd.screenplay.actions.Open; +import net.serenitybdd.screenplay.ensure.Ensure; +import net.serenitybdd.screenplay.ui.Button; +import net.serenitybdd.screenplay.ui.InputField; +import net.serenitybdd.screenplay.ui.Link; +import org.openqa.selenium.Keys; +import starter.navigation.SpringPetclinicHomePage; + +import java.util.List; + +public class PetTypeStepDefinitions { + @Given("a system operator named {actor} is looking at the pet types page") + public void lookingAtPetTypesPage(Actor actor) { + actor.wasAbleTo( + Open.browserOn() + .the(SpringPetclinicHomePage.class), + // TODO: Refactor the two actions below into a new Performable class + HoverOverBy.over(Link.withText("Pet Types")), + Click.on(Link.withText("Pet Types")) + ); + } + + @And("{actor} found the following pet types exist:") + public void verifyingExistingPetTypes(Actor actor, DataTable table) { + List<String> existingPetTypes = InputField + .withNameOrId("pettype_name") + .resolveAllFor(actor) + .map(WebElementFacade::getValue); + + actor.wasAbleTo( + Ensure.that(existingPetTypes) + .containsElementsFrom(table.asList()) + ); + } + + @When("{actor} adds a new pet type named {string}") + public void addsNewPetType(Actor actor, String name) { + actor.attemptsTo( + // TODO: Refactor the click action below into a new Performable class + Click.on(Button.withText("Add")), + Enter.theValue(name) + .into(InputField.withNameOrId("name")) + .thenHit(Keys.ENTER) + ); + } + + @Then("{actor} should see the pet type {string} on the list of pet types") + public void shouldSeeThePetType(Actor actor, String name) { + actor.attemptsTo( + Ensure.thatAmongst(InputField.withNameOrId("pettype_name")) + .anyMatch(name + " should be on the list", + (field) -> field.getValue() + .equals(name) + ) + ); + } +} diff --git a/src/test/java/starter/stepdefinitions/SearchStepDefinitions.java b/src/test/java/starter/stepdefinitions/SearchStepDefinitions.java deleted file mode 100644 index cf2d19ee130809006dc34d0dc1a9d8fd10268331..0000000000000000000000000000000000000000 --- a/src/test/java/starter/stepdefinitions/SearchStepDefinitions.java +++ /dev/null @@ -1,32 +0,0 @@ -package starter.stepdefinitions; - -import io.cucumber.java.en.Given; -import io.cucumber.java.en.Then; -import io.cucumber.java.en.When; -import net.serenitybdd.screenplay.Actor; -import net.serenitybdd.screenplay.ensure.Ensure; -import net.serenitybdd.screenplay.questions.page.TheWebPage; -import starter.navigation.NavigateTo; -import starter.search.LookForInformation; - -public class SearchStepDefinitions { - - @Given("{actor} is researching things on the internet") - public void researchingThings(Actor actor) { - actor.wasAbleTo(NavigateTo.theSearchHomePage()); - } - - @When("{actor} looks up {string}") - public void searchesFor(Actor actor, String term) { - actor.attemptsTo( - LookForInformation.about(term) - ); - } - - @Then("{actor} should see information about {string}") - public void should_see_information_about(Actor actor, String term) { - actor.attemptsTo( - Ensure.that(TheWebPage.title()).containsIgnoringCase(term) - ); - } -} diff --git a/src/test/java/starter/stepdefinitions/SpecialtyStepDefinitions.java b/src/test/java/starter/stepdefinitions/SpecialtyStepDefinitions.java new file mode 100644 index 0000000000000000000000000000000000000000..cd54eb5ac01d9af55180156b9585fac931cf212d --- /dev/null +++ b/src/test/java/starter/stepdefinitions/SpecialtyStepDefinitions.java @@ -0,0 +1,61 @@ +package starter.stepdefinitions; + +import io.cucumber.java.en.Given; +import io.cucumber.java.en.Then; +import io.cucumber.java.en.When; +import net.serenitybdd.screenplay.Actor; +import net.serenitybdd.screenplay.actions.*; +import net.serenitybdd.screenplay.ensure.Ensure; +import net.serenitybdd.screenplay.ui.Button; +import net.serenitybdd.screenplay.ui.InputField; +import net.serenitybdd.screenplay.ui.Link; +import org.openqa.selenium.By; +import org.openqa.selenium.Keys; +import starter.navigation.SpringPetclinicHomePage; + +public class SpecialtyStepDefinitions { + + @Given("a system operator named {actor} is looking at the specialties page") + public void lookingAtSpecialtiesPage(Actor actor) { + actor.wasAbleTo( + Open.browserOn() + .the(SpringPetclinicHomePage.class), + // TODO: Refactor the two actions below into a new Performable class + HoverOverBy.over(Link.withText("Specialties")), + Click.on(Link.withText("Specialties")) + ); + } + + @When("{actor} adds a new specialty called {string}") + public void addsNewSpecialty(Actor actor, String name) { + actor.attemptsTo( + // TODO: Refactor the Click action into a new Performable class + Click.on(Button.withText("Add")), + Enter.theValue(name) + .into(InputField.withNameOrId("name")) + .thenHit(Keys.ENTER) + ); + } + + @When("{actor} edits the first specialty to {string}") + public void editsFirstSpecialty(Actor actor, String name) { + actor.attemptsTo( + Click.on(Button.located(By.xpath("//table[@id='specialties']/tbody/tr[1]/td[2]/button[1]"))), + Clear.field(InputField.withNameOrId("name")), + Enter.theValue(name) + .into(InputField.withNameOrId("name")), + Click.on(Button.withText("Update")) + ); + } + + @Then("{actor} should see the specialty {string} on the list of specialties") + public void shouldSeeTheSpecialty(Actor actor, String name) { + actor.attemptsTo( + Ensure.thatAmongst(InputField.withNameOrId("spec_name")) + .anyMatch(name + " should be on the list", + (field) -> field.getValue() + .equals(name) + ) + ); + } +} diff --git a/src/test/resources/features/search/search_by_keyword.feature b/src/test/resources/features/search/search_by_keyword.feature deleted file mode 100644 index e6475dee301ffa5542f03fd4a8a81027e51ecdfb..0000000000000000000000000000000000000000 --- a/src/test/resources/features/search/search_by_keyword.feature +++ /dev/null @@ -1,13 +0,0 @@ -Feature: Search by keyword - - @green - Scenario: Searching for 'green' - Given Sergey is researching things on the internet - When he looks up "green" - Then he should see information about "green" - - @red - Scenario: Searching for 'red' - Given Sergey is researching things on the internet - When he looks up "red" - Then he should see information about "red" diff --git a/src/test/resources/features/veterinarian/manage_pet_types.feature b/src/test/resources/features/veterinarian/manage_pet_types.feature new file mode 100644 index 0000000000000000000000000000000000000000..1b87c497b5c7d5ceb760b44e779646a8fecb0ede --- /dev/null +++ b/src/test/resources/features/veterinarian/manage_pet_types.feature @@ -0,0 +1,16 @@ +Feature: Manage pet types + The veterinarian wants to be able to add, edit, and delete pet types. + + Scenario: Add new pet type + Given a system operator named "Jane" is looking at the pet types page + And she found the following pet types exist: + | cat | + | dog | + | lizard | + | snake | + | bird | + | hamster | + When she adds a new pet type named "turtle" + Then she should see the pet type "turtle" on the list of pet types + + # TODO: Add a scenario to "Edit the last pet type" \ No newline at end of file diff --git a/src/test/resources/features/veterinarian/manage_specialties.feature b/src/test/resources/features/veterinarian/manage_specialties.feature new file mode 100644 index 0000000000000000000000000000000000000000..a5692d412025689114309bc0b705607e1909d21e --- /dev/null +++ b/src/test/resources/features/veterinarian/manage_specialties.feature @@ -0,0 +1,14 @@ +Feature: Manage specialties + The veterinarian wants to be able to add, edit, and delete specialties. + + Scenario: Add new specialty + Given a system operator named "John" is looking at the specialties page + When he adds a new specialty called "cardiology" + Then he should see the specialty "cardiology" on the list of specialties + + Scenario: Edit the first specialty + Given a system operator named "John" is looking at the specialties page + When he edits the first specialty to "snake oil" + Then he should see the specialty "snake oil" on the list of specialties + + # TODO: Add a scenario to "Add new specialty and remove it immediately" \ No newline at end of file diff --git a/src/test/resources/junit-platform.properties b/src/test/resources/junit-platform.properties index c36f2bb1ffd064820140c8540a9966ff96ac9f62..3105dc4b5e70c8ce5c3b9d0f46dc9f9c8311ae95 100644 --- a/src/test/resources/junit-platform.properties +++ b/src/test/resources/junit-platform.properties @@ -1,4 +1,4 @@ -cucumber.execution.parallel.enabled=true +cucumber.execution.parallel.enabled=false cucumber.execution.parallel.config.strategy=fixed cucumber.execution.parallel.config.fixed.parallelism=4 cucumber.execution.parallel.config.fixed.max-pool-size=4