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)); + } +}