diff --git a/scm-webapp/pom.xml b/scm-webapp/pom.xml
index b1b971af3e..1a629c71f9 100644
--- a/scm-webapp/pom.xml
+++ b/scm-webapp/pom.xml
@@ -326,13 +326,20 @@
${selenium.version}test
-
+
org.seleniumhq.seleniumselenium-firefox-driver${selenium.version}test
+
+
+ org.seleniumhq.selenium
+ htmlunit-driver
+ 2.21
+ test
+ com.sun.jersey
@@ -528,7 +535,7 @@
DEVELOPMENTtarget/scm-itdefault
- 2.28.0
+ 2.53.11.311.13.11.0
@@ -688,6 +695,24 @@
selenium
+
+
+
+ org.apache.httpcomponents
+ httpclient
+ 4.3.2
+ test
+
+
+
+ xml-apis
+ xml-apis
+ 1.4.01
+ test
+
+
+
+
diff --git a/scm-webapp/src/test/java/sonia/scm/selenium/AuthenticationITCase.java b/scm-webapp/src/test/java/sonia/scm/selenium/AuthenticationITCase.java
index a2b0d0fe6d..34013e7e76 100644
--- a/scm-webapp/src/test/java/sonia/scm/selenium/AuthenticationITCase.java
+++ b/scm-webapp/src/test/java/sonia/scm/selenium/AuthenticationITCase.java
@@ -34,25 +34,27 @@ package sonia.scm.selenium;
//~--- non-JDK imports --------------------------------------------------------
+import sonia.scm.selenium.page.Pages;
+import sonia.scm.selenium.page.MainPage;
+import sonia.scm.selenium.page.LoginPage;
+import static org.junit.Assert.*;
import org.junit.Test;
/**
- *
+ * Authentication related selenium integration tests.
+ *
* @author Sebastian Sdorra
*/
-public class AuthenticationITCase extends SeleniumTestBase
-{
+public class AuthenticationITCase extends SeleniumITCaseBase {
/**
- * Method description
- *
- *
- * @throws Exception
+ * Authenticates an user and call logout function.
*/
@Test
- public void testAuthentication() throws Exception
- {
- login("scmadmin", "scmadmin");
- logout();
+ public void testAuthentication() {
+ MainPage main = Pages.get(driver, LoginPage.class).login("scmadmin", "scmadmin");
+ assertEquals("scmadmin", main.getUserInfo());
+ main.logout();
}
+
}
diff --git a/scm-webapp/src/test/java/sonia/scm/selenium/RepositoryCRUDITCase.java b/scm-webapp/src/test/java/sonia/scm/selenium/RepositoriesITCase.java
similarity index 66%
rename from scm-webapp/src/test/java/sonia/scm/selenium/RepositoryCRUDITCase.java
rename to scm-webapp/src/test/java/sonia/scm/selenium/RepositoriesITCase.java
index 64760ae774..05898f6529 100644
--- a/scm-webapp/src/test/java/sonia/scm/selenium/RepositoryCRUDITCase.java
+++ b/scm-webapp/src/test/java/sonia/scm/selenium/RepositoriesITCase.java
@@ -34,61 +34,55 @@ package sonia.scm.selenium;
//~--- non-JDK imports --------------------------------------------------------
+import sonia.scm.selenium.page.Pages;
+import sonia.scm.selenium.page.MainPage;
+import sonia.scm.selenium.page.LoginPage;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
-import static org.junit.Assert.*;
+import sonia.scm.repository.Repository;
/**
- *
+ * Repository related selenium integration tests.
+ *
* @author Sebastian Sdorra
*/
-public class RepositoryCRUDITCase extends SeleniumTestBase
-{
+public class RepositoriesITCase extends SeleniumITCaseBase {
+ private MainPage main;
+
/**
- * Method description
- *
- */
- @After
- public void after()
- {
- logout();
- }
-
- /**
- * Method description
- *
- */
- @Test
- public void createRepository() throws InterruptedException
- {
- waitAndClick("#repositoryAddButton");
- waitForPresence("input[name=name]").sendKeys("scm");
- select("#x-form-el-repositoryType img").click();
- waitAndClick("div.x-combo-list-item:nth-of-type(2)");
- type("input[name=contact]", "scmadmin@scm-manager.org");
- type("textarea[name=description]", "SCM-Manager");
- waitAndClick("div.x-panel-btns button:nth-of-type(1)");
-
- String name =
- waitForPresence(
- "div.x-grid3-row-selected div.x-grid3-col-name").getText();
-
- assertEquals("scm", name);
-
- waitAndClick("#repoRmButton button");
- waitAndClick("div.x-window button:nth-of-type(1)");
- }
-
- /**
- * Method description
- *
+ * Authenticates admin user, before each test.
*/
@Before
- public void login()
- {
- login("scmadmin", "scmadmin");
+ public void login() {
+ main = Pages.get(driver, LoginPage.class)
+ .login("scmadmin", "scmadmin");
+ }
+
+ /**
+ * Creates, select and removes a repository.
+ */
+ @Test
+ public void createRepository() {
+ Repository repository = new Repository();
+ repository.setName("scm");
+ repository.setType("git");
+ repository.setContact("scmadmin@scm-manager.org");
+ repository.setDescription("SCM-Manager");
+
+ main.repositories()
+ .add(repository)
+ .select(repository.getName())
+ .remove();
+ }
+
+ /**
+ * Logs the user out, after each test.
+ */
+ @After
+ public void logout() {
+ main.logout();
}
}
diff --git a/scm-webapp/src/test/java/sonia/scm/selenium/SeleniumITCaseBase.java b/scm-webapp/src/test/java/sonia/scm/selenium/SeleniumITCaseBase.java
new file mode 100644
index 0000000000..fde04d9cad
--- /dev/null
+++ b/scm-webapp/src/test/java/sonia/scm/selenium/SeleniumITCaseBase.java
@@ -0,0 +1,71 @@
+/**
+ * Copyright (c) 2014, Sebastian Sdorra
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of SCM-Manager; nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * http://bitbucket.org/sdorra/scm-manager
+ *
+ */
+package sonia.scm.selenium;
+
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.openqa.selenium.WebDriver;
+import org.openqa.selenium.firefox.FirefoxDriver;
+
+/**
+ * Base class for selenium integration tests.
+ *
+ * @author Sebastian Sdorra
+ */
+public class SeleniumITCaseBase {
+
+ /**
+ * Selenium test driver.
+ */
+ protected static WebDriver driver;
+
+ /**
+ * Setup selenium test driver.
+ */
+ @BeforeClass
+ public static void setUpDriver() {
+ // DesiredCapabilities capa = DesiredCapabilities.chrome();
+ // capa.setBrowserName("firefox");
+ // capa.setPlatform(Platform.ANY);
+ // RemoteWebDriver driver = new RemoteWebDriver(new URL("http://localhost:4444/wd/hub"), capa);
+
+ driver = new FirefoxDriver();
+ driver.get("http://localhost:8082/scm/index.html");
+ }
+
+ /**
+ * Closes the selenium test driver.
+ */
+ @AfterClass
+ public static void tearDownDriver() {
+ driver.close();
+ }
+}
diff --git a/scm-webapp/src/test/java/sonia/scm/selenium/SeleniumTestBase.java b/scm-webapp/src/test/java/sonia/scm/selenium/SeleniumTestBase.java
deleted file mode 100644
index 1ae5e86b3d..0000000000
--- a/scm-webapp/src/test/java/sonia/scm/selenium/SeleniumTestBase.java
+++ /dev/null
@@ -1,271 +0,0 @@
-/**
- * Copyright (c) 2010, Sebastian Sdorra
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- * 3. Neither the name of SCM-Manager; nor the names of its
- * contributors may be used to endorse or promote products derived from this
- * software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
- * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * http://bitbucket.org/sdorra/scm-manager
- *
- */
-
-
-package sonia.scm.selenium;
-
-//~--- non-JDK imports --------------------------------------------------------
-
-import com.google.common.io.Files;
-
-import org.junit.After;
-import org.junit.Before;
-
-import org.openqa.selenium.By;
-import org.openqa.selenium.OutputType;
-import org.openqa.selenium.TakesScreenshot;
-import org.openqa.selenium.WebDriver;
-import org.openqa.selenium.WebElement;
-import org.openqa.selenium.firefox.FirefoxDriver;
-import org.openqa.selenium.support.ui.ExpectedConditions;
-import org.openqa.selenium.support.ui.WebDriverWait;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import static org.junit.Assert.*;
-
-//~--- JDK imports ------------------------------------------------------------
-
-import java.io.File;
-import java.io.IOException;
-
-import java.util.concurrent.TimeUnit;
-
-/**
- *
- * @author Sebastian Sdorra
- */
-public class SeleniumTestBase
-{
-
- /**
- * the logger for SeleniumTestBase
- */
- private static final Logger logger =
- LoggerFactory.getLogger(SeleniumTestBase.class);
-
- //~--- methods --------------------------------------------------------------
-
- /**
- * Method description
- *
- *
- * @throws Exception
- */
- @After
- public void tearDown() throws Exception
- {
- driver.quit();
- }
-
- //~--- set methods ----------------------------------------------------------
-
- /**
- * Method description
- *
- *
- * @throws Exception
- */
- @Before
- public void setUp() throws Exception
- {
- driver = new FirefoxDriver();
- baseUrl = "http://localhost:8082/scm/";
- open("index.html");
- }
-
- //~--- methods --------------------------------------------------------------
-
- /**
- * Method description
- *
- *
- * @param username
- * @param password
- */
- protected void login(String username, String password)
- {
- type("input[name=username]", username);
- type("input[name=password]", password);
- waitAndClick("#loginButton button");
-
- String ue = waitForPresence("#scm-userinfo-tip").getText();
-
- assertEquals(username, ue);
- }
-
- /**
- * Method description
- *
- */
- protected void logout()
- {
- waitAndClick("#navLogout a");
- }
-
- /**
- * Method description
- *
- *
- * @param url
- */
- protected void open(String url)
- {
- driver.get(baseUrl + url);
- pause(500, TimeUnit.MILLISECONDS);
- }
-
- /**
- * Method description
- *
- *
- * @param value
- * @param unit
- */
- protected void pause(int value, TimeUnit unit)
- {
- driver.manage().timeouts().implicitlyWait(value, unit);
- }
-
- /**
- * Method description
- *
- *
- * @param target
- */
- protected void screenshot(String target)
- {
- screenshot(new File(target));
- }
-
- /**
- * Method description
- *
- *
- * @param target
- */
- protected void screenshot(File target)
- {
- try
- {
- File scrFile =
- ((TakesScreenshot) driver).getScreenshotAs(OutputType.FILE);
-
- Files.copy(scrFile, target);
- }
- catch (IOException ex)
- {
- logger.error("could not create screenshot", ex);
- }
- }
-
- /**
- * Method description
- *
- *
- * @param cssSelector
- *
- * @return
- */
- protected WebElement select(String cssSelector)
- {
- WebElement element = driver.findElement(By.cssSelector(cssSelector));
-
- assertNotNull(element);
-
- return element;
- }
-
- /**
- * Method description
- *
- *
- * @param cssLocator
- * @param value
- */
- protected void type(String cssLocator, String value)
- {
- select(cssLocator).clear();
- select(cssLocator).sendKeys(value);
- }
-
- /**
- * Method description
- *
- *
- * @param query
- */
- protected void waitAndClick(String query)
- {
- waitToBeClickable(query).click();
- }
-
- /**
- * Method description
- *
- *
- * @param query
- *
- * @return
- */
- protected WebElement waitForPresence(String query)
- {
- WebDriverWait wait = new WebDriverWait(driver, 5);
-
- return wait.until(
- ExpectedConditions.presenceOfElementLocated(By.cssSelector(query)));
- }
-
- /**
- * Method description
- *
- *
- * @param query
- *
- * @return
- */
- protected WebElement waitToBeClickable(String query)
- {
- WebDriverWait wait = new WebDriverWait(driver, 5);
-
- return wait.until(
- ExpectedConditions.elementToBeClickable(By.cssSelector(query)));
- }
-
- //~--- fields ---------------------------------------------------------------
-
- /** Field description */
- protected WebDriver driver;
-
- /** Field description */
- private String baseUrl;
-}
diff --git a/scm-webapp/src/test/java/sonia/scm/selenium/page/BasePage.java b/scm-webapp/src/test/java/sonia/scm/selenium/page/BasePage.java
new file mode 100644
index 0000000000..28c27457a8
--- /dev/null
+++ b/scm-webapp/src/test/java/sonia/scm/selenium/page/BasePage.java
@@ -0,0 +1,168 @@
+/**
+ * Copyright (c) 2014, Sebastian Sdorra
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of SCM-Manager; nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * http://bitbucket.org/sdorra/scm-manager
+ *
+ */
+package sonia.scm.selenium.page;
+
+import com.google.common.base.Throwables;
+import com.google.common.io.Files;
+import java.io.File;
+import java.io.IOException;
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+import org.openqa.selenium.By;
+import org.openqa.selenium.OutputType;
+import org.openqa.selenium.TakesScreenshot;
+import org.openqa.selenium.WebDriver;
+import org.openqa.selenium.WebElement;
+import org.openqa.selenium.support.ui.ExpectedConditions;
+import org.openqa.selenium.support.ui.WebDriverWait;
+
+/**
+ * Abstract selenium base page.
+ *
+ * @author Sebastian Sdorra
+ *
+ * @param
concrete page implementation
+ */
+public abstract class BasePage
{
+
+ /**
+ * Selenium test driver.
+ */
+ protected final WebDriver driver;
+
+ /**
+ * Constructs a new base page.
+ *
+ * @param driver selenium test driver
+ */
+ protected BasePage(WebDriver driver) {
+ this.driver = driver;
+ }
+
+ /**
+ * Performs a {@link Thread#sleep(long)} for the given timeout.
+ *
+ * @param time timeout
+ * @param unit time unit of timeout
+ */
+ protected void sleep(long time, TimeUnit unit) {
+ try {
+ unit.sleep(time);
+ } catch (InterruptedException ex) {
+ throw Throwables.propagate(ex);
+ }
+ }
+
+ /**
+ * Wait for the element until it is clickable.
+ *
+ * @param by element selector
+ *
+ * @return web element
+ */
+ protected WebElement waitToBeClickable(By by){
+ return waitToBeClickable(driver.findElement(by));
+ }
+
+ /**
+ * Waits for the element until it is clickable.
+ *
+ * @param element web element
+ *
+ * @return web element
+ */
+ protected WebElement waitToBeClickable(WebElement element) {
+ WebDriverWait wait = new WebDriverWait(driver, 5);
+
+ return wait.until(ExpectedConditions.elementToBeClickable(element));
+ }
+
+ /**
+ * Waits until the element is present.
+ *
+ * @param by element locator
+ *
+ * @return web element
+ */
+ protected WebElement waitFor(By by){
+ WebDriverWait wait = new WebDriverWait(driver, 1);
+ return wait.until(ExpectedConditions.presenceOfElementLocated(by));
+ }
+
+ /**
+ * Waits until the elements are present.
+ *
+ * @param by element selector
+ *
+ * @return list of web elements
+ */
+ protected List waitForAll(By by){
+ WebDriverWait wait = new WebDriverWait(driver, 1);
+ return wait.until(ExpectedConditions.presenceOfAllElementsLocatedBy(by));
+ }
+
+ /**
+ * Creates a screenshot of the current browser content and stores it at the given path.
+ *
+ * @param target target file path
+ *
+ * @return {@code this}
+ */
+ public P screenshot(String target) {
+ return screenshot(new File(target));
+ }
+
+ /**
+ * Creates a screenshot of the current browser content and stores it at the file.
+ *
+ * @param target target file
+ *
+ * @return {@code this}
+ */
+ public P screenshot(File target) {
+ try {
+ File scrFile = ((TakesScreenshot) driver).getScreenshotAs(OutputType.FILE);
+
+ Files.copy(scrFile, target);
+ } catch (IOException ex) {
+ throw Throwables.propagate(ex);
+ }
+ return self();
+ }
+
+ /**
+ * Returns {@code this}.
+ *
+ * @return {@code this}
+ */
+ protected abstract P self();
+
+}
diff --git a/scm-webapp/src/test/java/sonia/scm/selenium/page/LoginPage.java b/scm-webapp/src/test/java/sonia/scm/selenium/page/LoginPage.java
new file mode 100644
index 0000000000..cf9d231510
--- /dev/null
+++ b/scm-webapp/src/test/java/sonia/scm/selenium/page/LoginPage.java
@@ -0,0 +1,89 @@
+/**
+ * Copyright (c) 2014, Sebastian Sdorra
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of SCM-Manager; nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * http://bitbucket.org/sdorra/scm-manager
+ *
+ */
+package sonia.scm.selenium.page;
+
+import java.util.concurrent.TimeUnit;
+import org.openqa.selenium.WebDriver;
+import org.openqa.selenium.WebElement;
+import org.openqa.selenium.support.FindBy;
+
+/**
+ * Page object for the scm-manager login page.
+ *
+ * @author Sebastian Sdorra
+ */
+public class LoginPage extends BasePage {
+
+ @FindBy(css = "input[name=username]")
+ private WebElement usernameInput;
+
+ @FindBy(css = "input[name=password]")
+ private WebElement passwordInput;
+
+ @FindBy(css = "#loginButton button")
+ private WebElement loginButton;
+
+ /**
+ * Constructs a new page. This constructor should only be called from {@link Pages}.
+ *
+ * @param driver selenium test driver
+ */
+ LoginPage(WebDriver driver) {
+ super(driver);
+ }
+
+ @Override
+ protected LoginPage self() {
+ return this;
+ }
+
+ /**
+ * Authenticates the user and returns the {@link MainPage}.
+ *
+ * @param username username
+ * @param password password
+ *
+ * @return {@link MainPage} after successful authentication
+ */
+ public MainPage login(String username, String password) {
+ usernameInput.clear();
+ usernameInput.sendKeys(username);
+
+ passwordInput.clear();
+ passwordInput.sendKeys(password);
+
+ sleep(250, TimeUnit.MILLISECONDS);
+
+ waitToBeClickable(loginButton).click();
+
+ return Pages.get(driver, MainPage.class);
+ }
+}
diff --git a/scm-webapp/src/test/java/sonia/scm/selenium/page/MainPage.java b/scm-webapp/src/test/java/sonia/scm/selenium/page/MainPage.java
new file mode 100644
index 0000000000..42fc807e67
--- /dev/null
+++ b/scm-webapp/src/test/java/sonia/scm/selenium/page/MainPage.java
@@ -0,0 +1,95 @@
+/**
+ * Copyright (c) 2014, Sebastian Sdorra
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of SCM-Manager; nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * http://bitbucket.org/sdorra/scm-manager
+ *
+ */
+package sonia.scm.selenium.page;
+
+import org.openqa.selenium.WebDriver;
+import org.openqa.selenium.WebElement;
+import org.openqa.selenium.support.FindBy;
+
+/**
+ * Page object for scm-manager's main page.
+ *
+ * @author Sebastian Sdorra
+ */
+public class MainPage extends BasePage {
+
+ @FindBy(css = "#navLogout a")
+ private WebElement logoutLink;
+
+ @FindBy(linkText = "Repositories")
+ private WebElement repositoriesLink;
+
+ @FindBy(css = "#scm-userinfo-tip")
+ private WebElement userInfoTip;
+
+ /**
+ * Constructs a new page. This constructor should only be called from {@link Pages}.
+ *
+ * @param driver selenium test driver
+ */
+ MainPage(WebDriver driver) {
+ super(driver);
+ }
+
+ @Override
+ protected MainPage self() {
+ return this;
+ }
+
+ /**
+ * Returns the name of the current authenticated user from the user info tip.
+ *
+ * @return name of the current authenticated user
+ */
+ public String getUserInfo(){
+ return userInfoTip.getText();
+ }
+
+ /**
+ * Navigates to the repositories page and returns the page object for this page.
+ *
+ * @return page object for repositories page
+ */
+ public RepositoriesPage repositories(){
+ repositoriesLink.click();
+ return Pages.get(driver, RepositoriesPage.class);
+ }
+
+ /**
+ * Logs the current user out.
+ *
+ * @return page object for the login
+ */
+ public LoginPage logout(){
+ waitToBeClickable(logoutLink).click();
+ return Pages.get(driver, LoginPage.class);
+ }
+}
diff --git a/scm-webapp/src/test/java/sonia/scm/selenium/page/Pages.java b/scm-webapp/src/test/java/sonia/scm/selenium/page/Pages.java
new file mode 100644
index 0000000000..b8d85ea08b
--- /dev/null
+++ b/scm-webapp/src/test/java/sonia/scm/selenium/page/Pages.java
@@ -0,0 +1,113 @@
+/**
+ * Copyright (c) 2014, Sebastian Sdorra
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of SCM-Manager; nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * http://bitbucket.org/sdorra/scm-manager
+ *
+ */
+package sonia.scm.selenium.page;
+
+import com.google.common.base.Throwables;
+import com.google.common.collect.Lists;
+import java.lang.reflect.Constructor;
+import java.util.Arrays;
+import java.util.List;
+import org.openqa.selenium.By;
+import org.openqa.selenium.SearchContext;
+import org.openqa.selenium.WebDriver;
+import org.openqa.selenium.WebElement;
+import org.openqa.selenium.support.PageFactory;
+import org.openqa.selenium.support.pagefactory.DefaultElementLocatorFactory;
+import org.openqa.selenium.support.ui.ExpectedConditions;
+import org.openqa.selenium.support.ui.WebDriverWait;
+
+/**
+ * Helper class for selenium page objects.
+ *
+ * @author Sebastian Sdorra
+ */
+public final class Pages {
+
+ private Pages() {
+ }
+
+ /**
+ * Creates an instance of the given page object.
+ *
+ * @param page object type
+ * @param driver selenium driver
+ * @param clazz page object type
+ * @param otherArguments other constructor arguments
+ *
+ * @return instance of page object
+ */
+ public static T get(WebDriver driver, Class clazz, Object... otherArguments)
+ {
+ T page = null;
+ try {
+ List> argumentTypes = Lists.newArrayList();
+ argumentTypes.add(WebDriver.class);
+ for (Object argument : otherArguments) {
+ argumentTypes.add(argument.getClass());
+ }
+
+ List