JS Browser: Support for AJAX form submission

This commit is contained in:
Kovid Goyal 2011-09-21 21:01:48 -06:00
parent 70ff56c1b2
commit f9dabe9140
3 changed files with 67 additions and 1 deletions

View File

@ -130,6 +130,7 @@ class NetworkAccessManager(QNetworkAccessManager): # {{{
def __init__(self, log, use_disk_cache=True, parent=None):
QNetworkAccessManager.__init__(self, parent)
self.reply_count = 0
self.log = log
if use_disk_cache:
self.cache = QNetworkDiskCache(self)
@ -170,6 +171,7 @@ class NetworkAccessManager(QNetworkAccessManager): # {{{
def on_finished(self, reply):
reply_url = unicode(reply.url().toString())
self.reply_count += 1
if reply.error():
self.log.warn("Reply error: %s - %d (%s)" %
@ -286,6 +288,17 @@ class Browser(QObject, FormsMixin):
return lw.loaded_ok
def _wait_for_replies(self, reply_count, timeout):
final_time = time.time() + timeout
loop = QEventLoop(self)
while (time.time() < final_time and self.nam.reply_count <
reply_count):
loop.processEvents()
time.sleep(0.1)
if self.nam.reply_count < reply_count:
raise Timeout('Waiting for replies took longer than %d seconds' %
timeout)
def visit(self, url, timeout=30.0):
'''
Open the page specified in URL and wait for it to complete loading.
@ -310,6 +323,7 @@ class Browser(QObject, FormsMixin):
:para ajax_replies: Number of replies to wait for after clicking a link
that triggers some AJAX interaction
'''
initial_count = self.nam.reply_count
js = '''
var e = document.createEvent('MouseEvents');
e.initEvent( 'click', true, true );
@ -317,7 +331,8 @@ class Browser(QObject, FormsMixin):
'''
qwe.evaluateJavaScript(js)
if ajax_replies > 0:
raise NotImplementedError('AJAX clicking not implemented')
reply_count = initial_count + ajax_replies
self._wait_for_replies(reply_count, timeout)
elif wait_for_load and not self._wait_for_load(timeout):
raise LoadError('Clicking resulted in a failed load')

View File

@ -229,3 +229,15 @@ class FormsMixin(object):
self.click(sc.qwe, wait_for_load=wait_for_load,
ajax_replies=ajax_replies, timeout=timeout)
def ajax_submit(self, submit_control_selector=None,
num_of_replies=1, timeout=30.0):
'''
Submit the current form. This method is meant for those forms that
use AJAX rather than a plain submit. It will block until the specified
number of responses are returned from the server after the submit
button is clicked.
'''
self.submit(submit_control_selector=submit_control_selector,
wait_for_load=False, ajax_replies=num_of_replies,
timeout=timeout)

View File

@ -23,6 +23,24 @@ class Server(object):
return '''
<html>
<head><title>JS Browser test</title></head>
<script type="text/javascript" src="jquery"></script>
<script type="text/javascript">
$(document).ready(function() {
$('#ajax_test').submit(function() {
var val = $('#ajax_test input[name="text"]').val();
$.ajax({
dataType: "html",
url: "/controls_test",
data: {"text":val},
success: function(data) {
$('#ajax_test input[name="text"]').val(data);
}
});
return false;
});
});
</script>
<body>
<form id="controls_test" method="post" action="controls_test">
<h3>Test controls</h3>
@ -40,6 +58,12 @@ class Server(object):
<div><label>Simple Text:</label><input type="text" name="text" value="Image Test" /></div>
<input type="image" src="button_image" alt="Submit" />
</form>
<form id="ajax_test" method="post" action="controls_test">
<h3>Test AJAX submit</h3>
<div><label>Simple Text:</label><input type="text" name="text" value="AJAX Test" /></div>
<input type="submit" />
</form>
</body>
</html>
'''
@ -55,6 +79,12 @@ class Server(object):
cherrypy.response.headers['Content-Type'] = 'image/png'
return I('next.png', data=True)
@cherrypy.expose
def jquery(self):
cherrypy.response.headers['Content-Type'] = 'text/javascript'
return P('content_server/jquery.js', data=True)
class Test(unittest.TestCase):
@classmethod
@ -121,6 +151,15 @@ class Test(unittest.TestCase):
self.browser.submit()
self.assertEqual(self.server.form_data['text'], 'Image Test')
def test_ajax_submit(self):
'Test AJAX based form submission'
self.assertEqual(self.browser.visit('http://127.0.0.1:%d'%self.port),
True)
f = self.browser.select_form('#ajax_test')
f['text'] = 'Changed'
self.browser.ajax_submit()
self.assertEqual(self.server.form_data['text'], 'Changed')
def tests():
return unittest.TestLoader().loadTestsFromTestCase(Test)