From d08673ecb110603437096ec7a2dc38284ab30aae Mon Sep 17 00:00:00 2001
From: Daya Adianto <dayaadianto@cs.ui.ac.id>
Date: Thu, 9 Nov 2023 09:56:30 +0700
Subject: [PATCH] Prepare code template for workshop day 3

---
 README.md                                     |  4 +-
 docker-compose.yml                            | 10 +++
 src/test/java/starter/CucumberTestSuite.java  |  2 +-
 .../navigation/DuckDuckGoHomePage.java        |  8 ---
 .../java/starter/navigation/NavigateTo.java   |  7 +-
 .../navigation/SpringPetclinicHomePage.java   |  8 +++
 .../starter/search/LookForInformation.java    | 16 -----
 .../java/starter/search/SearchArticle.java    |  7 --
 src/test/java/starter/search/SearchForm.java  |  8 ---
 .../PetTypeStepDefinitions.java               | 69 +++++++++++++++++++
 .../SearchStepDefinitions.java                | 32 ---------
 .../SpecialtyStepDefinitions.java             | 61 ++++++++++++++++
 .../features/search/search_by_keyword.feature | 13 ----
 .../veterinarian/manage_pet_types.feature     | 16 +++++
 .../veterinarian/manage_specialties.feature   | 14 ++++
 src/test/resources/junit-platform.properties  |  2 +-
 16 files changed, 186 insertions(+), 91 deletions(-)
 create mode 100644 docker-compose.yml
 delete mode 100644 src/test/java/starter/navigation/DuckDuckGoHomePage.java
 create mode 100644 src/test/java/starter/navigation/SpringPetclinicHomePage.java
 delete mode 100644 src/test/java/starter/search/LookForInformation.java
 delete mode 100644 src/test/java/starter/search/SearchArticle.java
 delete mode 100644 src/test/java/starter/search/SearchForm.java
 create mode 100644 src/test/java/starter/stepdefinitions/PetTypeStepDefinitions.java
 delete mode 100644 src/test/java/starter/stepdefinitions/SearchStepDefinitions.java
 create mode 100644 src/test/java/starter/stepdefinitions/SpecialtyStepDefinitions.java
 delete mode 100644 src/test/resources/features/search/search_by_keyword.feature
 create mode 100644 src/test/resources/features/veterinarian/manage_pet_types.feature
 create mode 100644 src/test/resources/features/veterinarian/manage_specialties.feature

diff --git a/README.md b/README.md
index 3d44df9..7b3ef26 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 0000000..2aefcde
--- /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 cdac1f7..da9bb37 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 d54895b..0000000
--- 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 7292a40..ed2172b 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 0000000..de53d17
--- /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 d17fa05..0000000
--- 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 e510ffc..0000000
--- 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 404636c..0000000
--- 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 0000000..1fee08f
--- /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 cf2d19e..0000000
--- 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 0000000..cd54eb5
--- /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 e6475de..0000000
--- 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 0000000..1b87c49
--- /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 0000000..a5692d4
--- /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 c36f2bb..3105dc4 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
-- 
GitLab