← Back to team overview

launchpad-reviewers team mailing list archive

[Merge] lp:~wallyworld/launchpad/windmill-setup-improvement into lp:launchpad

 

Ian Booth has proposed merging lp:~wallyworld/launchpad/windmill-setup-improvement into lp:launchpad with lp:~wallyworld/launchpad/show-ajax-notifications as a prerequisite.

Requested reviews:
  Launchpad code reviewers (launchpad-reviewers)

For more details, see:
https://code.launchpad.net/~wallyworld/launchpad/windmill-setup-improvement/+merge/55286

The work done in this branch removes a less than ideal use of some executed javascript to implement login functionality in Windmill tests. This was done to remove one incompatibility stopping the Windmill tests working with Firefox 4. But it's also a good change regardless because it results in the new getClientFor() API being uniformly used to start the test - ie opens the page and logs in.

== Implementation ==

The LaunchpadUser object provided an ensure_login() method which assumed a URL had already been loaded. This method attempted to figure out this URL, log in, and then return to the URL again. However, this is all backwards. This method was usually called to set up a test and the URL was known to the caller but not passed into the method. The getClientFor() method is designed to do things "The Right Way" and is a better choice.

Along the way, other yak shaving was done. Old code was deleted, a new getClientForPerson() method was introduced, some xpath replaced by jquery etc. A couple of failing tests were also fixed.

It's a large diff but the changes all follow a similar pattern and there's a lot of deleted code.

== Tests ==

The complete Windmill test suite
-- 
https://code.launchpad.net/~wallyworld/launchpad/windmill-setup-improvement/+merge/55286
Your team Launchpad code reviewers is requested to review the proposed merge of lp:~wallyworld/launchpad/windmill-setup-improvement into lp:launchpad.
=== modified file 'lib/canonical/launchpad/components/apihelpers.py'
--- lib/canonical/launchpad/components/apihelpers.py	2011-03-28 05:34:07 +0000
+++ lib/canonical/launchpad/components/apihelpers.py	2011-03-30 06:39:14 +0000
@@ -20,6 +20,7 @@
     'patch_choice_vocabulary',
     'patch_collection_property',
     'patch_collection_return_type',
+    'patch_entry_explicit_version',
     'patch_plain_parameter_type',
     'patch_list_parameter_type',
     'patch_operations_explicit_version',

=== modified file 'lib/lp/bugs/windmill/tests/test_bug_also_affects_new_upstream.py'
--- lib/lp/bugs/windmill/tests/test_bug_also_affects_new_upstream.py	2011-02-10 04:00:00 +0000
+++ lib/lp/bugs/windmill/tests/test_bug_also_affects_new_upstream.py	2011-03-30 06:39:14 +0000
@@ -1,8 +1,6 @@
 # Copyright 2009 Canonical Ltd.  This software is licensed under the
 # GNU Affero General Public License version 3 (see the file LICENSE).
 
-import unittest
-
 from lp.bugs.windmill.testing import BugsWindmillLayer
 from lp.testing import WindmillTestCase
 from lp.testing.windmill import (
@@ -22,7 +20,8 @@
 
     def setUp(self):
         WindmillTestCase.setUp(self)
-        lpuser.SAMPLE_PERSON.ensure_login(self.client)
+        self.client, start_url = self.getClientFor(
+            '/', user=lpuser.SAMPLE_PERSON)
         self.choose_affected_url = (
                             '%s/tomcat/+bug/3/+choose-affected-product'
                             % BugsWindmillLayer.base_url)
@@ -59,7 +58,3 @@
         search_picker_widget(client, 'nonexistant')
         client.waits.forElement(
             link=u'Register it', timeout=constants.FOR_ELEMENT)
-
-
-def test_suite():
-    return unittest.TestLoader().loadTestsFromName(__name__)

=== modified file 'lib/lp/bugs/windmill/tests/test_bug_commenting.py'
--- lib/lp/bugs/windmill/tests/test_bug_commenting.py	2011-02-10 04:00:00 +0000
+++ lib/lp/bugs/windmill/tests/test_bug_commenting.py	2011-03-30 06:39:14 +0000
@@ -6,7 +6,6 @@
 __metaclass__ = type
 __all__ = []
 
-import unittest
 from uuid import uuid1
 
 from lp.bugs.windmill.testing import BugsWindmillLayer
@@ -14,13 +13,6 @@
 from lp.testing.windmill import lpuser
 
 
-WAIT_PAGELOAD = u'30000'
-WAIT_ELEMENT_COMPLETE = u'30000'
-WAIT_CHECK_CHANGE = u'1000'
-ADD_COMMENT_BUTTON = (
-    u'//input[@id="field.actions.save" and contains(@class, "button")]')
-
-
 class TestBugCommenting(WindmillTestCase):
 
     layer = BugsWindmillLayer
@@ -28,22 +20,14 @@
 
     def test_bug_commenting(self):
         """Test commenting on bugs."""
-        client = self.client
-        lpuser.NO_PRIV.ensure_login(client)
-
-        client.open(url='%s/bugs/1' % BugsWindmillLayer.base_url)
-        client.waits.forPageLoad(timeout=WAIT_PAGELOAD)
-        client.waits.forElement(xpath=ADD_COMMENT_BUTTON)
+        client, start_url = self.getClientFor('/bugs/1', user=lpuser.NO_PRIV)
+        client.waits.forElement(jquery=u"('input#field\\.actions\\.save')")
 
         # Generate a unique piece of text, so we can run the test multiple
         # times, without resetting the db.
         new_comment_text = str(uuid1())
         client.type(text=new_comment_text, id="field.comment")
-        client.click(xpath=ADD_COMMENT_BUTTON)
+        client.click(jquery=u"('input[id=\"field\\.actions\\.save\"]')[0]")
         client.waits.forElement(
-            xpath=u'//div[@class="bug-comment"]/p[contains(., "%s")]' % (
-                new_comment_text))
-
-
-def test_suite():
-    return unittest.TestLoader().loadTestsFromName(__name__)
+            jquery=u'("div.bug-comment p:contains(\'%s\')")' %
+                new_comment_text)

=== modified file 'lib/lp/bugs/windmill/tests/test_bug_inline_subscriber.py'
--- lib/lp/bugs/windmill/tests/test_bug_inline_subscriber.py	2011-02-10 04:00:00 +0000
+++ lib/lp/bugs/windmill/tests/test_bug_inline_subscriber.py	2011-03-30 06:39:14 +0000
@@ -29,13 +29,8 @@
         This test makes sure that subscribing and unsubscribing
         from a bug works inline on a bug page.
         """
-        client = self.client
-
-        bug_url = u'%s/bugs/%%s' % BugsWindmillLayer.base_url
-        # Open a bug page and wait for it to finish loading.
-        client.open(url=bug_url % 11)
-        client.waits.forPageLoad(timeout=PAGE_LOAD)
-        lpuser.SAMPLE_PERSON.ensure_login(client)
+        client, start_url = self.getClientFor('/bugs/11',
+            user=lpuser.SAMPLE_PERSON)
 
         # Ensure the subscriber's portlet has finished loading.
         client.waits.forElement(
@@ -125,8 +120,8 @@
 
         # Login Foo Bar who is a member of Ubuntu Team.
         # After login, wait for the page load and subscribers portlet.
-        lpuser.FOO_BAR.ensure_login(client)
-        client.waits.forPageLoad(timeout=PAGE_LOAD)
+        client, start_url = self.getClientFor('/bugs/11',
+            user=lpuser.FOO_BAR)
         client.waits.forElement(
             id=u'subscribers-links', timeout=FOR_ELEMENT)
 
@@ -141,6 +136,8 @@
             xpath=SUBSCRIPTION_LINK,
             validator=u'className|remove')
 
+        bug_url = u'%s/bugs/%%s' % BugsWindmillLayer.base_url
+
         # Test unsubscribing via the remove icon for duplicates.
         # First, go to bug 6 and subscribe.
         client.open(url=bug_url % 6)
@@ -176,10 +173,9 @@
         #
         # First test case, ensure unsubscribing works when
         # dealing with a duplicate and an indirect subscription.
-        lpuser.SAMPLE_PERSON.ensure_login(client)
         # Go to bug 6, the dupe, and subscribe.
-        client.open(url=bug_url % 6)
-        client.waits.forPageLoad(timeout=PAGE_LOAD)
+        client, start_url = self.getClientFor('/bugs/6',
+            user=lpuser.SAMPLE_PERSON)
         client.waits.forElement(
             id=u'subscribers-links', timeout=FOR_ELEMENT)
         client.click(xpath=SUBSCRIPTION_LINK)

=== modified file 'lib/lp/bugs/windmill/tests/test_bug_me_too.py'
--- lib/lp/bugs/windmill/tests/test_bug_me_too.py	2011-02-10 04:00:00 +0000
+++ lib/lp/bugs/windmill/tests/test_bug_me_too.py	2011-03-30 06:39:14 +0000
@@ -53,13 +53,11 @@
         This test ensures that, with Javascript enabled, the "me too"
         status can be edited in-page.
         """
-        client = self.client
 
         # Open bug 11 and wait for it to finish loading.
