Skip to content

Commit

Permalink
Merge changes from the jinty-webtest2 branch: WebTest integration and…
Browse files Browse the repository at this point in the history
… test refactoring.
  • Loading branch information
Brian Sutherland committed Jan 30, 2011
3 parents a20fb00 + 0e8eee3 + 0d070a2 commit e53da70
Show file tree
Hide file tree
Showing 12 changed files with 564 additions and 160 deletions.
70 changes: 34 additions & 36 deletions src/zope/testbrowser/README.txt
Expand Up @@ -11,8 +11,8 @@ HTTP Browser
The ``zope.testbrowser.browser`` module exposes a ``Browser`` class that
simulates a web browser similar to Mozilla Firefox or IE.

>>> from zope.testbrowser.browser import Browser
>>> browser = Browser()
>>> from zope.testbrowser.browser import Browser as RealBrowser
>>> browser = RealBrowser()

This version of the browser object can be used to access any web site just as
you would do using a normal web browser.
Expand All @@ -24,8 +24,8 @@ There is also a special version of the ``Browser`` class which uses
`wsgi_intercept`_ and can be used to do functional testing of WSGI
applications, it can be imported from ``zope.testbrowser.wsgi``:

>>> from zope.testbrowser.wsgi import Browser
>>> browser = Browser()
>>> from zope.testbrowser.wsgi import Browser as WSGIBrowser
>>> browser = WSGIBrowser()

.. _`wsgi_intercept`: http://pypi.python.org/pypi/wsgi_intercept

Expand All @@ -50,18 +50,28 @@ Where ``simple_app`` is the callable of your WSGI application.
Zope 3 Test Browser
~~~~~~~~~~~~~~~~~~~

WSGI applications can also be tested directly when wrapped by WebTest:

>>> from zope.testbrowser.webtest import Browser as WSGIBrowser
>>> from wsgiref.simple_server import demo_app
>>> browser = WSGIBrowser(demo_app, url='http://localhost/')
>>> print browser.contents
Hello world!
...

There is also a special version of the ``Browser`` class used to do functional
testing of Zope 3 applications, it can be imported from
``zope.testbrowser.testing``:

>>> from zope.testbrowser.testing import Browser
>>> browser = Browser()
>>> from zope.testbrowser.testing import Browser as TestingBrowser
>>> browser = TestingBrowser()

Bowser Usage
------------

All browsers are used the same way. An initial page to load can be passed
to the ``Browser`` constructor:
To allow this test to be run against different implementations, we will use a
Browser object from the test globals. An initial page to load can be passed to
the ``Browser`` constructor:

>>> browser = Browser('http://localhost/@@/testbrowser/simple.html')
>>> browser.url
Expand Down Expand Up @@ -1245,63 +1255,51 @@ In addition to the open method, zope.testbrowser.testing.Browser has a ``post``
method that allows a request body to be supplied. This method is particularly
helpful when testing Ajax methods.

Let's visit a page that echos it's request:
Let's visit a page that echos some interesting values from it's request:

>>> browser.open('http://localhost/@@echo.html')
>>> print browser.contents,
HTTP_USER_AGENT: Python-urllib/2.4
HTTP_CONNECTION: close
HTTP_COOKIE:
REMOTE_ADDR: 127.0.0.1
>>> print browser.contents
HTTP_ACCEPT_LANGUAGE: en-US
REQUEST_METHOD: GET
HTTP_CONNECTION: close
HTTP_HOST: localhost
HTTP_USER_AGENT: Python-urllib/2.4
PATH_INFO: /@@echo.html
SERVER_PROTOCOL: HTTP/1.1
QUERY_STRING:
REQUEST_METHOD: GET
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,
>>> print browser.contents
CONTENT_LENGTH: 7
HTTP_USER_AGENT: Python-urllib/2.4
HTTP_CONNECTION: close
HTTP_COOKIE:
REMOTE_ADDR: 127.0.0.1
CONTENT_TYPE: application/x-www-form-urlencoded
HTTP_ACCEPT_LANGUAGE: en-US
y: 2
REQUEST_METHOD: POST
HTTP_CONNECTION: close
HTTP_HOST: localhost
HTTP_USER_AGENT: Python-urllib/2.4
PATH_INFO: /@@echo.html
CONTENT_TYPE: application/x-www-form-urlencoded
SERVER_PROTOCOL: HTTP/1.1
QUERY_STRING:
REQUEST_METHOD: POST
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-javascript')
>>> print browser.contents,
>>> print browser.contents
CONTENT_LENGTH: 13
HTTP_USER_AGENT: Python-urllib/2.4
HTTP_CONNECTION: close
HTTP_COOKIE:
REMOTE_ADDR: 127.0.0.1
CONTENT_TYPE: application/x-javascript
HTTP_ACCEPT_LANGUAGE: en-US
REQUEST_METHOD: POST
HTTP_CONNECTION: close
HTTP_HOST: localhost
HTTP_USER_AGENT: Python-urllib/2.4
PATH_INFO: /@@echo.html
CONTENT_TYPE: application/x-javascript
SERVER_PROTOCOL: HTTP/1.1
REQUEST_METHOD: POST
Body: '{"x":1,"y":2}'

Here, the body is left in place because it isn't form data.
Expand Down
13 changes: 5 additions & 8 deletions src/zope/testbrowser/cookies.txt
Expand Up @@ -9,7 +9,6 @@ The cookies mapping has an extended mapping interface that allows getting,
setting, and deleting the cookies that the browser is remembering for the
current url, or for an explicitly provided URL.

