diff --git a/src/test/java/es/uvigo/esei/daa/dataset/PetsDataset.java b/src/test/java/es/uvigo/esei/daa/dataset/PetsDataset.java new file mode 100644 index 0000000000000000000000000000000000000000..2ce8dc8f3db01440ccfeec8892d264587a77b2fb --- /dev/null +++ b/src/test/java/es/uvigo/esei/daa/dataset/PetsDataset.java @@ -0,0 +1,75 @@ +package es.uvigo.esei.daa.dataset; + +import java.util.Arrays; +import java.util.function.Predicate; +import static java.util.Arrays.binarySearch; +import static java.util.Arrays.stream; + +import es.uvigo.esei.daa.entities.Person; +import es.uvigo.esei.daa.entities.Pet; + +public final class PetsDataset { + + private PetsDataset() {} + + public static Pet[] pets() { + return new Pet[] { + new Pet (1, "Brune", PeopleDataset.people()[6]), + new Pet (2, "Toby", PeopleDataset.people()[6]), + new Pet (3, "Zeus", PeopleDataset.people()[6]) + }; + } + + public static Pet[] petsWithout (int ... ids) { + Arrays.sort(ids); + + final Predicate hasValidId = pet -> binarySearch (ids, pet.getId()) < 0; + + return stream(pets()).filter(hasValidId).toArray(Pet[]::new); + } + + public static Pet pet (int id) { + return stream(pets()).filter(pet -> pet.getId() == id).findAny().orElseThrow(IllegalArgumentException::new); + } + + public static int existentId() { + return 1; + } + + public static int existentIdOwner() { + return 7; + } + + public static int nonExistentIdOwner() { + return 7777; + } + + public static int nonExistentId() { + return 1234; + } + + public static Pet existentPet () { + return pet(existentId()); + } + + public static Pet nonExistentPet() { + return new Pet (nonExistentId(), "PetDoesntExist", PeopleDataset.existentPerson()); + } + + public static String newName() { + return "Luna"; + } + + public static Person newOwner () { + return PeopleDataset.people()[6]; + } + + public static String newOwnerID () { + return "7"; + } + + public static Pet newPet (){ + return new Pet ( pets().length + 1, newName(), newOwner() ); + } + +} diff --git a/src/test/java/es/uvigo/esei/daa/entities/PetUnitTest.java b/src/test/java/es/uvigo/esei/daa/entities/PetUnitTest.java new file mode 100644 index 0000000000000000000000000000000000000000..cba07ac8a32c30a5c1fd6909e84690af3ec21fdf --- /dev/null +++ b/src/test/java/es/uvigo/esei/daa/entities/PetUnitTest.java @@ -0,0 +1,114 @@ +package es.uvigo.esei.daa.entities; + +import static org.hamcrest.CoreMatchers.equalTo; +import static org.hamcrest.CoreMatchers.is; +import static org.junit.Assert.*; + +import org.junit.Test; + +import nl.jqno.equalsverifier.EqualsVerifier; +import nl.jqno.equalsverifier.Warning; + +public class PetUnitTest { + + @Test + public void testPetIntStringPerson() { + final int idPerson = 1; + final String namePerson = "John"; + final String surnamePerson = "Doe"; + + final Person owner = new Person(1, namePerson, surnamePerson); + + final int idPet = 1; + final String namePet = "Mascota"; + + final Pet pet = new Pet (idPet, namePet, owner); + + assertThat(pet.getId(), is(equalTo(idPet))); + assertThat(pet.getName(), is(equalTo(namePet))); + assertThat(pet.getOwner().getId(), is(equalTo(idPerson))); + assertThat(pet.getOwner().getName(), is(equalTo(namePerson))); + assertThat(pet.getOwner().getSurname(), is(equalTo(surnamePerson))); + + } + + @Test(expected = NullPointerException.class) + public void testPetNullName() { + new Pet(1, null, new Person (1, "John", "Doe") ); + } + + @Test(expected = NullPointerException.class) + public void testPetNullOwner() { + new Pet(1, "Mascota", null); + } + + @Test + public void testSetName() { + final int id = 1; + final Person owner = new Person (1, "John", "Doe"); + + final Pet pet = new Pet(id, "Mascota", owner); + pet.setName("Pet"); + + assertThat(pet.getId(), is(equalTo(id))); + assertThat(pet.getName(), is(equalTo("Pet"))); + assertThat(pet.getOwner().getId(), is(equalTo(1))); + assertThat(pet.getOwner().getName(), is(equalTo("John"))); + assertThat(pet.getOwner().getSurname(), is(equalTo("Doe"))); + } + + @Test(expected = NullPointerException.class) + public void testSetNullName() { + final int id = 1; + final Person owner = new Person (1, "John", "Doe"); + + final Pet pet = new Pet(id, "Mascota", owner); + pet.setName(null); + } + + @Test + public void testSetOwner() { + final int id = 1; + final Person owner = new Person (1, "John", "Doe"); + final Person ownerSet = new Person (2, "Antonio", "Perez"); + + final Pet pet = new Pet(id, "Mascota", owner); + pet.setOwner(ownerSet); + + assertThat(pet.getId(), is(equalTo(id))); + assertThat(pet.getName(), is(equalTo("Mascota"))); + assertThat(pet.getOwner().getId(), is(equalTo(2))); + assertThat(pet.getOwner().getName(), is(equalTo("Antonio"))); + assertThat(pet.getOwner().getSurname(), is(equalTo("Perez"))); + } + + @Test(expected = NullPointerException.class) + public void testSetNullSurname() { + final int id = 1; + final Person owner = new Person (1, "John", "Doe"); + + final Pet pet = new Pet(id, "Mascota", owner); + pet.setOwner(null); + } + + @Test + public void testEqualsObject() { + final int id = 1; + final Person owner = new Person (1, "John", "Doe"); + + final Pet pet1 = new Pet(id, "Mascota", owner); + final Pet pet2 = new Pet(id, "Mascota", owner); + + assertTrue(pet1.equals(pet2)); + } + + @Test + public void testEqualsHashcode() { + EqualsVerifier.forClass(Pet.class) + .withIgnoredFields("name", "owner") + .suppress(Warning.STRICT_INHERITANCE) + .suppress(Warning.NONFINAL_FIELDS) + .verify(); + } + +} diff --git a/src/test/java/es/uvigo/esei/daa/matchers/IsEqualToPet.java b/src/test/java/es/uvigo/esei/daa/matchers/IsEqualToPet.java new file mode 100644 index 0000000000000000000000000000000000000000..b771dd9d3fc2447a50408070091594f342529eec --- /dev/null +++ b/src/test/java/es/uvigo/esei/daa/matchers/IsEqualToPet.java @@ -0,0 +1,40 @@ +package es.uvigo.esei.daa.matchers; + +import org.hamcrest.Factory; +import org.hamcrest.Matcher; + +import es.uvigo.esei.daa.entities.Pet; + +public class IsEqualToPet extends IsEqualToEntity{ + + public IsEqualToPet(Pet entity) { + super(entity); + } + + @Override + protected boolean matchesSafely (Pet actual) { + + this.clearDescribeTo(); + + if (actual == null) { + this.addTemplatedDescription("actual", expected.toString()); + return false; + } else { + return checkAttribute("id", Pet::getId, actual) + && checkAttribute ("name", Pet::getName, actual) + && checkAttribute ("owner", Pet::getOwner, actual); + } + + } + + @Factory + public static IsEqualToPet equalsToPet (Pet pet) { + return new IsEqualToPet(pet); + } + + @Factory + public static Matcher> containsPetsInAnyOrder(Pet ... pets){ + return containsEntityInAnyOrder(IsEqualToPet::equalsToPet, pets); + } + +} diff --git a/src/test/java/es/uvigo/esei/daa/rest/PetsResourceTest.java b/src/test/java/es/uvigo/esei/daa/rest/PetsResourceTest.java new file mode 100644 index 0000000000000000000000000000000000000000..1a90bab005089ba4d9ea6b647b2828ebdee4a0b0 --- /dev/null +++ b/src/test/java/es/uvigo/esei/daa/rest/PetsResourceTest.java @@ -0,0 +1,280 @@ +package es.uvigo.esei.daa.rest; + +import static es.uvigo.esei.daa.dataset.PetsDataset.*; +import static es.uvigo.esei.daa.dataset.UsersDataset.adminLogin; +import static es.uvigo.esei.daa.dataset.UsersDataset.normalLogin; +import static es.uvigo.esei.daa.dataset.UsersDataset.userToken; +import static es.uvigo.esei.daa.matchers.HasHttpStatus.hasBadRequestStatus; +import static es.uvigo.esei.daa.matchers.HasHttpStatus.hasOkStatus; +import static es.uvigo.esei.daa.matchers.HasHttpStatus.hasUnauthorized; +import static es.uvigo.esei.daa.matchers.IsEqualToPet.containsPetsInAnyOrder; +import static es.uvigo.esei.daa.matchers.IsEqualToPet.equalsToPet; +import static javax.ws.rs.client.Entity.entity; +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.CoreMatchers.equalTo; +import static org.junit.Assert.assertThat; + +import java.io.IOException; +import java.util.List; + +import javax.sql.DataSource; +import javax.ws.rs.core.Application; +import javax.ws.rs.core.GenericType; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.Form; + +import org.glassfish.jersey.client.ClientConfig; +import org.glassfish.jersey.test.JerseyTest; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.TestExecutionListeners; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; + +import com.fasterxml.jackson.jaxrs.json.JacksonJsonProvider; +import com.github.springtestdbunit.DbUnitTestExecutionListener; +import com.github.springtestdbunit.annotation.DatabaseSetup; +import com.github.springtestdbunit.annotation.ExpectedDatabase; + +import es.uvigo.esei.daa.DAAExampleTestApplication; +import es.uvigo.esei.daa.entities.Pet; +import es.uvigo.esei.daa.listeners.ApplicationContextBinding; +import es.uvigo.esei.daa.listeners.ApplicationContextJndiBindingTestExecutionListener; +import es.uvigo.esei.daa.listeners.DbManagement; +import es.uvigo.esei.daa.listeners.DbManagementTestExecutionListener; + + +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration("classpath:contexts/mem-context.xml") +@TestExecutionListeners({ + DbUnitTestExecutionListener.class, + DbManagementTestExecutionListener.class, + ApplicationContextJndiBindingTestExecutionListener.class +}) + +@ApplicationContextBinding( + jndiUrl = "java:/comp/env/jdbc/daaexample", + type = DataSource.class +) + +@DbManagement( + create = "classpath:db/hsqldb.sql", + drop = "classpath:db/hsqldb-drop.sql" +) + +@DatabaseSetup("/datasets/dataset.xml") +@ExpectedDatabase("/datasets/dataset.xml") + +public class PetsResourceTest extends JerseyTest{ + + + @Override + protected Application configure() { + return new DAAExampleTestApplication(); + } + + @Override + protected void configureClient(ClientConfig config) { + super.configureClient(config); + + // Enables JSON transformation in client + config.register(JacksonJsonProvider.class); + config.property("com.sun.jersey.api.json.POJOMappingFeature", Boolean.TRUE); + } + + + @Test + public void testList() throws IOException { + + final Response response = target("people/" + existentIdOwner() + "/pets").request().header("Authorization", "Basic " + userToken(adminLogin())).get(); + + assertThat(response, hasOkStatus()); + + final List pets = response.readEntity(new GenericType>() {}); + + assertThat(pets, containsPetsInAnyOrder(pets())); + + } + + @Test + public void testListUnauthorized() throws IOException { + + final Response response = target("people/" + existentIdOwner() + "/pets").request().header("Authorization", "Basic " + userToken(normalLogin())).get(); + + assertThat(response, hasUnauthorized()); + + } + + + @Test + @ExpectedDatabase(value="/datasets/dataset-add.xml", table="pet") + public void testAdd() throws IOException { + final Form form = new Form(); + form.param("name", newName()); + + final Response response = target("people/" + existentIdOwner() + "/pets") + .request(MediaType.APPLICATION_JSON_TYPE) + .header("Authorization", "Basic " + userToken(adminLogin())) + .post(entity(form, MediaType.APPLICATION_FORM_URLENCODED_TYPE)); + + assertThat(response, hasOkStatus()); + + final Pet pet = response.readEntity(Pet.class); + + assertThat(pet, is(equalsToPet(newPet()))); + + } + + + @Test + public void testAddUnauthorized() throws IOException { + final Form form = new Form(); + form.param("name", newName()); + + final Response response = target("people/" + existentIdOwner() + "/pets") + .request(MediaType.APPLICATION_JSON_TYPE) + .header("Authorization", "Basic " + userToken(normalLogin())) + .post(entity(form, MediaType.APPLICATION_FORM_URLENCODED_TYPE)); + + assertThat(response, hasUnauthorized()); + + } + + @Test + public void testAddMissingName() throws IOException { + final Form form = new Form(); + + final Response response = target("people/" + existentIdOwner() + "/pets") + .request(MediaType.APPLICATION_JSON_TYPE) + .header("Authorization", "Basic " + userToken(adminLogin())) + .post(entity(form, MediaType.APPLICATION_FORM_URLENCODED_TYPE)); + + assertThat(response, hasBadRequestStatus()); + + } + + + @Test + @ExpectedDatabase(value="/datasets/dataset-modify.xml", table="pet") + public void testModify() throws IOException { + final Form form = new Form(); + form.param("name", newName()); + + final Response response = target("people/" + existentIdOwner() + "/pets/" + existentId()) + .request(MediaType.APPLICATION_JSON_TYPE) + .header("Authorization", "Basic " + userToken(adminLogin())) + .put(entity(form, MediaType.APPLICATION_FORM_URLENCODED_TYPE)); + + assertThat(response, hasOkStatus()); + + final Pet modifiedPet = response.readEntity(Pet.class); + + final Pet pet = existentPet(); + pet.setName(newName()); + + assertThat(modifiedPet, is(equalsToPet(pet))); + } + + @Test + public void testModifyUnauthorized() throws IOException { + final Form form = new Form(); + form.param("name", newName()); + + final Response response = target("people/" + existentIdOwner() + "/pets/" + existentId()) + .request(MediaType.APPLICATION_JSON_TYPE) + .header("Authorization", "Basic " + userToken(normalLogin())) + .put(entity(form, MediaType.APPLICATION_FORM_URLENCODED_TYPE)); + + assertThat(response, hasUnauthorized()); + } + + @Test + public void testModifyInvalidId() throws IOException { + final Form form = new Form(); + form.param("name", newName()); + + final Response response = target("people/" + existentIdOwner() + "/pets/" + nonExistentId()) + .request(MediaType.APPLICATION_JSON_TYPE) + .header("Authorization", "Basic " + userToken(adminLogin())) + .put(entity(form, MediaType.APPLICATION_FORM_URLENCODED_TYPE)); + + assertThat(response, hasBadRequestStatus()); + } + + @Test + public void testModifyInvalidIdOwner() throws IOException { + final Form form = new Form(); + form.param("name", newName()); + + final Response response = target("people/" + nonExistentIdOwner() + "/pets/" + existentId()) + .request(MediaType.APPLICATION_JSON_TYPE) + .header("Authorization", "Basic " + userToken(adminLogin())) + .put(entity(form, MediaType.APPLICATION_FORM_URLENCODED_TYPE)); + + assertThat(response, hasBadRequestStatus()); + } + + @Test + @ExpectedDatabase(value="/datasets/dataset-delete.xml", table="pet") + public void testDelete () throws IOException { + final Response response = target ("people/" + existentIdOwner() + "/pets/" + existentId()) + .request().header("Authorization", "Basic " + userToken(adminLogin())).delete(); + + assertThat(response, hasOkStatus()); + + final Integer deletedId = response.readEntity(Integer.class); + + assertThat(deletedId, is(equalTo(existentId()))); + } + + @Test + public void testDeleteUnauthorized () throws IOException { + final Response response = target ("people/" + existentIdOwner() + "/pets/" + existentId()) + .request().header("Authorization", "Basic " + userToken(normalLogin())).delete(); + + assertThat(response, hasUnauthorized()); + } + + @Test + public void testDeleteInvalidId () throws IOException { + final Response response = target ("people/" + existentIdOwner() + "/pets/" + nonExistentId()) + .request().header("Authorization", "Basic " + userToken(adminLogin())).delete(); + + assertThat(response, hasBadRequestStatus()); + } + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +} diff --git a/src/test/java/es/uvigo/esei/daa/util/AdditionalConditions.java b/src/test/java/es/uvigo/esei/daa/util/AdditionalConditions.java new file mode 100644 index 0000000000000000000000000000000000000000..68bb9225e2f3d972c3f93428ea588d0f78ebdde2 --- /dev/null +++ b/src/test/java/es/uvigo/esei/daa/util/AdditionalConditions.java @@ -0,0 +1,14 @@ +package es.uvigo.esei.daa.util; + +import org.openqa.selenium.JavascriptExecutor; +import org.openqa.selenium.support.ui.ExpectedCondition; + +/* + * Implementation based on https://stackoverflow.com/questions/33348600/selenium-wait-for-ajax-content-to-load-universal-approach + */ +public class AdditionalConditions { + public static ExpectedCondition jQueryAjaxCallsHaveCompleted() { + return driver -> + (Boolean) ((JavascriptExecutor) driver).executeScript("return (window.jQuery !== null) && (jQuery.active === 0)"); + } +} diff --git a/src/test/java/es/uvigo/esei/daa/web/PeopleWebTest.java b/src/test/java/es/uvigo/esei/daa/web/PeopleWebTest.java new file mode 100644 index 0000000000000000000000000000000000000000..81313c8bdab5129e4a6f26e11bd69c78d520fd4f --- /dev/null +++ b/src/test/java/es/uvigo/esei/daa/web/PeopleWebTest.java @@ -0,0 +1,134 @@ +package es.uvigo.esei.daa.web; + +import static es.uvigo.esei.daa.dataset.PeopleDataset.existentId; +import static es.uvigo.esei.daa.dataset.PeopleDataset.existentPerson; +import static es.uvigo.esei.daa.dataset.PeopleDataset.newName; +import static es.uvigo.esei.daa.dataset.PeopleDataset.newPerson; +import static es.uvigo.esei.daa.dataset.PeopleDataset.newSurname; +import static es.uvigo.esei.daa.dataset.PeopleDataset.people; +import static es.uvigo.esei.daa.matchers.IsEqualToPerson.containsPeopleInAnyOrder; +import static es.uvigo.esei.daa.matchers.IsEqualToPerson.equalsToPerson; +import static org.hamcrest.CoreMatchers.is; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertThat; + +import java.util.concurrent.TimeUnit; + +import javax.sql.DataSource; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.openqa.selenium.WebDriver; +import org.openqa.selenium.firefox.FirefoxDriver; +import org.openqa.selenium.firefox.FirefoxOptions; +import org.openqa.selenium.firefox.FirefoxProfile; +import org.openqa.selenium.html5.LocalStorage; +import org.openqa.selenium.remote.DesiredCapabilities; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.TestExecutionListeners; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; + +import com.github.springtestdbunit.DbUnitTestExecutionListener; +import com.github.springtestdbunit.annotation.DatabaseSetup; +import com.github.springtestdbunit.annotation.ExpectedDatabase; + +import es.uvigo.esei.daa.entities.Person; +import es.uvigo.esei.daa.listeners.ApplicationContextBinding; +import es.uvigo.esei.daa.listeners.ApplicationContextJndiBindingTestExecutionListener; +import es.uvigo.esei.daa.listeners.DbManagement; +import es.uvigo.esei.daa.listeners.DbManagementTestExecutionListener; +import es.uvigo.esei.daa.web.pages.MainPage; + +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration("classpath:contexts/hsql-context.xml") +@TestExecutionListeners({ + DbUnitTestExecutionListener.class, + DbManagementTestExecutionListener.class, + ApplicationContextJndiBindingTestExecutionListener.class +}) +@ApplicationContextBinding( + jndiUrl = "java:/comp/env/jdbc/daaexample", + type = DataSource.class +) +@DbManagement( + create = "classpath:db/hsqldb.sql", + drop = "classpath:db/hsqldb-drop.sql" +) +@DatabaseSetup("/datasets/dataset.xml") +@ExpectedDatabase("/datasets/dataset.xml") +public class PeopleWebTest { + private static final int DEFAULT_WAIT_TIME = 1; + + private WebDriver driver; + private MainPage mainPage; + + @Before + public void setUp() throws Exception { + final String baseUrl = "http://localhost:9080/DAAExample/"; + + final FirefoxProfile profile = new FirefoxProfile(); + profile.setPreference("browser.privatebrowsing.autostart", true); + + final FirefoxOptions options = new FirefoxOptions(DesiredCapabilities.firefox()); + options.setProfile(profile); + + final FirefoxDriver firefoxDriver; + driver = firefoxDriver = new FirefoxDriver(); + driver.get(baseUrl); + + // Driver will wait DEFAULT_WAIT_TIME if it doesn't find and element. + driver.manage().timeouts().implicitlyWait(DEFAULT_WAIT_TIME, TimeUnit.SECONDS); + driver.manage().window().maximize(); + + // Login as "admin:adminpass" + final LocalStorage localStorage = firefoxDriver.getLocalStorage(); + localStorage.setItem("authorization-token", "YWRtaW46YWRtaW5wYXNz"); + + mainPage = new MainPage(driver, baseUrl); + mainPage.navigateTo(); + } + + @After + public void tearDown() throws Exception { + driver.quit(); + driver = null; + mainPage = null; + } + + @Test + public void testList() throws Exception { + assertThat(mainPage.listPeople(), containsPeopleInAnyOrder(people())); + } + + @Test + @ExpectedDatabase("/datasets/dataset-add.xml") + public void testAdd() throws Exception { + final Person newPerson = mainPage.addPerson(newName(), newSurname()); + + assertThat(newPerson, is(equalsToPerson(newPerson()))); + } + + @Test + @ExpectedDatabase("/datasets/dataset-modify.xml") + public void testEdit() throws Exception { + final Person person = existentPerson(); + person.setName(newName()); + person.setSurname(newSurname()); + + mainPage.editPerson(person); + + final Person webPerson = mainPage.getPerson(person.getId()); + + assertThat(webPerson, is(equalsToPerson(person))); + } + + @Test + @ExpectedDatabase("/datasets/dataset-delete.xml") + public void testDelete() throws Exception { + mainPage.deletePerson(existentId()); + + assertFalse(mainPage.hasPerson(existentId())); + } +} diff --git a/src/test/java/es/uvigo/esei/daa/web/pages/MainPage.java b/src/test/java/es/uvigo/esei/daa/web/pages/MainPage.java new file mode 100644 index 0000000000000000000000000000000000000000..97b6a1a230a6f8135a33e1beae89b06a0d14504d --- /dev/null +++ b/src/test/java/es/uvigo/esei/daa/web/pages/MainPage.java @@ -0,0 +1,242 @@ +package es.uvigo.esei.daa.web.pages; + +import static es.uvigo.esei.daa.util.AdditionalConditions.jQueryAjaxCallsHaveCompleted; +import static java.util.stream.Collectors.toList; +import static org.openqa.selenium.support.ui.ExpectedConditions.presenceOfElementLocated; +import static org.openqa.selenium.support.ui.ExpectedConditions.textToBePresentInElement; + +import java.util.List; + +import org.openqa.selenium.By; +import org.openqa.selenium.NoSuchElementException; +import org.openqa.selenium.WebDriver; +import org.openqa.selenium.WebElement; +import org.openqa.selenium.support.ui.WebDriverWait; + +import es.uvigo.esei.daa.entities.Person; + +public class MainPage { + private static final String TABLE_ID = "people-list"; + private static final String FORM_ID = "people-form"; + + private static final String ID_PREFIX = "person-"; + + private final WebDriver driver; + + private final WebDriverWait wait; + + private final String baseUrl; + + public MainPage(WebDriver driver, String baseUrl) { + this.driver = driver; + this.baseUrl = baseUrl; + + this.wait = new WebDriverWait(driver, 1); + } + + public void navigateTo() { + this.driver.get(this.baseUrl + "main.html"); + + this.wait.until(presenceOfElementLocated(By.id("people-list"))); + } + + public int countPeople() { + return new PeopleTable(this.driver).countPeople(); + } + + public List listPeople() { + return new PeopleTable(this.driver).listPeople(); + } + + public Person getLastPerson() { + return new PeopleTable(this.driver).getPersonInLastRow(); + } + + public Person getPerson(int id) { + return new PeopleTable(this.driver).getPersonById(id); + } + + public boolean hasPerson(int id) { + return new PeopleTable(this.driver).hasPerson(id); + } + + public Person addPerson(String name, String surname) { + final PersonForm form = new PersonForm(this.driver); + + form.clear(); + form.setName(name); + form.setSurname(surname); + form.submit(); + + final PeopleTable table = new PeopleTable(driver); + return table.getPerson(name, surname); + } + + public void editPerson(Person person) { + final PeopleTable table = new PeopleTable(this.driver); + table.editPerson(person.getId()); + + final PersonForm form = new PersonForm(this.driver); + form.setName(person.getName()); + form.setSurname(person.getSurname()); + form.submit(); + } + + public void deletePerson(int id) { + final PeopleTable table = new PeopleTable(this.driver); + + table.deletePerson(id); + + wait.until(jQueryAjaxCallsHaveCompleted()); + } + + private final static class PeopleTable { + private final WebDriver driver; + + private final WebElement table; + + public PeopleTable(WebDriver driver) { + this.driver = driver; + + this.table = this.driver.findElement(By.id(TABLE_ID)); + } + + public boolean hasPerson(int id) { + try { + return this.getPersonRow(id) != null; + } catch (NoSuchElementException nsee) { + return false; + } + } + + public void editPerson(int id) { + final WebElement personRow = this.getPersonRow(id); + + personRow.findElement(By.className("edit")).click(); + } + + public void deletePerson(int id) { + final WebElement personRow = this.getPersonRow(id); + + personRow.findElement(By.className("delete")).click(); + + this.acceptDialog(); + } + + public Person getPersonById(int id) { + return rowToPerson(getPersonRow(id)); + } + + public Person getPerson(String name, String surname) { + return rowToPerson(getPersonRow(name, surname)); + } + + public Person getPersonInLastRow() { + final WebElement row = this.table.findElement(By.cssSelector("tbody > tr:last-child")); + + return rowToPerson(row); + } + + private WebElement getPersonRow(int id) { + return this.table.findElement(By.id(ID_PREFIX + id)); + } + + public WebElement getPersonRow(String name, String surname) { + final List rows = table.findElements(By.cssSelector("tbody > tr")); + + for (WebElement row : rows) { + final String rowName = row.findElement(By.className("name")).getText(); + final String rowSurname = row.findElement(By.className("surname")).getText(); + + if (rowName.equals(name) && rowSurname.equals(surname)) { + return row; + } + } + + throw new IllegalArgumentException(String.format("No row found with name '%s' and surname '%s'", name, surname)); + } + + public int countPeople() { + return getRows().size(); + } + + public List listPeople() { + return getRows().stream() + .map(this::rowToPerson) + .collect(toList()); + } + + private List getRows() { + final String xpathQuery = "//tbody/tr[starts-with(@id, '" + ID_PREFIX + "')]"; + + return this.table.findElements(By.xpath(xpathQuery)); + } + + private Person rowToPerson(WebElement row) { + return new Person( + Integer.parseInt(row.getAttribute("id").substring(ID_PREFIX.length())), + row.findElement(By.className("name")).getText(), + row.findElement(By.className("surname")).getText() + ); + } + + private void acceptDialog() { + driver.switchTo().alert().accept(); + } + } + + public final static class PersonForm { + private final WebDriverWait wait; + + private final WebElement fieldName; + private final WebElement fieldSurname; + private final WebElement buttonClear; + private final WebElement buttonSubmit; + + public PersonForm(WebDriver driver) { + this.wait = new WebDriverWait(driver, 1); + + final WebElement form = driver.findElement(By.id(FORM_ID)); + + this.fieldName = form.findElement(By.name("name")); + this.fieldSurname = form.findElement(By.name("surname")); + this.buttonClear = form.findElement(By.id("btnClear")); + this.buttonSubmit = form.findElement(By.id("btnSubmit")); + } + + public void submit() { + this.buttonSubmit.click(); + + this.waitForCleanFields(); + } + + public void clear() { + this.buttonClear.click(); + + this.waitForCleanFields(); + } + + public void setName(String name) { + this.fieldName.clear(); + this.fieldName.sendKeys(name); + } + + public void setSurname(String surname) { + this.fieldSurname.clear(); + this.fieldSurname.sendKeys(surname); + } + + public String getName() { + return this.fieldName.getText(); + } + + public String getSurname() { + return this.fieldSurname.getText(); + } + + private void waitForCleanFields() { + wait.until(textToBePresentInElement(fieldName, "")); + wait.until(textToBePresentInElement(fieldSurname, "")); + } + } +} diff --git a/src/test/resources/datasets/dataset-add.xml b/src/test/resources/datasets/dataset-add.xml index 9a75a999a98510f7d6d32992877e71772e8f536c..afa5ff51514743113b9d06e8b5293a95057142c6 100644 --- a/src/test/resources/datasets/dataset-add.xml +++ b/src/test/resources/datasets/dataset-add.xml @@ -16,4 +16,10 @@ + + + + + + \ No newline at end of file diff --git a/src/test/resources/datasets/dataset-delete.xml b/src/test/resources/datasets/dataset-delete.xml index e49223db335c0f49f7d78cdcb3f27e80e14d30da..eefb0d935f5d430b29521903edd4f18c0260582a 100644 --- a/src/test/resources/datasets/dataset-delete.xml +++ b/src/test/resources/datasets/dataset-delete.xml @@ -14,4 +14,9 @@ + + + + + \ No newline at end of file diff --git a/src/test/resources/datasets/dataset-modify.xml b/src/test/resources/datasets/dataset-modify.xml index 6e2dfc903798c9e26431fbaf42bea176a05fc59c..6832aebd502448bdd16adbf050be910896e4bc3c 100644 --- a/src/test/resources/datasets/dataset-modify.xml +++ b/src/test/resources/datasets/dataset-modify.xml @@ -15,4 +15,9 @@ + + + + + \ No newline at end of file diff --git a/src/test/resources/datasets/dataset.dtd b/src/test/resources/datasets/dataset.dtd index e64500f9760310832c4352657d6b41454a653582..33990680d7a6b1b5bdc3eb0ca181e2ac23011880 100644 --- a/src/test/resources/datasets/dataset.dtd +++ b/src/test/resources/datasets/dataset.dtd @@ -1,7 +1,8 @@ - + + + diff --git a/src/test/resources/datasets/dataset.xml b/src/test/resources/datasets/dataset.xml index 3f48cc9b6888070b9fb5b4c42bee31f8eae267b6..fc37694d6ff828d422b0e1518a96f5d322346b25 100644 --- a/src/test/resources/datasets/dataset.xml +++ b/src/test/resources/datasets/dataset.xml @@ -15,4 +15,9 @@ + + + + + \ No newline at end of file diff --git a/src/test/resources/db/hsqldb-drop.sql b/src/test/resources/db/hsqldb-drop.sql index 31f86431b16948308e44087e73b488fc3043628a..448d5036d15aadfdf1bfde602f9c23c1ba2a7602 100644 --- a/src/test/resources/db/hsqldb-drop.sql +++ b/src/test/resources/db/hsqldb-drop.sql @@ -1,2 +1,3 @@ DROP TABLE People IF EXISTS; DROP TABLE Users IF EXISTS; +DROP TABLE Pet IF EXISTS; diff --git a/src/test/resources/db/hsqldb.sql b/src/test/resources/db/hsqldb.sql index a62944149d65c732b38a85ca9455f804265fd185..73439fa6876013b52233284c9d72b2b4a0c03809 100644 --- a/src/test/resources/db/hsqldb.sql +++ b/src/test/resources/db/hsqldb.sql @@ -10,4 +10,11 @@ CREATE TABLE users ( password VARCHAR(64) NOT NULL, role VARCHAR(5) NOT NULL, PRIMARY KEY (login) -); \ No newline at end of file +); + +CREATE TABLE pet ( + id INTEGER GENERATED BY DEFAULT AS IDENTITY (START WITH 1, INCREMENT BY 1) NOT NULL, + name varchar(50) NOT NULL, + owner int NOT NULL, + PRIMARY KEY (id) +) \ No newline at end of file