-        client.open(
-            url=u'%s/jokosher/+bug/11/+index' % BugsWindmillLayer.base_url)
-        client.waits.forPageLoad(timeout=constants.PAGE_LOAD)
-        lpuser.SAMPLE_PERSON.ensure_login(client)
+        client, start_url = self.getClientFor(
+            '/jokosher/+bug/11', user=lpuser.SAMPLE_PERSON,
+            view_name='+index')
 
         # Ensure the link for "Does this bug affect you?" is setup.
         client.waits.forElement(

=== modified file 'lib/lp/bugs/windmill/tests/test_bug_privacy_settings.py'
--- lib/lp/bugs/windmill/tests/test_bug_privacy_settings.py	2011-02-10 04:00:00 +0000
+++ lib/lp/bugs/windmill/tests/test_bug_privacy_settings.py	2011-03-30 06:39:14 +0000
@@ -1,8 +1,6 @@
 # Copyright 2010 Canonical Ltd.  This software is licensed under the
 # GNU Affero General Public License version 3 (see the file LICENSE).
 
-import unittest
-
 from lp.bugs.windmill.testing import BugsWindmillLayer
 from lp.testing import WindmillTestCase
 from lp.testing.windmill import (
@@ -47,14 +45,10 @@
         is public[private]" on a bug page uses the formoverlay to update the
         flags "private" and "security vulnerability".
          """
-        client = self.client
 
-        bug_url = u'%s/bugs/15' % BugsWindmillLayer.base_url
         # Open a bug page and wait for it to finish loading.
-        client.open(url=bug_url)
-        client.waits.forPageLoad(timeout=constants.PAGE_LOAD)
-        lpuser.SAMPLE_PERSON.ensure_login(client)
-
+        client, start_url = self.getClientFor(
+            '/bugs/15', user=lpuser.SAMPLE_PERSON)
         client.waits.forElement(
             xpath=MAIN_FORM_ELEMENT, timeout=constants.FOR_ELEMENT)
 
@@ -99,7 +93,7 @@
         # we get the same text in the HTML data sent by the server,
         # so that we can be sure that the security settings are correctly
         # updated.
-        client.open(url=bug_url)
+        client.open(url=start_url)
         client.waits.forPageLoad(timeout=constants.PAGE_LOAD)
         client.waits.forElement(
             xpath=MAIN_FORM_ELEMENT, timeout=constants.FOR_ELEMENT)
@@ -137,7 +131,7 @@
         client.asserts.assertChecked(id=FIELD_SECURITY_RELATED)
 
         # When we reload the page, we get the same texts.
-        client.open(url=bug_url)
+        client.open(url=start_url)
         client.waits.forPageLoad(timeout=constants.PAGE_LOAD)
         client.waits.forElement(
             xpath=MAIN_FORM_ELEMENT, timeout=constants.FOR_ELEMENT)
@@ -157,7 +151,7 @@
 
         # When we reload the page, the <div> for the security message
         # does not exist either.
-        client.open(url=bug_url)
+        client.open(url=start_url)
         client.waits.forPageLoad(timeout=constants.PAGE_LOAD)
         client.waits.forElement(
             xpath=MAIN_FORM_ELEMENT, timeout=constants.FOR_ELEMENT)
@@ -175,7 +169,3 @@
         client.click(xpath=CANCEL_BUTTON)
         client.asserts.assertElemJS(
             xpath=MAIN_FORM_ELEMENT, js=FORM_NOT_VISIBLE)
-
-
-def test_suite():
-    return unittest.TestLoader().loadTestsFromName(__name__)

=== modified file 'lib/lp/bugs/windmill/tests/test_bug_tags_entry.py'
--- lib/lp/bugs/windmill/tests/test_bug_tags_entry.py	2011-02-10 04:00:00 +0000
+++ lib/lp/bugs/windmill/tests/test_bug_tags_entry.py	2011-03-30 06:39:14 +0000
@@ -6,8 +6,6 @@
 __metaclass__ = type
 __all__ = []
 
-import unittest
-
 import transaction
 from zope.security.proxy import removeSecurityProxy
 
@@ -27,7 +25,6 @@
 
     def test_bug_tags_entry(self):
         """Test bug tags inline, auto-completing UI."""
-        client = self.client
 
         # First, we add some official tags to test with
 
@@ -36,16 +33,12 @@
             u'eenie', u'meenie', u'meinie', u'moe']
         bug = self.factory.makeBug(product=product)
         removeSecurityProxy(bug).tags = ['unofficial-tag']
-        bug_url = canonical_url(bug)
         transaction.commit()
 
 
         # Now let's tag a bug using the auto-complete widget
 
-        client.open(url=bug_url)
-        client.waits.forPageLoad(timeout=constants.PAGE_LOAD)
-        lpuser.FOO_BAR.ensure_login(client)
-        client.waits.sleep(milliseconds=constants.SLEEP)
+        client, start_url = self.getClientFor(bug, user=lpuser.FOO_BAR)
 
         # XXX intellectronica 2009-05-26:
         # We (almost) consistently get an error on the following line
@@ -67,15 +60,9 @@
 
         # Test that anonymous users are prompted to log in.
 
-        lpuser.ANONYMOUS.ensure_login(client)
-        client.open(url=bug_url)
-        client.waits.forPageLoad(timeout=constants.PAGE_LOAD)
+        client, start_url = self.getClientForAnomymous(bug)
         client.waits.sleep(milliseconds=constants.SLEEP)
         client.click(id=u'edit-tags-trigger')
         client.waits.forPageLoad(timeout=constants.PAGE_LOAD)
         client.asserts.assertJS(
             js=u'window.location.href.indexOf("+openid") > 0')
-
-
-def test_suite():
-    return unittest.TestLoader().loadTestsFromName(__name__)

=== modified file 'lib/lp/bugs/windmill/tests/test_filebug_dupe_finder.py'
--- lib/lp/bugs/windmill/tests/test_filebug_dupe_finder.py	2011-02-11 21:41:34 +0000
+++ lib/lp/bugs/windmill/tests/test_filebug_dupe_finder.py	2011-03-30 06:39:14 +0000
@@ -1,8 +1,6 @@
 # Copyright 2009 Canonical Ltd.  This software is licensed under the
 # GNU Affero General Public License version 3 (see the file LICENSE).
 
-import unittest
-
 from lp.bugs.windmill.testing import BugsWindmillLayer
 from lp.testing import WindmillTestCase
 from lp.testing.windmill import (
@@ -41,12 +39,10 @@
         duplicates for a bug, with an expander that allows the user to view
         more information if they wish.
         """
-        client = self.client
-        lpuser.SAMPLE_PERSON.ensure_login(client)
 
         # Go to the +filebug page for Firefox
-        client.open(url=u'%s/firefox/+filebug' % BugsWindmillLayer.base_url)
-        client.waits.forPageLoad(timeout=constants.PAGE_LOAD)
+        client, start_url = self.getClientFor(
+            '/firefox/+filebug', user=lpuser.SAMPLE_PERSON)
 
         # Ensure the "search" field has finished loading, then enter a simple
         # search and hit search.
@@ -117,7 +113,3 @@
         client.asserts.assertText(
             xpath=u'//div[@class="message"]',
             validator="Provide details about the issue.")
-
-
-def test_suite():
-    return unittest.TestLoader().loadTestsFromName(__name__)

=== modified file 'lib/lp/bugs/windmill/tests/test_filebug_extra_options.py'
--- lib/lp/bugs/windmill/tests/test_filebug_extra_options.py	2011-02-10 04:00:00 +0000
+++ lib/lp/bugs/windmill/tests/test_filebug_extra_options.py	2011-03-30 06:39:14 +0000
@@ -1,8 +1,6 @@
 # Copyright 2009 Canonical Ltd.  This software is licensed under the
 # GNU Affero General Public License version 3 (see the file LICENSE).
 
-import unittest
-
 from lp.bugs.windmill.testing import BugsWindmillLayer
 from lp.testing import WindmillTestCase
 from lp.testing.windmill import (
@@ -22,12 +20,10 @@
         This test ensures that, with Javascript enabled, the extra options
         expander starts closed, and contains several fields when opened.
         """
-        client = self.client
 
         # Open a +filebug page and wait for it to finish loading.
-        client.open(url=u'%s/firefox/+filebug' % BugsWindmillLayer.base_url)
-        client.waits.forPageLoad(timeout=constants.PAGE_LOAD)
-        lpuser.SAMPLE_PERSON.ensure_login(client)
+        client, start_url = self.getClientFor(
+            '/firefox/+filebug', user=lpuser.SAMPLE_PERSON)
 
         # Search for a possible duplicate.
         client.waits.forElement(
@@ -61,7 +57,3 @@
 
     # The collapsible area is expanded and does display.
     client.asserts.assertNode(xpath=form_opened)
-
-
-def test_suite():
-    return unittest.TestLoader().loadTestsFromName(__name__)

=== modified file 'lib/lp/bugs/windmill/tests/test_mark_duplicate.py'
--- lib/lp/bugs/windmill/tests/test_mark_duplicate.py	2011-02-10 04:00:00 +0000
+++ lib/lp/bugs/windmill/tests/test_mark_duplicate.py	2011-03-30 06:39:14 +0000
@@ -6,8 +6,6 @@
 __metaclass__ = type
 __all__ = []
 
-import unittest
-
 from lp.bugs.windmill.testing import BugsWindmillLayer
 from lp.testing import WindmillTestCase
 from lp.testing.windmill import (
@@ -38,13 +36,10 @@
         link on a bug page uses the formoverlay to update the duplicateof
         field via the api.
         """
-        client = self.client
 
         # Open a bug page and wait for it to finish loading
-        client.open(url=u'%s/bugs/15' % BugsWindmillLayer.base_url)
-        client.waits.forPageLoad(timeout=constants.PAGE_LOAD)
-        lpuser.SAMPLE_PERSON.ensure_login(client)
-
+        client, start_url = self.getClientFor(
+            '/bugs/15', user=lpuser.SAMPLE_PERSON)
         client.waits.forElement(
             xpath=MAIN_FORM_ELEMENT, timeout=constants.FOR_ELEMENT)
 
@@ -133,7 +128,7 @@
             timeout=constants.FOR_ELEMENT)
 
         # When we go back to the page for the duplicate bug...
-        client.open(url=u'%s/bugs/15' % BugsWindmillLayer.base_url)
+        client.open(url=start_url)
         client.waits.forPageLoad(timeout=constants.PAGE_LOAD)
         client.waits.forElement(
             xpath=MAIN_FORM_ELEMENT, timeout=constants.FOR_ELEMENT)
@@ -153,6 +148,3 @@
 
         # ...the warning is gone.
         client.asserts.assertNotNode(id='warning-comment-on-duplicate')
-
-def test_suite():
-    return unittest.TestLoader().loadTestsFromName(__name__)

=== modified file 'lib/lp/bugs/windmill/tests/test_official_bug_tags_management.py'
--- lib/lp/bugs/windmill/tests/test_official_bug_tags_management.py	2011-02-10 04:00:00 +0000
+++ lib/lp/bugs/windmill/tests/test_official_bug_tags_management.py	2011-03-30 06:39:14 +0000
@@ -6,8 +6,6 @@
 __metaclass__ = type
 __all__ = []
 
-import unittest
-
 from lp.bugs.windmill.testing import BugsWindmillLayer
 from lp.testing import WindmillTestCase
 from lp.testing.windmill import (
@@ -27,9 +25,7 @@
 
     # Firefox is a product - an official bug tags target.
 
-        client.open(url='%s/firefox' % BugsWindmillLayer.base_url)
-        client.waits.forPageLoad(timeout=constants.PAGE_LOAD)
-        lpuser.FOO_BAR.ensure_login(client)
+        client, start_url = self.getClientFor('/firefox', user=lpuser.FOO_BAR)
 
     # foobar has the permission to edit the official bug tags for firefox.
 
@@ -214,6 +210,3 @@
         client.click(id=u'remove-official-tags')
         client.click(id=u'save-button')
         client.waits.forPageLoad(timeout=constants.PAGE_LOAD)
-
-def test_suite():
-    return unittest.TestLoader().loadTestsFromName(__name__)

=== modified file 'lib/lp/code/windmill/tests/test_branch_bugspeclinks.py'
--- lib/lp/code/windmill/tests/test_branch_bugspeclinks.py	2011-02-10 04:00:00 +0000
+++ lib/lp/code/windmill/tests/test_branch_bugspeclinks.py	2011-03-30 06:39:14 +0000
@@ -6,10 +6,6 @@
 __metaclass__ = type
 __all__ = []
 
-import unittest
-
-import windmill
-
 from lp.code.windmill.testing import CodeWindmillLayer
 from lp.testing import WindmillTestCase
 from lp.testing.windmill import lpuser
@@ -38,13 +34,9 @@
 
     def test_inline_branch_bug_link_unlink(self):
         """Link a bug from the branch page."""
-        client = self.client
-
-        lpuser.FOO_BAR.ensure_login(client)
-
-        start_url = (
-            windmill.settings['TEST_URL'] + '~mark/firefox/release--0.9.1')
-        client.open(url=start_url)
+
+        client, start_url = self.getClientFor(
+            '/~mark/firefox/release--0.9.1', lpuser.FOO_BAR)
         client.waits.forElement(id=u'linkbug', timeout=u'10000')
 
         self.link_bug_and_assert_success(client, u'1')
@@ -59,7 +51,3 @@
         self.unlink_bug_and_assert_success(client, u'2')
         client.asserts.assertText(id=u'linkbug',
             validator=u'Link to a bug report')
-
-
-def test_suite():
-    return unittest.TestLoader().loadTestsFromName(__name__)

=== modified file 'lib/lp/code/windmill/tests/test_branch_popupdiff.py'
--- lib/lp/code/windmill/tests/test_branch_popupdiff.py	2011-02-10 04:00:00 +0000
+++ lib/lp/code/windmill/tests/test_branch_popupdiff.py	2011-03-30 06:39:14 +0000
@@ -18,9 +18,6 @@
     WindmillTestCase,
     )
 from lp.testing.windmill.constants import PAGE_LOAD
-from lp.testing.windmill.lpuser import (
-    login_person as windmill_login_person,
-    )
 
 
 POPUP_DIFF = (
@@ -123,14 +120,8 @@
         bug = self.factory.makeBug(product=objs['fooix'])
         transaction.commit()
 
-        # The `objs` used here hides the email, but that is no longer
-        # accessible.  We have to pass it in by hand.
-        windmill_login_person(
-            objs['eric'], "eric@xxxxxxxxxxx", "test", client)
-
-        start_url = (windmill.settings['TEST_URL'] + 'bugs/%d' % bug.id)
-        client.open(url=start_url)
-        client.waits.forPageLoad(timeout=PAGE_LOAD)
+        client, start_url = self.getClientForPerson(
+            '/bugs/%d' % bug.id, objs['eric'])
         # Sleep for a bit to make sure that the JS onload has had time to
         # execute.
         client.waits.sleep(milliseconds=JS_ONLOAD_EXECUTE_DELAY)

=== modified file 'lib/lp/code/windmill/tests/test_branch_status.py'
--- lib/lp/code/windmill/tests/test_branch_status.py	2011-03-07 03:20:44 +0000
+++ lib/lp/code/windmill/tests/test_branch_status.py	2011-03-30 06:39:14 +0000
@@ -31,8 +31,6 @@
         branch = self.factory.makeBranch(owner=eric)
         transaction.commit()
 
-        client = self.client
-
         client, start_url = self.getClientFor(branch, user=eric)
         # Click on the element containing the branch status.
         client.click(id=u'edit-lifecycle_status')

=== modified file 'lib/lp/code/windmill/tests/test_branch_subscriptions.py'
--- lib/lp/code/windmill/tests/test_branch_subscriptions.py	2011-02-10 04:00:00 +0000
+++ lib/lp/code/windmill/tests/test_branch_subscriptions.py	2011-03-30 06:39:14 +0000
@@ -6,8 +6,6 @@
 __metaclass__ = type
 __all__ = []
 
-import unittest
-
 import windmill
 
 from lp.code.windmill.testing import CodeWindmillLayer
@@ -24,12 +22,8 @@
     def test_branch_subscription_ajax_load(self):
         """Subscribe to a branch from the branch page."""
 
-        client = self.client
-
-        lpuser.FOO_BAR.ensure_login(client)
-
-        client.open(url=(
-            windmill.settings['TEST_URL'] + '~mark/firefox/release--0.9.1'))
+        client, start_url = self.getClientFor(
+            '/~mark/firefox/release--0.9.1', lpuser.FOO_BAR)
         client.waits.forElement(id=u'none-subscribers', timeout=u'10000')
         client.asserts.assertText(
             xpath=u'//a[@class="sprite add subscribe-self js-action"]',
@@ -60,18 +54,12 @@
     def test_team_edit_subscription_ajax_load(self):
         """Unsubscribe a team from the branch."""
 
-        client = self.client
-
-        lpuser.SAMPLE_PERSON.ensure_login(client)
-
-        client.open(url=''.join([
-            windmill.settings['TEST_URL'],
-            '~name12/landscape/feature-x/']))
-        client.waits.forPageLoad(timeout=u'10000')
-
+        client, start_url = self.getClientFor(
+            '/~name12/landscape/feature-x/', lpuser.SAMPLE_PERSON)
         client.waits.forElement(
             id=u'editsubscription-icon-landscape-developers',
             timeout=u'10000')
+
         client.asserts.assertText(id=u'subscriber-landscape-developers',
             validator=u'Landscape Developers')
         client.click(id=u'editsubscription-icon-landscape-developers')
@@ -82,7 +70,3 @@
         client.waits.forElement(id=u'none-subscribers', timeout=u'10000')
         client.asserts.assertText(id=u'none-subscribers',
             validator=u'No subscribers.')
-
-
-def test_suite():
-    return unittest.TestLoader().loadTestsFromName(__name__)

=== modified file 'lib/lp/code/windmill/tests/test_branchmergeproposal_commitmessage.py'
--- lib/lp/code/windmill/tests/test_branchmergeproposal_commitmessage.py	2011-02-10 04:00:00 +0000
+++ lib/lp/code/windmill/tests/test_branchmergeproposal_commitmessage.py	2011-03-30 06:39:14 +0000
@@ -6,11 +6,8 @@
 __metaclass__ = type
 __all__ = []
 
-import unittest
-
 import transaction
 
-from canonical.launchpad.webapp import canonical_url
 from lp.code.windmill.testing import CodeWindmillLayer
 from lp.testing import WindmillTestCase
 from lp.testing.windmill.constants import (
@@ -18,7 +15,6 @@
     PAGE_LOAD,
     SLEEP,
     )
-from lp.testing.windmill.lpuser import login_person
 
 
 EDIT_COMMIT_LINK = u'//a[contains(@href, "+edit-commit-message")]'
@@ -46,12 +42,7 @@
         bmp = self.factory.makeBranchMergeProposal(registrant=eric)
         transaction.commit()
 
-        client = self.client
-
-        login_person(eric, "eric@xxxxxxxxxxx", "test", client)
-
-        client.open(url=canonical_url(bmp))
-        client.waits.forPageLoad(timeout=PAGE_LOAD)
+        client, start_url = self.getClientForPerson(bmp, eric)
 
         # Click on the element containing the branch status.
         client.click(xpath=EDIT_COMMIT_LINK)
@@ -67,7 +58,7 @@
             xpath=COMMIT_MESSAGE_TEXT, validator=message)
 
         # Confirm that the change was saved.
-        client.open(url=canonical_url(bmp))
+        client.open(url=start_url)
         client.waits.forPageLoad(timeout=PAGE_LOAD)
         client.asserts.assertText(
             xpath=COMMIT_MESSAGE_TEXT, validator=message)
@@ -89,12 +80,7 @@
         merge_proposal = second_branch.addLandingTarget(mike, branch)
         transaction.commit()
 
-        client = self.client
-
-        merge_url = canonical_url(merge_proposal)
-        client.open(url=merge_url)
-        client.waits.forPageLoad(timeout=PAGE_LOAD)
-        login_person(mike, "mike@xxxxxxxxxxx", "test", client)
+        client, start_url = self.getClientForPerson(merge_proposal, mike)
 
         # Click on the element containing the branch status.
         client.waits.forElement(
@@ -116,7 +102,7 @@
             validator=u'5')
 
         # Reload the page and make sure the change sticks.
-        client.open(url=merge_url)
+        client.open(url=start_url)
         client.waits.forPageLoad(timeout=PAGE_LOAD)
         client.waits.forElement(
             xpath=u'//td[@id="branchmergeproposal-status-value"]/a',
@@ -124,7 +110,3 @@
         client.asserts.assertText(
             xpath=u'//td[@id="branchmergeproposal-status-value"]/a',
             validator=u'Approved')
-
-
-def test_suite():
-    return unittest.TestLoader().loadTestsFromName(__name__)

=== modified file 'lib/lp/code/windmill/tests/test_branchmergeproposal_review.py'
--- lib/lp/code/windmill/tests/test_branchmergeproposal_review.py	2011-02-10 04:00:00 +0000
+++ lib/lp/code/windmill/tests/test_branchmergeproposal_review.py	2011-03-30 06:39:14 +0000
@@ -5,11 +5,9 @@
 __metaclass__ = type
 __all__ = []
 
-import unittest
 from uuid import uuid1
 
 import transaction
-import windmill
 
 from canonical.launchpad.webapp import canonical_url
 from lp.code.windmill.testing import CodeWindmillLayer
@@ -42,14 +40,8 @@
     def test_inline_request_a_reviewer(self):
         """Request a review."""
 
-        client = self.client
-
-        lpuser.FOO_BAR.ensure_login(client)
-
-        client.open(url=''.join([
-            windmill.settings['TEST_URL'],
-            '~name12/gnome-terminal/klingon/']))
-        client.waits.forPageLoad(timeout=u'10000')
+        client, start_url = self.getClientFor(
+            '/~name12/gnome-terminal/klingon/', lpuser.FOO_BAR)
 
         link = u'//a[@class="menu-link-register_merge sprite add"]'
         client.waits.forElement(xpath=link, timeout=constants.FOR_ELEMENT)
@@ -102,8 +94,7 @@
 
     def test_merge_proposal_commenting(self):
         """Comment on a merge proposal."""
-        client = self.client
-        lpuser.NO_PRIV.ensure_login(client)
+        client, start_url = self.getClientFor('/', lpuser.NO_PRIV)
 
         proposal = self.factory.makeBranchMergeProposal()
         self.open_proposal_page(client, proposal)
@@ -121,8 +112,7 @@
 
     def test_merge_proposal_replying(self):
         """Reply to a review comment."""
-        client = self.client
-        lpuser.NO_PRIV.ensure_login(client)
+        client, start_url = self.getClientFor('/', lpuser.NO_PRIV)
         proposal = self.factory.makeBranchMergeProposal()
         login_person(proposal.registrant)
         proposal.createComment(proposal.registrant, 'hello', 'content')
@@ -141,9 +131,7 @@
 
     def test_merge_proposal_reviewing(self):
         """Comment on a merge proposal."""
-        client = self.client
-        lpuser.NO_PRIV.ensure_login(client)
-
+        client, start_url = self.getClientFor('/', lpuser.NO_PRIV)
         proposal = self.factory.makeBranchMergeProposal()
         self.open_proposal_page(client, proposal)
         client.waits.forElement(xpath=ADD_COMMENT_BUTTON)
@@ -153,7 +141,3 @@
         client.select(id=u'field.vote', val=u'APPROVE')
         client.click(xpath=ADD_COMMENT_BUTTON)
         client.waits.forElement(id=u'review-no-priv', timeout=u'40000')
-
-
-def test_suite():
-    return unittest.TestLoader().loadTestsFromName(__name__)

=== modified file 'lib/lp/code/windmill/tests/test_productseries_setbranch.py'
--- lib/lp/code/windmill/tests/test_productseries_setbranch.py	2011-02-10 04:00:00 +0000
+++ lib/lp/code/windmill/tests/test_productseries_setbranch.py	2011-03-30 06:39:14 +0000
@@ -6,11 +6,10 @@
 __metaclass__ = type
 __all__ = []
 
-import unittest
-
 from lp.code.windmill.testing import CodeWindmillLayer
 from lp.testing import WindmillTestCase
 from lp.testing.windmill import lpuser
+from lp.testing.windmill.constants import FOR_ELEMENT
 
 
 class TestProductSeriesSetbranch(WindmillTestCase):
@@ -23,10 +22,8 @@
         """Test productseries JS on /$projectseries/+setbranch page."""
 
         # Ensure we're logged in as 'foo bar'
-        user = lpuser.FOO_BAR
-        user.ensure_login(self.client)
-        self.client.open(
-            url=u'%s/firefox/trunk/+setbranch' % CodeWindmillLayer.base_url)
+        client, start_url = self.getClientFor(
+            '/firefox/trunk/+setbranch', user=lpuser.FOO_BAR)
 
         # To demonstrate the Javascript is loaded we simply need to see that
         # one of the controls is deactivated when the radio button selections
@@ -34,12 +31,12 @@
         # branch_location field should be enabled.  When any other radio
         # button is selected the branch_location field is disabled.
         self.client.waits.forElement(id=u'field.branch_type.link-lp-bzr',
-                                     timeout=u'20000')
+                                     timeout=FOR_ELEMENT)
 
         # Select Bazaar as the RCS type...
         self.client.click(id=u'field.branch_type.link-lp-bzr')
         self.client.waits.forElement(id=u'field.branch_location',
-                                     timeout=u'20000')
+                                     timeout=FOR_ELEMENT)
         # And the branch location is enabled.
         self.client.asserts.assertElemJS(id=u'field.branch_location',
                                          js='!element.disabled')
@@ -47,11 +44,8 @@
         # Select 'create new'...
         self.client.click(id=u'field.branch_type.create-new')
         self.client.waits.forElement(id=u'field.branch_location',
-                                     timeout=u'20000')
+                                     timeout=FOR_ELEMENT)
         # And the branch location is now disabled, proving that the javascript
         # controls have loaded and are functioning.
         self.client.asserts.assertElemJS(id=u'field.branch_location',
                                          js='element.disabled')
-
-def test_suite():
-    return unittest.TestLoader().loadTestsFromName(__name__)

=== modified file 'lib/lp/code/windmill/tests/test_recipe_request_build.py'
--- lib/lp/code/windmill/tests/test_recipe_request_build.py	2011-03-23 05:40:27 +0000
+++ lib/lp/code/windmill/tests/test_recipe_request_build.py	2011-03-30 06:39:14 +0000
@@ -10,13 +10,10 @@
 from zope.component import getUtility
 from zope.security.proxy import removeSecurityProxy
 
-from canonical.launchpad.webapp.publisher import canonical_url
 from lp.testing.windmill.constants import (
     FOR_ELEMENT,
-    PAGE_LOAD,
     SLEEP,
     )
-from lp.testing.windmill.lpuser import login_person
 from lp.app.browser.tales import PPAFormatterAPI
 from lp.code.windmill.testing import CodeWindmillLayer
 from lp.registry.interfaces.distribution import IDistributionSet
@@ -54,7 +51,10 @@
             ' Secret Squirrel changes.', branches=[cake_branch],
             daily_build_archive=self.ppa, build_daily=True, is_stale=True)
         transaction.commit()
