Skip to content

Commit

Permalink
Added a zope.testbrowser.testing.Browser.post method that allows
Browse files Browse the repository at this point in the history
tests to supply a body and a content type.  This is handy for
testing ajax with non-form input (e.g. json).
  • Loading branch information
Jim Fulton committed Mar 23, 2008
1 parent 5c7268f commit 3c9ccbd
Show file tree
Hide file tree
Showing 6 changed files with 124 additions and 3 deletions.
7 changes: 7 additions & 0 deletions CHANGES.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,13 @@
CHANGES
=======

3.5 (unreleased)
----------------

- Added a zope.testbrowser.testing.Browser.post method that allows
tests to supply a body and a content type. This is handy for
testing ajax with non-form input (e.g. json).

3.4.3 (unreleased)
------------------

Expand Down
9 changes: 8 additions & 1 deletion buildout.cfg
Original file line number Diff line number Diff line change
@@ -1,7 +1,14 @@
[buildout]
develop = . mechanize
parts = test interpreter
index = http://download.zope.org/zope3.4
index = http://download.zope.org/simple
extends = http://download.zope.org/zope3.4/versions-3.4.0c1.cfg
versions = versions

[versions]
zope.publisher = 3.5.1
zope.testbrowser =
mechanize =

[test]
recipe = zc.recipe.testrunner
Expand Down
66 changes: 66 additions & 0 deletions src/zope/testbrowser/README.txt
Original file line number Diff line number Diff line change
Expand Up @@ -1107,6 +1107,72 @@ disambiguate if no other arguments are provided:
ValueError: if no other arguments are given, index is required.


Submitting a posts body directly
--------------------------------

In addition to the open method, zope.testbrowser.testing.Browser has a
post method that allows a body to be supplied.

Let's visit a page that echos it's request:

>>> browser.open('http://localhost/@@echo.html')
>>> print browser.contents,
HTTP_ACCEPT_LANGUAGE: en-US
HTTP_CONNECTION: close
HTTP_COOKIE:
HTTP_HOST: localhost
HTTP_REFERER: localhost
HTTP_USER_AGENT: Python-urllib/2.4
PATH_INFO: /@@echo.html
QUERY_STRING:
REQUEST_METHOD: GET
SERVER_PROTOCOL: HTTP/1.1
Body: ''

Now, we'll try a post. The post method takes a URL, a data string,
and an optional content type. If we just pass a string, then
a URL-encoded query string is assumed:

>>> browser.post('http://localhost/@@echo.html', 'x=1&y=2')
>>> print browser.contents,
CONTENT_LENGTH: 7
CONTENT_TYPE: application/x-www-form-urlencoded
HTTP_ACCEPT_LANGUAGE: en-US
HTTP_CONNECTION: close
HTTP_COOKIE:
HTTP_HOST: localhost
HTTP_REFERER: localhost
HTTP_USER_AGENT: Python-urllib/2.4
PATH_INFO: /@@echo.html
QUERY_STRING:
REQUEST_METHOD: POST
SERVER_PROTOCOL: HTTP/1.1
x: 1
y: 2
Body: ''

The body is empty because it is consumed to get form data.

We can pass a content-type explicitly:

>>> browser.post('http://localhost/@@echo.html',
... '{"x":1,"y":2}', 'application/x-javascipt')
>>> print browser.contents,
CONTENT_LENGTH: 13
CONTENT_TYPE: application/x-javascipt
HTTP_ACCEPT_LANGUAGE: en-US
HTTP_CONNECTION: close
HTTP_COOKIE:
HTTP_HOST: localhost
HTTP_REFERER: localhost
HTTP_USER_AGENT: Python-urllib/2.4
PATH_INFO: /@@echo.html
REQUEST_METHOD: POST
SERVER_PROTOCOL: HTTP/1.1
Body: '{"x":1,"y":2}'

Here, the body if left in place because it isn't form data.

Performance Testing
-------------------

Expand Down
24 changes: 23 additions & 1 deletion src/zope/testbrowser/ftests/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +1,23 @@
# Make a package.
##############################################################################
#
# Copyright (c) Zope Corporation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
#
##############################################################################

class Echo:
"""Simply echo a request
"""

def __init__(self, context, request):
self.request = request

def __call__(self):
return '%s\nBody: %r' % (self.request, self.request.bodyStream.read())
6 changes: 6 additions & 0 deletions src/zope/testbrowser/ftests/ftesting.zcml
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,12 @@
<grant permission="zope.View"
role="zope.Anonymous" />

<browser:page
name="echo.html"
for="*"
class=".ftests.Echo"
permission="zope.Public"
/>

<browser:resourceDirectory
name="testbrowser"
Expand Down
15 changes: 14 additions & 1 deletion src/zope/testbrowser/testing.py
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,15 @@ def close(self):
class PublisherHTTPHandler(urllib2.HTTPHandler):
"""Special HTTP handler to use the Zope Publisher."""

http_request = urllib2.AbstractHTTPHandler.do_request_
def http_request(self, req):
# look at data and set content type
if req.has_data():
data = req.get_data()
if isinstance(data, dict):
req.add_data(data['body'])
req.add_unredirected_header('Content-type',
data['content-type'])
return urllib2.AbstractHTTPHandler.do_request_(self, req)

def http_open(self, req):
"""Open an HTTP connection having a ``urllib2`` request."""
Expand Down Expand Up @@ -160,6 +168,11 @@ def __init__(self, url=None):
mech_browser = PublisherMechanizeBrowser()
super(Browser, self).__init__(url=url, mech_browser=mech_browser)

def post(self, url, data, content_type=None):
if content_type is not None:
data = {'body': data, 'content-type': content_type}
return self.open(url, data)

#### virtual host test suites ####

example_path_re = re.compile('http://example.com/virtual_path/')
Expand Down

0 comments on commit 3c9ccbd

Please sign in to comment.