提交 6813ded1 编写于 作者: T tfennelly

Force the web response loading for a submit

and sniff in on the response
上级 516a4e52
......@@ -25,8 +25,13 @@ package com.gargoylesoftware.htmlunit.html;
import com.gargoylesoftware.htmlunit.ElementNotFoundException;
import com.gargoylesoftware.htmlunit.Page;
import com.gargoylesoftware.htmlunit.SgmlPage;
import com.gargoylesoftware.htmlunit.WebClient;
import com.gargoylesoftware.htmlunit.WebResponse;
import com.gargoylesoftware.htmlunit.WebWindow;
import org.junit.Assert;
import org.jvnet.hudson.test.WebClientResponseLoadListenable;
import javax.annotation.Nonnull;
import java.io.IOException;
import java.util.List;
......@@ -35,32 +40,50 @@ import java.util.List;
*/
public class HtmlFormUtil {
/**
* Plain {@link com.gargoylesoftware.htmlunit.html.HtmlForm#submit()} doesn't work correctly due to the use of YUI in Hudson.
*/
public static Page submit(final HtmlForm htmlForm) throws IOException {
HtmlElement submitElement = getSubmitButton(htmlForm);
return submit(htmlForm, submitElement);
}
/**
* Plain {@link com.gargoylesoftware.htmlunit.html.HtmlForm#submit()} doesn't work correctly due to the use of YUI in Hudson.
*/
public static Page submit(HtmlForm htmlForm, HtmlElement submitElement) throws IOException {
if (submitElement == null) {
return htmlForm.submit(null);
} else if (submitElement instanceof SubmittableElement) {
SgmlPage formPage = htmlForm.getPage();
Page submitResultPage = htmlForm.submit((SubmittableElement) submitElement);
if (submitResultPage != formPage) {
return submitResultPage;
if (submitElement != null && !(submitElement instanceof SubmittableElement)) {
// Just click and return
return submitElement.click();
}
final HtmlPage htmlPage = (HtmlPage) htmlForm.getPage();
final WebClient webClient = htmlPage.getWebClient();
Page resultPage = null;
try {
resultPage = htmlForm.submit((SubmittableElement) submitElement);
} finally {
// The HtmlForm submit doesn't really do anything. It just adds a "LoadJob"
// to an internal queue. What we are doing here is manually forcing the load of
// the response for that submit LoadJob and listening in on the WebClient
// instance for the response, allowing us to create the correct HtmlPage
// object for return to the tests.
if (webClient instanceof WebClientResponseLoadListenable) {
FormSubmitResponseLoadListener loadListener = new FormSubmitResponseLoadListener();
((WebClientResponseLoadListenable) webClient).addResponseLoadListener(loadListener);
try {
webClient.loadDownloadedResponses();
resultPage = loadListener.getPage();
} finally {
((WebClientResponseLoadListenable) webClient).removeResponseLoadListener(loadListener);
}
if (resultPage == htmlPage) {
// We're still on the same page (form submit didn't bring us anywhere).
// Hackery. Seems like YUI is messing us about.
return submitElement.click();
}
} else {
// We're still on the same page (form submit didn't bring us anywhere).
// Hackery. Seems like YUI is messing us about.
return submitElement.click();
Assert.fail("WebClient doesn't implement WebClientResponseLoadListenable.");
}
} else {
return submitElement.click();
return resultPage;
}
}
......@@ -102,4 +125,18 @@ public class HtmlFormUtil {
}
throw new ElementNotFoundException("button", "caption", caption);
}
private static class FormSubmitResponseLoadListener implements WebClientResponseLoadListenable.WebClientResponseLoadListener {
private WebWindow webWindow;
@Override
public void onLoad(@Nonnull WebResponse webResponse, @Nonnull WebWindow webWindow) {
this.webWindow = webWindow;
}
private Page getPage() {
if (webWindow == null) {
Assert.fail("Expected FormSubmitResponseLoadListener to be called on form submit.");
}
return webWindow.getEnclosedPage();
}
}
}
......@@ -26,6 +26,8 @@ package org.jvnet.hudson.test;
import com.gargoylesoftware.htmlunit.AlertHandler;
import com.gargoylesoftware.htmlunit.WebRequest;
import com.gargoylesoftware.htmlunit.WebResponse;
import com.gargoylesoftware.htmlunit.WebWindow;
import com.gargoylesoftware.htmlunit.html.DomNodeUtil;
import com.gargoylesoftware.htmlunit.html.HtmlFormUtil;
import com.gargoylesoftware.htmlunit.html.HtmlImage;
......@@ -124,6 +126,7 @@ import java.util.logging.Level;
import java.util.logging.LogRecord;
import java.util.logging.Logger;
import javax.annotation.Nonnull;
import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
......@@ -1622,9 +1625,11 @@ public abstract class HudsonTestCase extends TestCase implements RootAction {
* Extends {@link com.gargoylesoftware.htmlunit.WebClient} and provide convenience methods
* for accessing Hudson.
*/
public class WebClient extends com.gargoylesoftware.htmlunit.WebClient {
public class WebClient extends com.gargoylesoftware.htmlunit.WebClient implements WebClientResponseLoadListenable {
private static final long serialVersionUID = 5808915989048338267L;
private List<WebClientResponseLoadListener> loadListeners = new CopyOnWriteArrayList<>();
public WebClient() {
// default is IE6, but this causes 'n.doScroll('left')' to fail in event-debug.js:1907 as HtmlUnit doesn't implement such a method,
// so trying something else, until we discover another problem.
......@@ -1686,6 +1691,31 @@ public abstract class HudsonTestCase extends TestCase implements RootAction {
//setTimeout(60*1000);
}
@Override
public void addResponseLoadListener(@Nonnull WebClientResponseLoadListener listener) {
removeResponseLoadListener(listener);
loadListeners.add(listener);
}
@Override
public void removeResponseLoadListener(@Nonnull WebClientResponseLoadListener listener) {
loadListeners.remove(listener);
}
@Override
public Page loadWebResponseInto(WebResponse webResponse, WebWindow webWindow) throws IOException, FailingHttpStatusCodeException {
try {
return super.loadWebResponseInto(webResponse, webWindow);
} finally {
if (!loadListeners.isEmpty()) {
for (WebClientResponseLoadListener listener : loadListeners) {
listener.onLoad(webResponse, webWindow);
}
}
}
}
/**
* Logs in to Jenkins.
*/
......
......@@ -32,6 +32,7 @@ import com.gargoylesoftware.htmlunit.FailingHttpStatusCodeException;
import com.gargoylesoftware.htmlunit.Page;
import com.gargoylesoftware.htmlunit.WebRequest;
import com.gargoylesoftware.htmlunit.WebResponse;
import com.gargoylesoftware.htmlunit.WebWindow;
import com.gargoylesoftware.htmlunit.html.DomNode;
import com.gargoylesoftware.htmlunit.html.HtmlButton;
import com.gargoylesoftware.htmlunit.html.HtmlElement;
......@@ -39,7 +40,6 @@ import com.gargoylesoftware.htmlunit.html.HtmlForm;
import com.gargoylesoftware.htmlunit.html.HtmlImage;
import com.gargoylesoftware.htmlunit.html.HtmlInput;
import com.gargoylesoftware.htmlunit.html.HtmlPage;
import com.gargoylesoftware.htmlunit.html.HtmlSubmitInput;
import com.gargoylesoftware.htmlunit.javascript.HtmlUnitContextFactory;
import com.gargoylesoftware.htmlunit.javascript.host.xml.XMLHttpRequest;
import com.gargoylesoftware.htmlunit.util.NameValuePair;
......@@ -147,6 +147,7 @@ import java.util.TimerTask;
import java.util.TreeSet;
import java.util.UUID;
import java.util.concurrent.Callable;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Future;
import java.util.concurrent.LinkedBlockingQueue;
......@@ -159,6 +160,7 @@ import java.util.logging.Level;
import java.util.logging.LogRecord;
import java.util.logging.Logger;
import javax.annotation.CheckForNull;
import javax.annotation.Nonnull;
import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
......@@ -1828,9 +1830,11 @@ public class JenkinsRule implements TestRule, MethodRule, RootAction {
* Extends {@link com.gargoylesoftware.htmlunit.WebClient} and provide convenience methods
* for accessing Hudson.
*/
public class WebClient extends com.gargoylesoftware.htmlunit.WebClient {
public class WebClient extends com.gargoylesoftware.htmlunit.WebClient implements WebClientResponseLoadListenable {
private static final long serialVersionUID = 5808915989048338267L;
private List<WebClientResponseLoadListener> loadListeners = new CopyOnWriteArrayList<>();
public WebClient() {
// default is IE6, but this causes 'n.doScroll('left')' to fail in event-debug.js:1907 as HtmlUnit doesn't implement such a method,
// so trying something else, until we discover another problem.
......@@ -1890,6 +1894,30 @@ public class JenkinsRule implements TestRule, MethodRule, RootAction {
//setTimeout(60*1000);
}
@Override
public void addResponseLoadListener(@Nonnull WebClientResponseLoadListener listener) {
removeResponseLoadListener(listener);
loadListeners.add(listener);
}
@Override
public void removeResponseLoadListener(@Nonnull WebClientResponseLoadListener listener) {
loadListeners.remove(listener);
}
@Override
public Page loadWebResponseInto(WebResponse webResponse, WebWindow webWindow) throws IOException, FailingHttpStatusCodeException {
try {
return super.loadWebResponseInto(webResponse, webWindow);
} finally {
if (!loadListeners.isEmpty()) {
for (WebClientResponseLoadListener listener : loadListeners) {
listener.onLoad(webResponse, webWindow);
}
}
}
}
/**
* Logs in to Jenkins.
*/
......@@ -1925,7 +1953,7 @@ public class JenkinsRule implements TestRule, MethodRule, RootAction {
* and passwords. All the test accounts have the same user name and password.
*/
public WebClient login(String username) throws Exception {
login(username,username);
login(username, username);
return this;
}
......@@ -2008,7 +2036,7 @@ public class JenkinsRule implements TestRule, MethodRule, RootAction {
}
public HtmlPage getPage(Node item) throws IOException, SAXException {
return getPage(item,"");
return getPage(item, "");
}
public HtmlPage getPage(Node item, String relative) throws IOException, SAXException {
......@@ -2127,7 +2155,7 @@ public class JenkinsRule implements TestRule, MethodRule, RootAction {
NameValuePair crumb = new NameValuePair(
jenkins.getCrumbIssuer().getDescriptor().getCrumbRequestField(),
jenkins.getCrumbIssuer().getCrumb( null ));
req.setRequestParameters(Arrays.asList( crumb ));
req.setRequestParameters(Arrays.asList(crumb));
return req;
}
......
/*
* The MIT License
*
* Copyright (c) 2015, CloudBees, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package org.jvnet.hudson.test;
import com.gargoylesoftware.htmlunit.WebResponse;
import com.gargoylesoftware.htmlunit.WebWindow;
import javax.annotation.Nonnull;
/**
* Hook into the HtmlUnit {@link org.jvnet.hudson.test.JenkinsRule.WebClient}
* response loading into a "window".
* @author <a href="mailto:tom.fennelly@gmail.com">tom.fennelly@gmail.com</a>
*/
public interface WebClientResponseLoadListenable {
/**
* Add a listener.
* @param listener The listener.
*/
void addResponseLoadListener(@Nonnull WebClientResponseLoadListener listener);
/**
* Removing a listener.
* @param listener The listener.
*/
void removeResponseLoadListener(@Nonnull WebClientResponseLoadListener listener);
/**
* Load listener interface.
*/
public interface WebClientResponseLoadListener {
/**
* Response load event.
* @param webResponse The response.
* @param webWindow The window into which the response is being loaded.
*/
void onLoad(@Nonnull WebResponse webResponse, @Nonnull WebWindow webWindow);
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册