2014-05-16 01:41:55 +08:00
|
|
|
# -*- coding: utf-8 -*-
|
2013-07-30 01:19:04 +08:00
|
|
|
from __future__ import unicode_literals
|
2010-09-12 02:34:40 +08:00
|
|
|
|
2014-04-16 03:01:55 +08:00
|
|
|
import gettext
|
|
|
|
import os
|
2015-01-28 20:35:27 +08:00
|
|
|
from datetime import datetime, timedelta
|
|
|
|
from importlib import import_module
|
2013-11-03 07:57:35 +08:00
|
|
|
from unittest import TestCase, skipIf
|
|
|
|
|
2009-01-16 23:32:31 +08:00
|
|
|
from django import forms
|
2010-10-15 10:35:51 +08:00
|
|
|
from django.conf import settings
|
2009-01-16 23:32:31 +08:00
|
|
|
from django.contrib import admin
|
|
|
|
from django.contrib.admin import widgets
|
Fixed #2879 -- Added support for the integration with Selenium and other in-browser testing frameworks. Also added the first Selenium tests for `contrib.admin`. Many thanks to everyone for their contributions and feedback: Mikeal Rogers, Dirk Datzert, mir, Simon G., Almad, Russell Keith-Magee, Denis Golomazov, devin, robertrv, andrewbadr, Idan Gazit, voidspace, Tom Christie, hjwp2, Adam Nelson, Jannis Leidel, Anssi Kääriäinen, Preston Holmes, Bruno Renié and Jacob Kaplan-Moss.
git-svn-id: http://code.djangoproject.com/svn/django/trunk@17241 bcc190cf-cafb-0310-a4f2-bffc1f526a37
2011-12-22 16:33:58 +08:00
|
|
|
from django.contrib.admin.tests import AdminSeleniumWebDriverTestCase
|
2010-10-15 10:35:51 +08:00
|
|
|
from django.core.files.storage import default_storage
|
|
|
|
from django.core.files.uploadedfile import SimpleUploadedFile
|
2015-02-07 06:25:15 +08:00
|
|
|
from django.core.urlresolvers import reverse
|
2012-12-08 19:41:11 +08:00
|
|
|
from django.db.models import CharField, DateField
|
2015-01-28 20:35:27 +08:00
|
|
|
from django.test import TestCase as DjangoTestCase, override_settings
|
|
|
|
from django.utils import six, translation
|
2010-10-11 20:55:17 +08:00
|
|
|
|
2011-10-14 02:51:33 +08:00
|
|
|
from . import models
|
|
|
|
from .widgetadmin import site as widget_admin_site
|
|
|
|
|
2015-01-28 20:35:27 +08:00
|
|
|
try:
|
|
|
|
import pytz
|
|
|
|
except ImportError:
|
|
|
|
pytz = None
|
2009-01-16 23:32:31 +08:00
|
|
|
|
2012-04-09 05:13:32 +08:00
|
|
|
admin_static_prefix = lambda: {
|
|
|
|
'ADMIN_STATIC_PREFIX': "%sadmin/" % settings.STATIC_URL,
|
2011-06-30 17:06:19 +08:00
|
|
|
}
|
2010-10-15 10:35:51 +08:00
|
|
|
|
2013-11-03 12:36:09 +08:00
|
|
|
|
2009-01-16 23:32:31 +08:00
|
|
|
class AdminFormfieldForDBFieldTests(TestCase):
|
|
|
|
"""
|
|
|
|
Tests for correct behavior of ModelAdmin.formfield_for_dbfield
|
|
|
|
"""
|
|
|
|
|
|
|
|
def assertFormfield(self, model, fieldname, widgetclass, **admin_overrides):
|
|
|
|
"""
|
|
|
|
Helper to call formfield_for_dbfield for a given model and field name
|
|
|
|
and verify that the returned formfield is appropriate.
|
|
|
|
"""
|
|
|
|
# Override any settings on the model admin
|
2010-11-23 05:55:29 +08:00
|
|
|
class MyModelAdmin(admin.ModelAdmin):
|
|
|
|
pass
|
2009-01-16 23:32:31 +08:00
|
|
|
for k in admin_overrides:
|
|
|
|
setattr(MyModelAdmin, k, admin_overrides[k])
|
2009-01-17 05:18:21 +08:00
|
|
|
|
2009-01-16 23:32:31 +08:00
|
|
|
# Construct the admin, and ask it for a formfield
|
|
|
|
ma = MyModelAdmin(model, admin.site)
|
|
|
|
ff = ma.formfield_for_dbfield(model._meta.get_field(fieldname), request=None)
|
2009-01-17 05:18:21 +08:00
|
|
|
|
2009-01-16 23:32:31 +08:00
|
|
|
# "unwrap" the widget wrapper, if needed
|
|
|
|
if isinstance(ff.widget, widgets.RelatedFieldWidgetWrapper):
|
|
|
|
widget = ff.widget.widget
|
|
|
|
else:
|
|
|
|
widget = ff.widget
|
2009-01-17 05:18:21 +08:00
|
|
|
|
2009-01-16 23:32:31 +08:00
|
|
|
# Check that we got a field of the right type
|
2011-03-03 23:04:39 +08:00
|
|
|
self.assertTrue(
|
2009-01-17 05:18:21 +08:00
|
|
|
isinstance(widget, widgetclass),
|
2013-10-20 07:33:10 +08:00
|
|
|
"Wrong widget for %s.%s: expected %s, got %s" % (
|
|
|
|
model.__class__.__name__,
|
|
|
|
fieldname,
|
|
|
|
widgetclass,
|
|
|
|
type(widget),
|
|
|
|
)
|
2009-01-16 23:32:31 +08:00
|
|
|
)
|
2009-01-17 05:18:21 +08:00
|
|
|
|
2009-01-16 23:32:31 +08:00
|
|
|
# Return the formfield so that other tests can continue
|
|
|
|
return ff
|
2009-01-17 05:18:21 +08:00
|
|
|
|
2014-07-08 07:08:42 +08:00
|
|
|
def test_DateField(self):
|
2009-01-17 05:18:21 +08:00
|
|
|
self.assertFormfield(models.Event, 'start_date', widgets.AdminDateWidget)
|
|
|
|
|
2014-07-08 07:08:42 +08:00
|
|
|
def test_DateTimeField(self):
|
2009-01-16 23:32:31 +08:00
|
|
|
self.assertFormfield(models.Member, 'birthdate', widgets.AdminSplitDateTime)
|
2009-01-17 05:18:21 +08:00
|
|
|
|
2014-07-08 07:08:42 +08:00
|
|
|
def test_TimeField(self):
|
2009-01-16 23:32:31 +08:00
|
|
|
self.assertFormfield(models.Event, 'start_time', widgets.AdminTimeWidget)
|
|
|
|
|
2014-07-08 07:08:42 +08:00
|
|
|
def test_TextField(self):
|
2009-01-16 23:32:31 +08:00
|
|
|
self.assertFormfield(models.Event, 'description', widgets.AdminTextareaWidget)
|
2009-01-17 05:18:21 +08:00
|
|
|
|
2014-07-08 07:08:42 +08:00
|
|
|
def test_URLField(self):
|
2009-01-16 23:32:31 +08:00
|
|
|
self.assertFormfield(models.Event, 'link', widgets.AdminURLFieldWidget)
|
|
|
|
|
2014-07-08 07:08:42 +08:00
|
|
|
def test_IntegerField(self):
|
2009-01-16 23:32:31 +08:00
|
|
|
self.assertFormfield(models.Event, 'min_age', widgets.AdminIntegerFieldWidget)
|
2009-01-17 05:18:21 +08:00
|
|
|
|
2014-07-08 07:08:42 +08:00
|
|
|
def test_CharField(self):
|
2009-01-16 23:32:31 +08:00
|
|
|
self.assertFormfield(models.Member, 'name', widgets.AdminTextInputWidget)
|
2009-01-17 05:18:21 +08:00
|
|
|
|
2014-07-08 07:08:42 +08:00
|
|
|
def test_EmailField(self):
|
2013-07-26 19:22:30 +08:00
|
|
|
self.assertFormfield(models.Member, 'email', widgets.AdminEmailInputWidget)
|
|
|
|
|
2014-07-08 07:08:42 +08:00
|
|
|
def test_FileField(self):
|
2009-01-16 23:32:31 +08:00
|
|
|
self.assertFormfield(models.Album, 'cover_art', widgets.AdminFileWidget)
|
2009-01-17 05:18:21 +08:00
|
|
|
|
2014-07-08 07:08:42 +08:00
|
|
|
def test_ForeignKey(self):
|
2013-08-05 07:06:47 +08:00
|
|
|
self.assertFormfield(models.Event, 'main_band', forms.Select)
|
2009-01-17 05:18:21 +08:00
|
|
|
|
2014-07-08 07:08:42 +08:00
|
|
|
def test_raw_id_ForeignKey(self):
|
2013-08-05 07:06:47 +08:00
|
|
|
self.assertFormfield(models.Event, 'main_band', widgets.ForeignKeyRawIdWidget,
|
|
|
|
raw_id_fields=['main_band'])
|
2009-01-17 05:18:21 +08:00
|
|
|
|
2014-07-08 07:08:42 +08:00
|
|
|
def test_radio_fields_ForeignKey(self):
|
2013-08-05 07:06:47 +08:00
|
|
|
ff = self.assertFormfield(models.Event, 'main_band', widgets.AdminRadioSelect,
|
2013-10-27 03:15:03 +08:00
|
|
|
radio_fields={'main_band': admin.VERTICAL})
|
2009-01-16 23:32:31 +08:00
|
|
|
self.assertEqual(ff.empty_label, None)
|
2009-01-17 05:18:21 +08:00
|
|
|
|
2014-07-08 07:08:42 +08:00
|
|
|
def test_many_to_many(self):
|
2009-01-16 23:32:31 +08:00
|
|
|
self.assertFormfield(models.Band, 'members', forms.SelectMultiple)
|
2009-01-17 05:18:21 +08:00
|
|
|
|
2014-07-08 07:08:42 +08:00
|
|
|
def test_raw_id_many_to_many(self):
|
2009-01-16 23:32:31 +08:00
|
|
|
self.assertFormfield(models.Band, 'members', widgets.ManyToManyRawIdWidget,
|
|
|
|
raw_id_fields=['members'])
|
2009-01-17 05:18:21 +08:00
|
|
|
|
2014-07-08 07:08:42 +08:00
|
|
|
def test_filtered_many_to_many(self):
|
2009-01-16 23:32:31 +08:00
|
|
|
self.assertFormfield(models.Band, 'members', widgets.FilteredSelectMultiple,
|
|
|
|
filter_vertical=['members'])
|
2009-01-17 05:18:21 +08:00
|
|
|
|
2014-07-08 07:08:42 +08:00
|
|
|
def test_formfield_overrides(self):
|
2009-01-17 05:18:21 +08:00
|
|
|
self.assertFormfield(models.Event, 'start_date', forms.TextInput,
|
2009-12-31 06:11:48 +08:00
|
|
|
formfield_overrides={DateField: {'widget': forms.TextInput}})
|
2009-01-17 05:18:21 +08:00
|
|
|
|
2014-07-08 07:08:42 +08:00
|
|
|
def test_formfield_overrides_widget_instances(self):
|
2012-12-08 19:41:11 +08:00
|
|
|
"""
|
|
|
|
Test that widget instances in formfield_overrides are not shared between
|
|
|
|
different fields. (#19423)
|
|
|
|
"""
|
|
|
|
class BandAdmin(admin.ModelAdmin):
|
|
|
|
formfield_overrides = {
|
2013-10-27 03:15:03 +08:00
|
|
|
CharField: {'widget': forms.TextInput(attrs={'size': '10'})}
|
2012-12-08 19:41:11 +08:00
|
|
|
}
|
|
|
|
ma = BandAdmin(models.Band, admin.site)
|
|
|
|
f1 = ma.formfield_for_dbfield(models.Band._meta.get_field('name'), request=None)
|
|
|
|
f2 = ma.formfield_for_dbfield(models.Band._meta.get_field('style'), request=None)
|
|
|
|
self.assertNotEqual(f1.widget, f2.widget)
|
|
|
|
self.assertEqual(f1.widget.attrs['maxlength'], '100')
|
|
|
|
self.assertEqual(f2.widget.attrs['maxlength'], '20')
|
|
|
|
self.assertEqual(f2.widget.attrs['size'], '10')
|
|
|
|
|
2014-07-08 07:08:42 +08:00
|
|
|
def test_field_with_choices(self):
|
2009-01-16 23:32:31 +08:00
|
|
|
self.assertFormfield(models.Member, 'gender', forms.Select)
|
2009-01-17 05:18:21 +08:00
|
|
|
|
2014-07-08 07:08:42 +08:00
|
|
|
def test_choices_with_radio_fields(self):
|
2009-01-17 05:18:21 +08:00
|
|
|
self.assertFormfield(models.Member, 'gender', widgets.AdminRadioSelect,
|
2013-10-27 03:15:03 +08:00
|
|
|
radio_fields={'gender': admin.VERTICAL})
|
2009-01-16 23:32:31 +08:00
|
|
|
|
2014-07-08 07:08:42 +08:00
|
|
|
def test_inheritance(self):
|
2009-04-09 04:25:56 +08:00
|
|
|
self.assertFormfield(models.Album, 'backside_art', widgets.AdminFileWidget)
|
2009-01-16 23:32:31 +08:00
|
|
|
|
2013-05-20 03:28:33 +08:00
|
|
|
def test_m2m_widgets(self):
|
|
|
|
"""m2m fields help text as it applies to admin app (#9321)."""
|
|
|
|
class AdvisorAdmin(admin.ModelAdmin):
|
|
|
|
filter_vertical = ['companies']
|
|
|
|
|
|
|
|
self.assertFormfield(models.Advisor, 'companies', widgets.FilteredSelectMultiple,
|
|
|
|
filter_vertical=['companies'])
|
|
|
|
ma = AdvisorAdmin(models.Advisor, admin.site)
|
|
|
|
f = ma.formfield_for_dbfield(models.Advisor._meta.get_field('companies'), request=None)
|
|
|
|
self.assertEqual(six.text_type(f.help_text), 'Hold down "Control", or "Command" on a Mac, to select more than one.')
|
|
|
|
|
2010-10-15 10:35:51 +08:00
|
|
|
|
2015-01-22 00:55:57 +08:00
|
|
|
@override_settings(PASSWORD_HASHERS=['django.contrib.auth.hashers.SHA1PasswordHasher'],
|
2014-04-05 14:04:46 +08:00
|
|
|
ROOT_URLCONF='admin_widgets.urls')
|
2009-01-16 23:32:31 +08:00
|
|
|
class AdminFormfieldForDBFieldWithRequestTests(DjangoTestCase):
|
|
|
|
fixtures = ["admin-widgets-users.xml"]
|
2009-01-17 05:18:21 +08:00
|
|
|
|
2014-07-08 07:08:42 +08:00
|
|
|
def test_filter_choices_by_request_user(self):
|
2009-01-16 23:32:31 +08:00
|
|
|
"""
|
|
|
|
Ensure the user can only see their own cars in the foreign key dropdown.
|
|
|
|
"""
|
|
|
|
self.client.login(username="super", password="secret")
|
2015-02-07 06:25:15 +08:00
|
|
|
response = self.client.get(reverse('admin:admin_widgets_cartire_add'))
|
2012-04-14 21:35:25 +08:00
|
|
|
self.assertNotContains(response, "BMW M3")
|
|
|
|
self.assertContains(response, "Volkswagon Passat")
|
2009-03-31 07:16:34 +08:00
|
|
|
|
2010-10-15 10:35:51 +08:00
|
|
|
|
2015-01-22 00:55:57 +08:00
|
|
|
@override_settings(PASSWORD_HASHERS=['django.contrib.auth.hashers.SHA1PasswordHasher'],
|
2014-04-05 14:04:46 +08:00
|
|
|
ROOT_URLCONF='admin_widgets.urls')
|
2009-03-31 07:16:34 +08:00
|
|
|
class AdminForeignKeyWidgetChangeList(DjangoTestCase):
|
|
|
|
fixtures = ["admin-widgets-users.xml"]
|
2009-04-09 04:25:56 +08:00
|
|
|
|
2009-03-31 07:16:34 +08:00
|
|
|
def setUp(self):
|
|
|
|
self.client.login(username="super", password="secret")
|
2009-04-09 04:25:56 +08:00
|
|
|
|
2014-07-08 07:08:42 +08:00
|
|
|
def test_changelist_ForeignKey(self):
|
2015-02-07 06:25:15 +08:00
|
|
|
response = self.client.get(reverse('admin:admin_widgets_car_changelist'))
|
2014-01-14 23:43:27 +08:00
|
|
|
self.assertContains(response, '/auth/user/add/')
|
2010-03-02 10:28:49 +08:00
|
|
|
|
2010-10-15 10:35:51 +08:00
|
|
|
|
2015-01-22 00:55:57 +08:00
|
|
|
@override_settings(PASSWORD_HASHERS=['django.contrib.auth.hashers.SHA1PasswordHasher'],
|
2014-04-05 14:04:46 +08:00
|
|
|
ROOT_URLCONF='admin_widgets.urls')
|
2010-03-02 10:28:49 +08:00
|
|
|
class AdminForeignKeyRawIdWidget(DjangoTestCase):
|
|
|
|
fixtures = ["admin-widgets-users.xml"]
|
|
|
|
|
|
|
|
def setUp(self):
|
|
|
|
self.client.login(username="super", password="secret")
|
|
|
|
|
|
|
|
def test_nonexistent_target_id(self):
|
|
|
|
band = models.Band.objects.create(name='Bogey Blues')
|
|
|
|
pk = band.pk
|
|
|
|
band.delete()
|
|
|
|
post_data = {
|
2013-08-05 07:06:47 +08:00
|
|
|
"main_band": '%s' % pk,
|
2010-03-02 10:28:49 +08:00
|
|
|
}
|
|
|
|
# Try posting with a non-existent pk in a raw id field: this
|
|
|
|
# should result in an error message, not a server exception.
|
2015-02-07 06:25:15 +08:00
|
|
|
response = self.client.post(reverse('admin:admin_widgets_event_add'), post_data)
|
2010-03-02 10:28:49 +08:00
|
|
|
self.assertContains(response,
|
|
|
|
'Select a valid choice. That choice is not one of the available choices.')
|
2010-09-12 02:34:40 +08:00
|
|
|
|
|
|
|
def test_invalid_target_id(self):
|
|
|
|
|
|
|
|
for test_str in ('Iñtërnâtiônàlizætiøn', "1234'", -1234):
|
|
|
|
# This should result in an error message, not a server exception.
|
2015-02-07 06:25:15 +08:00
|
|
|
response = self.client.post(reverse('admin:admin_widgets_event_add'),
|
2013-08-05 07:06:47 +08:00
|
|
|
{"main_band": test_str})
|
2010-09-12 02:34:40 +08:00
|
|
|
|
|
|
|
self.assertContains(response,
|
|
|
|
'Select a valid choice. That choice is not one of the available choices.')
|
2010-10-15 10:35:51 +08:00
|
|
|
|
2011-04-22 20:03:50 +08:00
|
|
|
def test_url_params_from_lookup_dict_any_iterable(self):
|
2011-08-02 07:38:11 +08:00
|
|
|
lookup1 = widgets.url_params_from_lookup_dict({'color__in': ('red', 'blue')})
|
|
|
|
lookup2 = widgets.url_params_from_lookup_dict({'color__in': ['red', 'blue']})
|
2011-04-22 20:03:50 +08:00
|
|
|
self.assertEqual(lookup1, {'color__in': 'red,blue'})
|
|
|
|
self.assertEqual(lookup1, lookup2)
|
|
|
|
|
2013-08-07 00:38:31 +08:00
|
|
|
def test_url_params_from_lookup_dict_callable(self):
|
|
|
|
def my_callable():
|
|
|
|
return 'works'
|
|
|
|
lookup1 = widgets.url_params_from_lookup_dict({'myfield': my_callable})
|
|
|
|
lookup2 = widgets.url_params_from_lookup_dict({'myfield': my_callable()})
|
|
|
|
self.assertEqual(lookup1, lookup2)
|
|
|
|
|
2010-10-15 10:35:51 +08:00
|
|
|
|
2011-06-30 17:06:19 +08:00
|
|
|
class FilteredSelectMultipleWidgetTest(DjangoTestCase):
|
2010-10-15 10:35:51 +08:00
|
|
|
def test_render(self):
|
2011-08-02 07:38:11 +08:00
|
|
|
w = widgets.FilteredSelectMultiple('test', False)
|
2012-02-01 04:36:11 +08:00
|
|
|
self.assertHTMLEqual(
|
2013-08-14 04:22:46 +08:00
|
|
|
w.render('test', 'test'),
|
2012-04-09 05:13:32 +08:00
|
|
|
'<select multiple="multiple" name="test" class="selectfilter">\n</select><script type="text/javascript">addEvent(window, "load", function(e) {SelectFilter.init("id_test", "test", 0, "%(ADMIN_STATIC_PREFIX)s"); });</script>\n' % admin_static_prefix()
|
2010-10-15 10:35:51 +08:00
|
|
|
)
|
|
|
|
|
|
|
|
def test_stacked_render(self):
|
2011-08-02 07:38:11 +08:00
|
|
|
w = widgets.FilteredSelectMultiple('test', True)
|
2012-02-01 04:36:11 +08:00
|
|
|
self.assertHTMLEqual(
|
2013-08-14 04:22:46 +08:00
|
|
|
w.render('test', 'test'),
|
2012-04-09 05:13:32 +08:00
|
|
|
'<select multiple="multiple" name="test" class="selectfilterstacked">\n</select><script type="text/javascript">addEvent(window, "load", function(e) {SelectFilter.init("id_test", "test", 1, "%(ADMIN_STATIC_PREFIX)s"); });</script>\n' % admin_static_prefix()
|
2010-10-15 10:35:51 +08:00
|
|
|
)
|
|
|
|
|
2013-11-03 12:36:09 +08:00
|
|
|
|
2011-11-20 19:12:37 +08:00
|
|
|
class AdminDateWidgetTest(DjangoTestCase):
|
|
|
|
def test_attrs(self):
|
|
|
|
"""
|
|
|
|
Ensure that user-supplied attrs are used.
|
|
|
|
Refs #12073.
|
|
|
|
"""
|
|
|
|
w = widgets.AdminDateWidget()
|
2012-02-01 04:36:11 +08:00
|
|
|
self.assertHTMLEqual(
|
2013-08-14 04:22:46 +08:00
|
|
|
w.render('test', datetime(2007, 12, 1, 9, 30)),
|
2011-11-20 19:12:37 +08:00
|
|
|
'<input value="2007-12-01" type="text" class="vDateField" name="test" size="10" />',
|
|
|
|
)
|
|
|
|
# pass attrs to widget
|
|
|
|
w = widgets.AdminDateWidget(attrs={'size': 20, 'class': 'myDateField'})
|
2012-02-01 04:36:11 +08:00
|
|
|
self.assertHTMLEqual(
|
2013-08-14 04:22:46 +08:00
|
|
|
w.render('test', datetime(2007, 12, 1, 9, 30)),
|
2011-11-20 19:12:37 +08:00
|
|
|
'<input value="2007-12-01" type="text" class="myDateField" name="test" size="20" />',
|
|
|
|
)
|
|
|
|
|
2013-11-03 12:36:09 +08:00
|
|
|
|
2011-11-20 19:12:37 +08:00
|
|
|
class AdminTimeWidgetTest(DjangoTestCase):
|
|
|
|
def test_attrs(self):
|
|
|
|
"""
|
|
|
|
Ensure that user-supplied attrs are used.
|
|
|
|
Refs #12073.
|
|
|
|
"""
|
|
|
|
w = widgets.AdminTimeWidget()
|
2012-02-01 04:36:11 +08:00
|
|
|
self.assertHTMLEqual(
|
2013-08-14 04:22:46 +08:00
|
|
|
w.render('test', datetime(2007, 12, 1, 9, 30)),
|
2011-11-20 19:12:37 +08:00
|
|
|
'<input value="09:30:00" type="text" class="vTimeField" name="test" size="8" />',
|
|
|
|
)
|
|
|
|
# pass attrs to widget
|
|
|
|
w = widgets.AdminTimeWidget(attrs={'size': 20, 'class': 'myTimeField'})
|
2012-02-01 04:36:11 +08:00
|
|
|
self.assertHTMLEqual(
|
2013-08-14 04:22:46 +08:00
|
|
|
w.render('test', datetime(2007, 12, 1, 9, 30)),
|
2011-11-20 19:12:37 +08:00
|
|
|
'<input value="09:30:00" type="text" class="myTimeField" name="test" size="20" />',
|
|
|
|
)
|
2010-10-15 10:35:51 +08:00
|
|
|
|
2013-11-03 12:36:09 +08:00
|
|
|
|
2011-05-06 21:29:44 +08:00
|
|
|
class AdminSplitDateTimeWidgetTest(DjangoTestCase):
|
2010-10-15 10:35:51 +08:00
|
|
|
def test_render(self):
|
2011-08-02 07:38:11 +08:00
|
|
|
w = widgets.AdminSplitDateTime()
|
2012-02-01 04:36:11 +08:00
|
|
|
self.assertHTMLEqual(
|
2013-08-14 04:22:46 +08:00
|
|
|
w.render('test', datetime(2007, 12, 1, 9, 30)),
|
2010-10-15 10:35:51 +08:00
|
|
|
'<p class="datetime">Date: <input value="2007-12-01" type="text" class="vDateField" name="test_0" size="10" /><br />Time: <input value="09:30:00" type="text" class="vTimeField" name="test_1" size="8" /></p>',
|
|
|
|
)
|
|
|
|
|
|
|
|
def test_localization(self):
|
2011-08-02 07:38:11 +08:00
|
|
|
w = widgets.AdminSplitDateTime()
|
2010-10-15 10:35:51 +08:00
|
|
|
|
2013-08-17 02:12:10 +08:00
|
|
|
with self.settings(USE_L10N=True), translation.override('de-at'):
|
|
|
|
w.is_localized = True
|
|
|
|
self.assertHTMLEqual(
|
|
|
|
w.render('test', datetime(2007, 12, 1, 9, 30)),
|
|
|
|
'<p class="datetime">Datum: <input value="01.12.2007" type="text" class="vDateField" name="test_0" size="10" /><br />Zeit: <input value="09:30:00" type="text" class="vTimeField" name="test_1" size="8" /></p>',
|
|
|
|
)
|
2010-10-15 10:35:51 +08:00
|
|
|
|
|
|
|
|
2012-07-07 20:24:50 +08:00
|
|
|
class AdminURLWidgetTest(DjangoTestCase):
|
|
|
|
def test_render(self):
|
|
|
|
w = widgets.AdminURLFieldWidget()
|
|
|
|
self.assertHTMLEqual(
|
2013-08-14 04:22:46 +08:00
|
|
|
w.render('test', ''),
|
2013-07-26 19:22:30 +08:00
|
|
|
'<input class="vURLField" name="test" type="url" />'
|
2012-07-07 20:24:50 +08:00
|
|
|
)
|
|
|
|
self.assertHTMLEqual(
|
2013-08-14 04:22:46 +08:00
|
|
|
w.render('test', 'http://example.com'),
|
2013-07-26 19:22:30 +08:00
|
|
|
'<p class="url">Currently:<a href="http://example.com">http://example.com</a><br />Change:<input class="vURLField" name="test" type="url" value="http://example.com" /></p>'
|
2012-07-07 20:24:50 +08:00
|
|
|
)
|
|
|
|
|
|
|
|
def test_render_idn(self):
|
|
|
|
w = widgets.AdminURLFieldWidget()
|
|
|
|
self.assertHTMLEqual(
|
2013-08-14 04:22:46 +08:00
|
|
|
w.render('test', 'http://example-äüö.com'),
|
2013-08-14 00:06:41 +08:00
|
|
|
'<p class="url">Currently: <a href="http://xn--example--7za4pnc.com">http://example-äüö.com</a><br />Change:<input class="vURLField" name="test" type="url" value="http://example-äüö.com" /></p>'
|
2012-07-07 20:24:50 +08:00
|
|
|
)
|
|
|
|
|
|
|
|
def test_render_quoting(self):
|
2013-08-14 00:06:41 +08:00
|
|
|
# WARNING: Don't use assertHTMLEqual in that testcase!
|
|
|
|
# assertHTMLEqual will get rid of some escapes which are tested here!
|
2012-07-07 20:24:50 +08:00
|
|
|
w = widgets.AdminURLFieldWidget()
|
2013-08-14 00:06:41 +08:00
|
|
|
self.assertEqual(
|
|
|
|
w.render('test', 'http://example.com/<sometag>some text</sometag>'),
|
|
|
|
'<p class="url">Currently: <a href="http://example.com/%3Csometag%3Esome%20text%3C/sometag%3E">http://example.com/<sometag>some text</sometag></a><br />Change: <input class="vURLField" name="test" type="url" value="http://example.com/<sometag>some text</sometag>" /></p>'
|
2012-07-07 20:24:50 +08:00
|
|
|
)
|
2013-08-14 00:06:41 +08:00
|
|
|
self.assertEqual(
|
|
|
|
w.render('test', 'http://example-äüö.com/<sometag>some text</sometag>'),
|
|
|
|
'<p class="url">Currently: <a href="http://xn--example--7za4pnc.com/%3Csometag%3Esome%20text%3C/sometag%3E">http://example-äüö.com/<sometag>some text</sometag></a><br />Change: <input class="vURLField" name="test" type="url" value="http://example-äüö.com/<sometag>some text</sometag>" /></p>'
|
|
|
|
)
|
|
|
|
self.assertEqual(
|
|
|
|
w.render('test', 'http://www.example.com/%C3%A4"><script>alert("XSS!")</script>"'),
|
|
|
|
'<p class="url">Currently: <a href="http://www.example.com/%C3%A4%22%3E%3Cscript%3Ealert(%22XSS!%22)%3C/script%3E%22">http://www.example.com/%C3%A4"><script>alert("XSS!")</script>"</a><br />Change: <input class="vURLField" name="test" type="url" value="http://www.example.com/%C3%A4"><script>alert("XSS!")</script>"" /></p>'
|
2012-07-07 20:24:50 +08:00
|
|
|
)
|
|
|
|
|
|
|
|
|
2014-04-05 23:58:05 +08:00
|
|
|
@override_settings(
|
|
|
|
PASSWORD_HASHERS=['django.contrib.auth.hashers.SHA1PasswordHasher'],
|
|
|
|
ROOT_URLCONF='admin_widgets.urls',
|
|
|
|
)
|
|
|
|
class AdminFileWidgetTests(DjangoTestCase):
|
|
|
|
fixtures = ['admin-widgets-users.xml']
|
|
|
|
|
|
|
|
def setUp(self):
|
2010-10-15 10:35:51 +08:00
|
|
|
band = models.Band.objects.create(name='Linkin Park')
|
2014-04-05 23:58:05 +08:00
|
|
|
self.album = band.album_set.create(
|
2010-10-15 10:35:51 +08:00
|
|
|
name='Hybrid Theory', cover_art=r'albums\hybrid_theory.jpg'
|
|
|
|
)
|
|
|
|
|
2014-04-05 23:58:05 +08:00
|
|
|
def test_render(self):
|
2011-08-02 07:38:11 +08:00
|
|
|
w = widgets.AdminFileWidget()
|
2012-02-01 04:36:11 +08:00
|
|
|
self.assertHTMLEqual(
|
2014-04-05 23:58:05 +08:00
|
|
|
w.render('test', self.album.cover_art),
|
|
|
|
'<p class="file-upload">Currently: <a href="%(STORAGE_URL)salbums/'
|
|
|
|
'hybrid_theory.jpg">albums\hybrid_theory.jpg</a> '
|
|
|
|
'<span class="clearable-file-input">'
|
|
|
|
'<input type="checkbox" name="test-clear" id="test-clear_id" /> '
|
|
|
|
'<label for="test-clear_id">Clear</label></span><br />'
|
|
|
|
'Change: <input type="file" name="test" /></p>' % {
|
|
|
|
'STORAGE_URL': default_storage.url(''),
|
2013-10-15 03:13:14 +08:00
|
|
|
},
|
2010-10-15 10:35:51 +08:00
|
|
|
)
|
2012-02-01 04:36:11 +08:00
|
|
|
self.assertHTMLEqual(
|
2013-08-14 04:22:46 +08:00
|
|
|
w.render('test', SimpleUploadedFile('test', b'content')),
|
2010-10-15 10:35:51 +08:00
|
|
|
'<input type="file" name="test" />',
|
|
|
|
)
|
|
|
|
|
2014-04-05 23:58:05 +08:00
|
|
|
def test_readonly_fields(self):
|
|
|
|
"""
|
|
|
|
File widgets should render as a link when they're marked "read only."
|
|
|
|
"""
|
|
|
|
self.client.login(username="super", password="secret")
|
2015-02-07 06:25:15 +08:00
|
|
|
response = self.client.get(reverse('admin:admin_widgets_album_change', args=(self.album.id,)))
|
2014-04-05 23:58:05 +08:00
|
|
|
self.assertContains(
|
|
|
|
response,
|
|
|
|
'<p><a href="%(STORAGE_URL)salbums/hybrid_theory.jpg">'
|
|
|
|
'albums\hybrid_theory.jpg</a></p>' % {'STORAGE_URL': default_storage.url('')},
|
|
|
|
html=True,
|
|
|
|
)
|
|
|
|
self.assertNotContains(
|
|
|
|
response,
|
|
|
|
'<input type="file" name="cover_art" id="id_cover_art" />',
|
|
|
|
html=True,
|
|
|
|
)
|
|
|
|
|
2010-10-15 10:35:51 +08:00
|
|
|
|
2014-04-05 14:04:46 +08:00
|
|
|
@override_settings(ROOT_URLCONF='admin_widgets.urls')
|
2010-10-15 10:35:51 +08:00
|
|
|
class ForeignKeyRawIdWidgetTest(DjangoTestCase):
|
2014-01-14 23:43:27 +08:00
|
|
|
|
2010-10-15 10:35:51 +08:00
|
|
|
def test_render(self):
|
|
|
|
band = models.Band.objects.create(name='Linkin Park')
|
|
|
|
band.album_set.create(
|
|
|
|
name='Hybrid Theory', cover_art=r'albums\hybrid_theory.jpg'
|
|
|
|
)
|
|
|
|
rel = models.Album._meta.get_field('band').rel
|
|
|
|
|
2011-08-02 07:38:11 +08:00
|
|
|
w = widgets.ForeignKeyRawIdWidget(rel, widget_admin_site)
|
2012-02-01 04:36:11 +08:00
|
|
|
self.assertHTMLEqual(
|
2014-06-24 21:07:36 +08:00
|
|
|
w.render('test', band.pk, attrs={}), (
|
|
|
|
'<input type="text" name="test" value="%(bandpk)s" class="vForeignKeyRawIdAdminField" />'
|
|
|
|
'<a href="/admin_widgets/band/?_to_field=id" class="related-lookup" id="lookup_id_test" title="Lookup"></a>'
|
|
|
|
' <strong>Linkin Park</strong>'
|
|
|
|
) % {'bandpk': band.pk}
|
2010-10-15 10:35:51 +08:00
|
|
|
)
|
|
|
|
|
|
|
|
def test_relations_to_non_primary_key(self):
|
|
|
|
# Check that ForeignKeyRawIdWidget works with fields which aren't
|
|
|
|
# related to the model's primary key.
|
|
|
|
apple = models.Inventory.objects.create(barcode=86, name='Apple')
|
|
|
|
models.Inventory.objects.create(barcode=22, name='Pear')
|
|
|
|
core = models.Inventory.objects.create(
|
|
|
|
barcode=87, name='Core', parent=apple
|
|
|
|
)
|
|
|
|
rel = models.Inventory._meta.get_field('parent').rel
|
2011-08-02 07:38:11 +08:00
|
|
|
w = widgets.ForeignKeyRawIdWidget(rel, widget_admin_site)
|
2012-02-01 04:36:11 +08:00
|
|
|
self.assertHTMLEqual(
|
2014-06-24 21:07:36 +08:00
|
|
|
w.render('test', core.parent_id, attrs={}), (
|
|
|
|
'<input type="text" name="test" value="86" class="vForeignKeyRawIdAdminField" />'
|
|
|
|
'<a href="/admin_widgets/inventory/?_to_field=barcode" class="related-lookup" id="lookup_id_test" title="Lookup">'
|
|
|
|
'</a> <strong>Apple</strong>'
|
|
|
|
)
|
2010-10-15 10:35:51 +08:00
|
|
|
)
|
|
|
|
|
2011-08-02 07:38:11 +08:00
|
|
|
def test_fk_related_model_not_in_admin(self):
|
2011-08-12 22:14:15 +08:00
|
|
|
# FK to a model not registered with admin site. Raw ID widget should
|
2011-08-02 07:38:11 +08:00
|
|
|
# have no magnifying glass link. See #16542
|
|
|
|
big_honeycomb = models.Honeycomb.objects.create(location='Old tree')
|
|
|
|
big_honeycomb.bee_set.create()
|
|
|
|
rel = models.Bee._meta.get_field('honeycomb').rel
|
|
|
|
|
|
|
|
w = widgets.ForeignKeyRawIdWidget(rel, widget_admin_site)
|
2012-02-01 04:36:11 +08:00
|
|
|
self.assertHTMLEqual(
|
2013-08-14 04:22:46 +08:00
|
|
|
w.render('honeycomb_widget', big_honeycomb.pk, attrs={}),
|
2011-08-02 07:38:11 +08:00
|
|
|
'<input type="text" name="honeycomb_widget" value="%(hcombpk)s" /> <strong>Honeycomb object</strong>' % {'hcombpk': big_honeycomb.pk}
|
|
|
|
)
|
|
|
|
|
|
|
|
def test_fk_to_self_model_not_in_admin(self):
|
2011-08-12 22:14:15 +08:00
|
|
|
# FK to self, not registered with admin site. Raw ID widget should have
|
2011-08-02 07:38:11 +08:00
|
|
|
# no magnifying glass link. See #16542
|
|
|
|
subject1 = models.Individual.objects.create(name='Subject #1')
|
|
|
|
models.Individual.objects.create(name='Child', parent=subject1)
|
|
|
|
rel = models.Individual._meta.get_field('parent').rel
|
|
|
|
|
|
|
|
w = widgets.ForeignKeyRawIdWidget(rel, widget_admin_site)
|
2012-02-01 04:36:11 +08:00
|
|
|
self.assertHTMLEqual(
|
2013-08-14 04:22:46 +08:00
|
|
|
w.render('individual_widget', subject1.pk, attrs={}),
|
2011-08-02 07:38:11 +08:00
|
|
|
'<input type="text" name="individual_widget" value="%(subj1pk)s" /> <strong>Individual object</strong>' % {'subj1pk': subject1.pk}
|
|
|
|
)
|
2010-10-15 10:35:51 +08:00
|
|
|
|
|
|
|
def test_proper_manager_for_label_lookup(self):
|
|
|
|
# see #9258
|
|
|
|
rel = models.Inventory._meta.get_field('parent').rel
|
2011-08-02 07:38:11 +08:00
|
|
|
w = widgets.ForeignKeyRawIdWidget(rel, widget_admin_site)
|
2010-10-15 10:35:51 +08:00
|
|
|
|
|
|
|
hidden = models.Inventory.objects.create(
|
|
|
|
barcode=93, name='Hidden', hidden=True
|
|
|
|
)
|
|
|
|
child_of_hidden = models.Inventory.objects.create(
|
|
|
|
barcode=94, name='Child of hidden', parent=hidden
|
|
|
|
)
|
2012-02-01 04:36:11 +08:00
|
|
|
self.assertHTMLEqual(
|
2014-06-24 21:07:36 +08:00
|
|
|
w.render('test', child_of_hidden.parent_id, attrs={}), (
|
|
|
|
'<input type="text" name="test" value="93" class="vForeignKeyRawIdAdminField" />'
|
|
|
|
'<a href="/admin_widgets/inventory/?_to_field=barcode" class="related-lookup" id="lookup_id_test" title="Lookup">'
|
|
|
|
'</a> <strong>Hidden</strong>'
|
|
|
|
)
|
2010-10-15 10:35:51 +08:00
|
|
|
)
|
|
|
|
|
|
|
|
|
2014-04-05 14:04:46 +08:00
|
|
|
@override_settings(ROOT_URLCONF='admin_widgets.urls')
|
2010-10-15 10:35:51 +08:00
|
|
|
class ManyToManyRawIdWidgetTest(DjangoTestCase):
|
2014-01-14 23:43:27 +08:00
|
|
|
|
2010-10-15 10:35:51 +08:00
|
|
|
def test_render(self):
|
|
|
|
band = models.Band.objects.create(name='Linkin Park')
|
|
|
|
|
|
|
|
m1 = models.Member.objects.create(name='Chester')
|
|
|
|
m2 = models.Member.objects.create(name='Mike')
|
|
|
|
band.members.add(m1, m2)
|
|
|
|
rel = models.Band._meta.get_field('members').rel
|
|
|
|
|
2011-08-02 07:38:11 +08:00
|
|
|
w = widgets.ManyToManyRawIdWidget(rel, widget_admin_site)
|
2012-02-01 04:36:11 +08:00
|
|
|
self.assertHTMLEqual(
|
2014-06-24 21:07:36 +08:00
|
|
|
w.render('test', [m1.pk, m2.pk], attrs={}), (
|
|
|
|
'<input type="text" name="test" value="%(m1pk)s,%(m2pk)s" class="vManyToManyRawIdAdminField" />'
|
|
|
|
'<a href="/admin_widgets/member/" class="related-lookup" id="lookup_id_test" title="Lookup"></a>'
|
|
|
|
) % dict(m1pk=m1.pk, m2pk=m2.pk)
|
2010-10-15 10:35:51 +08:00
|
|
|
)
|
|
|
|
|
2012-02-01 04:36:11 +08:00
|
|
|
self.assertHTMLEqual(
|
2014-06-24 21:07:36 +08:00
|
|
|
w.render('test', [m1.pk]), (
|
|
|
|
'<input type="text" name="test" value="%(m1pk)s" class="vManyToManyRawIdAdminField">'
|
|
|
|
'<a href="/admin_widgets/member/" class="related-lookup" id="lookup_id_test" title="Lookup"></a>'
|
|
|
|
) % dict(m1pk=m1.pk)
|
2010-10-15 10:35:51 +08:00
|
|
|
)
|
|
|
|
|
2011-08-02 07:38:11 +08:00
|
|
|
def test_m2m_related_model_not_in_admin(self):
|
|
|
|
# M2M relationship with model not registered with admin site. Raw ID
|
2011-08-12 22:14:15 +08:00
|
|
|
# widget should have no magnifying glass link. See #16542
|
2011-08-02 07:38:11 +08:00
|
|
|
consultor1 = models.Advisor.objects.create(name='Rockstar Techie')
|
|
|
|
|
|
|
|
c1 = models.Company.objects.create(name='Doodle')
|
|
|
|
c2 = models.Company.objects.create(name='Pear')
|
|
|
|
consultor1.companies.add(c1, c2)
|
|
|
|
rel = models.Advisor._meta.get_field('companies').rel
|
|
|
|
|
|
|
|
w = widgets.ManyToManyRawIdWidget(rel, widget_admin_site)
|
2012-02-01 04:36:11 +08:00
|
|
|
self.assertHTMLEqual(
|
2013-08-14 04:22:46 +08:00
|
|
|
w.render('company_widget1', [c1.pk, c2.pk], attrs={}),
|
2011-08-02 07:38:11 +08:00
|
|
|
'<input type="text" name="company_widget1" value="%(c1pk)s,%(c2pk)s" />' % {'c1pk': c1.pk, 'c2pk': c2.pk}
|
|
|
|
)
|
|
|
|
|
2012-02-01 04:36:11 +08:00
|
|
|
self.assertHTMLEqual(
|
2013-08-14 04:22:46 +08:00
|
|
|
w.render('company_widget2', [c1.pk]),
|
2011-08-02 07:38:11 +08:00
|
|
|
'<input type="text" name="company_widget2" value="%(c1pk)s" />' % {'c1pk': c1.pk}
|
|
|
|
)
|
|
|
|
|
2013-11-03 12:36:09 +08:00
|
|
|
|
2010-11-23 05:55:29 +08:00
|
|
|
class RelatedFieldWidgetWrapperTests(DjangoTestCase):
|
|
|
|
def test_no_can_add_related(self):
|
2011-08-02 07:38:11 +08:00
|
|
|
rel = models.Individual._meta.get_field('parent').rel
|
|
|
|
w = widgets.AdminRadioSelect()
|
2010-11-23 05:55:29 +08:00
|
|
|
# Used to fail with a name error.
|
2011-08-02 07:38:11 +08:00
|
|
|
w = widgets.RelatedFieldWidgetWrapper(w, rel, widget_admin_site)
|
2010-11-23 05:55:29 +08:00
|
|
|
self.assertFalse(w.can_add_related)
|
Fixed #2879 -- Added support for the integration with Selenium and other in-browser testing frameworks. Also added the first Selenium tests for `contrib.admin`. Many thanks to everyone for their contributions and feedback: Mikeal Rogers, Dirk Datzert, mir, Simon G., Almad, Russell Keith-Magee, Denis Golomazov, devin, robertrv, andrewbadr, Idan Gazit, voidspace, Tom Christie, hjwp2, Adam Nelson, Jannis Leidel, Anssi Kääriäinen, Preston Holmes, Bruno Renié and Jacob Kaplan-Moss.
git-svn-id: http://code.djangoproject.com/svn/django/trunk@17241 bcc190cf-cafb-0310-a4f2-bffc1f526a37
2011-12-22 16:33:58 +08:00
|
|
|
|
2013-11-18 06:26:20 +08:00
|
|
|
def test_select_multiple_widget_cant_change_delete_related(self):
|
|
|
|
rel = models.Individual._meta.get_field('parent').rel
|
|
|
|
widget = forms.SelectMultiple()
|
|
|
|
wrapper = widgets.RelatedFieldWidgetWrapper(
|
|
|
|
widget, rel, widget_admin_site,
|
|
|
|
can_add_related=True,
|
|
|
|
can_change_related=True,
|
|
|
|
can_delete_related=True,
|
|
|
|
)
|
|
|
|
self.assertTrue(wrapper.can_add_related)
|
|
|
|
self.assertFalse(wrapper.can_change_related)
|
|
|
|
self.assertFalse(wrapper.can_delete_related)
|
|
|
|
|
|
|
|
def test_on_delete_cascade_rel_cant_delete_related(self):
|
|
|
|
rel = models.Individual._meta.get_field('soulmate').rel
|
|
|
|
widget = forms.Select()
|
|
|
|
wrapper = widgets.RelatedFieldWidgetWrapper(
|
|
|
|
widget, rel, widget_admin_site,
|
|
|
|
can_add_related=True,
|
|
|
|
can_change_related=True,
|
|
|
|
can_delete_related=True,
|
|
|
|
)
|
|
|
|
self.assertTrue(wrapper.can_add_related)
|
|
|
|
self.assertTrue(wrapper.can_change_related)
|
|
|
|
self.assertFalse(wrapper.can_delete_related)
|
|
|
|
|
Fixed #2879 -- Added support for the integration with Selenium and other in-browser testing frameworks. Also added the first Selenium tests for `contrib.admin`. Many thanks to everyone for their contributions and feedback: Mikeal Rogers, Dirk Datzert, mir, Simon G., Almad, Russell Keith-Magee, Denis Golomazov, devin, robertrv, andrewbadr, Idan Gazit, voidspace, Tom Christie, hjwp2, Adam Nelson, Jannis Leidel, Anssi Kääriäinen, Preston Holmes, Bruno Renié and Jacob Kaplan-Moss.
git-svn-id: http://code.djangoproject.com/svn/django/trunk@17241 bcc190cf-cafb-0310-a4f2-bffc1f526a37
2011-12-22 16:33:58 +08:00
|
|
|
|
2015-01-22 00:55:57 +08:00
|
|
|
@override_settings(PASSWORD_HASHERS=['django.contrib.auth.hashers.SHA1PasswordHasher'],
|
2014-04-05 14:04:46 +08:00
|
|
|
ROOT_URLCONF='admin_widgets.urls')
|
2012-02-23 16:07:07 +08:00
|
|
|
class DateTimePickerSeleniumFirefoxTests(AdminSeleniumWebDriverTestCase):
|
2013-06-10 18:11:46 +08:00
|
|
|
|
|
|
|
available_apps = ['admin_widgets'] + AdminSeleniumWebDriverTestCase.available_apps
|
Fixed #2879 -- Added support for the integration with Selenium and other in-browser testing frameworks. Also added the first Selenium tests for `contrib.admin`. Many thanks to everyone for their contributions and feedback: Mikeal Rogers, Dirk Datzert, mir, Simon G., Almad, Russell Keith-Magee, Denis Golomazov, devin, robertrv, andrewbadr, Idan Gazit, voidspace, Tom Christie, hjwp2, Adam Nelson, Jannis Leidel, Anssi Kääriäinen, Preston Holmes, Bruno Renié and Jacob Kaplan-Moss.
git-svn-id: http://code.djangoproject.com/svn/django/trunk@17241 bcc190cf-cafb-0310-a4f2-bffc1f526a37
2011-12-22 16:33:58 +08:00
|
|
|
fixtures = ['admin-widgets-users.xml']
|
2013-06-10 18:11:46 +08:00
|
|
|
webdriver_class = 'selenium.webdriver.firefox.webdriver.WebDriver'
|
Fixed #2879 -- Added support for the integration with Selenium and other in-browser testing frameworks. Also added the first Selenium tests for `contrib.admin`. Many thanks to everyone for their contributions and feedback: Mikeal Rogers, Dirk Datzert, mir, Simon G., Almad, Russell Keith-Magee, Denis Golomazov, devin, robertrv, andrewbadr, Idan Gazit, voidspace, Tom Christie, hjwp2, Adam Nelson, Jannis Leidel, Anssi Kääriäinen, Preston Holmes, Bruno Renié and Jacob Kaplan-Moss.
git-svn-id: http://code.djangoproject.com/svn/django/trunk@17241 bcc190cf-cafb-0310-a4f2-bffc1f526a37
2011-12-22 16:33:58 +08:00
|
|
|
|
|
|
|
def test_show_hide_date_time_picker_widgets(self):
|
|
|
|
"""
|
|
|
|
Ensure that pressing the ESC key closes the date and time picker
|
|
|
|
widgets.
|
|
|
|
Refs #17064.
|
|
|
|
"""
|
|
|
|
from selenium.webdriver.common.keys import Keys
|
|
|
|
|
|
|
|
self.admin_login(username='super', password='secret', login_url='/')
|
|
|
|
# Open a page that has a date and time picker widgets
|
|
|
|
self.selenium.get('%s%s' % (self.live_server_url,
|
2015-02-07 06:25:15 +08:00
|
|
|
reverse('admin:admin_widgets_member_add')))
|
Fixed #2879 -- Added support for the integration with Selenium and other in-browser testing frameworks. Also added the first Selenium tests for `contrib.admin`. Many thanks to everyone for their contributions and feedback: Mikeal Rogers, Dirk Datzert, mir, Simon G., Almad, Russell Keith-Magee, Denis Golomazov, devin, robertrv, andrewbadr, Idan Gazit, voidspace, Tom Christie, hjwp2, Adam Nelson, Jannis Leidel, Anssi Kääriäinen, Preston Holmes, Bruno Renié and Jacob Kaplan-Moss.
git-svn-id: http://code.djangoproject.com/svn/django/trunk@17241 bcc190cf-cafb-0310-a4f2-bffc1f526a37
2011-12-22 16:33:58 +08:00
|
|
|
|
|
|
|
# First, with the date picker widget ---------------------------------
|
|
|
|
# Check that the date picker is hidden
|
|
|
|
self.assertEqual(
|
|
|
|
self.get_css_value('#calendarbox0', 'display'), 'none')
|
|
|
|
# Click the calendar icon
|
|
|
|
self.selenium.find_element_by_id('calendarlink0').click()
|
|
|
|
# Check that the date picker is visible
|
|
|
|
self.assertEqual(
|
|
|
|
self.get_css_value('#calendarbox0', 'display'), 'block')
|
|
|
|
# Press the ESC key
|
2012-02-22 15:14:10 +08:00
|
|
|
self.selenium.find_element_by_tag_name('body').send_keys([Keys.ESCAPE])
|
Fixed #2879 -- Added support for the integration with Selenium and other in-browser testing frameworks. Also added the first Selenium tests for `contrib.admin`. Many thanks to everyone for their contributions and feedback: Mikeal Rogers, Dirk Datzert, mir, Simon G., Almad, Russell Keith-Magee, Denis Golomazov, devin, robertrv, andrewbadr, Idan Gazit, voidspace, Tom Christie, hjwp2, Adam Nelson, Jannis Leidel, Anssi Kääriäinen, Preston Holmes, Bruno Renié and Jacob Kaplan-Moss.
git-svn-id: http://code.djangoproject.com/svn/django/trunk@17241 bcc190cf-cafb-0310-a4f2-bffc1f526a37
2011-12-22 16:33:58 +08:00
|
|
|
# Check that the date picker is hidden again
|
|
|
|
self.assertEqual(
|
|
|
|
self.get_css_value('#calendarbox0', 'display'), 'none')
|
|
|
|
|
|
|
|
# Then, with the time picker widget ----------------------------------
|
|
|
|
# Check that the time picker is hidden
|
|
|
|
self.assertEqual(
|
|
|
|
self.get_css_value('#clockbox0', 'display'), 'none')
|
|
|
|
# Click the time icon
|
|
|
|
self.selenium.find_element_by_id('clocklink0').click()
|
|
|
|
# Check that the time picker is visible
|
|
|
|
self.assertEqual(
|
|
|
|
self.get_css_value('#clockbox0', 'display'), 'block')
|
|
|
|
# Press the ESC key
|
2012-02-22 15:14:10 +08:00
|
|
|
self.selenium.find_element_by_tag_name('body').send_keys([Keys.ESCAPE])
|
Fixed #2879 -- Added support for the integration with Selenium and other in-browser testing frameworks. Also added the first Selenium tests for `contrib.admin`. Many thanks to everyone for their contributions and feedback: Mikeal Rogers, Dirk Datzert, mir, Simon G., Almad, Russell Keith-Magee, Denis Golomazov, devin, robertrv, andrewbadr, Idan Gazit, voidspace, Tom Christie, hjwp2, Adam Nelson, Jannis Leidel, Anssi Kääriäinen, Preston Holmes, Bruno Renié and Jacob Kaplan-Moss.
git-svn-id: http://code.djangoproject.com/svn/django/trunk@17241 bcc190cf-cafb-0310-a4f2-bffc1f526a37
2011-12-22 16:33:58 +08:00
|
|
|
# Check that the time picker is hidden again
|
|
|
|
self.assertEqual(
|
|
|
|
self.get_css_value('#clockbox0', 'display'), 'none')
|
2012-02-22 15:14:10 +08:00
|
|
|
|
2013-09-08 05:12:13 +08:00
|
|
|
def test_calendar_nonday_class(self):
|
|
|
|
"""
|
|
|
|
Ensure cells that are not days of the month have the `nonday` CSS class.
|
|
|
|
Refs #4574.
|
|
|
|
"""
|
|
|
|
self.admin_login(username='super', password='secret', login_url='/')
|
|
|
|
# Open a page that has a date and time picker widgets
|
|
|
|
self.selenium.get('%s%s' % (self.live_server_url,
|
2015-02-07 06:25:15 +08:00
|
|
|
reverse('admin:admin_widgets_member_add')))
|
2013-09-08 05:12:13 +08:00
|
|
|
|
|
|
|
# fill in the birth date.
|
|
|
|
self.selenium.find_element_by_id('id_birthdate_0').send_keys('2013-06-01')
|
|
|
|
|
|
|
|
# Click the calendar icon
|
|
|
|
self.selenium.find_element_by_id('calendarlink0').click()
|
|
|
|
|
|
|
|
# get all the tds within the calendar
|
|
|
|
calendar0 = self.selenium.find_element_by_id('calendarin0')
|
|
|
|
tds = calendar0.find_elements_by_tag_name('td')
|
|
|
|
|
|
|
|
# make sure the first and last 6 cells have class nonday
|
|
|
|
for td in tds[:6] + tds[-6:]:
|
|
|
|
self.assertEqual(td.get_attribute('class'), 'nonday')
|
|
|
|
|
|
|
|
def test_calendar_selected_class(self):
|
|
|
|
"""
|
|
|
|
Ensure cell for the day in the input has the `selected` CSS class.
|
|
|
|
Refs #4574.
|
|
|
|
"""
|
|
|
|
self.admin_login(username='super', password='secret', login_url='/')
|
|
|
|
# Open a page that has a date and time picker widgets
|
|
|
|
self.selenium.get('%s%s' % (self.live_server_url,
|
2015-02-07 06:25:15 +08:00
|
|
|
reverse('admin:admin_widgets_member_add')))
|
2013-09-08 05:12:13 +08:00
|
|
|
|
|
|
|
# fill in the birth date.
|
|
|
|
self.selenium.find_element_by_id('id_birthdate_0').send_keys('2013-06-01')
|
|
|
|
|
|
|
|
# Click the calendar icon
|
|
|
|
self.selenium.find_element_by_id('calendarlink0').click()
|
|
|
|
|
|
|
|
# get all the tds within the calendar
|
|
|
|
calendar0 = self.selenium.find_element_by_id('calendarin0')
|
|
|
|
tds = calendar0.find_elements_by_tag_name('td')
|
|
|
|
|
|
|
|
# verify the selected cell
|
|
|
|
selected = tds[6]
|
|
|
|
self.assertEqual(selected.get_attribute('class'), 'selected')
|
|
|
|
|
|
|
|
self.assertEqual(selected.text, '1')
|
|
|
|
|
|
|
|
def test_calendar_no_selected_class(self):
|
|
|
|
"""
|
|
|
|
Ensure no cells are given the selected class when the field is empty.
|
|
|
|
Refs #4574.
|
|
|
|
"""
|
|
|
|
self.admin_login(username='super', password='secret', login_url='/')
|
|
|
|
# Open a page that has a date and time picker widgets
|
|
|
|
self.selenium.get('%s%s' % (self.live_server_url,
|
2015-02-07 06:25:15 +08:00
|
|
|
reverse('admin:admin_widgets_member_add')))
|
2013-09-08 05:12:13 +08:00
|
|
|
|
|
|
|
# Click the calendar icon
|
|
|
|
self.selenium.find_element_by_id('calendarlink0').click()
|
|
|
|
|
|
|
|
# get all the tds within the calendar
|
|
|
|
calendar0 = self.selenium.find_element_by_id('calendarin0')
|
|
|
|
tds = calendar0.find_elements_by_tag_name('td')
|
|
|
|
|
|
|
|
# verify there are no cells with the selected class
|
|
|
|
selected = [td for td in tds if td.get_attribute('class') == 'selected']
|
|
|
|
|
|
|
|
self.assertEqual(len(selected), 0)
|
|
|
|
|
2014-04-16 03:01:55 +08:00
|
|
|
def test_calendar_show_date_from_input(self):
|
|
|
|
"""
|
|
|
|
Ensure that the calendar show the date from the input field for every
|
|
|
|
locale supported by django.
|
|
|
|
"""
|
|
|
|
self.admin_login(username='super', password='secret', login_url='/')
|
|
|
|
|
|
|
|
# Enter test data
|
2014-08-14 15:58:15 +08:00
|
|
|
member = models.Member.objects.create(name='Bob', birthdate=datetime(1984, 5, 15), gender='M')
|
2014-04-16 03:01:55 +08:00
|
|
|
|
|
|
|
# Get month names translations for every locales
|
|
|
|
month_string = 'January February March April May June July August September October November December'
|
|
|
|
path = os.path.join(os.path.dirname(import_module('django.contrib.admin').__file__), 'locale')
|
|
|
|
for language_code, language_name in settings.LANGUAGES:
|
|
|
|
try:
|
|
|
|
catalog = gettext.translation('djangojs', path, [language_code])
|
|
|
|
except IOError:
|
|
|
|
continue
|
|
|
|
if month_string in catalog._catalog:
|
|
|
|
month_names = catalog._catalog[month_string]
|
|
|
|
else:
|
|
|
|
month_names = month_string
|
|
|
|
|
|
|
|
# Get the expected caption
|
|
|
|
may_translation = month_names.split(' ')[4]
|
|
|
|
expected_caption = '{0:s} {1:d}'.format(may_translation, 1984)
|
|
|
|
|
|
|
|
# Test with every locale
|
|
|
|
with override_settings(LANGUAGE_CODE=language_code, USE_L10N=True):
|
|
|
|
|
|
|
|
# Open a page that has a date picker widget
|
|
|
|
self.selenium.get('{}{}'.format(self.live_server_url,
|
2015-02-07 06:25:15 +08:00
|
|
|
reverse('admin:admin_widgets_member_change', args=(member.pk,))))
|
2014-04-16 03:01:55 +08:00
|
|
|
|
|
|
|
# Click on the calendar icon
|
|
|
|
self.selenium.find_element_by_id('calendarlink0').click()
|
|
|
|
|
|
|
|
# Get the calendar caption
|
|
|
|
calendar0 = self.selenium.find_element_by_id('calendarin0')
|
|
|
|
caption = calendar0.find_element_by_tag_name('caption')
|
|
|
|
|
|
|
|
# Make sure that the right month and year are displayed
|
|
|
|
self.assertEqual(caption.text, expected_caption)
|
|
|
|
|
2013-09-08 05:12:13 +08:00
|
|
|
|
2012-02-23 16:07:07 +08:00
|
|
|
class DateTimePickerSeleniumChromeTests(DateTimePickerSeleniumFirefoxTests):
|
|
|
|
webdriver_class = 'selenium.webdriver.chrome.webdriver.WebDriver'
|
|
|
|
|
2013-11-03 12:36:09 +08:00
|
|
|
|
2012-03-05 16:13:09 +08:00
|
|
|
class DateTimePickerSeleniumIETests(DateTimePickerSeleniumFirefoxTests):
|
|
|
|
webdriver_class = 'selenium.webdriver.ie.webdriver.WebDriver'
|
2013-07-01 22:48:14 +08:00
|
|
|
|
|
|
|
|
2013-11-03 07:57:35 +08:00
|
|
|
@skipIf(pytz is None, "this test requires pytz")
|
2013-07-01 22:48:14 +08:00
|
|
|
@override_settings(TIME_ZONE='Asia/Singapore')
|
2015-01-22 00:55:57 +08:00
|
|
|
@override_settings(PASSWORD_HASHERS=['django.contrib.auth.hashers.SHA1PasswordHasher'],
|
2014-04-05 14:04:46 +08:00
|
|
|
ROOT_URLCONF='admin_widgets.urls')
|
2013-07-01 22:48:14 +08:00
|
|
|
class DateTimePickerShortcutsSeleniumFirefoxTests(AdminSeleniumWebDriverTestCase):
|
|
|
|
available_apps = ['admin_widgets'] + AdminSeleniumWebDriverTestCase.available_apps
|
|
|
|
fixtures = ['admin-widgets-users.xml']
|
|
|
|
webdriver_class = 'selenium.webdriver.firefox.webdriver.WebDriver'
|
|
|
|
|
|
|
|
def test_date_time_picker_shortcuts(self):
|
|
|
|
"""
|
|
|
|
Ensure that date/time/datetime picker shortcuts work in the current time zone.
|
|
|
|
Refs #20663.
|
|
|
|
|
|
|
|
This test case is fairly tricky, it relies on selenium still running the browser
|
|
|
|
in the default time zone "America/Chicago" despite `override_settings` changing
|
|
|
|
the time zone to "Asia/Singapore".
|
|
|
|
"""
|
|
|
|
self.admin_login(username='super', password='secret', login_url='/')
|
|
|
|
|
|
|
|
error_margin = timedelta(seconds=10)
|
|
|
|
|
2013-11-03 07:57:35 +08:00
|
|
|
# If we are neighbouring a DST, we add an hour of error margin.
|
|
|
|
tz = pytz.timezone('America/Chicago')
|
|
|
|
utc_now = datetime.now(pytz.utc)
|
|
|
|
tz_yesterday = (utc_now - timedelta(days=1)).astimezone(tz).tzname()
|
|
|
|
tz_tomorrow = (utc_now + timedelta(days=1)).astimezone(tz).tzname()
|
|
|
|
if tz_yesterday != tz_tomorrow:
|
|
|
|
error_margin += timedelta(hours=1)
|
|
|
|
|
|
|
|
now = datetime.now()
|
|
|
|
|
2013-07-01 22:48:14 +08:00
|
|
|
self.selenium.get('%s%s' % (self.live_server_url,
|
2015-02-07 06:25:15 +08:00
|
|
|
reverse('admin:admin_widgets_member_add')))
|
2013-07-01 22:48:14 +08:00
|
|
|
|
|
|
|
self.selenium.find_element_by_id('id_name').send_keys('test')
|
|
|
|
|
|
|
|
# Click on the "today" and "now" shortcuts.
|
|
|
|
shortcuts = self.selenium.find_elements_by_css_selector(
|
|
|
|
'.field-birthdate .datetimeshortcuts')
|
|
|
|
|
|
|
|
for shortcut in shortcuts:
|
|
|
|
shortcut.find_element_by_tag_name('a').click()
|
|
|
|
|
|
|
|
# Check that there is a time zone mismatch warning.
|
|
|
|
# Warning: This would effectively fail if the TIME_ZONE defined in the
|
|
|
|
# settings has the same UTC offset as "Asia/Singapore" because the
|
|
|
|
# mismatch warning would be rightfully missing from the page.
|
|
|
|
self.selenium.find_elements_by_css_selector(
|
|
|
|
'.field-birthdate .timezonewarning')
|
|
|
|
|
|
|
|
# Submit the form.
|
|
|
|
self.selenium.find_element_by_tag_name('form').submit()
|
|
|
|
self.wait_page_loaded()
|
|
|
|
|
|
|
|
# Make sure that "now" in javascript is within 10 seconds
|
|
|
|
# from "now" on the server side.
|
|
|
|
member = models.Member.objects.get(name='test')
|
|
|
|
self.assertGreater(member.birthdate, now - error_margin)
|
|
|
|
self.assertLess(member.birthdate, now + error_margin)
|
|
|
|
|
2013-11-03 12:36:09 +08:00
|
|
|
|
2013-07-01 22:48:14 +08:00
|
|
|
class DateTimePickerShortcutsSeleniumChromeTests(DateTimePickerShortcutsSeleniumFirefoxTests):
|
|
|
|
webdriver_class = 'selenium.webdriver.chrome.webdriver.WebDriver'
|
|
|
|
|
2013-11-03 12:36:09 +08:00
|
|
|
|
2013-07-01 22:48:14 +08:00
|
|
|
class DateTimePickerShortcutsSeleniumIETests(DateTimePickerShortcutsSeleniumFirefoxTests):
|
|
|
|
webdriver_class = 'selenium.webdriver.ie.webdriver.WebDriver'
|
2012-03-05 16:13:09 +08:00
|
|
|
|
2012-02-23 16:07:07 +08:00
|
|
|
|
2015-01-22 00:55:57 +08:00
|
|
|
@override_settings(PASSWORD_HASHERS=['django.contrib.auth.hashers.SHA1PasswordHasher'],
|
2014-04-05 14:04:46 +08:00
|
|
|
ROOT_URLCONF='admin_widgets.urls')
|
2012-02-23 16:07:07 +08:00
|
|
|
class HorizontalVerticalFilterSeleniumFirefoxTests(AdminSeleniumWebDriverTestCase):
|
2013-06-10 18:11:46 +08:00
|
|
|
|
|
|
|
available_apps = ['admin_widgets'] + AdminSeleniumWebDriverTestCase.available_apps
|
2012-02-23 16:07:07 +08:00
|
|
|
fixtures = ['admin-widgets-users.xml']
|
2013-06-10 18:11:46 +08:00
|
|
|
webdriver_class = 'selenium.webdriver.firefox.webdriver.WebDriver'
|
2012-02-23 16:07:07 +08:00
|
|
|
|
|
|
|
def setUp(self):
|
|
|
|
self.lisa = models.Student.objects.create(name='Lisa')
|
|
|
|
self.john = models.Student.objects.create(name='John')
|
|
|
|
self.bob = models.Student.objects.create(name='Bob')
|
|
|
|
self.peter = models.Student.objects.create(name='Peter')
|
|
|
|
self.jenny = models.Student.objects.create(name='Jenny')
|
|
|
|
self.jason = models.Student.objects.create(name='Jason')
|
|
|
|
self.cliff = models.Student.objects.create(name='Cliff')
|
|
|
|
self.arthur = models.Student.objects.create(name='Arthur')
|
|
|
|
self.school = models.School.objects.create(name='School of Awesome')
|
|
|
|
super(HorizontalVerticalFilterSeleniumFirefoxTests, self).setUp()
|
|
|
|
|
2012-03-04 09:20:03 +08:00
|
|
|
def assertActiveButtons(self, mode, field_name, choose, remove,
|
2013-11-03 12:36:09 +08:00
|
|
|
choose_all=None, remove_all=None):
|
2012-03-04 09:20:03 +08:00
|
|
|
choose_link = '#id_%s_add_link' % field_name
|
|
|
|
choose_all_link = '#id_%s_add_all_link' % field_name
|
|
|
|
remove_link = '#id_%s_remove_link' % field_name
|
|
|
|
remove_all_link = '#id_%s_remove_all_link' % field_name
|
|
|
|
self.assertEqual(self.has_css_class(choose_link, 'active'), choose)
|
|
|
|
self.assertEqual(self.has_css_class(remove_link, 'active'), remove)
|
|
|
|
if mode == 'horizontal':
|
|
|
|
self.assertEqual(self.has_css_class(choose_all_link, 'active'), choose_all)
|
|
|
|
self.assertEqual(self.has_css_class(remove_all_link, 'active'), remove_all)
|
|
|
|
|
|
|
|
def execute_basic_operations(self, mode, field_name):
|
2012-02-23 16:07:07 +08:00
|
|
|
from_box = '#id_%s_from' % field_name
|
|
|
|
to_box = '#id_%s_to' % field_name
|
|
|
|
choose_link = 'id_%s_add_link' % field_name
|
|
|
|
choose_all_link = 'id_%s_add_all_link' % field_name
|
|
|
|
remove_link = 'id_%s_remove_link' % field_name
|
|
|
|
remove_all_link = 'id_%s_remove_all_link' % field_name
|
|
|
|
|
|
|
|
# Initial positions ---------------------------------------------------
|
|
|
|
self.assertSelectOptions(from_box,
|
|
|
|
[str(self.arthur.id), str(self.bob.id),
|
|
|
|
str(self.cliff.id), str(self.jason.id),
|
|
|
|
str(self.jenny.id), str(self.john.id)])
|
|
|
|
self.assertSelectOptions(to_box,
|
|
|
|
[str(self.lisa.id), str(self.peter.id)])
|
2012-03-04 09:20:03 +08:00
|
|
|
self.assertActiveButtons(mode, field_name, False, False, True, True)
|
2012-02-23 16:07:07 +08:00
|
|
|
|
|
|
|
# Click 'Choose all' --------------------------------------------------
|
|
|
|
if mode == 'horizontal':
|
|
|
|
self.selenium.find_element_by_id(choose_all_link).click()
|
|
|
|
elif mode == 'vertical':
|
|
|
|
# There 's no 'Choose all' button in vertical mode, so individually
|
|
|
|
# select all options and click 'Choose'.
|
2012-03-05 16:13:09 +08:00
|
|
|
for option in self.selenium.find_elements_by_css_selector(from_box + ' > option'):
|
2012-02-23 16:07:07 +08:00
|
|
|
option.click()
|
|
|
|
self.selenium.find_element_by_id(choose_link).click()
|
|
|
|
self.assertSelectOptions(from_box, [])
|
|
|
|
self.assertSelectOptions(to_box,
|
|
|
|
[str(self.lisa.id), str(self.peter.id),
|
|
|
|
str(self.arthur.id), str(self.bob.id),
|
|
|
|
str(self.cliff.id), str(self.jason.id),
|
|
|
|
str(self.jenny.id), str(self.john.id)])
|
2012-03-04 09:20:03 +08:00
|
|
|
self.assertActiveButtons(mode, field_name, False, False, False, True)
|
2012-02-23 16:07:07 +08:00
|
|
|
|
|
|
|
# Click 'Remove all' --------------------------------------------------
|
|
|
|
if mode == 'horizontal':
|
|
|
|
self.selenium.find_element_by_id(remove_all_link).click()
|
|
|
|
elif mode == 'vertical':
|
|
|
|
# There 's no 'Remove all' button in vertical mode, so individually
|
|
|
|
# select all options and click 'Remove'.
|
2012-03-05 16:13:09 +08:00
|
|
|
for option in self.selenium.find_elements_by_css_selector(to_box + ' > option'):
|
2012-02-23 16:07:07 +08:00
|
|
|
option.click()
|
|
|
|
self.selenium.find_element_by_id(remove_link).click()
|
|
|
|
self.assertSelectOptions(from_box,
|
|
|
|
[str(self.lisa.id), str(self.peter.id),
|
|
|
|
str(self.arthur.id), str(self.bob.id),
|
|
|
|
str(self.cliff.id), str(self.jason.id),
|
|
|
|
str(self.jenny.id), str(self.john.id)])
|
|
|
|
self.assertSelectOptions(to_box, [])
|
2012-03-04 09:20:03 +08:00
|
|
|
self.assertActiveButtons(mode, field_name, False, False, True, False)
|
2012-02-23 16:07:07 +08:00
|
|
|
|
|
|
|
# Choose some options ------------------------------------------------
|
2013-09-07 04:46:38 +08:00
|
|
|
from_lisa_select_option = self.get_select_option(from_box, str(self.lisa.id))
|
|
|
|
|
|
|
|
# Check the title attribute is there for tool tips: ticket #20821
|
|
|
|
self.assertEqual(from_lisa_select_option.get_attribute('title'), from_lisa_select_option.get_attribute('text'))
|
|
|
|
|
|
|
|
from_lisa_select_option.click()
|
2012-02-23 16:07:07 +08:00
|
|
|
self.get_select_option(from_box, str(self.jason.id)).click()
|
|
|
|
self.get_select_option(from_box, str(self.bob.id)).click()
|
|
|
|
self.get_select_option(from_box, str(self.john.id)).click()
|
2012-03-04 09:20:03 +08:00
|
|
|
self.assertActiveButtons(mode, field_name, True, False, True, False)
|
2012-02-23 16:07:07 +08:00
|
|
|
self.selenium.find_element_by_id(choose_link).click()
|
2012-03-04 09:20:03 +08:00
|
|
|
self.assertActiveButtons(mode, field_name, False, False, True, True)
|
2012-02-23 16:07:07 +08:00
|
|
|
|
|
|
|
self.assertSelectOptions(from_box,
|
|
|
|
[str(self.peter.id), str(self.arthur.id),
|
|
|
|
str(self.cliff.id), str(self.jenny.id)])
|
|
|
|
self.assertSelectOptions(to_box,
|
|
|
|
[str(self.lisa.id), str(self.bob.id),
|
|
|
|
str(self.jason.id), str(self.john.id)])
|
|
|
|
|
2013-09-07 04:46:38 +08:00
|
|
|
# Check the tooltip is still there after moving: ticket #20821
|
|
|
|
to_lisa_select_option = self.get_select_option(to_box, str(self.lisa.id))
|
|
|
|
self.assertEqual(to_lisa_select_option.get_attribute('title'), to_lisa_select_option.get_attribute('text'))
|
|
|
|
|
2012-02-23 16:07:07 +08:00
|
|
|
# Remove some options -------------------------------------------------
|
|
|
|
self.get_select_option(to_box, str(self.lisa.id)).click()
|
|
|
|
self.get_select_option(to_box, str(self.bob.id)).click()
|
2012-03-04 09:20:03 +08:00
|
|
|
self.assertActiveButtons(mode, field_name, False, True, True, True)
|
2012-02-23 16:07:07 +08:00
|
|
|
self.selenium.find_element_by_id(remove_link).click()
|
2012-03-04 09:20:03 +08:00
|
|
|
self.assertActiveButtons(mode, field_name, False, False, True, True)
|
2012-02-23 16:07:07 +08:00
|
|
|
|
|
|
|
self.assertSelectOptions(from_box,
|
|
|
|
[str(self.peter.id), str(self.arthur.id),
|
|
|
|
str(self.cliff.id), str(self.jenny.id),
|
|
|
|
str(self.lisa.id), str(self.bob.id)])
|
|
|
|
self.assertSelectOptions(to_box,
|
|
|
|
[str(self.jason.id), str(self.john.id)])
|
|
|
|
|
|
|
|
# Choose some more options --------------------------------------------
|
|
|
|
self.get_select_option(from_box, str(self.arthur.id)).click()
|
|
|
|
self.get_select_option(from_box, str(self.cliff.id)).click()
|
|
|
|
self.selenium.find_element_by_id(choose_link).click()
|
|
|
|
|
|
|
|
self.assertSelectOptions(from_box,
|
|
|
|
[str(self.peter.id), str(self.jenny.id),
|
|
|
|
str(self.lisa.id), str(self.bob.id)])
|
|
|
|
self.assertSelectOptions(to_box,
|
|
|
|
[str(self.jason.id), str(self.john.id),
|
|
|
|
str(self.arthur.id), str(self.cliff.id)])
|
|
|
|
|
|
|
|
def test_basic(self):
|
|
|
|
self.school.students = [self.lisa, self.peter]
|
|
|
|
self.school.alumni = [self.lisa, self.peter]
|
|
|
|
self.school.save()
|
|
|
|
|
|
|
|
self.admin_login(username='super', password='secret', login_url='/')
|
2015-02-07 06:25:15 +08:00
|
|
|
self.selenium.get('%s%s' % (
|
|
|
|
self.live_server_url, reverse('admin:admin_widgets_school_change', args=(self.school.id,))))
|
2012-02-23 16:07:07 +08:00
|
|
|
|
2013-02-20 09:08:55 +08:00
|
|
|
self.wait_page_loaded()
|
2012-03-04 09:20:03 +08:00
|
|
|
self.execute_basic_operations('vertical', 'students')
|
|
|
|
self.execute_basic_operations('horizontal', 'alumni')
|
2012-02-23 16:07:07 +08:00
|
|
|
|
|
|
|
# Save and check that everything is properly stored in the database ---
|
|
|
|
self.selenium.find_element_by_xpath('//input[@value="Save"]').click()
|
2013-02-20 09:08:55 +08:00
|
|
|
self.wait_page_loaded()
|
|
|
|
self.school = models.School.objects.get(id=self.school.id) # Reload from database
|
2012-02-23 16:07:07 +08:00
|
|
|
self.assertEqual(list(self.school.students.all()),
|
|
|
|
[self.arthur, self.cliff, self.jason, self.john])
|
|
|
|
self.assertEqual(list(self.school.alumni.all()),
|
|
|
|
[self.arthur, self.cliff, self.jason, self.john])
|
|
|
|
|
2012-03-04 09:20:03 +08:00
|
|
|
def test_filter(self):
|
|
|
|
"""
|
|
|
|
Ensure that typing in the search box filters out options displayed in
|
|
|
|
the 'from' box.
|
|
|
|
"""
|
|
|
|
from selenium.webdriver.common.keys import Keys
|
|
|
|
|
|
|
|
self.school.students = [self.lisa, self.peter]
|
|
|
|
self.school.alumni = [self.lisa, self.peter]
|
|
|
|
self.school.save()
|
|
|
|
|
|
|
|
self.admin_login(username='super', password='secret', login_url='/')
|
|
|
|
self.selenium.get(
|
2015-02-07 06:25:15 +08:00
|
|
|
'%s%s' % (self.live_server_url, reverse('admin:admin_widgets_school_change', args=(self.school.id,))))
|
2012-03-04 09:20:03 +08:00
|
|
|
|
|
|
|
for field_name in ['students', 'alumni']:
|
|
|
|
from_box = '#id_%s_from' % field_name
|
|
|
|
to_box = '#id_%s_to' % field_name
|
2012-03-04 12:50:58 +08:00
|
|
|
choose_link = '#id_%s_add_link' % field_name
|
|
|
|
remove_link = '#id_%s_remove_link' % field_name
|
2012-03-04 09:20:03 +08:00
|
|
|
input = self.selenium.find_element_by_css_selector('#id_%s_input' % field_name)
|
|
|
|
|
|
|
|
# Initial values
|
|
|
|
self.assertSelectOptions(from_box,
|
|
|
|
[str(self.arthur.id), str(self.bob.id),
|
|
|
|
str(self.cliff.id), str(self.jason.id),
|
|
|
|
str(self.jenny.id), str(self.john.id)])
|
|
|
|
|
|
|
|
# Typing in some characters filters out non-matching options
|
|
|
|
input.send_keys('a')
|
|
|
|
self.assertSelectOptions(from_box, [str(self.arthur.id), str(self.jason.id)])
|
|
|
|
input.send_keys('R')
|
|
|
|
self.assertSelectOptions(from_box, [str(self.arthur.id)])
|
|
|
|
|
|
|
|
# Clearing the text box makes the other options reappear
|
|
|
|
input.send_keys([Keys.BACK_SPACE])
|
|
|
|
self.assertSelectOptions(from_box, [str(self.arthur.id), str(self.jason.id)])
|
|
|
|
input.send_keys([Keys.BACK_SPACE])
|
|
|
|
self.assertSelectOptions(from_box,
|
|
|
|
[str(self.arthur.id), str(self.bob.id),
|
|
|
|
str(self.cliff.id), str(self.jason.id),
|
|
|
|
str(self.jenny.id), str(self.john.id)])
|
|
|
|
|
2012-03-04 12:50:58 +08:00
|
|
|
# -----------------------------------------------------------------
|
2014-11-04 06:48:03 +08:00
|
|
|
# Check that choosing a filtered option sends it properly to the
|
2012-03-04 09:20:03 +08:00
|
|
|
# 'to' box.
|
|
|
|
input.send_keys('a')
|
|
|
|
self.assertSelectOptions(from_box, [str(self.arthur.id), str(self.jason.id)])
|
|
|
|
self.get_select_option(from_box, str(self.jason.id)).click()
|
2012-03-04 12:50:58 +08:00
|
|
|
self.selenium.find_element_by_css_selector(choose_link).click()
|
2012-03-04 09:20:03 +08:00
|
|
|
self.assertSelectOptions(from_box, [str(self.arthur.id)])
|
2012-03-04 12:50:58 +08:00
|
|
|
self.assertSelectOptions(to_box,
|
|
|
|
[str(self.lisa.id), str(self.peter.id),
|
|
|
|
str(self.jason.id)])
|
|
|
|
|
|
|
|
self.get_select_option(to_box, str(self.lisa.id)).click()
|
|
|
|
self.selenium.find_element_by_css_selector(remove_link).click()
|
|
|
|
self.assertSelectOptions(from_box,
|
|
|
|
[str(self.arthur.id), str(self.lisa.id)])
|
|
|
|
self.assertSelectOptions(to_box,
|
|
|
|
[str(self.peter.id), str(self.jason.id)])
|
|
|
|
|
2013-11-03 05:02:56 +08:00
|
|
|
input.send_keys([Keys.BACK_SPACE]) # Clear text box
|
2012-03-04 09:20:03 +08:00
|
|
|
self.assertSelectOptions(from_box,
|
|
|
|
[str(self.arthur.id), str(self.bob.id),
|
|
|
|
str(self.cliff.id), str(self.jenny.id),
|
2012-03-04 12:50:58 +08:00
|
|
|
str(self.john.id), str(self.lisa.id)])
|
2012-03-04 09:20:03 +08:00
|
|
|
self.assertSelectOptions(to_box,
|
2012-03-04 12:50:58 +08:00
|
|
|
[str(self.peter.id), str(self.jason.id)])
|
|
|
|
|
2014-08-09 02:10:09 +08:00
|
|
|
# -----------------------------------------------------------------
|
|
|
|
# Check that pressing enter on a filtered option sends it properly
|
|
|
|
# to the 'to' box.
|
|
|
|
self.get_select_option(to_box, str(self.jason.id)).click()
|
|
|
|
self.selenium.find_element_by_css_selector(remove_link).click()
|
|
|
|
input.send_keys('ja')
|
|
|
|
self.assertSelectOptions(from_box, [str(self.jason.id)])
|
|
|
|
input.send_keys([Keys.ENTER])
|
|
|
|
self.assertSelectOptions(to_box, [str(self.peter.id), str(self.jason.id)])
|
|
|
|
input.send_keys([Keys.BACK_SPACE, Keys.BACK_SPACE])
|
|
|
|
|
2012-03-04 12:50:58 +08:00
|
|
|
# Save and check that everything is properly stored in the database ---
|
|
|
|
self.selenium.find_element_by_xpath('//input[@value="Save"]').click()
|
2013-02-20 09:08:55 +08:00
|
|
|
self.wait_page_loaded()
|
2013-11-03 05:02:56 +08:00
|
|
|
self.school = models.School.objects.get(id=self.school.id) # Reload from database
|
2012-03-04 12:50:58 +08:00
|
|
|
self.assertEqual(list(self.school.students.all()),
|
|
|
|
[self.jason, self.peter])
|
|
|
|
self.assertEqual(list(self.school.alumni.all()),
|
|
|
|
[self.jason, self.peter])
|
2012-03-04 09:20:03 +08:00
|
|
|
|
2013-11-03 12:36:09 +08:00
|
|
|
|
2012-02-23 16:07:07 +08:00
|
|
|
class HorizontalVerticalFilterSeleniumChromeTests(HorizontalVerticalFilterSeleniumFirefoxTests):
|
2012-03-05 16:13:09 +08:00
|
|
|
webdriver_class = 'selenium.webdriver.chrome.webdriver.WebDriver'
|
|
|
|
|
2013-11-03 12:36:09 +08:00
|
|
|
|
2012-03-05 16:13:09 +08:00
|
|
|
class HorizontalVerticalFilterSeleniumIETests(HorizontalVerticalFilterSeleniumFirefoxTests):
|
2012-04-09 05:13:32 +08:00
|
|
|
webdriver_class = 'selenium.webdriver.ie.webdriver.WebDriver'
|
2013-08-05 07:06:47 +08:00
|
|
|
|
|
|
|
|
2015-01-22 00:55:57 +08:00
|
|
|
@override_settings(PASSWORD_HASHERS=['django.contrib.auth.hashers.SHA1PasswordHasher'],
|
2014-04-05 14:04:46 +08:00
|
|
|
ROOT_URLCONF='admin_widgets.urls')
|
2013-08-05 07:06:47 +08:00
|
|
|
class AdminRawIdWidgetSeleniumFirefoxTests(AdminSeleniumWebDriverTestCase):
|
|
|
|
available_apps = ['admin_widgets'] + AdminSeleniumWebDriverTestCase.available_apps
|
|
|
|
fixtures = ['admin-widgets-users.xml']
|
|
|
|
webdriver_class = 'selenium.webdriver.firefox.webdriver.WebDriver'
|
|
|
|
|
|
|
|
def setUp(self):
|
|
|
|
models.Band.objects.create(id=42, name='Bogey Blues')
|
|
|
|
models.Band.objects.create(id=98, name='Green Potatoes')
|
|
|
|
super(AdminRawIdWidgetSeleniumFirefoxTests, self).setUp()
|
|
|
|
|
2014-07-08 07:08:42 +08:00
|
|
|
def test_ForeignKey(self):
|
2013-08-05 07:06:47 +08:00
|
|
|
self.admin_login(username='super', password='secret', login_url='/')
|
|
|
|
self.selenium.get(
|
2015-02-07 06:25:15 +08:00
|
|
|
'%s%s' % (self.live_server_url, reverse('admin:admin_widgets_event_add')))
|
2013-08-05 07:06:47 +08:00
|
|
|
main_window = self.selenium.current_window_handle
|
|
|
|
|
|
|
|
# No value has been selected yet
|
|
|
|
self.assertEqual(
|
|
|
|
self.selenium.find_element_by_id('id_main_band').get_attribute('value'),
|
|
|
|
'')
|
|
|
|
|
|
|
|
# Open the popup window and click on a band
|
|
|
|
self.selenium.find_element_by_id('lookup_id_main_band').click()
|
2014-07-24 20:25:15 +08:00
|
|
|
self.selenium.switch_to.window('id_main_band')
|
2013-08-05 13:03:53 +08:00
|
|
|
self.wait_page_loaded()
|
2013-08-05 07:06:47 +08:00
|
|
|
link = self.selenium.find_element_by_link_text('Bogey Blues')
|
2014-10-28 18:02:56 +08:00
|
|
|
self.assertIn('/band/42/', link.get_attribute('href'))
|
2013-08-05 07:06:47 +08:00
|
|
|
link.click()
|
|
|
|
|
|
|
|
# The field now contains the selected band's id
|
2014-07-24 20:25:15 +08:00
|
|
|
self.selenium.switch_to.window(main_window)
|
2014-01-03 18:25:24 +08:00
|
|
|
self.wait_for_value('#id_main_band', '42')
|
2013-08-05 07:06:47 +08:00
|
|
|
|
|
|
|
# Reopen the popup window and click on another band
|
|
|
|
self.selenium.find_element_by_id('lookup_id_main_band').click()
|
2014-07-24 20:25:15 +08:00
|
|
|
self.selenium.switch_to.window('id_main_band')
|
2013-08-05 13:03:53 +08:00
|
|
|
self.wait_page_loaded()
|
2013-08-05 07:06:47 +08:00
|
|
|
link = self.selenium.find_element_by_link_text('Green Potatoes')
|
2014-10-28 18:02:56 +08:00
|
|
|
self.assertIn('/band/98/', link.get_attribute('href'))
|
2013-08-05 07:06:47 +08:00
|
|
|
link.click()
|
|
|
|
|
|
|
|
# The field now contains the other selected band's id
|
2014-07-24 20:25:15 +08:00
|
|
|
self.selenium.switch_to.window(main_window)
|
2014-01-03 18:25:24 +08:00
|
|
|
self.wait_for_value('#id_main_band', '98')
|
2013-08-05 07:06:47 +08:00
|
|
|
|
|
|
|
def test_many_to_many(self):
|
|
|
|
self.admin_login(username='super', password='secret', login_url='/')
|
|
|
|
self.selenium.get(
|
2015-02-07 06:25:15 +08:00
|
|
|
'%s%s' % (self.live_server_url, reverse('admin:admin_widgets_event_add')))
|
2013-08-05 07:06:47 +08:00
|
|
|
main_window = self.selenium.current_window_handle
|
|
|
|
|
|
|
|
# No value has been selected yet
|
|
|
|
self.assertEqual(
|
|
|
|
self.selenium.find_element_by_id('id_supporting_bands').get_attribute('value'),
|
|
|
|
'')
|
|
|
|
|
|
|
|
# Open the popup window and click on a band
|
|
|
|
self.selenium.find_element_by_id('lookup_id_supporting_bands').click()
|
2014-07-24 20:25:15 +08:00
|
|
|
self.selenium.switch_to.window('id_supporting_bands')
|
2013-08-05 13:03:53 +08:00
|
|
|
self.wait_page_loaded()
|
2013-08-05 07:06:47 +08:00
|
|
|
link = self.selenium.find_element_by_link_text('Bogey Blues')
|
2014-10-28 18:02:56 +08:00
|
|
|
self.assertIn('/band/42/', link.get_attribute('href'))
|
2013-08-05 07:06:47 +08:00
|
|
|
link.click()
|
|
|
|
|
|
|
|
# The field now contains the selected band's id
|
2014-07-24 20:25:15 +08:00
|
|
|
self.selenium.switch_to.window(main_window)
|
2014-01-03 18:25:24 +08:00
|
|
|
self.wait_for_value('#id_supporting_bands', '42')
|
2013-08-05 07:06:47 +08:00
|
|
|
|
|
|
|
# Reopen the popup window and click on another band
|
|
|
|
self.selenium.find_element_by_id('lookup_id_supporting_bands').click()
|
2014-07-24 20:25:15 +08:00
|
|
|
self.selenium.switch_to.window('id_supporting_bands')
|
2013-08-05 13:03:53 +08:00
|
|
|
self.wait_page_loaded()
|
2013-08-05 07:06:47 +08:00
|
|
|
link = self.selenium.find_element_by_link_text('Green Potatoes')
|
2014-10-28 18:02:56 +08:00
|
|
|
self.assertIn('/band/98/', link.get_attribute('href'))
|
2013-08-05 07:06:47 +08:00
|
|
|
link.click()
|
|
|
|
|
|
|
|
# The field now contains the two selected bands' ids
|
2014-07-24 20:25:15 +08:00
|
|
|
self.selenium.switch_to.window(main_window)
|
2014-01-03 18:25:24 +08:00
|
|
|
self.wait_for_value('#id_supporting_bands', '42,98')
|
2013-08-05 07:06:47 +08:00
|
|
|
|
2013-11-03 12:36:09 +08:00
|
|
|
|
2013-08-05 07:06:47 +08:00
|
|
|
class AdminRawIdWidgetSeleniumChromeTests(AdminRawIdWidgetSeleniumFirefoxTests):
|
|
|
|
webdriver_class = 'selenium.webdriver.chrome.webdriver.WebDriver'
|
|
|
|
|
2013-11-03 12:36:09 +08:00
|
|
|
|
2013-08-05 07:06:47 +08:00
|
|
|
class AdminRawIdWidgetSeleniumIETests(AdminRawIdWidgetSeleniumFirefoxTests):
|
2013-08-07 00:38:31 +08:00
|
|
|
webdriver_class = 'selenium.webdriver.ie.webdriver.WebDriver'
|
2013-09-08 00:52:14 +08:00
|
|
|
|
|
|
|
|
2015-01-22 00:55:57 +08:00
|
|
|
@override_settings(PASSWORD_HASHERS=['django.contrib.auth.hashers.SHA1PasswordHasher'],
|
2014-04-05 14:04:46 +08:00
|
|
|
ROOT_URLCONF='admin_widgets.urls')
|
2013-09-08 00:52:14 +08:00
|
|
|
class RelatedFieldWidgetSeleniumFirefoxTests(AdminSeleniumWebDriverTestCase):
|
|
|
|
available_apps = ['admin_widgets'] + AdminSeleniumWebDriverTestCase.available_apps
|
|
|
|
fixtures = ['admin-widgets-users.xml']
|
|
|
|
webdriver_class = 'selenium.webdriver.firefox.webdriver.WebDriver'
|
|
|
|
|
2014-07-08 07:08:42 +08:00
|
|
|
def test_ForeignKey_using_to_field(self):
|
2013-09-08 00:52:14 +08:00
|
|
|
self.admin_login(username='super', password='secret', login_url='/')
|
|
|
|
self.selenium.get('%s%s' % (
|
|
|
|
self.live_server_url,
|
2015-02-07 06:25:15 +08:00
|
|
|
reverse('admin:admin_widgets_profile_add')))
|
2013-09-08 00:52:14 +08:00
|
|
|
|
|
|
|
main_window = self.selenium.current_window_handle
|
|
|
|
# Click the Add User button to add new
|
|
|
|
self.selenium.find_element_by_id('add_id_user').click()
|
2014-07-24 20:25:15 +08:00
|
|
|
self.selenium.switch_to.window('id_user')
|
2014-08-13 21:55:24 +08:00
|
|
|
self.wait_for('#id_password')
|
2013-09-08 00:52:14 +08:00
|
|
|
password_field = self.selenium.find_element_by_id('id_password')
|
|
|
|
password_field.send_keys('password')
|
|
|
|
|
|
|
|
username_field = self.selenium.find_element_by_id('id_username')
|
|
|
|
username_value = 'newuser'
|
|
|
|
username_field.send_keys(username_value)
|
|
|
|
|
|
|
|
save_button_css_selector = '.submit-row > input[type=submit]'
|
|
|
|
self.selenium.find_element_by_css_selector(save_button_css_selector).click()
|
2014-07-24 20:25:15 +08:00
|
|
|
self.selenium.switch_to.window(main_window)
|
2014-01-03 07:31:53 +08:00
|
|
|
# The field now contains the new user
|
|
|
|
self.wait_for('#id_user option[value="newuser"]')
|
2013-09-08 00:52:14 +08:00
|
|
|
|
2013-11-18 06:26:20 +08:00
|
|
|
# Click the Change User button to change it
|
|
|
|
self.selenium.find_element_by_id('change_id_user').click()
|
|
|
|
self.selenium.switch_to_window('id_user')
|
|
|
|
self.wait_page_loaded()
|
|
|
|
|
|
|
|
username_field = self.selenium.find_element_by_id('id_username')
|
|
|
|
username_value = 'changednewuser'
|
|
|
|
username_field.clear()
|
|
|
|
username_field.send_keys(username_value)
|
|
|
|
|
|
|
|
save_button_css_selector = '.submit-row > input[type=submit]'
|
|
|
|
self.selenium.find_element_by_css_selector(save_button_css_selector).click()
|
|
|
|
self.selenium.switch_to_window(main_window)
|
|
|
|
# Wait up to 2 seconds for the new option to show up after clicking save in the popup.
|
|
|
|
self.selenium.implicitly_wait(2)
|
|
|
|
self.selenium.find_element_by_css_selector('#id_user option[value=changednewuser]')
|
|
|
|
self.selenium.implicitly_wait(0)
|
|
|
|
|
2013-09-08 00:52:14 +08:00
|
|
|
# Go ahead and submit the form to make sure it works
|
|
|
|
self.selenium.find_element_by_css_selector(save_button_css_selector).click()
|
2013-11-18 06:26:20 +08:00
|
|
|
self.wait_for_text('li.success', 'The profile "changednewuser" was added successfully.')
|
2013-09-08 00:52:14 +08:00
|
|
|
profiles = models.Profile.objects.all()
|
|
|
|
self.assertEqual(len(profiles), 1)
|
|
|
|
self.assertEqual(profiles[0].user.username, username_value)
|
|
|
|
|
2013-11-03 12:36:09 +08:00
|
|
|
|
2013-09-08 00:52:14 +08:00
|
|
|
class RelatedFieldWidgetSeleniumChromeTests(RelatedFieldWidgetSeleniumFirefoxTests):
|
|
|
|
webdriver_class = 'selenium.webdriver.chrome.webdriver.WebDriver'
|
|
|
|
|
2013-11-03 12:36:09 +08:00
|
|
|
|
2013-09-08 00:52:14 +08:00
|
|
|
class RelatedFieldWidgetSeleniumIETests(RelatedFieldWidgetSeleniumFirefoxTests):
|
2013-09-15 07:11:07 +08:00
|
|
|
webdriver_class = 'selenium.webdriver.ie.webdriver.WebDriver'
|