M dist/mcp-test/src/test/java/cardemo/CarDemoTest.java

- this automated test is now a complete example for how to test an ajax
  web application in an automated fashion.

M dom/classes/org/mozilla/dom/NodeImpl.java
M dom/jni/org_mozilla_dom_NodeImpl.cpp

- implement getTextContent() from DOM level 3.

M webclient/build-tests.xml

- add cardemoTest to unit test list as a place-holder until I can write
  a testcase that doesn't require the public Internet.

A webclient/classes_spec/org/mozilla/mcp/AjaxListener.java

- New class.  Docs forthcoming.

M webclient/classes_spec/org/mozilla/mcp/MCP.java

- new methods to support complete ajax automated testing.

M webclient/src_moz/AjaxListener.cpp
M webclient/src_moz/AjaxListener.h

- add mIsObserving flag.  From our dtor, make sure to remove ourselves
  from the EmbedProgress.

M webclient/src_moz/EmbedProgress.cpp
M webclient/src_moz/EmbedProgress.h

- We need to add ourselves as an observer both from SetCapturePageInfo
  and SetEventRegistration.

M webclient/src_moz/NativeBrowserControl.cpp

- Unit testing found a bug!  We can't call mWindow->ReleaseChildren()
  until after we remove ourself as a listener.
This commit is contained in:
edburns%acm.org 2007-03-09 04:34:24 +00:00
Родитель a9099030a8
Коммит 2f0d5d1aac
11 изменённых файлов: 331 добавлений и 24 удалений

Просмотреть файл

@ -1,12 +1,34 @@
/*
* CarDemoTest.java
* JUnit based test
*
* Created on March 3, 2007, 2:31 PM
* $Id: CarDemoTest.java,v 1.6 2007-03-09 04:34:23 edburns%acm.org Exp $
*/
/*
*
* The contents of this file are subject to the Mozilla Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is Sun
* Microsystems, Inc. Portions created by Sun are
* Copyright (C) 1999 Sun Microsystems, Inc. All
* Rights Reserved.
*
* Contributor(s): Ed Burns <edburns@acm.org>
*/
package cardemo;
import java.util.BitSet;
import java.util.Map;
import junit.framework.TestFailure;
import org.mozilla.mcp.AjaxListener;
import org.mozilla.mcp.MCP;
import org.mozilla.webclient.WebclientTestCase;
import org.w3c.dom.Element;
@ -36,19 +58,79 @@ public class CarDemoTest extends WebclientTestCase {
}
enum TestFeature {
RECEIVED_END_AJAX_EVENT,
HAS_MAP,
HAS_VALID_PARTIAL_RESPONSE,
HAS_VALID_READYSTATE,
STOP_WAITING
}
public void testCardemo() throws Exception {
mcp.getRealizedVisibleBrowserWindow();
final BitSet bitSet = new BitSet();
AjaxListener listener = new AjaxListener() {
public void endAjax(Map eventMap) {
bitSet.flip(TestFeature.RECEIVED_END_AJAX_EVENT.ordinal());
if (null != eventMap) {
bitSet.flip(TestFeature.HAS_MAP.ordinal());
}
String responseText = (String) eventMap.get("responseText");
if (null != responseText) {
if (-1 != responseText.indexOf("<partial-response>") &&
-1 != responseText.indexOf("</partial-response>")) {
bitSet.flip(TestFeature.HAS_VALID_PARTIAL_RESPONSE.ordinal());
}
}
String readyState = (String) eventMap.get("readyState");
bitSet.set(TestFeature.HAS_VALID_READYSTATE.ordinal(),
null != readyState && readyState.equals("4"));
bitSet.flip(TestFeature.STOP_WAITING.ordinal());
}
};
mcp.addAjaxListener(listener);
// Load the main page of the app
mcp.blockingLoad("http://webdev1.sun.com/jsf-ajax-cardemo/faces/chooseLocale.jsp");
mcp.blockingLoad("http://javaserver.org/jsf-ajax-cardemo/faces/chooseLocale.jsp");
// Choose the "German" language button
mcp.blockingClickElement("j_id_id73:Germany");
// Choose the roadster
mcp.blockingClickElement("j_id_id18:j_id_id43");
// Sample the Basis-Preis and Ihr Preis before the ajax transaction
Element pricePanel = mcp.findElement("j_id_id10:zone1");
assertNotNull(pricePanel);
String pricePanelText = pricePanel.getTextContent();
assertNotNull(pricePanelText);
assertTrue(pricePanelText.matches("(?s).*Basis-Preis\\s*15700.*"));
assertTrue(pricePanelText.matches("(?s).*Ihr Preis\\s*15700.*"));
// Choose the "Tempomat" checkbox
mcp.clickElement("j_id_id21:j_id_id67j_id_1");
bitSet.clear();
mcp.clickElement("j_id_id10:j_id_id63j_id_1");
while (!bitSet.get(TestFeature.STOP_WAITING.ordinal())) {
Thread.currentThread().sleep(5000);
}
// assert that the ajax transaction succeeded
assertTrue(bitSet.get(TestFeature.RECEIVED_END_AJAX_EVENT.ordinal()));
assertTrue(bitSet.get(TestFeature.HAS_MAP.ordinal()));
assertTrue(bitSet.get(TestFeature.HAS_VALID_PARTIAL_RESPONSE.ordinal()));
assertTrue(bitSet.get(TestFeature.HAS_VALID_READYSTATE.ordinal()));
bitSet.clear();
// Sample the Basis-Preis and Ihr-Preis after the ajax transaction
pricePanel = mcp.findElement("j_id_id10:zone1");
assertNotNull(pricePanel);
pricePanelText = pricePanel.getTextContent();
Thread.currentThread().sleep(10000);
assertNotNull(pricePanelText);
assertTrue(pricePanelText.matches("(?s).*Basis-Preis\\s*15700.*"));
assertTrue(pricePanelText.matches("(?s).*Ihr Preis\\s*16600.*"));
mcp.deleteBrowserControl();
}
}

