From 41a14c8abdbc92e4fc31ecfb67c08567dc4b41a8 Mon Sep 17 00:00:00 2001
From: anttil <anttil>
Date: Thu, 6 Sep 2012 08:28:02 +0000
Subject: [PATCH] SWE-2 / SP-263: Vocabulary creation + CI build fixes

SVN: 26527
---
 .../ui/vocabulary/VocabularyGrid.java         |   3 +
 .../VocabularyRegistrationFieldSet.java       |   2 +
 ui-test/build/build.xml                       |  41 ++++++-
 .../openbis/uitest/AuthorizationTest.java     |  14 ++-
 .../cisd/openbis/uitest/SpaceTest.java        |   2 +-
 .../cisd/openbis/uitest/VocabularyTest.java   |  26 +++++
 .../uitest/infra/ApplicationRunner.java       |  31 ++++--
 .../openbis/uitest/infra/SeleniumTest.java    |  36 ++++---
 .../cisd/openbis/uitest/infra/Vocabulary.java | 102 ++++++++++++++++++
 .../openbis/uitest/page/AddSpaceDialog.java   |   4 +-
 .../uitest/page/AddVocabularyDialog.java      |  58 ++++++++++
 .../cisd/openbis/uitest/page/AdminMenu.java   |   9 ++
 .../uitest/page/VocabularyBrowser.java        |  60 +++++++++++
 13 files changed, 358 insertions(+), 30 deletions(-)
 create mode 100644 ui-test/source/java/ch/systemsx/cisd/openbis/uitest/VocabularyTest.java
 create mode 100644 ui-test/source/java/ch/systemsx/cisd/openbis/uitest/infra/Vocabulary.java
 create mode 100644 ui-test/source/java/ch/systemsx/cisd/openbis/uitest/page/AddVocabularyDialog.java
 create mode 100644 ui-test/source/java/ch/systemsx/cisd/openbis/uitest/page/VocabularyBrowser.java

diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/vocabulary/VocabularyGrid.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/vocabulary/VocabularyGrid.java
index 7a302e3cf88..37c8af18f2e 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/vocabulary/VocabularyGrid.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/vocabulary/VocabularyGrid.java
@@ -79,6 +79,8 @@ public class VocabularyGrid extends TypedTableGrid<Vocabulary>
 
     public static final String SHOW_DETAILS_BUTTON_ID = BROWSER_ID + "_show-details-button";
 
+    public static final String ADD_BUTTON_ID = BROWSER_ID + "_add-button";
+
     private final IDelegatedAction postEditionCallback;
 
     public static IDisposableComponent create(
@@ -196,6 +198,7 @@ public class VocabularyGrid extends TypedTableGrid<Vocabulary>
                                             viewContext).getVocabularyRegistration());
                                 }
                             });
+        addButton.setId(ADD_BUTTON_ID);
         addButton(addButton);
 
         Button showDetailsButton =
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/vocabulary/VocabularyRegistrationFieldSet.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/vocabulary/VocabularyRegistrationFieldSet.java
index e24ce51f09a..c40cfde516c 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/vocabulary/VocabularyRegistrationFieldSet.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/vocabulary/VocabularyRegistrationFieldSet.java
@@ -242,6 +242,8 @@ public final class VocabularyRegistrationFieldSet extends FieldSet
             result.setRegex(regex);
             result.getMessages().setRegexText(regexTextMsg);
 
