diff --git a/build.gradle b/build.gradle index 4801337..d7090e1 100644 --- a/build.gradle +++ b/build.gradle @@ -1,42 +1,31 @@ +plugins { + id "java" + id "net.serenity-bdd.serenity-gradle-plugin" version "3.3.10" +} + defaultTasks 'clean', 'test', 'aggregate' repositories { - mavenLocal() - jcenter() + mavenCentral() } -buildscript { - repositories { - mavenLocal() - jcenter() - } - dependencies { - classpath("net.serenity-bdd:serenity-gradle-plugin:2.2.0") - } -} - -apply plugin: 'java' -apply plugin: 'eclipse' -apply plugin: 'idea' -apply plugin: 'net.serenity-bdd.aggregator' - -sourceCompatibility = 1.8 -targetCompatibility = 1.8 +sourceCompatibility = 16 +targetCompatibility = 16 ext { slf4jVersion = '1.7.7' - serenityCoreVersion = '2.2.0' - serenityCucumberVersion = '2.2.0' + serenityCoreVersion = '3.3.10' + serenityCucumberVersion = '3.3.10' junitVersion = '4.12' - assertJVersion = '3.8.0' + assertJVersion = '3.22.0' logbackVersion = '1.2.3' } dependencies { - compile "ch.qos.logback:logback-classic:${logbackVersion}" + implementation "ch.qos.logback:logback-classic:${logbackVersion}" - testCompile "net.serenity-bdd:serenity-core:${serenityCoreVersion}", - "net.serenity-bdd:serenity-cucumber5:${serenityCucumberVersion}", + testImplementation "net.serenity-bdd:serenity-core:${serenityCoreVersion}", + "net.serenity-bdd:serenity-cucumber:${serenityCoreVersion}", "net.serenity-bdd:serenity-screenplay:${serenityCoreVersion}", "net.serenity-bdd:serenity-screenplay-webdriver:${serenityCoreVersion}", "junit:junit:${junitVersion}", diff --git a/pom.xml b/pom.xml index 3a321e8..f02af18 100644 --- a/pom.xml +++ b/pom.xml @@ -11,9 +11,7 @@ UTF-8 - 2.4.24 - 2.4.24 - 2.4.24 + 3.3.10 UTF-8 4 @@ -24,7 +22,7 @@ ch.qos.logback logback-classic - 1.0.13 + 1.2.10 net.serenity-bdd @@ -52,8 +50,8 @@ net.serenity-bdd - serenity-cucumber6 - ${serenity.cucumber.version} + serenity-cucumber + ${serenity.version} test @@ -65,14 +63,9 @@ org.assertj assertj-core - 3.6.2 + 3.23.1 test - - org.projectlombok - lombok - 1.18.20 - @@ -122,17 +115,10 @@ net.serenity-bdd.maven.plugins serenity-maven-plugin - ${serenity.maven.version} + ${serenity.version} ${tags} - - - net.serenity-bdd - serenity-core - ${serenity.version} - - serenity-reports diff --git a/src/main/java/caffeinateme/Order.java b/src/main/java/caffeinateme/Order.java deleted file mode 100644 index b1004f6..0000000 --- a/src/main/java/caffeinateme/Order.java +++ /dev/null @@ -1,75 +0,0 @@ -package caffeinateme; - -public class Order { - private final long customerId; - private final int quantity; - private final String product; - private int etaInMinutes; - - public Order(long customerId, int quantity, String product) { - - this.customerId = customerId; - this.quantity = quantity; - this.product = product; - } - - public OrderReceipt getReceipt() { - return new OrderReceipt(customerId, quantity, product); - } - - public long getCustomerId() { - return customerId; - } - - public int getQuantity() { - return quantity; - } - - public String getProduct() { - return product; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - - Order order = (Order) o; - - if (customerId != order.customerId) return false; - if (quantity != order.quantity) return false; - return product != null ? product.equals(order.product) : order.product == null; - } - - @Override - public int hashCode() { - int result = (int) (customerId ^ (customerId >>> 32)); - result = 31 * result + quantity; - result = 31 * result + (product != null ? product.hashCode() : 0); - return result; - } - - @Override - public String toString() { - return "Order{" + - "customerId=" + customerId + - ", quantity=" + quantity + - ", product='" + product + '\'' + - '}'; - } - - public static Order matching(OrderReceipt orderReceipt) { - return new Order(orderReceipt.getCustomerId(), orderReceipt.getQuantity(), orderReceipt.getProduct()); - } - - public void updateETATo(int etaInMinutes) { - - this.etaInMinutes = etaInMinutes; - } - - public Urgency getUrgency() { - if (etaInMinutes < 5) return Urgency.Urgent; - if (etaInMinutes <= 10) return Urgency.High; - return Urgency.Normal; - } -} diff --git a/src/main/java/caffeinateme/OrderItem.java b/src/main/java/caffeinateme/OrderItem.java deleted file mode 100644 index e411e25..0000000 --- a/src/main/java/caffeinateme/OrderItem.java +++ /dev/null @@ -1,27 +0,0 @@ -package caffeinateme; - -public class OrderItem { - private final String product; - private final int quantity; - - public OrderItem(String product, int quantity) { - this.product = product; - this.quantity = quantity; - } - - public String getProduct() { - return product; - } - - public int getQuantity() { - return quantity; - } - - @Override - public String toString() { - return "OrderItem{" + - "product='" + product + '\'' + - ", quantity=" + quantity + - '}'; - } -} diff --git a/src/main/java/caffeinateme/OrderReceipt.java b/src/main/java/caffeinateme/OrderReceipt.java deleted file mode 100644 index 3afb0b8..0000000 --- a/src/main/java/caffeinateme/OrderReceipt.java +++ /dev/null @@ -1,54 +0,0 @@ -package caffeinateme; - -public class OrderReceipt { - private final long customerId; - private final int quantity; - private final String product; - - public OrderReceipt(long customerId, int quantity, String product) { - this.customerId = customerId; - this.quantity = quantity; - this.product = product; - } - - public long getCustomerId() { - return customerId; - } - - public int getQuantity() { - return quantity; - } - - public String getProduct() { - return product; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - - OrderReceipt that = (OrderReceipt) o; - - if (customerId != that.customerId) return false; - if (quantity != that.quantity) return false; - return product != null ? product.equals(that.product) : that.product == null; - } - - @Override - public int hashCode() { - int result = (int) (customerId ^ (customerId >>> 32)); - result = 31 * result + quantity; - result = 31 * result + (product != null ? product.hashCode() : 0); - return result; - } - - @Override - public String toString() { - return "OrderReceipt{" + - "customerId=" + customerId + - ", quantity=" + quantity + - ", product='" + product + '\'' + - '}'; - } -} diff --git a/src/main/java/caffeinateme/ProductPrice.java b/src/main/java/caffeinateme/ProductPrice.java deleted file mode 100644 index f4fd66f..0000000 --- a/src/main/java/caffeinateme/ProductPrice.java +++ /dev/null @@ -1,27 +0,0 @@ -package caffeinateme; - -public class ProductPrice { - private final String product; - private final double price; - - public ProductPrice(String product, double price) { - this.product = product; - this.price = price; - } - - public String getProduct() { - return product; - } - - public double getPrice() { - return price; - } - - @Override - public String toString() { - return "ProductPrice{" + - "product='" + product + '\'' + - ", price=" + price + - '}'; - } -} diff --git a/src/main/java/caffeinateme/README.md b/src/main/java/caffeinateme/README.md deleted file mode 100644 index 75de116..0000000 --- a/src/main/java/caffeinateme/README.md +++ /dev/null @@ -1,5 +0,0 @@ -### Application code - -These packages contain either application code or reusable test components such as Page Objects or Tasks. -If your source code and your application code go in the same module (common for smaller projects), page objects, -tasks and test domain classes would go in the src/test/java directory instead. \ No newline at end of file diff --git a/src/main/java/caffeinateme/Receipt.java b/src/main/java/caffeinateme/Receipt.java deleted file mode 100644 index c91f6e7..0000000 --- a/src/main/java/caffeinateme/Receipt.java +++ /dev/null @@ -1,43 +0,0 @@ -package caffeinateme; - -import java.util.ArrayList; -import java.util.List; - -public class Receipt { - private double subtotal; - private double serviceFee; - private double total; - private List lineItems; - - public Receipt(double subtotal, double serviceFee, double total, List lineItems) { - this.subtotal = subtotal; - this.serviceFee = serviceFee; - this.total = total; - this.lineItems = lineItems; - } - - public double getSubtotal() { - return subtotal; - } - - public double getServiceFee() { - return serviceFee; - } - - public double getTotal() { - return total; - } - - public List getLineItems() { - return new ArrayList<>(lineItems); - } - - @Override - public String toString() { - return "Receipt{" + - "subtotal=" + subtotal + - ", serviceFee=" + serviceFee + - ", total=" + total + - '}'; - } -} \ No newline at end of file diff --git a/src/main/java/caffeinateme/ReceiptLineItem.java b/src/main/java/caffeinateme/ReceiptLineItem.java deleted file mode 100644 index 47c775b..0000000 --- a/src/main/java/caffeinateme/ReceiptLineItem.java +++ /dev/null @@ -1,57 +0,0 @@ -package caffeinateme; - -public class ReceiptLineItem { - private final String product; - private final int quantity; - private final double price; - - public ReceiptLineItem(String product, int quanity, double price) { - this.product = product; - this.quantity = quanity; - this.price = price; - } - - public String getProduct() { - return product; - } - - public int getQuantity() { - return quantity; - } - - public double getPrice() { - return price; - } - - @Override - public String toString() { - return "ReceiptLineItem{" + - "product='" + product + '\'' + - ", quantity=" + quantity + - ", price=" + price + - '}'; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - - ReceiptLineItem that = (ReceiptLineItem) o; - - if (quantity != that.quantity) return false; - if (Double.compare(that.price, price) != 0) return false; - return product != null ? product.equals(that.product) : that.product == null; - } - - @Override - public int hashCode() { - int result; - long temp; - result = product != null ? product.hashCode() : 0; - result = 31 * result + quantity; - temp = Double.doubleToLongBits(price); - result = 31 * result + (int) (temp ^ (temp >>> 32)); - return result; - } -} diff --git a/src/main/java/caffeinateme/UnknownProductException.java b/src/main/java/caffeinateme/UnknownProductException.java deleted file mode 100644 index ca45ea6..0000000 --- a/src/main/java/caffeinateme/UnknownProductException.java +++ /dev/null @@ -1,4 +0,0 @@ -package caffeinateme; - -public class UnknownProductException extends RuntimeException{ -} diff --git a/src/main/java/caffeinateme/Urgency.java b/src/main/java/caffeinateme/Urgency.java deleted file mode 100644 index 419fee3..0000000 --- a/src/main/java/caffeinateme/Urgency.java +++ /dev/null @@ -1,5 +0,0 @@ -package caffeinateme; - -public enum Urgency { - Normal, High, Urgent -} diff --git a/src/main/java/caffeinateme/model/CoffeeShop.java b/src/main/java/caffeinateme/model/CoffeeShop.java new file mode 100644 index 0000000..fbf005c --- /dev/null +++ b/src/main/java/caffeinateme/model/CoffeeShop.java @@ -0,0 +1,35 @@ +package caffeinateme.model; + +import java.util.*; + +public class CoffeeShop { + + private Queue orders = new LinkedList<>(); + private Map registeredCustomers = new HashMap<>(); + + public void placeOrder(Order order, int distanceInMetres) { + if (distanceInMetres <= 200) { + order = order.withStatus(OrderStatus.Urgent); + } else { + order = order.withStatus(OrderStatus.Normal); + } + orders.add(order); + } + + public List getPendingOrders() { + return new ArrayList<>(orders); + } + + + public Optional getOrderFor(Customer customer) { + return orders.stream() + .filter( order -> order.getCustomer().equals(customer)) + .findFirst(); + } + + public Customer registerNewCustomer(String customerName) { + Customer newCustomer = Customer.named(customerName); + registeredCustomers.put(customerName, newCustomer); + return newCustomer; + } +} diff --git a/src/main/java/caffeinateme/model/Customer.java b/src/main/java/caffeinateme/model/Customer.java new file mode 100644 index 0000000..d89d878 --- /dev/null +++ b/src/main/java/caffeinateme/model/Customer.java @@ -0,0 +1,55 @@ +package caffeinateme.model; + +import java.util.Objects; + +public class Customer { + private String name; + private Integer distanceInMetres = 10000; + + public Customer(String name) { + this.name = name; + } + + public String getName() { + return name; + } + + public static Customer named(String name) { + return new Customer(name); + } + + public void setDistanceFromShop(Integer distanceInMetres) { + this.distanceInMetres = distanceInMetres; + } + + public CustomerOrderBuilder placesAnOrderFor(Order order) { + return new CustomerOrderBuilder(order, distanceInMetres); + } + + public static class CustomerOrderBuilder { + private Order order; + private final Integer distanceInMetres; + + public CustomerOrderBuilder(Order order, Integer distanceInMetres) { + this.order = order; + this.distanceInMetres = distanceInMetres; + } + + public void at(CoffeeShop coffeeShop) { + coffeeShop.placeOrder(order, distanceInMetres); + } + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + Customer customer = (Customer) o; + return Objects.equals(name, customer.name); + } + + @Override + public int hashCode() { + return Objects.hash(name); + } +} diff --git a/src/main/java/caffeinateme/model/Order.java b/src/main/java/caffeinateme/model/Order.java new file mode 100644 index 0000000..975e3df --- /dev/null +++ b/src/main/java/caffeinateme/model/Order.java @@ -0,0 +1,90 @@ +package caffeinateme.model; + +import java.util.Objects; + +public class Order { + private final int quantity; + private final String comment; + private final String product; + private final Customer customer; + private final OrderStatus status; + + public Order(int quantity, String product, Customer customer) { + this(quantity,product, customer, OrderStatus.Normal, ""); + } + + public Order(int quantity, String product, Customer customer, String comment) { + this(quantity,product, customer, OrderStatus.Normal, comment); + } + + public Order(int quantity, String product, Customer customer, OrderStatus status, String comment) { + this.quantity = quantity; + this.product = product; + this.customer = customer; + this.status = status; + this.comment = comment; + } + + public Order withComment(String comment) { + return new Order(quantity, product, customer, status, comment); + } + + public Order withStatus(OrderStatus status) { + return new Order(quantity,product,customer, status, comment); + } + + public OrderStatus getStatus() { + return status; + } + + public int getQuantity() { + return quantity; + } + + public String getProduct() { + return product; + } + + public String getComment() + { + return comment; + } + + public Customer getCustomer() { + return customer; + } + + public static OrderBuilder of(int quantity, String product) { + return new OrderBuilder(quantity, product); + } + + public static class OrderBuilder { + + private final int quantity; + private final String product; + + public OrderBuilder(int quantity, String product) { + this.quantity = quantity; + this.product = product; + } + + public Order forCustomer(Customer customerName) { + return new Order(quantity, product, customerName); + } + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + Order order = (Order) o; + return quantity == order.quantity && + Objects.equals(product, order.product) && + Objects.equals(customer, order.customer); + } + + @Override + public int hashCode() { + return Objects.hash(quantity, product, customer); + } +} diff --git a/src/main/java/caffeinateme/model/OrderStatus.java b/src/main/java/caffeinateme/model/OrderStatus.java new file mode 100644 index 0000000..43fc2cf --- /dev/null +++ b/src/main/java/caffeinateme/model/OrderStatus.java @@ -0,0 +1,5 @@ +package caffeinateme.model; + +public enum OrderStatus { + Normal, Urgent +} diff --git a/src/test/java/caffeinateme/OrderACoffeeStepDefinitions.java b/src/test/java/caffeinateme/OrderACoffeeStepDefinitions.java deleted file mode 100644 index f720b70..0000000 --- a/src/test/java/caffeinateme/OrderACoffeeStepDefinitions.java +++ /dev/null @@ -1,102 +0,0 @@ -package caffeinateme; - -import caffeinateme.steps.Barista; -import caffeinateme.steps.Customer; -import caffeinateme.steps.ProductCatalog; -import io.cucumber.java.DataTableType; -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.Serenity; -import net.thucydides.core.annotations.Steps; - -import java.util.ArrayList; -import java.util.List; -import java.util.Map; - -import static org.assertj.core.api.Assertions.assertThat; - -public class OrderACoffeeStepDefinitions { - - @Steps(shared = true) - Customer customer; - - @Steps - Barista barry; - - OrderReceipt orderReceipt; - - @Steps(shared = true) - private ProductCatalog productCatalog; - - @When("^(?:.*) (?:orders|has ordered) an? (.*)$") - public void sheOrdersA(String order) throws Throwable { - orderReceipt = customer.placesAnOrderFor(1, order); - - Serenity.setSessionVariable("orderReceipt").to(orderReceipt); - } - - @Then("^Barry should receive the order$") - public void barryShouldReceiveTheOrder() throws Throwable { - assertThat(barry.pendingOrders()).contains(Order.matching(orderReceipt)); - } - - @DataTableType - public OrderItem convertToOrderItem(Map orderItem) { - return new OrderItem(orderItem.get("Product"), Integer.parseInt(orderItem.get("Quantity"))); - } - - @Given("^Sarah has ordered:$") - public void sarahHasOrdered(List orders) throws Throwable { - orders.forEach( - order -> { - customer.placesAnOrderFor(order.getQuantity(), - order.getProduct()); - } - ); - } - - Receipt receipt; - - @When("^she asks for a receipt$") - public void sheAsksForAReceipt() throws Throwable { - receipt = customer.requestsAReceipt(); - } - - @DataTableType - public Receipt convertToReceipt(Map receipt) { - double subtotal = Double.parseDouble(receipt.get("Subtotal")); - double serviceFee = Double.parseDouble(receipt.get("Service Fee")); - double total = Double.parseDouble(receipt.get("Total")); - return new Receipt(subtotal, serviceFee,total, null); - } - - @Then("^she should receive a receipt totalling:$") - public void sheShouldReceiveAReceiptTotalling(List expectedReceipts) throws Throwable { - Receipt expectedReceipt = expectedReceipts.get(0); - assertThat(receipt).isEqualToIgnoringNullFields(expectedReceipt); - } - - @DataTableType - public ProductPrice convertToProductPrice(Map productPrice) { - return new ProductPrice(productPrice.get("Product"), Double.parseDouble(productPrice.get("Price"))); - } - - @And("^the following prices:$") - public void theFollowingPrices(List productPrices) throws Throwable { - productCatalog.addProductsWithPrices(productPrices); - } - - @DataTableType - public ReceiptLineItem convertToReceiptLineItem(Map receiptLineItem) { - return new ReceiptLineItem(receiptLineItem.get("Product"), - Integer.parseInt(receiptLineItem.get("Quantity")), - Double.parseDouble(receiptLineItem.get("Price"))); - } - - @And("^the receipt should contain the line items:$") - public void theReceiptShouldContainTheLineItems(List expectedLineItems) throws Throwable { - assertThat(receipt.getLineItems()).containsExactlyElementsOf(expectedLineItems); - } -} diff --git a/src/test/java/caffeinateme/PrioritiseOrdersStepDefinitions.java b/src/test/java/caffeinateme/PrioritiseOrdersStepDefinitions.java deleted file mode 100644 index d47191d..0000000 --- a/src/test/java/caffeinateme/PrioritiseOrdersStepDefinitions.java +++ /dev/null @@ -1,54 +0,0 @@ -package caffeinateme; - -import caffeinateme.steps.Barista; -import caffeinateme.steps.Customer; -import io.cucumber.java.en.Given; -import io.cucumber.java.en.Then; -import io.cucumber.java.en.When; -import net.serenitybdd.core.Serenity; -import net.thucydides.core.annotations.Steps; - -import java.util.List; -import java.util.Optional; - -import static org.assertj.core.api.Assertions.assertThat; - -public class PrioritiseOrdersStepDefinitions { - - @Steps(shared=true) - Customer sarah; - - @Steps - Barista barry; - - @Given("^Sarah is (\\d+) minutes away from the shop") - public void notifyETA(int minutesAway) { - sarah.updatesHerETATo(minutesAway); - } - - List pendingOrders; - - @When("^Barry reviews the pending orders$") - public void barryReviewsThePendingOrders() throws Throwable { - pendingOrders = barry.pendingOrders(); - } - - @Then("^Sarah's order should have an urgency of (.*)$") - public void sarahsOrderShouldHaveAnUrgencyOf(Urgency urgency) throws Throwable { - Optional sarahsOrder = sarahsOrderIn(pendingOrders); - - assertThat(sarahsOrder).isPresent(); - - assertThat(sarahsOrder.get().getUrgency()).isEqualTo(urgency); - - } - - private Optional sarahsOrderIn(List pendingOrders) { - - OrderReceipt orderReceipt = Serenity.sessionVariableCalled("orderReceipt"); - - return pendingOrders.stream() - .filter( order -> order.equals(Order.matching(orderReceipt))) - .findFirst(); - } -} diff --git a/src/test/java/caffeinateme/README.md b/src/test/java/caffeinateme/README.md deleted file mode 100644 index a5146ef..0000000 --- a/src/test/java/caffeinateme/README.md +++ /dev/null @@ -1 +0,0 @@ -## Cucumber test runner and step definition classes \ No newline at end of file diff --git a/src/test/java/caffeinateme/UserRegistrationStepDefinitions.java b/src/test/java/caffeinateme/UserRegistrationStepDefinitions.java deleted file mode 100644 index d158d12..0000000 --- a/src/test/java/caffeinateme/UserRegistrationStepDefinitions.java +++ /dev/null @@ -1,21 +0,0 @@ -package caffeinateme; - -import caffeinateme.steps.Customer; -import caffeinateme.steps.UserRegistrationClient; -import io.cucumber.java.en.Given; -import net.thucydides.core.annotations.Steps; - -public class UserRegistrationStepDefinitions { - - @Steps - UserRegistrationClient userRegistrations; - - @Steps(shared = true) - Customer customer; - - @Given("^(.*) has a Caffeinate-Me account") - public void userHasACaffeinateMeAccount(String userName) { - userRegistrations.registerUser(customer); - customer.isCalled(userName); - } -} diff --git a/src/test/java/caffeinateme/steps/Barista.java b/src/test/java/caffeinateme/steps/Barista.java deleted file mode 100644 index d6c6f76..0000000 --- a/src/test/java/caffeinateme/steps/Barista.java +++ /dev/null @@ -1,17 +0,0 @@ -package caffeinateme.steps; - -import caffeinateme.Order; -import net.serenitybdd.core.steps.ScenarioActor; -import net.thucydides.core.annotations.Steps; - -import java.util.List; - -public class Barista extends ScenarioActor { - - @Steps(shared = true) - CoffeeOrdersClient coffeeOrders; - - public List pendingOrders() { - return coffeeOrders.getOrders(); - } -} diff --git a/src/test/java/caffeinateme/steps/CoffeeOrdersClient.java b/src/test/java/caffeinateme/steps/CoffeeOrdersClient.java deleted file mode 100644 index b55201e..0000000 --- a/src/test/java/caffeinateme/steps/CoffeeOrdersClient.java +++ /dev/null @@ -1,68 +0,0 @@ -package caffeinateme.steps; - -import caffeinateme.Order; -import caffeinateme.OrderReceipt; -import caffeinateme.Receipt; -import caffeinateme.ReceiptLineItem; -import net.thucydides.core.annotations.Step; -import net.thucydides.core.annotations.Steps; - -import java.math.BigDecimal; -import java.util.ArrayList; -import java.util.List; -import java.util.stream.Collectors; - -public class CoffeeOrdersClient { - - @Steps(shared = true) - ProductCatalog productCatalog; - - List orders = new ArrayList<>(); - - @Step("Place order for customer {0} for {1} x {2}") - public OrderReceipt placeOrder(long customerId, int quantity, String product) { - Order order = new Order(customerId, quantity, product); - orders.add(order); - return order.getReceipt(); - } - - @Step - public List getOrders() { - return new ArrayList<>(orders); - } - - @Step("Notify updated ETA for customer {0} who is {1} minutes away from the shop") - public void updateCustomerEta(long customerId, int minutesAway) { - orders.stream().filter(order -> order.getCustomerId() == customerId) - .forEach(order -> order.updateETATo(minutesAway)); - } - - public Receipt getReceiptFor(long customerId) { - double subTotal = orders.stream() - .filter(order -> order.getCustomerId() == customerId) - .mapToDouble(this::subtotalFor) - .sum(); - - List lineItems = orders.stream() - .filter(order -> order.getCustomerId() == customerId) - .map(order -> new ReceiptLineItem(order.getProduct(), order.getQuantity(), subtotalFor(order))) - .collect(Collectors.toList()); - - - double serviceFee = subTotal * 5 / 100; - double total = subTotal + serviceFee; - return new Receipt(roundedTo2DecimalPlaces(subTotal), - roundedTo2DecimalPlaces(serviceFee), - roundedTo2DecimalPlaces(total), - lineItems); - } - - private double roundedTo2DecimalPlaces(double value) { - return new BigDecimal(Double.toString(value)).setScale(2, BigDecimal.ROUND_HALF_UP) - .doubleValue(); - } - - private double subtotalFor(Order order) { - return productCatalog.priceOf(order.getProduct()) * order.getQuantity(); - } -} diff --git a/src/test/java/caffeinateme/steps/Customer.java b/src/test/java/caffeinateme/steps/Customer.java deleted file mode 100644 index eb09be1..0000000 --- a/src/test/java/caffeinateme/steps/Customer.java +++ /dev/null @@ -1,38 +0,0 @@ -package caffeinateme.steps; - -import caffeinateme.OrderReceipt; -import caffeinateme.Receipt; -import net.serenitybdd.core.steps.ScenarioActor; -import net.thucydides.core.annotations.Step; -import net.thucydides.core.annotations.Steps; - -public class Customer extends ScenarioActor { - - private long customerId; - - @Steps(shared = true) - CoffeeOrdersClient coffeeOrders; - - public void hasACustomerIdOf(long customerId) { - this.customerId = customerId; - } - - public long getCustomerId() { - return customerId; - } - - @Step("#actor places an order for {0} {1}") - public OrderReceipt placesAnOrderFor(int quantity, String product) { - return coffeeOrders.placeOrder(customerId, quantity, product); - } - - @Step("#actor updates her ETA to {0}") - public void updatesHerETATo(int minutesAway) { - coffeeOrders.updateCustomerEta(customerId, minutesAway); - } - - @Step("#actor requests a receipt") - public Receipt requestsAReceipt() { - return coffeeOrders.getReceiptFor(customerId); - } -} diff --git a/src/test/java/caffeinateme/steps/OrderCoffeeSteps.java b/src/test/java/caffeinateme/steps/OrderCoffeeSteps.java new file mode 100644 index 0000000..ab90e5a --- /dev/null +++ b/src/test/java/caffeinateme/steps/OrderCoffeeSteps.java @@ -0,0 +1,74 @@ +package caffeinateme.steps; + +import caffeinateme.model.CoffeeShop; +import caffeinateme.model.Customer; +import caffeinateme.model.Order; +import caffeinateme.model.OrderStatus; +import io.cucumber.java.ParameterType; +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 java.util.Collection; +import java.util.List; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.hasItem; + +public class OrderCoffeeSteps { + + Customer cathy = Customer.named("Cathy"); + Customer customer; + CoffeeShop coffeeShop = new CoffeeShop(); + Order order; + + + @Given("{} is a CaffeinateMe customer") + public void a_caffeinate_me_customer_named(String customerName){ + customer = coffeeShop.registerNewCustomer(customerName); + } + + @And("Cathy is {int} metres from the coffee shop") + public void cathy_is_metres_from_the_coffee_shop(Integer distanceInMetres) { + cathy.setDistanceFromShop(distanceInMetres); + } + + @ParameterType("\"(.*)\"") + public Order order(String orderedProduct) { + return Order.of(1, orderedProduct).forCustomer(customer); + } + @When("Cathy orders a {order}") + public void cathy_orders_a(Order order) { + this.order = order; + cathy.placesAnOrderFor(order).at(coffeeShop); + } + @Then("Barry should receive the order") + public void barry_should_receive_the_order() { + assertThat(coffeeShop.getPendingOrders(), hasItem(order)); + } + + @Then("^Barry should know that the order is (.*)") + public void barry_should_know_that_the_order_is(OrderStatus expectedStatus) { + Order cathysOrder = coffeeShop.getOrderFor(cathy) + .orElseThrow(() -> new AssertionError("No order found!")); + assertThat(cathysOrder.getStatus(), equalTo(expectedStatus)); + } + + + + @When("Cathy orders a {order} with a comment {string}") + public void cathy_orders_with_comment(Order order, String comment) { + this.order = order.withComment(comment); + customer.placesAnOrderFor(order).at(coffeeShop); + } + + @Then("the order should have the comment {string}") + public void order_should_have_comment(String comment) { + Order order = coffeeShop.getOrderFor(customer).get(); + assertThat(order.getComment(),equalTo(comment)); + + +} +} diff --git a/src/test/java/caffeinateme/steps/ProductCatalog.java b/src/test/java/caffeinateme/steps/ProductCatalog.java deleted file mode 100644 index 258595c..0000000 --- a/src/test/java/caffeinateme/steps/ProductCatalog.java +++ /dev/null @@ -1,26 +0,0 @@ -package caffeinateme.steps; - -import caffeinateme.ProductPrice; -import caffeinateme.UnknownProductException; -import net.thucydides.core.annotations.Step; - -import java.util.ArrayList; -import java.util.List; - -public class ProductCatalog { - - List catalog = new ArrayList<>(); - - @Step - public void addProductsWithPrices(List productPrices) { - catalog.addAll(productPrices); - } - - public double priceOf(String productName) { - return catalog.stream() - .filter(product -> product.getProduct().equals(productName)) - .findFirst() - .orElseThrow(UnknownProductException::new) - .getPrice(); - } -} diff --git a/src/test/java/caffeinateme/steps/UserRegistrationClient.java b/src/test/java/caffeinateme/steps/UserRegistrationClient.java deleted file mode 100644 index 1b905aa..0000000 --- a/src/test/java/caffeinateme/steps/UserRegistrationClient.java +++ /dev/null @@ -1,9 +0,0 @@ -package caffeinateme.steps; - -public class UserRegistrationClient { - - long customerIdCounter = 1; - public void registerUser(Customer newCustomer) { - newCustomer.hasACustomerIdOf(customerIdCounter++); - } -} diff --git a/src/test/resources/assets/caffeinateme.png b/src/test/resources/assets/caffeinateme.png deleted file mode 100644 index b3da120..0000000 Binary files a/src/test/resources/assets/caffeinateme.png and /dev/null differ diff --git a/src/test/resources/features/just_in_time_coffees/prioritise_orders.feature b/src/test/resources/features/just_in_time_coffees/prioritise_orders.feature deleted file mode 100644 index c109ff4..0000000 --- a/src/test/resources/features/just_in_time_coffees/prioritise_orders.feature +++ /dev/null @@ -1,20 +0,0 @@ -@Backend:PrioritiseOrders -Feature: Prioritise orders - - Orders are prioritised by nearby customers. - This lets the barista know when he or she needs to start preparing the next coffee. - - Background: - Given Sarah has a Caffeinate-Me account - - Scenario Outline: Order urgency - Given Sarah has ordered an espresso - And Sarah is minutes away from the shop - When Barry reviews the pending orders - Then Sarah's order should have an urgency of - - Examples: - | Rule | ETA | Urgency | - | More than 10 minutes away | 12 | Normal | - | Between 5 and 10 minutes | 7 | High | - | Less than 5 minutes | 3 | Urgent | diff --git a/src/test/resources/features/optimised_stocks/view_order_history_stats.feature b/src/test/resources/features/optimised_stocks/view_order_history_stats.feature deleted file mode 100644 index 46e4381..0000000 --- a/src/test/resources/features/optimised_stocks/view_order_history_stats.feature +++ /dev/null @@ -1,10 +0,0 @@ -@Backend:OrderHistory -Feature: View order history stats - - Barry needs to see what sorts of drinks his customers order, so that he can plan his stocks better. - - @Pending - Scenario: Barry can see the number of each type of drink ordered - - @Pending - Scenario: Barry can see the amount of ingredients consumed each month diff --git a/src/test/resources/features/order_coffee_remotely/ask_for_a_receipt.feature b/src/test/resources/features/order_coffee_remotely/ask_for_a_receipt.feature deleted file mode 100644 index 992c774..0000000 --- a/src/test/resources/features/order_coffee_remotely/ask_for_a_receipt.feature +++ /dev/null @@ -1,24 +0,0 @@ -@Frontend:AskForReceipt -Feature: Ask for a receipt - - Background: - Given Sarah has a Caffeinate-Me account - And the following prices: - | Product | Price | - | regular cappuccino | 1.90 | - | large cappuccino | 2.25 | - | muffin | 1.25 | - - Scenario: Order several items - Given Sarah has ordered: - | Quantity | Product | - | 1 | large cappuccino | - | 2 | muffin | - When she asks for a receipt - Then she should receive a receipt totalling: - | Subtotal | Service Fee | Total | - | 4.75 | 0.24 | 4.99 | - And the receipt should contain the line items: - | Product | Quantity | Price | - | large cappuccino | 1 | 2.25 | - | muffin | 2 | 2.50 | diff --git a/src/test/resources/features/order_coffee_remotely/complete_an_order.feature b/src/test/resources/features/order_coffee_remotely/complete_an_order.feature deleted file mode 100644 index 7eaf679..0000000 --- a/src/test/resources/features/order_coffee_remotely/complete_an_order.feature +++ /dev/null @@ -1,13 +0,0 @@ -@Frontend:CompletingOrder -Feature: Completing orders - - Background: - Given Barry is a barista - And Sarah is a registered customer - - Scenario: Barry delivers a completed order - Given Sarah has ordered an espresso - When Barry marks the order as complete - Then the order should no longer appear in the pending orders - And Sarah should see the order in her order history - diff --git a/src/test/resources/features/order_coffee_remotely/overview.md b/src/test/resources/features/order_coffee_remotely/overview.md deleted file mode 100644 index 1654c33..0000000 --- a/src/test/resources/features/order_coffee_remotely/overview.md +++ /dev/null @@ -1,3 +0,0 @@ -We think that allowing our regular customers to order coffees ahead of time and avoid waiting in a queue will increase sales to regular customers - -We will consider the application a success if we increase our coffee sales to regular customers by 5% diff --git a/src/test/resources/features/order_coffee_remotely/place_an_order.feature b/src/test/resources/features/order_coffee_remotely/place_an_order.feature deleted file mode 100644 index 36611b7..0000000 --- a/src/test/resources/features/order_coffee_remotely/place_an_order.feature +++ /dev/null @@ -1,16 +0,0 @@ -@Frontend:PlaceAnOrder -@Backend:PlaceAnOrder -Feature: Place an order - - In order to save time when I pick up my morning coffee - As a coffee lover - I want to be able to order my coffee in advance - - Caffeinate-Me customers like their coffee hot - - Scenario: Buyer orders a coffee - Given Cathy has a Caffeinate-Me account - When she orders a large cappuccino - Then Barry should receive the order - - diff --git a/src/test/resources/features/order_coffee_remotely/view_pending_orders.feature b/src/test/resources/features/order_coffee_remotely/view_pending_orders.feature deleted file mode 100644 index f30f0a2..0000000 --- a/src/test/resources/features/order_coffee_remotely/view_pending_orders.feature +++ /dev/null @@ -1,22 +0,0 @@ -@Backend:PendingOrders -Feature: View pending orders - - Barry needs to see the orders that his customers have placed. - - Background: - Given Barry is a barista - And Sarah is a registered customer - And Joe is a registered customer - - Scenario: Barry sees all the orders - Given Sarah has ordered an espresso - Given Joe has ordered a cappuccino - When Barry reviews the pending orders - Then Barry should see the orders: - | customer | order | - | Sarah | espresso | - | Joe | cappuccino | - - - @Pending - Scenario: Barry sees the high priority orders first diff --git a/src/test/resources/features/orders/order_a_coffee.feature b/src/test/resources/features/orders/order_a_coffee.feature new file mode 100644 index 0000000..f10c620 --- /dev/null +++ b/src/test/resources/features/orders/order_a_coffee.feature @@ -0,0 +1,34 @@ +Feature: Order a coffee + + In order to save time when I pick up my morning coffee + As a coffee love + I want to be able to order my coffee in advance + + Background: + Given Cathy is a CaffeinateMe customer + +Rule: Orders placed close to the store should be considered as Urgent + Example: Buyer orders a coffee when they are close to the coffee shop + Given Cathy is 100 metres from the coffee shop + When Cathy orders a "large cappuccino" + Then Barry should receive the order + And Barry should know that the order is Urgent + + + Example: Buyer orders a coffee when they are 50 metres away from the shop + Given Cathy is 50 metres from the coffee shop + When Cathy orders a "large cappuccino" + Then Barry should receive the order + And Barry should know that the order is Urgent + + Scenario: Buyer orders a coffee when they are far to the shop + Given Cathy is 300 metres from the coffee shop + When Cathy orders a "large Cappuccino" + Then Barry should receive the order + And Barry should know that the order is Normal + + Rule: Buyers can specify their preferences when they order + Example: Buyers can add a comment with their order + Given Cathy orders a "large cappuccino" with a comment "Double sugar" + Then Barry should receive the order + And the order should have the comment "Double sugar" \ No newline at end of file diff --git a/src/test/resources/features/overview.md b/src/test/resources/features/overview.md deleted file mode 100644 index f4c462a..0000000 --- a/src/test/resources/features/overview.md +++ /dev/null @@ -1,3 +0,0 @@ -Caffeinate-Me will _revolutionise_ the lives of coffee lovers everywhere. - -![Caffeinate-Me](assets/caffeinateme.png) \ No newline at end of file diff --git a/src/test/resources/logback-test.xml b/src/test/resources/logback-test.xml index 1f14f95..1e4475b 100644 --- a/src/test/resources/logback-test.xml +++ b/src/test/resources/logback-test.xml @@ -1,18 +1,18 @@ - - - - - %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n - - - - - - - - - - - - + + + + + %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n + + + + + + + + + + + + \ No newline at end of file