Просмотреть файл

@ -137,6 +137,7 @@ public class NodeImpl implements Node, EventTarget {
public native Node removeChild(Node oldChild) throws DOMException;
public native Node replaceChild(Node newChild, Node oldChild) throws DOMException;
public native void setNodeValue(String nodeValue);
public native String getTextContent() throws DOMException;
protected native void finalize();
@ -254,9 +255,7 @@ public void setTextContent(String textContent) {
public Object setUserData(String key, Object data, UserDataHandler handler) {
throw new UnsupportedOperationException();
}
public String getTextContent() throws DOMException {
throw new UnsupportedOperationException();
}
}

Просмотреть файл

@ -22,6 +22,7 @@
#include "prlog.h"
#include "nsCOMPtr.h"
#include "nsIDOMNode.h"
#include "nsIDOM3Node.h"
#include "nsIDOMNodeList.h"
#include "nsIDOMNamedNodeMap.h"
#include "nsIDOMDocument.h"
@ -727,6 +728,48 @@ JNIEXPORT jstring JNICALL Java_org_mozilla_dom_NodeImpl_getNodeValue
return jret;
}
/*
* Class: org_mozilla_dom_NodeImpl
* Method: getTextContent
* Signature: ()Ljava/lang/String;
*/
JNIEXPORT jstring JNICALL Java_org_mozilla_dom_NodeImpl_getTextContent
(JNIEnv *env, jobject jthis)
{
nsCOMPtr<nsIDOMNode> node = (nsIDOMNode*)
env->GetLongField(jthis, JavaDOMGlobals::nodePtrFID);
nsCOMPtr<nsIDOM3Node> dom3Node = nsnull;;
if (!node)
return NULL;
nsString ret;
nsresult rv;
dom3Node = do_QueryInterface(node, &rv);
if (NS_SUCCEEDED(rv) && dom3Node) {
rv = dom3Node->GetTextContent(ret);
}
if (NS_FAILED(rv)) {
JavaDOMGlobals::ExceptionType exceptionType = JavaDOMGlobals::EXCEPTION_RUNTIME;
if (rv == NS_ERROR_DOM_DOMSTRING_SIZE_ERR) {
exceptionType = JavaDOMGlobals::EXCEPTION_DOM;
}
JavaDOMGlobals::ThrowException(env,
"Node.getNodeValue: failed", rv, exceptionType);
return NULL;
}
jstring jret = env->NewString((jchar*) ret.get(), ret.Length());
if (!jret) {
JavaDOMGlobals::ThrowException(env,
"Node.getNodeValue: NewString failed");
return NULL;
}
return jret;
}
/*
* Class: org_mozilla_dom_NodeImpl
* Method: getOwnerDocument

Просмотреть файл

@ -188,6 +188,7 @@ PENDING(edburns): 20070130 XULRunner has no bookmarks
<test name="org.mozilla.webclient.WindowCreatorTest"/>
<test name="org.mozilla.webclient.DOMTest"/>
<test name="org.mozilla.webclient.CurrentPageTest"/>
<test name="cardemo.CarDemoTest"/>
<!-- non running
<test name="org.mozilla.webclient.wrapper_native.gtk.TestGtkBrowserControlCanvas"/>
-->

Просмотреть файл

@ -0,0 +1,71 @@
/*
* $Id: AjaxListener.java,v 1.1 2007-03-09 04:34:24 edburns%acm.org Exp $
*/
/*
*
* The contents of this file are subject to the Mozilla Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is Sun
* Microsystems, Inc. Portions created by Sun are
* Copyright (C) 1999 Sun Microsystems, Inc. All
* Rights Reserved.
*
* Contributor(s): Ed Burns &lt;edburns@acm.org&gt;
*/
package org.mozilla.mcp;
import java.util.Map;
import org.mozilla.webclient.DocumentLoadEvent;
import org.mozilla.webclient.PageInfoListener;
import org.mozilla.webclient.WebclientEvent;
/**
*
* @author edburns
*/
public class AjaxListener implements PageInfoListener {
public void eventDispatched(WebclientEvent event) {
Map map = (Map) event.getEventData();
if (!(event instanceof DocumentLoadEvent)) {
return;
}
DocumentLoadEvent dle = (DocumentLoadEvent) event;
int eventType = (int) dle.getType();
switch (eventType) {
case (int) DocumentLoadEvent.START_AJAX_EVENT_MASK:
startAjax(map);
break;
case (int) DocumentLoadEvent.ERROR_AJAX_EVENT_MASK:
errorAjax(map);
break;
case (int) DocumentLoadEvent.END_AJAX_EVENT_MASK:
endAjax(map);
break;
}
}
public void startAjax(Map eventMap) {
}
public void errorAjax(Map eventMap) {
}
public void endAjax(Map eventMap) {
}
}

