Ticket #2879: 2879.selenium-support.7.diff
File 2879.selenium-support.7.diff, 32.1 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 0aee63d..da9d030 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..8a09604
- + 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)) 45 No newline at end of file -
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..4e69b48 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, … … from django.test.utils import (get_warnings_state, restore_warnings_state, 23 30 override_settings) 24 31 from django.utils import simplejson, unittest as ut2 25 32 from django.utils.encoding import smart_str 33 from django.views.static import serve 26 34 27 35 __all__ = ('DocTestRunner', 'OutputChecker', 'TestCase', 'TransactionTestCase', 28 36 'SimpleTestCase', 'skipIfDBFeature', 'skipUnlessDBFeature') … … def skipUnlessDBFeature(feature): 732 740 """ 733 741 return _deferredSkip(lambda: not getattr(connection.features, feature), 734 742 "Database doesn't support feature %s" % feature) 743 744 class QuietWSGIRequestHandler(WSGIRequestHandler): 745 """ 746 Just a regular WSGIRequestHandler except it doesn't log to the standard 747 output any of the requests received, so as to not clutter the output for 748 the tests' results. 749 """ 750 def log_message(*args): 751 pass 752 753 class StoppableWSGIServer(WSGIServer): 754 """ 755 The code in this class is borrowed from the `SocketServer.BaseServer` class 756 in Python 2.6. The important functionality here is that the server is non- 757 blocking and that it can be shut down at any moment. This is made possible 758 by the server regularly polling the socket and checking if it has been 759 asked to stop. 760 Note for the future: Once Django stops supporting Python 2.5, this class 761 can be removed as `WSGIServer` will have this ability to shutdown on 762 demand. 763 """ 764 765 def __init__(self, *args, **kwargs): 766 super(StoppableWSGIServer, self).__init__(*args, **kwargs) 767 self.__is_shut_down = threading.Event() 768 self.__serving = False 769 770 def serve_forever(self, poll_interval=0.5): 771 """Handle one request at a time until shutdown. 772 773 Polls for shutdown every poll_interval seconds. 774 """ 775 self.__serving = True 776 self.__is_shut_down.clear() 777 while self.__serving: 778 r, w, e = select.select([self], [], [], poll_interval) 779 if r: 780 self._handle_request_noblock() 781 self.__is_shut_down.set() 782 783 def shutdown(self): 784 """Stops the serve_forever loop. 785 786 Blocks until the loop has finished. This must be called while 787 serve_forever() is running in another thread, or it will 788 deadlock. 789 """ 790 self.__serving = False 791 self.__is_shut_down.wait() 792 793 def handle_request(self): 794 """Handle one request, possibly blocking. 795 """ 796 fd_sets = select.select([self], [], [], None) 797 if not fd_sets[0]: 798 return 799 self._handle_request_noblock() 800 801 def _handle_request_noblock(self): 802 """Handle one request, without blocking. 803 804 I assume that select.select has returned that the socket is 805 readable before this function was called, so there should be 806 no risk of blocking in get_request(). 807 """ 808 try: 809 request, client_address = self.get_request() 810 except socket.error: 811 return 812 if self.verify_request(request, client_address): 813 try: 814 self.process_request(request, client_address) 815 except Exception: 816 self.handle_error(request, client_address) 817 self.close_request(request) 818 819 class MediaFilesHandler(StaticFilesHandler): 820 """ 821 Handler for serving the media files. 822 """ 823 824 def get_base_dir(self): 825 return settings.MEDIA_ROOT 826 827 def get_base_url(self): 828 return settings.MEDIA_URL 829 830 def serve(self, request): 831 return serve(request, self.file_path(request.path), 832 document_root=self.get_base_dir()) 833 834 class LiveServerThread(threading.Thread): 835 """ 836 Thread for running a live http server while the tests are running. 837 """ 838 839 def __init__(self, address, port): 840 self.address = address 841 self.port = port 842 self.is_ready = threading.Event() 843 self.error = None 844 super(LiveServerThread, self).__init__() 845 846 def run(self): 847 """ 848 Sets up live server and database and loops over handling http requests. 849 """ 850 try: 851 # Instantiate and start the server 852 self.httpd = StoppableWSGIServer( 853 (self.address, self.port), QuietWSGIRequestHandler) 854 handler = StaticFilesHandler(MediaFilesHandler(WSGIHandler())) 855 self.httpd.set_app(handler) 856 self.is_ready.set() 857 self.httpd.serve_forever() 858 except WSGIServerException, e: 859 self.error = e 860 self.is_ready.set() 861 862 def join(self, timeout=None): 863 self.httpd.shutdown() 864 self.httpd.server_close() 865 super(LiveServerThread, self).join(timeout) 866 867 class LiveServerTestCase(TransactionTestCase): 868 """ 869 Does basically the same as TransactionTestCase but also launches a live 870 http server in a separate thread so that the tests may use another testing 871 framework, such as Selenium for example, instead of the built-in dummy 872 client. 873 """ 874 875 @property 876 def live_server_url(self): 877 return 'http://%s:%s' % (settings.LIVE_TEST_SERVER_HOST, 878 settings.LIVE_TEST_SERVER_PORT) 879 880 def setUp(self): 881 for conn in connections.all(): 882 if (conn.settings_dict['ENGINE'] == 'django.db.backends.sqlite3' 883 and conn.settings_dict['NAME'] == ':memory:'): 884 raise ut2.SkipTest('In-memory sqlite databases are not ' 885 'supported by LiveServerTestCase because the memory ' 886 'cannot be shared between threads.') 887 888 # Launch the Django live server's thread 889 self.server_thread = LiveServerThread( 890 settings.LIVE_TEST_SERVER_HOST, 891 int(settings.LIVE_TEST_SERVER_PORT)) 892 self.server_thread.start() 893 894 # Wait for the Django server to be ready 895 self.server_thread.is_ready.wait() 896 if self.server_thread.error: 897 raise self.server_thread.error 898 899 super(LiveServerTestCase, self).setUp() 900 901 def tearDown(self): 902 # Terminate the Django server's thread 903 self.server_thread.join() 904 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..fdf4e81 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.TransactionTestCase` with one extra thing: it launches a 1843 live Django server in the background on setup, and shuts it down on teardown. 1844 This allows 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 37fa7bc..ecf3165 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): 407 408 # Used to fail with a name error. 408 409 w = widgets.RelatedFieldWidgetWrapper(w, rel, widget_admin_site) 409 410 self.assertFalse(w.can_add_related) 411 412 413 class SeleniumFirefoxTests(AdminSeleniumWebDriverTestCase): 414 webdriver_class = 'selenium.webdriver.firefox.webdriver.WebDriver' 415 fixtures = ['admin-widgets-users.xml'] 416 urls = "regressiontests.admin_widgets.urls" 417 418 def test_show_hide_date_time_picker_widgets(self): 419 """ 420 Ensure that pressing the ESC key closes the date and time picker 421 widgets. 422 Refs #17064. 423 """ 424 from selenium.webdriver.common.keys import Keys 425 426 self.admin_login(username='super', password='secret', login_url='/') 427 # Open a page that has a date and time picker widgets 428 self.selenium.get('%s%s' % (self.live_server_url, 429 '/admin_widgets/member/add/')) 430 431 # First, with the date picker widget --------------------------------- 432 # Check that the date picker is hidden 433 self.assertEqual( 434 self.get_css_value('#calendarbox0', 'display'), 'none') 435 # Click the calendar icon 436 self.selenium.find_element_by_id('calendarlink0').click() 437 # Check that the date picker is visible 438 self.assertEqual( 439 self.get_css_value('#calendarbox0', 'display'), 'block') 440 # Press the ESC key 441 self.selenium.find_element_by_tag_name('html').send_keys([Keys.ESCAPE]) 442 # Check that the date picker is hidden again 443 self.assertEqual( 444 self.get_css_value('#calendarbox0', 'display'), 'none') 445 446 # Then, with the time picker widget ---------------------------------- 447 # Check that the time picker is hidden 448 self.assertEqual( 449 self.get_css_value('#clockbox0', 'display'), 'none') 450 # Click the time icon 451 self.selenium.find_element_by_id('clocklink0').click() 452 # Check that the time picker is visible 453 self.assertEqual( 454 self.get_css_value('#clockbox0', 'display'), 'block') 455 # Press the ESC key 456 self.selenium.find_element_by_tag_name('html').send_keys([Keys.ESCAPE]) 457 # Check that the time picker is hidden again 458 self.assertEqual( 459 self.get_css_value('#clockbox0', 'display'), 'none') 460 461 class SeleniumInternetExplorerTests(SeleniumFirefoxTests): 462 webdriver_class = 'selenium.webdriver.ie.webdriver.WebDriver' 463 No newline at end of file -
new file tests/regressiontests/live_server/fixtures/testdata.json
diff --git a/tests/regressiontests/live_server/__init__.py b/tests/regressiontests/live_server/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/regressiontests/live_server/fixtures/testdata.json b/tests/regressiontests/live_server/fixtures/testdata.json new file mode 100644 index 0000000..e987a04
- + 1 [ 2 { 3 "pk": 1, 4 "model": "live_server.person", 5 "fields": { 6 "name": "jane" 7 } 8 }, 9 { 10 "pk": 2, 11 "model": "live_server.person", 12 "fields": { 13 "name": "robert" 14 } 15 } 16 ] 17 No newline at end of file -
new file tests/regressiontests/live_server/media/example_media_file.txt
diff --git a/tests/regressiontests/live_server/media/example_media_file.txt b/tests/regressiontests/live_server/media/example_media_file.txt new file mode 100644 index 0000000..dd2dda9
- + 1 example media file -
new file tests/regressiontests/live_server/models.py
diff --git a/tests/regressiontests/live_server/models.py b/tests/regressiontests/live_server/models.py new file mode 100644 index 0000000..6e1414a
- + 1 from django.db import models 2 3 4 class Person(models.Model): 5 name = models.CharField(max_length=256) -
new file tests/regressiontests/live_server/static/example_file.txt
diff --git a/tests/regressiontests/live_server/static/example_file.txt b/tests/regressiontests/live_server/static/example_file.txt new file mode 100644 index 0000000..5f1cfce
- + 1 example file -
new file tests/regressiontests/live_server/tests.py
diff --git a/tests/regressiontests/live_server/tests.py b/tests/regressiontests/live_server/tests.py new file mode 100644 index 0000000..67acf5d
- + 1 import os 2 import urllib2 3 4 from django.conf import settings 5 from django.test import LiveServerTestCase 6 from django.test.utils import override_settings 7 8 from .models import Person 9 10 11 TEST_ROOT = os.path.dirname(__file__) 12 TEST_SETTINGS = { 13 'MEDIA_URL': '/media/', 14 'MEDIA_ROOT': os.path.join(TEST_ROOT, 'media'), 15 'STATIC_URL': '/static/', 16 'STATIC_ROOT': os.path.join(TEST_ROOT, 'static'), 17 } 18 19 20 class LiveServerTestBase(LiveServerTestCase): 21 urls = 'regressiontests.live_server.urls' 22 fixtures = ['testdata.json'] 23 24 def urlopen(self, url): 25 base = 'http://%s:%s' % (settings.LIVE_TEST_SERVER_HOST, 26 settings.LIVE_TEST_SERVER_PORT) 27 return urllib2.urlopen(base + url) 28 29 30 class TestViews(LiveServerTestBase): 31 def test_404(self): 32 """ 33 Ensure that the LiveServerTestCase serves 404s. 34 """ 35 try: 36 self.urlopen('/') 37 except urllib2.HTTPError, err: 38 self.assertEquals(err.code, 404, 'Expected 404 response') 39 else: 40 self.fail('Expected 404 response') 41 42 def test_view(self): 43 """ 44 Ensure that the LiveServerTestCase serves views. 45 """ 46 f = self.urlopen('/example_view/') 47 self.assertEquals(f.read(), 'example view') 48 49 def test_static_file(self): 50 """ 51 Ensure that the LiveServerTestCase serves static files. 52 """ 53 f = self.urlopen('/static/example_file.txt') 54 self.assertEquals(f.read(), 'example file\n') 55 56 def test_media_files(self): 57 """ 58 Ensure that the LiveServerTestCase serves media files. 59 """ 60 f = self.urlopen('/media/example_media_file.txt') 61 self.assertEquals(f.read(), 'example media file\n') 62 63 TestViews = override_settings(**TEST_SETTINGS)(TestViews) 64 65 66 class TestDatabase(LiveServerTestBase): 67 68 def test_fixtures_loaded(self): 69 """ 70 Ensure that fixtures are properly loaded and visible to the 71 live server thread. 72 """ 73 import pdb; pdb.set_trace() 74 f = self.urlopen('/model_view/') 75 self.assertEquals(f.read().splitlines(), ['jane', 'robert']) 76 77 def test_database_writes(self): 78 """ 79 Ensure that data written to the database by a view can be read. 80 """ 81 self.urlopen('/create_model_instance/') 82 names = [person.name for person in Person.objects.all()] 83 self.assertEquals(names, ['jane', 'robert', 'emily']) -
new file tests/regressiontests/live_server/urls.py
diff --git a/tests/regressiontests/live_server/urls.py b/tests/regressiontests/live_server/urls.py new file mode 100644 index 0000000..83f757f
- + 1 from __future__ import absolute_import 2 3 from django.conf.urls import patterns, url 4 5 from . import views 6 7 8 urlpatterns = 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 ) -
new file tests/regressiontests/live_server/views.py
diff --git a/tests/regressiontests/live_server/views.py b/tests/regressiontests/live_server/views.py new file mode 100644 index 0000000..bfc7513
- + 1 from django.http import HttpResponse 2 from .models import Person 3 4 5 def example_view(request): 6 return HttpResponse('example view') 7 8 9 def model_view(request): 10 people = Person.objects.all() 11 import pdb; pdb.set_trace() 12 return HttpResponse('\n'.join([person.name for person in people])) 13 14 15 def create_model_instance(request): 16 person = Person(name='emily') 17 person.save() 18 return HttpResponse('')