diff --git a/pom.xml b/pom.xml
index e20eafc9..ee04d26b 100644
--- a/pom.xml
+++ b/pom.xml
@@ -151,7 +151,7 @@
commons-io
commons-io
- 1.3.1
+ 2.4
commons-dbcp
@@ -191,6 +191,12 @@
2.3
test
+
+ org.seleniumhq.selenium
+ selenium-java
+ 3.5.3
+ test
+
diff --git a/src/main/java/se/citerus/dddsample/interfaces/booking/web/CargoAdminController.java b/src/main/java/se/citerus/dddsample/interfaces/booking/web/CargoAdminController.java
index 853ababa..b8fcccc7 100644
--- a/src/main/java/se/citerus/dddsample/interfaces/booking/web/CargoAdminController.java
+++ b/src/main/java/se/citerus/dddsample/interfaces/booking/web/CargoAdminController.java
@@ -61,7 +61,7 @@ public String registration(HttpServletRequest request, HttpServletResponse respo
@RequestMapping(value = "/register", method = RequestMethod.POST)
public void register(HttpServletRequest request, HttpServletResponse response,
RegistrationCommand command) throws Exception {
- Date arrivalDeadline = new SimpleDateFormat("M/dd/yyyy").parse(command.getArrivalDeadline());
+ Date arrivalDeadline = new SimpleDateFormat("dd/MM/yyyy").parse(command.getArrivalDeadline());
String trackingId = bookingServiceFacade.bookNewCargo(
command.getOriginUnlocode(), command.getDestinationUnlocode(), arrivalDeadline
);
diff --git a/src/test/java/se/citerus/dddsample/acceptance/AbstractAcceptanceTest.java b/src/test/java/se/citerus/dddsample/acceptance/AbstractAcceptanceTest.java
new file mode 100644
index 00000000..dadb6395
--- /dev/null
+++ b/src/test/java/se/citerus/dddsample/acceptance/AbstractAcceptanceTest.java
@@ -0,0 +1,32 @@
+package se.citerus.dddsample.acceptance;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.runner.RunWith;
+import org.openqa.selenium.WebDriver;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
+import org.springframework.test.web.servlet.htmlunit.webdriver.MockMvcHtmlUnitDriverBuilder;
+import org.springframework.web.context.WebApplicationContext;
+import se.citerus.dddsample.Application;
+
+@RunWith(SpringJUnit4ClassRunner.class)
+@SpringBootTest(classes = Application.class)
+public abstract class AbstractAcceptanceTest {
+
+ @Autowired
+ private WebApplicationContext context;
+
+ protected WebDriver driver;
+
+ @Before
+ public void setup() {
+ driver = MockMvcHtmlUnitDriverBuilder.webAppContextSetup(context).contextPath("/dddsample").build();
+ }
+
+ @After
+ public void tearDown() {
+ driver.quit();
+ }
+}
diff --git a/src/test/java/se/citerus/dddsample/acceptance/AdminAcceptanceTest.java b/src/test/java/se/citerus/dddsample/acceptance/AdminAcceptanceTest.java
new file mode 100644
index 00000000..f1f30463
--- /dev/null
+++ b/src/test/java/se/citerus/dddsample/acceptance/AdminAcceptanceTest.java
@@ -0,0 +1,50 @@
+package se.citerus.dddsample.acceptance;
+
+import org.junit.Test;
+import se.citerus.dddsample.acceptance.pages.AdminPage;
+import se.citerus.dddsample.acceptance.pages.CargoBookingPage;
+import se.citerus.dddsample.acceptance.pages.CargoDestinationPage;
+import se.citerus.dddsample.acceptance.pages.CargoDetailsPage;
+
+import java.time.LocalDate;
+import java.time.temporal.ChronoUnit;
+
+import static junit.framework.TestCase.assertTrue;
+
+public class AdminAcceptanceTest extends AbstractAcceptanceTest {
+
+ @Test
+ public void adminSiteCargoListContainsCannedCargo() {
+ AdminPage page = new AdminPage(driver);
+ page.listAllCargo();
+
+ assertTrue("Cargo list doesn't contain ABC123", page.listedCargoContains("ABC123"));
+ assertTrue("Cargo list doesn't contain JKL567", page.listedCargoContains("JKL567"));
+ }
+
+ @Test
+ public void adminSiteCanBookNewCargo() {
+ AdminPage adminPage = new AdminPage(driver);
+
+ CargoBookingPage cargoBookingPage = adminPage.bookNewCargo();
+ cargoBookingPage.selectOrigin("NLRTM");
+ cargoBookingPage.selectDestination("USDAL");
+ LocalDate arrivalDeadline = LocalDate.now().plus(3, ChronoUnit.WEEKS);
+ cargoBookingPage.selectArrivalDeadline(arrivalDeadline);
+ CargoDetailsPage cargoDetailsPage = cargoBookingPage.book();
+
+ String newCargoTrackingId = cargoDetailsPage.getTrackingId();
+ adminPage = cargoDetailsPage.listAllCargo();
+ assertTrue("Cargo list doesn't contain " + newCargoTrackingId, adminPage.listedCargoContains(newCargoTrackingId));
+
+ cargoDetailsPage = adminPage.showDetailsFor(newCargoTrackingId);
+ cargoDetailsPage.expectOriginOf("NLRTM");
+ cargoDetailsPage.expectDestinationOf("USDAL");
+
+ CargoDestinationPage cargoDestinationPage = cargoDetailsPage.changeDestination();
+ cargoDetailsPage = cargoDestinationPage.selectDestinationTo("AUMEL");
+ cargoDetailsPage.expectDestinationOf("AUMEL");
+ cargoDetailsPage.expectArrivalDeadlineOf(arrivalDeadline);
+
+ }
+}
diff --git a/src/test/java/se/citerus/dddsample/acceptance/CustomerAcceptanceTest.java b/src/test/java/se/citerus/dddsample/acceptance/CustomerAcceptanceTest.java
new file mode 100644
index 00000000..8f98615a
--- /dev/null
+++ b/src/test/java/se/citerus/dddsample/acceptance/CustomerAcceptanceTest.java
@@ -0,0 +1,33 @@
+package se.citerus.dddsample.acceptance;
+
+import org.junit.Before;
+import org.junit.Test;
+import se.citerus.dddsample.acceptance.pages.CustomerPage;
+
+public class CustomerAcceptanceTest extends AbstractAcceptanceTest {
+ private CustomerPage customerPage;
+
+ @Before
+ public void goToCustomerPage() {
+ customerPage = new CustomerPage(driver);
+ }
+
+ @Test
+ public void customerSiteCanTrackValidCargo() {
+ customerPage.trackCargoWithIdOf("ABC123");
+ customerPage.expectCargoLocation("New York");
+ }
+
+ @Test
+ public void customerSiteErrorsOnInvalidCargo() {
+ customerPage.trackCargoWithIdOf("XXX999");
+ customerPage.expectErrorFor("Unknown tracking id");
+ }
+
+ @Test
+ public void customerSiteNotifiesOnMisdirectedCargo() {
+ customerPage.trackCargoWithIdOf("JKL567");
+ customerPage.expectNotificationOf("Cargo is misdirected");
+ }
+
+}
diff --git a/src/test/java/se/citerus/dddsample/acceptance/pages/AdminPage.java b/src/test/java/se/citerus/dddsample/acceptance/pages/AdminPage.java
new file mode 100644
index 00000000..3fa42ecf
--- /dev/null
+++ b/src/test/java/se/citerus/dddsample/acceptance/pages/AdminPage.java
@@ -0,0 +1,43 @@
+package se.citerus.dddsample.acceptance.pages;
+
+import org.openqa.selenium.By;
+import org.openqa.selenium.WebDriver;
+import org.openqa.selenium.WebElement;
+
+import java.util.List;
+import java.util.Optional;
+
+import static org.junit.Assert.assertEquals;
+
+public class AdminPage {
+ private final WebDriver driver;
+
+ public AdminPage(WebDriver driver) {
+ this.driver = driver;
+ driver.get("http://localhost:8080/dddsample/admin/list");
+ assertEquals("Cargo Administration", driver.getTitle());
+ }
+
+ public void listAllCargo() {
+ driver.findElement(By.linkText("List all cargos")).click();
+ assertEquals("Cargo Administration", driver.getTitle());
+ }
+
+ public CargoBookingPage bookNewCargo() {
+ driver.findElement(By.linkText("Book new cargo")).click();
+
+ return new CargoBookingPage(driver);
+ }
+
+ public boolean listedCargoContains(String expectedTrackingId) {
+ List cargoList = driver.findElements(By.cssSelector("#body table tbody tr td a"));
+ Optional matchingCargo = cargoList.stream().filter(cargo -> cargo.getText().equals(expectedTrackingId)).findFirst();
+ return matchingCargo.isPresent();
+ }
+
+ public CargoDetailsPage showDetailsFor(String cargoTrackingId) {
+ driver.findElement(By.linkText(cargoTrackingId)).click();
+
+ return new CargoDetailsPage(driver);
+ }
+}
diff --git a/src/test/java/se/citerus/dddsample/acceptance/pages/CargoBookingPage.java b/src/test/java/se/citerus/dddsample/acceptance/pages/CargoBookingPage.java
new file mode 100644
index 00000000..973c2917
--- /dev/null
+++ b/src/test/java/se/citerus/dddsample/acceptance/pages/CargoBookingPage.java
@@ -0,0 +1,46 @@
+package se.citerus.dddsample.acceptance.pages;
+
+import org.openqa.selenium.By;
+import org.openqa.selenium.WebDriver;
+import org.openqa.selenium.WebElement;
+import org.openqa.selenium.support.ui.Select;
+
+import java.time.LocalDate;
+import java.time.format.DateTimeFormatter;
+
+import static org.junit.Assert.assertEquals;
+
+public class CargoBookingPage {
+
+ private final WebDriver driver;
+
+ public CargoBookingPage(WebDriver driver) {
+ this.driver = driver;
+
+ WebElement newCargoTableCaption = driver.findElement(By.cssSelector("table caption"));
+
+ assertEquals("Book new cargo", newCargoTableCaption.getText());
+ }
+
+ public void selectOrigin(String origin) {
+ Select select = new Select(driver.findElement(By.name("originUnlocode")));
+ select.selectByVisibleText(origin);
+ }
+
+ public void selectDestination(String destination) {
+ Select select = new Select(driver.findElement(By.name("destinationUnlocode")));
+ select.selectByVisibleText(destination);
+ }
+
+ public CargoDetailsPage book() {
+ driver.findElement(By.name("originUnlocode")).submit();
+
+ return new CargoDetailsPage(driver);
+ }
+
+ public void selectArrivalDeadline(LocalDate arrivalDeadline) {
+ WebElement datePicker = driver.findElement(By.id("arrivalDeadline"));
+ datePicker.clear();
+ datePicker.sendKeys(arrivalDeadline.format(DateTimeFormatter.ofPattern("dd/MM/yyyy")));
+ }
+}
diff --git a/src/test/java/se/citerus/dddsample/acceptance/pages/CargoDestinationPage.java b/src/test/java/se/citerus/dddsample/acceptance/pages/CargoDestinationPage.java
new file mode 100644
index 00000000..f7f6d849
--- /dev/null
+++ b/src/test/java/se/citerus/dddsample/acceptance/pages/CargoDestinationPage.java
@@ -0,0 +1,29 @@
+package se.citerus.dddsample.acceptance.pages;
+
+import org.openqa.selenium.By;
+import org.openqa.selenium.WebDriver;
+import org.openqa.selenium.WebElement;
+import org.openqa.selenium.support.ui.Select;
+
+import static junit.framework.TestCase.assertTrue;
+
+public class CargoDestinationPage {
+ private final WebDriver driver;
+
+ public CargoDestinationPage(WebDriver driver) {
+ this.driver = driver;
+ WebElement cargoDestinationHeader = driver.findElement(By.cssSelector("table caption"));
+
+ assertTrue(cargoDestinationHeader.getText().startsWith("Change destination for cargo "));
+ }
+
+ public CargoDetailsPage selectDestinationTo(String destination) {
+ WebElement destinationPicker = driver.findElement(By.name("unlocode"));
+ Select select = new Select(destinationPicker);
+ select.selectByVisibleText(destination);
+
+ destinationPicker.submit();
+
+ return new CargoDetailsPage(driver);
+ }
+}
diff --git a/src/test/java/se/citerus/dddsample/acceptance/pages/CargoDetailsPage.java b/src/test/java/se/citerus/dddsample/acceptance/pages/CargoDetailsPage.java
new file mode 100644
index 00000000..dc42047d
--- /dev/null
+++ b/src/test/java/se/citerus/dddsample/acceptance/pages/CargoDetailsPage.java
@@ -0,0 +1,60 @@
+package se.citerus.dddsample.acceptance.pages;
+
+import org.openqa.selenium.By;
+import org.openqa.selenium.WebDriver;
+import org.openqa.selenium.WebElement;
+
+import java.time.LocalDate;
+import java.time.format.DateTimeFormatter;
+
+import static junit.framework.TestCase.assertTrue;
+import static org.junit.Assert.assertEquals;
+
+public class CargoDetailsPage {
+ public static final String TRACKING_ID_HEADER = "Details for cargo ";
+ private final WebDriver driver;
+ private String trackingId;
+
+ public CargoDetailsPage(WebDriver driver) {
+ this.driver = driver;
+
+ WebElement newCargoTableCaption = driver.findElement(By.cssSelector("table caption"));
+
+ assertTrue(newCargoTableCaption.getText().startsWith(TRACKING_ID_HEADER));
+ trackingId = newCargoTableCaption.getText().replaceFirst(TRACKING_ID_HEADER, "");
+ }
+
+ public String getTrackingId() {
+ return trackingId;
+ }
+
+ public AdminPage listAllCargo() {
+ driver.findElement(By.linkText("List all cargos")).click();
+
+ return new AdminPage(driver);
+ }
+
+ public void expectOriginOf(String expectedOrigin) {
+ String actualOrigin = driver.findElement(By.xpath("//div[@id='container']/table/tbody/tr[1]/td[2]")).getText();
+
+ assertEquals(expectedOrigin, actualOrigin);
+ }
+
+ public void expectDestinationOf(String expectedDestination) {
+ String actualDestination = driver.findElement(By.xpath("//div[@id='container']/table/tbody/tr[2]/td[2]")).getText();
+
+ assertEquals(expectedDestination, actualDestination);
+ }
+
+ public CargoDestinationPage changeDestination() {
+ driver.findElement(By.linkText("Change destination")).click();
+
+ return new CargoDestinationPage(driver);
+ }
+
+ public void expectArrivalDeadlineOf(LocalDate expectedArrivalDeadline) {
+ String actualArrivalDeadline = driver.findElement(By.xpath("//div[@id='container']/table/tbody/tr[4]/td[2]")).getText();
+
+ assertEquals(expectedArrivalDeadline.format(DateTimeFormatter.ofPattern("dd/MM/yyyy")), actualArrivalDeadline);
+ }
+}
diff --git a/src/test/java/se/citerus/dddsample/acceptance/pages/CustomerPage.java b/src/test/java/se/citerus/dddsample/acceptance/pages/CustomerPage.java
new file mode 100644
index 00000000..76d602eb
--- /dev/null
+++ b/src/test/java/se/citerus/dddsample/acceptance/pages/CustomerPage.java
@@ -0,0 +1,40 @@
+package se.citerus.dddsample.acceptance.pages;
+
+import org.openqa.selenium.By;
+import org.openqa.selenium.WebDriver;
+import org.openqa.selenium.WebElement;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+public class CustomerPage {
+ private final WebDriver driver;
+
+ public CustomerPage(WebDriver driver) {
+ this.driver = driver;
+ driver.get("http://localhost:8080/dddsample/track");
+ assertEquals("Tracking cargo", driver.getTitle());
+ }
+
+ public void trackCargoWithIdOf(String trackingId) {
+ WebElement element = driver.findElement(By.id("idInput"));
+ element.sendKeys(trackingId);
+ element.submit();
+
+ }
+
+ public void expectCargoLocation(String expectedLocation) {
+ WebElement cargoSummary = driver.findElement(By.cssSelector("#result h2"));
+ assertTrue(cargoSummary.getText().endsWith(expectedLocation));
+ }
+
+ public void expectErrorFor(String expectedErrorMessage) {
+ WebElement error = driver.findElement(By.cssSelector(".error"));
+ assertTrue(error.getText().endsWith(expectedErrorMessage));
+ }
+
+ public void expectNotificationOf(String expectedNotificationMessage) {
+ WebElement error = driver.findElement(By.cssSelector(".notify"));
+ assertTrue(error.getText().endsWith(expectedNotificationMessage));
+ }
+}