-        login_person(self.chef, "chef@xxxxxxxxxxx", "test", self.client)
+        self.client, start_url = self.getClientForPerson(
+            self.recipe, self.chef)
+        self.client.waits.forElement(
+            id=u'request-builds', timeout=FOR_ELEMENT)
 
     def _check_build_renders(self, ppa):
         self.client.waits.forElement(
@@ -65,15 +65,10 @@
     def test_recipe_build_request(self):
         """Request a recipe build."""
 
-        client = self.client
-        client.open(url=canonical_url(self.recipe))
-        client.waits.forElement(
-            id=u'request-builds', timeout=PAGE_LOAD)
-
         # Request a new build.
-        client.click(id=u'request-builds')
-        client.waits.forElement(id=u'field.archive')
-        client.click(name=u'field.actions.request')
+        self.client.click(id=u'request-builds')
+        self.client.waits.forElement(id=u'field.archive')
+        self.client.click(name=u'field.actions.request')
 
         # Ensure it shows up.
         self._check_build_renders(self.ppa)
@@ -85,41 +80,36 @@
         should be hidden.
         """
 
-        client = self.client
-        client.open(url=canonical_url(self.recipe))
-        client.waits.forElement(
-            id=u'request-builds', timeout=PAGE_LOAD)
-
         # Request a new build.
-        client.click(id=u'request-builds')
-        client.waits.forElement(id=u'field.archive')
-        client.click(name=u'field.actions.request')
+        self.client.click(id=u'request-builds')
+        self.client.waits.forElement(id=u'field.archive')
+        self.client.click(name=u'field.actions.request')
 
         # Give the new build a chance to be queued.
-        client.waits.sleep(milliseconds=SLEEP)
+        self.client.waits.sleep(milliseconds=SLEEP)
 
         # And open the request form again.
-        client.click(id=u'request-builds')
-        client.waits.forElement(id=u'field.archive')
+        self.client.click(id=u'request-builds')
+        self.client.waits.forElement(id=u'field.archive')
 
         def check_build_pending(field_id, build_name):
-            client.asserts.assertTextIn(
-                jquery=u"('label[for=\"field.distros.%d\"]')[0]" % field_id,
-                validator=u'%s (build pending)' % build_name)
+            self.client.asserts.assertTextIn(
+                jquery=u"('label[for=\"field.distroseries.%d\"]')[0]"
+                % field_id, validator=u'%s (build pending)' % build_name)
 
         # We need just a little time for the ajax call to complete
-        client.waits.sleep(milliseconds=SLEEP)
+        self.client.waits.sleep(milliseconds=SLEEP)
 
         # Check that previous build is marked as pending
         check_build_pending(0, self.squirrel.displayname)
 
         # Now request builds for all the remaining distro series
-        client.click(id=u'field.distros.1')
-        client.click(id=u'field.distros.2')
-        client.click(name=u'field.actions.request')
+        self.client.click(id=u'field.distroseries.1')
+        self.client.click(id=u'field.distroseries.2')
+        self.client.click(name=u'field.actions.request')
 
         # Give the new builds a chance to be queued.
-        client.waits.sleep(milliseconds=SLEEP)
+        self.client.waits.sleep(milliseconds=SLEEP)
 
         distribution_set = getUtility(IDistributionSet)
         ubuntu_hoary = distribution_set.getByName('ubuntu').getSeries('hoary')
@@ -130,11 +120,11 @@
         self._check_build_renders(ubuntu_warty)
 
         # And open the request form again.
-        client.click(id=u'request-builds')
-        client.waits.forElement(id=u'field.archive')
+        self.client.click(id=u'request-builds')
+        self.client.waits.forElement(id=u'field.archive')
 
         # We need just a little time for the ajax call to complete
-        client.waits.sleep(milliseconds=SLEEP)
+        self.client.waits.sleep(milliseconds=SLEEP)
 
         # Check that previous builds are marked as pending
         check_build_pending(0, self.squirrel.displayname)
@@ -142,23 +132,18 @@
         check_build_pending(2, ubuntu_warty.displayname)
 
         # Check that the Request Builds button is hidden
-        client.asserts.assertNode(
+        self.client.asserts.assertNode(
             jquery=(u"('div.yui3-lazr-formoverlay-actions button[name=\""
                     "field.actions.request display=\"None\"\"]')"))
 
     def test_recipe_daily_build_request(self):
         """Request a recipe build."""
 
-        client = self.client
-        client.open(url=canonical_url(self.recipe))
-        client.waits.forElement(
-            id=u'request-daily-build', timeout=PAGE_LOAD)
-
         # Request a daily build.
-        client.click(id=u'request-daily-build')
+        self.client.click(id=u'request-daily-build')
 
         # Ensure it shows up.
-        client.waits.forElement(
+        self.client.waits.forElement(
             jquery=u"('tr.package-build a[href$=\"%s\"]')"
             % quote_jquery_expression(PPAFormatterAPI(self.ppa).url()),
             timeout=FOR_ELEMENT)

=== modified file 'lib/lp/registry/windmill/tests/test_add_bugtracker.py'
--- lib/lp/registry/windmill/tests/test_add_bugtracker.py	2011-02-10 04:00:00 +0000
+++ lib/lp/registry/windmill/tests/test_add_bugtracker.py	2011-03-30 06:39:14 +0000
@@ -6,79 +6,11 @@
 __metaclass__ = type
 __all__ = []
 
-import unittest
-
 from lp.registry.windmill.testing import RegistryWindmillLayer
 from lp.testing import WindmillTestCase
 from lp.testing.windmill import lpuser
 
 
-def test_inline_add_bugtracker(client, url, name=None, suite='bugtracker',
-                               user=lpuser.FOO_BAR):
-    """Test the form overlay for adding a bugtracker.
-
-    :param name: Name of the test.
-    :param url: Starting url.
-    :param suite: The suite in which this test is part of.
-    :param user: The user who should be logged in.
-    """
-    bugtracker_name = u'FOObar'
-    title = u'\xdf-title-%s' % bugtracker_name
-    location = u'http://example.com/%s' % bugtracker_name
-
-    user.ensure_login(client)
-    client.open(url=url)
-    client.waits.forPageLoad(timeout=u'20000')
-
-    client.waits.forElement(id=u'create-bugtracker-link')
-
-    # Click the "Create external bug tracker" link.
-    client.click(id=u'create-bugtracker-link')
-
-    # Submit bugtracker form.
-    client.waits.forElement(id=u'field.name')
-    client.type(id='field.name', text=bugtracker_name)
-    client.type(id='field.title', text=title)
-    client.type(id='field.baseurl', text=location)
-    client.click(id=u'formoverlay-add-bugtracker')
-
-    # Verify that the bugtracker name was entered in the text box.
-    client.waits.sleep(milliseconds='1000')
-    client.asserts.assertProperty(
-        id="field.bugtracker.bugtracker",
-        validator='value|%s' % bugtracker_name.lower())
-    client.asserts.assertChecked(id="field.bugtracker.2")
-
-    # Verify error message when trying to create a bugtracker with a
-    # conflicting name.
-    client.click(id=u'create-bugtracker-link')
-    client.waits.forElement(id=u'field.name')
-    client.type(id='field.name', text=bugtracker_name)
-    client.click(id=u'formoverlay-add-bugtracker')
-    client.waits.forElement(
-        xpath="//div[contains(@class, 'yui3-lazr-formoverlay-errors')]/ul/li")
-    client.asserts.assertTextIn(
-        classname='yui3-lazr-formoverlay-errors',
-        validator='name: %s is already in use' % bugtracker_name.lower())
-    client.click(classname='close-button')
-
-    # Configure bug tracker for the project.
-    client.click(id=u'field.actions.change')
-
-    # You should now be on the project index page.
-    client.waits.forElement(
-        xpath="//a[contains(@class, 'menu-link-configure_bugtracker')]")
-    client.click(
-        xpath="//a[contains(@class, 'menu-link-configure_bugtracker')]")
-
-    # Verify that the new bug tracker was configured for this project.
-    client.waits.forElement(id="field.bugtracker.bugtracker")
-    client.asserts.assertProperty(
-        id="field.bugtracker.bugtracker",
-        validator='value|%s' % bugtracker_name.lower())
-    client.asserts.assertChecked(id="field.bugtracker.2")
-
-
 class TestAddBugTracker(WindmillTestCase):
     """Test form overlay widget for adding a bug tracker."""
 
@@ -89,12 +21,63 @@
     suite_name = 'AddBugTracker'
 
     def test_adding_bugtracker_for_project(self):
-        test_inline_add_bugtracker(
-            self.client,
-            url='%s/bzr/+configure-bugtracker'
-                 % RegistryWindmillLayer.base_url,
-            name='test_inline_add_bugtracker_for_project')
-
-
-def test_suite():
-    return unittest.TestLoader().loadTestsFromName(__name__)
+        """Test the form overlay for adding a bugtracker.
+
+        :param name: Name of the test.
+        :param url: Starting url.
+        :param suite: The suite in which this test is part of.
+        :param user: The user who should be logged in.
+        """
+        bugtracker_name = u'FOObar'
+        title = u'\xdf-title-%s' % bugtracker_name
+        location = u'http://example.com/%s' % bugtracker_name
+
+        client, start_url = self.getClientFor(
+            '/bzr/+configure-bugtracker', user=lpuser.FOO_BAR)
+        client.waits.forElement(id=u'create-bugtracker-link')
+
+        # Click the "Create external bug tracker" link.
+        client.click(id=u'create-bugtracker-link')
+
+        # Submit bugtracker form.
+        client.waits.forElement(id=u'field.name')
+        client.type(id='field.name', text=bugtracker_name)
+        client.type(id='field.title', text=title)
+        client.type(id='field.baseurl', text=location)
+        client.click(id=u'formoverlay-add-bugtracker')
+
+        # Verify that the bugtracker name was entered in the text box.
+        client.waits.sleep(milliseconds='1000')
+        client.asserts.assertProperty(
+            id="field.bugtracker.bugtracker",
+            validator='value|%s' % bugtracker_name.lower())
+        client.asserts.assertChecked(id="field.bugtracker.2")
+
+        # Verify error message when trying to create a bugtracker with a
+        # conflicting name.
+        client.click(id=u'create-bugtracker-link')
+        client.waits.forElement(id=u'field.name')
+        client.type(id='field.name', text=bugtracker_name)
+        client.click(id=u'formoverlay-add-bugtracker')
+        client.waits.forElement(
+            xpath="//div[contains(@class, 'yui3-lazr-formoverlay-errors')]/ul/li")
+        client.asserts.assertTextIn(
+            classname='yui3-lazr-formoverlay-errors',
+            validator='name: %s is already in use' % bugtracker_name.lower())
+        client.click(classname='close-button')
+
+        # Configure bug tracker for the project.
+        client.click(id=u'field.actions.change')
+
+        # You should now be on the project index page.
+        client.waits.forElement(
+            xpath="//a[contains(@class, 'menu-link-configure_bugtracker')]")
+        client.click(
+            xpath="//a[contains(@class, 'menu-link-configure_bugtracker')]")
+
+        # Verify that the new bug tracker was configured for this project.
+        client.waits.forElement(id="field.bugtracker.bugtracker")
+        client.asserts.assertProperty(
+            id="field.bugtracker.bugtracker",
+            validator='value|%s' % bugtracker_name.lower())
+        client.asserts.assertChecked(id="field.bugtracker.2")

=== modified file 'lib/lp/registry/windmill/tests/test_add_milestone.py'
--- lib/lp/registry/windmill/tests/test_add_milestone.py	2011-02-10 04:00:00 +0000
+++ lib/lp/registry/windmill/tests/test_add_milestone.py	2011-03-30 06:39:14 +0000
@@ -6,75 +6,14 @@
 __metaclass__ = type
 __all__ = []
 
-import unittest
-
 from lp.registry.windmill.testing import RegistryWindmillLayer
 from lp.testing import WindmillTestCase
 from lp.testing.windmill import lpuser
-
-
-def test_inline_add_milestone(client, url, name=None, suite='milestone',
-                              user=lpuser.FOO_BAR):
-    """Test the form overlay for adding a milestone.
-
-    :param name: Name of the test.
-    :param url: Starting url.
-    :param suite: The suite in which this test is part of.
-    :param user: The user who should be logged in.
-    """
-    milestone_name = u'FOObar'
-    code_name = u'code-%s' % milestone_name
-
-    user.ensure_login(client)
-    client.open(url=url)
-    client.waits.forPageLoad(timeout=u'20000')
-
-    client.waits.forElement(
-        id=u'field.milestone_for_release', timeout=u'8000')
-
-    # Click the "Create milestone" link.
-    client.click(id=u'create-milestone-link')
-
-    # Submit milestone form.
-    client.waits.forElement(id=u'field.name', timeout=u'8000')
-    client.type(id='field.name', text=milestone_name)
-    client.type(id='field.code_name', text=code_name)
-    client.type(id='field.dateexpected', text=u"2004-01-05")
-    client.type(id='field.summary', text=u"foo bar")
-    client.click(id=u'formoverlay-add-milestone')
-
-    # Verify that the milestone was added to the SELECT input,
-    # and that it is now selected.
-    client.waits.sleep(milliseconds='1000')
-    client.asserts.assertSelected(id="field.milestone_for_release",
-                                  validator=milestone_name.lower())
-
-    # Verify error message when trying to create a milestone with a
-    # conflicting name.
-    client.click(id=u'create-milestone-link')
-    client.waits.forElement(id=u'field.name', timeout=u'8000')
-    client.type(id='field.name', text=milestone_name)
-    client.click(id=u'formoverlay-add-milestone')
-    client.waits.forElement(
-        xpath="//div[contains(@class, 'yui3-lazr-formoverlay-errors')]/ul/li")
-    client.asserts.assertTextIn(
-        classname='yui3-lazr-formoverlay-errors',
-        validator='The name %s is already used' % milestone_name.lower())
-    client.click(classname='close-button')
-
-    # Submit product release form.
-    client.select(id='field.milestone_for_release',
-                  val=milestone_name.lower())
-    client.type(id='field.datereleased', text=u"2004-02-22")
-    client.click(id=u'field.actions.create')
-    client.waits.forPageLoad(timeout=u'20000')
-
-    # Verify that the release was created.
-    client.waits.forElement(id="version")
-    client.asserts.assertText(
-        xpath="//*[@id='version']/dd", validator=milestone_name.lower())
-    client.asserts.assertText(
-        xpath="//*[@id='code-name']/dd", validator=code_name)
+from lp.testing.windmill.constants import (
+    FOR_ELEMENT,
+    PAGE_LOAD,
+    SLEEP,
+    )
 
 
 class TestAddMilestone(WindmillTestCase):
@@ -84,11 +23,61 @@
     suite_name = 'AddMilestone'
 
     def test_adding_milestone_on_addrelease_page(self):
-        test_inline_add_milestone(
-            self.client,
-            url='%s/bzr/trunk/+addrelease' % RegistryWindmillLayer.base_url,
-            name='test_inline_add_milestone_for_release')
-
-
-def test_suite():
-    return unittest.TestLoader().loadTestsFromName(__name__)
+        """Test the form overlay for adding a milestone.
+
+        :param name: Name of the test.
+        :param url: Starting url.
+        :param suite: The suite in which this test is part of.
+        :param user: The user who should be logged in.
+        """
+        milestone_name = u'FOObar'
+        code_name = u'code-%s' % milestone_name
+
+        client, start_url = self.getClientFor(
+            '/bzr/trunk/+addrelease', user=lpuser.FOO_BAR)
+        client.waits.forElement(
+            id=u'field.milestone_for_release', timeout=FOR_ELEMENT)
+
+        # Click the "Create milestone" link.
+        client.click(id=u'create-milestone-link')
+
+        # Submit milestone form.
+        client.waits.forElement(id=u'field.name', timeout=FOR_ELEMENT)
+        client.type(id='field.name', text=milestone_name)
+        client.type(id='field.code_name', text=code_name)
+        client.type(id='field.dateexpected', text=u"2004-01-05")
+        client.type(id='field.summary', text=u"foo bar")
+        client.click(id=u'formoverlay-add-milestone')
+
+        # Verify that the milestone was added to the SELECT input,
+        # and that it is now selected.
+        client.waits.sleep(milliseconds=SLEEP)
+        client.asserts.assertSelected(id="field.milestone_for_release",
+                                      validator=milestone_name.lower())
+
+        # Verify error message when trying to create a milestone with a
+        # conflicting name.
+        client.click(id=u'create-milestone-link')
+        client.waits.forElement(id=u'field.name', timeout=FOR_ELEMENT)
+        client.type(id='field.name', text=milestone_name)
+        client.click(id=u'formoverlay-add-milestone')
+        client.waits.forElement(
+            xpath="//div[contains(@class, 'yui3-lazr-formoverlay-errors')]/ul/li")
+        client.asserts.assertTextIn(
+            classname='yui3-lazr-formoverlay-errors',
+            validator='The name %s is already used' % milestone_name.lower())
+        client.click(classname='close-button')
+
+        # Submit product release form.
+        client.select(id='field.milestone_for_release',
+                      val=milestone_name.lower())
+        client.type(id='field.datereleased', text=u"2004-02-22")
+        client.click(id=u'field.actions.create')
+        client.waits.forPageLoad(timeout=PAGE_LOAD)
+
+        # Verify that the release was created.
+        client.waits.forElement(id="version")
+        client.asserts.assertText(
+            xpath="//*[@id='version']/dd", validator=milestone_name.lower())
+        client.asserts.assertText(
+            xpath="//*[@id='code-name']/dd", validator=code_name)

=== modified file 'lib/lp/registry/windmill/tests/test_datetime_picker.py'
--- lib/lp/registry/windmill/tests/test_datetime_picker.py	2011-02-10 04:00:00 +0000
+++ lib/lp/registry/windmill/tests/test_datetime_picker.py	2011-03-30 06:39:14 +0000
@@ -6,11 +6,10 @@
 __metaclass__ = type
 __all__ = []
 
-import unittest
-
 from lp.registry.windmill.testing import RegistryWindmillLayer
 from lp.testing import WindmillTestCase
 from lp.testing.windmill import lpuser
+from lp.testing.windmill.constants import FOR_ELEMENT
 
 
 class TestDateTimeCalendarWidget(WindmillTestCase):
@@ -27,14 +26,11 @@
         which opens up a calendar widget. The extra class 'withtime' is
         used to optionally include time fields.
         """
-        lpuser.SAMPLE_PERSON.ensure_login(self.client)
-
         # Open a new sprint page and wait for it to finish loading.
-        self.client.open(
-            url=u'%s/sprints/+new'
-                % self.layer.appserver_root_url('blueprints'))
-        self.client.waits.forPageLoad(timeout=u'20000')
-        self.client.waits.forElement(link=u'Choose...', timeout=u'8000')
+        client, start_url = self.getClientFor(
+            '/sprints/+new', user=lpuser.SAMPLE_PERSON,
+            base_url=self.layer.appserver_root_url('blueprints'))
+        self.client.waits.forElement(link=u'Choose...', timeout=FOR_ELEMENT)
 
         # Enter a date directly in the field first (which will ensure
         # the calendar widget opens with this date.)
@@ -70,7 +66,3 @@
                    u"/div[2]/button"))
         self.client.asserts.assertValue(
             validator=u'2009-06-09 10:30', id=u'field.time_starts')
