Commit a343a84c authored by Julien Phalip's avatar Julien Phalip
Browse files

Added the `wait_until()` and `wait_loaded_tag()` methods to...

Added the `wait_until()` and `wait_loaded_tag()` methods to `AdminSeleniumWebDriverTestCase` to prevent some concurrency issues with in-memory SQLite database access in the admin Selenium tests. Thanks to Florian Apolloner, Anssi Kääriäinen and Aymeric Augustin for their help debugging this problem.

git-svn-id: http://code.djangoproject.com/svn/django/trunk@17283 bcc190cf-cafb-0310-a4f2-bffc1f526a37
parent 46c12d12
Loading
Loading
Loading
Loading
+22 −0
Original line number Diff line number Diff line
@@ -29,6 +29,26 @@ class AdminSeleniumWebDriverTestCase(LiveServerTestCase):
        if hasattr(cls, 'selenium'):
            cls.selenium.quit()

    def wait_until(self, callback, timeout=10):
        """
        Helper function that blocks the execution of the tests until the
        specified callback returns a value that is not falsy. This function can
        be called, for example, after clicking a link or submitting a form.
        See the other public methods that call this function for more details.
        """
        from selenium.webdriver.support.wait import WebDriverWait
        WebDriverWait(self.selenium, timeout).until(callback)

    def wait_loaded_tag(self, tag_name, timeout=10):
        """
        Helper function that blocks until the element with the given tag name
        is found on the page.
        """
        self.wait_until(
            lambda driver: driver.find_element_by_tag_name(tag_name),
            timeout
        )

    def admin_login(self, username, password, login_url='/admin/'):
        """
        Helper function to log into the admin.
@@ -41,6 +61,8 @@ class AdminSeleniumWebDriverTestCase(LiveServerTestCase):
        login_text = _('Log in')
        self.selenium.find_element_by_xpath(
            '//input[@value="%s"]' % login_text).click()
        # Wait for the next page to be loaded.
        self.wait_loaded_tag('body')

    def get_css_value(self, selector, attribute):
        """
+35 −0
Original line number Diff line number Diff line
@@ -1843,6 +1843,41 @@ out the `full reference`_ for more details.
    </howto/static-files>` so you'll need to have your project configured
    accordingly (in particular by setting :setting:`STATIC_URL`).

.. note::

    When using an in-memory SQLite database to run the tests, the same database
    connection will be shared by two threads in parallel: the thread in which
    the live server is run, and the thread in which the test case is run. It is
    important to prevent simultaneous database queries via this shared
    connection by the two threads as that may sometimes cause the tests to
    randomly fail. So you need to ensure that the two threads do not access the
    database at the same time. In particular, this means that in some cases
    (for example just after clicking a link or submitting a form) you might
    need to check that a response is received by Selenium and that the next
    page is loaded before proceeding further with the execution of the tests.
    This can be achieved, for example, by making Selenium wait until the
    `<body>` HTML tag is found in the response:

    .. code-block:: python

        def test_login(self):
            from selenium.webdriver.support.wait import WebDriverWait
            ...
            self.selenium.find_element_by_xpath('//input[@value="Log in"]').click()
            # Wait until the response is received
            WebDriverWait(self.selenium, timeout).until(
                lambda driver: driver.find_element_by_tag_name('body'), timeout=10)

    The difficult point is that there really is no such thing as a "page load",
    especially in modern Web apps that have dynamically-generated page
    components that do not exist in the HTML initially received from the
    server. So simply checking for the presence of the `<body>` tag in the
    response might not necessarily be appropriate for all use cases. Please
    refer to the `Selenium FAQ`_ and the `Selenium documentation`_ for more
    information on this topic.

    .. _Selenium FAQ: http://code.google.com/p/selenium/wiki/FrequentlyAskedQuestions#Q:_WebDriver_fails_to_find_elements_/_Does_not_block_on_page_loa
    .. _Selenium documentation: http://seleniumhq.org/docs/04_webdriver_advanced.html#explicit-waits

Using different testing frameworks
==================================
+3 −0
Original line number Diff line number Diff line
@@ -443,6 +443,9 @@ class SeleniumFirefoxTests(AdminSeleniumWebDriverTestCase):
        self.selenium.find_element_by_name('profile_set-2-last_name').send_keys('2 last name 2')
        self.selenium.find_element_by_xpath('//input[@value="Save"]').click()

        # Wait for the next page to be loaded.
        self.wait_loaded_tag('body')

        # Check that the objects have been created in the database
        self.assertEqual(ProfileCollection.objects.all().count(), 1)
        self.assertEqual(Profile.objects.all().count(), 3)