==================== 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 (`