From b91f71cfabbc11a5c411a39ab2427b76548c669a Mon Sep 17 00:00:00 2001
From: anttil <anttil>
Date: Fri, 31 Aug 2012 11:32:32 +0000
Subject: [PATCH] SWE-2 / SP-263: Make screenshots available in Hudson

SVN: 26490
---
 .../cisd/openbis/uitest/SpaceTest.java        |   2 +-
 .../cisd/openbis/uitest/infra/Help.java       |  57 -------
 .../cisd/openbis/uitest/infra/PageProxy.java  |  98 ++++++++++++
 .../uitest/infra/ScreenShotDecorator.java     |  14 +-
 .../openbis/uitest/infra/ScreenShotProxy.java |  58 ++++---
 .../openbis/uitest/infra/ScreenShotter.java   |  52 ++++++
 .../openbis/uitest/infra/SeleniumTest.java    | 150 +++++++-----------
 .../openbis/uitest/page/AddSpaceDialog.java   |  20 ++-
 .../cisd/openbis/uitest/page/AdminMenu.java   |  15 +-
 .../cisd/openbis/uitest/page/HomePage.java    |  20 ++-
 .../uitest/page/InvalidPasswordDialog.java    |  16 +-
 .../cisd/openbis/uitest/page/LoginPage.java   |  23 ++-
 .../cisd/openbis/uitest/page/Page.java        |  67 +++++++-
 .../openbis/uitest/page/SpaceBrowser.java     |  25 ++-
 14 files changed, 366 insertions(+), 251 deletions(-)
 delete mode 100644 ui-test/source/java/ch/systemsx/cisd/openbis/uitest/infra/Help.java
 create mode 100644 ui-test/source/java/ch/systemsx/cisd/openbis/uitest/infra/PageProxy.java
 create mode 100644 ui-test/source/java/ch/systemsx/cisd/openbis/uitest/infra/ScreenShotter.java

