Revision: 901
http://jwebunit.svn.sourceforge.net/jwebunit/?rev=901&view=rev
Author: henryju
Date: 2011-03-21 16:20:16 +0000 (Mon, 21 Mar 2011)
Log Message:
-----------
Improved support of webdriver.
Modified Paths:
--------------
branches/webdriver/jwebunit-commons-tests/src/main/java/net/sourceforge/jwebunit/tests/FormSubmissionTest.java
branches/webdriver/jwebunit-commons-tests/src/main/java/net/sourceforge/jwebunit/tests/FramesAndWindowsTest.java
branches/webdriver/jwebunit-commons-tests/src/main/resources/testcases/FormSubmissionTest/InvalidActionForm.html
branches/webdriver/jwebunit-htmlunit-plugin/src/main/java/net/sourceforge/jwebunit/htmlunit/HtmlUnitTestingEngineImpl.java
branches/webdriver/jwebunit-webdriver-plugin/src/main/java/net/sourceforge/jwebunit/webdriver/WebDriverTestingEngineImpl.java
branches/webdriver/jwebunit-webdriver-plugin/src/test/java/net/sourceforge/jwebunit/webdriver/JWebUnitTest.java
Added Paths:
-----------
branches/webdriver/jwebunit-webdriver-plugin/pom.xml
branches/webdriver/jwebunit-webdriver-plugin/src/main/java/net/sourceforge/jwebunit/webdriver/WebdriverElementImpl.java
Modified:
branches/webdriver/jwebunit-commons-tests/src/main/java/net/sourceforge/jwebunit/tests/FormSubmissionTest.java
===================================================================
---
branches/webdriver/jwebunit-commons-tests/src/main/java/net/sourceforge/jwebunit/tests/FormSubmissionTest.java
2011-03-18 22:07:48 UTC (rev 900)
+++
branches/webdriver/jwebunit-commons-tests/src/main/java/net/sourceforge/jwebunit/tests/FormSubmissionTest.java
2011-03-21 16:20:16 UTC (rev 901)
@@ -64,7 +64,7 @@
setTextField("text", "sometext");
submit("button");
assertTextPresent("Submitted parameters");
- assertTextPresent("Params are:" + System.getProperty("line.separator")
+ "text=sometext");
+ assertTextPresent("Params are:\ntext=sometext");
clickLink("return");
setTextField("text", "anothertext");
submit();
@@ -134,7 +134,7 @@
checkCheckbox("checkBox", "3");
checkCheckbox("checkBox", "3"); // check for duplicates
submit();
- assertTextPresent("checkBox=1,3" +
System.getProperty("line.separator"));
+ assertTextPresent("checkBox=1,3\n");
}
@Test
@@ -156,7 +156,7 @@
setTextField("color", "blue");
uncheckCheckbox("checkBox");
submit();
- assertTextPresent("color=blue" + System.getProperty("line.separator"));
+ assertTextPresent("color=blue\n");
}
@Test
@@ -165,7 +165,7 @@
clickRadioOption("radio", "1");
assertRadioOptionSelected("radio", "1");
submit();
- assertTextPresent("radio=1" + System.getProperty("line.separator"));
+ assertTextPresent("radio=1\n");
clickLink("return");
clickRadioOption("radio", "2");
clickRadioOption("radio", "3");
@@ -173,7 +173,7 @@
assertRadioOptionNotSelected("radio", "2");
assertRadioOptionSelected("radio", "3");
submit();
- assertTextPresent("radio=3" + System.getProperty("line.separator"));
+ assertTextPresent("radio=3\n");
}
@Test
@@ -181,7 +181,7 @@
beginAt("/SingleUnnamedButtonForm.html");
setTextField("color", "blue");
submit();
- assertTextPresent("color=blue" + System.getProperty("line.separator"));
+ assertTextPresent("color=blue\n");
}
@Test
@@ -196,7 +196,7 @@
public void testSingleFormMultipleButtonSubmission() {
gotoMultiButtonPage();
submit("color");
- assertTextPresent("Params are:" + System.getProperty("line.separator")
+ "color=red");
+ assertTextPresent("Params are:\ncolor=red");
gotoMultiButtonPage();
submit("color", "blue");
assertTextPresent("color=blue");
@@ -284,7 +284,7 @@
beginAt("/MultiFormPage.html");
setTextField("param2", "anyvalue");
submit("button2b");
- assertTextPresent("param2=anyvalue" +
System.getProperty("line.separator"));
+ assertTextPresent("param2=anyvalue\n");
assertTextPresent("button2b=b2b");
}
Modified:
branches/webdriver/jwebunit-commons-tests/src/main/java/net/sourceforge/jwebunit/tests/FramesAndWindowsTest.java
===================================================================
---
branches/webdriver/jwebunit-commons-tests/src/main/java/net/sourceforge/jwebunit/tests/FramesAndWindowsTest.java
2011-03-18 22:07:48 UTC (rev 900)
+++
branches/webdriver/jwebunit-commons-tests/src/main/java/net/sourceforge/jwebunit/tests/FramesAndWindowsTest.java
2011-03-21 16:20:16 UTC (rev 901)
@@ -55,7 +55,7 @@
@Test public void testGotoWindow() {
gotoRootAndOpenChild("ChildPage1");
gotoWindow("ChildPage1");
- assertTextPresent("child 1");
+ assertTextPresent("Child Page 1");
}
@Test public void testGotoWindowByID() {
@@ -87,7 +87,7 @@
assertTitleEquals("This is the Root");
clickLink("ChildPage1");
gotoWindow("ChildPage1");
- assertTextPresent("child 1");
+ assertTextPresent("Child Page 1");
closeWindow();
assertWindowCountEquals(1);
assertTitleEquals("This is the Root");
@@ -161,7 +161,7 @@
assertFormPresent();
setTextField("color", "red");
submit("submit");
- assertTextPresent("color=red" + System.getProperty("line.separator"));
+ assertTextPresent("color=red\n");
}
@Test public void testFormInputInInlineFrame() {
@@ -170,7 +170,7 @@
assertFormPresent();
setTextField("color", "red");
submit("submit");
- assertTextPresent("color=red" + System.getProperty("line.separator"));
+ assertTextPresent("color=red\n");
}
//TODO this just posts to a new frameset inside the frame, is the test
needed?
Modified:
branches/webdriver/jwebunit-commons-tests/src/main/resources/testcases/FormSubmissionTest/InvalidActionForm.html
===================================================================
---
branches/webdriver/jwebunit-commons-tests/src/main/resources/testcases/FormSubmissionTest/InvalidActionForm.html
2011-03-18 22:07:48 UTC (rev 900)
+++
branches/webdriver/jwebunit-commons-tests/src/main/resources/testcases/FormSubmissionTest/InvalidActionForm.html
2011-03-21 16:20:16 UTC (rev 901)
@@ -23,9 +23,9 @@
<head></head>
<body>
<form method=GET action="nonExistingPage">
- <input name="button1" value="b1" type=submit>
- <input name="color" value="red" type=submit>
- <input name="color" value="blue" type=submit>
+ <input name="button1" value="b1" type="submit">
+ <input name="color" value="red" type="submit">
+ <input name="color" value="blue" type="submit">
</form>
</body>
</html>
\ No newline at end of file
Modified:
branches/webdriver/jwebunit-htmlunit-plugin/src/main/java/net/sourceforge/jwebunit/htmlunit/HtmlUnitTestingEngineImpl.java
===================================================================
---
branches/webdriver/jwebunit-htmlunit-plugin/src/main/java/net/sourceforge/jwebunit/htmlunit/HtmlUnitTestingEngineImpl.java
2011-03-18 22:07:48 UTC (rev 900)
+++
branches/webdriver/jwebunit-htmlunit-plugin/src/main/java/net/sourceforge/jwebunit/htmlunit/HtmlUnitTestingEngineImpl.java
2011-03-21 16:20:16 UTC (rev 901)
@@ -713,7 +713,7 @@
public String getPageText() {
Page page = win.getEnclosedPage();
if (page instanceof HtmlPage) {
- return ((HtmlPage) page).asText();
+ return ((HtmlPage) page).getBody().asText();
}
if (page instanceof TextPage) {
return ((TextPage) page).getContent();
@@ -1365,7 +1365,7 @@
* @return <code>true</code> when the button with text could be found.
*/
public boolean hasButtonWithText(String text) {
- return getButtonWithText(text) != null ? true : false;
+ return getButtonWithText(text) != null;
}
/**
Added: branches/webdriver/jwebunit-webdriver-plugin/pom.xml
===================================================================
--- branches/webdriver/jwebunit-webdriver-plugin/pom.xml
(rev 0)
+++ branches/webdriver/jwebunit-webdriver-plugin/pom.xml 2011-03-21
16:20:16 UTC (rev 901)
@@ -0,0 +1,67 @@
+<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/xsd/maven-4.0.0.xsd">
+ <parent>
+ <artifactId>jwebunit</artifactId>
+ <groupId>net.sourceforge.jwebunit</groupId>
+ <version>3.0-SNAPSHOT</version>
+ <relativePath>../pom.xml</relativePath>
+ </parent>
+ <modelVersion>4.0.0</modelVersion>
+ <artifactId>jwebunit-webdriver-plugin</artifactId>
+ <name>Webdriver Plugin</name>
+ <description>Webdriver plugin for JWebUnit.</description>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-surefire-plugin</artifactId>
+ <configuration>
+ <testFailureIgnore>true</testFailureIgnore>
+ <skip>true</skip>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+ <dependencies>
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit-dep</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.seleniumhq.selenium</groupId>
+ <artifactId>selenium-htmlunit-driver</artifactId>
+ <version>2.0b2</version>
+ </dependency>
+ <dependency>
+ <groupId>org.seleniumhq.selenium</groupId>
+ <artifactId>selenium-support</artifactId>
+ <version>2.0b2</version>
+ </dependency>
+ <dependency>
+ <groupId>net.sourceforge.jwebunit</groupId>
+ <artifactId>jwebunit-core</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>net.sourceforge.jwebunit</groupId>
+ <artifactId>jwebunit-commons-tests</artifactId>
+ <version>${project.version}</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-api</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>ch.qos.logback</groupId>
+ <artifactId>logback-classic</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>javax.servlet</groupId>
+ <artifactId>servlet-api</artifactId>
+ </dependency>
+ </dependencies>
+ <properties>
+ <topDirectoryLocation>..</topDirectoryLocation>
+ </properties>
+</project>
Modified:
branches/webdriver/jwebunit-webdriver-plugin/src/main/java/net/sourceforge/jwebunit/webdriver/WebDriverTestingEngineImpl.java
===================================================================
---
branches/webdriver/jwebunit-webdriver-plugin/src/main/java/net/sourceforge/jwebunit/webdriver/WebDriverTestingEngineImpl.java
2011-03-18 22:07:48 UTC (rev 900)
+++
branches/webdriver/jwebunit-webdriver-plugin/src/main/java/net/sourceforge/jwebunit/webdriver/WebDriverTestingEngineImpl.java
2011-03-21 16:20:16 UTC (rev 901)
@@ -18,18 +18,23 @@
*/
package net.sourceforge.jwebunit.webdriver;
+import org.apache.regexp.RE;
+import org.apache.regexp.RESyntaxException;
+
+import com.gargoylesoftware.htmlunit.html.HtmlElement;
+
import com.gargoylesoftware.htmlunit.BrowserVersion;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
+import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
-import java.util.logging.Level;
-
+import net.sourceforge.jwebunit.api.HttpHeader;
import net.sourceforge.jwebunit.api.IElement;
import net.sourceforge.jwebunit.api.ITestingEngine;
import net.sourceforge.jwebunit.exception.ExpectedJavascriptAlertException;
@@ -43,12 +48,13 @@
import net.sourceforge.jwebunit.util.TestContext;
import org.openqa.selenium.By;
import org.openqa.selenium.Cookie;
+import org.openqa.selenium.JavascriptExecutor;
import org.openqa.selenium.NoSuchElementException;
import org.openqa.selenium.NoSuchWindowException;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.htmlunit.HtmlUnitDriver;
-
+import org.openqa.selenium.support.ui.Select;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -76,6 +82,10 @@
public void beginAt(URL aInitialURL, TestContext aTestContext) throws
TestingEngineResponseException {
this.setTestContext(aTestContext);
driver = new HtmlUnitDriver(BrowserVersion.FIREFOX_3);
+ ((HtmlUnitDriver) driver).setJavascriptEnabled(true);
+
+ //Reset form
+ formIdent = null;
gotoPage(aInitialURL);
}
@@ -85,10 +95,12 @@
}
public void closeBrowser() throws ExpectedJavascriptAlertException,
ExpectedJavascriptConfirmException, ExpectedJavascriptPromptException {
+ formIdent = null;
driver.close();
}
public void gotoPage(URL url) throws TestingEngineResponseException {
+ formIdent = null;
driver.get(url.toString());
}
@@ -167,11 +179,11 @@
}
public void gotoWindow(int windowID) {
- driver.switchTo().window("" + windowID);
+ throw new UnsupportedOperationException("Not supported yet.");
}
public void gotoRootWindow() {
- driver.switchTo().window("top");
+ throw new UnsupportedOperationException("Not supported yet.");
}
public int getWindowCount() {
@@ -179,6 +191,7 @@
}
public void closeWindow() {
+ formIdent = null;
driver.close();
}
@@ -262,139 +275,222 @@
}
public String getTextFieldValue(String paramName) {
- WebElement e = getWebElementByXPath("/input[@type='text' and @name='"
+ paramName + "']", false);
+ WebElement e = getWebElementByXPath("//input[@type='text' and @name='"
+ paramName + "']", false);
return e.getValue();
}
public String getHiddenFieldValue(String paramName) {
- throw new UnsupportedOperationException("Not supported yet.");
+ WebElement e = getWebElementByXPath("//input[@type='hidden' and
@name='" + paramName + "']", false);
+ return e.getValue();
}
public void setTextField(String inputName, String text) {
- WebElement e = getWebElementByXPath("/input[@type='text' and @name='"
+ inputName + "']", false);
+ WebElement e = getWebElementByXPath("//input[@type='text' and @name='"
+ inputName + "']", false);
if (e == null) {
- e = getWebElementByXPath("/textarea[@name='" + inputName + "']",
false);
+ e = getWebElementByXPath("//textarea[@name='" + inputName + "']",
false);
}
if (e == null) {
- e = getWebElementByXPath("/input[@type='file' and @name='" +
inputName + "']", false);
+ e = getWebElementByXPath("//input[@type='file' and @name='" +
inputName + "']", false);
}
e.clear();
e.sendKeys(text);
}
public void setHiddenField(String inputName, String text) {
- throw new UnsupportedOperationException("Not supported yet.");
+ WebElement e = getWebElementByXPath("//input[@type='hidden' and
@name='" + inputName + "']", false);
+ ((JavascriptExecutor)driver).executeScript("arguments[0].value=" +
escapeQuotes(text), e);
}
public String[] getSelectOptionValues(String selectName) {
- throw new UnsupportedOperationException("Not supported yet.");
+ return getSelectOptionValues(selectName, 0);
}
public String[] getSelectOptionValues(String selectName, int index) {
- throw new UnsupportedOperationException("Not supported yet.");
+ Select select = new Select(getWebElementByXPath("//select[@name='" +
selectName + "' and position()=" + (index + 1) + "]", true));
+ ArrayList<String> result = new ArrayList<String>();
+ for (WebElement opt : select.getOptions()) {
+ result.add(opt.getValue());
+ }
+ return result.toArray(new String[result.size()]);
}
public String[] getSelectedOptions(String selectName) {
- throw new UnsupportedOperationException("Not supported yet.");
+ return getSelectedOptions(selectName, 0);
}
+ private String[] getSelectedOptions(Select select) {
+ String[] result = new String[select.getAllSelectedOptions().size()];
+ int i = 0;
+ for (WebElement opt : select.getAllSelectedOptions()) {
+ result[i++] = opt.getValue();
+ }
+ return result;
+ }
+
public String[] getSelectedOptions(String selectName, int index) {
- throw new UnsupportedOperationException("Not supported yet.");
+ Select select = new Select(getWebElementByXPath("//select[@name='" +
selectName + "' and position()=" + (index + 1) + "]", true));
+ return getSelectedOptions(select);
}
+ private String getSelectOptionValueForLabel(Select select, String label) {
+ for (WebElement opt : select.getOptions()) {
+ if (opt.getText().equals(label)) {
+ return opt.getValue();
+ }
+ }
+ throw new RuntimeException("Unable to find option " + label);
+ }
+
+ private String getSelectOptionLabelForValue(Select select, String value) {
+ for (WebElement opt : select.getOptions()) {
+ if (opt.getValue().equals(value)) {
+ return opt.getText();
+ }
+ }
+ throw new RuntimeException("Unable to find option " + value);
+ }
+
public String getSelectOptionLabelForValue(String selectName, String
optionValue) {
- throw new UnsupportedOperationException("Not supported yet.");
+ Select select = new Select(getWebElementByXPath("//select[@name='" +
selectName + "']", true));
+ return getSelectOptionLabelForValue(select, optionValue);
}
public String getSelectOptionLabelForValue(String selectName, int index,
String optionValue) {
- throw new UnsupportedOperationException("Not supported yet.");
+ Select select = new Select(getWebElementByXPath("//select[@name='" +
selectName + "' and position()=" + (index + 1) + "]", true));
+ return getSelectOptionLabelForValue(select, optionValue);
}
public String getSelectOptionValueForLabel(String selectName, String
optionLabel) {
- throw new UnsupportedOperationException("Not supported yet.");
+ Select select = new Select(getWebElementByXPath("//select[@name='" +
selectName + "']", true));
+ return getSelectOptionValueForLabel(select, optionLabel);
}
public String getSelectOptionValueForLabel(String selectName, int index,
String optionLabel) {
- throw new UnsupportedOperationException("Not supported yet.");
+ Select select = new Select(getWebElementByXPath("//select[@name='" +
selectName + "' and position()=" + (index + 1) + "]", true));
+ return getSelectOptionValueForLabel(select, optionLabel);
}
public void selectOptions(String selectName, String[] optionValues) {
- throw new UnsupportedOperationException("Not supported yet.");
+ selectOptions(selectName, 0, optionValues);
}
public void selectOptions(String selectName, int index, String[]
optionValues) {
- throw new UnsupportedOperationException("Not supported yet.");
+ Select select = new Select(getWebElementByXPath("//select[@name='" +
selectName + "' and position()=" + (index + 1) + "]", true));
+ if (!select.isMultiple() && optionValues.length > 1)
+ throw new RuntimeException("Multiselect not enabled");
+ for (String option : optionValues) {
+ boolean found = false;
+ for (WebElement opt : select.getOptions()) {
+ if (opt.getValue().equals(option)) {
+ select.selectByValue(option);
+ found = true;
+ break;
+ }
+ }
+ if (!found) {
+ throw new RuntimeException("Option " + option
+ + " not found");
+ }
+ }
}
public void unselectOptions(String selectName, String[] optionValues) {
- throw new UnsupportedOperationException("Not supported yet.");
+ unselectOptions(selectName, 0, optionValues);
}
public void unselectOptions(String selectName, int index, String[]
optionValues) {
- throw new UnsupportedOperationException("Not supported yet.");
+ Select select = new Select(getWebElementByXPath("//select[@name='" +
selectName + "' and position()=" + (index + 1) + "]", true));
+ if (!select.isMultiple() && optionValues.length > 1)
+ throw new RuntimeException("Multiselect not enabled");
+ for (String option : optionValues) {
+ boolean found = false;
+ for (WebElement opt : select.getOptions()) {
+ if (opt.getValue().equals(option)) {
+ select.deselectByValue(option);
+ found = true;
+ break;
+ }
+ }
+ if (!found) {
+ throw new RuntimeException("Option " + option
+ + " not found");
+ }
+ }
}
public boolean hasSelectOption(String selectName, String optionLabel) {
- throw new UnsupportedOperationException("Not supported yet.");
+ return hasSelectOption(selectName, 0, optionLabel);
}
public boolean hasSelectOptionValue(String selectName, String optionValue)
{
- throw new UnsupportedOperationException("Not supported yet.");
+ return hasSelectOptionValue(selectName, 0, optionValue);
}
public boolean hasSelectOption(String selectName, int index, String
optionLabel) {
- throw new UnsupportedOperationException("Not supported yet.");
+ Select select = new Select(getWebElementByXPath("//select[@name='" +
selectName + "' and position()=" + (index + 1) + "]", true));
+ for (WebElement opt : select.getOptions()) {
+ if (opt.getText().equals(optionLabel)) {
+ return true;
+ }
+ }
+ return false;
}
public boolean hasSelectOptionValue(String selectName, int index, String
optionValue) {
- throw new UnsupportedOperationException("Not supported yet.");
+ Select select = new Select(getWebElementByXPath("//select[@name='" +
selectName + "' and position()=" + (index + 1) + "]", true));
+ for (WebElement opt : select.getOptions()) {
+ if (opt.getValue().equals(optionValue)) {
+ return true;
+ }
+ }
+ return false;
}
public boolean isCheckboxSelected(String checkBoxName) {
- WebElement e = getWebElementByXPath("/input[@type='checkbox' and
@name='" + checkBoxName + "']", true);
+ WebElement e = getWebElementByXPath("//input[@type='checkbox' and
@name='" + checkBoxName + "']", true);
return e.isSelected();
}
public boolean isCheckboxSelected(String checkBoxName, String
checkBoxValue) {
- WebElement e = getWebElementByXPath("/input[@type='checkbox' and
@name='" + checkBoxName + "' and @value='" + checkBoxValue + "']", true);
+ WebElement e = getWebElementByXPath("//input[@type='checkbox' and
@name='" + checkBoxName + "' and @value='" + checkBoxValue + "']", true);
return e.isSelected();
}
public void checkCheckbox(String checkBoxName) {
- WebElement e = getWebElementByXPath("/input[@type='checkbox' and
@name='" + checkBoxName + "']", true);
+ WebElement e = getWebElementByXPath("//input[@type='checkbox' and
@name='" + checkBoxName + "']", true);
if (!e.isSelected()) {
e.toggle();
}
}
public void checkCheckbox(String checkBoxName, String checkBoxValue) {
- WebElement e = getWebElementByXPath("/input[@type='checkbox' and
@name='" + checkBoxName + "' and @value='" + checkBoxValue + "']", true);
+ WebElement e = getWebElementByXPath("//input[@type='checkbox' and
@name='" + checkBoxName + "' and @value='" + checkBoxValue + "']", true);
if (!e.isSelected()) {
e.toggle();
}
}
public void uncheckCheckbox(String checkBoxName) {
- WebElement e = getWebElementByXPath("/input[@type='checkbox' and
@name='" + checkBoxName + "']", true);
+ WebElement e = getWebElementByXPath("//input[@type='checkbox' and
@name='" + checkBoxName + "']", true);
if (e.isSelected()) {
e.toggle();
}
}
public void uncheckCheckbox(String checkBoxName, String value) {
- WebElement e = getWebElementByXPath("/input[@type='checkbox' and
@name='" + checkBoxName + "' and @value='" + value + "']", true);
+ WebElement e = getWebElementByXPath("//input[@type='checkbox' and
@name='" + checkBoxName + "' and @value='" + value + "']", true);
if (e.isSelected()) {
e.toggle();
}
}
public void clickRadioOption(String radioGroup, String radioOptionValue) {
- WebElement e = getWebElementByXPath("/input[@type='radio' and @name='"
+ radioGroup + "' and @value='" + radioOptionValue + "']", false);
+ WebElement e = getWebElementByXPath("//input[@type='radio' and
@name='" + radioGroup + "' and @value='" + radioOptionValue + "']", false);
e.click();
}
public boolean hasRadioOption(String radioGroup, String radioOptionValue) {
- WebElement e = getWebElementByXPath("/input[@type='radio' and @name='"
+ radioGroup + "' and @value='" + radioOptionValue + "']", false);
+ WebElement e = getWebElementByXPath("//input[@type='radio' and
@name='" + radioGroup + "' and @value='" + radioOptionValue + "']", false);
return e != null;
}
@@ -409,63 +505,67 @@
}
public boolean hasSubmitButton() {
- return (getWebElementByXPath("/input[@type='submit' or
@type='image']", true) != null) ||
(getWebElementByXPath("/button[@type='submit']", false) != null);
+ return (getWebElementByXPath("//input[@type='submit' or
@type='image']", true) != null) ||
(getWebElementByXPath("//button[@type='submit']", false) != null);
}
public boolean hasSubmitButton(String nameOrID) {
- return (getWebElementByXPath("/input[(@type='submit' or @type='image')
and (@name='" + nameOrID + "' or @id='" + nameOrID + "')]", true) != null)
- || (getWebElementByXPath("/button[@type='submit' and (@name='"
+ nameOrID + "' or @id='" + nameOrID + "')]", true) != null);
+ return (getWebElementByXPath("//input[(@type='submit' or
@type='image') and (@name='" + nameOrID + "' or @id='" + nameOrID + "')]",
true) != null)
+ || (getWebElementByXPath("//button[@type='submit' and
(@name='" + nameOrID + "' or @id='" + nameOrID + "')]", true) != null);
}
public boolean hasSubmitButton(String nameOrID, String value) {
- return (getWebElementByXPath("/input[(@type='submit' or @type='image')
and (@name='" + nameOrID + "' or @id='" + nameOrID + "') and @value='" + value
+ "']", true) != null)
- || (getWebElementByXPath("/button[@type='submit' and (@name='"
+ nameOrID + "' or @id='" + nameOrID + "') and @value='" + value + "']", true)
!= null);
+ return (getWebElementByXPath("//input[(@type='submit' or
@type='image') and (@name='" + nameOrID + "' or @id='" + nameOrID + "') and
@value='" + value + "']", true) != null)
+ || (getWebElementByXPath("//button[@type='submit' and
(@name='" + nameOrID + "' or @id='" + nameOrID + "') and @value='" + value +
"']", true) != null);
}
public void submit() {
- driver.findElement(By.xpath(formSelector())).submit();
+ WebElement e = getWebElementByXPath("//input[@type='submit' or
@type='image']", true);
+ if (e == null) {
+ e = getWebElementByXPath("//button[@type='submit']", true);
+ }
+ e.submit();
}
public void submit(String nameOrID) {
- WebElement e = getWebElementByXPath("/input[(@type='submit' or
@type='image') and (@name='" + nameOrID + "' or @id='" + nameOrID + "')]",
true);
+ WebElement e = getWebElementByXPath("//input[(@type='submit' or
@type='image') and (@name='" + nameOrID + "' or @id='" + nameOrID + "')]",
true);
if (e == null) {
- e = getWebElementByXPath("/button[@type='submit' and (@name='" +
nameOrID + "' or @id='" + nameOrID + "')]", true);
+ e = getWebElementByXPath("//button[@type='submit' and (@name='" +
nameOrID + "' or @id='" + nameOrID + "')]", true);
}
e.submit();
}
public void submit(String buttonName, String buttonValue) {
- WebElement e = getWebElementByXPath("/input[(@type='submit' or
@type='image') and (@name='" + buttonName + "' or @id='" + buttonName + "') and
@value='" + buttonValue + "']", true);
+ WebElement e = getWebElementByXPath("//input[(@type='submit' or
@type='image') and (@name='" + buttonName + "' or @id='" + buttonName + "') and
@value='" + buttonValue + "']", true);
if (e == null) {
- e = getWebElementByXPath("/button[@type='submit' and (@name='" +
buttonName + "' or @id='" + buttonName + "') and @value='" + buttonValue +
"']", true);
+ e = getWebElementByXPath("//button[@type='submit' and (@name='" +
buttonName + "' or @id='" + buttonName + "') and @value='" + buttonValue +
"']", true);
}
e.submit();
}
public boolean hasResetButton() {
- return getWebElementByXPath("/input[@type='reset']", false) != null;
+ return getWebElementByXPath("//input[@type='reset']", false) != null;
}
public boolean hasResetButton(String nameOrID) {
- return getWebElementByXPath("/input[@type='reset' and (@name='" +
nameOrID + "' or @id='" + nameOrID + "')]", true) != null;
+ return getWebElementByXPath("//input[@type='reset' and (@name='" +
nameOrID + "' or @id='" + nameOrID + "')]", true) != null;
}
public void reset() {
- getWebElementByXPath("/input[@type='reset']", true).click();;
+ getWebElementByXPath("//input[@type='reset']", true).click();;
}
private WebElement getButton(String nameOrID) {
- WebElement e = getWebElementByXPath("/input[(@type='submit' or
@type='image' or @type='reset' or @type='button') and (@name='" + nameOrID + "'
or @id='" + nameOrID + "')]", false);
+ WebElement e = getWebElementByXPath("//input[(@type='submit' or
@type='image' or @type='reset' or @type='button') and (@name='" + nameOrID + "'
or @id='" + nameOrID + "')]", false);
if (e == null) {
- e = getWebElementByXPath("/button[@type='submit' and (@name='" +
nameOrID + "' or @id='" + nameOrID + "')]", false);
+ e = getWebElementByXPath("//button[@type='submit' and (@name='" +
nameOrID + "' or @id='" + nameOrID + "')]", false);
}
return e;
}
private WebElement getButtonWithText(String text) {
- WebElement e = getWebElementByXPath("/input[(@type='submit' or
@type='image' or @type='reset' or @type='button') and contains(.,'" + text +
"')]", false);
+ WebElement e = getWebElementByXPath("//input[(@type='submit' or
@type='reset' or @type='button') and contains(@value," + escapeQuotes(text) +
")]", false);
if (e == null) {
- e = getWebElementByXPath("/button[@type='submit' and contains(.,'"
+ text + "')]", false);
+ e = getWebElementByXPath("//button[contains(.," +
escapeQuotes(text) + ")]", false);
}
return e;
}
@@ -526,20 +626,56 @@
throw new UnsupportedOperationException("Not supported yet.");
}
+ private WebElement getLinkWithImage(String filename, int index) {
+ try {
+ return driver.findElement(By.xpath("(//a[img[contains(@src,"
+ + escapeQuotes(filename) + ")]])[" + (index + 1) + "]"));
+ } catch (NoSuchElementException e) {
+ return null;
+ }
+ }
+
+ private WebElement getLinkWithText(String linkText, int index) {
+ List<WebElement> lnks = driver.findElements(By.xpath("//a"));
+ int count = 0;
+ for (WebElement lnk : lnks) {
+ if ((lnk.getText().indexOf(linkText) >= 0) && (count++ == index)) {
+ return lnk;
+ }
+ }
+ return null;
+ }
+
+ private WebElement getLinkWithExactText(String linkText, int index) {
+ List<WebElement> lnks = driver.findElements(By.xpath("//a"));
+ int count = 0;
+ for (WebElement lnk : lnks) {
+ if (lnk.getText().equals(linkText) && (count++ == index)) {
+ return lnk;
+ }
+ }
+ return null;
+ }
+
public boolean hasLinkWithText(String linkText, int index) {
- throw new UnsupportedOperationException("Not supported yet.");
+ return getLinkWithText(linkText, index) != null;
}
public boolean hasLinkWithExactText(String linkText, int index) {
- throw new UnsupportedOperationException("Not supported yet.");
+ return getLinkWithExactText(linkText, index) != null;
}
public boolean hasLinkWithImage(String imageFileName, int index) {
- throw new UnsupportedOperationException("Not supported yet.");
+ return getLinkWithImage(imageFileName, index) != null;
}
public boolean hasLink(String anId) {
- return driver.findElement(By.xpath("//a[@id='" + anId + "']")) != null;
+ try {
+ driver.findElement(By.xpath("//a[@id='" + anId + "']"));
+ return true;
+ } catch (NoSuchElementException e) {
+ return false;
+ }
}
public void clickLinkWithText(String linkText, int index) {
@@ -559,7 +695,12 @@
}
public boolean hasElement(String anID) {
- throw new UnsupportedOperationException("Not supported yet.");
+ try {
+ driver.findElement(By.id(anID));
+ return true;
+ } catch (NoSuchElementException e) {
+ return false;
+ }
}
public boolean hasElementByXPath(String xpath) {
@@ -572,26 +713,53 @@
}
public void clickElementByXPath(String xpath) {
- throw new UnsupportedOperationException("Not supported yet.");
+ driver.findElement(By.xpath(xpath)).click();
}
public String getElementAttributByXPath(String xpath, String attribut) {
- throw new UnsupportedOperationException("Not supported yet.");
+ return driver.findElement(By.xpath(xpath)).getAttribute(attribut);
}
public String getElementTextByXPath(String xpath) {
- throw new UnsupportedOperationException("Not supported yet.");
+ return driver.findElement(By.xpath(xpath)).getText();
}
public boolean isTextInElement(String elementID, String text) {
- throw new UnsupportedOperationException("Not supported yet.");
+ return isTextInElement(driver.findElement(By.id(elementID)), text);
}
+ /**
+ * Return true if a given string is contained within the specified element.
+ *
+ * @param element element to inspect.
+ * @param text text to check for.
+ */
+ private boolean isTextInElement(WebElement element, String text) {
+ return element.getText().indexOf(text) >= 0;
+ }
+
public boolean isMatchInElement(String elementID, String regexp) {
- throw new UnsupportedOperationException("Not supported yet.");
+ return isMatchInElement(driver.findElement(By.id(elementID)), regexp);
}
- public void setExpectedJavaScriptAlert(JavascriptAlert[] alerts) throws
ExpectedJavascriptAlertException {
+ /**
+ * Return true if a given regexp is contained within the specified element.
+ *
+ * @param element element to inspect.
+ * @param regexp regexp to match.
+ */
+ private boolean isMatchInElement(WebElement element, String regexp) {
+ RE re = getRE(regexp);
+ return re.match(element.getText());
+ }
+
+ private RE getRE(String regexp) {
+ try {
+ return new RE(regexp, RE.MATCH_SINGLELINE);
+ } catch (RESyntaxException e) {
+ throw new RuntimeException(e);
+ }
+ } public void setExpectedJavaScriptAlert(JavascriptAlert[] alerts)
throws ExpectedJavascriptAlertException {
throw new UnsupportedOperationException("Not supported yet.");
}
@@ -638,4 +806,41 @@
public void setTimeout(int milliseconds) {
throw new UnsupportedOperationException("Not supported yet.");
}
+
+ public List<HttpHeader> getResponseHeaders() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ /**
+ * Copied from {@link Select}
+ * @param toEscape
+ * @return
+ */
+ protected String escapeQuotes(String toEscape) {
+ // Convert strings with both quotes and ticks into: foo'"bar ->
concat("foo'", '"', "bar")
+ if (toEscape.indexOf("\"") > -1 && toEscape.indexOf("'") > -1) {
+ boolean quoteIsLast = false;
+ if (toEscape.indexOf("\"") == toEscape.length() -1) {
+ quoteIsLast = true;
+ }
+ String[] substrings = toEscape.split("\"");
+
+ StringBuilder quoted = new StringBuilder("concat(");
+ for (int i = 0; i < substrings.length; i++) {
+ quoted.append("\"").append(substrings[i]).append("\"");
+ quoted.append(((i == substrings.length -1) ? (quoteIsLast ? ",
'\"')" : ")") : ", '\"', "));
+ }
+ return quoted.toString();
+ }
+
+ // Escape string with just a quote into being single quoted: f"oo ->
'f"oo'
+ if (toEscape.indexOf("\"") > -1) {
+ return String.format("'%s'", toEscape);
+ }
+
+ // Otherwise return the quoted string
+ return String.format("\"%s\"", toEscape);
+ }
+
}
Added:
branches/webdriver/jwebunit-webdriver-plugin/src/main/java/net/sourceforge/jwebunit/webdriver/WebdriverElementImpl.java
===================================================================
---
branches/webdriver/jwebunit-webdriver-plugin/src/main/java/net/sourceforge/jwebunit/webdriver/WebdriverElementImpl.java
(rev 0)
+++
branches/webdriver/jwebunit-webdriver-plugin/src/main/java/net/sourceforge/jwebunit/webdriver/WebdriverElementImpl.java
2011-03-21 16:20:16 UTC (rev 901)
@@ -0,0 +1,198 @@
+/**
+ * Copyright (c) 2010, JWebUnit team.
+ *
+ * This file is part of JWebUnit.
+ *
+ * JWebUnit 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * JWebUnit 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with JWebUnit. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/**
+ *
+ */
+package net.sourceforge.jwebunit.webdriver;
+
+import org.openqa.selenium.JavascriptExecutor;
+
+import org.openqa.selenium.By;
+
+import org.openqa.selenium.WebElement;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import net.sourceforge.jwebunit.api.IElement;
+
+import com.gargoylesoftware.htmlunit.html.DomNode;
+import com.gargoylesoftware.htmlunit.html.HtmlElement;
+import com.gargoylesoftware.htmlunit.html.HtmlInput;
+import com.gargoylesoftware.htmlunit.html.HtmlTextArea;
+
+/**
+ * Webdriver implementation of IElement wrapper.
+ *
+ * @author henryju
+ *
+ */
+public class WebdriverElementImpl implements IElement {
+
+ /**
+ * The wrapped element.
+ */
+ private WebElement element;
+
+ public WebdriverElementImpl(WebElement element) {
+ if (element == null)
+ throw new NullPointerException("Cannot create an IElement for a
null element.");
+ this.element = element;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see net.sourceforge.jwebunit.api.IElement#attribute(java.lang.String)
+ */
+ public String getAttribute(String name) {
+ return element.getAttribute(name);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see net.sourceforge.jwebunit.api.IElement#name()
+ */
+ public String getName() {
+ return element.getTagName();
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see net.sourceforge.jwebunit.api.IElement#getChildren()
+ */
+ public List<IElement> getChildren() {
+ List<IElement> children = new ArrayList<IElement>();
+ for (WebElement e : element.findElements(By.xpath("/"))) {
+ if (e != null)
+ children.add(new WebdriverElementImpl(e));
+ }
+ return children;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see net.sourceforge.jwebunit.api.IElement#getParent()
+ */
+ public IElement getParent() {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see net.sourceforge.jwebunit.api.IElement#getTextContent()
+ */
+ public String getTextContent() {
+ return element.getText();
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see net.sourceforge.jwebunit.api.IElement#getElement(java.lang.String)
+ */
+ public IElement getElement(String xpath) {
+ return new WebdriverElementImpl((WebElement)
element.findElement(By.xpath(xpath)));
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see net.sourceforge.jwebunit.api.IElement#getElements(java.lang.String)
+ */
+ public List<IElement> getElements(String xpath) {
+ List<IElement> elements = new ArrayList<IElement>();
+ for (WebElement o : element.findElements(By.xpath(xpath))) {
+ elements.add(new WebdriverElementImpl(o));
+ }
+ return elements;
+ }
+
+ public String toString() {
+ return "IElement[name=" + getName() + " wrapped=" + element + "]";
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
net.sourceforge.jwebunit.api.IElement#setAttribute(java.lang.String)
+ */
+ public void setAttribute(String string) {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
net.sourceforge.jwebunit.api.IElement#setAttribute(java.lang.String,
java.lang.String)
+ */
+ public void setAttribute(String string, String value) {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
net.sourceforge.jwebunit.api.IElement#setTextContent(java.lang.String)
+ */
+ public void setTextContent(String value) {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 37;
+ int result = 1;
+ result = prime * result + ((element == null) ? 0 : element.hashCode());
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ final WebdriverElementImpl other = (WebdriverElementImpl) obj;
+ if (element == null) {
+ if (other.element != null)
+ return false;
+ }
+ else if (!element.equals(other.element))
+ return false;
+ return true;
+ }
+
+ /**
+ * Return the unwrapped Webdriver element that this IElement represents.
+ *
+ * @return the Webdriver element this IElement represents.
+ */
+ public WebElement getHtmlElement() {
+ return element;
+ }
+
+}
Property changes on:
branches/webdriver/jwebunit-webdriver-plugin/src/main/java/net/sourceforge/jwebunit/webdriver/WebdriverElementImpl.java
___________________________________________________________________
Added: svn:mime-type
+ text/plain
Modified:
branches/webdriver/jwebunit-webdriver-plugin/src/test/java/net/sourceforge/jwebunit/webdriver/JWebUnitTest.java
===================================================================
---
branches/webdriver/jwebunit-webdriver-plugin/src/test/java/net/sourceforge/jwebunit/webdriver/JWebUnitTest.java
2011-03-18 22:07:48 UTC (rev 900)
+++
branches/webdriver/jwebunit-webdriver-plugin/src/test/java/net/sourceforge/jwebunit/webdriver/JWebUnitTest.java
2011-03-21 16:20:16 UTC (rev 901)
@@ -19,58 +19,70 @@
package net.sourceforge.jwebunit.webdriver;
-import junit.framework.Test;
-import junit.framework.TestCase;
-import junit.framework.TestSuite;
+import net.sourceforge.jwebunit.tests.ButtonAssertionsTest;
+import net.sourceforge.jwebunit.tests.CharsetTest;
+import net.sourceforge.jwebunit.tests.CustomTesterTest;
+import net.sourceforge.jwebunit.tests.ExpectedTableAssertionsHtmlTest;
+import net.sourceforge.jwebunit.tests.ExpectedTableAssertionsXHtmlTest;
+import net.sourceforge.jwebunit.tests.FormAssertionsTest;
+import net.sourceforge.jwebunit.tests.FormSubmissionTest;
+import net.sourceforge.jwebunit.tests.FramesAndWindowsTest;
+import net.sourceforge.jwebunit.tests.HelloWorldTest;
+import net.sourceforge.jwebunit.tests.HtmlParsingTest;
+import net.sourceforge.jwebunit.tests.IElementTest;
+import net.sourceforge.jwebunit.tests.ImageTest;
+import net.sourceforge.jwebunit.tests.JUnitPerfTest;
+import net.sourceforge.jwebunit.tests.JavaScriptEventsTest;
+import net.sourceforge.jwebunit.tests.JavaScriptTest;
+import net.sourceforge.jwebunit.tests.NavigationTest;
+import net.sourceforge.jwebunit.tests.NonHtmlContentTest;
+import net.sourceforge.jwebunit.tests.RedirectionTest;
+import net.sourceforge.jwebunit.tests.ResourceBundleAssertionsTest;
+import net.sourceforge.jwebunit.tests.ResponseServletTest;
+import net.sourceforge.jwebunit.tests.SelectOptionsTest;
+import net.sourceforge.jwebunit.tests.TableAssertionsTest;
+import net.sourceforge.jwebunit.tests.TestContextTest;
+import net.sourceforge.jwebunit.tests.WebAssertionsTest;
+import net.sourceforge.jwebunit.tests.WebCookieTest;
+import net.sourceforge.jwebunit.tests.XPathTest;
import net.sourceforge.jwebunit.tests.util.JettySetup;
-import net.sourceforge.jwebunit.tests.*;
+import org.junit.runner.RunWith;
+import org.junit.runners.Suite;
/**
* Test Suite for JWebUnit.
*
* @author Julien Henry
*/
-public class JWebUnitTest extends TestCase {
+@RunWith(Suite.class)
[email protected]({
+ FormSubmissionTest.class,
+ WebAssertionsTest.class,
+ FramesAndWindowsTest.class,
+ TableAssertionsTest.class,
+ ExpectedTableAssertionsHtmlTest.class,
+ ExpectedTableAssertionsXHtmlTest.class,
+ JavaScriptEventsTest.class,
+ JavaScriptTest.class,
+ HelloWorldTest.class,
+ HtmlParsingTest.class,
+ WebCookieTest.class,
+ TestContextTest.class,
+ FormAssertionsTest.class,
+ NavigationTest.class,
+ XPathTest.class,
+ CharsetTest.class,
+ ButtonAssertionsTest.class,
+ NonHtmlContentTest.class,
+ RedirectionTest.class,
+ ImageTest.class,
+ ResourceBundleAssertionsTest.class,
+ SelectOptionsTest.class,
+ IElementTest.class,
+ ResponseServletTest.class,
+ CustomTesterTest.class,
+ JUnitPerfTest.class
+})
+public class JWebUnitTest extends JettySetup {
- /**
- * Runs all the tests for JWebUnit. Add each new TestCase by using the
<code>addTestSuite(Class)</code> method, so
- * that the TestCase's <code>suite</code> method <strong>isn't called
</strong>. This prevents
- * <code>JettySetup</code> from starting the Jetty server twice and
consequently the error 'port 80xx is already
- * in use'.
- *
- * @return the <code>TestSuite</code> containing all the tests for
JWebUnit ready to run utilizing Jetty as
- * testserver.
- */
- public static Test suite() {
- TestSuite suite = new TestSuite("Test for net.sourceforge.jwebunit");
- // $JUnit-BEGIN$
- suite.addTestSuite(FormSubmissionTest.class);
- suite.addTestSuite(WebAssertionsTest.class);
- suite.addTestSuite(FramesAndWindowsTest.class);
- suite.addTestSuite(TableAssertionsTest.class);
- suite.addTestSuite(ExpectedTableAssertionsHtmlTest.class);
- suite.addTestSuite(ExpectedTableAssertionsXHtmlTest.class);
- suite.addTestSuite(JavaScriptEventsTest.class);
- suite.addTestSuite(JavaScriptTest.class);
- suite.addTestSuite(HelloWorldTest.class);
- suite.addTestSuite(HtmlParsingTest.class);
- suite.addTestSuite(WebCookieTest.class);
- suite.addTestSuite(TestContextTest.class);
- suite.addTestSuite(FormAssertionsTest.class);
- suite.addTestSuite(NavigationTest.class);
- suite.addTestSuite(XPathTest.class);
- suite.addTestSuite(CharsetTest.class);
- suite.addTestSuite(ButtonAssertionsTest.class);
- suite.addTestSuite(NonHtmlContentTest.class);
- suite.addTestSuite(RedirectionTest.class);
- suite.addTestSuite(ImageTest.class);
- suite.addTestSuite(ResourceBundleAssertionsTest.class);
- suite.addTestSuite(IElementTest.class);
- suite.addTestSuite(ResponseServletTest.class);
- suite.addTestSuite(CustomTesterTest.class);
- //suite.addTest(JUnitPerfTest.suite());
- // $JUnit-END$
- return new JettySetup(suite);
- }
-
}
This was sent by the SourceForge.net collaborative development platform, the
world's largest Open Source development site.
------------------------------------------------------------------------------
Colocation vs. Managed Hosting
A question and answer guide to determining the best fit
for your organization - today and in the future.
http://p.sf.net/sfu/internap-sfd2d
_______________________________________________
JWebUnit-development mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/jwebunit-development