+            result.setId(ID + "-url");
+
             // manually clear invalid messages on focus (automatic validation is turned off)
             result.addListener(Events.Focus, new Listener<FieldEvent>()
                 {
diff --git a/ui-test/build/build.xml b/ui-test/build/build.xml
index 70aae5c6d3d..a257d980257 100644
--- a/ui-test/build/build.xml
+++ b/ui-test/build/build.xml
@@ -1,8 +1,8 @@
 <project name="ui-test" default="run-tests" basedir="..">
 	<import file="../../build_resources/ant/build-common.xml" />
 
-    <project-classpath name="ecp" classes="${classes}" />
-    <project-classpath name="eclipse.cp" classes="${targets}/classes" />
+  <project-classpath name="ecp" classes="${classes}" />
+  <project-classpath name="eclipse.cp" classes="${targets}/classes" />
 
 	
 	<target name="clean" description="Cleans distribution directory.">
@@ -11,10 +11,45 @@
   </target>
 
   <target name="run-tests">
-    <antcall target="build-common.run-tests">
+    <antcall target="run-tests-ui">
     	<param name="sources.test" value="source/java" />
       <param name="test.suite" value="tests.xml" />
     </antcall>
   </target>
+	
+	<target name="run-tests-ui" depends="compile-tests">
+		<delete dir="${output.test}" />
+		
+		<antcall target="_run-testng-ui">
+			<param name="test.suite" value="${test.suite}" />
+			<param name="failure.property" value="tests.failed" />
+		</antcall>
+				
+		<junitreport todir="${output.test}">
+			<fileset dir="${output.test}">
+				<include name="*/*.xml" />
+			</fileset>
+			<report format="noframes" todir="${output.test}" />
+		</junitreport>
+		<fail if="tests.failed" message="At least one test failed." />
+	</target>
+	
+	<target name="_run-testng-ui">
+
+		<condition property="internal-url" value="${ui-test.url}" else="">
+		    <isset property="ui-test.url"/>
+		</condition>
+
+		<testng classpath="${ecp}"
+		        workingDir="."
+		        outputdir="${output.test}"
+		        failureproperty="${failure.property}">
+			<xmlfileset dir="${sources.test}" includes="${test.suite}" />
+			<jvmarg value="-Xmx1024M" />
+			<jvmarg value="-XX:MaxPermSize=512m" />
+	  	<jvmarg value="-Dui-test.url=${internal-url}" />
+		</testng>
+		
+	</target>
 
 </project>
diff --git a/ui-test/source/java/ch/systemsx/cisd/openbis/uitest/AuthorizationTest.java b/ui-test/source/java/ch/systemsx/cisd/openbis/uitest/AuthorizationTest.java
index a20021fcb5e..07bd9360e3e 100644
--- a/ui-test/source/java/ch/systemsx/cisd/openbis/uitest/AuthorizationTest.java
+++ b/ui-test/source/java/ch/systemsx/cisd/openbis/uitest/AuthorizationTest.java
@@ -44,10 +44,14 @@ public class AuthorizationTest extends SeleniumTest
     public void adminCanOpenRoleAssignmentBrowser() throws Exception
     {
         openbis.login(User.ADMIN);
-        openbis.browseToRoleAssignmentBrowser();
-
-        assertThat(browser(), isShowing(RoleAssignmentBrowser.class));
-
-        openbis.logout();
+        try
+        {
+
+            openbis.browseToRoleAssignmentBrowser();
+            assertThat(browser(), isShowing(RoleAssignmentBrowser.class));
+        } finally
+        {
+            openbis.logout();
+        }
     }
 }
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 c247ff59f6a..ce685841d9b 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
@@ -18,7 +18,7 @@ public class SpaceTest extends SeleniumTest
     {
         Space space = new Space();
 
-        openbis.createSpace(space);
+        openbis.create(space);
 
         assertThat(SpaceBrowser.class, listsSpace(space));
     }
diff --git a/ui-test/source/java/ch/systemsx/cisd/openbis/uitest/VocabularyTest.java b/ui-test/source/java/ch/systemsx/cisd/openbis/uitest/VocabularyTest.java
new file mode 100644
index 00000000000..337ad18adf9
--- /dev/null
+++ b/ui-test/source/java/ch/systemsx/cisd/openbis/uitest/VocabularyTest.java
@@ -0,0 +1,26 @@
+package ch.systemsx.cisd.openbis.uitest;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+
+import org.testng.annotations.Test;
+
+import ch.systemsx.cisd.openbis.uitest.infra.SeleniumTest;
+import ch.systemsx.cisd.openbis.uitest.infra.Vocabulary;
+import ch.systemsx.cisd.openbis.uitest.page.VocabularyBrowser;
+
+@Test(groups =
+    { "login-admin" })
+public class VocabularyTest extends SeleniumTest
+{
+
+    @Test
+    public void newVocabularyIsListedInVocabularyBrowser() throws Exception
+    {
+        Vocabulary vocabulary = new Vocabulary();
+
+        openbis.create(vocabulary);
+
+        assertThat(VocabularyBrowser.class, listsVocabulary(vocabulary));
+    }
+
+}
diff --git a/ui-test/source/java/ch/systemsx/cisd/openbis/uitest/infra/ApplicationRunner.java b/ui-test/source/java/ch/systemsx/cisd/openbis/uitest/infra/ApplicationRunner.java
index 75dbd2ca11d..9cacecda26c 100644
--- a/ui-test/source/java/ch/systemsx/cisd/openbis/uitest/infra/ApplicationRunner.java
+++ b/ui-test/source/java/ch/systemsx/cisd/openbis/uitest/infra/ApplicationRunner.java
@@ -18,6 +18,7 @@ package ch.systemsx.cisd.openbis.uitest.infra;
 
 import ch.systemsx.cisd.openbis.uitest.page.AddSampleTypeDialog;
 import ch.systemsx.cisd.openbis.uitest.page.AddSpaceDialog;
+import ch.systemsx.cisd.openbis.uitest.page.AddVocabularyDialog;
 import ch.systemsx.cisd.openbis.uitest.page.EditSampleTypeDialog;
 import ch.systemsx.cisd.openbis.uitest.page.LoginPage;
 import ch.systemsx.cisd.openbis.uitest.page.PrivatePage;
@@ -25,6 +26,7 @@ import ch.systemsx.cisd.openbis.uitest.page.RoleAssignmentBrowser;
 import ch.systemsx.cisd.openbis.uitest.page.SampleBrowser;
 import ch.systemsx.cisd.openbis.uitest.page.SampleTypeBrowser;
 import ch.systemsx.cisd.openbis.uitest.page.SpaceBrowser;
+import ch.systemsx.cisd.openbis.uitest.page.VocabularyBrowser;
 
 /**
  * @author anttil
@@ -39,7 +41,7 @@ public class ApplicationRunner
         this.proxy = proxy;
     }
 
-    public void createSpace(Space space)
+    public void create(Space space)
     {
         AddSpaceDialog dialog = browseToAddSpaceDialog();
         dialog.fillWith(space);
@@ -53,6 +55,13 @@ public class ApplicationRunner
         dialog.save();
     }
 
+    public void create(Vocabulary vocabulary)
+    {
+        AddVocabularyDialog dialog = browseToAddVocabularyDialog();
+        dialog.fillWith(vocabulary);
+        dialog.save();
+    }
+
     public void update(SampleType sampleType)
     {
         SampleTypeBrowser sampleTypeBrowser = browseToSampleTypeBrowser();
@@ -78,14 +87,14 @@ public class ApplicationRunner
         getMenus().user().logout();
     }
 
-    public AddSampleTypeDialog browseToAddSampleTypeDialog()
+    public SampleTypeBrowser browseToSampleTypeBrowser()
     {
-        return getMenus().admin().types().sampleTypes().add();
+        return getMenus().admin().types().sampleTypes();
     }
 
-    public SampleTypeBrowser browseToSampleTypeBrowser()
+    public AddSampleTypeDialog browseToAddSampleTypeDialog()
     {
-        return getMenus().admin().types().sampleTypes();
+        return browseToSampleTypeBrowser().add();
     }
 
     public SpaceBrowser browseToSpaceBrowser()
@@ -95,7 +104,7 @@ public class ApplicationRunner
 
     public AddSpaceDialog browseToAddSpaceDialog()
     {
-        return getMenus().admin().spaces().addSpace();
+        return browseToSpaceBrowser().addSpace();
     }
 
     public SampleBrowser browseToSampleBrowser()
@@ -108,6 +117,16 @@ public class ApplicationRunner
         return getMenus().admin().authorization().roles();
     }
 
+    public VocabularyBrowser browseToVocabularyBrowser()
+    {
+        return getMenus().admin().vocabularies();
+    }
+
+    public AddVocabularyDialog browseToAddVocabularyDialog()
+    {
+        return browseToVocabularyBrowser().add();
+    }
+
     public void closeAllTabs()
     {
         getMenus().closeTabs();
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 624932ba49b..cedac6e3391 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
@@ -55,32 +55,29 @@ public abstract class SeleniumTest
 
     protected ApplicationRunner openbis;
 
-    // @BeforeSuite
+    @BeforeSuite
     public void initWebDriver()
     {
+        /*
         System.setProperty("webdriver.firefox.bin",
                 "/Users/anttil/Desktop/Firefox 10.app/Contents/MacOS/firefox");
 
         System.setProperty("webdriver.firefox.profile", "default");
-
+        */
         driver = new FirefoxDriver();
         driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
         delete(new File("targets/dist"));
 
         driver.manage().deleteAllCookies();
-        driver.get("http://127.0.0.1:8888/ch.systemsx.cisd.openbis.OpenBIS/index.html?gwt.codesvr=127.0.0.1:9997");
-    }
-
-    @BeforeSuite
-    public void initWebDriverForCi()
-    {
-        driver = new FirefoxDriver();
-        driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
-        delete(new File("targets/dist"));
 
-        driver.manage().deleteAllCookies();
+        String url = System.getProperty("ui-test.url");
+        if (url == null || url.length() == 0)
+        {
+            url =
+                    "http://127.0.0.1:8888/ch.systemsx.cisd.openbis.OpenBIS/index.html?gwt.codesvr=127.0.0.1:9997";
+        }
 
-        driver.get("https://sprint-openbis.ethz.ch/openbis/");
+        driver.get(url);
     }
 
     @AfterSuite
