Author: mstruk
Date: 2011-03-03 07:37:38 -0500 (Thu, 03 Mar 2011)
New Revision: 5957
Added:
portal/trunk/testsuite/htmlunit-tests/
portal/trunk/testsuite/htmlunit-tests/pom.xml
portal/trunk/testsuite/htmlunit-tests/src/
portal/trunk/testsuite/htmlunit-tests/src/test/
portal/trunk/testsuite/htmlunit-tests/src/test/java/
portal/trunk/testsuite/htmlunit-tests/src/test/java/org/
portal/trunk/testsuite/htmlunit-tests/src/test/java/org/jboss/
portal/trunk/testsuite/htmlunit-tests/src/test/java/org/jboss/gatein/
portal/trunk/testsuite/htmlunit-tests/src/test/java/org/jboss/gatein/htmlunit/
portal/trunk/testsuite/htmlunit-tests/src/test/java/org/jboss/gatein/htmlunit/AbstractWebTest.java
portal/trunk/testsuite/htmlunit-tests/src/test/java/org/jboss/gatein/htmlunit/common/
portal/trunk/testsuite/htmlunit-tests/src/test/java/org/jboss/gatein/htmlunit/common/WebHelper.java
portal/trunk/testsuite/htmlunit-tests/src/test/java/org/jboss/gatein/htmlunit/jira/
portal/trunk/testsuite/htmlunit-tests/src/test/java/org/jboss/gatein/htmlunit/jira/Test_GTNPORTAL_1823_FailToCreatePage.java
Log:
HTMLUnit based testsuite that can be used instead of selenium-tests-other
Added: portal/trunk/testsuite/htmlunit-tests/pom.xml
===================================================================
--- portal/trunk/testsuite/htmlunit-tests/pom.xml (rev 0)
+++ portal/trunk/testsuite/htmlunit-tests/pom.xml 2011-03-03 12:37:38 UTC (rev 5957)
@@ -0,0 +1,103 @@
+<!--
+ ~ JBoss, Home of Professional Open Source.
+ ~ Copyright 2011, Red Hat Middleware LLC, and individual contributors
+ ~ as indicated by the @author tags. See the copyright.txt file in the
+ ~ distribution for a full listing of individual contributors.
+ ~
+ ~ This is free software; you can redistribute it and/or modify it
+ ~ under the terms of the GNU Lesser General Public License as
+ ~ published by the Free Software Foundation; either version 2.1 of
+ ~ the License, or (at your option) any later version.
+ ~
+ ~ This software is distributed in the hope that it will be useful,
+ ~ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ ~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ ~ Lesser General Public License for more details.
+ ~
+ ~ You should have received a copy of the GNU Lesser General Public
+ ~ License along with this software; if not, write to the Free
+ ~ Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ ~ 02110-1301 USA, or see the FSF site:
http://www.fsf.org.
+ -->
+
+<project
xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/maven-v4_0_0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+
+ <groupId>org.jboss.gatein</groupId>
+ <artifactId>gatein.tests.htmlunit</artifactId>
+ <version>3.2.0-Beta01-SNAPSHOT</version>
+ <packaging>jar</packaging>
+ <name>HTMLUnit Tests for GateIn</name>
+ <description>HTMLUnit Tests for GateIn</description>
+
+ <properties>
+ <testng.suite.file>testng.xml</testng.suite.file>
+ </properties>
+
+ <!-- no tests by default -->
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-surefire-plugin</artifactId>
+ <configuration>
+ <skip>true</skip>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <configuration>
+ <source>1.5</source>
+ <target>1.5</target>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+
+ <profiles>
+ <profile>
+ <id>htmlunit</id>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-surefire-plugin</artifactId>
+ <executions>
+ <execution>
+ <phase>integration-test</phase>
+ <goals>
+ <goal>test</goal>
+ </goals>
+ <configuration>
+ <skip>false</skip>
+ <includes>
+ <include>**/Test*.java</include>
+ </includes>
+ <!--suiteXmlFiles>
+
<suiteXmlFile>src/test/resources/${testng.suite.file}</suiteXmlFile>
+ </suiteXmlFiles-->
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+ </profile>
+ </profiles>
+ <dependencies>
+ <dependency>
+ <groupId>org.testng</groupId>
+ <artifactId>testng</artifactId>
+ <version>5.12.1</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>net.sourceforge.htmlunit</groupId>
+ <artifactId>htmlunit</artifactId>
+ <version>2.8</version>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+</project>
Added:
portal/trunk/testsuite/htmlunit-tests/src/test/java/org/jboss/gatein/htmlunit/AbstractWebTest.java
===================================================================
---
portal/trunk/testsuite/htmlunit-tests/src/test/java/org/jboss/gatein/htmlunit/AbstractWebTest.java
(rev 0)
+++
portal/trunk/testsuite/htmlunit-tests/src/test/java/org/jboss/gatein/htmlunit/AbstractWebTest.java 2011-03-03
12:37:38 UTC (rev 5957)
@@ -0,0 +1,198 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2011, Red Hat Middleware LLC, and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site:
http://www.fsf.org.
+ */
+
+package org.jboss.gatein.htmlunit;
+
+import com.gargoylesoftware.htmlunit.WebClient;
+import com.gargoylesoftware.htmlunit.html.HtmlElement;
+import org.jboss.gatein.htmlunit.common.WebHelper;
+
+import java.io.IOException;
+
+/**
+ * This class provides every thread of execution with a single instance of WebHelper
+ * which represents a single session with the web application.
+ *
+ * By extending this class test code can be written as if the state exists at the test
class instance level
+ * (shared across concurrent method calls), when in fact every thread has it's own
copy.
+ *
+ * @author <a href="mailto:mstrukel@redhat.com">Marko Strukelj</a>
+ */
+public abstract class AbstractWebTest
+{
+ /** Thread specific WebHelper storage */
+ private static final ThreadLocal<WebHelper> tcl = new
ThreadLocal<WebHelper>();
+
+ /**
+ * Get current WebHelper - lazy initialized if none yet exists.
+ *
+ * @return current WebHelper
+ */
+ protected WebHelper getWebHelper()
+ {
+ WebHelper ret = tcl.get();
+ if (ret == null)
+ {
+ tcl.set(new WebHelper());
+ ret = tcl.get();
+ }
+ return ret;
+ }
+
+ /**
+ * Get current WebClient
+ *
+ * @return current WebClient
+ */
+ protected WebClient getWebClient()
+ {
+ return getWebHelper().getWebClient();
+ }
+
+ /**
+ * @see WebHelper#openPortal(boolean)
+ */
+ protected void openPortal(boolean publicMode) throws IOException
+ {
+ getWebHelper().openPortal(publicMode);
+ }
+
+ /**
+ * @see WebHelper#signInAsRoot()
+ */
+ protected void signInAsRoot()
+ {
+ getWebHelper().signInAsRoot();
+ }
+
+ /**
+ * @see WebHelper#signIn(String, String)
+ */
+ protected void signIn(String user, String pass)
+ {
+ getWebHelper().signIn(user, pass);
+ }
+
+ /**
+ * @see WebHelper#type(String, String)
+ */
+ protected void type(String field, String value)
+ {
+ getWebHelper().type(field, value);
+ }
+
+ /**
+ * @see WebHelper#click(String)
+ */
+ protected void click(String el)
+ {
+ getWebHelper().click(el);
+ }
+
+ /**
+ * @see WebHelper#waitForElementPresent(String)
+ */
+ protected void waitForElementPresent(String el)
+ {
+ getWebHelper().waitForElementPresent(el);
+ }
+
+ /**
+ * @see WebHelper#isElementPresent(String)
+ */
+ protected boolean isElementPresent(String el)
+ {
+ return getWebHelper().isElementPresent(el);
+ }
+
+ /**
+ * @see WebHelper#getElement(String)
+ */
+ protected HtmlElement getElement(String el)
+ {
+ return getWebHelper().getElement(el);
+ }
+
+ /**
+ * @see WebHelper#waitForTextPresent(String)
+ */
+ protected void waitForTextPresent(String text)
+ {
+ getWebHelper().waitForTextPresent(text);
+ }
+
+ /**
+ * @see WebHelper#waitForTextNotPresent(String)
+ */
+ protected void waitForTextNotPresent(String text)
+ {
+ getWebHelper().waitForTextNotPresent(text);
+ }
+
+ /**
+ * @see WebHelper#isTextPresent(String)
+ */
+ protected boolean isTextPresent(String text)
+ {
+ return getWebHelper().isTextPresent(text);
+ }
+
+ /**
+ * @see WebHelper#shortPause
+ */
+ protected void shortPause()
+ {
+ getWebHelper().shortPause();
+ }
+
+ /**
+ * @see WebHelper#pause(long)
+ */
+ protected void pause(long millis)
+ {
+ WebHelper.pause(millis);
+ }
+
+ /**
+ * @see WebHelper#dragAndDropToObject(String, String)
+ */
+ protected void dragAndDropToObject(String sourceEl, String targetEl)
+ {
+ getWebHelper().dragAndDropToObject(sourceEl, targetEl);
+ }
+
+ /**
+ * @see WebHelper#finishPageEdit
+ */
+ protected void finishPageEdit()
+ {
+ getWebHelper().finishPageEdit();
+ }
+
+ /**
+ * @see WebHelper#addNewPageUpToFinish(String, String, String, String)
+ */
+ protected void addNewPageUpToFinish(String categoryTitle, String portletName, String
pageName, String portletElementToDnD)
+ {
+ getWebHelper().addNewPageUpToFinish(categoryTitle, portletName, pageName,
portletElementToDnD);
+ }
+}
Added:
portal/trunk/testsuite/htmlunit-tests/src/test/java/org/jboss/gatein/htmlunit/common/WebHelper.java
===================================================================
---
portal/trunk/testsuite/htmlunit-tests/src/test/java/org/jboss/gatein/htmlunit/common/WebHelper.java
(rev 0)
+++
portal/trunk/testsuite/htmlunit-tests/src/test/java/org/jboss/gatein/htmlunit/common/WebHelper.java 2011-03-03
12:37:38 UTC (rev 5957)
@@ -0,0 +1,311 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2011, Red Hat Middleware LLC, and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site:
http://www.fsf.org.
+ */
+
+package org.jboss.gatein.htmlunit.common;
+
+import com.gargoylesoftware.htmlunit.WebClient;
+import com.gargoylesoftware.htmlunit.html.HtmlElement;
+import com.gargoylesoftware.htmlunit.html.HtmlInput;
+import com.gargoylesoftware.htmlunit.html.HtmlPage;
+import org.testng.Assert;
+
+import java.io.IOException;
+
+/**
+ * WebHelper class contains helper methods to easily perform GateIn portal operations
+ *
+ * @author <a href="mailto:mstrukel@redhat.com">Marko Strukelj</a>
+ */
+public class WebHelper
+{
+ /** HTMLUnit Webclient represents a web session */
+ private WebClient webClient;
+
+ /** Host to use for web session */
+ private String host = "localhost";
+
+ /** Port to use for web session */
+ private int port = 8888;
+
+ /** Portal container to use for web session */
+ private String portalContainer = "portal";
+
+ /** Current page */
+ private HtmlPage page;
+
+ /** Time to wait (in seconds) for element or text to appear in the page */
+ private int timeout = 20;
+
+ /** Short pause period (in seconds)*/
+ private int shortPause = 3;
+
+ /** Get HTMLUnit WebClient instance representing the current session */
+ public WebClient getWebClient()
+ {
+ if (webClient == null)
+ {
+ webClient = new WebClient();
+ webClient.setThrowExceptionOnFailingStatusCode(false);
+ webClient.setThrowExceptionOnScriptError(false);
+ }
+ return webClient;
+ }
+
+ /**
+ * Open GateIn's home page.
+ *
+ * @param publicMode if true 'public' portal page is used, otherwise
'private', which requires signing in
+ * @throws IOException
+ */
+ public void openPortal(boolean publicMode) throws IOException
+ {
+ System.out.println("--Open portal home--");
+ page = getWebClient().getPage(getStartUrl(publicMode));
+ HtmlElement desc = page.getFirstByXPath(".//div[contains(text(), 'All
rights reserved')]");
+ if (desc == null)
+ throw new RuntimeException("Portal page content corrupted\r\n" +
page.asText());
+ }
+
+ private String getStartUrl(boolean publicMode)
+ {
+ return "http://" + host + ":" + port + "/" +
portalContainer + "/" + (publicMode ? "public" :
"private");
+ }
+
+ public void signInAsRoot()
+ {
+ signIn("root", "gtn");
+ }
+
+ public void signIn(String user, String pass)
+ {
+ System.out.println("--Sign in as " + user + "--");
+ waitForElementPresent("link=Sign in");
+ click("link=Sign in");
+ waitForElementPresent("username");
+ type("username", user);
+ type("password", pass);
+ click("//div[@id='UIPortalLoginFormAction']/div/div/div/a");
+ //waitForPageToLoad(timeout);
+ }
+
+ /**
+ * Fill form field with text
+ *
+ * @param field
+ * @param value
+ */
+ public void type(String field, String value)
+ {
+ HtmlElement textField = getElement(field);
+ if (textField instanceof HtmlInput == false)
+ throw new RuntimeException("Element not text input: " + textField);
+
+ ((HtmlInput) textField).setValueAttribute(value);
+ }
+
+ /**
+ * Simulate clicking an element in the page
+ *
+ * @param el expression identifying an element
+ */
+ public void click(String el)
+ {
+ HtmlElement node = getElement(el);
+ try
+ {
+ page = node.click();
+ }
+ catch (Exception ex)
+ {
+ throw new RuntimeException("Click failed [" + el + "]" ,
ex);
+ }
+ }
+
+ public void waitForElementPresent(String el)
+ {
+ for (int second = 0; ; second++)
+ {
+ if (second >= timeout)
+ {
+ Assert.fail("Timeout at waitForElementPresent: " + el);
+ }
+ if (isElementPresent(el))
+ {
+ break;
+ }
+ pause(1000);
+ }
+ }
+
+ public boolean isElementPresent(String el)
+ {
+ HtmlElement node = getElement(el);
+ return node != null;
+ }
+
+ public HtmlElement getElement(String el)
+ {
+ if (el.startsWith("link="))
+ {
+ String xpath = convertFromLinkElSpec(el);
+ return page.getFirstByXPath(xpath);
+ }
+ else if (el.startsWith("//"))
+ {
+ return page.getFirstByXPath(el);
+ }
+ else
+ {
+ return page.getFirstByXPath(".//node()[@name='" + el + "'
or @id='" + el + "']");
+ }
+ }
+
+ private String convertFromLinkElSpec(String el)
+ {
+ if (el.startsWith("link="))
+ el = el.substring(5);
+ return ".//a[text() = '" + el + "']";
+ }
+
+ public void waitForTextPresent(String text)
+ {
+ for (int second = 0; ; second++)
+ {
+ if (second >= timeout)
+ {
+ //System.out.println("[DEBUG] " + page.asXml());
+ Assert.fail("Timeout at waitForTextPresent: " + text);
+ }
+ if (isTextPresent(text))
+ {
+ break;
+ }
+ pause(1000);
+ }
+ }
+
+ public void waitForTextNotPresent(String text)
+ {
+ for (int second = 0; ; second++)
+ {
+ if (second >= timeout)
+ {
+ Assert.fail("Timeout at waitForTextPresent: " + text);
+ }
+ if (isTextPresent(text) == false)
+ {
+ break;
+ }
+ pause(1000);
+ }
+ }
+
+ public boolean isTextPresent(String text)
+ {
+ return page.asText().indexOf(text) > -1;
+ }
+
+ public void shortPause()
+ {
+ pause(shortPause * 1000);
+ }
+
+ public static void pause(long millis)
+ {
+ try
+ {
+ Thread.sleep(millis);
+ }
+ catch (InterruptedException e)
+ {
+ throw new RuntimeException("Interrupted!");
+ }
+ }
+
+ /**
+ * Simulate dragging source element onto a target element
+ *
+ * @param sourceEl source element specification
+ * @param targetEl target element specification
+ */
+ public void dragAndDropToObject(String sourceEl, String targetEl)
+ {
+ System.out.println("--Drag and drop to object--");
+ HtmlElement src = getElement(sourceEl);
+ if (src == null)
+ throw new RuntimeException("No source element: " + sourceEl);
+
+ HtmlElement target = getElement(targetEl);
+ if (target == null)
+ throw new RuntimeException("No target element: " + targetEl);
+
+ src.mouseDown();
+ src.mouseMove();
+ target.mouseMove();
+ target.mouseUp();
+ }
+
+ /**
+ * Simulate clicking Finish inside Page Editor
+ */
+ public void finishPageEdit()
+ {
+ System.out.println("--Finish Page Edit--");
+
waitForElementPresent("//div[@id='UIPageEditor']/div[1]/div/div/div/a[2]");
+ click("//div[@id='UIPageEditor']/div[1]/div/div/div/a[2]");
+ waitForTextNotPresent("Page Editor");
+ }
+
+ /**
+ * Add a new page with the specified name, containing one specific portlet.
+ *
+ * @param categoryTitle application registry category title that contains the portlet
to use
+ * @param portletName portlet name in application registry
+ * @param pageName name of the new page - used for both navigation node, and page
title
+ * @param portletElementToDnD - element specification pointing to the div that is
dragged onto
+ * the content placeholder within the new page
+ */
+ public void addNewPageUpToFinish(String categoryTitle, String portletName, String
pageName, String portletElementToDnD)
+ {
+ System.out.println("--Add new page up to Finish--");
+
+ waitForElementPresent("link=Add New Page");
+ click("link=Add New Page");
+
+ waitForElementPresent("pageName");
+ type("pageName", pageName);
+ type("pageDisplayName", pageName);
+ click("//table[@class='ActionContainer']/tbody/tr/td/div[2]");
+ waitForTextPresent("Empty Layout");
+ click("//table[@class='ActionContainer']/tbody/tr/td/div[2]");
+ if (categoryTitle != null & portletName != null & portletElementToDnD !=
null)
+ {
+ waitForElementPresent("//div[contains(@class,
'Tab')]/a[@title='" + categoryTitle + "']");
+ click("//div[contains(@class, 'Tab')]/a[@title='" +
categoryTitle + "']");
+ waitForTextPresent(portletName);
+ shortPause();
+ dragAndDropToObject(portletElementToDnD,
"//div[@class='UIComponentBlock']");
+ shortPause();
+ }
+ }
+
+}
Added:
portal/trunk/testsuite/htmlunit-tests/src/test/java/org/jboss/gatein/htmlunit/jira/Test_GTNPORTAL_1823_FailToCreatePage.java
===================================================================
---
portal/trunk/testsuite/htmlunit-tests/src/test/java/org/jboss/gatein/htmlunit/jira/Test_GTNPORTAL_1823_FailToCreatePage.java
(rev 0)
+++
portal/trunk/testsuite/htmlunit-tests/src/test/java/org/jboss/gatein/htmlunit/jira/Test_GTNPORTAL_1823_FailToCreatePage.java 2011-03-03
12:37:38 UTC (rev 5957)
@@ -0,0 +1,106 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2011, Red Hat Middleware LLC, and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site:
http://www.fsf.org.
+ */
+
+package org.jboss.gatein.htmlunit.jira;
+
+import org.jboss.gatein.htmlunit.AbstractWebTest;
+import org.testng.annotations.Test;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.atomic.AtomicInteger;
+
+/**
+ * @author <a href="mailto:mstrukel@redhat.com">Marko Strukelj</a>
+ */
+public class Test_GTNPORTAL_1823_FailToCreatePage extends AbstractWebTest
+{
+ /** Number of concurrent threads for the test */
+ private static final int TCOUNT = 2;
+
+ /** Counter for id generation */
+ private static AtomicInteger idCounter = new AtomicInteger(1);
+
+ /** Down counter used to synchronize threads before clicking Finish */
+ private static CountDownLatch sync = new CountDownLatch(TCOUNT);
+
+ /**
+ * Id for inclusion in page title so that every thread uses unique name for the newly
added page
+ *
+ * @return id
+ */
+ public String nextId()
+ {
+ return "" + idCounter.getAndIncrement();
+ }
+
+ /**
+ * This test method relies on TestNG parallel test execution facility
+ * to perform two concurrent executions of this method on a single instance of the
test class
+ *
+ * @throws Throwable if test fails
+ */
+ @Test(invocationCount = TCOUNT, threadPoolSize = TCOUNT, groups = {"GateIn",
"jira", "htmlunit"})
+ public void testGTNPORTAL_1823_FailToCreatePage() throws Throwable
+ {
+ try
+ {
+ test();
+ }
+ finally
+ {
+ // If exception occurs we don't want the other thread to lock up
+ // - so we perform another countDown()
+ sync.countDown();
+ }
+ }
+
+ /**
+ * Main body of the test
+ *
+ * @throws Throwable
+ */
+ private void test() throws Throwable
+ {
+ String id = nextId();
+
+ openPortal(true);
+
+ signInAsRoot();
+
+ // Add new page, but don't click Finish yet at the end
+ String categoryTitle = "Gadgets";
+ String portletName = "Calculator";
+ String pageName = "TestPage" + id;
+ String portletElementToDnD = "//div[@id='" + categoryTitle +
"/" + portletName + "']";
+
+ addNewPageUpToFinish(categoryTitle, portletName, pageName, portletElementToDnD);
+
+ // Wait for the other thread ...
+ sync.countDown();
+ sync.await();
+
+ // Now click Finish (both threads at the same time)
+ finishPageEdit();
+ waitForTextPresent(portletName);
+ }
+
+}
\ No newline at end of file