Просмотреть файл

@ -1,12 +1,28 @@
/*
* MCP.java
*
* Created on February 27, 2007, 10:24 PM
*
* To change this template, choose Tools | Template Manager
* and open the template in the editor.
* $Id: MCP.java,v 1.6 2007-03-09 04:34:24 edburns%acm.org Exp $
*/
/*
*
* The contents of this file are subject to the Mozilla Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is Sun
* Microsystems, Inc. Portions created by Sun are
* Copyright (C) 1999 Sun Microsystems, Inc. All
* Rights Reserved.
*
* Contributor(s): Ed Burns &lt;edburns@acm.org&gt;
*/
package org.mozilla.mcp;
import java.awt.AWTException;
@ -14,6 +30,8 @@ import java.awt.BorderLayout;
import java.awt.Frame;
import java.awt.Robot;
import java.awt.event.InputEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseListener;
import java.io.FileNotFoundException;
import java.util.Map;
import java.util.logging.Level;
@ -46,13 +64,14 @@ public class MCP {
public static final Logger LOGGER = getLogger(MCP_LOG);
public static Logger getLogger( String loggerName ) {
static Logger getLogger( String loggerName ) {
return Logger.getLogger(loggerName, MCP_LOG_STRINGS );
}
private BrowserControl browserControl = null;
private Navigation2 navigation = null;
private EventRegistration2 eventRegistration = null;
private BrowserControlCanvas canvas = null;
private PageInfoListener pageInfoListener = null;
private Frame frame = null;
private int x = 0;
@ -118,6 +137,24 @@ public class MCP {
}
return eventRegistration;
}
private BrowserControlCanvas getBrowserControlCanvas() {
if (null == canvas) {
try {
canvas = (BrowserControlCanvas)
getBrowserControl().queryInterface(BrowserControl.BROWSER_CONTROL_CANVAS_NAME);
}
catch (Throwable th) {
if (LOGGER.isLoggable(Level.SEVERE)) {
LOGGER.throwing(this.getClass().getName(), "getBrowserControlCanvas",
th);
LOGGER.severe("Unable to obtain BrowserControlCanvas reference from BrowserControl");
}
}
}
return canvas;
}
private CurrentPage2 getCurrentPage() {
CurrentPage2 currentPage = null;
@ -144,6 +181,30 @@ public class MCP {
return pageInfoListener;
}
public void addAjaxListener(AjaxListener listener) {
getEventRegistration().addDocumentLoadListener(listener);
}
public void removeAjaxListener(AjaxListener listener) {
getEventRegistration().removeDocumentLoadListener(listener);
}
public void addMouseListener(MouseListener listener) {
getBrowserControlCanvas().addMouseListener(listener);
}
public void removeMouseListener(MouseListener listener) {
getBrowserControlCanvas().removeMouseListener(listener);
}
public void addKeyListener(KeyListener listener) {
getBrowserControlCanvas().addKeyListener(listener);
}
public void removeKeyListener(KeyListener listener) {
getBrowserControlCanvas().removeKeyListener(listener);
}
public BrowserControl getBrowserControl() {
if (!initialized) {
IllegalStateException ise = new IllegalStateException("Not initialized. Call setAppData()");
@ -196,6 +257,11 @@ public class MCP {
return frame;
}
public void deleteBrowserControl() {
getRealizedVisibleBrowserWindow().setVisible(false);
BrowserControlFactory.deleteBrowserControl(getBrowserControl());
}
public Element findElement(String id) {
Element result = null;
Document dom = getCurrentPage().getDOM();
@ -212,6 +278,12 @@ public class MCP {
return result;
}
public boolean findInPage(String toFind) {
boolean found = false;
found = getCurrentPage().find(toFind, true, true);
return found;
}
public void clickElement(String id) {
Element element = findElement(id);
String clientX = null, clientY = null;
@ -298,6 +370,7 @@ public class MCP {
long type = webclientEvent.getType();
switch ((int)type) {
case ((int) DocumentLoadEvent.END_AJAX_EVENT_MASK):
case ((int) DocumentLoadEvent.END_DOCUMENT_LOAD_EVENT_MASK):
synchronized (owner) {
owner.notifyAll();

Просмотреть файл

@ -54,12 +54,18 @@ AjaxListener::AjaxListener(EmbedProgress *owner,
jobject eventRegistration) :
mOwner(owner),
mJNIEnv(env),
mEventRegistration(eventRegistration)
mEventRegistration(eventRegistration),
mIsObserving(PR_FALSE)
{
}
AjaxListener::~AjaxListener()
{
mOwner->RemoveAjaxListener();
mEventRegistration = nsnull;
mJNIEnv = nsnull;
mOwner = nsnull;
mIsObserving = PR_FALSE;
}
//
@ -176,10 +182,16 @@ NS_IMETHODIMP
AjaxListener::StartObserving(void)
{
nsresult rv = NS_ERROR_NOT_IMPLEMENTED;
if (mIsObserving) {
return NS_OK;
}
nsCOMPtr<nsIObserverService> obsService = do_GetService("@mozilla.org/observer-service;1", &rv);
if (obsService && NS_SUCCEEDED(rv)) {
rv = obsService->AddObserver(this, "http-on-modify-request", PR_FALSE);
if (NS_SUCCEEDED(rv)) {
mIsObserving = PR_TRUE;
}
}
return rv;
@ -189,9 +201,13 @@ NS_IMETHODIMP
AjaxListener::StopObserving()
{
nsresult rv = NS_ERROR_NOT_IMPLEMENTED;
if (!mIsObserving) {
return NS_OK;
}
nsCOMPtr<nsIObserverService> obsService = do_GetService("@mozilla.org/observer-service;1", &rv);
if (obsService && NS_SUCCEEDED(rv)) {
mIsObserving = PR_FALSE;
rv = obsService->RemoveObserver(this, "http-on-modify-request");
}

Просмотреть файл

@ -63,6 +63,7 @@ private:
EmbedProgress* mOwner;
JNIEnv *mJNIEnv;
jobject mEventRegistration;
PRBool mIsObserving;
};
#endif

Просмотреть файл

@ -90,6 +90,8 @@ EmbedProgress::SetEventRegistration(jobject yourEventRegistration)
::util_ThrowExceptionToJava(env, "Exception: EmbedProgress->SetEventRegistration(): can't create NewGlobalRef\n\tfor eventRegistration");
rv = NS_ERROR_FAILURE;
}
// We get the listener here to ensure the mEventRegistration is
// properly passed to the AjaxListener ctor.
AjaxListener *observer = nsnull;
rv = GetAjaxListener(&observer);
if (observer && NS_SUCCEEDED(rv)) {
@ -108,7 +110,18 @@ nsresult
EmbedProgress::SetCapturePageInfo(jboolean newState)
{
mCapturePageInfo = newState;
return NS_OK;
AjaxListener *observer = nsnull;
nsresult rv = GetAjaxListener(&observer);
if (observer && NS_SUCCEEDED(rv)) {
if (mCapturePageInfo) {
observer->StartObserving();
}
else {
observer->StopObserving();
}
}
return rv;
}
NS_IMETHODIMP
@ -505,7 +518,14 @@ EmbedProgress::GetAjaxListener(AjaxListener* *result)
NS_IMETHODIMP
EmbedProgress::RemoveAjaxListener(void)
{
nsresult rv = NS_ERROR_NOT_IMPLEMENTED;
nsresult rv = NS_OK;
AjaxListener *observer = nsnull;
rv = GetAjaxListener(&observer);
if (NS_SUCCEEDED(rv) && observer) {
observer->StopObserving();
mAjaxListener = nsnull;
}
return rv;
}

Просмотреть файл

@ -57,6 +57,7 @@ class EmbedProgress : public nsIWebProgressListener,
NativeBrowserControl *mOwner;
friend class AjaxListener;
AjaxListener *mAjaxListener;
jobject mEventRegistration;

Просмотреть файл

@ -244,9 +244,6 @@ NativeBrowserControl::Destroy(void)
if (mEventReceiver)
mEventReceiver = nsnull;
// destroy our child window
mWindow->ReleaseChildren();
// release navigation
mNavigation = nsnull;
@ -259,12 +256,15 @@ NativeBrowserControl::Destroy(void)
nsIWebProgressListener::GetIID());
weakRef = nsnull;
supportsWeak = nsnull;
// Now that we have removed the listener, release our progress
// object
mProgressGuard = nsnull;
mProgress = nsnull;
fflush(stdout);
// destroy our child window
mWindow->ReleaseChildren();
parentHWnd = nsnull;
}