@@ -293,6 +290,19 @@ public abstract class SeleniumTest
             });
     }
 
+    protected Matcher<Class<? extends BrowserPage>> listsVocabulary(Browsable browsable)
+    {
+        return new ListsElementMatcher(browsable, new Opener(this.openbis)
+            {
+                @Override
+                public BrowserPage open(Class<? extends BrowserPage> pageClass)
+                {
+                    return this.openbis.browseToVocabularyBrowser();
+                }
+
+            });
+    }
+
     private abstract class Opener
     {
         protected ApplicationRunner openbis;
diff --git a/ui-test/source/java/ch/systemsx/cisd/openbis/uitest/infra/Vocabulary.java b/ui-test/source/java/ch/systemsx/cisd/openbis/uitest/infra/Vocabulary.java
new file mode 100644
index 00000000000..98132e943cd
--- /dev/null
+++ b/ui-test/source/java/ch/systemsx/cisd/openbis/uitest/infra/Vocabulary.java
@@ -0,0 +1,102 @@
+/*
+ * 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.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import java.util.UUID;
+
+/**
+ * @author anttil
+ */
+public class Vocabulary implements Browsable
+{
+
+    private String code;
+
+    private String description;
+
+    private Set<String> terms;
+
+    private String url;
+
+    public Vocabulary()
+    {
+        this.code = UUID.randomUUID().toString();
+        this.description = "";
+        this.terms = new HashSet<String>();
+        this.terms.add("term1");
+        this.url = "http://invalid.com/${term}";
+    }
+
+    public String getCode()
+    {
+        return code;
+    }
+
+    public Vocabulary setCode(String code)
+    {
+        this.code = code;
+        return this;
+    }
+
+    public String getDescription()
+    {
+        return description;
+    }
+
+    public Vocabulary setDescription(String description)
+    {
+        this.description = description;
+        return this;
+    }
+
+    public Set<String> getTerms()
+    {
+        return terms;
+    }
+
+    public Vocabulary setTerms(Set<String> terms)
+    {
+        this.terms = terms;
+        return this;
+    }
+
+    public String getUrl()
+    {
+        return url;
+    }
+
+    public Vocabulary setUrl(String url)
+    {
+        this.url = url;
+        return this;
+    }
+
+    @Override
+    public boolean isRepresentedBy(Map<String, String> row)
+    {
+        return this.code.equalsIgnoreCase(row.get("Code"));
+    }
+
+    @Override
+    public String toString()
+    {
+        return "Vocabulary " + this.code + ": " + this.terms;
+    }
+}
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 a65690b0db3..6b5ff4165c8 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
@@ -16,7 +16,6 @@
 
 package ch.systemsx.cisd.openbis.uitest.page;
 
-import org.openqa.selenium.By;
 import org.openqa.selenium.WebElement;
 import org.openqa.selenium.support.FindBy;
 
@@ -31,6 +30,7 @@ public class AddSpaceDialog extends Page
     @FindBy(id = "openbis_dialog-save-button")
     private WebElement saveButton;
 
+    /* this is not deleted as this is an example of WAIT
     public SpaceBrowser addSpace(String name, String description)
     {
         this.code.sendKeys(name);
@@ -38,7 +38,7 @@ public class AddSpaceDialog extends Page
         wait(By.xpath("//div[.=\"" + name.toUpperCase() + "\"]"));
         return get(SpaceBrowser.class);
     }
-
+    */
     public void fillWith(Space space)
     {
         this.code.sendKeys(space.getCode());
diff --git a/ui-test/source/java/ch/systemsx/cisd/openbis/uitest/page/AddVocabularyDialog.java b/ui-test/source/java/ch/systemsx/cisd/openbis/uitest/page/AddVocabularyDialog.java
new file mode 100644
index 00000000000..32f04e6c4a6
--- /dev/null
+++ b/ui-test/source/java/ch/systemsx/cisd/openbis/uitest/page/AddVocabularyDialog.java
@@ -0,0 +1,58 @@
+/*
+ * 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.page;
+
+import org.openqa.selenium.WebElement;
+import org.openqa.selenium.support.FindBy;
+
+import ch.systemsx.cisd.openbis.uitest.infra.Vocabulary;
+
+public class AddVocabularyDialog extends Page
+{
+
+    @FindBy(id = "openbis_vocabulary-registration_formvocabulary_registration_field_set_code-input")
+    private WebElement code;
+
+    @FindBy(id = "openbis_vocabulary-registration_formvocabulary_registration_field_set_description-input")
+    private WebElement description;
+
+    @FindBy(id = "openbis_vocabulary-registration_formvocabulary_registration_field_set_terms-input")
+    private WebElement terms;
+
+    @FindBy(id = "vocabulary_registration_field_set-url-input")
+    private WebElement url;
+
+    @FindBy(id = "openbis_vocabulary-registration_formsave-button")
+    private WebElement saveButton;
+
+    public void fillWith(Vocabulary vocabulary)
+    {
+        this.code.sendKeys(vocabulary.getCode());
+        this.description.sendKeys(vocabulary.getDescription());
+        for (String term : vocabulary.getTerms())
+        {
+            this.terms.sendKeys(term + ", ");
+        }
+        this.url.sendKeys(vocabulary.getUrl());
+    }
+
+    public VocabularyBrowser save()
+    {
+        this.saveButton.click();
+        return get(VocabularyBrowser.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 73d628c432a..723074f298f 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
@@ -28,6 +28,9 @@ public class AdminMenu extends PrivatePage
     @FindBy(id = "openbis_top-menu_ADMINISTRATION_MENU_MANAGE_GROUPS")
     private WebElement spaces;
 
+    @FindBy(id = "openbis_top-menu_VOCABULARY_MENU_BROWSE")
+    private WebElement vocabularies;
+
     @FindBy(id = "ADMINISTRATION_MENU_MANAGE_TYPES")
     private WebElement types;
 
@@ -43,6 +46,12 @@ public class AdminMenu extends PrivatePage
         return get(SpaceBrowser.class);
     }
 
+    public VocabularyBrowser vocabularies()
+    {
+        vocabularies.click();
+        return get(VocabularyBrowser.class);
+    }
+
     public AdminMenu types()
     {
         Actions builder = new Actions(SeleniumTest.driver);
diff --git a/ui-test/source/java/ch/systemsx/cisd/openbis/uitest/page/VocabularyBrowser.java b/ui-test/source/java/ch/systemsx/cisd/openbis/uitest/page/VocabularyBrowser.java
new file mode 100644
index 00000000000..68588df30a8
--- /dev/null
+++ b/ui-test/source/java/ch/systemsx/cisd/openbis/uitest/page/VocabularyBrowser.java
@@ -0,0 +1,60 @@
+/*
+ * 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.page;
+
+import java.util.List;
+
+import org.openqa.selenium.WebElement;
+import org.openqa.selenium.support.FindBy;
+import org.openqa.selenium.support.FindBys;
+
+public class VocabularyBrowser extends BrowserPage
+{
+
+    @FindBys(
+        {
+                @FindBy(id = "openbis_vocabulary-browser-grid"),
+                @FindBy(xpath = "//*[contains(@class, \"x-grid\") and contains(@class, \"-header \")]//span") })
+    private List<WebElement> columns;
+
+    @FindBys(
+        {
+                @FindBy(id = "openbis_vocabulary-browser-grid"),
+                @FindBy(xpath = "//*[contains(@class, \"x-grid\") and contains(@class, \"-col \")]/div") })
+    private List<WebElement> data;
+
+    @FindBy(id = "openbis_vocabulary-browser_add-button")
+    private WebElement addVocabularyButton;
+
+    public AddVocabularyDialog add()
+    {
+        addVocabularyButton.click();
+        return get(AddVocabularyDialog.class);
+    }
+
+    @Override
+    protected List<WebElement> getColumns()
+    {
+        return this.columns;
+    }
+
+    @Override
+    protected List<WebElement> getData()
+    {
+        return this.data;
+    }
+}
-- 
GitLab