Ticket #2879: 2879.selenium-support-extra-tests.diff

File 2879.selenium-support-extra-tests.diff, 30.6 KB (added by Tom Christie, 12 years ago)
  • django/conf/global_settings.py

    diff --git a/django/conf/global_settings.py b/django/conf/global_settings.py
    index 6b09be2..373d280 100644
    a b DEFAULT_EXCEPTION_REPORTER_FILTER = 'django.views.debug.SafeExceptionReporterFil  
    560560# The name of the class to use to run the test suite
    561561TEST_RUNNER = 'django.test.simple.DjangoTestSuiteRunner'
    562562
     563# For the live test server (e.g. used for running Selenium tests)
     564LIVE_TEST_SERVER_HOST = 'localhost'
     565LIVE_TEST_SERVER_PORT = 8081
     566
    563567############
    564568# FIXTURES #
    565569############
  • django/test/__init__.py

    diff --git a/django/test/__init__.py b/django/test/__init__.py
    index a3a03e3..21a4841 100644
    a b Django Unit Test and Doctest framework.  
    44
    55from django.test.client import Client, RequestFactory
    66from django.test.testcases import (TestCase, TransactionTestCase,
    7         SimpleTestCase, skipIfDBFeature, skipUnlessDBFeature)
     7    SimpleTestCase, LiveServerTestCase, skipIfDBFeature,
     8    skipUnlessDBFeature)
    89from django.test.utils import Approximate
  • django/test/testcases.py

    diff --git a/django/test/testcases.py b/django/test/testcases.py
    index ee22ac2..049da26 100644
    a b import sys  
    55from functools import wraps
    66from urlparse import urlsplit, urlunsplit
    77from xml.dom.minidom import parseString, Node
     8import select
     9import socket
     10import threading
    811
    912from django.conf import settings
     13from django.contrib.staticfiles.handlers import StaticFilesHandler
    1014from django.core import mail
    1115from django.core.exceptions import ValidationError
     16from django.core.handlers.wsgi import WSGIHandler
    1217from django.core.management import call_command
    1318from django.core.signals import request_started
     19from django.core.servers.basehttp import (WSGIRequestHandler, WSGIServer,
     20    WSGIServerException)
    1421from django.core.urlresolvers import clear_url_caches
    1522from django.core.validators import EMPTY_VALUES
    1623from django.db import (transaction, connection, connections, DEFAULT_DB_ALIAS,
    class TransactionTestCase(SimpleTestCase):  
    364371        for db in databases:
    365372            call_command('flush', verbosity=0, interactive=False, database=db)
    366373
    367             if hasattr(self, 'fixtures'):
     374            if getattr(self, 'fixtures', None):
    368375                # We have to use this slightly awkward syntax due to the fact
    369376                # that we're using *args and **kwargs together.
    370377                call_command('loaddata', *self.fixtures,
    class TestCase(TransactionTestCase):  
    679686        Site.objects.clear_cache()
    680687
    681688        for db in databases:
    682             if hasattr(self, 'fixtures'):
     689            if getattr(self, 'fixtures', None):
    683690                call_command('loaddata', *self.fixtures,
    684691                             **{
    685692                                'verbosity': 0,
    def skipUnlessDBFeature(feature):  
    732739    """
    733740    return _deferredSkip(lambda: not getattr(connection.features, feature),
    734741                         "Database doesn't support feature %s" % feature)
     742
     743class QuietWSGIRequestHandler(WSGIRequestHandler):
     744    """
     745    Just a regular WSGIRequestHandler except it doesn't log to the standard
     746    output any of the requests received, so as to not clutter the output for
     747    the tests' results.
     748    """
     749    def log_message(*args):
     750        pass
     751
     752class StoppableWSGIServer(WSGIServer):
     753    """
     754    The code in this class is borrowed from the `SocketServer.BaseServer` class
     755    in Python 2.6. The important functionality here is that the server is non-
     756    blocking and that it can be shut down at any moment. This is made possible
     757    by the server regularly polling the socket and checking if it has been
     758    asked to stop.
     759    Note for the future: Once Django stops supporting Python 2.5, this class
     760    can be removed as `WSGIServer` will have this ability to shutdown on
     761    demand.
     762    """
     763
     764    def __init__(self, *args, **kwargs):
     765        super(StoppableWSGIServer, self).__init__(*args, **kwargs)
     766        self.__is_shut_down = threading.Event()
     767        self.__serving = False
     768
     769    def serve_forever(self, poll_interval=0.5):
     770        """Handle one request at a time until shutdown.
     771
     772        Polls for shutdown every poll_interval seconds.
     773        """
     774        self.__serving = True
     775        self.__is_shut_down.clear()
     776        while self.__serving:
     777            r, w, e = select.select([self], [], [], poll_interval)
     778            if r:
     779                self._handle_request_noblock()
     780        self.__is_shut_down.set()
     781
     782    def shutdown(self):
     783        """Stops the serve_forever loop.
     784
     785        Blocks until the loop has finished. This must be called while
     786        serve_forever() is running in another thread, or it will
     787        deadlock.
     788        """
     789        self.__serving = False
     790        self.__is_shut_down.wait()
     791
     792    def handle_request(self):
     793        """Handle one request, possibly blocking.
     794        """
     795        fd_sets = select.select([self], [], [], None)
     796        if not fd_sets[0]:
     797            return
     798        self._handle_request_noblock()
     799
     800    def _handle_request_noblock(self):
     801        """Handle one request, without blocking.
     802
     803        I assume that select.select has returned that the socket is
     804        readable before this function was called, so there should be
     805        no risk of blocking in get_request().
     806        """
     807        try:
     808            request, client_address = self.get_request()
     809        except socket.error:
     810            return
     811        if self.verify_request(request, client_address):
     812            try:
     813                self.process_request(request, client_address)
     814            except Exception:
     815                self.handle_error(request, client_address)
     816                self.close_request(request)
     817
     818class LiveServerThread(threading.Thread):
     819    """
     820    Thread for running a live http server while the tests are running.
     821    """
     822
     823    def __init__(self, address, port, fixtures=None):
     824        self.address = address
     825        self.port = port
     826        self.fixtures = fixtures
     827        self.is_ready = threading.Event()
     828        self.error = None
     829        super(LiveServerThread, self).__init__()
     830
     831    def run(self):
     832        """
     833        Sets up live server and database and loops over handling http requests.
     834        """
     835        try:
     836            # Instantiate and start the server
     837            self.httpd = StoppableWSGIServer(
     838                (self.address, self.port), QuietWSGIRequestHandler)
     839            handler = StaticFilesHandler(WSGIHandler())
     840            self.httpd.set_app(handler)
     841
     842            # If the database is in memory we must reload the data in this new
     843            # thread.
     844            if (settings.DATABASES['default']['ENGINE'] == 'django.db.backends.sqlite3' or
     845                settings.DATABASES['default']['TEST_NAME']):
     846                connection.creation.create_test_db(0)
     847                # Import the fixtures into the test database
     848                if self.fixtures:
     849                    call_command('loaddata', *self.fixtures,
     850                        **{'verbosity': 0})
     851            self.is_ready.set()
     852            self.httpd.serve_forever()
     853        except WSGIServerException, e:
     854            self.error = e
     855            self.is_ready.set()
     856
     857    def join(self, timeout=None):
     858        self.httpd.shutdown()
     859        self.httpd.server_close()
     860        super(LiveServerThread, self).join(timeout)
     861
     862class LiveServerTestCase(TestCase):
     863    """
     864    Does basically the same as TestCase but also launches a live http server in
     865    a separate thread so that the tests may use another testing framework, such
     866    as Selenium for example, instead of the built-in dummy client.
     867    """
     868
     869    @property
     870    def live_server_url(self):
     871        return 'http://%s:%s' % (settings.LIVE_TEST_SERVER_HOST,
     872                                 settings.LIVE_TEST_SERVER_PORT)
     873
     874    def setUp(self):
     875        # Launch the Django live server's thread
     876        self.server_thread = LiveServerThread(
     877            settings.LIVE_TEST_SERVER_HOST,
     878            int(settings.LIVE_TEST_SERVER_PORT),
     879            fixtures=getattr(self, 'fixtures', None))
     880        self.server_thread.start()
     881
     882        # Wait for the Django server to be ready
     883        self.server_thread.is_ready.wait()
     884        if self.server_thread.error:
     885            raise self.server_thread.error
     886
     887        super(LiveServerTestCase, self).setUp()
     888
     889    def tearDown(self):
     890        # Terminate the Django server's thread
     891        self.server_thread.join()
     892        super(LiveServerTestCase, self).tearDown()
  • docs/internals/contributing/writing-code/unit-tests.txt

    diff --git a/docs/internals/contributing/writing-code/unit-tests.txt b/docs/internals/contributing/writing-code/unit-tests.txt
    index 5ec09fe..baa20a1 100644
    a b Going beyond that, you can specify an individual test method like this:  
    122122
    123123    ./runtests.py --settings=path.to.settings i18n.TranslationTests.test_lazy_objects
    124124
     125Running the Selenium tests
     126~~~~~~~~~~~~~~~~~~~~~~~~~~
     127
     128Some admin tests require Selenium 2 to work via a real Web browser. To allow
     129those tests to run and not be skipped, you must install the selenium_ package
     130(version > 2.13) into your Python path.
     131
     132Then, run the tests normally, for example:
     133
     134.. code-block:: bash
     135
     136    ./runtests.py --settings=test_sqlite admin_inlines
     137
    125138Running all the tests
    126139~~~~~~~~~~~~~~~~~~~~~
    127140
    dependencies:  
    135148*  setuptools_
    136149*  memcached_, plus a :ref:`supported Python binding <memcached>`
    137150*  gettext_ (:ref:`gettext_on_windows`)
     151*  selenium_
    138152
    139153If you want to test the memcached cache backend, you'll also need to define
    140154a :setting:`CACHES` setting that points at your memcached instance.
    associated tests will be skipped.  
    149163.. _setuptools: http://pypi.python.org/pypi/setuptools/
    150164.. _memcached: http://www.danga.com/memcached/
    151165.. _gettext: http://www.gnu.org/software/gettext/manual/gettext.html
     166.. _selenium: http://pypi.python.org/pypi/selenium
    152167
    153168.. _contrib-apps:
    154169
  • docs/ref/settings.txt

    diff --git a/docs/ref/settings.txt b/docs/ref/settings.txt
    index 20366e3..2a794ce 100644
    a b all cache keys used by the Django server.  
    195195
    196196See the :ref:`cache documentation <cache_key_prefixing>` for more information.
    197197
     198.. setting:: LIVE_TEST_SERVER_HOST
     199
     200LIVE_TEST_SERVER_HOST
     201~~~~~~~~~~~~~~~~~~~~~
     202
     203Default: ``'localhost'``
     204
     205Controls the host address at which the live test server gets started when using
     206a :class:`~django.test.LiveServerTestCase`.
     207
     208See also: :setting:`LIVE_TEST_SERVER_PORT`
     209
     210.. setting:: LIVE_TEST_SERVER_PORT
     211
     212LIVE_TEST_SERVER_PORT
     213~~~~~~~~~~~~~~~~~~~~~
     214
     215Default: ``8081``
     216
     217Controls the port at which the live test server gets started when using
     218a :class:`~django.test.LiveServerTestCase`.
     219
     220See also: :setting:`LIVE_TEST_SERVER_HOST`
     221
    198222.. setting:: CACHES-LOCATION
    199223
    200224LOCATION
  • docs/topics/testing.txt

    diff --git a/docs/topics/testing.txt b/docs/topics/testing.txt
    index 181b4ff..e5f8dcc 100644
    a b Some of the things you can do with the test client are:  
    580580* Test that a given request is rendered by a given Django template, with
    581581  a template context that contains certain values.
    582582
    583 Note that the test client is not intended to be a replacement for Twill_,
     583Note that the test client is not intended to be a replacement for Windmill_,
    584584Selenium_, or other "in-browser" frameworks. Django's test client has
    585585a different focus. In short:
    586586
    587587* Use Django's test client to establish that the correct view is being
    588588  called and that the view is collecting the correct context data.
    589589
    590 * Use in-browser frameworks such as Twill and Selenium to test *rendered*
    591   HTML and the *behavior* of Web pages, namely JavaScript functionality.
     590* Use in-browser frameworks such as Windmill_ and Selenium_ to test *rendered*
     591  HTML and the *behavior* of Web pages, namely JavaScript functionality. Django
     592  also provides special support for those frameworks; see the section on
     593  :class:`~django.test.LiveServerTestCase` for more details.
    592594
    593595A comprehensive test suite should use a combination of both test types.
    594596
    595 .. _Twill: http://twill.idyll.org/
    596 .. _Selenium: http://seleniumhq.org/
    597 
    598597Overview and a quick example
    599598~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    600599
    set up, execute and tear down the test suite.  
    18301829    those options will be added to the list of command-line options that
    18311830    the :djadmin:`test` command can use.
    18321831
     1832Live test server
     1833----------------
     1834
     1835.. versionadded:: 1.4
     1836
     1837.. currentmodule:: django.test
     1838
     1839.. class:: LiveServerTestCase()
     1840
     1841``LiveServerTestCase`` does basically the same as
     1842:class:`~django.test.TestCase` with one extra thing: it launches a live Django
     1843server in the background on setup, and shuts it down on teardown. This allows
     1844to use other automated test clients than the
     1845:ref:`Django dummy client <test-client>` such as, for example, the Selenium_ or
     1846Windmill_ clients, to execute a series of functional tests inside a browser and
     1847simulate a real user's actions.
     1848
     1849You may control which host and port the live server will run at with
     1850respectively the :setting:`LIVE_TEST_SERVER_HOST` and
     1851:setting:`LIVE_TEST_SERVER_PORT` settings. The full server url can then be
     1852accessed during the tests with ``self.live_server_url``.
     1853
     1854To demonstrate how to use ``LiveServerTestCase``, let's write a simple Selenium
     1855test. First of all, you need to install the `selenium package`_ into your
     1856Python path:
     1857
     1858.. code-block:: bash
     1859
     1860   pip install selenium
     1861
     1862Then, add the following code to one of your app's tests module (for example:
     1863``myapp/tests.py``):
     1864
     1865.. code-block:: python
     1866
     1867    from django.test import LiveServerTestCase
     1868    from selenium.webdriver.firefox.webdriver import WebDriver
     1869
     1870    class MySeleniumTests(LiveServerTestCase):
     1871        fixtures = ['user-data.json']
     1872
     1873        def setUp(self):
     1874            self.selenium = WebDriver()
     1875            super(MySeleniumTests, self).setUp()
     1876
     1877        def tearDown(self):
     1878            super(MySeleniumTests, self).tearDown()
     1879            self.selenium.quit()
     1880
     1881        def test_login(self):
     1882            self.selenium.get('%s%s' % (self.live_server_url, '/login/'))
     1883            username_input = self.selenium.find_element_by_name("username")
     1884            username_input.send_keys('myuser')
     1885            password_input = self.selenium.find_element_by_name("password")
     1886            password_input.send_keys('secret')
     1887            self.selenium.find_element_by_xpath('//input[@value="Log in"]').click()
     1888
     1889Finally, you may run the test as follows:
     1890
     1891.. code-block:: bash
     1892
     1893    ./manage.py test myapp.MySeleniumTests.test_login
     1894
     1895This example will automatically open Firefox then go to the login page, enter
     1896the credentials and press the "Log in" button. Selenium offers other drivers in
     1897case you do not have Firefox installed or wish to use another browser. The
     1898example above is just a tiny fraction of what the Selenium client can do; check
     1899out the `full reference`_ for more details.
     1900
     1901.. _Windmill: http://www.getwindmill.com/
     1902.. _Selenium: http://seleniumhq.org/
     1903.. _selenium package: http://pypi.python.org/pypi/selenium
     1904.. _full reference: http://readthedocs.org/docs/selenium-python/en/latest/api.html
     1905.. _Firefox: http://www.mozilla.com/firefox/
    18331906
    18341907Attributes
    18351908~~~~~~~~~~
    18361909
    1837 
    18381910.. attribute:: DjangoTestSuiteRunner.option_list
    18391911
    18401912    .. versionadded:: 1.4
  • tests/modeltests/test_client/models.py

    diff --git a/tests/modeltests/test_client/models.py b/tests/modeltests/test_client/models.py
    index df872cd..351b6e9 100644
    a b class CSRFEnabledClientTests(TestCase):  
    489489class CustomTestClient(Client):
    490490    i_am_customized = "Yes"
    491491
     492
    492493class CustomTestClientTest(TestCase):
    493494    client_class = CustomTestClient
    494495
  • tests/regressiontests/admin_inlines/tests.py

    diff --git a/tests/regressiontests/admin_inlines/tests.py b/tests/regressiontests/admin_inlines/tests.py
    index c2e3bbc..d4f8f67 100644
    a b  
    11from __future__ import absolute_import
    22
     3from django.contrib.admin.tests import AdminSeleniumWebDriverTestCase
    34from django.contrib.admin.helpers import InlineAdminForm
    45from django.contrib.auth.models import User, Permission
    56from django.contrib.contenttypes.models import ContentType
    class TestInlinePermissions(TestCase):  
    380381        self.assertContains(response, 'value="4" id="id_inner2_set-TOTAL_FORMS"')
    381382        self.assertContains(response, '<input type="hidden" name="inner2_set-0-id" value="%i"' % self.inner2_id)
    382383        self.assertContains(response, 'id="id_inner2_set-0-DELETE"')
     384
     385class SeleniumFirefoxTests(AdminSeleniumWebDriverTestCase):
     386    webdriver_class = 'selenium.webdriver.firefox.webdriver.WebDriver'
     387    fixtures = ['admin-views-users.xml']
     388    urls = "regressiontests.admin_inlines.urls"
     389
     390    def test_add_inlines(self):
     391        """
     392        Ensure that the "Add another XXX" link correctly adds items to the
     393        inline form.
     394        """
     395        self.admin_login(username='super', password='secret')
     396        self.selenium.get('%s%s' % (self.live_server_url,
     397            '/admin/admin_inlines/titlecollection/add/'))
     398
     399        # Check that there's only one inline to start with and that it has the
     400        # correct ID.
     401        self.failUnlessEqual(len(self.selenium.find_elements_by_css_selector(
     402            '#title_set-group table tr.dynamic-title_set')), 1)
     403        self.failUnlessEqual(self.selenium.find_element_by_css_selector(
     404            '.dynamic-title_set:nth-of-type(1)').get_attribute('id'),
     405            'title_set-0')
     406        self.failUnlessEqual(len(self.selenium.find_elements_by_css_selector(
     407            'form#titlecollection_form tr.dynamic-title_set#title_set-0 input[name=title_set-0-title1]')), 1)
     408        self.failUnlessEqual(len(self.selenium.find_elements_by_css_selector(
     409            'form#titlecollection_form tr.dynamic-title_set#title_set-0 input[name=title_set-0-title2]')), 1)
     410
     411        # Add an inline
     412        self.selenium.find_element_by_link_text('Add another Title').click()
     413
     414        # Check that the inline has been added, that it has the right id, and
     415        # that it contains the right fields.
     416        self.failUnlessEqual(len(self.selenium.find_elements_by_css_selector(
     417            '#title_set-group table tr.dynamic-title_set')), 2)
     418        self.failUnlessEqual(self.selenium.find_element_by_css_selector(
     419            '.dynamic-title_set:nth-of-type(2)').get_attribute('id'), 'title_set-1')
     420        self.failUnlessEqual(len(self.selenium.find_elements_by_css_selector(
     421            'form#titlecollection_form tr.dynamic-title_set#title_set-1 input[name=title_set-1-title1]')), 1)
     422        self.failUnlessEqual(len(self.selenium.find_elements_by_css_selector(
     423            'form#titlecollection_form tr.dynamic-title_set#title_set-1 input[name=title_set-1-title2]')), 1)
     424
     425        # Let's add another one to be sure
     426        self.selenium.find_element_by_link_text('Add another Title').click()
     427        self.failUnlessEqual(len(self.selenium.find_elements_by_css_selector(
     428            '#title_set-group table tr.dynamic-title_set')), 3)
     429        self.failUnlessEqual(self.selenium.find_element_by_css_selector(
     430            '.dynamic-title_set:nth-of-type(3)').get_attribute('id'), 'title_set-2')
     431        self.failUnlessEqual(len(self.selenium.find_elements_by_css_selector(
     432            'form#titlecollection_form tr.dynamic-title_set#title_set-2 input[name=title_set-2-title1]')), 1)
     433        self.failUnlessEqual(len(self.selenium.find_elements_by_css_selector(
     434            'form#titlecollection_form tr.dynamic-title_set#title_set-2 input[name=title_set-2-title2]')), 1)
     435
     436    def test_delete_inlines(self):
     437        self.admin_login(username='super', password='secret')
     438        self.selenium.get('%s%s' % (self.live_server_url,
     439            '/admin/admin_inlines/titlecollection/add/'))
     440
     441        # Add a few inlines
     442        self.selenium.find_element_by_link_text('Add another Title').click()
     443        self.selenium.find_element_by_link_text('Add another Title').click()
     444        self.selenium.find_element_by_link_text('Add another Title').click()
     445        self.selenium.find_element_by_link_text('Add another Title').click()
     446        self.failUnlessEqual(len(self.selenium.find_elements_by_css_selector(
     447            '#title_set-group table tr.dynamic-title_set')), 5)
     448        self.failUnlessEqual(len(self.selenium.find_elements_by_css_selector(
     449            'form#titlecollection_form tr.dynamic-title_set#title_set-0')), 1)
     450        self.failUnlessEqual(len(self.selenium.find_elements_by_css_selector(
     451            'form#titlecollection_form tr.dynamic-title_set#title_set-1')), 1)
     452        self.failUnlessEqual(len(self.selenium.find_elements_by_css_selector(
     453            'form#titlecollection_form tr.dynamic-title_set#title_set-2')), 1)
     454        self.failUnlessEqual(len(self.selenium.find_elements_by_css_selector(
     455            'form#titlecollection_form tr.dynamic-title_set#title_set-3')), 1)
     456        self.failUnlessEqual(len(self.selenium.find_elements_by_css_selector(
     457            'form#titlecollection_form tr.dynamic-title_set#title_set-4')), 1)
     458
     459        # Click on a few delete buttons
     460        self.selenium.find_element_by_css_selector(
     461            'form#titlecollection_form tr.dynamic-title_set#title_set-1 td.delete a').click()
     462        self.selenium.find_element_by_css_selector(
     463            'form#titlecollection_form tr.dynamic-title_set#title_set-2 td.delete a').click()
     464        # Verify that they're gone and that the IDs have been re-sequenced
     465        self.failUnlessEqual(len(self.selenium.find_elements_by_css_selector(
     466            '#title_set-group table tr.dynamic-title_set')), 3)
     467        self.failUnlessEqual(len(self.selenium.find_elements_by_css_selector(
     468            'form#titlecollection_form tr.dynamic-title_set#title_set-0')), 1)
     469        self.failUnlessEqual(len(self.selenium.find_elements_by_css_selector(
     470            'form#titlecollection_form tr.dynamic-title_set#title_set-1')), 1)
     471        self.failUnlessEqual(len(self.selenium.find_elements_by_css_selector(
     472            'form#titlecollection_form tr.dynamic-title_set#title_set-2')), 1)
     473
     474class SeleniumInternetExplorerTests(SeleniumFirefoxTests):
     475    webdriver_class = 'selenium.webdriver.ie.webdriver.WebDriver'
     476 No newline at end of file
  • tests/regressiontests/admin_widgets/tests.py

    diff --git a/tests/regressiontests/admin_widgets/tests.py b/tests/regressiontests/admin_widgets/tests.py
    index 08a1a59..a4b2bf4 100644
    a b from django import forms  
    77from django.conf import settings
    88from django.contrib import admin
    99from django.contrib.admin import widgets
     10from django.contrib.admin.tests import AdminSeleniumWebDriverTestCase
    1011from django.core.files.storage import default_storage
    1112from django.core.files.uploadedfile import SimpleUploadedFile
    1213from django.db.models import DateField
    class RelatedFieldWidgetWrapperTests(DjangoTestCase):  
    372373        # Used to fail with a name error.
    373374        w = widgets.RelatedFieldWidgetWrapper(w, rel, widget_admin_site)
    374375        self.assertFalse(w.can_add_related)
     376
     377
     378class SeleniumFirefoxTests(AdminSeleniumWebDriverTestCase):
     379    webdriver_class = 'selenium.webdriver.firefox.webdriver.WebDriver'
     380    fixtures = ['admin-widgets-users.xml']
     381    urls = "regressiontests.admin_widgets.urls"
     382
     383    def test_show_hide_date_time_picker_widgets(self):
     384        """
     385        Ensure that pressing the ESC key closes the date and time picker
     386        widgets.
     387        Refs #17064.
     388        """
     389        from selenium.webdriver.common.keys import Keys
     390
     391        self.admin_login(username='super', password='secret', login_url='/')
     392        # Open a page that has a date and time picker widgets
     393        self.selenium.get('%s%s' % (self.live_server_url,
     394            '/admin_widgets/member/add/'))
     395
     396        # First, with the date picker widget ---------------------------------
     397        # Check that the date picker is hidden
     398        self.assertEqual(
     399            self.get_css_value('#calendarbox0', 'display'), 'none')
     400        # Click the calendar icon
     401        self.selenium.find_element_by_id('calendarlink0').click()
     402        # Check that the date picker is visible
     403        self.assertEqual(
     404            self.get_css_value('#calendarbox0', 'display'), 'block')
     405        # Press the ESC key
     406        self.selenium.find_element_by_tag_name('html').send_keys([Keys.ESCAPE])
     407        # Check that the date picker is hidden again
     408        self.assertEqual(
     409            self.get_css_value('#calendarbox0', 'display'), 'none')
     410
     411        # Then, with the time picker widget ----------------------------------
     412        # Check that the time picker is hidden
     413        self.assertEqual(
     414            self.get_css_value('#clockbox0', 'display'), 'none')
     415        # Click the time icon
     416        self.selenium.find_element_by_id('clocklink0').click()
     417        # Check that the time picker is visible
     418        self.assertEqual(
     419            self.get_css_value('#clockbox0', 'display'), 'block')
     420        # Press the ESC key
     421        self.selenium.find_element_by_tag_name('html').send_keys([Keys.ESCAPE])
     422        # Check that the time picker is hidden again
     423        self.assertEqual(
     424            self.get_css_value('#clockbox0', 'display'), 'none')
     425
     426class SeleniumInternetExplorerTests(SeleniumFirefoxTests):
     427    webdriver_class = 'selenium.webdriver.ie.webdriver.WebDriver'
     428 No newline at end of file
  • tests/regressiontests/live_server_tests/models.py

    diff --git a/tests/regressiontests/live_server_tests/models.py b/tests/regressiontests/live_server_tests/models.py
    index e69de29..6e1414a 100644
    a b  
     1from django.db import models
     2
     3
     4class Person(models.Model):
     5    name = models.CharField(max_length=256)
  • tests/regressiontests/live_server_tests/tests.py

    diff --git a/tests/regressiontests/live_server_tests/tests.py b/tests/regressiontests/live_server_tests/tests.py
    index e69de29..5e431b9 100644
    a b  
     1import os
     2import urllib2
     3
     4from django.conf import settings
     5from django.test import LiveServerTestCase
     6from django.test.utils import override_settings
     7
     8from .models import Person
     9
     10
     11TEST_ROOT = os.path.dirname(__file__)
     12TEST_SETTINGS = {
     13    'MEDIA_URL': '/media/',
     14    'MEDIA_ROOT': os.path.join(TEST_ROOT, 'media'),
     15}
     16
     17
     18class LiveServerTestBase(LiveServerTestCase):
     19    urls = 'regressiontests.live_server_tests.urls'
     20    fixtures = ['testdata.json']
     21
     22    def urlopen(self, url):
     23        base = 'http://%s:%s' % (settings.LIVE_TEST_SERVER_HOST,
     24                                 settings.LIVE_TEST_SERVER_PORT)
     25        return urllib2.urlopen(base + url)
     26
     27
     28class TestViews(LiveServerTestBase):
     29    def test_404(self):
     30        """
     31        Ensure that the LiveServerTestCase serves 404s.
     32        """
     33        try:
     34            self.urlopen('/')
     35        except urllib2.HTTPError, err:
     36            self.assertEquals(err.code, 404, 'Expected 404 response')
     37        else:
     38            self.fail('Expected 404 response')
     39
     40    def test_view(self):
     41        """
     42        Ensure that the LiveServerTestCase serves views.
     43        """
     44        f = self.urlopen('/example_view/')
     45        self.assertEquals(f.read(), 'example view')
     46
     47    def test_static_file(self):
     48        """
     49        Ensure that the LiveServerTestCase serves static files.
     50        """
     51        f = self.urlopen('/static/example_file.txt')
     52        self.assertEquals(f.read(), 'example file\n')
     53
     54    def test_media_files(self):
     55        """
     56        Ensure that the LiveServerTestCase serves media files.
     57        """
     58        f = self.urlopen('/media/example_media_file.txt')
     59        self.assertEquals(f.read(), 'example media file\n')
     60
     61TestViews = override_settings(**TEST_SETTINGS)(TestViews)
     62
     63
     64class TestDatabase(LiveServerTestBase):
     65    def test_fixtures_loaded(self):
     66        """
     67        Ensure that fixtures are properly loaded and visible to the
     68        live server thread.
     69        """
     70        f = self.urlopen('/model_view/')
     71        self.assertEquals(f.read().splitlines(), ['jane', 'robert'])
     72
     73    def test_database_writes(self):
     74        """
     75        Ensure that data written to the database by a view can be read.
     76        """
     77        self.urlopen('/create_model_instance/')
     78        names = [person.name for person in Person.objects.all()]
     79        self.assertEquals(names, ['jane', 'robert', 'emily'])
     80
     81
     82class TestDatabaseIsolation(LiveServerTestBase):
     83    urls = 'regressiontests.live_server_tests.urls'
     84    fixtures = ['testdata.json']
     85
     86    def urlopen(self, url):
     87        return urllib2.urlopen('http://localhost:8081' + url)
     88
     89    def test_data_seperation_1(self):
     90        """
     91        Ensure destructive operations on the database are isolated between
     92        tests.  Both test_data_seperation_1 and test_data_seperation_2
     93        must run.
     94        """
     95        f = self.urlopen('/model_view/')
     96        self.assertEquals(f.read().splitlines(), ['jane', 'robert'])
     97        self.urlopen('/create_model_instance/')
     98        f = self.urlopen('/model_view/')
     99        self.assertEquals(f.read().splitlines(), ['jane', 'robert', 'emily'])
     100
     101    def test_data_seperation_2(self):
     102        f = self.urlopen('/model_view/')
     103        self.assertEquals(f.read().splitlines(), ['jane', 'robert'])
     104        self.urlopen('/create_model_instance/')
     105        f = self.urlopen('/model_view/')
     106        self.assertEquals(f.read().splitlines(), ['jane', 'robert', 'emily'])
  • tests/regressiontests/live_server_tests/urls.py

    diff --git a/tests/regressiontests/live_server_tests/urls.py b/tests/regressiontests/live_server_tests/urls.py
    index e69de29..83f757f 100644
    a b  
     1from __future__ import absolute_import
     2
     3from django.conf.urls import patterns, url
     4
     5from . import views
     6
     7
     8urlpatterns = patterns('',
     9    url(r'^example_view/$', views.example_view),
     10    url(r'^model_view/$', views.model_view),
     11    url(r'^create_model_instance/$', views.create_model_instance),
     12)
  • tests/regressiontests/live_server_tests/views.py

    diff --git a/tests/regressiontests/live_server_tests/views.py b/tests/regressiontests/live_server_tests/views.py
    index e69de29..42fafe0 100644
    a b  
     1from django.http import HttpResponse
     2from .models import Person
     3
     4
     5def example_view(request):
     6    return HttpResponse('example view')
     7
     8
     9def model_view(request):
     10    people = Person.objects.all()
     11    return HttpResponse('\n'.join([person.name for person in people]))
     12
     13
     14def create_model_instance(request):
     15    person = Person(name='emily')
     16    person.save()
     17    return HttpResponse('')
Back to Top