-
-
-def test_suite():
-    return unittest.TestLoader().loadTestsFromName(__name__)

=== modified file 'lib/lp/registry/windmill/tests/test_distroseriesdifference_expander.py'
--- lib/lp/registry/windmill/tests/test_distroseriesdifference_expander.py	2011-02-10 04:00:00 +0000
+++ lib/lp/registry/windmill/tests/test_distroseriesdifference_expander.py	2011-03-30 06:39:14 +0000
@@ -36,21 +36,18 @@
                 derived='1.15-2ubuntu1derilucid2', parent='1.17-1'))
         transaction.commit()
 
-        self.package_diffs_url = (
-            canonical_url(self.diff.derived_series) + '/+localpackagediffs')
-
     def test_diff_extra_details_blacklisting(self):
         """A successful request for the extra info updates the display."""
         #login_person(self.diff.owner, 'test', self.client)
-        lpuser.FOO_BAR.ensure_login(self.client)
-        self.client.open(url=self.package_diffs_url)
-        self.client.waits.forPageLoad(timeout=constants.PAGE_LOAD)
-        self.client.click(link=u'foo')
-        self.client.waits.forElement(
+        client, start_url = self.getClientFor(
+            '/+localpackagediffs', user=lpuser.FOO_BAR,
+            base_url=canonical_url(self.diff.derived_series))
+        client.click(link=u'foo')
+        client.waits.forElement(
             classname=u'diff-extra', timeout=constants.FOR_ELEMENT)
 
-        self.client.click(id=u'field.blacklist_options.1')
-        self.client.waits.forElementProperty(
+        client.click(id=u'field.blacklist_options.1')
+        client.waits.forElementProperty(
             option=u'enabled', id=u'field.blacklist_options.1')
 
         # Reload the diff and ensure it's been updated.
@@ -63,8 +60,8 @@
             diff_reloaded.status)
 
         # Now set it back so that it's not blacklisted.
-        self.client.click(id=u'field.blacklist_options.0')
-        self.client.waits.forElementProperty(
+        client.click(id=u'field.blacklist_options.0')
+        client.waits.forElementProperty(
             option=u'enabled', id=u'field.blacklist_options.0')
         transaction.commit()
         diff_reloaded = diff_source.getByDistroSeriesAndName(
@@ -74,15 +71,15 @@
             diff_reloaded.status)
 
         # Finally, add a comment to this difference.
-        self.client.click(link=u'Add comment')
-        self.client.click(
+        client.click(link=u'Add comment')
+        client.click(
             xpath=u"//div[@class='add-comment-placeholder foo']//textarea")
-        self.client.type(
+        client.type(
             xpath=u"//div[@class='add-comment-placeholder foo']//textarea",
             text=u"Here's a comment.")
-        self.client.click(
+        client.click(
             xpath=u"//div[@class='add-comment-placeholder foo']//button")
-        self.client.waits.forElement(
+        client.waits.forElement(
             classname=u'boardComment', timeout=constants.FOR_ELEMENT)
-        self.client.asserts.assertText(
+        client.asserts.assertText(
             classname=u'boardCommentBody', validator=u"Here's a comment.")

=== modified file 'lib/lp/registry/windmill/tests/test_person_picker.py'
--- lib/lp/registry/windmill/tests/test_person_picker.py	2011-02-10 04:00:00 +0000
+++ lib/lp/registry/windmill/tests/test_person_picker.py	2011-03-30 06:39:14 +0000
@@ -6,8 +6,6 @@
 __metaclass__ = type
 __all__ = []
 
-import unittest
-
 from lp.registry.windmill.testing import RegistryWindmillLayer
 from lp.testing import WindmillTestCase
 from lp.testing.windmill import (
@@ -27,12 +25,9 @@
     suite_name = 'PersonPickerWidget'
 
     def test_person_picker_widget(self):
-        client = self.client
-        lpuser.SAMPLE_PERSON.ensure_login(client)
 
-        client.open(url=u'%s/people/+requestmerge'
-                    % RegistryWindmillLayer.base_url)
-        client.waits.forPageLoad(timeout=constants.PAGE_LOAD)
+        client, start_url = self.getClientFor(
+            '/people/+requestmerge', user=lpuser.SAMPLE_PERSON)
         client.waits.forElement(id=u'show-widget-field-dupe_person',
                                 timeout=constants.FOR_ELEMENT)
 
@@ -53,7 +48,3 @@
         client.asserts.assertProperty(
             xpath=u'//input[@name="field.dupe_person"]',
             validator='value|salgado')
-
-
-def test_suite():
-    return unittest.TestLoader().loadTestsFromName(__name__)

=== modified file 'lib/lp/registry/windmill/tests/test_plusnew_step1.py'
--- lib/lp/registry/windmill/tests/test_plusnew_step1.py	2011-02-10 04:00:00 +0000
+++ lib/lp/registry/windmill/tests/test_plusnew_step1.py	2011-03-30 06:39:14 +0000
@@ -6,8 +6,6 @@
 __metaclass__ = type
 __all__ = []
 
-import unittest
-
 from lp.registry.windmill.testing import RegistryWindmillLayer
 from lp.testing import WindmillTestCase
 from lp.testing.windmill import lpuser
@@ -30,11 +28,8 @@
         """
         # Perform step 1 of the project registration, using information
         # that will yield search results.
-        self.client.open(url=u'%s/projects/+new'
-                        % RegistryWindmillLayer.base_url)
-
-        lpuser.SAMPLE_PERSON.ensure_login(self.client)
-
+        client, start_url = self.getClientFor(
+            '/projects/+new', user=lpuser.SAMPLE_PERSON)
         self.client.waits.forElement(id='field.displayname')
         self.client.type(text=u'dolphin', id='field.displayname')
 
@@ -63,7 +58,3 @@
         self.client.asserts.assertValue(
             id=u'field.name',
             validator=u'hyena')
-
-
-def test_suite():
-    return unittest.TestLoader().loadTestsFromName(__name__)

=== modified file 'lib/lp/registry/windmill/tests/test_plusnew_step2.py'
--- lib/lp/registry/windmill/tests/test_plusnew_step2.py	2011-02-10 04:00:00 +0000
+++ lib/lp/registry/windmill/tests/test_plusnew_step2.py	2011-03-30 06:39:14 +0000
@@ -6,12 +6,10 @@
 __metaclass__ = type
 __all__ = []
 
-import unittest
-
 from lp.registry.windmill.testing import RegistryWindmillLayer
 from lp.testing import WindmillTestCase
 from lp.testing.windmill import lpuser
-
+from lp.testing.windmill.constants import FOR_ELEMENT
 
 class TestNewProjectStep2(WindmillTestCase):
     """Test form for creating a new project."""
@@ -32,12 +30,11 @@
 
         # Perform step 1 of the project registration, using information
         # that will yield search results.
-        self.client.open(url=u'%s/projects/+new'
-                        % RegistryWindmillLayer.base_url)
-
-        lpuser.SAMPLE_PERSON.ensure_login(self.client)
-
-        self.client.waits.forElement(id='field.displayname', timeout=u'20000')
+        client, start_url = self.getClientFor(
+            '/projects/+new', user=lpuser.SAMPLE_PERSON)
+        self.client.waits.forElement(
+            id='field.displayname', timeout=FOR_ELEMENT)
+
         self.client.type(text=u'Badgers', id='field.displayname')
         self.client.type(text=u'badgers', id='field.name')
         self.client.type(text=u"There's the Badger", id='field.title')
@@ -87,7 +84,3 @@
         self.client.asserts.assertProperty(
             id=u'search-results',
             validator='className|lazr-closed')
-
-
-def test_suite():
-    return unittest.TestLoader().loadTestsFromName(__name__)

=== modified file 'lib/lp/registry/windmill/tests/test_product.py'
--- lib/lp/registry/windmill/tests/test_product.py	2011-02-10 04:00:00 +0000
+++ lib/lp/registry/windmill/tests/test_product.py	2011-03-30 06:39:14 +0000
@@ -6,8 +6,6 @@
 __metaclass__ = type
 __all__ = []
 
-import unittest
-
 from lp.registry.windmill.testing import RegistryWindmillLayer
 from lp.testing import WindmillTestCase
 from lp.testing.windmill import (
@@ -28,7 +26,7 @@
             expected_value='Mozilla Firefox',
             new_value='The awesome Mozilla Firefox',
             name='test_title_inline_edit',
-            suite=__name__,
+            suite_name=__name__,
             user=lpuser.SAMPLE_PERSON)
         test()
 
@@ -40,10 +38,6 @@
             expected_value='Not yet specified',
             new_value='C++',
             name='test_proglang_inline_edit',
-            suite=__name__,
+            suite_name=__name__,
             user=lpuser.SAMPLE_PERSON)
         test()
-
-
-def test_suite():
-    return unittest.TestLoader().loadTestsFromName(__name__)

=== modified file 'lib/lp/registry/windmill/tests/test_product_configuration_hidden.py'
--- lib/lp/registry/windmill/tests/test_product_configuration_hidden.py	2011-02-10 04:00:00 +0000
+++ lib/lp/registry/windmill/tests/test_product_configuration_hidden.py	2011-03-30 06:39:14 +0000
@@ -1,8 +1,6 @@
 # Copyright 2010 Canonical Ltd.  This software is licensed under the
 # GNU Affero General Public License version 3 (see the file LICENSE).
 
-import unittest
-
 import transaction
 
 from lp.registry.windmill.testing import RegistryWindmillLayer
@@ -31,11 +29,10 @@
     def test_not_fully_configured_starts_shown(self):
         # A product that is not fully configured displays the links on
         # page load, but they can be hidden.
-        client = self.client
 
-        client.open(url=u'http://launchpad.dev:8085/hidden-configs')
-        client.waits.forPageLoad(timeout=constants.PAGE_LOAD)
-        lpuser.FOO_BAR.ensure_login(client)
+        client, start_url = self.getClientFor(
+            '/hidden-configs', user=lpuser.FOO_BAR,
+            base_url=self.layer.appserver_root_url())
 
         # We can only safely use this class selector in this test b/c there's
         # only one collapsible element on this page.
@@ -64,11 +61,9 @@
             translations_usage="NOT_APPLICABLE")
         transaction.commit()
 
-        client = self.client
-
-        client.open(url=u'http://launchpad.dev:8085/hidden-configs')
-        client.waits.forPageLoad(timeout=constants.PAGE_LOAD)
-        lpuser.FOO_BAR.ensure_login(client)
+        client, start_url = self.getClientFor(
+            '/hidden-configs', user=lpuser.FOO_BAR,
+            base_url=self.layer.appserver_root_url())
         client.waits.forElement(
             classname='collapseWrapper lazr-closed',
             timeout=constants.FOR_ELEMENT)
@@ -85,7 +80,3 @@
         client.asserts.assertProperty(
             classname='collapseWrapper',
             validator='className|lazr-open')
-
-
-def test_suite():
-    return unittest.TestLoader().loadTestsFromName(__name__)

=== modified file 'lib/lp/registry/windmill/tests/test_product_edit_people.py'
--- lib/lp/registry/windmill/tests/test_product_edit_people.py	2011-02-10 04:00:00 +0000
+++ lib/lp/registry/windmill/tests/test_product_edit_people.py	2011-03-30 06:39:14 +0000
@@ -6,7 +6,6 @@
 __metaclass__ = type
 __all__ = []
 
-import unittest
 
 from lp.registry.windmill.testing import RegistryWindmillLayer
 from lp.testing import WindmillTestCase
@@ -37,7 +36,3 @@
             result_index=1,
             new_value='guadamen')
         test()
-
-
-def test_suite():
-    return unittest.TestLoader().loadTestsFromName(__name__)

=== modified file 'lib/lp/registry/windmill/tests/test_project_licenses.py'
--- lib/lp/registry/windmill/tests/test_project_licenses.py	2011-02-10 04:00:00 +0000
+++ lib/lp/registry/windmill/tests/test_project_licenses.py	2011-03-30 06:39:14 +0000
@@ -6,11 +6,10 @@
 __metaclass__ = type
 __all__ = []
 
-import unittest
-
 from lp.registry.windmill.testing import RegistryWindmillLayer
 from lp.testing import WindmillTestCase
 from lp.testing.windmill import lpuser
+from lp.testing.windmill.constants import PAGE_LOAD
 
 
 class TestProjectLicenses(WindmillTestCase):
@@ -22,98 +21,96 @@
     def test_project_licenses(self):
         """Test the dynamic aspects of the project license picker."""
         # The firefox project is as good as any.
-        lpuser.SAMPLE_PERSON.ensure_login(self.client)
-        self.client.open(url=u'%s/firefox/+edit'
-                        % RegistryWindmillLayer.base_url)
-        self.client.waits.forPageLoad(timeout=u'20000')
+        client, start_url = self.getClientFor(
+            '/firefox/+edit', lpuser.SAMPLE_PERSON)
 
         # The Recommended table is visible.
-        self.client.waits.forElementProperty(
+        client.waits.forElementProperty(
             id=u'recommended',
             option='className|lazr-opened')
         # But the More table is not.
-        self.client.asserts.assertProperty(
+        client.asserts.assertProperty(
             id=u'more',
             validator='className|lazr-closed')
         # Neither is the Other choices.
-        self.client.asserts.assertProperty(
+        client.asserts.assertProperty(
             id=u'special',
             validator='className|lazr-closed')
 
         # Clicking on the link exposes the More section though.
-        self.client.click(id='more-expand')
-        self.client.waits.forElementProperty(
+        client.click(id='more-expand')
+        client.waits.forElementProperty(
             id=u'more',
             option='className|lazr-opened')
 
         # As does clicking on the Other choices section.
-        self.client.click(id='special-expand')
-        self.client.waits.forElementProperty(
+        client.click(id='special-expand')
+        client.waits.forElementProperty(
             id=u'special',
             option='className|lazr-opened')
 
         # Clicking on any opened link closes the section.
-        self.client.click(id='recommended-expand')
-        self.client.waits.forElementProperty(
+        client.click(id='recommended-expand')
+        client.waits.forElementProperty(
             id=u'recommended',
             option='className|lazr-closed')
 
         # The license details box starts out hidden.
-        self.client.waits.forElementProperty(
+        client.waits.forElementProperty(
             id=u'license-details',
             option='className|lazr-closed')
 
         # But clicking on one of the Other/* licenses exposes it.
-        self.client.click(xpath='//input[@value = "OTHER_OPEN_SOURCE"]')
-        self.client.waits.forElementProperty(
+        client.click(xpath='//input[@value = "OTHER_OPEN_SOURCE"]')
+        client.waits.forElementProperty(
             id=u'license-details',
             option='className|lazr-opened')
 
         # Clicking on Other/Proprietary exposes the additional commercial
         # licensing details.
-        self.client.waits.forElementProperty(
+        client.waits.forElementProperty(
             id=u'proprietary',
             option='className|lazr-closed')
 
-        self.client.click(xpath='//input[@value = "OTHER_PROPRIETARY"]')
-        self.client.waits.forElementProperty(
+        client.click(xpath='//input[@value = "OTHER_PROPRIETARY"]')
+        client.waits.forElementProperty(
             id=u'license-details',
             option='className|lazr-opened')
-        self.client.waits.forElementProperty(
+        client.waits.forElementProperty(
             id=u'proprietary',
             option='className|lazr-opened')
 
         # Only when all Other/* items are unchecked does the details box get
         # hidden.
-        self.client.click(xpath='//input[@value = "OTHER_OPEN_SOURCE"]')
-        self.client.waits.forElementProperty(
+        client.click(xpath='//input[@value = "OTHER_OPEN_SOURCE"]')
+        client.waits.forElementProperty(
             id=u'license-details',
             option='className|lazr-opened')
 
-        self.client.click(xpath='//input[@value = "OTHER_PROPRIETARY"]')
-        self.client.waits.forElementProperty(
+        client.click(xpath='//input[@value = "OTHER_PROPRIETARY"]')
+        client.waits.forElementProperty(
             id=u'license-details',
             option='className|lazr-closed')
-        self.client.waits.forElementProperty(
+        client.waits.forElementProperty(
             id=u'proprietary',
             option='className|lazr-closed')
 
         # Clicking on "I haven't specified..." unchecks everything and
         # closes the details box, but leaves the sections opened.
 
-        self.client.click(xpath='//input[@value = "OTHER_PROPRIETARY"]')
-        self.client.waits.forElementProperty(
+        client.click(xpath='//input[@value = "OTHER_PROPRIETARY"]')
+        client.waits.forElementProperty(
             id=u'license-details',
             option='className|lazr-opened')
 
-        self.client.asserts.assertChecked(
-            xpath='//input[@value = "OTHER_PROPRIETARY"]')
-
-        self.client.click(id='license_pending')
-        self.client.asserts.assertNotChecked(
-            xpath='//input[@value = "OTHER_PROPRIETARY"]')
-
-        self.client.asserts.assertProperty(
+        client.asserts.assertChecked(
+            xpath='//input[@value = "OTHER_PROPRIETARY"]')
+
+        client.click(id='license_pending')
+        client.asserts.assertNotChecked(
+            xpath='//input[@value = "OTHER_PROPRIETARY"]')
+
+        client.asserts.assertProperty(
             id=u'license-details',
             validator='className|lazr-closed')
 
@@ -121,27 +118,23 @@
         # time the page is visited, those sections will be open.  The
         # Recommended section is always open.
 
-        self.client.click(xpath='//input[@value = "OTHER_PROPRIETARY"]')
-        self.client.type(id='field.license_info', text='Foo bar')
-        self.client.click(id='field.licenses.3')
-        self.client.click(id='field.actions.change')
-        self.client.waits.forPageLoad(timeout=u'20000')
+        client.click(xpath='//input[@value = "OTHER_PROPRIETARY"]')
+        client.type(id='field.license_info', text='Foo bar')
+        client.click(id='field.licenses.3')
+        client.click(id='field.actions.change')
+        client.waits.forPageLoad(timeout=PAGE_LOAD)
 
-        self.client.open(url=u'%s/firefox/+edit'
+        client.open(url=u'%s/firefox/+edit'
                         % RegistryWindmillLayer.base_url)
-        self.client.waits.forPageLoad(timeout=u'20000')
+        client.waits.forPageLoad(timeout=PAGE_LOAD)
 
-        self.client.asserts.assertProperty(
+        client.asserts.assertProperty(
             id=u'more',
             validator='className|lazr-opened')
         # Neither is the Other choices.
-        self.client.asserts.assertProperty(
+        client.asserts.assertProperty(
             id=u'special',
             validator='className|lazr-opened')
-        self.client.asserts.assertProperty(
+        client.asserts.assertProperty(
             id=u'license-details',
             validator='className|lazr-opened')
-
-
-def test_suite():
-    return unittest.TestLoader().loadTestsFromName(__name__)

=== modified file 'lib/lp/registry/windmill/tests/test_team_index.py'
--- lib/lp/registry/windmill/tests/test_team_index.py	2011-02-10 04:00:00 +0000
+++ lib/lp/registry/windmill/tests/test_team_index.py	2011-03-30 06:39:14 +0000
@@ -6,8 +6,6 @@
 __metaclass__ = type
 __all__ = []
 
-import unittest
-
 from lp.registry.windmill.testing import RegistryWindmillLayer
 from lp.testing import WindmillTestCase
 from lp.testing.windmill import lpuser
@@ -23,10 +21,8 @@
     suite_name = __name__
 
     def test_addmember(self):
-        self.client.open(
-            url=u'%s/~testing-spanish-team' % RegistryWindmillLayer.base_url)
-
-        lpuser.TRANSLATIONS_ADMIN.ensure_login(self.client)
+        client, start_url = self.getClientFor(
+            '/~testing-spanish-team', user=lpuser.TRANSLATIONS_ADMIN)
 
         addmember_xpath = (
             '//*[@id="membership"]' +
@@ -71,7 +67,3 @@
         self.client.asserts.assertNode(
             xpath='//*[@id="membership-counts"]'
                   '//a[@href="+members#invited"]')
-
-
-def test_suite():
-    return unittest.TestLoader().loadTestsFromName(__name__)

=== modified file 'lib/lp/soyuz/windmill/tests/test_archivesubscribersindex.py'
--- lib/lp/soyuz/windmill/tests/test_archivesubscribersindex.py	2011-02-10 04:00:00 +0000
+++ lib/lp/soyuz/windmill/tests/test_archivesubscribersindex.py	2011-03-30 06:39:14 +0000
@@ -6,8 +6,6 @@
 __metaclass__ = type
 __all__ = []
 
-import unittest
-
 import transaction
 from zope.component import getUtility
 
@@ -60,14 +58,9 @@
 
     def test_add_subscriber(self):
         """Test adding a private PPA subscriber.."""
-        client = self.client
-
-        self.lpuser.ensure_login(client)
-
-        client.open(url='%s/~joe-bloggs/'
-                        '+archive/myppa/+subscriptions'
-                        % SoyuzWindmillLayer.base_url)
-        client.waits.forPageLoad(timeout=constants.PAGE_LOAD)
+
+        client, start_url = self.getClientFor(
+            '/~joe-bloggs/+archive/myppa/+subscriptions', self.lpuser)
 
         # Click on the JS add access action.
         client.waits.forElement(
@@ -98,6 +91,3 @@
                       'to install software from PPA named myppa for Joe '
                       'Bloggs. Members of Launchpad Developers will be '
                       'notified of the access  via email.')
-
-def test_suite():
-    return unittest.TestLoader().loadTestsFromName(__name__)

=== modified file 'lib/lp/soyuz/windmill/tests/test_ppainlineedit.py'
--- lib/lp/soyuz/windmill/tests/test_ppainlineedit.py	2011-02-10 04:00:00 +0000
+++ lib/lp/soyuz/windmill/tests/test_ppainlineedit.py	2011-03-30 06:39:14 +0000
@@ -25,6 +25,6 @@
             new_value="Celso's default PPA",
             name='test_ppa_displayname_inline_edit',
             user=lpuser.FOO_BAR,
-            suite=__name__)
+            suite_name=__name__)
 
         ppa_displayname_inline_edit_test()

=== modified file 'lib/lp/testing/__init__.py'
--- lib/lp/testing/__init__.py	2011-03-29 00:11:57 +0000
+++ lib/lp/testing/__init__.py	2011-03-30 06:39:14 +0000
@@ -4,6 +4,7 @@
 # pylint: disable-msg=W0401,C0301,F0401
 
 from __future__ import absolute_import
+from lp.testing.windmill.lpuser import LaunchpadUser
 
 __metaclass__ = type
 __all__ = [
@@ -776,11 +777,16 @@
         # of things like https://launchpad.net/bugs/515494)
         self.client.open(url=self.layer.appserver_root_url())
 
-    def getClientFor(self, obj, user=None, password='test', view_name=None):
+    def getClientFor(self, obj, user=None, password='test', base_url=None,
+                     view_name=None):
         """Return a new client, and the url that it has loaded."""
         client = WindmillTestClient(self.suite_name)
         if user is not None:
-            email = removeSecurityProxy(user).preferredemail.email
+            if isinstance(user, LaunchpadUser):
+                email = user.email
+                password = user.password
+            else:
+                email = removeSecurityProxy(user).preferredemail.email
             client.open(url=lpuser.get_basic_login_url(email, password))
             client.waits.forPageLoad(timeout=constants.PAGE_LOAD)
         if isinstance(obj, basestring):
@@ -788,7 +794,31 @@
         else:
             url = canonical_url(
                 obj, view_name=view_name, force_local_path=True)
+        if base_url is None:
+            base_url = self.layer.base_url
+        obj_url = base_url + url
+        client.open(url=obj_url)
+        client.waits.forPageLoad(timeout=constants.PAGE_LOAD)
+        return client, obj_url
+
+    def getClientForPerson(self, url, person, password='test'):
+        """Create a LaunchpadUser for a person and login to the url."""
+        naked_person = removeSecurityProxy(person)
+        user = LaunchpadUser(
+            person.displayname, naked_person.preferredemail.email, password)
+        return self.getClientFor(url, user=user)
+
+
+    def getClientForAnomymous(self, obj, view_name=None):
+        """Return a new client, and the url that it has loaded."""
+        client = WindmillTestClient(self.suite_name)
+        if isinstance(obj, basestring):
+            url = obj
+        else:
+            url = canonical_url(
+                obj, view_name=view_name, force_local_path=True)
         obj_url = self.layer.base_url + url
+        obj_url = obj_url.replace('http://', 'http://foo:foo@')
         client.open(url=obj_url)
         client.waits.forPageLoad(timeout=constants.PAGE_LOAD)
         return client, obj_url

=== modified file 'lib/lp/testing/windmill/lpuser.py'
--- lib/lp/testing/windmill/lpuser.py	2011-02-11 00:25:51 +0000
+++ lib/lp/testing/windmill/lpuser.py	2011-03-30 06:39:14 +0000
@@ -8,8 +8,6 @@
 
 import windmill
 
-from lp.testing.windmill import constants
-
 
 def get_basic_login_url(email, password):
     """Return the constructed url to login a user."""
@@ -27,54 +25,8 @@
         self.email = email
         self.password = password
 
-    def ensure_login(self, client):
-        """Ensure that this user is logged on the page under windmill."""
-        client.waits.forPageLoad(timeout=constants.PAGE_LOAD)
-        lookup_user = (
-            """lookupNode({xpath: '//div[@id="logincontrol"]//a'}).text""")
-        result = client.commands.execJS(code=lookup_user)
-        if (result['result'] is not None and
-            result['result'].strip() == self.display_name):
-            # We are logged in as that user already.
-            return
-
-        current_url = client.commands.execJS(
-            code='windmill.testWin().location;')['result']['href']
-        client.open(url=get_basic_login_url(self.email, self.password))
-        client.waits.forPageLoad(timeout=constants.PAGE_LOAD)
-        client.open(url=current_url)
-        client.waits.forPageLoad(timeout=constants.PAGE_LOAD)
-
-
-class AnonymousUser:
-    """Object representing the anonymous user."""
-
-    def ensure_login(self, client):
-        """Ensure that the user is surfing anonymously."""
-        client.waits.forPageLoad(timeout=constants.PAGE_LOAD)
-        result = client.asserts.assertNode(
-            link=u'Log in / Register', assertion=False)
-        if result['result']:
-            return
-
-        # Open a page with invalid HTTP Basic Auth credentials just to
-        # invalidate the ones previously used.
-        current_url = client.commands.execJS(
-            code='windmill.testWin().location;')['result']['href']
-        current_url = current_url.replace('http://', 'http://foo:foo@')
-        client.open(url=current_url)
-        client.waits.forPageLoad(timeout=constants.PAGE_LOAD)
-
-
-def login_person(person, email, password, client):
-    """Create a LaunchpadUser for a person and password."""
-    user = LaunchpadUser(person.displayname, email, password)
-    user.ensure_login(client)
-
 
 # Well Known Users
-ANONYMOUS = AnonymousUser()
-
 SAMPLE_PERSON = LaunchpadUser(
     'Sample Person', 'test@xxxxxxxxxxxxx', 'test')
 

=== modified file 'lib/lp/testing/windmill/widgets.py'
--- lib/lp/testing/windmill/widgets.py	2011-02-10 04:00:00 +0000
+++ lib/lp/testing/windmill/widgets.py	2011-03-30 06:39:14 +0000
@@ -116,11 +116,25 @@
         self.client.click(xpath=item_xpath)
 
 
-class InlineEditorWidgetTest:
+class WidgetTest:
+    """A base class to provide logon capability."""
+    def getLoggedInClient(self):
+        """Return a new client, and the url that it has loaded."""
+        client = WindmillTestClient(self.suite_name)
+        email = self.user.email
+        password = self.user.password
+        client.open(url=lpuser.get_basic_login_url(email, password))
+        client.waits.forPageLoad(timeout=constants.PAGE_LOAD)
+        client.open(url=self.url)
+        client.waits.forPageLoad(timeout=constants.PAGE_LOAD)
+        return client
+
+
+class InlineEditorWidgetTest(WidgetTest):
     """Test that the inline editor widget is working properly on a page."""
 
     def __init__(self, url, widget_id, expected_value, new_value, name=None,
-                 suite='inline_editor', user=lpuser.NO_PRIV,
+                 suite_name='inline_editor', user=lpuser.NO_PRIV,
                  widget_tag='h1'):
         """Create a new InlineEditorWidgetTest.
 
@@ -141,7 +155,7 @@
         self.widget_id = widget_id
         self.expected_value = expected_value
         self.new_value = new_value
-        self.suite = suite
+        self.suite_name = suite_name
         self.user = user
         self.widget_tag = widget_tag
 
@@ -155,11 +169,7 @@
         * asserts that the page was updated with the new value;
         * reloads and verifies that the new value sticked.
         """
-        client = WindmillTestClient(self.suite)
-        self.user.ensure_login(client)
-        client.open(url=self.url)
-
-        client.waits.forPageLoad(timeout=constants.PAGE_LOAD)
+        client = self.getLoggedInClient()
         widget_base = u"//%s[@id='%s']" % (self.widget_tag, self.widget_id)
         client.waits.forElement(
             xpath=widget_base + '/a', timeout=constants.FOR_ELEMENT)
@@ -193,11 +203,11 @@
     picker.click_result_by_number(result_index)
 
 
-class InlinePickerWidgetSearchTest:
+class InlinePickerWidgetSearchTest(WidgetTest):
     """Test that the Picker widget edits a value inline."""
 
     def __init__(self, url, activator_id, search_text, result_index,
-                 new_value, name=None, suite='inline_picker_search_test',
+                 new_value, name=None, suite_name='inline_picker_search_test',
                  user=lpuser.FOO_BAR):
         """Create a new InlinePickerSearchWidgetTest.
 
@@ -220,16 +230,12 @@
         self.search_text = search_text
         self.result_index = result_index
         self.new_value = new_value
-        self.suite = suite
+        self.suite_name = suite_name
         self.user = user
 
     def __call__(self):
-        client = WindmillTestClient(self.suite)
-        self.user.ensure_login(client)
-
         # Load page.
-        client.open(url=self.url)
-        client.waits.forPageLoad(timeout=constants.PAGE_LOAD)
+        client = self.getLoggedInClient()
 
         # Click on edit button.
         button_xpath = (
@@ -264,11 +270,11 @@
             validator=self.new_value)
 
 
-class InlinePickerWidgetButtonTest:
+class InlinePickerWidgetButtonTest(WidgetTest):
     """Test custom buttons/links added to the Picker."""
 
     def __init__(self, url, activator_id, button_class, new_value,
-                 name=None, suite='inline_picker_button_test',
+                 name=None, suite_name='inline_picker_button_test',
                  user=lpuser.FOO_BAR):
         """Create a new InlinePickerWidgetButtonTest.
 
@@ -284,7 +290,7 @@
         self.activator_id = activator_id
         self.button_class = button_class
         self.new_value = new_value
-        self.suite = suite
+        self.suite_name = suite_name
         self.user = user
         if name is None:
             self.__name__ = 'test_%s_inline_picker' % (
@@ -293,12 +299,8 @@
             self.__name__ = name
 
     def __call__(self):
-        client = WindmillTestClient(self.suite)
-        self.user.ensure_login(client)
-
         # Load page.
-        client.open(url=self.url)
-        client.waits.forPageLoad(timeout=u'25000')
+        client = self.getLoggedInClient()
 
         # Click on edit button.
         button_xpath = (
@@ -338,11 +340,11 @@
             validator=self.new_value)
 
 
-class FormPickerWidgetTest:
+class FormPickerWidgetTest(WidgetTest):
     """Test that the Picker widget edits a form value properly."""
 
     def __init__(self, url, short_field_name, search_text, result_index,
-                 new_value, name=None, suite='form_picker',
+                 new_value, name=None, suite_name='form_picker',
                  user=lpuser.FOO_BAR):
         """Create a new FormPickerWidgetTest.
 
@@ -365,17 +367,14 @@
         self.search_text = search_text
         self.result_index = result_index
         self.new_value = new_value
-        self.suite = suite
+        self.suite_name = suite_name
         self.user = user
         self.choose_link_id = 'show-widget-field-%s' % short_field_name
         self.field_id = 'field.%s' % short_field_name
 
     def __call__(self):
-        client = WindmillTestClient(self.suite)
-        self.user.ensure_login(client)
-
         # Load page.
-        client.open(url=self.url)
+        client = self.getLoggedInClient()
 
         # Click on "Choose" link to show picker for the given field.
         client.waits.forElement(

=== modified file 'lib/lp/translations/windmill/tests/disabled_test_productseries_templates.py'
--- lib/lp/translations/windmill/tests/disabled_test_productseries_templates.py	2011-02-10 04:00:00 +0000
+++ lib/lp/translations/windmill/tests/disabled_test_productseries_templates.py	2011-03-30 06:39:14 +0000
@@ -8,6 +8,8 @@
 
 from lp.testing import WindmillTestCase
 from lp.testing.windmill import lpuser
+from lp.testing.windmill.constants import FOR_ELEMENT
+
 from lp.translations.windmill.testing import TranslationsWindmillLayer
 
 
@@ -47,16 +49,10 @@
           * simulates moving the mouse cursor off the table row;
           * verifies that the action links of the row are deactivated;
         """
-        client = self.client
-        url = ('%s/evolution/trunk/+templates'
-               % TranslationsWindmillLayer.base_url)
-        user = lpuser.TRANSLATIONS_ADMIN
-        # Go to templates page logged in as translations admin.
-        client.open(url=url)
-        client.waits.forPageLoad(timeout=u'20000')
-        user.ensure_login(client)
+        client, start_url = self.getClientFor(
+            '/evolution/trunk/+templates', lpuser.TRANSLATIONS_ADMIN)
 
-        client.waits.forElement(id=u'templates_table', timeout=u'8000')
+        client.waits.forElement(id=u'templates_table', timeout=FOR_ELEMENT)
         # All links are inactive to start with.
         for row_num in range(self.MAX_ROW):
             client.waits.forElement(

=== modified file 'lib/lp/translations/windmill/tests/test_documentation_links.py'
--- lib/lp/translations/windmill/tests/test_documentation_links.py	2011-02-10 04:00:00 +0000
+++ lib/lp/translations/windmill/tests/test_documentation_links.py	2011-03-30 06:39:14 +0000
@@ -11,6 +11,10 @@
 from lp.app.enums import ServiceUsage
 from lp.testing import WindmillTestCase
 from lp.testing.windmill import lpuser
+from lp.testing.windmill.constants import (
+    FOR_ELEMENT,
+    PAGE_LOAD,
+    )
 from lp.translations.windmill.testing import TranslationsWindmillLayer
 
 
@@ -38,9 +42,6 @@
         * makes sure it's hidden when you stay on the same translation;
         * makes sure it's shown again when you go to a different translation.
         """
-        client = self.client
-
-        user = lpuser.TRANSLATIONS_ADMIN
 
         # Create a translation group with documentation to use in the test.
         group = self.factory.makeTranslationGroup(
@@ -63,30 +64,27 @@
         transaction.commit()
 
         # Go to Evolution translations page logged in as translations admin.
-        user.ensure_login(client)
-
-        client.open(
-            url=(u'%s/test-product/trunk/+pots/template/es/'
-                 % TranslationsWindmillLayer.base_url))
-        client.waits.forPageLoad(timeout=u'20000')
+        client, start_url = self.getClientFor(
+            '/test-product/trunk/+pots/template/es/',
+            user=lpuser.TRANSLATIONS_ADMIN)
 
         # Make sure notification box is shown.
         client.waits.forElement(classname=u'important-notice-container',
-                                timeout=u'8000')
+                                timeout=FOR_ELEMENT)
         # Click the hide button.
         client.waits.forElement(classname=u'important-notice-cancel-button',
-                                timeout=u'8000')
+                                timeout=FOR_ELEMENT)
         client.click(classname=u'important-notice-cancel-button')
         # Hiding entire container looks ugly, so only the ballon itself
         # is hidden.
         client.waits.forElementProperty(classname=u'important-notice-balloon',
                                         option=u'style.display|none',
-                                        timeout=u'8000')
+                                        timeout=FOR_ELEMENT)
 
         # Navigating to the next page of this translation doesn't show
         # the notification box.
         client.click(classname=u'next')
-        client.waits.forPageLoad(timeout=u'20000')
+        client.waits.forPageLoad(timeout=PAGE_LOAD)
         client.asserts.assertProperty(classname=u'important-notice-container',
                                       validator=u'style.display|none')
 
@@ -96,7 +94,7 @@
         client.open(
             url=(u'%s/test-product/trunk/+pots/template/ca/'
                  % TranslationsWindmillLayer.base_url))
-        client.waits.forPageLoad(timeout=u'20000')
+        client.waits.forPageLoad(timeout=PAGE_LOAD)
         client.asserts.assertNotProperty(
             classname=u'important-notice-container',
             validator=u'style.display|none')

=== modified file 'lib/lp/translations/windmill/tests/test_import_queue.py'
--- lib/lp/translations/windmill/tests/test_import_queue.py	2011-02-10 04:00:00 +0000
+++ lib/lp/translations/windmill/tests/test_import_queue.py	2011-03-30 06:39:14 +0000
@@ -9,7 +9,6 @@
 import transaction
 from zope.component import getUtility
 
-from canonical.launchpad.webapp import canonical_url
 from lp.app.enums import ServiceUsage
 from lp.testing import WindmillTestCase
 from lp.testing.windmill import lpuser
@@ -18,7 +17,6 @@
     PAGE_LOAD,
     SLEEP,
     )
-from lp.testing.windmill.lpuser import login_person
 from lp.translations.interfaces.translationimportqueue import (
     ITranslationImportQueue,
     )
@@ -77,13 +75,10 @@
 
     def test_import_queue_entry(self):
         """Tests that import queue entry fields behave correctly."""
-        client = self.client
-        start_url = '%s/+imports/1' % TranslationsWindmillLayer.base_url
-        user = lpuser.TRANSLATIONS_ADMIN
+
         # Go to import queue page logged in as translations admin.
-        user.ensure_login(client)
-        client.open(url=start_url)
-        client.waits.forPageLoad(timeout=PAGE_LOAD)
+        client, start_url = self.getClientFor(
+            '/+imports/1', user=lpuser.TRANSLATIONS_ADMIN)
 
         po_only_fields = set(self.FIELDS['PO']) - set(self.FIELDS['POT'])
         pot_only_fields = set(self.FIELDS['POT']) - set(self.FIELDS['PO'])
@@ -127,16 +122,11 @@
         path = base_filename + '.pot'
         entry = self.factory.makeTranslationImportQueueEntry(
             path=path, productseries=productseries)
-        url = canonical_url(entry, rootsite='translations')
-
         transaction.commit()
 
         # The client reviews the upload.
-        client = self.client
-        user = lpuser.TRANSLATIONS_ADMIN
-        user.ensure_login(client)
-        client.open(url=url)
-        client.waits.forPageLoad(timeout=PAGE_LOAD)
+        client, start_url = self.getClientFor(
+            entry, user=lpuser.TRANSLATIONS_ADMIN)
         client.waits.sleep(milliseconds=SLEEP)
 
         # No template is preselected in the templates dropdown.
@@ -189,16 +179,11 @@
             path=path, productseries=template.productseries,
             distroseries=template.distroseries,
             sourcepackagename=template.sourcepackagename)
-        url = canonical_url(entry, rootsite='translations')
-
         transaction.commit()
 
         # The client reviews the upload.
-        client = self.client
-        user = lpuser.TRANSLATIONS_ADMIN
-        user.ensure_login(client)
-        client.open(url=url)
-        client.waits.forPageLoad(timeout=PAGE_LOAD)
+        client, start_url = self.getClientFor(
+            entry, user=lpuser.TRANSLATIONS_ADMIN)
         client.waits.sleep(milliseconds=SLEEP)
 
         # The matching template is preselected in the templates dropdown.
@@ -216,15 +201,10 @@
             path='foo.pot', productseries=template.productseries,
             distroseries=template.distroseries,
             sourcepackagename=template.sourcepackagename)
-        url = canonical_url(entry, rootsite='translations')
-
         transaction.commit()
 
-        client = self.client
-        user = lpuser.TRANSLATIONS_ADMIN
-        user.ensure_login(client)
-        client.open(url=url)
-        client.waits.forPageLoad(timeout=PAGE_LOAD)
+        client, start_url = self.getClientFor(
+            entry, user=lpuser.TRANSLATIONS_ADMIN)
         client.waits.sleep(milliseconds=SLEEP)
 
         client.select(id=u'field.potemplate', option=u'quote')
@@ -246,13 +226,10 @@
 
     def test_import_queue_status_admin(self):
         """Tests that the admin can use the status picker."""
-        client = self.client
-        queue_url = self.layer.base_url+'/+imports'
-        user = lpuser.TRANSLATIONS_ADMIN
+
         # Go to import queue page logged in as translations admin.
-        client.open(url=queue_url)
-        client.waits.forPageLoad(timeout=PAGE_LOAD)
-        user.ensure_login(client)
+        client, start_url = self.getClientFor(
+            '/+imports', user=lpuser.TRANSLATIONS_ADMIN)
 
         # Click on the element containing the import status.
         client.waits.forElement(xpath=IMPORT_STATUS_1, timeout=FOR_ELEMENT)
@@ -265,15 +242,13 @@
         client.asserts.assertText(xpath=IMPORT_STATUS_1, validator=u'Deleted')
 
         # Reload the page and make sure the change sticks.
-        client.open(url=queue_url)
+        client.open(url=start_url)
         client.waits.forPageLoad(timeout=PAGE_LOAD)
         client.waits.forElement(xpath=IMPORT_STATUS_1, timeout=FOR_ELEMENT)
         client.asserts.assertText(xpath=IMPORT_STATUS_1, validator=u'Deleted')
 
     def test_import_queue_status_nopriv(self):
         """Tests that a none-admin will have less choices."""
-        client = self.client
-        queue_url = self.layer.base_url+'/+imports'
         hubert = self.factory.makePerson(
             name="hubert", displayname="Hubert Hunt", password="test",
             email="hubert@xxxxxxxxxxx")
@@ -291,9 +266,7 @@
         import_status = IMPORT_STATUS % entry.id
 
         # Go to import queue page logged in as a normal user.
-        client.open(url=queue_url)
-        client.waits.forPageLoad(timeout=PAGE_LOAD)
-        login_person(hubert, "hubert@xxxxxxxxxxx", "test", client)
+        client, start_url = self.getClientForPerson('/+imports', hubert)
 
         # There should be no status picker for entry 1.
         client.waits.forElement(xpath=import_status, timeout=FOR_ELEMENT)
@@ -313,7 +286,7 @@
         client.asserts.assertText(xpath=import_status, validator=u'Deleted')
 
         # Reload the page and make sure the change sticks.
-        client.open(url=queue_url)
+        client.open(url=start_url)
         client.waits.forPageLoad(timeout=PAGE_LOAD)
         client.waits.forElement(xpath=import_status, timeout=FOR_ELEMENT)
         client.asserts.assertText(xpath=import_status, validator=u'Deleted')

=== modified file 'lib/lp/translations/windmill/tests/test_pofile_translate.py'
--- lib/lp/translations/windmill/tests/test_pofile_translate.py	2011-02-10 04:00:00 +0000
+++ lib/lp/translations/windmill/tests/test_pofile_translate.py	2011-03-30 06:39:14 +0000
@@ -36,25 +36,22 @@
         translation.
         """
         # Go to the translation page.
-        self.client.open(url=url)
-        self.client.waits.forPageLoad(timeout=constants.PAGE_LOAD)
-        self.test_user.ensure_login(self.client)
+        client, start_url = self.getClientFor(url, user=self.test_user)
 
         # Wait for the new translation field and it's associated radio button.
-        self.client.waits.forElement(
+        client.waits.forElement(
             id=new_translation_id, timeout=constants.FOR_ELEMENT)
-        self.client.waits.forElement(
+        client.waits.forElement(
             id=new_translation_select_id, timeout=constants.FOR_ELEMENT)
 
         # Check that the associated radio button is not selected.
-        self.client.asserts.assertNotChecked(id=new_translation_select_id)
+        client.asserts.assertNotChecked(id=new_translation_select_id)
 
         # Type a new translation.
-        self.client.type(
-            id=new_translation_id, text=u'New translation')
+        client.type(id=new_translation_id, text=u'New translation')
 
         # Check that the associated radio button is selected.
-        self.client.asserts.assertChecked(id=new_translation_select_id)
+        client.asserts.assertChecked(id=new_translation_select_id)
 
     def test_pofile_new_translation_autoselect(self):
         """Test for automatically selecting new translation on text input.
@@ -65,26 +62,22 @@
         self.test_user = lpuser.TRANSLATIONS_ADMIN
 
         # Test the zoom out view for Evolution trunk Spanish (es).
-        start_url = ('%s/evolution/trunk/+pots/evolution-2.2/es/+translate'
-                     % TranslationsWindmillLayer.base_url)
+        start_url = '/evolution/trunk/+pots/evolution-2.2/es/+translate'
         new_translation_id = u'msgset_1_es_translation_0_new'
         new_translation_select_id = u'msgset_1_es_translation_0_new_select'
         self._checkTranslationAutoselect(
             start_url, new_translation_id, new_translation_select_id)
 
         # Test the zoom in view for Evolution trunk Brazilian (pt_BR).
-        start_url = ('%s/evolution/trunk/+pots/evolution-2.2/'
-                        'pt_BR/1/+translate'
-                        % TranslationsWindmillLayer.base_url )
+        start_url = '/evolution/trunk/+pots/evolution-2.2/pt_BR/1/+translate'
         new_translation_id = u'msgset_1_pt_BR_translation_0_new'
         new_translation_select_id = u'msgset_1_pt_BR_translation_0_new_select'
         self._checkTranslationAutoselect(
             start_url, new_translation_id, new_translation_select_id)
 
         # Test the zoom out view for Ubuntu Hoary Brazilian (pt_BR).
-        start_url = ('%s/ubuntu/hoary/+source/mozilla/+pots/pkgconf-mozilla/'
-                        'pt_BR/1/+translate'
-                        % TranslationsWindmillLayer.base_url)
+        start_url = ('/ubuntu/hoary/+source/mozilla/+pots/pkgconf-mozilla/'
+                        'pt_BR/1/+translate')
         new_translation_id = u'msgset_152_pt_BR_translation_0_new'
         new_translation_select_id = (u'msgset_152_pt_BR'
                                        '_translation_0_new_select')
@@ -108,31 +101,28 @@
 
         self.test_user = lpuser.TRANSLATIONS_ADMIN
         # Test the zoom out view for Evolution trunk Spanish (es).
-        url = ('%s/evolution/trunk/+pots/evolution-2.2/es/5/+translate'
-               % TranslationsWindmillLayer.base_url)
+        url = '/evolution/trunk/+pots/evolution-2.2/es/5/+translate'
         dismiss_id = u'msgset_5_dismiss'
         force_suggestion_id = u'msgset_5_force_suggestion'
 
         # Go to the translation page.
-        self.client.open(url=url)
-        self.client.waits.forPageLoad(timeout=constants.PAGE_LOAD)
-        self.test_user.ensure_login(self.client)
-        self.client.waits.forElement(
+        client, start_url = self.getClientFor(url, user=self.test_user)
+        client.waits.forElement(
             id=dismiss_id, timeout=constants.FOR_ELEMENT)
-        self.client.waits.forElement(
+        client.waits.forElement(
             id=force_suggestion_id, timeout=constants.FOR_ELEMENT)
 
         # Check that initially the checkboxes are not selected.
-        self.client.asserts.assertNotChecked(id=dismiss_id)
-        self.client.asserts.assertNotChecked(id=force_suggestion_id)
+        client.asserts.assertNotChecked(id=dismiss_id)
+        client.asserts.assertNotChecked(id=force_suggestion_id)
 
         # Click the force suggestion checkbox and verify that it is checked.
-        self.client.click(id=force_suggestion_id)
-        self.client.asserts.assertChecked(id=force_suggestion_id)
+        client.click(id=force_suggestion_id)
+        client.asserts.assertChecked(id=force_suggestion_id)
 
-        self.client.click(id=dismiss_id)
-        self.client.asserts.assertChecked(id=dismiss_id)
-        self.client.asserts.assertNotChecked(id=force_suggestion_id)
+        client.click(id=dismiss_id)
+        client.asserts.assertChecked(id=dismiss_id)
+        client.asserts.assertNotChecked(id=force_suggestion_id)
 
     def test_diverge_and_force_suggestion_mutual_exclusion(self):
         """Test the mutual exclusion of diverge and force suggestion.
@@ -163,8 +153,7 @@
         transaction.commit()
         logout()
 
-        url = ('%s/%s/%s/+pots/%s/pt_BR/1/+translate' % (
-                        TranslationsWindmillLayer.base_url,
+        url = ('/%s/%s/+pots/%s/pt_BR/1/+translate' % (
                         potemplate.product.name,
                         potemplate.productseries.name,
                         potemplate.name))
@@ -174,65 +163,63 @@
         diverge_id = u'msgset_%s_diverge' % potmsgset_id
 
         # Go to the translation page.
-        self.client.open(url=url)
-        self.client.waits.forPageLoad(timeout=constants.PAGE_LOAD)
-        self.test_user.ensure_login(self.client)
-        self.client.waits.forElement(
+        client, start_url = self.getClientFor(url, user=self.test_user)
+        client.waits.forElement(
             id=dismiss_id, timeout=constants.FOR_ELEMENT)
-        self.client.waits.forElement(
+        client.waits.forElement(
             id=force_suggestion_id, timeout=constants.FOR_ELEMENT)
-        self.client.waits.forElement(
+        client.waits.forElement(
             id=diverge_id, timeout=constants.FOR_ELEMENT)
 
         # Check that initialy the checkboxes are not selected.
-        self.client.asserts.assertNotChecked(id=dismiss_id)
-        self.client.asserts.assertNotChecked(id=force_suggestion_id)
-        self.client.asserts.assertNotChecked(id=diverge_id)
+        client.asserts.assertNotChecked(id=dismiss_id)
+        client.asserts.assertNotChecked(id=force_suggestion_id)
+        client.asserts.assertNotChecked(id=diverge_id)
 
         # Test the diverge translation checking and unchecking.
-        self.client.click(id=diverge_id)
-        self.client.asserts.assertChecked(id=diverge_id)
-        self.client.asserts.assertNotChecked(id=force_suggestion_id)
-        self.client.asserts.assertNotChecked(id=dismiss_id)
-        self.client.asserts.assertElemJS(
+        client.click(id=diverge_id)
+        client.asserts.assertChecked(id=diverge_id)
+        client.asserts.assertNotChecked(id=force_suggestion_id)
+        client.asserts.assertNotChecked(id=dismiss_id)
+        client.asserts.assertElemJS(
             id=force_suggestion_id, js=u'element.disabled')
 
-        self.client.click(id=diverge_id)
-        self.client.asserts.assertNotChecked(id=diverge_id)
-        self.client.asserts.assertNotChecked(id=force_suggestion_id)
-        self.client.asserts.assertNotChecked(id=dismiss_id)
-        self.client.asserts.assertElemJS(
+        client.click(id=diverge_id)
+        client.asserts.assertNotChecked(id=diverge_id)
+        client.asserts.assertNotChecked(id=force_suggestion_id)
+        client.asserts.assertNotChecked(id=dismiss_id)
+        client.asserts.assertElemJS(
             id=force_suggestion_id, js=u'!element.disabled')
 
         # Test the force suggestion checking and unchecking.
-        self.client.click(id=force_suggestion_id)
-        self.client.asserts.assertChecked(id=force_suggestion_id)
-        self.client.asserts.assertNotChecked(id=diverge_id)
-        self.client.asserts.assertNotChecked(id=dismiss_id)
-        self.client.asserts.assertElemJS(
+        client.click(id=force_suggestion_id)
+        client.asserts.assertChecked(id=force_suggestion_id)
+        client.asserts.assertNotChecked(id=diverge_id)
+        client.asserts.assertNotChecked(id=dismiss_id)
+        client.asserts.assertElemJS(
             id=diverge_id, js=u'element.disabled')
 
-        self.client.click(id=force_suggestion_id)
-        self.client.asserts.assertNotChecked(id=force_suggestion_id)
-        self.client.asserts.assertNotChecked(id=diverge_id)
-        self.client.asserts.assertNotChecked(id=dismiss_id)
-        self.client.asserts.assertElemJS(
+        client.click(id=force_suggestion_id)
+        client.asserts.assertNotChecked(id=force_suggestion_id)
+        client.asserts.assertNotChecked(id=diverge_id)
+        client.asserts.assertNotChecked(id=dismiss_id)
+        client.asserts.assertElemJS(
             id=diverge_id, js=u'!element.disabled')
 
         # Test unchecking the diverge translations when dismiss all
         # suggestions is enabled.
-        self.client.click(id=dismiss_id)
-        self.client.asserts.assertElemJS(
-            id=force_suggestion_id, js=u'element.disabled')
-        self.client.click(id=diverge_id)
-        self.client.asserts.assertElemJS(
-            id=force_suggestion_id, js=u'element.disabled')
-        self.client.asserts.assertNotChecked(id=force_suggestion_id)
+        client.click(id=dismiss_id)
+        client.asserts.assertElemJS(
+            id=force_suggestion_id, js=u'element.disabled')
+        client.click(id=diverge_id)
+        client.asserts.assertElemJS(
+            id=force_suggestion_id, js=u'element.disabled')
+        client.asserts.assertNotChecked(id=force_suggestion_id)
 
-        self.client.click(id=diverge_id)
-        self.client.asserts.assertElemJS(
+        client.click(id=diverge_id)
+        client.asserts.assertElemJS(
             id=force_suggestion_id, js=u'element.disabled')
-        self.client.asserts.assertNotChecked(id=force_suggestion_id)
+        client.asserts.assertNotChecked(id=force_suggestion_id)
 
     def _checkResetTranslationSelect(
         self, client, checkbox, singular_new_select, singular_current_select,
@@ -304,16 +291,10 @@
         """Test for automatically selecting new translation when
         'Someone needs to review this translations' is checked.
         """
-        client = self.client
-        user = lpuser.TRANSLATIONS_ADMIN
-
         # Go to the zoom in page for a translation with plural forms.
-        self.client.open(
-            url='%s/ubuntu/hoary/+source/evolution/+pots/'
-                'evolution-2.2/es/15/+translate'
-                % TranslationsWindmillLayer.base_url)
-        self.client.waits.forPageLoad(timeout=constants.PAGE_LOAD)
-        user.ensure_login(self.client)
+        client, start_url = self.getClientFor(
+            '/ubuntu/hoary/+source/evolution/+pots/evolution-2.2/es/15/'
+            '+translate', user=lpuser.TRANSLATIONS_ADMIN)
 
         checkbox = u'msgset_144_force_suggestion'
         singular_new_select = u'msgset_144_es_translation_0_new_select'
@@ -331,11 +312,11 @@
         # Go to the zoom in page for a pt_BR translation with plural forms.
         # pt_BR is a language code using the same delimiter as HTTP form
         # fields and are prone to errors.
-        self.client.open(
+        client.open(
             url='%s/ubuntu/hoary/+source/evolution/+pots/'
                 'evolution-2.2/pt_BR/15/+translate'
                 % TranslationsWindmillLayer.base_url)
-        self.client.waits.forPageLoad(timeout=constants.PAGE_LOAD)
+        client.waits.forPageLoad(timeout=constants.PAGE_LOAD)
 
         checkbox = u'msgset_144_force_suggestion'
         singular_new_select = u'msgset_144_pt_BR_translation_0_new_select'
@@ -352,11 +333,11 @@
             plural_new_select=plural_new_select)
 
         # Go to the zoom in page for a translation without plural forms.
-        self.client.open(
+        client.open(
             url='%s/ubuntu/hoary/+source/evolution/+pots/'
                 'evolution-2.2/es/19/+translate'
                 % TranslationsWindmillLayer.base_url)
-        self.client.waits.forPageLoad(timeout=constants.PAGE_LOAD)
+        client.waits.forPageLoad(timeout=constants.PAGE_LOAD)
 
         checkbox = u'msgset_148_force_suggestion'
         singular_new_select = u'msgset_148_es_translation_0_new_select'
@@ -424,11 +405,9 @@
         Adding new translations will force them as suggestions.
         """
 
-        self.client.open(
-            url='%s/evolution/trunk/+pots/evolution-2.2/pt_BR/1/+translate'
-                % TranslationsWindmillLayer.base_url)
-        self.client.waits.forPageLoad(timeout=constants.PAGE_LOAD)
-        self.test_user.ensure_login(self.client)
+        self.client, start_url = self.getClientFor(
+            '/evolution/trunk/+pots/evolution-2.2/pt_BR/1/+translate',
+            user=self.test_user)
 
         self._ensureTranslationMode(reviewer=True)
 
@@ -443,11 +422,9 @@
         Adding new translations will not force them as suggestions.
         """
 
-        self.client.open(
-            url='%s/evolution/trunk/+pots/evolution-2.2/pt_BR/1/+translate'
-                % TranslationsWindmillLayer.base_url)
-        self.client.waits.forPageLoad(timeout=constants.PAGE_LOAD)
-        self.test_user.ensure_login(self.client)
+        self.client, start_url = self.getClientFor(
+            '/evolution/trunk/+pots/evolution-2.2/pt_BR/1/+translate',
+            user=self.test_user)
 
         self._ensureTranslationMode(translator=True)
 
@@ -468,13 +445,14 @@
     def _ensureTranslationMode(self, reviewer=False, translator=False):
         """Ensure the specified mode is currently selected."""
 
-        if (reviewer is translator):
+        if reviewer is translator:
             raise AssertionError("You must specify a single working mode.")
 
         self.client.waits.forElement(
             id=self.switch_working_mode, timeout=constants.FOR_ELEMENT)
 
-        current_is_reviewer = self.client.execJS(js=self.js_code)['output']
+        current_is_reviewer = self.client.commands.execJS(
+            js=self.js_code)['result']
         need_to_switch_mode = (
             reviewer and not current_is_reviewer or
             translator and current_is_reviewer)
@@ -484,7 +462,8 @@
             return
 
         # We check that the mode was changed.
-        current_is_reviewer = self.client.execJS(js=self.js_code)['output']
+        current_is_reviewer = self.client.commands.execJS(
+            js=self.js_code)['result']
 
         switch_done = (
             reviewer and current_is_reviewer or

=== modified file 'lib/lp/translations/windmill/tests/test_serieslanguages.py'
--- lib/lp/translations/windmill/tests/test_serieslanguages.py	2011-02-10 04:00:00 +0000
+++ lib/lp/translations/windmill/tests/test_serieslanguages.py	2011-03-30 06:39:14 +0000
@@ -9,7 +9,6 @@
 from lp.testing import WindmillTestCase
 from lp.testing.windmill import lpuser
 from lp.testing.windmill.constants import (
-    PAGE_LOAD,
     SLEEP,
     )
 from lp.translations.windmill.testing import TranslationsWindmillLayer
@@ -26,9 +25,9 @@
     layer = TranslationsWindmillLayer
     suite_name = 'SeriesLanguages Tables'
 
-    def _toggle_languages_visiblity(self):
-        self.client.click(id="toggle-languages-visibility")
-        self.client.waits.sleep(milliseconds=SLEEP)
+    def _toggle_languages_visiblity(self, client):
+        client.click(id="toggle-languages-visibility")
+        client.waits.sleep(milliseconds=SLEEP)
 
     def _assert_languages_visible(self, languages):
         for language, visibility in languages.items():
@@ -46,17 +45,14 @@
         The test cannot fully cover all languages so we just test with a
         person having Catalan and Spanish as preferred languages.
         """
-        client = self.client
-        start_url = '%s/ubuntu' % TranslationsWindmillLayer.base_url
-        user = lpuser.TRANSLATIONS_ADMIN
+
         # Go to the distribution languages page
-        self.client.open(url=start_url)
-        self.client.waits.forPageLoad(timeout=PAGE_LOAD)
-        user.ensure_login(self.client)
+        client, start_url = self.getClientFor(
+            '/ubuntu', user=lpuser.TRANSLATIONS_ADMIN)
 
         # A link will be displayed for viewing all languages
         # and only user preferred langauges are displayed
-        self.client.asserts.assertProperty(
+        client.asserts.assertProperty(
             id=u'toggle-languages-visibility',
             validator='text|View all languages')
         self._assert_languages_visible({
@@ -67,8 +63,8 @@
             })
 
         # Toggle language visibility by clicking the toggle link.
-        self._toggle_languages_visiblity()
-        self.client.asserts.assertProperty(
+        self._toggle_languages_visiblity(client)
+        client.asserts.assertProperty(
             id=u'toggle-languages-visibility',
             validator='text|View only preferred languages')
         # All languages should be visible now