====================
User documentation
====================
.. contents:: :local:
Setup
=====
For using the test browser, just decorate your test methods with the `@browsing`
decorator.
.. code:: py
from ftw.testbrowser import browsing
from unittest2 import TestCase
from plone.app.testing import PLONE_FUNCTIONAL_TESTING
class TestMyView(TestCase):
layer = PLONE_FUNCTIONAL_TESTING
@browsing
def test_view_displays_things(self, browser):
browser.visit(view='my_view')
.. warning:: Make sure that you use a functional testing layer!
.. seealso:: :py:func:`ftw.testbrowser.browsing`
By default there is only one, global browser, but it is also possible to instantiate
a new browser and to set it up manually:
.. code:: py
from ftw.testbrowser.core import Browser
browser = Browser()
app = zope_app
with browser(app):
browser.open()
.. warning:: Page objects and forms usually use the global browser. Creating a new
browser manually will not set it as global browser and page objects / forms will
not be able to access it!
Choosing the default driver
---------------------------
The default driver is chosen automatically, depending on whether the browser is
set up with a zope app (=> ``LIB_MECHANIZE``) or not (=> ``LIB_REQUESTS``).
The default driver can be changed on the browser instance, overriding the
automatic driver selection:
.. code:: py
from ftw.testbrowser.core import Browser
from ftw.testbrowser.core import LIB_MECHANIZE
from ftw.testbrowser.core import LIB_REQUESTS
browser = Browser()
# always use mechanize:
browser.default_driver = LIB_MECHANIZE
# or always use requests:
browser.default_driver = LIB_REQUESTS
When using the testbrowser in a ``plone.testing`` layer, the driver can be
chosen by using a standard ``plone.testing`` fixture:
.. code:: py
from ftw.testbrowser import MECHANIZE_BROWSER_FIXTURE
from ftw.testbrowser import REQUESTS_BROWSER_FIXTURE
from plone.app.testing import PLONE_FIXTURE
from plone.app.testing import FunctionalTesting
MY_FUNCTIONAL_TESTING_WITH_MECHANIZE = FunctionalTesting(
bases=(PLONE_FIXTURE,
MECHANIZE_BROWSER_FIXTURE),
name='functional:mechanize')
MY_FUNCTIONAL_TESTING_WITH_REQUESTS = FunctionalTesting(
bases=(PLONE_FIXTURE,
REQUESTS_BROWSER_FIXTURE),
name='functional:requests')
Visit pages
===========
For visiting a page, use the `visit` or `open` method on the browser (those methods
do the same).
Visiting the Plone site root:
.. code:: py
browser.open()
print browser.url
.. seealso:: :py:func:`ftw.testbrowser.core.Browser.url`
Visiting a full url:
.. code:: py
browser.open('http://nohost/plone/sitemap')
Visiting an object:
.. code:: py
folder = portal.get('the-folder')
browser.visit(folder)
Visit a view on an object:
.. code:: py
folder = portal.get('the-folder')
browser.visit(folder, view='folder_contents')
The `open` method can also be used to make POST request:
.. code:: py
browser.open('http://nohost/plone/login_form',
{'__ac_name': TEST_USER_NAME,
'__ac_password': TEST_USER_PASSWORD,
'form.submitted': 1})
.. seealso:: :py:func:`ftw.testbrowser.core.Browser.open`
Logging in
==========
The `login` method sets the `Authorization` request header.
Login with the `plone.app.testing` default test user (`TEST_USER_NAME`):
.. code:: py
browser.login().open()
Logging in with another user:
.. code:: py
browser.login(username='john.doe', password='secret')
Logout and login a different user:
.. code:: py
browser.login(username='john.doe', password='secret').open()
browser.reset()
browser.login().open()
.. seealso:: :py:func:`ftw.testbrowser.core.Browser.login`,
:py:func:`ftw.testbrowser.core.Browser.reset`
Finding elements
================
Elements can be found using CSS-Selectors (`css` method) or using XPath-Expressions
(`xpath` method). A result set (`Nodes`) of all matches is returned.
.. seealso:: :py:func:`ftw.testbrowser.nodes.Nodes`
CSS:
.. code:: py
browser.open()
heading = browser.css('.documentFirstHeading').first
self.assertEquals('Plone Site', heading.normalized_text())
.. seealso:: :py:func:`ftw.testbrowser.core.Browser.css`,
:py:func:`ftw.testbrowser.nodes.NodeWrapper.normalized_text`
XPath:
.. code:: py
browser.open()
heading = browser.xpath('h1').first
self.assertEquals('Plone Site', heading.normalized_text())
.. seealso:: :py:func:`ftw.testbrowser.core.Browser.xpath`
Finding elements by text:
.. code:: py
browser.open()
browser.find('Sitemap').click()
The `find` method will look for theese elements (in this order):
- a link with this text (normalized, including subelements' texts)
- a field which has a label with this text
- a button which has a label with this text
.. seealso:: :py:func:`ftw.testbrowser.core.Browser.find`
Matching text content
=====================
In HTML, most elements can contain direct text but the elements can also
contain sub-elements which also have text.
When having this HTML:
.. code:: html
This is
a link
We can get only direct text of the link:
.. code:: py
>>> browser.css('#link').first.text
'\n This is\n '
or the text recursively:
.. code:: py
>>> browser.css('#link').first.text_content()
'\n This is\n a link\n '
.. seealso:: :py:func:`ftw.testbrowser.nodes.NodeWrapper.text_content`
or the normalized recursive text:
.. code:: py
>>> browser.css('#link').first.normalized_text()
'This is a link'
.. seealso:: :py:func:`ftw.testbrowser.nodes.NodeWrapper.normalized_text`
Functions such as `find` usually use the `normalized_text`.
.. seealso:: :py:func:`ftw.testbrowser.core.Browser.find`
Get the page contents / json data
=================================
The page content of the currently loaded page is always available on the browser:
.. code :: py
browser.open()
print browser.contents
.. seealso:: :py:func:`ftw.testbrowser.core.Browser.contents`
If the result is a JSON string, you can access the JSON data (converted to python
data structure already) with the `json` property:
.. code :: py
browser.open(view='a-json-view')
print browser.json
.. seealso:: :py:func:`ftw.testbrowser.core.Browser.json`
Filling and submitting forms
============================
The browser's `fill` method helps to easily fill forms by label text without knowing
the structure and details of the form:
.. code:: py
browser.visit(view='login_form')
browser.fill({'Login Name': TEST_USER_NAME,
'Password': TEST_USER_PASSWORD}).submit()
The `fill` method returns the browser instance which can be submitted with `submit`.
The keys of the dict with the form data can be either field labels (`