[web test] add basic windmill tests and documentation
authorJulien Jehannet <julien.jehannet@logilab.fr>
Mon, 31 May 2010 19:33:43 +0200
changeset 5675 4535f8e57580
parent 5674 9378d13e9ac4
child 5676 aa04ccb8dd62
[web test] add basic windmill tests and documentation - connection / deconnection - user creation
doc/book/en/tutorials/index.rst
doc/book/en/tutorials/tools/windmill.rst
web/test/test_windmill.py
web/test/windmill/test_connexion.py
web/test/windmill/test_creation.py
--- a/doc/book/en/tutorials/index.rst	Tue Jun 01 17:09:22 2010 +0200
+++ b/doc/book/en/tutorials/index.rst	Mon May 31 19:33:43 2010 +0200
@@ -17,3 +17,4 @@
 
    base/index
    advanced/index
+   tools/windmill.rst
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/en/tutorials/tools/windmill.rst	Mon May 31 19:33:43 2010 +0200
@@ -0,0 +1,133 @@
+==========================
+Use Windmill with CubicWeb
+==========================
+
+Windmill_ implements cross browser testing, in-browser recording and playback,
+and functionality for fast accurate debugging and test environment integration.
+
+.. _Windmill: http://www.getwindmill.com/
+
+`Online features list <http://www.getwindmill.com/features>`_ is available.
+
+
+Installation
+============
+
+Windmill
+--------
+
+You have to install Windmill manually for now. If you're using Debian, there is
+no binary package (`yet <http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=579109>`_).
+
+The simplest solution is to use a *setuptools/pip* command (for a clean
+environment, take a look to the `virtualenv
+<http://pypi.python.org/pypi/virtualenv>`_ project as well)::
+
+    pip install windmill
+    curl -O http://github.com/windmill/windmill/tarball/master
+
+Some install instructions are `available <http://wiki.github.com/windmill/windmill/installing>`_.
+
+Be sure to have the windmill module in your PYTHONPATH afterwards::
+
+    python -c "import windmill"
+
+X dummy
+-------
+
+In order to reduce unecessary system load from your test machines, It's
+recommended to use X dummy server for testing the Unix web clients, you need a
+dummy video X driver (as xserver-xorg-video-dummy package in Debian) coupled
+with a light X server as `Xvfb <http://en.wikipedia.org/wiki/Xvfb>`_.
+
+    The dummy driver is a special driver available with the XFree86 DDX. To use
+    the dummy driver, simply substitue it for your normal card driver in the
+    Device section of your xorg.conf configuration file. For example, if you
+    normally uses an ati driver, then you will have a Device section with
+    Driver "ati" to let the X server know that you want it to load and use the
+    ati driver; however, for these conformance tests, you would change that
+    line to Driver "dummy" and remove any other ati specific options from the
+    Device section.
+
+    *From: http://www.x.org/wiki/XorgTesting*
+
+Then, you can run the X server with the following command :
+
+    /usr/bin/X11/Xvfb :1 -ac -screen 0 1280x1024x8 -fbdir /tmp
+
+
+Windmill usage
+==============
+
+Record your use case
+--------------------
+
+- start your instance manually
+- start Windmill_ with url site as last argument (read Usage_ or use *'-h'*
+  option to find required command line arguments)
+- use the record button
+- click on save to obtain python code of your use case
+- copy the content to a new file in a *windmill* directory
+
+.. _Usage: http://wiki.github.com/windmill/windmill/running-tests
+
+If you are using firefox as client, consider the "firebug" option.
+
+You can refine the test by the *loadtest* windmill option:
+
+    windmill -m firebug loadtest=<test_file.py> <instance url>
+
+
+Integrate Windmill tests into CubicWeb
+======================================
+
+Run your tests
+--------------
+
+You can easily run your windmill test suite through `pytest` or :mod:`unittest`.
+You have to copy a *test_windmill.py* file from :mod:`web.test`.
+
+By default, CubicWeb will use **firefox** as the default browser and will try
+to run test instance server on localhost. In the general case, You've no need
+to change anything.
+
+Check the :class:`cubicweb.devtools.cwwindmill.CubicWebServerTC` class for server
+parameters and :class:`cubicweb.devtools.cwwindmill.CubicWebWindmillUseCase` for
+Windmill configuration.
+
+Best practises
+--------------
+
+Don't run another instance on the same port. You risk to silence some
+regressions (test runner will automatically fail in further versions).
+
+Start your use case by using an assert on the expected primary url page.
+Otherwise all your tests could fail without clear explanation of the used
+navigation.
+
+In the same location of the *test_windmill.py*, create a *windmill/* with your
+windmill recorded use cases.
+
+Then, you can launch the test series with::
+
+    % pytest test/test_windmill.py
+
+For instance, you can start CubicWeb framework use tests by::
+
+    % pytest web/test/test_windmill.py
+
+
+Preferences
+===========
+
+A *.windmill/prefs.py* could be used to redefine default configuration values.
+
+.. define CubicWeb preferences in the parent test case instead with a dedicated firefox profile
+
+For managing browser extensions, read `advanced topic chapter
+<http://wiki.github.com/windmill/windmill/advanced-topics>`_.
+
+More configuration examples could be seen in *windmill/conf/global_settings.py*
+as template.
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/web/test/test_windmill.py	Mon May 31 19:33:43 2010 +0200
@@ -0,0 +1,42 @@
+from cubicweb.devtools import cwwindmill
+
+
+class CubicWebWindmillUseCase(cwwindmill.CubicWebWindmillUseCase):
+    """class for windmill use case tests
+
+    From test server parameters:
+
+    :params ports_range: range of http ports to test (range(7000, 8000) by default)
+    :type ports_range: iterable
+    :param anonymous_logged: is anonymous user logged by default ?
+    :type anonymous_logged: bool
+
+    The first port found as available in `ports_range` will be used to launch
+    the test server
+
+    From Windmill configuration:
+
+    :param browser: browser identification string (firefox|ie|safari|chrome) (firefox by default)
+    :param test_dir: testing file path or directory (./windmill by default)
+    """
+    #ports_range = range(7000, 8000)
+    anonymous_logged = False
+    #browser = 'firefox'
+    #test_dir = osp.join(os.getcwd(), 'windmill')
+
+    # If you prefer, you can put here the use cases recorded by windmill GUI
+    # (services transformer) instead of the windmill sub-directory
+    # You can change `test_dir` as following:
+    #test_dir = __file__
+
+
+from windmill.authoring import WindmillTestClient
+def test_usecase():
+    client = WindmillTestClient(__name__)
+    import pdb; pdb.set_trace()
+    client.open(url=u'/')
+#    ...
+
+
+if __name__ == '__main__':
+    cwwindmill.unittest_main()
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/web/test/windmill/test_connexion.py	Mon May 31 19:33:43 2010 +0200
@@ -0,0 +1,35 @@
+from cubicweb.devtools import DEFAULT_SOURCES
+LOGIN, PASSWORD = DEFAULT_SOURCES['admin'].values()
+
+# Generated by the windmill services transformer
+from windmill.authoring import WindmillTestClient
+
+
+def test_connect():
+    client = WindmillTestClient(__name__)
+
+    client.open(url=u'/')
+    client.asserts.assertJS(js=u"$('#loginForm').is(':visible')")
+    client.type(text=LOGIN, id=u'__login')
+    client.type(text=PASSWORD, id=u'__password')
+    client.execJS(js=u"$('#loginForm').submit()")
+    client.waits.forPageLoad(timeout=u'20000')
+    client.asserts.assertJS(js=u'$(\'.message\').text() == "welcome %s !"' % LOGIN)
+    client.open(url=u'/logout')
+    client.open(url=u'/')
+    client.asserts.assertJS(js=u"$('#loginForm').is(':visible')")
+
+def test_wrong_connect():
+    client = WindmillTestClient(__name__)
+
+    client.open(url=u'/')
+    # XXX windmill wants to use its proxy internally on 403 :-(
+    #client.asserts.assertJS(js=u"$('#loginForm').is(':visible')")
+    #client.type(text=LOGIN, id=u'__login')
+    #client.type(text=u'novalidpassword', id=u'__password')
+    #client.click(value=u'log in')
+    client.open(url=u'/?__login=user&__password=nopassword')
+    client.waits.forPageLoad(timeout=u'20000')
+    client.asserts.assertTextIn(validator=u'authentication failure', id=u'loginBox')
+    client.open(url=u'/')
+    client.asserts.assertJS(js=u"$('#loginForm').is(':visible')")
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/web/test/windmill/test_creation.py	Mon May 31 19:33:43 2010 +0200
@@ -0,0 +1,55 @@
+from cubicweb.devtools import DEFAULT_SOURCES
+LOGIN, PASSWORD = DEFAULT_SOURCES['admin'].values()
+
+# Generated by the windmill services transformer
+from windmill.authoring import WindmillTestClient
+
+def test_creation():
+    client = WindmillTestClient(__name__)
+
+    client.open(url=u'/')
+    client.waits.forPageLoad(timeout=u'8000')
+    client.type(text=LOGIN, id=u'__login')
+    client.type(text=PASSWORD, id=u'__password')
+    client.click(value=u'log in')
+    client.waits.forPageLoad(timeout=u'20000')
+
+    # pre-condition
+    client.open(url=u'/cwuser/myuser')
+    client.asserts.assertJS(js=u'$(\'#contentmain h1\').text() == "this resource does not exist"')
+    client.open(url=u'/?rql=Any U WHERE U is CWUser, U login "myuser"')
+    client.asserts.assertJS(js=u'$(\'.searchMessage strong\').text() == "No result matching query"')
+
+    client.open(url=u'/manage')
+    client.open(url=u'/add/CWUser')
+    client.type(text=u'myuser', id=u'login-subject:A')
+    client.type(text=u'myuser', id=u'upassword-subject:A')
+    client.type(text=u'myuser', name=u'upassword-subject-confirm:A')
+    client.type(text=u'myuser', id=u'firstname-subject:A')
+    client.select(val=u'4', id=u'in_group-subject:A')
+    client.waits.forPageLoad(timeout=u'20000')
+    client.click(id=u'adduse_email:Alink')
+    client.waits.forPageLoad(timeout=u'20000')
+    client.type(text=u'myuser@logilab.fr', id=u'address-subject:B')
+    client.waits.forPageLoad(timeout=u'20000')
+    client.click(value=u'button_ok')
+    client.waits.forPageLoad(timeout=u'20000')
+    client.asserts.assertJS(js=u'$(\'.message\').text() == "entity created"')
+    client.open(url=u'/?rql=Any U WHERE U is CWUser, U login "myuser"')
+    client.asserts.assertJS(js=u'$(\'#contentmain h1\').text() == "myuser"')
+    client.waits.forPageLoad(timeout=u'8000')
+    client.open(url=u'/cwuser/myuser?vid=sameetypelist')
+    client.waits.forPageLoad(timeout=u'8000')
+    client.asserts.assertJS(js=u'$(\'#contentmain a\').text() == "myuser"')
+    client.open(url=u'/cwuser/myuser?vid=text')
+    client.waits.forPageLoad(timeout=u'8000')
+    client.asserts.assertJS(js=u'$(\'#contentmain\').text() == "\\nmyuser"')
+    client.open(url=u'/cwuser/myuser?vid=deleteconf')
+    client.waits.forElement(timeout=u'8000', value=u'button_delete')
+    client.click(value=u'button_delete')
+    client.waits.forPageLoad(timeout=u'8000')
+    client.open(url=u'/cwuser/myuser')
+    client.asserts.assertJS(js=u'$(\'#contentmain h1\').text() == "this resource does not exist"')
+    client.open(url=u'/?rql=Any U WHERE U is CWUser, U login "myuser"')
+    client.asserts.assertJS(js=u'$(\'.searchMessage strong\').text() == "No result matching query"')
+