diff --git a/ui-test/source/java/ch/systemsx/cisd/openbis/uitest/SpaceTest.java b/ui-test/source/java/ch/systemsx/cisd/openbis/uitest/SpaceTest.java
index d1cb1e1563c..f9f52e32be2 100644
--- a/ui-test/source/java/ch/systemsx/cisd/openbis/uitest/SpaceTest.java
+++ b/ui-test/source/java/ch/systemsx/cisd/openbis/uitest/SpaceTest.java
@@ -13,7 +13,7 @@ import ch.systemsx.cisd.openbis.uitest.page.SpaceBrowser;
 
 public class SpaceTest extends SeleniumTest
 {
-    @Test(enabled = false)
+    @Test
     public void newSpaceIsListedInSpaceBrowser() throws Exception
     {
         String spaceName = "selenium-spacetest-" + UUID.randomUUID();
diff --git a/ui-test/source/java/ch/systemsx/cisd/openbis/uitest/infra/Help.java b/ui-test/source/java/ch/systemsx/cisd/openbis/uitest/infra/Help.java
deleted file mode 100644
index 81312c4c919..00000000000
--- a/ui-test/source/java/ch/systemsx/cisd/openbis/uitest/infra/Help.java
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Copyright 2012 ETH Zuerich, CISD
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package ch.systemsx.cisd.openbis.uitest.infra;
-
-import org.openqa.selenium.By;
-import org.openqa.selenium.WebDriver;
-import org.openqa.selenium.WebElement;
-import org.openqa.selenium.support.ui.ExpectedCondition;
-import org.openqa.selenium.support.ui.WebDriverWait;
-
-import static org.hamcrest.MatcherAssert.assertThat;
-import static org.hamcrest.Matchers.is;
-import static org.hamcrest.Matchers.notNullValue;
-
-public class Help
-{
-
-    public static WebElement findElementWithText(String text, By by) {
-        WebElement element = null;
-        for (WebElement e : SeleniumTest.driver.findElements(by)) {
-            if (e.getText().equals(text)) {
-                element = e;
-                break;
-            }
-        }
-        assertThat(element, is(notNullValue()));
-        
-        return (WebElement) ScreenShotProxy.newInstance(element);    
-    }
-    
-    public static void wait(final By by) {
-
-        ExpectedCondition<?> condition =  new ExpectedCondition<WebElement>() {
-            @Override
-            public WebElement apply(WebDriver d) {
-                return d.findElement(by);
-            }
-        };
-        
-        new WebDriverWait(SeleniumTest.driver, 10).until(condition);
-    }
-    
-}
diff --git a/ui-test/source/java/ch/systemsx/cisd/openbis/uitest/infra/PageProxy.java b/ui-test/source/java/ch/systemsx/cisd/openbis/uitest/infra/PageProxy.java
new file mode 100644
index 00000000000..7d5e750e56a
--- /dev/null
+++ b/ui-test/source/java/ch/systemsx/cisd/openbis/uitest/infra/PageProxy.java
@@ -0,0 +1,98 @@
+/*
+ * Copyright 2012 ETH Zuerich, CISD
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package ch.systemsx.cisd.openbis.uitest.infra;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+
+import javassist.util.proxy.MethodHandler;
+import javassist.util.proxy.ProxyFactory;
+
+import org.openqa.selenium.StaleElementReferenceException;
+import org.openqa.selenium.support.PageFactory;
+
+import ch.systemsx.cisd.openbis.uitest.page.Page;
+
+/**
+ * @author anttil
+ */
+public class PageProxy
+{
+    private ScreenShotter shotter;
+
+    public <T extends SeleniumTest> PageProxy(ScreenShotter shotter)
+    {
+        this.shotter = shotter;
+    }
+
+    @SuppressWarnings("unchecked")
+    public <T extends Page> T get(Class<T> clazz)
+    {
+
+        ProxyFactory factory = new ProxyFactory();
+        factory.setSuperclass(clazz);
+
+        MethodHandler handler = new MethodHandler()
+            {
+                @Override
+                public Object invoke(Object self, Method thisMethod, Method proceed, Object[] args)
+                        throws Throwable
+                {
+                    try
+                    {
+                        return proceed.invoke(self, args);
+                    } catch (InvocationTargetException e)
+                    {
+                        if (e.getTargetException() instanceof StaleElementReferenceException)
+                        {
+                            PageFactory.initElements(new ScreenShotDecorator(shotter), self);
+                            return proceed.invoke(self, args);
+                        } else
+                        {
+                            throw e.getTargetException();
+                        }
+                    }
+                }
+            };
+
+        T t;
+        try
+        {
+            t = (T) factory.create(new Class<?>[0], new Object[0], handler);
+        } catch (IllegalArgumentException ex1)
+        {
+            throw new RuntimeException(ex1);
+        } catch (NoSuchMethodException ex1)
+        {
+            throw new RuntimeException(ex1);
+        } catch (InstantiationException ex1)
+        {
+            throw new RuntimeException(ex1);
+        } catch (IllegalAccessException ex1)
+        {
+            throw new RuntimeException(ex1);
+        } catch (InvocationTargetException ex1)
+        {
+            throw new RuntimeException(ex1);
+        }
+
+        PageFactory.initElements(new ScreenShotDecorator(shotter), t);
+        t.setPageProxy(this);
+        t.setScreenShotter(shotter);
+        return t;
+    }
+}
diff --git a/ui-test/source/java/ch/systemsx/cisd/openbis/uitest/infra/ScreenShotDecorator.java b/ui-test/source/java/ch/systemsx/cisd/openbis/uitest/infra/ScreenShotDecorator.java
index c56d081ccb3..bc777aa208e 100644
--- a/ui-test/source/java/ch/systemsx/cisd/openbis/uitest/infra/ScreenShotDecorator.java
+++ b/ui-test/source/java/ch/systemsx/cisd/openbis/uitest/infra/ScreenShotDecorator.java
@@ -26,18 +26,24 @@ public class ScreenShotDecorator implements FieldDecorator
 {
 
     private DefaultFieldDecorator dec;
-    public ScreenShotDecorator() {
+
+    private ScreenShotter shotter;
+
+    public ScreenShotDecorator(ScreenShotter shotter)
+    {
         this.dec = new DefaultFieldDecorator(new DefaultElementLocatorFactory(SeleniumTest.driver));
+        this.shotter = shotter;
     }
-    
+
     @Override
     public Object decorate(ClassLoader loader, Field field)
     {
         Object o = this.dec.decorate(loader, field);
-        if (o == null) {
+        if (o == null)
+        {
             return null;
         }
-        return ScreenShotProxy.newInstance(o);
+        return ScreenShotProxy.newInstance(o, shotter);
     }
 
 }
diff --git a/ui-test/source/java/ch/systemsx/cisd/openbis/uitest/infra/ScreenShotProxy.java b/ui-test/source/java/ch/systemsx/cisd/openbis/uitest/infra/ScreenShotProxy.java
index e3366813154..c5873f2687a 100644
--- a/ui-test/source/java/ch/systemsx/cisd/openbis/uitest/infra/ScreenShotProxy.java
+++ b/ui-test/source/java/ch/systemsx/cisd/openbis/uitest/infra/ScreenShotProxy.java
@@ -16,66 +16,64 @@
 
 package ch.systemsx.cisd.openbis.uitest.infra;
 
-import java.io.File;
-import java.io.IOException;
 import java.lang.reflect.InvocationHandler;
 import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
 import java.util.Collection;
-import java.util.Date;
 import java.util.HashSet;
 
-import org.apache.commons.io.FileUtils;
-import org.openqa.selenium.OutputType;
-import org.openqa.selenium.TakesScreenshot;
-
-public class ScreenShotProxy implements InvocationHandler 
+public class ScreenShotProxy implements InvocationHandler
 {
 
     private Object obj;
 
-    public static Object newInstance(Object obj) {
+    private ScreenShotter shotter;
+
+    public static Object newInstance(Object obj, ScreenShotter shotter)
+    {
         Collection<Class<?>> interfaces = new HashSet<Class<?>>();
-        
+
         Class<?> current = obj.getClass();
-        while (current != null) {
-            for (Class<?> c : current.getInterfaces()) {
+        while (current != null)
+        {
+            for (Class<?> c : current.getInterfaces())
+            {
                 interfaces.add(c);
             }
             current = current.getSuperclass();
         }
-        
+
         return java.lang.reflect.Proxy.newProxyInstance(
-            obj.getClass().getClassLoader(),
-            interfaces.toArray(new Class<?>[0]),
-            new ScreenShotProxy(obj));
+                obj.getClass().getClassLoader(),
+                interfaces.toArray(new Class<?>[0]),
+                new ScreenShotProxy(obj, shotter));
     }
 
-    private ScreenShotProxy(Object obj) {
+    private ScreenShotProxy(Object obj, ScreenShotter shotter)
+    {
         this.obj = obj;
+        this.shotter = shotter;
     }
 
     @Override
     public Object invoke(Object proxy, Method m, Object[] args) throws Throwable
     {
         Object result;
-        try {
-            if (m.getName().equals("click") || m.getName().equals("sendKeys")) {
-                screenshot();
+        try
+        {
+            if (m.getName().equals("click") || m.getName().equals("sendKeys"))
+            {
+                shotter.screenshot();
             }
             result = m.invoke(this.obj, args);
-        } catch (InvocationTargetException e) {
+        } catch (InvocationTargetException e)
+        {
             throw e.getTargetException();
-        } catch (Exception e) {
+        } catch (Exception e)
+        {
             throw new RuntimeException("unexpected invocation exception: " +
-                           e.getMessage());
+                    e.getMessage());
         }
-        return result;    
+        return result;
     }
-    
-    public static void screenshot() throws IOException {
-        File file = ((TakesScreenshot)SeleniumTest.driver).getScreenshotAs(OutputType.FILE);
-        FileUtils.copyFile(file, new File("/tmp/screenshot-"+ new Date().getTime()+".png"));        
-    }
-
 }
diff --git a/ui-test/source/java/ch/systemsx/cisd/openbis/uitest/infra/ScreenShotter.java b/ui-test/source/java/ch/systemsx/cisd/openbis/uitest/infra/ScreenShotter.java
new file mode 100644
index 00000000000..ae4704117a0
--- /dev/null
+++ b/ui-test/source/java/ch/systemsx/cisd/openbis/uitest/infra/ScreenShotter.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2012 ETH Zuerich, CISD
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package ch.systemsx.cisd.openbis.uitest.infra;
+
+import java.io.File;
+import java.io.IOException;
+
+import org.apache.commons.io.FileUtils;
+import org.openqa.selenium.OutputType;
+import org.openqa.selenium.TakesScreenshot;
+
+/**
+ * @author anttil
+ */
+public class ScreenShotter
+{
+    private String directory;
+
+    private TakesScreenshot driver;
+
+    private int counter;
+
+    public ScreenShotter(TakesScreenshot driver, String directory)
+    {
+        this.driver = driver;
+        this.directory = directory;
+        this.counter = 1;
+    }
+
+    public void screenshot() throws IOException
+    {
+        File file = driver.getScreenshotAs(OutputType.FILE);
+        FileUtils.copyFile(file, new File(directory + "/screenshot_"
+                + String.format("%4s", counter).replace(" ", "0") + ".png"));
+        counter++;
+    }
+
+}
diff --git a/ui-test/source/java/ch/systemsx/cisd/openbis/uitest/infra/SeleniumTest.java b/ui-test/source/java/ch/systemsx/cisd/openbis/uitest/infra/SeleniumTest.java
index d0b9fc5a36c..ac976dda454 100644
--- a/ui-test/source/java/ch/systemsx/cisd/openbis/uitest/infra/SeleniumTest.java
+++ b/ui-test/source/java/ch/systemsx/cisd/openbis/uitest/infra/SeleniumTest.java
@@ -16,27 +16,25 @@
 
 package ch.systemsx.cisd.openbis.uitest.infra;
 
+import java.io.File;
 import java.io.IOException;
 import java.lang.reflect.Field;
-import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
 import java.util.concurrent.TimeUnit;
 
-import javassist.util.proxy.MethodHandler;
-import javassist.util.proxy.ProxyFactory;
-
 import org.hamcrest.Description;
 import org.hamcrest.Matcher;
 import org.hamcrest.TypeSafeMatcher;
-import org.openqa.selenium.StaleElementReferenceException;
+import org.openqa.selenium.NoAlertPresentException;
+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.FindBy;
-import org.openqa.selenium.support.PageFactory;
 import org.testng.annotations.AfterMethod;
 import org.testng.annotations.AfterSuite;
 import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.BeforeSuite;
 
 import ch.systemsx.cisd.openbis.uitest.page.LoginPage;
 import ch.systemsx.cisd.openbis.uitest.page.Page;
@@ -44,119 +42,80 @@ import ch.systemsx.cisd.openbis.uitest.page.SpaceBrowser;
 
 public abstract class SeleniumTest
 {
-    public static final WebDriver driver = new FirefoxDriver();
+    public static WebDriver driver;
+
+    protected PageProxy pageProxy;
+
+    protected LoginPage loginPage;
+
+    private ScreenShotter shotter;
+
+    @BeforeSuite
+    public void initWebDriver()
     {
+        driver = new FirefoxDriver();
         driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
+        delete(new File("targets/selenium"));
     }
 
-    protected LoginPage loginPage;
+    @AfterSuite
+    public void closeBrowser()
+    {
+        driver.quit();
+    }
 
     @BeforeMethod
+    public void initPageProxy(Method method)
+    {
+        this.shotter =
+                new ScreenShotter((TakesScreenshot) driver, "targets/selenium/"
+                        + this.getClass().getSimpleName() + "/" + method.getName());
+        this.pageProxy = new PageProxy(shotter);
+    }
+
+    @BeforeMethod(dependsOnMethods = "initPageProxy")
     public void gotoLoginPage()
     {
         driver.manage().deleteAllCookies();
         driver.get("https://sprint-openbis.ethz.ch/openbis/");
+        try
+        {
+            driver.switchTo().alert().accept();
+        } catch (NoAlertPresentException e)
+        {
+        }
         this.loginPage = get(LoginPage.class);
     }
 
     @AfterMethod
     public void takeScreenShot() throws IOException
     {
-        ScreenShotProxy.screenshot();
+        shotter.screenshot();
     }
 
-    @AfterSuite
-    public void closeBrowser()
+    public <T extends Page> T get(Class<T> clazz)
     {
-        driver.quit();
+        return this.pageProxy.get(clazz);
     }
 
-    @SuppressWarnings("unchecked")
-    public static <T extends Page> T get(Class<T> clazz)
+    protected WebDriver browser()
     {
-
-        ProxyFactory factory = new ProxyFactory();
-        factory.setSuperclass(clazz);
-
-        MethodHandler handler = new MethodHandler()
-            {
-                @Override
-                public Object invoke(Object self, Method thisMethod, Method proceed, Object[] args)
-                        throws Throwable
-                {
-                    try
-                    {
-                        return proceed.invoke(self, args);
-                    } catch (InvocationTargetException e)
-                    {
-                        if (e.getTargetException() instanceof StaleElementReferenceException)
-                        {
-                            PageFactory.initElements(new ScreenShotDecorator(), self);
-                            return proceed.invoke(self, args);
-                        } else
-                        {
-                            throw e.getTargetException();
-                        }
-                    }
-                }
-            };
-
-        T t;
-        try
-        {
-            t = (T) factory.create(new Class<?>[]
-                { WebDriver.class }, new Object[]
-                { driver }, handler);
-        } catch (IllegalArgumentException ex)
-        {
-            throw new RuntimeException(ex);
-        } catch (SecurityException ex)
-        {
-            throw new RuntimeException(ex);
-        } catch (InstantiationException ex)
-        {
-            throw new RuntimeException(ex);
-        } catch (IllegalAccessException ex)
-        {
-            throw new RuntimeException(ex);
-        } catch (InvocationTargetException ex)
-        {
-            throw new RuntimeException(ex);
-        } catch (NoSuchMethodException ex)
-        {
-            try
-            {
-                t = (T) factory.create(new Class<?>[0], new Object[0], handler);
-            } catch (IllegalArgumentException ex1)
-            {
-                throw new RuntimeException(ex1);
-            } catch (NoSuchMethodException ex1)
-            {
-                throw new RuntimeException(ex1);
-            } catch (InstantiationException ex1)
-            {
-                throw new RuntimeException(ex1);
-            } catch (IllegalAccessException ex1)
-            {
-                throw new RuntimeException(ex1);
-            } catch (InvocationTargetException ex1)
-            {
-                throw new RuntimeException(ex1);
-            }
-
-        }
-        PageFactory.initElements(new ScreenShotDecorator(), t);
-        return t;
+        return driver;
     }
 
-    protected static WebDriver browser()
+    private void delete(File f)
     {
-        return driver;
+        if (f.isDirectory())
+        {
+            for (File c : f.listFiles())
+                delete(c);
+        }
+        f.delete();
     }
 
-    protected static Matcher<WebDriver> isShowing(Class<? extends Page> pageClass)
+    protected Matcher<WebDriver> isShowing(Class<? extends Page> pageClass)
     {
-        return new PageMatcher(pageClass);
+        return new PageMatcher(pageClass, pageProxy);
     }
 
     private static class PageMatcher extends TypeSafeMatcher<WebDriver>
@@ -164,9 +123,12 @@ public abstract class SeleniumTest
 
         private Class<? extends Page> pageClass;
 
-        public PageMatcher(Class<? extends Page> pageClass)
+        private PageProxy pageProxy;
+
+        public PageMatcher(Class<? extends Page> pageClass, PageProxy pageProxy)
         {
             this.pageClass = pageClass;
+            this.pageProxy = pageProxy;
         }
 
         @Override
@@ -178,7 +140,7 @@ public abstract class SeleniumTest
         @Override
         public boolean matchesSafely(WebDriver ignore)
         {
-            Object o = get(pageClass);
+            Object o = pageProxy.get(pageClass);
             for (Field field : pageClass.getDeclaredFields())
             {
                 if ((field.getAnnotation(FindBy.class) != null)
@@ -209,7 +171,7 @@ public abstract class SeleniumTest
 
     }
 
-    protected static Matcher<SpaceBrowser> listsSpace(String spaceName)
+    protected Matcher<SpaceBrowser> listsSpace(String spaceName)
     {
         return new SpaceMatcher(spaceName);
     }
diff --git a/ui-test/source/java/ch/systemsx/cisd/openbis/uitest/page/AddSpaceDialog.java b/ui-test/source/java/ch/systemsx/cisd/openbis/uitest/page/AddSpaceDialog.java
index 63643c587b8..ec06f3de45e 100644
--- a/ui-test/source/java/ch/systemsx/cisd/openbis/uitest/page/AddSpaceDialog.java
+++ b/ui-test/source/java/ch/systemsx/cisd/openbis/uitest/page/AddSpaceDialog.java
@@ -20,19 +20,17 @@ import org.openqa.selenium.By;
 import org.openqa.selenium.WebElement;
 import org.openqa.selenium.support.FindBy;
 
-import ch.systemsx.cisd.openbis.uitest.infra.Help;
-import ch.systemsx.cisd.openbis.uitest.infra.SeleniumTest;
-
-public class AddSpaceDialog implements Page
+public class AddSpaceDialog extends Page
 {
-    
-    @FindBy(id="openbis_dialog-code-field-input")
+
+    @FindBy(id = "openbis_dialog-code-field-input")
     private WebElement code;
 
-    public SpaceBrowser addSpace(String name, String description) {
+    public SpaceBrowser addSpace(String name, String description)
+    {
         this.code.sendKeys(name);
-        Help.findElementWithText("Save", By.className("x-btn-text")).click();
-        Help.wait(By.xpath("//div[.=\""+name.toUpperCase()+"\"]"));
-        return SeleniumTest.get(SpaceBrowser.class);
-    }    
+        findElementWithText("Save", By.className("x-btn-text")).click();
+        wait(By.xpath("//div[.=\"" + name.toUpperCase() + "\"]"));
+        return get(SpaceBrowser.class);
+    }
 }
diff --git a/ui-test/source/java/ch/systemsx/cisd/openbis/uitest/page/AdminMenu.java b/ui-test/source/java/ch/systemsx/cisd/openbis/uitest/page/AdminMenu.java
index f549b9a3aab..c4a6e80e122 100644
--- a/ui-test/source/java/ch/systemsx/cisd/openbis/uitest/page/AdminMenu.java
+++ b/ui-test/source/java/ch/systemsx/cisd/openbis/uitest/page/AdminMenu.java
@@ -19,17 +19,16 @@ package ch.systemsx.cisd.openbis.uitest.page;
 import org.openqa.selenium.WebElement;
 import org.openqa.selenium.support.FindBy;
 
-import ch.systemsx.cisd.openbis.uitest.infra.SeleniumTest;
-
-public class AdminMenu implements Page
+public class AdminMenu extends Page
 {
 
-    @FindBy(id="openbis_top-menu_ADMINISTRATION_MENU_MANAGE_GROUPS")
+    @FindBy(id = "openbis_top-menu_ADMINISTRATION_MENU_MANAGE_GROUPS")
     private WebElement spaces;
-     
-    public SpaceBrowser spaces() {
+
+    public SpaceBrowser spaces()
+    {
         spaces.click();
-        return SeleniumTest.get(SpaceBrowser.class);
+        return get(SpaceBrowser.class);
     }
-    
+
 }
diff --git a/ui-test/source/java/ch/systemsx/cisd/openbis/uitest/page/HomePage.java b/ui-test/source/java/ch/systemsx/cisd/openbis/uitest/page/HomePage.java
index f4d6aafd07b..719e2033805 100644
--- a/ui-test/source/java/ch/systemsx/cisd/openbis/uitest/page/HomePage.java
+++ b/ui-test/source/java/ch/systemsx/cisd/openbis/uitest/page/HomePage.java
@@ -21,23 +21,21 @@ import org.openqa.selenium.WebElement;
 import org.openqa.selenium.support.FindBy;
 
 import ch.systemsx.cisd.openbis.uitest.infra.NotAlwaysPresent;
-import ch.systemsx.cisd.openbis.uitest.infra.SeleniumTest;
 
-import static ch.systemsx.cisd.openbis.uitest.infra.Help.findElementWithText;
-
-public class HomePage implements Page
+public class HomePage extends Page
 {
-    
+
     @NotAlwaysPresent
-    @FindBy(id="just_something_that_is_not_there")
+    @FindBy(id = "just_something_that_is_not_there")
     private WebElement nonExistent;
-    
-    @FindBy(id="openbis_search-widget_text-field-input")
+
+    @FindBy(id = "openbis_search-widget_text-field-input")
     private WebElement searchTextBox;
-    
-    public AdminMenu adminMenu() {
+
+    public AdminMenu adminMenu()
+    {
         WebElement adminMenuButton = findElementWithText("Admin", By.className("x-btn-text"));
         adminMenuButton.click();
-        return SeleniumTest.get(AdminMenu.class);
+        return get(AdminMenu.class);
     }
 }
diff --git a/ui-test/source/java/ch/systemsx/cisd/openbis/uitest/page/InvalidPasswordDialog.java b/ui-test/source/java/ch/systemsx/cisd/openbis/uitest/page/InvalidPasswordDialog.java
index dbf0f8775e7..41fe77a19b9 100644
--- a/ui-test/source/java/ch/systemsx/cisd/openbis/uitest/page/InvalidPasswordDialog.java
+++ b/ui-test/source/java/ch/systemsx/cisd/openbis/uitest/page/InvalidPasswordDialog.java
@@ -18,15 +18,13 @@ package ch.systemsx.cisd.openbis.uitest.page;
 
 import org.openqa.selenium.By;
 
-import ch.systemsx.cisd.openbis.uitest.infra.Help;
-import ch.systemsx.cisd.openbis.uitest.infra.SeleniumTest;
-
-public class InvalidPasswordDialog implements Page
+public class InvalidPasswordDialog extends Page
 {
-    
-    public LoginPage dismiss() {
-        Help.findElementWithText("OK", By.className("x-btn-text")).click();
-        return SeleniumTest.get(LoginPage.class);
+
+    public LoginPage dismiss()
+    {
+        findElementWithText("OK", By.className("x-btn-text")).click();
+        return get(LoginPage.class);
     }
-    
+
 }
diff --git a/ui-test/source/java/ch/systemsx/cisd/openbis/uitest/page/LoginPage.java b/ui-test/source/java/ch/systemsx/cisd/openbis/uitest/page/LoginPage.java
index fefaaba080b..809f6d12be4 100644
--- a/ui-test/source/java/ch/systemsx/cisd/openbis/uitest/page/LoginPage.java
+++ b/ui-test/source/java/ch/systemsx/cisd/openbis/uitest/page/LoginPage.java
@@ -19,26 +19,25 @@ package ch.systemsx.cisd.openbis.uitest.page;
 import org.openqa.selenium.WebElement;
 import org.openqa.selenium.support.FindBy;
 
-import ch.systemsx.cisd.openbis.uitest.infra.SeleniumTest;
-
-public class LoginPage implements Page
+public class LoginPage extends Page
 {
 
-    @FindBy(id="openbis_login_username")
+    @FindBy(id = "openbis_login_username")
     private WebElement username;
-    
-    @FindBy(id="openbis_login_password")
+
+    @FindBy(id = "openbis_login_password")
     private WebElement password;
-    
-    @FindBy(id="openbis_login_submit")
+
+    @FindBy(id = "openbis_login_submit")
     private WebElement button;
-    
-    public HomePage loginAs(String user, String pwd) {
+
+    public HomePage loginAs(String user, String pwd)
+    {
         username.sendKeys(user);
         password.sendKeys(pwd);
         button.click();
 
-        return SeleniumTest.get(HomePage.class);
+        return get(HomePage.class);
     }
-    
+
 }
diff --git a/ui-test/source/java/ch/systemsx/cisd/openbis/uitest/page/Page.java b/ui-test/source/java/ch/systemsx/cisd/openbis/uitest/page/Page.java
index 07f12e255de..f2afdd8a0a7 100644
--- a/ui-test/source/java/ch/systemsx/cisd/openbis/uitest/page/Page.java
+++ b/ui-test/source/java/ch/systemsx/cisd/openbis/uitest/page/Page.java
@@ -16,6 +16,71 @@
 
 package ch.systemsx.cisd.openbis.uitest.page;
 
-public interface Page
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.is;
+import static org.hamcrest.Matchers.notNullValue;
+
+import org.openqa.selenium.By;
+import org.openqa.selenium.WebDriver;
+import org.openqa.selenium.WebElement;
+import org.openqa.selenium.support.ui.ExpectedCondition;
+import org.openqa.selenium.support.ui.WebDriverWait;
+
+import ch.systemsx.cisd.openbis.uitest.infra.PageProxy;
+import ch.systemsx.cisd.openbis.uitest.infra.ScreenShotProxy;
+import ch.systemsx.cisd.openbis.uitest.infra.ScreenShotter;
+import ch.systemsx.cisd.openbis.uitest.infra.SeleniumTest;
+
+public abstract class Page
 {
+    private PageProxy pageProxy;
+
+    private ScreenShotter shotter;
+
+    public void setPageProxy(PageProxy proxy)
+    {
+        this.pageProxy = proxy;
+    }
+
+    public void setScreenShotter(ScreenShotter shotter)
+    {
+        this.shotter = shotter;
+    }
+
+    public <T extends Page> T get(Class<T> clazz)
+    {
+        return this.pageProxy.get(clazz);
+    }
+
+    public WebElement findElementWithText(String text, By by)
+    {
+        WebElement element = null;
+        for (WebElement e : SeleniumTest.driver.findElements(by))
+        {
+            if (e.getText().equals(text))
+            {
+                element = e;
+                break;
+            }
+        }
+        assertThat(element, is(notNullValue()));
+
+        return (WebElement) ScreenShotProxy.newInstance(element, shotter);
+    }
+
+    public void wait(final By by)
+    {
+
+        ExpectedCondition<?> condition = new ExpectedCondition<WebElement>()
+            {
+                @Override
+                public WebElement apply(WebDriver d)
+                {
+                    return d.findElement(by);
+                }
+            };
+
+        new WebDriverWait(SeleniumTest.driver, 10).until(condition);
+    }
+
 }
diff --git a/ui-test/source/java/ch/systemsx/cisd/openbis/uitest/page/SpaceBrowser.java b/ui-test/source/java/ch/systemsx/cisd/openbis/uitest/page/SpaceBrowser.java
index 32050892960..8462aac7e92 100644
--- a/ui-test/source/java/ch/systemsx/cisd/openbis/uitest/page/SpaceBrowser.java
+++ b/ui-test/source/java/ch/systemsx/cisd/openbis/uitest/page/SpaceBrowser.java
@@ -16,8 +16,6 @@
 
 package ch.systemsx.cisd.openbis.uitest.page;
 
-import static ch.systemsx.cisd.openbis.uitest.infra.Help.findElementWithText;
-
 import java.util.Collection;
 import java.util.HashSet;
 import java.util.List;
@@ -26,26 +24,27 @@ import org.openqa.selenium.By;
 import org.openqa.selenium.WebElement;
 import org.openqa.selenium.support.FindBy;
 
-import ch.systemsx.cisd.openbis.uitest.infra.SeleniumTest;
-
-public class SpaceBrowser implements Page
+public class SpaceBrowser extends Page
 {
 
-    @FindBy(className="x-grid3-col-CODE")
+    @FindBy(className = "x-grid3-col-CODE")
     private List<WebElement> spaceNames;
-    
-    public AddSpaceDialog addSpace() {
+
+    public AddSpaceDialog addSpace()
+    {
         WebElement addSpaceButton = findElementWithText("Add Space", By.className("x-btn-text"));
         addSpaceButton.click();
-        return SeleniumTest.get(AddSpaceDialog.class);
+        return get(AddSpaceDialog.class);
     }
-    
-    public Collection<String> getSpaces() {    
+
+    public Collection<String> getSpaces()
+    {
         Collection<String> spaces = new HashSet<String>();
-        for (WebElement element : spaceNames) {
+        for (WebElement element : spaceNames)
+        {
             spaces.add(element.getText());
         }
         return spaces;
     }
-    
+
 }
-- 
GitLab