[embjopr-commits] EMBJOPR SVN: r207 - in trunk/jsfunit/src/test/java/org/jboss/jopr/jsfunit: as5 and 1 other directories.
embjopr-commits at lists.jboss.org
embjopr-commits at lists.jboss.org
Tue Mar 10 20:46:34 EDT 2009
Author: ozizka at redhat.com
Date: 2009-03-10 20:46:33 -0400 (Tue, 10 Mar 2009)
New Revision: 207
Added:
trunk/jsfunit/src/test/java/org/jboss/jopr/jsfunit/util/EmbJoprTestToolkit.java
Modified:
trunk/jsfunit/src/test/java/org/jboss/jopr/jsfunit/ApplicationTestBaseAS5.java
trunk/jsfunit/src/test/java/org/jboss/jopr/jsfunit/EmbjoprTestCase.java
trunk/jsfunit/src/test/java/org/jboss/jopr/jsfunit/as5/ApplicationsPageTest.java
Log:
Moved EmbJoprTestToolkit to standalone class and added an instance of it to EmbJoprTestCase.java
Modified: trunk/jsfunit/src/test/java/org/jboss/jopr/jsfunit/ApplicationTestBaseAS5.java
===================================================================
--- trunk/jsfunit/src/test/java/org/jboss/jopr/jsfunit/ApplicationTestBaseAS5.java 2009-03-11 00:35:30 UTC (rev 206)
+++ trunk/jsfunit/src/test/java/org/jboss/jopr/jsfunit/ApplicationTestBaseAS5.java 2009-03-11 00:46:33 UTC (rev 207)
@@ -21,22 +21,14 @@
*/
package org.jboss.jopr.jsfunit;
-import com.gargoylesoftware.htmlunit.ElementNotFoundException;
-import com.gargoylesoftware.htmlunit.Page;
-import java.util.List;
-import java.util.Set;
+import java.io.IOException;
+import java.net.URL;
+import java.util.*;
import javax.management.*;
+import com.gargoylesoftware.htmlunit.*;
+import com.gargoylesoftware.htmlunit.html.*;
import org.jboss.mx.util.MBeanServerLocator;
-
import org.jboss.jopr.jsfunit.exceptions.*;
-import com.gargoylesoftware.htmlunit.html.*;
-import java.io.IOException;
-import java.net.URL;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Properties;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.math.NumberUtils;
import org.w3c.dom.Element;
@@ -1006,40 +998,6 @@
}
-
- // TODO
- protected class JMXDeploymentInfo {
-
- // Etc...
- public boolean isDeployed(){
- return false;
- }
-
- }
-
- // TODO
- protected class FileDeploymentInfo {
-
- // Etc...
- public boolean isDeployed(){
- return false;
- }
-
- }
-
- // TODO
- protected class EmbJoprDeploymentInfo {
-
- // Etc...
- public boolean isDeployed(){
- return false;
- }
-
- }
-
-
-
-
}// ApplicationTestBaseAS5
Modified: trunk/jsfunit/src/test/java/org/jboss/jopr/jsfunit/EmbjoprTestCase.java
===================================================================
--- trunk/jsfunit/src/test/java/org/jboss/jopr/jsfunit/EmbjoprTestCase.java 2009-03-11 00:35:30 UTC (rev 206)
+++ trunk/jsfunit/src/test/java/org/jboss/jopr/jsfunit/EmbjoprTestCase.java 2009-03-11 00:46:33 UTC (rev 207)
@@ -22,7 +22,6 @@
package org.jboss.jopr.jsfunit;
-import org.jboss.jopr.jsfunit.exceptions.EmbJoprTestException;
import com.gargoylesoftware.htmlunit.BrowserVersion;
import com.gargoylesoftware.htmlunit.html.*;
import java.io.IOException;
@@ -38,19 +37,15 @@
import java.util.regex.Pattern;
import javax.xml.xpath.XPathException;
import org.jboss.profileservice.spi.ProfileService;
-import org.jboss.profileservice.spi.ProfileKey;
+import org.jboss.profileservice.spi.NoSuchDeploymentException;
import javax.naming.InitialContext;
-import org.jboss.deployers.spi.management.ManagementView;
import javax.naming.NamingException;
-import org.jboss.managed.api.ComponentType;
-import org.jboss.managed.api.ManagedProperty;
+import org.jboss.deployers.spi.management.ManagementView;
+import org.jboss.managed.api.*;
import org.jboss.metatype.api.values.MetaValue;
-import org.jboss.managed.api.ManagedComponent;
-import org.jboss.managed.api.ManagedDeployment;
-import org.jboss.profileservice.spi.NoSuchDeploymentException;
import org.jboss.metatype.api.values.SimpleValueSupport;
import org.jboss.jopr.jsfunit.exceptions.EmbJoprTestException;
-import java.io.File;
+import org.jboss.jopr.jsfunit.util.EmbJoprTestToolkit;
/**
@@ -67,6 +62,8 @@
protected final Logger log = Logger.getLogger(this.getClass().getName());
+ protected EmbJoprTestToolkit ejtt;
+
protected boolean isJBoss4;
protected JSFClientSession client;
@@ -109,6 +106,7 @@
.getImplementationVersion();
log.info("Detected AS version: " + version);
isJBoss4 = version.startsWith("4");
+
// Initial JSF request
WebClientSpec wcSpec = new WebClientSpec("/", BrowserVersion.FIREFOX_3);
@@ -125,6 +123,7 @@
this.client = jsfSession.getJSFClientSession();
this.server = jsfSession.getJSFServerSession();
+ this.ejtt = new EmbJoprTestToolkit(client, server);
}
@Override
Modified: trunk/jsfunit/src/test/java/org/jboss/jopr/jsfunit/as5/ApplicationsPageTest.java
===================================================================
--- trunk/jsfunit/src/test/java/org/jboss/jopr/jsfunit/as5/ApplicationsPageTest.java 2009-03-11 00:35:30 UTC (rev 206)
+++ trunk/jsfunit/src/test/java/org/jboss/jopr/jsfunit/as5/ApplicationsPageTest.java 2009-03-11 00:46:33 UTC (rev 207)
@@ -23,21 +23,15 @@
package org.jboss.jopr.jsfunit.as5;
import java.io.IOException;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
+import java.util.*;
import org.apache.commons.lang.StringUtils;
import org.jboss.jopr.jsfunit.AppConstants.DeployableTypes;
import org.jboss.jopr.jsfunit.ApplicationTestBaseAS5;
-import org.jboss.jopr.jsfunit.DebugUtils;
import org.jboss.jopr.jsfunit.exceptions.EmbJoprTestException;
-
-
/**
* This class contains tests for testing the EmbJopr Application
* Management Functions for Enterprise Application archives with JBoss AS 5.
@@ -56,8 +50,8 @@
public void testNavigationToApplications() throws EmbJoprTestException, IOException {
- //DebugUtils.writeFile("target/appNav.html", client.getPageAsText());
-
+ // Wait until the tree is loaded via AJAX.
+ // TODO: navTree.waitForNavTreeLoaded();
sleep(2000);
// Navigate to apps summary tab
@@ -78,7 +72,7 @@
/**
* Test pagination in Applications page.
*
- * FAILS HERE because of EMBJOPR-61.
+ * FAILS because of EMBJOPR-61.
* Bad number of listed rows at page 2. expected:<5> but was:<0>
*/
public void testAppsPagination() throws EmbJoprTestException, IOException {
Added: trunk/jsfunit/src/test/java/org/jboss/jopr/jsfunit/util/EmbJoprTestToolkit.java
===================================================================
--- trunk/jsfunit/src/test/java/org/jboss/jopr/jsfunit/util/EmbJoprTestToolkit.java (rev 0)
+++ trunk/jsfunit/src/test/java/org/jboss/jopr/jsfunit/util/EmbJoprTestToolkit.java 2009-03-11 00:46:33 UTC (rev 207)
@@ -0,0 +1,949 @@
+
+package org.jboss.jopr.jsfunit.util;
+
+
+import com.gargoylesoftware.htmlunit.ElementNotFoundException;
+import com.gargoylesoftware.htmlunit.Page;
+import java.util.*;
+
+import org.jboss.jopr.jsfunit.exceptions.*;
+import com.gargoylesoftware.htmlunit.html.*;
+import java.io.IOException;
+import java.net.URL;
+import org.apache.commons.lang.StringUtils;
+import org.apache.commons.lang.math.NumberUtils;
+import org.jboss.jsfunit.jsfsession.*;
+import org.w3c.dom.Element;
+
+
+
+/**
+ * Embedded Jopr Test Toolkit - helps with testing EmbJopr's web UI
+ * by creating object model of the UI.
+ *
+ * @author Ondrej Zizka
+ */
+public class EmbJoprTestToolkit {
+
+ protected JSFClientSession client;
+ protected JSFServerSession server;
+
+ public JSFClientSession getClient() { return client; }
+ public JSFServerSession getServer() { return server; }
+
+
+ public EmbJoprTestToolkit(JSFClientSession client, JSFServerSession server) {
+ this.client = client;
+ this.server = server;
+ }
+
+
+
+
+
+ /**
+ * Single nav tree instance.
+ *
+ * Using instance instead of static methods is necessary
+ * if we want to subclass this tools for AS 4 tests in the future.
+ */
+ protected final NavTree navTree = new NavTree();
+
+ /**
+ * Single tab menu instance.
+ *
+ * Using instance instead of static methods is necessary
+ * if we want to subclass this tools for AS 4 tests in the future.
+ */
+ protected final TabMenu tabMenu = new TabMenu();
+
+
+
+
+
+
+ /**
+ * Inner class to encapsulate navigation tree operations.
+ *
+ * Note that this class does not hold any element reference,
+ * because the reference becomes invalid with every navigation action.
+ *
+ * Instead, all these methods call client methods.
+ */
+ protected class NavTree {
+
+ public static final String ID_NAV_TREE_FORM = "navTreeForm";
+
+ private void clickRootNode() throws IOException, EmbJoprTestException {
+ DomElement element = (DomElement)client.getElement(ID_NAV_TREE_FORM);
+ if( null == element )
+ throw new HtmlElementNotFoundException("Can't find #"+ID_NAV_TREE_FORM+".");
+
+ // ID changes upon core build?
+ //HtmlAnchor rootNodeLink = element.getFirstByXPath(".//a[@id='navTreeForm:navTree:2::homeLink']");
+
+ // No XSLT 2.0 support :(
+ // javax.xml.transform.TransformerException: Can't find function: matches
+ //HtmlAnchor rootNodeLink = element.getFirstByXPath(
+ // ".//a[matches(@id,'^navTreeForm:navTree:.+::homeLink$')]");
+
+ String xPath = ".//a[ starts-with( @id, '"+ID_NAV_TREE_FORM+":navTree:' ) " +
+ " and contains( @id, '::homeLink' ) ]"; // XPath 2.0: ends-with( @id, '::homeLink' )
+ HtmlAnchor rootNodeLink = element.getFirstByXPath(xPath);
+
+ if( null == rootNodeLink )
+ throw new HtmlElementNotFoundException("Root node not found using XPath: "+xPath);
+
+ rootNodeLink.click();
+ }
+
+
+ public void waitForNavTreeLoaded(){
+ sleep(1500);///
+ // TODO: Use ActiveConditionChecker
+
+ }
+
+
+ /**
+ * Finds the nav tree node by it's link label.
+ *
+ * @param label
+ * @return
+ * @throws org.jboss.jopr.jsfunit.exceptions.HtmlElementNotFoundException
+ * when there's no node with given label.
+ */
+ public NavTreeNode getNodeByLabel( String label ) throws HtmlElementNotFoundException{
+
+ DomElement navTreeForm = (DomElement)client.getElement(ID_NAV_TREE_FORM);
+
+ // A table which has an anchor containing given text.
+ // Note: Different node types have different id endings - typeSummaryLink, categorySummaryLink, ...
+ //String xPath = ".//table[.//td[contains(@id,':text')]//a[contains(@id,'SummaryLink') and normalize-space() = '"+label+"']]";
+ // Node has @id = navTreeForm:navTree:136:137:138:139:143:195::instanceNodeOrLeafLink
+ // Let's rely on the ":text" id part only and suppose there will be just one link in that TD.
+ String xPath = ".//table[.//td[contains(@id,':text')]//a[normalize-space() = '"+label+"']]";
+
+ HtmlTable nodeTable = navTreeForm.getFirstByXPath( xPath );
+
+ if( null == nodeTable )
+ throw new HtmlElementNotFoundException("Node '"+label+"' not found using XPath: "+xPath);
+
+ return new NavTreeNode(nodeTable);
+
+ }
+
+
+ /**
+ * Need a standard JSFUnit API to replace this code.
+ * @see getNodeByLabel().getLabelLink()
+ */
+ public HtmlAnchor getNodeLink(String linkLabel) throws HtmlElementNotFoundException
+ {
+ return getLinkInsideForm(ID_NAV_TREE_FORM, linkLabel);
+ }
+
+
+ /**
+ * Finds the arrow icon in the nav tree that corresponds to the resource
+ * given by resourceName. This method is used to expand tree nodes
+ * (eg. "Web Applications (WAR)", "Datasources", etc.) in the
+ * navigation tree.
+ * @see getNodeByLabel().getArrowLink()
+ */
+ public ClickableElement getNodeArrow(String resourceName) throws HtmlElementNotFoundException
+ {
+ HtmlAnchor link = getNodeLink(resourceName);
+ String id = link.getIdAttribute();
+
+ // An example id is: "navTreeForm:navTree:81:82:83:84::typeSummaryLink"
+ // The icon's id would be: "81:82:83:84::typeSummary:handle:img:collapsed"
+ int index = id.lastIndexOf("Link");
+ id = id.substring(0, index) + ":handle";
+ return (ClickableElement)client.getElement(id);
+ }
+
+ }// class NavTree
+
+
+
+ /**
+ * Represents nav tree node.
+ * Contains convenience methods to work with the node.
+ */
+ protected class NavTreeNode {
+
+ /** Keeps the table element of this node. */
+ private HtmlElement elem;
+ public HtmlElement getElement() { return this.elem; }
+
+ private NavTreeNode( HtmlTable nodeTable ){
+ this.elem = nodeTable;
+ }
+
+ /** Returns true if this node is expanded. */
+ public boolean isExpanded() throws EmbJoprTestException
+ {
+ HtmlAnchor arrowLink = this.getArrowLink();
+ HtmlElement img = (HtmlElement)arrowLink.getFirstByXPath("img[@style='display: none;']");
+
+ if( img.getId().endsWith("expanded") )
+ return false;
+ else if( img.getId().endsWith("collapsed") )
+ return true;
+ else
+ throw new EmbJoprTestException("Can't determine whether nav tree node is expanded.");
+
+ }
+
+ /** Returns the text link of this node. */
+ public HtmlAnchor getLabelLink(){
+ // Until I come up with something smarter, let it be so:
+ String xPath = ".//td[contains(@id,':text')]/a";
+ return (HtmlAnchor) this.elem.getFirstByXPath( xPath );
+ }
+
+ /** Returns the arrow's link. */
+ public HtmlAnchor getArrowLink(){
+ String xPath = ".//td[contains(@id,':handles')]//a[contains(@id,':handle')]";
+ return (HtmlAnchor) this.elem.getFirstByXPath( xPath );
+ }
+
+ /** Clicks the link of the this node. */
+ public void click() throws IOException {
+ this.getLabelLink().click();
+ }
+
+
+ }// class NavTreeNode()
+
+
+
+
+
+
+
+
+ /**
+ * Inner class to encapsulate tab menu operations.
+ */
+ protected class TabMenu {
+
+ public TabContentBox getTabContentBox() throws HtmlElementNotFoundException {
+
+ HtmlElement contentElement = (HtmlElement) client.getElement("content");
+ HtmlElement tabContentBox = (HtmlElement) contentElement.getFirstByXPath("div[@class='tabmenubox']");
+ if( null == tabContentBox )
+ throw new HtmlElementNotFoundException("Tab content box not found using div[@class='tabmenubox'] XPath");
+
+ return new TabContentBox(tabContentBox);
+ }
+
+ public ClickableElement getTab( String label ) throws HtmlElementNotFoundException {
+
+ DomElement element = (DomElement)client.getElement("tabmenu");
+ String xPath = "ul/li/span[normalize-space(string())='"+label+"'] | ul/li/a[normalize-space(string())='"+label+"']";
+ ClickableElement tabContent = element.getFirstByXPath(xPath);
+
+
+ if( null == tabContent )
+ throw new HtmlElementNotFoundException("Tab '"+label+"' not found using XPath '"+xPath+"'");
+
+ return tabContent;
+
+ }
+
+ /** Returns true if the tab with given label is active (it's content is shown). */
+ public boolean isTabActive( String label ) throws IOException, HtmlElementNotFoundException {
+
+ StyledElement tabContent = getTab(label);
+ return "span".equals( tabContent.getTagName() )
+ && tabContent.getClassAttribute().contains("active");
+ }
+
+ /** Returns true if the tab with given label is disabled (grayed and can't be activated). */
+ public boolean isTabDisabled( String label ) throws HtmlElementNotFoundException {
+ StyledElement tabContent = getTab(label);
+ return "span".equals( tabContent.getTagName() )
+ && tabContent.getClassAttribute().contains("disabled");
+ }
+
+ /** Shotcut - getTab(label).click(); Not necesarilly clicks an anchor. */
+ public void clickTab( String label ) throws IOException, ActionNotAvailableException, HtmlElementNotFoundException {
+
+ StyledElement tabContent = getTab(label);
+ if( !( tabContent instanceof ClickableElement ) )
+ throw new ActionNotAvailableException("Tab element <"+tabContent.getTagName()+"> is not clickable: "+label);
+
+ ((ClickableElement)tabContent).click();
+
+ }
+
+ }
+
+
+ /**
+ * Base class for parts that will check their validity before performing actions.
+ * Not necessary if we pay attention to validity, but why not check it -
+ * performance is not a question for us.
+ *
+ * TODO: Instead, use the Page returned from click() etc.
+ */
+ protected class PageContextAwareElement {
+ private URL validForURL;
+ private String validForDate;
+
+ /** Store the context identifiing attributes upon creation. */
+ public PageContextAwareElement() {
+ // TODO: Shouldn't we store the elements's page instead of current?
+ this.validForDate = client.getContentPage().getWebResponse().getResponseHeaderValue("Date");
+ this.validForURL = client.getContentPage().getWebResponse().getUrl();
+ }
+
+ /**
+ * Checks whether this element is still valid in the current web page context,
+ * i.e. whether we are still on the page in which this element existed.
+ * @throws org.jboss.jopr.jsfunit.exceptions.ActionOutOfSyncException
+ */
+ public void checkIfStillValid() throws ActionOutOfSyncException {
+
+ String validForDate_ = client.getContentPage().getWebResponse().getResponseHeaderValue("Date");
+ URL validForURL_ = client.getContentPage().getWebResponse().getUrl();
+
+ if( !validForDate_.equals(this.validForDate) ||
+ !validForURL_.equals(this.validForURL) )
+ {
+ throw new ActionOutOfSyncException(
+ "This element wrapper was created from another page and is not valid now.");
+ }
+ }
+
+ }
+
+ /**
+ * Base class for parts that will check their validity before performing actions.
+ * Not necessary if we pay attention to validity, but why not check it.
+ */
+ protected class PageAware {
+
+ private Page validForPage;
+
+ public PageAware(){
+ this.validForPage = client.getContentPage();
+ }
+
+ /**
+ * Checks whether this element is still valid in the current web page context,
+ * i.e. whether we are still on the page in which this element existed.
+ * @throws org.jboss.jopr.jsfunit.exceptions.ActionOutOfSyncException
+ */
+ public void checkIfStillValid() throws PageHasChangedException {
+ if( !client.getContentPage().equals( this.validForPage ) ){
+ throw new PageHasChangedException(
+ "This element wrapper was created from another page and is not valid now.",
+ client.getContentPage(), this.validForPage );
+ }
+ }
+ }
+
+
+ /**
+ * Inner class for manipulation with tab content box.
+ */
+ protected class TabContentBox extends PageAware {
+
+ private HtmlElement element;
+ public HtmlElement getElement() { return element; }
+
+ public TabContentBox(HtmlElement element) {
+ super();
+ this.element = element;
+ }
+
+ /**
+ * Returns first table under given header.
+ *
+ * Unfortunately, headers are not H2 or similar, but DIV class="instructionalText".
+ * To be revised later.
+ *
+ * @return
+ */
+ public ContentTable getTableUnderHeader( String headerText ) throws ActionOutOfSyncException
+ {
+ checkIfStillValid();
+
+ String xPath = "*[contains(normalize-space(), '"+headerText+"')]/following::table";
+ // [@id='resourceSummaryForm:dataTable'] - is this reliable?
+ HtmlTable tableElement = (HtmlTable) element.getFirstByXPath(xPath);
+ return new ContentTable(tableElement);
+ }
+
+ /**
+ * Returns first table in the content box.
+ * @param headerText
+ * @return
+ * @throws org.jboss.jopr.jsfunit.exceptions.ActionOutOfSyncException
+ */
+ public ContentTable getFirstTable() throws ActionOutOfSyncException
+ {
+ checkIfStillValid();
+
+ String xPath = ".//form//table[contains( normalize-space(@id), ':dataTable')]";
+ // [@id='resourceSummaryForm:dataTable'] - is this reliable?
+ HtmlTable tableElement = (HtmlTable) element.getFirstByXPath(xPath);
+ return new ContentTable(tableElement);
+ }
+
+
+ /**
+ * Finds first button with given label inside this box.
+ * @param label
+ * @return
+ * @throws org.jboss.jopr.jsfunit.exceptions.HtmlElementNotFoundException
+ * @throws org.jboss.jopr.jsfunit.exceptions.ActionOutOfSyncException
+ */
+ public HtmlButtonInput getButtonByLabel( String label )
+ throws HtmlElementNotFoundException, ActionOutOfSyncException {
+
+ checkIfStillValid();
+
+ HtmlButtonInput button = this.element.getFirstByXPath(".//input[normalize-space(@value)='"+label+"']");
+ if( null == button )
+ throw new HtmlElementNotFoundException("Button labelled '"+label+"' not found.");
+
+ return button;
+
+ }
+
+ }// inner class TabContentBox
+
+
+
+ /**
+ * Contains convenience methods for accessing content tables in EmbJopr.
+ */
+ protected class ContentTable {
+
+ public static final String ID_CATEGORY_DATA_TABLE = "categorySummaryForm:dataTable";
+ public static final String ID_RESOURCE_DATA_TABLE = "resourceSummaryForm:dataTable";
+
+ private HtmlTable element;
+ public HtmlTable getElement() { return element; }
+
+ /**
+ * Creates a data table wrapper for the given table element.
+ */
+ public ContentTable( HtmlTable element ) {
+ this.element = element;
+ }
+
+ /**
+ * Creates a data table wrapper for first found element with one of these IDs:
+ * ID_CATEGORY_DATA_TABLE, ID_RESOURCE_DATA_TABLE
+ *
+ * This method assumes there's only one "data table" per page.
+ * If not, it simply returns the first in the order of IDs searched.
+ * You can always specify the element using ContentTable( HtmlTable element ).
+ */
+ public ContentTable() throws HtmlElementNotFoundException {
+
+ // Find the data table - try some known IDs.
+ String[] elemIDs = { ID_CATEGORY_DATA_TABLE, ID_RESOURCE_DATA_TABLE };
+ Element elem = null;
+ for( String elemID : elemIDs ){
+ elem = client.getElement(elemID);
+ if( null != elem )
+ break;
+ }
+ if( null == elem )
+ throw new HtmlElementNotFoundException(
+ "Can't find the content table element, searched IDs: "
+ + elemIDs.toString() );
+
+ this.element = (HtmlTable)elem;
+ }
+
+
+ // Columns maps
+ private List<String> colLabels = null;
+ private Map<String, Integer> colIndexes = null;
+ //private boolean analyzedButNotFound = false;
+
+
+
+ /**
+ * Returns the first row that contains given text, or throws HtmlElementNotFoundException.
+ * @param text
+ * @return
+ * @throws org.jboss.jopr.jsfunit.exceptions.HtmlElementNotFoundException
+ * when no row contains specified text.
+ */
+ public ContentTableRow getFirstRowContainingText( String text )
+ throws HtmlElementNotFoundException
+ {
+ if( 0 == element.getRowCount() )
+ throw new HtmlElementNotFoundException("Table has no rows.");
+
+ // TODO: Escape the single quotes. By doubling?
+ // http://books.google.com/books?id=jzqFMlM0gb0C&pg=PA308&lpg=PA308&dq=xquery+escape+quote&source=bl&ots=DIKQ92AhHh&sig=A7adGlif6jfYKtJXGc4eZbXYeCQ&hl=cs&ei=LYCcSYKLO5ir-gazwfjtBA&sa=X&oi=book_result&resnum=8&ct=result
+ String xPath = ".//tr[contains(string(), '"+text+"')]";
+ HtmlTableRow elm = (HtmlTableRow) element.getFirstByXPath(xPath);
+ if( null == elm )
+ throw new HtmlElementNotFoundException(xPath);
+ return new ContentTableRow(elm, this);
+ }
+
+
+
+ /**
+ * Returns wrapper of the table row which contains a link with given label,
+ * or null when the no such row is found.
+ */
+ public ContentTableRow findFirstRowContainingLink( String linkLabel )
+ {
+ if( 0 == element.getRowCount() )
+ return null;
+
+ String xPath = ".//tr[.//a[normalize-space()='"+linkLabel+"']]";
+ HtmlTableRow elm = (HtmlTableRow) element.getFirstByXPath(xPath);
+ if( null == elm )
+ return null;
+ return new ContentTableRow(elm, this);
+ }
+
+ public List<ContentTableRow> getRows(){
+ if( 0 == element.getRowCount() )
+ return Collections.EMPTY_LIST;
+
+ String xPath = "./tbody/tr";
+ List<HtmlTableRow> trList = (List) element.getByXPath(xPath);
+ List<ContentTableRow> rows = new ArrayList(trList.size());
+ for (HtmlTableRow tr : trList) {
+ rows.add( new ContentTableRow(tr, this));
+ }
+ return rows;
+ }
+
+ /**
+ * Returns wrapper of the table row which contains a link with given label.
+ * @throws org.jboss.jopr.jsfunit.exceptions.HtmlElementNotFoundException
+ * when no row with such label found.
+ */
+ public ContentTableRow getFirstRowContainingLink( String linkLabel )
+ throws HtmlElementNotFoundException
+ {
+ if( 0 == element.getRowCount() )
+ throw new HtmlElementNotFoundException("Table has no rows.");
+
+ String xPath = ".//tr[.//a[normalize-space()='"+linkLabel+"']]";
+ HtmlTableRow elm = (HtmlTableRow) element.getFirstByXPath(xPath);
+ if( null == elm )
+ throw new HtmlElementNotFoundException(
+ "Can't find row containing link '"+linkLabel+"' using XPath: "+xPath);
+ return new ContentTableRow(elm, this);
+ }
+
+ /**
+ * Creates a list of columns headers
+ * and a label => col index map.
+ */
+ public void analyzeColumns() throws HtmlElementNotFoundException
+ {
+
+ /*if( this.analyzedButNotFound )
+ throw new HtmlElementNotFoundException("Table has no column headers.");
+ /**/ // Give it another chance, JavaScript could change it.
+
+ // Get all TH from the first THEAD row that contains TH.
+ String xPath = "./thead/tr[th and position()=1]/th";
+ List<HtmlTableHeaderCell> colHeaders = (List<HtmlTableHeaderCell>) this.element.getByXPath(xPath);
+
+ if( 0 == colHeaders.size() ){
+ //this.analyzedButNotFound = true;
+ throw new HtmlElementNotFoundException("Table has no column headers.");
+ }
+
+ List<String> colLabels_ = new ArrayList(colHeaders.size());
+ Map<String, Integer> colIndexes_ = new HashMap(colHeaders.size());
+
+ //for( HtmlTableHeaderCell th : colHeaders ){
+ for( int i = 0; i < colHeaders.size(); i++ ) {
+ HtmlTableHeaderCell th = colHeaders.get(i);
+ String sHeader = th.getTextContent();
+ colLabels_.add( sHeader );
+ colIndexes_.put( sHeader, i );
+ }
+
+ this.colLabels = colLabels_;
+ this.colIndexes = colIndexes_;
+
+ }
+
+ /**
+ * Returns an index of the column with given name in the TH header,
+ * or throws HtmlElementNotFound in two cases:
+ * 1) Table does not have column headers
+ * 2) No header with such name was found.
+ *
+ * @param colName
+ * @return
+ * @throws org.jboss.jopr.jsfunit.exceptions.HtmlElementNotFoundException
+ */
+ public int getColumnIndexByName( String colName ) throws HtmlElementNotFoundException {
+ if( null == this.colIndexes )
+ this.analyzeColumns();
+
+ Integer index = this.colIndexes.get(colName);
+ if( null == index )
+ throw new HtmlElementNotFoundException("No column named '"+colName+"'.");
+
+ return index;
+ }
+
+ }// inner class ContentTable
+
+
+
+
+
+ /**
+ * Provides extra method that parses text-like info table (with one column).
+ */
+ protected class ContentInfoTable extends ContentTable {
+
+ public ContentInfoTable(HtmlTable element) {
+ super(element);
+ }
+
+ /**
+ * Parses the content of the table for properties.
+ * @return
+ */
+ public Properties getProperties()
+ {
+ Properties props = new Properties();
+
+ // The template has label in span/strong and the value as text in td.
+ String xPath = ".//tr/td[span/strong]";
+ List<HtmlTableCell> cells = (List<HtmlTableCell>) this.getElement().getByXPath(xPath);
+ for( HtmlTableCell cell : cells ){
+ String[] parts = cell.getTextContent().split(":");
+ props.put(parts[0], parts[1]);
+ }
+ return props;
+ }
+
+ }// inner class ContentInfoTable
+
+
+
+ /**
+ * Row of a content table.
+ * Contains convenience methods for accessing content table rows in EmbJopr.
+ */
+ protected class ContentTableRow {
+
+ private HtmlTableRow element;
+ public HtmlTableRow getElement() { return element; }
+
+ private ContentTable containingTable;
+
+ private ContentTableRow(HtmlTableRow elm, ContentTable containingTable) {
+ this.element = elm;
+ this.containingTable = containingTable;
+ }
+
+ /**
+ * Finds a <button> or <input type="button"> with the given label.
+ * @param label The label of the button. Compared to a trimmed label text of the button.
+ * @returns the button element - either HtmlButtonInput or HtmlButton.
+ * @throws org.jboss.jopr.jsfunit.exceptions.HtmlElementNotFoundException
+ */
+ public ClickableElement getButtonByLabel( String label ) throws HtmlElementNotFoundException
+ {
+ String xPath = ".//input[@type='button' and normalize-space(@value) = '"+label+"']" +
+ " || .//button[normalize-space() = '"+label+"']";
+ HtmlElement elm = this.element.getFirstByXPath(xPath);
+ if( null == elm )
+ throw new HtmlElementNotFoundException("Can't find the button using xPath: "+xPath);
+ if( !(elm instanceof HtmlButton ) && !(elm instanceof HtmlButtonInput) )
+ throw new HtmlElementNotFoundException("Element is not a button, but: "+elm.getClass().getName());
+
+ return (ClickableElement)elm;
+ }
+
+
+ /**
+ * Gives the (first) link from the cell of this row, from the column with given header.
+ * @param colName
+ * @return
+ * @throws org.jboss.jopr.jsfunit.exceptions.HtmlElementNotFoundException
+ * in two cases:
+ * 1) Table has no column of given name
+ * 2) There's no link in that cell.
+ */
+ public HtmlAnchor getFirstLinkFromColumn(String colName) throws HtmlElementNotFoundException
+ {
+ HtmlTableCell cell = this.getCellByColumnName(colName);
+
+ String xPath = ".//a";
+ HtmlAnchor link = (HtmlAnchor) this.element.getFirstByXPath(xPath);
+
+ if( null == link )
+ throw new HtmlElementNotFoundException("No link found in column '"+colName+"'");
+
+ return link;
+ }
+
+
+ /**
+ * Returns the link with given label.
+ * @param string
+ */
+ public HtmlAnchor getLinkByLabel(String linkLabel) throws HtmlElementNotFoundException {
+ String xPath = ".//a[normalize-space()='"+linkLabel+"']";
+ HtmlAnchor link = (HtmlAnchor) this.element.getFirstByXPath(xPath);
+ if( null == link ){
+ StringBuilder sb = new StringBuilder();
+ List<HtmlElement> linksFound = this.element.getHtmlElementsByTagName("a");
+ for( HtmlElement linkFound : linksFound ){
+ sb.append("'").append( ((HtmlAnchor)linkFound).getTextContent() ).append("', ");
+ }
+ String availLinks = StringUtils.removeEnd( sb.toString(), ", " );
+
+ throw new HtmlElementNotFoundException("Can't find link using '"+xPath+"', available: "+availLinks);
+ }
+ return link;
+ }
+
+ /**
+ * Returns the cell of this table from given index,
+ * or throws IndexOutOfBoundsException.
+ *
+ * TODO: May throw IndexOutOfBoundsException - leave unchecked?
+ *
+ * @param index
+ * @return
+ */
+ public HtmlTableCell getCell( int index ){
+ HtmlTableCell cell = this.element.getCell(index);
+ return cell;
+ }
+
+ /**
+ * Returns this row's cell element from the column with specified name.
+ * @param colName Name of the column.
+ * @throws org.jboss.jopr.jsfunit.exceptions.HtmlElementNotFoundException
+ * if no such column exists in the table.
+ */
+ public HtmlTableCell getCellByColumnName( String colName ) throws HtmlElementNotFoundException
+ {
+ int index = this.containingTable.getColumnIndexByName(colName);
+ return getCell(index);
+ }
+
+ /** Shortcut - returns text content of this row's cell from given column. */
+ public String getCellTextByColumnName( String colName ) throws HtmlElementNotFoundException {
+ return this.getCellByColumnName(colName).getTextContent();
+ }
+
+
+ }// inner class ContentTableRow
+
+
+
+
+ /**
+ * Pagination control
+ * Not tested yet.
+ */
+ public class ContentBoxPagination {
+
+ //private HtmlElement element;
+ //public HtmlElement getElement() { return element; }
+
+ private static final String ID_PAGE_CONTROLS = "categorySummaryForm:dataTableScroller";
+ private static final String ID_PAGE_SIZE_SELECT = "categorySummaryForm:currentPageSize";
+ private static final String ID_PAGINATION_TOTAL_ITEMS = "paginationTotalItems";
+
+ protected HtmlDivision getPageContols(){
+ return (HtmlDivision) client.getElement(ID_PAGE_CONTROLS);
+ }
+
+ protected HtmlSelect getPageSizeSelect(){
+ return (HtmlSelect) client.getElement(ID_PAGE_SIZE_SELECT);
+ }
+
+ public int getTotalItemsCount() throws ActionNotAvailableException
+ {
+ Element e = client.getElement(ID_PAGINATION_TOTAL_ITEMS);
+ String textContent = e.getTextContent();
+ String[] parts = textContent.split(":");
+ if( parts.length < 2 )
+ throw new ActionNotAvailableException("Total pagination items count expected after 'Total:' or similar.");
+
+ String countStr = parts[1].trim();
+ try{
+ return NumberUtils.createInteger( countStr );
+ }catch(NumberFormatException ex ){
+ throw new ActionNotAvailableException("Can't parse pagination items count from '"+countStr+"'", ex);
+ }
+ }
+
+ protected HtmlSpan getGoSpan( String spanLabel ) throws HtmlElementNotFoundException {
+ String xPath = ".//span[normalize-space() = '"+spanLabel+"']";
+ HtmlSpan span = getPageContols().getFirstByXPath(xPath);
+ if( null == span )
+ throw new HtmlElementNotFoundException(
+ "Span with '"+spanLabel+"' not found using XPath '"+xPath+"'");
+ return span;
+ }
+
+ protected HtmlTableCell getGoPage( int pageNumber ) throws HtmlElementNotFoundException{
+ String xPath = ".//td[normalize-space() = '"+pageNumber+"']";
+ HtmlElement td = getPageContols().getFirstByXPath(xPath);
+ if( null == td )
+ throw new HtmlElementNotFoundException(
+ "Page number "+pageNumber+" not found. Try 1 - "+this.getPageCount());
+ return (HtmlTableCell) td;
+ }
+
+
+ public boolean goFirst() throws IOException, HtmlElementNotFoundException{
+ // TODO: Compare old and new page object reference?
+ HtmlSpan goSpan = getGoSpan("First");
+ goSpan.click();
+ return !"".equals( ((HtmlTableCell)goSpan.getParentNode()).getOnClickAttribute() );
+ }
+
+ public boolean goPrev() throws IOException, HtmlElementNotFoundException{
+ HtmlSpan goSpan = getGoSpan("Prev");
+ goSpan.click();
+ return !"".equals( ((HtmlTableCell)goSpan.getParentNode()).getOnClickAttribute() );
+ }
+
+ public boolean goNext() throws IOException, HtmlElementNotFoundException{
+ HtmlSpan goSpan = getGoSpan("Next");
+ goSpan.click();
+ return !"".equals( ((HtmlTableCell)goSpan.getParentNode()).getOnClickAttribute() );
+ }
+
+ public boolean goLast() throws IOException, HtmlElementNotFoundException{
+ HtmlSpan goSpan = getGoSpan("Last");
+ goSpan.click();
+ return !"".equals( ((HtmlTableCell)goSpan.getParentNode()).getOnClickAttribute() );
+ }
+
+ public void goPage( int pageNumber ) throws IOException, HtmlElementNotFoundException{
+ getGoPage(pageNumber).click();
+ }
+
+
+ public boolean isPageActive( int pageNumber ) throws IOException, HtmlElementNotFoundException{
+ return !getGoPage(pageNumber).getStyleAttribute().contains("-inact");
+ }
+
+ public int getPageCount(){
+ String xPath = ".//td[ count(./*) = 0 and normalize-space() > 0 ]";
+ List<?> elements = getPageContols().getByXPath(xPath);
+ return elements.size();
+ }
+
+ public int getItemsPerPage() throws HtmlElementNotFoundException, ActionNotAvailableException {
+ String selectText = getPageSizeSelect().asText();
+ try {
+ return NumberUtils.createInteger( selectText );
+ }
+ catch( NumberFormatException ex ){
+ throw new ActionNotAvailableException("Can't parse 'items per page' from '"+selectText+"'.", ex);
+ }
+ }
+ public void setItemsPerPage( int num ) throws HtmlElementNotFoundException {
+ String optionValue = ""+num;
+ HtmlSelect pageSizeSelect = getPageSizeSelect();
+
+ try{
+ pageSizeSelect.getOptionByValue(optionValue);
+ }
+ catch( ElementNotFoundException ex ){
+ // Print out available options.
+ StringBuilder sb = new StringBuilder(pageSizeSelect.getOptionSize());
+ for( HtmlOption opt : pageSizeSelect.getOptions() ){
+ sb.append(" ").append(opt.getValueAttribute());
+ }
+ String possibleOptions = sb.toString().trim().replace(" ", ", ");
+
+ throw new HtmlElementNotFoundException("Specified option is invalid. Try one of: "+possibleOptions, ex);
+ }
+
+ pageSizeSelect.setSelectedAttribute(optionValue, true);
+ }
+
+ }// ContentBoxPagination
+
+
+
+ /**
+ * Finds a <a> tag inside a form that has a particular label.
+ *
+ * TODO: Create Form wrapper.
+ */
+ public HtmlAnchor getLinkInsideForm(String formId, String linkLabel) throws HtmlElementNotFoundException
+ {
+ HtmlForm form = (HtmlForm)client.getElement(formId);
+ String xPath = ".//a[contains(normalize-space(), '"+linkLabel+"']";
+ HtmlAnchor link = form.getFirstByXPath(xPath);
+ if( null == link )
+ throw new HtmlElementNotFoundException("Can't find row containing link '"+linkLabel+"' using XPath: "+xPath);
+ return link;
+ }
+
+
+
+
+ /** Calls Thread.sleep(ms), ignores the InterruptedException. */
+ @SuppressWarnings("empty-statement")
+ public static void sleep( int ms ) {
+ try {
+ Thread.sleep(3000);
+ } catch (InterruptedException ex) {
+ ; // We don't care, that's the purpose of this method.
+ }
+ }
+
+
+
+ // TODO
+ protected class JMXDeploymentInfo {
+
+ // Etc...
+ public boolean isDeployed(){
+ return false;
+ }
+
+ }
+
+ // TODO
+ protected class FileDeploymentInfo {
+
+ // Etc...
+ public boolean isDeployed(){
+ return false;
+ }
+
+ }
+
+ // TODO
+ protected class EmbJoprDeploymentInfo {
+
+ // Etc...
+ public boolean isDeployed(){
+ return false;
+ }
+
+ }
+
+
+
+
+}// class EmbJoprTestToolkit
More information about the embjopr-commits
mailing list