# HG changeset patch # User Julien Jehannet # Date 1279550802 -7200 # Node ID b9c612274af7aed882652eac0071ff47ef8e9809 # Parent 97c55baefa0c306c995eb6e4e41009f3a1007ee9 [test] improve windmill integration, new test on relation edition Changes: - display traceback in case of failure - add new use test for relation edition - edition mode is now possible by toggling `edit_test` or with using "pytest -i" - install firebug extension in edition mode - update documentation diff -r 97c55baefa0c -r b9c612274af7 devtools/cwwindmill.py --- a/devtools/cwwindmill.py Mon Jul 19 15:37:02 2010 +0200 +++ b/devtools/cwwindmill.py Mon Jul 19 16:46:42 2010 +0200 @@ -15,19 +15,28 @@ # # You should have received a copy of the GNU Lesser General Public License along # with CubicWeb. If not, see . -"""this module contains base classes for windmill integration""" +"""this module contains base classes for windmill integration + +:todo: + + * import CubicWeb session object into windmill scope to be able to run RQL + * manage command line option from pytest to run specific use tests only +""" + import os, os.path as osp +import sys +import unittest # imported by default to simplify further import statements from logilab.common.testlib import unittest_main -from windmill.authoring import unit from windmill.dep import functest from cubicweb.devtools.httptest import CubicWebServerTC +# Excerpt from :ref:`windmill.authoring.unit` class UnitTestReporter(functest.reports.FunctestReportInterface): def summary(self, test_list, totals_dict, stdout_capture): self.test_list = test_list @@ -35,14 +44,33 @@ unittestreporter = UnitTestReporter() functest.reports.register_reporter(unittestreporter) -class CubicWebWindmillUseCase(CubicWebServerTC, unit.WindmillUnitTestCase): +class WindmillUnitTestCase(unittest.TestCase): + def setUp(self): + import windmill + windmill.stdout, windmill.stdin = sys.stdout, sys.stdin + from windmill.bin.admin_lib import configure_global_settings, setup + configure_global_settings() + windmill.settings['TEST_URL'] = self.test_url + if hasattr(self,"windmill_settings"): + for (setting,value) in self.windmill_settings.iteritems(): + windmill.settings[setting] = value + self.windmill_shell_objects = setup() + + def tearDown(self): + from windmill.bin.admin_lib import teardown + teardown(self.windmill_shell_objects) + + +class CubicWebWindmillUseCase(CubicWebServerTC, WindmillUnitTestCase): """basic class for Windmill use case tests :param browser: browser identification string (firefox|ie|safari|chrome) (firefox by default) :param test_dir: testing file path or directory (./windmill by default) + :param edit_test: load and edit test for debugging (False by default) """ browser = 'firefox' test_dir = osp.join(os.getcwd(), 'windmill') + edit_test = "-i" in sys.argv # detection for pytest invocation def setUp(self): # reduce log output @@ -53,18 +81,33 @@ # Start CubicWeb session before running the server to populate self.vreg CubicWebServerTC.setUp(self) assert os.path.exists(self.test_dir), "provide 'test_dir' as the given test file/dir" - unit.WindmillUnitTestCase.setUp(self) + WindmillUnitTestCase.setUp(self) def tearDown(self): - unit.WindmillUnitTestCase.tearDown(self) + WindmillUnitTestCase.tearDown(self) CubicWebServerTC.tearDown(self) def testWindmill(self): + if self.edit_test: + # see windmill.bin.admin_options.Firebug + import windmill + windmill.settings['INSTALL_FIREBUG'] = 'firebug' + self.windmill_shell_objects['start_' + self.browser]() - self.windmill_shell_objects['do_test'](self.test_dir, threaded=False) + self.windmill_shell_objects['do_test'](self.test_dir, + load=self.edit_test, + threaded=False) + # set a breakpoint to be able to debug windmill test + if self.edit_test: + import pdb; pdb.set_trace() + return + for test in unittestreporter.test_list: + msg = "" self._testMethodDoc = getattr(test, "__doc__", None) self._testMethodName = test.__name__ - self.assertEquals(test.result, True) + # try to display a better message in case of failure + if hasattr(test, "tb"): + msg = '\n'.join(test.tb) + self.assertEquals(test.result, True, msg=msg) - diff -r 97c55baefa0c -r b9c612274af7 doc/book/en/tutorials/tools/windmill.rst --- a/doc/book/en/tutorials/tools/windmill.rst Mon Jul 19 15:37:02 2010 +0200 +++ b/doc/book/en/tutorials/tools/windmill.rst Mon Jul 19 16:46:42 2010 +0200 @@ -82,11 +82,11 @@ If you are using firefox as client, consider the "firebug" option. -You can refine the test by the *loadtest* windmill option: +If you have a running instance, you can refine the test by the *loadtest* windmill option: windmill -m firebug loadtest= -But use the internal windmill shell to explore available commands: +Or use the internal windmill shell to explore available commands: windmill -m firebug shell @@ -106,6 +106,10 @@ 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`. +To run your test series:: + + % pytest test/test_windmill.py + 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. @@ -114,6 +118,24 @@ parameters and :class:`cubicweb.devtools.cwwindmill.CubicWebWindmillUseCase` for Windmill configuration. +For instance, CubicWeb framework windmill tests can be manually run by:: + + % pytest web/test/test_windmill.py + +Edit your tests +--------------- + +You can toggle the `edit_test` variable to enable test edition. + +But if you are using `pytest` as test runner, use the `-i` option directly. +The test series will be loaded and you can run assertions step-by-step:: + + % pytest -i test/test_windmill.py + +In this case, the `firebug` extension will be loaded automatically for you. + +Afterwards, don't forget to save your edited test into the right file (no autosave feature). + Best practises -------------- @@ -127,14 +149,6 @@ 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 =========== diff -r 97c55baefa0c -r b9c612274af7 web/test/test_windmill.py --- a/web/test/test_windmill.py Mon Jul 19 15:37:02 2010 +0200 +++ b/web/test/test_windmill.py Mon Jul 19 16:46:42 2010 +0200 @@ -1,3 +1,5 @@ +import os, os.path as osp + from cubicweb.devtools import cwwindmill @@ -14,15 +16,19 @@ The first port found as available in `ports_range` will be used to launch the test server + Instead of toggle `edit_test` value, try `pytest -i` + 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) + :param edit_test: load and edit test for debugging (False by default) """ #ports_range = range(7000, 8000) anonymous_logged = False #browser = 'firefox' #test_dir = osp.join(os.getcwd(), 'windmill') + #edit_test = False # If you prefer, you can put here the use cases recorded by windmill GUI # (services transformer) instead of the windmill sub-directory diff -r 97c55baefa0c -r b9c612274af7 web/test/windmill/test_edit_relation.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/web/test/windmill/test_edit_relation.py Mon Jul 19 16:46:42 2010 +0200 @@ -0,0 +1,82 @@ +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_edit_relation(): + client = WindmillTestClient(__name__) + + client.open(url=u'/logout') + 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.open(url=u'/add/Folder') + client.waits.forPageLoad(timeout=u'20000') + client.waits.forElement(timeout=u'8000', id=u'name-subject:A') + client.click(id=u'name-subject:A') + client.type(text=u'folder1', id=u'name-subject:A') + client.click(value=u'button_ok') + client.waits.forPageLoad(timeout=u'20000') + client.waits.forElement(link=u'add add Folder filed_under Folder object', timeout=u'8000') + client.click(link=u'add add Folder filed_under Folder object') + client.waits.forPageLoad(timeout=u'20000') + client.waits.forElement(timeout=u'8000', id=u'name-subject:A') + client.click(id=u'name-subject:A') + client.type(text=u'subfolder1', id=u'name-subject:A') + client.click(value=u'button_ok') + client.waits.forPageLoad(timeout=u'20000') + client.waits.forElement(link=u'more actions', timeout=u'8000') + client.click(link=u'more actions') + client.click(link=u'copy') + client.waits.forPageLoad(timeout=u'20000') + client.type(text=u'folder2', id=u'name-subject:A') + client.click(value=u'button_ok') + client.waits.forPageLoad(timeout=u'20000') + client.waits.forElement(link=u'modify', timeout=u'8000') + client.click(link=u'modify') + client.waits.forPageLoad(timeout=u'20000') + client.waits.forElement(timeout=u'8000', id=u'footer') + client.click(link=u'x') + client.click(value=u'button_ok') + client.waits.forPageLoad(timeout=u'20000') + client.waits.forElement(link=u'add add Folder filed_under Folder object', timeout=u'8000') + client.click(link=u'add add Folder filed_under Folder object') + client.waits.forPageLoad(timeout=u'20000') + client.type(text=u'subfolder2', id=u'name-subject:A') + client.click(value=u'button_ok') + client.waits.forPageLoad(timeout=u'20000') + client.waits.forElement(link=u'subfolder2', timeout=u'8000') + client.click(link=u'subfolder2') + client.waits.forPageLoad(timeout=u'20000') + client.waits.forElement(link=u'modify', timeout=u'8000') + client.click(link=u'modify') + client.waits.forPageLoad(timeout=u'20000') + client.waits.forElement(timeout=u'8000', id=u'footer') + client.click(link=u'x') + client.select(xpath=u'//select', index=u'1') + #client.execJQuery(jquery=u'("select").trigger(\'change\')') # BUGGY freeze UI.. + client.execJS(js=u'$("select").trigger(\'change\')') + client.waits.sleep(milliseconds=u'2000') + client.select(jquery=u'(\'select:contains("Search")\')[0]', option=u'Search for folder') + client.waits.forPageLoad(timeout=u'20000') + client.click(link=u'folder1') + client.waits.forPageLoad(timeout=u'20000') + client.waits.forElement(timeout=u'8000', value=u'button_ok') + client.click(value=u'button_ok') + client.waits.forPageLoad(timeout=u'20000') + client.asserts.assertText(xpath=u'//h1', validator=u'subfolder2') + client.waits.forElement(link=u'folder_plural', timeout=u'8000') + client.click(link=u'folder_plural') + client.waits.forPageLoad(timeout=u'20000') + client.asserts.assertText(jquery=u"('#contentmain div a')[0]", validator=u'folder1') + client.asserts.assertText(jquery=u"('#contentmain div a')[1]", validator=u'folder2') + client.asserts.assertText(jquery=u"('#contentmain div a')[2]", validator=u'subfolder1') + client.asserts.assertText(jquery=u"('#contentmain div a')[3]", validator=u'subfolder2') + client.click(link=u'subfolder2') + client.click(link=u'modify') + client.click(link=u'folder1')