Ticket #2879: 2879.selenium-support.6.diff
File 2879.selenium-support.6.diff, 26.9 KB (added by , 13 years ago) |
---|
-
django/conf/global_settings.py
diff --git a/django/conf/global_settings.py b/django/conf/global_settings.py index 2ef2f63..b10373f 100644
a b DEFAULT_EXCEPTION_REPORTER_FILTER = 'django.views.debug.SafeExceptionReporterFil 565 565 # The name of the class to use to run the test suite 566 566 TEST_RUNNER = 'django.test.simple.DjangoTestSuiteRunner' 567 567 568 # For the live test server (e.g. used for running Selenium tests) 569 LIVE_TEST_SERVER_HOST = 'localhost' 570 LIVE_TEST_SERVER_PORT = 8081 571 568 572 ############ 569 573 # FIXTURES # 570 574 ############ -
new file django/contrib/admin/tests.py
diff --git a/django/contrib/admin/tests.py b/django/contrib/admin/tests.py new file mode 100644 index 0000000..bdb84c5
- + 1 from django.test import LiveServerTestCase 2 from django.utils.importlib import import_module 3 from django.utils.unittest import SkipTest 4 5 class AdminSeleniumWebDriverTestCase(LiveServerTestCase): 6 7 webdriver_class = 'selenium.webdriver.firefox.webdriver.WebDriver' 8 9 def setUp(self): 10 try: 11 # Import and start the WebDriver class. 12 module, attr = self.webdriver_class.rsplit('.', 1) 13 mod = import_module(module) 14 WebDriver = getattr(mod, attr) 15 self.selenium = WebDriver() 16 except Exception: 17 raise SkipTest('Selenium webdriver "%s" not installed or not ' 18 'operational.' % self.webdriver_class) 19 super(AdminSeleniumWebDriverTestCase, self).setUp() 20 21 def tearDown(self): 22 super(AdminSeleniumWebDriverTestCase, self).tearDown() 23 if hasattr(self, 'selenium'): 24 self.selenium.quit() 25 26 def admin_login(self, username, password, login_url='/admin/'): 27 """ 28 Helper function to log into the admin. 29 """ 30 self.selenium.get('%s%s' % (self.live_server_url, login_url)) 31 username_input = self.selenium.find_element_by_name("username") 32 username_input.send_keys(username) 33 password_input = self.selenium.find_element_by_name("password") 34 password_input.send_keys(password) 35 self.selenium.find_element_by_xpath('//input[@value="Log in"]').click() 36 37 def get_css_value(self, selector, attribute): 38 """ 39 Helper function that returns the value for the CSS attribute of an 40 DOM element specified by the given selector. Uses the jQuery that ships 41 with Django. 42 """ 43 return self.selenium.execute_script( 44 'return django.jQuery("%s").css("%s")' % (selector, attribute)) -
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. 4 4 5 5 from django.test.client import Client, RequestFactory 6 6 from django.test.testcases import (TestCase, TransactionTestCase, 7 SimpleTestCase, skipIfDBFeature, skipUnlessDBFeature) 7 SimpleTestCase, LiveServerTestCase, skipIfDBFeature, 8 skipUnlessDBFeature) 8 9 from 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 5 5 from functools import wraps 6 6 from urlparse import urlsplit, urlunsplit 7 7 from xml.dom.minidom import parseString, Node 8 import select 9 import socket 10 import threading 8 11 9 12 from django.conf import settings 13 from django.contrib.staticfiles.handlers import StaticFilesHandler 10 14 from django.core import mail 11 15 from django.core.exceptions import ValidationError 16 from django.core.handlers.wsgi import WSGIHandler 12 17 from django.core.management import call_command 13 18 from django.core.signals import request_started 19 from django.core.servers.basehttp import (WSGIRequestHandler, WSGIServer, 20 WSGIServerException) 14 21 from django.core.urlresolvers import clear_url_caches 15 22 from django.core.validators import EMPTY_VALUES 16 23 from django.db import (transaction, connection, connections, DEFAULT_DB_ALIAS, … … class TransactionTestCase(SimpleTestCase): 364 371 for db in databases: 365 372 call_command('flush', verbosity=0, interactive=False, database=db) 366 373 367 if hasattr(self, 'fixtures'):374 if getattr(self, 'fixtures', None): 368 375 # We have to use this slightly awkward syntax due to the fact 369 376 # that we're using *args and **kwargs together. 370 377 call_command('loaddata', *self.fixtures, … … class TestCase(TransactionTestCase): 679 686 Site.objects.clear_cache() 680 687 681 688 for db in databases: 682 if hasattr(self, 'fixtures'):689 if getattr(self, 'fixtures', None): 683 690 call_command('loaddata', *self.fixtures, 684 691 **{ 685 692 'verbosity': 0, … … def skipUnlessDBFeature(feature): 732 739 """ 733 740 return _deferredSkip(lambda: not getattr(connection.features, feature), 734 741 "Database doesn't support feature %s" % feature) 742 743 class 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 752 class 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 818 class 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 862 class 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: 122 122 123 123 ./runtests.py --settings=path.to.settings i18n.TranslationTests.test_lazy_objects 124 124 125 Running the Selenium tests 126 ~~~~~~~~~~~~~~~~~~~~~~~~~~ 127 128 Some admin tests require Selenium 2 to work via a real Web browser. To allow 129 those tests to run and not be skipped, you must install the selenium_ package 130 (version > 2.13) into your Python path. 131 132 Then, run the tests normally, for example: 133 134 .. code-block:: bash 135 136 ./runtests.py --settings=test_sqlite admin_inlines 137 125 138 Running all the tests 126 139 ~~~~~~~~~~~~~~~~~~~~~ 127 140 … … dependencies: 135 148 * setuptools_ 136 149 * memcached_, plus a :ref:`supported Python binding <memcached>` 137 150 * gettext_ (:ref:`gettext_on_windows`) 151 * selenium_ 138 152 139 153 If you want to test the memcached cache backend, you'll also need to define 140 154 a :setting:`CACHES` setting that points at your memcached instance. … … associated tests will be skipped. 149 163 .. _setuptools: http://pypi.python.org/pypi/setuptools/ 150 164 .. _memcached: http://www.danga.com/memcached/ 151 165 .. _gettext: http://www.gnu.org/software/gettext/manual/gettext.html 166 .. _selenium: http://pypi.python.org/pypi/selenium 152 167 153 168 .. _contrib-apps: 154 169 -
docs/ref/settings.txt
diff --git a/docs/ref/settings.txt b/docs/ref/settings.txt index a35d99a..89f2c47 100644
a b all cache keys used by the Django server. 195 195 196 196 See the :ref:`cache documentation <cache_key_prefixing>` for more information. 197 197 198 .. setting:: LIVE_TEST_SERVER_HOST 199 200 LIVE_TEST_SERVER_HOST 201 ~~~~~~~~~~~~~~~~~~~~~ 202 203 Default: ``'localhost'`` 204 205 Controls the host address at which the live test server gets started when using 206 a :class:`~django.test.LiveServerTestCase`. 207 208 See also: :setting:`LIVE_TEST_SERVER_PORT` 209 210 .. setting:: LIVE_TEST_SERVER_PORT 211 212 LIVE_TEST_SERVER_PORT 213 ~~~~~~~~~~~~~~~~~~~~~ 214 215 Default: ``8081`` 216 217 Controls the port at which the live test server gets started when using 218 a :class:`~django.test.LiveServerTestCase`. 219 220 See also: :setting:`LIVE_TEST_SERVER_HOST` 221 198 222 .. setting:: CACHES-LOCATION 199 223 200 224 LOCATION -
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: 580 580 * Test that a given request is rendered by a given Django template, with 581 581 a template context that contains certain values. 582 582 583 Note that the test client is not intended to be a replacement for Twill_,583 Note that the test client is not intended to be a replacement for Windmill_, 584 584 Selenium_, or other "in-browser" frameworks. Django's test client has 585 585 a different focus. In short: 586 586 587 587 * Use Django's test client to establish that the correct view is being 588 588 called and that the view is collecting the correct context data. 589 589 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. 592 594 593 595 A comprehensive test suite should use a combination of both test types. 594 596 595 .. _Twill: http://twill.idyll.org/596 .. _Selenium: http://seleniumhq.org/597 598 597 Overview and a quick example 599 598 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 600 599 … … set up, execute and tear down the test suite. 1830 1829 those options will be added to the list of command-line options that 1831 1830 the :djadmin:`test` command can use. 1832 1831 1832 Live 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 1843 server in the background on setup, and shuts it down on teardown. This allows 1844 to use other automated test clients than the 1845 :ref:`Django dummy client <test-client>` such as, for example, the Selenium_ or 1846 Windmill_ clients, to execute a series of functional tests inside a browser and 1847 simulate a real user's actions. 1848 1849 You may control which host and port the live server will run at with 1850 respectively the :setting:`LIVE_TEST_SERVER_HOST` and 1851 :setting:`LIVE_TEST_SERVER_PORT` settings. The full server url can then be 1852 accessed during the tests with ``self.live_server_url``. 1853 1854 To demonstrate how to use ``LiveServerTestCase``, let's write a simple Selenium 1855 test. First of all, you need to install the `selenium package`_ into your 1856 Python path: 1857 1858 .. code-block:: bash 1859 1860 pip install selenium 1861 1862 Then, 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 1889 Finally, you may run the test as follows: 1890 1891 .. code-block:: bash 1892 1893 ./manage.py test myapp.MySeleniumTests.test_login 1894 1895 This example will automatically open Firefox then go to the login page, enter 1896 the credentials and press the "Log in" button. Selenium offers other drivers in 1897 case you do not have Firefox installed or wish to use another browser. The 1898 example above is just a tiny fraction of what the Selenium client can do; check 1899 out 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/ 1833 1906 1834 1907 Attributes 1835 1908 ~~~~~~~~~~ 1836 1909 1837 1838 1910 .. attribute:: DjangoTestSuiteRunner.option_list 1839 1911 1840 1912 .. versionadded:: 1.4 -
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 1 1 from __future__ import absolute_import 2 2 3 from django.contrib.admin.tests import AdminSeleniumWebDriverTestCase 3 4 from django.contrib.admin.helpers import InlineAdminForm 4 5 from django.contrib.auth.models import User, Permission 5 6 from django.contrib.contenttypes.models import ContentType … … class TestInlinePermissions(TestCase): 380 381 self.assertContains(response, 'value="4" id="id_inner2_set-TOTAL_FORMS"') 381 382 self.assertContains(response, '<input type="hidden" name="inner2_set-0-id" value="%i"' % self.inner2_id) 382 383 self.assertContains(response, 'id="id_inner2_set-0-DELETE"') 384 385 class 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 474 class 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 7 7 from django.conf import settings 8 8 from django.contrib import admin 9 9 from django.contrib.admin import widgets 10 from django.contrib.admin.tests import AdminSeleniumWebDriverTestCase 10 11 from django.core.files.storage import default_storage 11 12 from django.core.files.uploadedfile import SimpleUploadedFile 12 13 from django.db.models import DateField … … class RelatedFieldWidgetWrapperTests(DjangoTestCase): 372 373 # Used to fail with a name error. 373 374 w = widgets.RelatedFieldWidgetWrapper(w, rel, widget_admin_site) 374 375 self.assertFalse(w.can_add_related) 376 377 378 class 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 426 class SeleniumInternetExplorerTests(SeleniumFirefoxTests): 427 webdriver_class = 'selenium.webdriver.ie.webdriver.WebDriver' 428 No newline at end of file