>>> from zope.testbrowser.testing import Browser
>>> browser = Browser()

Initially the browser does not point to a URL, and the cookies cannot be used.
Expand Down Expand Up @@ -221,11 +220,14 @@ Here are some examples.

Max-age is converted to an "expires" value.

XXX: When using zope.app.testing.functional, silly billy ends up being
silly%20billy, webtest gives us a ' ', which is right? -jinty

>>> browser.open(
... 'http://localhost/set_cookie.html?name=max&value=min&'
... 'max-age=3000&&comment=silly+billy')
>>> pprint.pprint(browser.cookies.getinfo('max')) # doctest: +ELLIPSIS
{'comment': 'silly%20billy',
{'comment': 'silly billy',
'commenturl': None,
'domain': 'localhost.local',
'expires': datetime.datetime(..., tzinfo=<UTC>),
Expand Down Expand Up @@ -254,7 +256,7 @@ page using the ``iterinfo`` method.
'port': None,
'secure': False,
'value': 'bar'},
{'comment': 'silly%20billy',
{'comment': 'silly billy',
'commenturl': None,
'domain': 'localhost.local',
'expires': datetime.datetime(..., tzinfo=<UTC>),
Expand Down Expand Up @@ -312,11 +314,6 @@ the other page in the browser, or, as already mentioned, you can use the
>>> sorted(browser.cookies.keys())
['foo', 'max', 'sha', 'va', 'wow']

>>> import zope.site.folder
>>> getRootFolder()['inner'] = zope.site.folder.Folder()
>>> getRootFolder()['inner']['path'] = zope.site.folder.Folder()
>>> import transaction
>>> transaction.commit()
>>> browser.open('http://localhost/inner/get_cookie.html')
>>> print browser.contents # has gewgaw
foo: bar
Expand Down
2 changes: 0 additions & 2 deletions src/zope/testbrowser/fixed-bugs.txt
Expand Up @@ -24,12 +24,10 @@ Browser.addHeader().

The tests below failed before the change was put in place.

>>> from zope.testbrowser.testing import Browser
>>> browser = Browser()
>>> browser.addHeader('Cookie', 'test')
>>> browser.open(u'http://localhost/@@/testbrowser/simple.html')

>>> from zope.testbrowser.testing import Browser
>>> browser = Browser()
>>> browser.addHeader(u'Cookie', 'test')
>>> browser.open('http://localhost/@@/testbrowser/simple.html')
Expand Down
48 changes: 22 additions & 26 deletions src/zope/testbrowser/ftests/__init__.py
Expand Up @@ -18,36 +18,32 @@ def __init__(self, context, request):
self.context = context
self.request = request

class Echo(View):
"""Simply echo the contents of the request"""

def __call__(self):
return ('\n'.join('%s: %s' % x for x in self.request.items()) +
'\nBody: %r' % self.request.bodyStream.read())

class GetCookie(View):
"""Gets cookie value"""
_interesting_environ = ('CONTENT_LENGTH',
'CONTENT_TYPE',
'HTTP_ACCEPT_LANGUAGE',
'HTTP_CONNECTION',
'HTTP_HOST',
'HTTP_USER_AGENT',
'PATH_INFO',
'REQUEST_METHOD')

def __call__(self):
return '\n'.join(
('%s: %s' % (k, v)) for k, v in sorted(
self.request.cookies.items()))

class SetCookie(View):
"""Sets cookie value"""
class Echo(View):
"""Simply echo the interesting parts of the request"""

def __call__(self):
self.request.response.setCookie(
**dict((str(k), str(v)) for k, v in self.request.form.items()))
items = []
for k in _interesting_environ:
v = self.request.get(k, None)
if v is None:
continue
items.append('%s: %s' % (k, v))
items.extend('%s: %s' % x for x in sorted(self.request.form.items()))
items.append('Body: %r' % self.request.bodyStream.read())
return '\n'.join(items)


class SetStatus(View):
"""Sets HTTP status"""
class EchoOne(View):
"""Echo one variable from the request"""

def __call__(self):
status = self.request.get('status')
if status:
self.request.response.setStatus(int(status))
return 'Just set a status of %s' % status
else:
return 'Everything fine'
return repr(self.request.get(self.request.form['var']))
25 changes: 2 additions & 23 deletions src/zope/testbrowser/ftests/ftesting.zcml
Expand Up @@ -8,15 +8,12 @@
<!-- This file is used for functional testing setup -->

<include package="zope.browserpage" file="meta.zcml" />
<include package="zope.browserresource" file="meta.zcml" />
<include package="zope.component" file="meta.zcml" />
<include package="zope.security" file="meta.zcml" />
<include package="zope.app.publication" file="meta.zcml" />

<include package="zope.browserresource" />
<include package="zope.container" />
<include package="zope.principalregistry" />
<include package="zope.ptresource" />
<include package="zope.publisher" />
<include package="zope.security" />
<include package="zope.site" />
Expand All @@ -36,28 +33,10 @@
/>

<browser:page
name="set_cookie.html"
name="echo_one.html"
for="*"
class=".ftests.SetCookie"
class=".ftests.EchoOne"
permission="zope.Public"
/>

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

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

<browser:resourceDirectory
name="testbrowser"
directory="ftests" />

</configure>

0 comments on commit e53da70

Please sign in to comment.