diff options
author | django-bot <ops@djangoproject.com> | 2022-02-03 20:24:19 +0100 |
---|---|---|
committer | Mariusz Felisiak <felisiak.mariusz@gmail.com> | 2022-02-07 20:37:05 +0100 |
commit | 9c19aff7c7561e3a82978a272ecdaad40dda5c00 (patch) | |
tree | f0506b668a013d0063e5fba3dbf4863b466713ba /tests/admin_widgets | |
parent | f68fa8b45dfac545cfc4111d4e52804c86db68d3 (diff) | |
download | django-9c19aff7c7561e3a82978a272ecdaad40dda5c00.tar.gz |
Refs #33476 -- Reformatted code with Black.
Diffstat (limited to 'tests/admin_widgets')
-rw-r--r-- | tests/admin_widgets/models.py | 45 | ||||
-rw-r--r-- | tests/admin_widgets/test_autocomplete_widget.py | 144 | ||||
-rw-r--r-- | tests/admin_widgets/tests.py | 1154 | ||||
-rw-r--r-- | tests/admin_widgets/urls.py | 2 | ||||
-rw-r--r-- | tests/admin_widgets/widgetadmin.py | 39 |
5 files changed, 833 insertions, 551 deletions
diff --git a/tests/admin_widgets/models.py b/tests/admin_widgets/models.py index 85ba6c4f36..15d7a3022e 100644 --- a/tests/admin_widgets/models.py +++ b/tests/admin_widgets/models.py @@ -11,7 +11,9 @@ class MyFileField(models.FileField): class Member(models.Model): name = models.CharField(max_length=100) birthdate = models.DateTimeField(blank=True, null=True) - gender = models.CharField(max_length=1, blank=True, choices=[('M', 'Male'), ('F', 'Female')]) + gender = models.CharField( + max_length=1, blank=True, choices=[("M", "Male"), ("F", "Female")] + ) email = models.EmailField(blank=True) def __str__(self): @@ -36,16 +38,16 @@ class UnsafeLimitChoicesTo(models.Model): band = models.ForeignKey( Band, models.CASCADE, - limit_choices_to={'name': '"&><escapeme'}, + limit_choices_to={"name": '"&><escapeme'}, ) class Album(models.Model): - band = models.ForeignKey(Band, models.CASCADE, to_field='uuid') - featuring = models.ManyToManyField(Band, related_name='featured') + band = models.ForeignKey(Band, models.CASCADE, to_field="uuid") + featuring = models.ManyToManyField(Band, related_name="featured") name = models.CharField(max_length=100) - cover_art = models.FileField(upload_to='albums') - backside_art = MyFileField(upload_to='albums_back', null=True) + cover_art = models.FileField(upload_to="albums") + backside_art = MyFileField(upload_to="albums_back", null=True) def __str__(self): return self.name @@ -56,11 +58,12 @@ class ReleaseEvent(models.Model): Used to check that autocomplete widget correctly resolves attname for FK as PK example. """ + album = models.ForeignKey(Album, models.CASCADE, primary_key=True) name = models.CharField(max_length=100) class Meta: - ordering = ['name'] + ordering = ["name"] def __str__(self): return self.name @@ -77,7 +80,9 @@ class HiddenInventoryManager(models.Manager): class Inventory(models.Model): barcode = models.PositiveIntegerField(unique=True) - parent = models.ForeignKey('self', models.SET_NULL, to_field='barcode', blank=True, null=True) + parent = models.ForeignKey( + "self", models.SET_NULL, to_field="barcode", blank=True, null=True + ) name = models.CharField(blank=False, max_length=20) hidden = models.BooleanField(default=False) @@ -94,13 +99,13 @@ class Event(models.Model): Band, models.CASCADE, limit_choices_to=models.Q(pk__gt=0), - related_name='events_main_band_at', + related_name="events_main_band_at", ) supporting_bands = models.ManyToManyField( Band, blank=True, - related_name='events_supporting_band_at', - help_text='Supporting Bands.', + related_name="events_supporting_band_at", + help_text="Supporting Bands.", ) start_date = models.DateField(blank=True, null=True) start_time = models.TimeField(blank=True, null=True) @@ -122,6 +127,7 @@ class CarTire(models.Model): """ A single car tire. This to test that a user can only select their own cars. """ + car = models.ForeignKey(Car, models.CASCADE) @@ -136,6 +142,7 @@ class Bee(models.Model): (Honeycomb) so the corresponding raw ID widget won't have a magnifying glass link to select related honeycomb instances. """ + honeycomb = models.ForeignKey(Honeycomb, models.CASCADE) @@ -145,9 +152,12 @@ class Individual(models.Model): corresponding raw ID widget won't have a magnifying glass link to select related instances (rendering will be called programmatically in this case). """ + name = models.CharField(max_length=20) - parent = models.ForeignKey('self', models.SET_NULL, null=True) - soulmate = models.ForeignKey('self', models.CASCADE, null=True, related_name='soulmates') + parent = models.ForeignKey("self", models.SET_NULL, null=True) + soulmate = models.ForeignKey( + "self", models.CASCADE, null=True, related_name="soulmates" + ) class Company(models.Model): @@ -160,6 +170,7 @@ class Advisor(models.Model): (Company) so the corresponding raw ID widget won't have a magnifying glass link to select related company instances. """ + name = models.CharField(max_length=20) companies = models.ManyToManyField(Company) @@ -168,7 +179,7 @@ class Student(models.Model): name = models.CharField(max_length=255) class Meta: - ordering = ('name',) + ordering = ("name",) def __str__(self): return self.name @@ -176,15 +187,15 @@ class Student(models.Model): class School(models.Model): name = models.CharField(max_length=255) - students = models.ManyToManyField(Student, related_name='current_schools') - alumni = models.ManyToManyField(Student, related_name='previous_schools') + students = models.ManyToManyField(Student, related_name="current_schools") + alumni = models.ManyToManyField(Student, related_name="previous_schools") def __str__(self): return self.name class Profile(models.Model): - user = models.ForeignKey('auth.User', models.CASCADE, to_field='username') + user = models.ForeignKey("auth.User", models.CASCADE, to_field="username") def __str__(self): return self.user.username diff --git a/tests/admin_widgets/test_autocomplete_widget.py b/tests/admin_widgets/test_autocomplete_widget.py index a1c6e0ad7b..c7bcbd1d13 100644 --- a/tests/admin_widgets/test_autocomplete_widget.py +++ b/tests/admin_widgets/test_autocomplete_widget.py @@ -11,24 +11,26 @@ from .models import Album, Band, ReleaseEvent, VideoStream class AlbumForm(forms.ModelForm): class Meta: model = Album - fields = ['band', 'featuring'] + fields = ["band", "featuring"] widgets = { - 'band': AutocompleteSelect( - Album._meta.get_field('band'), + "band": AutocompleteSelect( + Album._meta.get_field("band"), admin.site, - attrs={'class': 'my-class'}, + attrs={"class": "my-class"}, ), - 'featuring': AutocompleteSelect( - Album._meta.get_field('featuring'), + "featuring": AutocompleteSelect( + Album._meta.get_field("featuring"), admin.site, - ) + ), } class NotRequiredBandForm(forms.Form): band = ModelChoiceField( queryset=Album.objects.all(), - widget=AutocompleteSelect(Album._meta.get_field('band').remote_field, admin.site), + widget=AutocompleteSelect( + Album._meta.get_field("band").remote_field, admin.site + ), required=False, ) @@ -36,7 +38,9 @@ class NotRequiredBandForm(forms.Form): class RequiredBandForm(forms.Form): band = ModelChoiceField( queryset=Album.objects.all(), - widget=AutocompleteSelect(Album._meta.get_field('band').remote_field, admin.site), + widget=AutocompleteSelect( + Album._meta.get_field("band").remote_field, admin.site + ), required=True, ) @@ -44,73 +48,84 @@ class RequiredBandForm(forms.Form): class VideoStreamForm(forms.ModelForm): class Meta: model = VideoStream - fields = ['release_event'] + fields = ["release_event"] widgets = { - 'release_event': AutocompleteSelect( - VideoStream._meta.get_field('release_event'), + "release_event": AutocompleteSelect( + VideoStream._meta.get_field("release_event"), admin.site, ), } -@override_settings(ROOT_URLCONF='admin_widgets.urls') +@override_settings(ROOT_URLCONF="admin_widgets.urls") class AutocompleteMixinTests(TestCase): empty_option = '<option value=""></option>' maxDiff = 1000 def test_build_attrs(self): form = AlbumForm() - attrs = form['band'].field.widget.get_context(name='my_field', value=None, attrs={})['widget']['attrs'] - self.assertEqual(attrs, { - 'class': 'my-class admin-autocomplete', - 'data-ajax--cache': 'true', - 'data-ajax--delay': 250, - 'data-ajax--type': 'GET', - 'data-ajax--url': '/autocomplete/', - 'data-theme': 'admin-autocomplete', - 'data-allow-clear': 'false', - 'data-app-label': 'admin_widgets', - 'data-field-name': 'band', - 'data-model-name': 'album', - 'data-placeholder': '', - 'lang': 'en', - }) + attrs = form["band"].field.widget.get_context( + name="my_field", value=None, attrs={} + )["widget"]["attrs"] + self.assertEqual( + attrs, + { + "class": "my-class admin-autocomplete", + "data-ajax--cache": "true", + "data-ajax--delay": 250, + "data-ajax--type": "GET", + "data-ajax--url": "/autocomplete/", + "data-theme": "admin-autocomplete", + "data-allow-clear": "false", + "data-app-label": "admin_widgets", + "data-field-name": "band", + "data-model-name": "album", + "data-placeholder": "", + "lang": "en", + }, + ) def test_build_attrs_no_custom_class(self): form = AlbumForm() - attrs = form['featuring'].field.widget.get_context(name='name', value=None, attrs={})['widget']['attrs'] - self.assertEqual(attrs['class'], 'admin-autocomplete') + attrs = form["featuring"].field.widget.get_context( + name="name", value=None, attrs={} + )["widget"]["attrs"] + self.assertEqual(attrs["class"], "admin-autocomplete") def test_build_attrs_not_required_field(self): form = NotRequiredBandForm() - attrs = form['band'].field.widget.build_attrs({}) - self.assertJSONEqual(attrs['data-allow-clear'], True) + attrs = form["band"].field.widget.build_attrs({}) + self.assertJSONEqual(attrs["data-allow-clear"], True) def test_build_attrs_required_field(self): form = RequiredBandForm() - attrs = form['band'].field.widget.build_attrs({}) - self.assertJSONEqual(attrs['data-allow-clear'], False) + attrs = form["band"].field.widget.build_attrs({}) + self.assertJSONEqual(attrs["data-allow-clear"], False) def test_get_url(self): - rel = Album._meta.get_field('band') + rel = Album._meta.get_field("band") w = AutocompleteSelect(rel, admin.site) url = w.get_url() - self.assertEqual(url, '/autocomplete/') + self.assertEqual(url, "/autocomplete/") def test_render_options(self): - beatles = Band.objects.create(name='The Beatles', style='rock') - who = Band.objects.create(name='The Who', style='rock') + beatles = Band.objects.create(name="The Beatles", style="rock") + who = Band.objects.create(name="The Who", style="rock") # With 'band', a ForeignKey. - form = AlbumForm(initial={'band': beatles.uuid}) + form = AlbumForm(initial={"band": beatles.uuid}) output = form.as_table() - selected_option = '<option value="%s" selected>The Beatles</option>' % beatles.uuid + selected_option = ( + '<option value="%s" selected>The Beatles</option>' % beatles.uuid + ) option = '<option value="%s">The Who</option>' % who.uuid self.assertIn(selected_option, output) self.assertNotIn(option, output) # With 'featuring', a ManyToManyField. - form = AlbumForm(initial={'featuring': [beatles.pk, who.pk]}) + form = AlbumForm(initial={"featuring": [beatles.pk, who.pk]}) output = form.as_table() - selected_option = '<option value="%s" selected>The Beatles</option>' % beatles.pk + selected_option = ( + '<option value="%s" selected>The Beatles</option>' % beatles.pk + ) option = '<option value="%s" selected>The Who</option>' % who.pk self.assertIn(selected_option, output) self.assertIn(option, output) @@ -128,41 +143,48 @@ class AutocompleteMixinTests(TestCase): self.assertNotIn(self.empty_option, output) def test_render_options_fk_as_pk(self): - beatles = Band.objects.create(name='The Beatles', style='rock') - rubber_soul = Album.objects.create(name='Rubber Soul', band=beatles) - release_event = ReleaseEvent.objects.create(name='Test Target', album=rubber_soul) - form = VideoStreamForm(initial={'release_event': release_event.pk}) + beatles = Band.objects.create(name="The Beatles", style="rock") + rubber_soul = Album.objects.create(name="Rubber Soul", band=beatles) + release_event = ReleaseEvent.objects.create( + name="Test Target", album=rubber_soul + ) + form = VideoStreamForm(initial={"release_event": release_event.pk}) output = form.as_table() - selected_option = '<option value="%s" selected>Test Target</option>' % release_event.pk + selected_option = ( + '<option value="%s" selected>Test Target</option>' % release_event.pk + ) self.assertIn(selected_option, output) def test_media(self): - rel = Album._meta.get_field('band').remote_field + rel = Album._meta.get_field("band").remote_field base_files = ( - 'admin/js/vendor/jquery/jquery.min.js', - 'admin/js/vendor/select2/select2.full.min.js', + "admin/js/vendor/jquery/jquery.min.js", + "admin/js/vendor/select2/select2.full.min.js", # Language file is inserted here. - 'admin/js/jquery.init.js', - 'admin/js/autocomplete.js', + "admin/js/jquery.init.js", + "admin/js/autocomplete.js", ) languages = ( - ('de', 'de'), + ("de", "de"), # Language with code 00 does not exist. - ('00', None), + ("00", None), # Language files are case sensitive. - ('sr-cyrl', 'sr-Cyrl'), - ('zh-hans', 'zh-CN'), - ('zh-hant', 'zh-TW'), + ("sr-cyrl", "sr-Cyrl"), + ("zh-hans", "zh-CN"), + ("zh-hant", "zh-TW"), ) for lang, select_lang in languages: with self.subTest(lang=lang): if select_lang: expected_files = ( - base_files[:2] + - (('admin/js/vendor/select2/i18n/%s.js' % select_lang),) + - base_files[2:] + base_files[:2] + + (("admin/js/vendor/select2/i18n/%s.js" % select_lang),) + + base_files[2:] ) else: expected_files = base_files with translation.override(lang): - self.assertEqual(AutocompleteSelect(rel, admin.site).media._js, list(expected_files)) + self.assertEqual( + AutocompleteSelect(rel, admin.site).media._js, + list(expected_files), + ) diff --git a/tests/admin_widgets/tests.py b/tests/admin_widgets/tests.py index 677ee18cff..35563653b0 100644 --- a/tests/admin_widgets/tests.py +++ b/tests/admin_widgets/tests.py @@ -18,28 +18,48 @@ from django.contrib.auth.models import User from django.core.files.storage import default_storage from django.core.files.uploadedfile import SimpleUploadedFile from django.db.models import ( - CharField, DateField, DateTimeField, ManyToManyField, UUIDField, + CharField, + DateField, + DateTimeField, + ManyToManyField, + UUIDField, ) from django.test import SimpleTestCase, TestCase, override_settings from django.urls import reverse from django.utils import translation from .models import ( - Advisor, Album, Band, Bee, Car, Company, Event, Honeycomb, Individual, - Inventory, Member, MyFileField, Profile, ReleaseEvent, School, Student, - UnsafeLimitChoicesTo, VideoStream, + Advisor, + Album, + Band, + Bee, + Car, + Company, + Event, + Honeycomb, + Individual, + Inventory, + Member, + MyFileField, + Profile, + ReleaseEvent, + School, + Student, + UnsafeLimitChoicesTo, + VideoStream, ) from .widgetadmin import site as widget_admin_site class TestDataMixin: - @classmethod def setUpTestData(cls): - cls.superuser = User.objects.create_superuser(username='super', password='secret', email=None) - cls.u2 = User.objects.create_user(username='testser', password='secret') - Car.objects.create(owner=cls.superuser, make='Volkswagen', model='Passat') - Car.objects.create(owner=cls.u2, make='BMW', model='M3') + cls.superuser = User.objects.create_superuser( + username="super", password="secret", email=None + ) + cls.u2 = User.objects.create_user(username="testser", password="secret") + Car.objects.create(owner=cls.superuser, make="Volkswagen", model="Passat") + Car.objects.create(owner=cls.u2, make="BMW", model="M3") class AdminFormfieldForDBFieldTests(SimpleTestCase): @@ -55,6 +75,7 @@ class AdminFormfieldForDBFieldTests(SimpleTestCase): # Override any settings on the model admin class MyModelAdmin(admin.ModelAdmin): pass + for k in admin_overrides: setattr(MyModelAdmin, k, admin_overrides[k]) @@ -74,75 +95,91 @@ class AdminFormfieldForDBFieldTests(SimpleTestCase): return ff def test_DateField(self): - self.assertFormfield(Event, 'start_date', widgets.AdminDateWidget) + self.assertFormfield(Event, "start_date", widgets.AdminDateWidget) def test_DateTimeField(self): - self.assertFormfield(Member, 'birthdate', widgets.AdminSplitDateTime) + self.assertFormfield(Member, "birthdate", widgets.AdminSplitDateTime) def test_TimeField(self): - self.assertFormfield(Event, 'start_time', widgets.AdminTimeWidget) + self.assertFormfield(Event, "start_time", widgets.AdminTimeWidget) def test_TextField(self): - self.assertFormfield(Event, 'description', widgets.AdminTextareaWidget) + self.assertFormfield(Event, "description", widgets.AdminTextareaWidget) def test_URLField(self): - self.assertFormfield(Event, 'link', widgets.AdminURLFieldWidget) + self.assertFormfield(Event, "link", widgets.AdminURLFieldWidget) def test_IntegerField(self): - self.assertFormfield(Event, 'min_age', widgets.AdminIntegerFieldWidget) + self.assertFormfield(Event, "min_age", widgets.AdminIntegerFieldWidget) def test_CharField(self): - self.assertFormfield(Member, 'name', widgets.AdminTextInputWidget) + self.assertFormfield(Member, "name", widgets.AdminTextInputWidget) def test_EmailField(self): - self.assertFormfield(Member, 'email', widgets.AdminEmailInputWidget) + self.assertFormfield(Member, "email", widgets.AdminEmailInputWidget) def test_FileField(self): - self.assertFormfield(Album, 'cover_art', widgets.AdminFileWidget) + self.assertFormfield(Album, "cover_art", widgets.AdminFileWidget) def test_ForeignKey(self): - self.assertFormfield(Event, 'main_band', forms.Select) + self.assertFormfield(Event, "main_band", forms.Select) def test_raw_id_ForeignKey(self): - self.assertFormfield(Event, 'main_band', widgets.ForeignKeyRawIdWidget, - raw_id_fields=['main_band']) + self.assertFormfield( + Event, + "main_band", + widgets.ForeignKeyRawIdWidget, + raw_id_fields=["main_band"], + ) def test_radio_fields_ForeignKey(self): - ff = self.assertFormfield(Event, 'main_band', widgets.AdminRadioSelect, - radio_fields={'main_band': admin.VERTICAL}) + ff = self.assertFormfield( + Event, + "main_band", + widgets.AdminRadioSelect, + radio_fields={"main_band": admin.VERTICAL}, + ) self.assertIsNone(ff.empty_label) def test_many_to_many(self): - self.assertFormfield(Band, 'members', forms.SelectMultiple) + self.assertFormfield(Band, "members", forms.SelectMultiple) def test_raw_id_many_to_many(self): - self.assertFormfield(Band, 'members', widgets.ManyToManyRawIdWidget, - raw_id_fields=['members']) + self.assertFormfield( + Band, "members", widgets.ManyToManyRawIdWidget, raw_id_fields=["members"] + ) def test_filtered_many_to_many(self): - self.assertFormfield(Band, 'members', widgets.FilteredSelectMultiple, - filter_vertical=['members']) + self.assertFormfield( + Band, "members", widgets.FilteredSelectMultiple, filter_vertical=["members"] + ) def test_formfield_overrides(self): - self.assertFormfield(Event, 'start_date', forms.TextInput, - formfield_overrides={DateField: {'widget': forms.TextInput}}) + self.assertFormfield( + Event, + "start_date", + forms.TextInput, + formfield_overrides={DateField: {"widget": forms.TextInput}}, + ) def test_formfield_overrides_widget_instances(self): """ Widget instances in formfield_overrides are not shared between different fields. (#19423) """ + class BandAdmin(admin.ModelAdmin): formfield_overrides = { - CharField: {'widget': forms.TextInput(attrs={'size': '10'})} + CharField: {"widget": forms.TextInput(attrs={"size": "10"})} } + ma = BandAdmin(Band, admin.site) - f1 = ma.formfield_for_dbfield(Band._meta.get_field('name'), request=None) - f2 = ma.formfield_for_dbfield(Band._meta.get_field('style'), request=None) + f1 = ma.formfield_for_dbfield(Band._meta.get_field("name"), request=None) + f2 = ma.formfield_for_dbfield(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') + self.assertEqual(f1.widget.attrs["maxlength"], "100") + self.assertEqual(f2.widget.attrs["maxlength"], "20") + self.assertEqual(f2.widget.attrs["size"], "10") def test_formfield_overrides_m2m_filter_widget(self): """ @@ -150,13 +187,15 @@ class AdminFormfieldForDBFieldTests(SimpleTestCase): filter_horizontal widgets for ManyToManyFields may be overridden by specifying a widget in formfield_overrides. """ + class BandAdmin(admin.ModelAdmin): - filter_vertical = ['members'] + filter_vertical = ["members"] formfield_overrides = { - ManyToManyField: {'widget': forms.CheckboxSelectMultiple}, + ManyToManyField: {"widget": forms.CheckboxSelectMultiple}, } + ma = BandAdmin(Band, admin.site) - field = ma.formfield_for_dbfield(Band._meta.get_field('members'), request=None) + field = ma.formfield_for_dbfield(Band._meta.get_field("members"), request=None) self.assertIsInstance(field.widget.widget, forms.CheckboxSelectMultiple) def test_formfield_overrides_for_datetime_field(self): @@ -164,10 +203,14 @@ class AdminFormfieldForDBFieldTests(SimpleTestCase): Overriding the widget for DateTimeField doesn't overrides the default form_class for that field (#26449). """ + class MemberAdmin(admin.ModelAdmin): - formfield_overrides = {DateTimeField: {'widget': widgets.AdminSplitDateTime}} + formfield_overrides = { + DateTimeField: {"widget": widgets.AdminSplitDateTime} + } + ma = MemberAdmin(Member, admin.site) - f1 = ma.formfield_for_dbfield(Member._meta.get_field('birthdate'), request=None) + f1 = ma.formfield_for_dbfield(Member._meta.get_field("birthdate"), request=None) self.assertIsInstance(f1.widget, widgets.AdminSplitDateTime) self.assertIsInstance(f1, forms.SplitDateTimeField) @@ -175,69 +218,79 @@ class AdminFormfieldForDBFieldTests(SimpleTestCase): """ formfield_overrides works for a custom field class. """ + class AlbumAdmin(admin.ModelAdmin): - formfield_overrides = {MyFileField: {'widget': forms.TextInput()}} + formfield_overrides = {MyFileField: {"widget": forms.TextInput()}} + ma = AlbumAdmin(Member, admin.site) - f1 = ma.formfield_for_dbfield(Album._meta.get_field('backside_art'), request=None) + f1 = ma.formfield_for_dbfield( + Album._meta.get_field("backside_art"), request=None + ) self.assertIsInstance(f1.widget, forms.TextInput) def test_field_with_choices(self): - self.assertFormfield(Member, 'gender', forms.Select) + self.assertFormfield(Member, "gender", forms.Select) def test_choices_with_radio_fields(self): - self.assertFormfield(Member, 'gender', widgets.AdminRadioSelect, - radio_fields={'gender': admin.VERTICAL}) + self.assertFormfield( + Member, + "gender", + widgets.AdminRadioSelect, + radio_fields={"gender": admin.VERTICAL}, + ) def test_inheritance(self): - self.assertFormfield(Album, 'backside_art', widgets.AdminFileWidget) + self.assertFormfield(Album, "backside_art", widgets.AdminFileWidget) def test_m2m_widgets(self): """m2m fields help text as it applies to admin app (#9321).""" + class AdvisorAdmin(admin.ModelAdmin): - filter_vertical = ['companies'] + filter_vertical = ["companies"] - self.assertFormfield(Advisor, 'companies', widgets.FilteredSelectMultiple, - filter_vertical=['companies']) + self.assertFormfield( + Advisor, + "companies", + widgets.FilteredSelectMultiple, + filter_vertical=["companies"], + ) ma = AdvisorAdmin(Advisor, admin.site) - f = ma.formfield_for_dbfield(Advisor._meta.get_field('companies'), request=None) + f = ma.formfield_for_dbfield(Advisor._meta.get_field("companies"), request=None) self.assertEqual( f.help_text, - 'Hold down “Control”, or “Command” on a Mac, to select more than one.' + "Hold down “Control”, or “Command” on a Mac, to select more than one.", ) -@override_settings(ROOT_URLCONF='admin_widgets.urls') +@override_settings(ROOT_URLCONF="admin_widgets.urls") class AdminFormfieldForDBFieldWithRequestTests(TestDataMixin, TestCase): - def test_filter_choices_by_request_user(self): """ Ensure the user can only see their own cars in the foreign key dropdown. """ self.client.force_login(self.superuser) - response = self.client.get(reverse('admin:admin_widgets_cartire_add')) + response = self.client.get(reverse("admin:admin_widgets_cartire_add")) self.assertNotContains(response, "BMW M3") self.assertContains(response, "Volkswagen Passat") -@override_settings(ROOT_URLCONF='admin_widgets.urls') +@override_settings(ROOT_URLCONF="admin_widgets.urls") class AdminForeignKeyWidgetChangeList(TestDataMixin, TestCase): - def setUp(self): self.client.force_login(self.superuser) def test_changelist_ForeignKey(self): - response = self.client.get(reverse('admin:admin_widgets_car_changelist')) - self.assertContains(response, '/auth/user/add/') + response = self.client.get(reverse("admin:admin_widgets_car_changelist")) + self.assertContains(response, "/auth/user/add/") -@override_settings(ROOT_URLCONF='admin_widgets.urls') +@override_settings(ROOT_URLCONF="admin_widgets.urls") class AdminForeignKeyRawIdWidget(TestDataMixin, TestCase): - def setUp(self): self.client.force_login(self.superuser) def test_nonexistent_target_id(self): - band = Band.objects.create(name='Bogey Blues') + band = Band.objects.create(name="Bogey Blues") pk = band.pk band.delete() post_data = { @@ -245,54 +298,63 @@ class AdminForeignKeyRawIdWidget(TestDataMixin, TestCase): } # Try posting with a nonexistent pk in a raw id field: this # should result in an error message, not a server exception. - response = self.client.post(reverse('admin:admin_widgets_event_add'), post_data) - self.assertContains(response, 'Select a valid choice. That choice is not one of the available choices.') + response = self.client.post(reverse("admin:admin_widgets_event_add"), post_data) + self.assertContains( + response, + "Select a valid choice. That choice is not one of the available choices.", + ) def test_invalid_target_id(self): - for test_str in ('Iñtërnâtiônàlizætiøn', "1234'", -1234): + 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. - response = self.client.post(reverse('admin:admin_widgets_event_add'), {"main_band": test_str}) + response = self.client.post( + reverse("admin:admin_widgets_event_add"), {"main_band": test_str} + ) - self.assertContains(response, 'Select a valid choice. That choice is not one of the available choices.') + self.assertContains( + response, + "Select a valid choice. That choice is not one of the available choices.", + ) def test_url_params_from_lookup_dict_any_iterable(self): - lookup1 = widgets.url_params_from_lookup_dict({'color__in': ('red', 'blue')}) - lookup2 = widgets.url_params_from_lookup_dict({'color__in': ['red', 'blue']}) - self.assertEqual(lookup1, {'color__in': 'red,blue'}) + lookup1 = widgets.url_params_from_lookup_dict({"color__in": ("red", "blue")}) + lookup2 = widgets.url_params_from_lookup_dict({"color__in": ["red", "blue"]}) + self.assertEqual(lookup1, {"color__in": "red,blue"}) self.assertEqual(lookup1, lookup2) 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()}) + 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) def test_label_and_url_for_value_invalid_uuid(self): - field = Bee._meta.get_field('honeycomb') + field = Bee._meta.get_field("honeycomb") self.assertIsInstance(field.target_field, UUIDField) widget = widgets.ForeignKeyRawIdWidget(field.remote_field, admin.site) - self.assertEqual(widget.label_and_url_for_value('invalid-uuid'), ('', '')) + self.assertEqual(widget.label_and_url_for_value("invalid-uuid"), ("", "")) class FilteredSelectMultipleWidgetTest(SimpleTestCase): def test_render(self): # Backslash in verbose_name to ensure it is JavaScript escaped. - w = widgets.FilteredSelectMultiple('test\\', False) + w = widgets.FilteredSelectMultiple("test\\", False) self.assertHTMLEqual( - w.render('test', 'test'), + w.render("test", "test"), '<select multiple name="test" class="selectfilter" ' - 'data-field-name="test\\" data-is-stacked="0">\n</select>' + 'data-field-name="test\\" data-is-stacked="0">\n</select>', ) def test_stacked_render(self): # Backslash in verbose_name to ensure it is JavaScript escaped. - w = widgets.FilteredSelectMultiple('test\\', True) + w = widgets.FilteredSelectMultiple("test\\", True) self.assertHTMLEqual( - w.render('test', 'test'), + w.render("test", "test"), '<select multiple name="test" class="selectfilterstacked" ' - 'data-field-name="test\\" data-is-stacked="1">\n</select>' + 'data-field-name="test\\" data-is-stacked="1">\n</select>', ) @@ -300,13 +362,13 @@ class AdminDateWidgetTest(SimpleTestCase): def test_attrs(self): w = widgets.AdminDateWidget() self.assertHTMLEqual( - w.render('test', datetime(2007, 12, 1, 9, 30)), + w.render("test", datetime(2007, 12, 1, 9, 30)), '<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'}) + w = widgets.AdminDateWidget(attrs={"size": 20, "class": "myDateField"}) self.assertHTMLEqual( - w.render('test', datetime(2007, 12, 1, 9, 30)), + w.render("test", datetime(2007, 12, 1, 9, 30)), '<input value="2007-12-01" type="text" class="myDateField" name="test" size="20">', ) @@ -315,13 +377,13 @@ class AdminTimeWidgetTest(SimpleTestCase): def test_attrs(self): w = widgets.AdminTimeWidget() self.assertHTMLEqual( - w.render('test', datetime(2007, 12, 1, 9, 30)), + w.render("test", datetime(2007, 12, 1, 9, 30)), '<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'}) + w = widgets.AdminTimeWidget(attrs={"size": 20, "class": "myTimeField"}) self.assertHTMLEqual( - w.render('test', datetime(2007, 12, 1, 9, 30)), + w.render("test", datetime(2007, 12, 1, 9, 30)), '<input value="09:30:00" type="text" class="myTimeField" name="test" size="20">', ) @@ -330,59 +392,58 @@ class AdminSplitDateTimeWidgetTest(SimpleTestCase): def test_render(self): w = widgets.AdminSplitDateTime() self.assertHTMLEqual( - w.render('test', datetime(2007, 12, 1, 9, 30)), + w.render("test", datetime(2007, 12, 1, 9, 30)), '<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>' + 'name="test_1" size="8"></p>', ) def test_localization(self): w = widgets.AdminSplitDateTime() - with translation.override('de-at'): + with translation.override("de-at"): w.is_localized = True self.assertHTMLEqual( - w.render('test', datetime(2007, 12, 1, 9, 30)), + 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>' + 'name="test_1" size="8"></p>', ) class AdminURLWidgetTest(SimpleTestCase): def test_get_context_validates_url(self): w = widgets.AdminURLFieldWidget() - for invalid in ['', '/not/a/full/url/', 'javascript:alert("Danger XSS!")']: + for invalid in ["", "/not/a/full/url/", 'javascript:alert("Danger XSS!")']: with self.subTest(url=invalid): - self.assertFalse(w.get_context('name', invalid, {})['url_valid']) - self.assertTrue(w.get_context('name', 'http://example.com', {})['url_valid']) + self.assertFalse(w.get_context("name", invalid, {})["url_valid"]) + self.assertTrue(w.get_context("name", "http://example.com", {})["url_valid"]) def test_render(self): w = widgets.AdminURLFieldWidget() self.assertHTMLEqual( - w.render('test', ''), - '<input class="vURLField" name="test" type="url">' + w.render("test", ""), '<input class="vURLField" name="test" type="url">' ) self.assertHTMLEqual( - w.render('test', 'http://example.com'), + w.render("test", "http://example.com"), '<p class="url">Currently:<a href="http://example.com">' - 'http://example.com</a><br>' + "http://example.com</a><br>" 'Change:<input class="vURLField" name="test" type="url" ' - 'value="http://example.com"></p>' + 'value="http://example.com"></p>', ) def test_render_idn(self): w = widgets.AdminURLFieldWidget() self.assertHTMLEqual( - w.render('test', 'http://example-äüö.com'), + w.render("test", "http://example-äüö.com"), '<p class="url">Currently: <a href="http://xn--example--7za4pnc.com">' - 'http://example-äüö.com</a><br>' + "http://example-äüö.com</a><br>" 'Change:<input class="vURLField" name="test" type="url" ' - 'value="http://example-äüö.com"></p>' + 'value="http://example-äüö.com"></p>', ) def test_render_quoting(self): @@ -392,47 +453,49 @@ class AdminURLWidgetTest(SimpleTestCase): """ HREF_RE = re.compile('href="([^"]+)"') VALUE_RE = re.compile('value="([^"]+)"') - TEXT_RE = re.compile('<a[^>]+>([^>]+)</a>') + TEXT_RE = re.compile("<a[^>]+>([^>]+)</a>") w = widgets.AdminURLFieldWidget() - output = w.render('test', 'http://example.com/<sometag>some-text</sometag>') + output = w.render("test", "http://example.com/<sometag>some-text</sometag>") self.assertEqual( HREF_RE.search(output)[1], - 'http://example.com/%3Csometag%3Esome-text%3C/sometag%3E', + "http://example.com/%3Csometag%3Esome-text%3C/sometag%3E", ) self.assertEqual( TEXT_RE.search(output)[1], - 'http://example.com/<sometag>some-text</sometag>', + "http://example.com/<sometag>some-text</sometag>", ) self.assertEqual( VALUE_RE.search(output)[1], - 'http://example.com/<sometag>some-text</sometag>', + "http://example.com/<sometag>some-text</sometag>", ) - output = w.render('test', 'http://example-äüö.com/<sometag>some-text</sometag>') + output = w.render("test", "http://example-äüö.com/<sometag>some-text</sometag>") self.assertEqual( HREF_RE.search(output)[1], - 'http://xn--example--7za4pnc.com/%3Csometag%3Esome-text%3C/sometag%3E', + "http://xn--example--7za4pnc.com/%3Csometag%3Esome-text%3C/sometag%3E", ) self.assertEqual( TEXT_RE.search(output)[1], - 'http://example-äüö.com/<sometag>some-text</sometag>', + "http://example-äüö.com/<sometag>some-text</sometag>", ) self.assertEqual( VALUE_RE.search(output)[1], - 'http://example-äüö.com/<sometag>some-text</sometag>', + "http://example-äüö.com/<sometag>some-text</sometag>", + ) + output = w.render( + "test", 'http://www.example.com/%C3%A4"><script>alert("XSS!")</script>"' ) - output = w.render('test', 'http://www.example.com/%C3%A4"><script>alert("XSS!")</script>"') self.assertEqual( HREF_RE.search(output)[1], - 'http://www.example.com/%C3%A4%22%3E%3Cscript%3Ealert(%22XSS!%22)%3C/script%3E%22', + "http://www.example.com/%C3%A4%22%3E%3Cscript%3Ealert(%22XSS!%22)%3C/script%3E%22", ) self.assertEqual( TEXT_RE.search(output)[1], - 'http://www.example.com/%C3%A4"><script>' - 'alert("XSS!")</script>"' + "http://www.example.com/%C3%A4"><script>" + "alert("XSS!")</script>"", ) self.assertEqual( VALUE_RE.search(output)[1], - 'http://www.example.com/%C3%A4"><script>alert("XSS!")</script>"', + "http://www.example.com/%C3%A4"><script>alert("XSS!")</script>"", ) @@ -440,42 +503,42 @@ class AdminUUIDWidgetTests(SimpleTestCase): def test_attrs(self): w = widgets.AdminUUIDInputWidget() self.assertHTMLEqual( - w.render('test', '550e8400-e29b-41d4-a716-446655440000'), + w.render("test", "550e8400-e29b-41d4-a716-446655440000"), '<input value="550e8400-e29b-41d4-a716-446655440000" type="text" class="vUUIDField" name="test">', ) - w = widgets.AdminUUIDInputWidget(attrs={'class': 'myUUIDInput'}) + w = widgets.AdminUUIDInputWidget(attrs={"class": "myUUIDInput"}) self.assertHTMLEqual( - w.render('test', '550e8400-e29b-41d4-a716-446655440000'), + w.render("test", "550e8400-e29b-41d4-a716-446655440000"), '<input value="550e8400-e29b-41d4-a716-446655440000" type="text" class="myUUIDInput" name="test">', ) -@override_settings(ROOT_URLCONF='admin_widgets.urls') +@override_settings(ROOT_URLCONF="admin_widgets.urls") class AdminFileWidgetTests(TestDataMixin, TestCase): - @classmethod def setUpTestData(cls): super().setUpTestData() - band = Band.objects.create(name='Linkin Park') + band = Band.objects.create(name="Linkin Park") cls.album = band.album_set.create( - name='Hybrid Theory', cover_art=r'albums\hybrid_theory.jpg' + name="Hybrid Theory", cover_art=r"albums\hybrid_theory.jpg" ) def test_render(self): w = widgets.AdminFileWidget() self.assertHTMLEqual( - w.render('test', self.album.cover_art), + w.render("test", self.album.cover_art), '<p class="file-upload">Currently: <a href="%(STORAGE_URL)salbums/' r'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(''), + 'Change: <input type="file" name="test"></p>' + % { + "STORAGE_URL": default_storage.url(""), }, ) self.assertHTMLEqual( - w.render('test', SimpleUploadedFile('test', b'content')), + w.render("test", SimpleUploadedFile("test", b"content")), '<input type="file" name="test">', ) @@ -483,25 +546,27 @@ class AdminFileWidgetTests(TestDataMixin, TestCase): widget = widgets.AdminFileWidget() widget.is_required = True self.assertHTMLEqual( - widget.render('test', self.album.cover_art), + widget.render("test", self.album.cover_art), '<p class="file-upload">Currently: <a href="%(STORAGE_URL)salbums/' r'hybrid_theory.jpg">albums\hybrid_theory.jpg</a><br>' - 'Change: <input type="file" name="test"></p>' % { - 'STORAGE_URL': default_storage.url(''), + 'Change: <input type="file" name="test"></p>' + % { + "STORAGE_URL": default_storage.url(""), }, ) def test_render_disabled(self): - widget = widgets.AdminFileWidget(attrs={'disabled': True}) + widget = widgets.AdminFileWidget(attrs={"disabled": True}) self.assertHTMLEqual( - widget.render('test', self.album.cover_art), + widget.render("test", self.album.cover_art), '<p class="file-upload">Currently: <a href="%(STORAGE_URL)salbums/' r'hybrid_theory.jpg">albums\hybrid_theory.jpg</a> ' '<span class="clearable-file-input">' '<input type="checkbox" name="test-clear" id="test-clear_id" disabled>' '<label for="test-clear_id">Clear</label></span><br>' - 'Change: <input type="file" name="test" disabled></p>' % { - 'STORAGE_URL': default_storage.url(''), + 'Change: <input type="file" name="test" disabled></p>' + % { + "STORAGE_URL": default_storage.url(""), }, ) @@ -510,11 +575,14 @@ class AdminFileWidgetTests(TestDataMixin, TestCase): File widgets should render as a link when they're marked "read only." """ self.client.force_login(self.superuser) - response = self.client.get(reverse('admin:admin_widgets_album_change', args=(self.album.id,))) + response = self.client.get( + reverse("admin:admin_widgets_album_change", args=(self.album.id,)) + ) self.assertContains( response, '<div class="readonly"><a href="%(STORAGE_URL)salbums/hybrid_theory.jpg">' - r'albums\hybrid_theory.jpg</a></div>' % {'STORAGE_URL': default_storage.url('')}, + r"albums\hybrid_theory.jpg</a></div>" + % {"STORAGE_URL": default_storage.url("")}, html=True, ) self.assertNotContains( @@ -522,7 +590,7 @@ class AdminFileWidgetTests(TestDataMixin, TestCase): '<input type="file" name="cover_art" id="id_cover_art">', html=True, ) - response = self.client.get(reverse('admin:admin_widgets_album_add')) + response = self.client.get(reverse("admin:admin_widgets_album_add")) self.assertContains( response, '<div class="readonly"></div>', @@ -530,30 +598,29 @@ class AdminFileWidgetTests(TestDataMixin, TestCase): ) -@override_settings(ROOT_URLCONF='admin_widgets.urls') +@override_settings(ROOT_URLCONF="admin_widgets.urls") class ForeignKeyRawIdWidgetTest(TestCase): - def test_render(self): - band = Band.objects.create(name='Linkin Park') + band = Band.objects.create(name="Linkin Park") band.album_set.create( - name='Hybrid Theory', cover_art=r'albums\hybrid_theory.jpg' + name="Hybrid Theory", cover_art=r"albums\hybrid_theory.jpg" ) - rel_uuid = Album._meta.get_field('band').remote_field + rel_uuid = Album._meta.get_field("band").remote_field w = widgets.ForeignKeyRawIdWidget(rel_uuid, widget_admin_site) self.assertHTMLEqual( - w.render('test', band.uuid, attrs={}), + w.render("test", band.uuid, attrs={}), '<input type="text" name="test" value="%(banduuid)s" ' 'class="vForeignKeyRawIdAdminField vUUIDField">' '<a href="/admin_widgets/band/?_to_field=uuid" class="related-lookup" ' 'id="lookup_id_test" title="Lookup"></a> <strong>' '<a href="/admin_widgets/band/%(bandpk)s/change/">Linkin Park</a>' - '</strong>' % {'banduuid': band.uuid, 'bandpk': band.pk} + "</strong>" % {"banduuid": band.uuid, "bandpk": band.pk}, ) - rel_id = ReleaseEvent._meta.get_field('album').remote_field + rel_id = ReleaseEvent._meta.get_field("album").remote_field w = widgets.ForeignKeyRawIdWidget(rel_id, widget_admin_site) self.assertHTMLEqual( - w.render('test', None, attrs={}), + w.render("test", None, attrs={}), '<input type="text" name="test" class="vForeignKeyRawIdAdminField">' '<a href="/admin_widgets/album/?_to_field=id" class="related-lookup" ' 'id="lookup_id_test" title="Lookup"></a>', @@ -562,156 +629,159 @@ class ForeignKeyRawIdWidgetTest(TestCase): def test_relations_to_non_primary_key(self): # ForeignKeyRawIdWidget works with fields which aren't related to # the model's primary key. - apple = Inventory.objects.create(barcode=86, name='Apple') - Inventory.objects.create(barcode=22, name='Pear') - core = Inventory.objects.create( - barcode=87, name='Core', parent=apple - ) - rel = Inventory._meta.get_field('parent').remote_field + apple = Inventory.objects.create(barcode=86, name="Apple") + Inventory.objects.create(barcode=22, name="Pear") + core = Inventory.objects.create(barcode=87, name="Core", parent=apple) + rel = Inventory._meta.get_field("parent").remote_field w = widgets.ForeignKeyRawIdWidget(rel, widget_admin_site) self.assertHTMLEqual( - w.render('test', core.parent_id, attrs={}), + 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><a href="/admin_widgets/inventory/%(pk)s/change/">' - 'Apple</a></strong>' % {'pk': apple.pk} + "Apple</a></strong>" % {"pk": apple.pk}, ) def test_fk_related_model_not_in_admin(self): # FK to a model not registered with admin site. Raw ID widget should # have no magnifying glass link. See #16542 - big_honeycomb = Honeycomb.objects.create(location='Old tree') + big_honeycomb = Honeycomb.objects.create(location="Old tree") big_honeycomb.bee_set.create() - rel = Bee._meta.get_field('honeycomb').remote_field + rel = Bee._meta.get_field("honeycomb").remote_field w = widgets.ForeignKeyRawIdWidget(rel, widget_admin_site) self.assertHTMLEqual( - w.render('honeycomb_widget', big_honeycomb.pk, attrs={}), + w.render("honeycomb_widget", big_honeycomb.pk, attrs={}), '<input type="text" name="honeycomb_widget" value="%(hcombpk)s">' - ' <strong>%(hcomb)s</strong>' - % {'hcombpk': big_honeycomb.pk, 'hcomb': big_honeycomb} + " <strong>%(hcomb)s</strong>" + % {"hcombpk": big_honeycomb.pk, "hcomb": big_honeycomb}, ) def test_fk_to_self_model_not_in_admin(self): # FK to self, not registered with admin site. Raw ID widget should have # no magnifying glass link. See #16542 - subject1 = Individual.objects.create(name='Subject #1') - Individual.objects.create(name='Child', parent=subject1) - rel = Individual._meta.get_field('parent').remote_field + subject1 = Individual.objects.create(name="Subject #1") + Individual.objects.create(name="Child", parent=subject1) + rel = Individual._meta.get_field("parent").remote_field w = widgets.ForeignKeyRawIdWidget(rel, widget_admin_site) self.assertHTMLEqual( - w.render('individual_widget', subject1.pk, attrs={}), + w.render("individual_widget", subject1.pk, attrs={}), '<input type="text" name="individual_widget" value="%(subj1pk)s">' - ' <strong>%(subj1)s</strong>' - % {'subj1pk': subject1.pk, 'subj1': subject1} + " <strong>%(subj1)s</strong>" + % {"subj1pk": subject1.pk, "subj1": subject1}, ) def test_proper_manager_for_label_lookup(self): # see #9258 - rel = Inventory._meta.get_field('parent').remote_field + rel = Inventory._meta.get_field("parent").remote_field w = widgets.ForeignKeyRawIdWidget(rel, widget_admin_site) - hidden = Inventory.objects.create( - barcode=93, name='Hidden', hidden=True - ) + hidden = Inventory.objects.create(barcode=93, name="Hidden", hidden=True) child_of_hidden = Inventory.objects.create( - barcode=94, name='Child of hidden', parent=hidden + barcode=94, name="Child of hidden", parent=hidden ) self.assertHTMLEqual( - w.render('test', child_of_hidden.parent_id, attrs={}), + 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><a href="/admin_widgets/inventory/%(pk)s/change/">' - 'Hidden</a></strong>' % {'pk': hidden.pk} + "Hidden</a></strong>" % {"pk": hidden.pk}, ) def test_render_unsafe_limit_choices_to(self): - rel = UnsafeLimitChoicesTo._meta.get_field('band').remote_field + rel = UnsafeLimitChoicesTo._meta.get_field("band").remote_field w = widgets.ForeignKeyRawIdWidget(rel, widget_admin_site) self.assertHTMLEqual( - w.render('test', None), + w.render("test", None), '<input type="text" name="test" class="vForeignKeyRawIdAdminField">\n' '<a href="/admin_widgets/band/?name=%22%26%3E%3Cescapeme&_to_field=artist_ptr" ' - 'class="related-lookup" id="lookup_id_test" title="Lookup"></a>' + 'class="related-lookup" id="lookup_id_test" title="Lookup"></a>', ) def test_render_fk_as_pk_model(self): - rel = VideoStream._meta.get_field('release_event').remote_field + rel = VideoStream._meta.get_field("release_event").remote_field w = widgets.ForeignKeyRawIdWidget(rel, widget_admin_site) self.assertHTMLEqual( - w.render('test', None), + w.render("test", None), '<input type="text" name="test" class="vForeignKeyRawIdAdminField">\n' '<a href="/admin_widgets/releaseevent/?_to_field=album" ' - 'class="related-lookup" id="lookup_id_test" title="Lookup"></a>' + 'class="related-lookup" id="lookup_id_test" title="Lookup"></a>', ) -@override_settings(ROOT_URLCONF='admin_widgets.urls') +@override_settings(ROOT_URLCONF="admin_widgets.urls") class ManyToManyRawIdWidgetTest(TestCase): - def test_render(self): - band = Band.objects.create(name='Linkin Park') + band = Band.objects.create(name="Linkin Park") - m1 = Member.objects.create(name='Chester') - m2 = Member.objects.create(name='Mike') + m1 = Member.objects.create(name="Chester") + m2 = Member.objects.create(name="Mike") band.members.add(m1, m2) - rel = Band._meta.get_field('members').remote_field + rel = Band._meta.get_field("members").remote_field w = widgets.ManyToManyRawIdWidget(rel, widget_admin_site) self.assertHTMLEqual( - w.render('test', [m1.pk, m2.pk], attrs={}), ( + 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>' - ) % {'m1pk': m1.pk, 'm2pk': m2.pk} + ) + % {"m1pk": m1.pk, "m2pk": m2.pk}, ) self.assertHTMLEqual( - w.render('test', [m1.pk]), ( + 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>' - ) % {'m1pk': m1.pk} + ) + % {"m1pk": m1.pk}, ) def test_m2m_related_model_not_in_admin(self): # M2M relationship with model not registered with admin site. Raw ID # widget should have no magnifying glass link. See #16542 - consultor1 = Advisor.objects.create(name='Rockstar Techie') + consultor1 = Advisor.objects.create(name="Rockstar Techie") - c1 = Company.objects.create(name='Doodle') - c2 = Company.objects.create(name='Pear') + c1 = Company.objects.create(name="Doodle") + c2 = Company.objects.create(name="Pear") consultor1.companies.add(c1, c2) - rel = Advisor._meta.get_field('companies').remote_field + rel = Advisor._meta.get_field("companies").remote_field w = widgets.ManyToManyRawIdWidget(rel, widget_admin_site) self.assertHTMLEqual( - w.render('company_widget1', [c1.pk, c2.pk], attrs={}), - '<input type="text" name="company_widget1" value="%(c1pk)s,%(c2pk)s">' % {'c1pk': c1.pk, 'c2pk': c2.pk} + w.render("company_widget1", [c1.pk, c2.pk], attrs={}), + '<input type="text" name="company_widget1" value="%(c1pk)s,%(c2pk)s">' + % {"c1pk": c1.pk, "c2pk": c2.pk}, ) self.assertHTMLEqual( - w.render('company_widget2', [c1.pk]), - '<input type="text" name="company_widget2" value="%(c1pk)s">' % {'c1pk': c1.pk} + w.render("company_widget2", [c1.pk]), + '<input type="text" name="company_widget2" value="%(c1pk)s">' + % {"c1pk": c1.pk}, ) -@override_settings(ROOT_URLCONF='admin_widgets.urls') +@override_settings(ROOT_URLCONF="admin_widgets.urls") class RelatedFieldWidgetWrapperTests(SimpleTestCase): def test_no_can_add_related(self): - rel = Individual._meta.get_field('parent').remote_field + rel = Individual._meta.get_field("parent").remote_field w = widgets.AdminRadioSelect() # Used to fail with a name error. w = widgets.RelatedFieldWidgetWrapper(w, rel, widget_admin_site) self.assertFalse(w.can_add_related) def test_select_multiple_widget_cant_change_delete_related(self): - rel = Individual._meta.get_field('parent').remote_field + rel = Individual._meta.get_field("parent").remote_field widget = forms.SelectMultiple() wrapper = widgets.RelatedFieldWidgetWrapper( - widget, rel, widget_admin_site, + widget, + rel, + widget_admin_site, can_add_related=True, can_change_related=True, can_delete_related=True, @@ -721,10 +791,12 @@ class RelatedFieldWidgetWrapperTests(SimpleTestCase): self.assertFalse(wrapper.can_delete_related) def test_on_delete_cascade_rel_cant_delete_related(self): - rel = Individual._meta.get_field('soulmate').remote_field + rel = Individual._meta.get_field("soulmate").remote_field widget = forms.Select() wrapper = widgets.RelatedFieldWidgetWrapper( - widget, rel, widget_admin_site, + widget, + rel, + widget_admin_site, can_add_related=True, can_change_related=True, can_delete_related=True, @@ -736,62 +808,67 @@ class RelatedFieldWidgetWrapperTests(SimpleTestCase): def test_custom_widget_render(self): class CustomWidget(forms.Select): def render(self, *args, **kwargs): - return 'custom render output' - rel = Album._meta.get_field('band').remote_field + return "custom render output" + + rel = Album._meta.get_field("band").remote_field widget = CustomWidget() wrapper = widgets.RelatedFieldWidgetWrapper( - widget, rel, widget_admin_site, + widget, + rel, + widget_admin_site, can_add_related=True, can_change_related=True, can_delete_related=True, ) - output = wrapper.render('name', 'value') - self.assertIn('custom render output', output) + output = wrapper.render("name", "value") + self.assertIn("custom render output", output) def test_widget_delegates_value_omitted_from_data(self): class CustomWidget(forms.Select): def value_omitted_from_data(self, data, files, name): return False - rel = Album._meta.get_field('band').remote_field + + rel = Album._meta.get_field("band").remote_field widget = CustomWidget() wrapper = widgets.RelatedFieldWidgetWrapper(widget, rel, widget_admin_site) - self.assertIs(wrapper.value_omitted_from_data({}, {}, 'band'), False) + self.assertIs(wrapper.value_omitted_from_data({}, {}, "band"), False) def test_widget_is_hidden(self): - rel = Album._meta.get_field('band').remote_field + rel = Album._meta.get_field("band").remote_field widget = forms.HiddenInput() widget.choices = () wrapper = widgets.RelatedFieldWidgetWrapper(widget, rel, widget_admin_site) self.assertIs(wrapper.is_hidden, True) - context = wrapper.get_context('band', None, {}) - self.assertIs(context['is_hidden'], True) - output = wrapper.render('name', 'value') + context = wrapper.get_context("band", None, {}) + self.assertIs(context["is_hidden"], True) + output = wrapper.render("name", "value") # Related item links are hidden. - self.assertNotIn('<a ', output) + self.assertNotIn("<a ", output) def test_widget_is_not_hidden(self): - rel = Album._meta.get_field('band').remote_field + rel = Album._meta.get_field("band").remote_field widget = forms.Select() wrapper = widgets.RelatedFieldWidgetWrapper(widget, rel, widget_admin_site) self.assertIs(wrapper.is_hidden, False) - context = wrapper.get_context('band', None, {}) - self.assertIs(context['is_hidden'], False) - output = wrapper.render('name', 'value') + context = wrapper.get_context("band", None, {}) + self.assertIs(context["is_hidden"], False) + output = wrapper.render("name", "value") # Related item links are present. - self.assertIn('<a ', output) + self.assertIn("<a ", output) -@override_settings(ROOT_URLCONF='admin_widgets.urls') +@override_settings(ROOT_URLCONF="admin_widgets.urls") class AdminWidgetSeleniumTestCase(AdminSeleniumTestCase): - available_apps = ['admin_widgets'] + AdminSeleniumTestCase.available_apps + available_apps = ["admin_widgets"] + AdminSeleniumTestCase.available_apps def setUp(self): - self.u1 = User.objects.create_superuser(username='super', password='secret', email='super@example.com') + self.u1 = User.objects.create_superuser( + username="super", password="secret", email="super@example.com" + ) class DateTimePickerSeleniumTests(AdminWidgetSeleniumTestCase): - def test_show_hide_date_time_picker_widgets(self): """ Pressing the ESC key or clicking on a widget value closes the date and @@ -800,57 +877,69 @@ class DateTimePickerSeleniumTests(AdminWidgetSeleniumTestCase): from selenium.webdriver.common.by import By from selenium.webdriver.common.keys import Keys - self.admin_login(username='super', password='secret', login_url='/') + self.admin_login(username="super", password="secret", login_url="/") # Open a page that has a date and time picker widgets - self.selenium.get(self.live_server_url + reverse('admin:admin_widgets_member_add')) + self.selenium.get( + self.live_server_url + reverse("admin:admin_widgets_member_add") + ) # First, with the date picker widget --------------------------------- - cal_icon = self.selenium.find_element(By.ID, 'calendarlink0') + cal_icon = self.selenium.find_element(By.ID, "calendarlink0") # The date picker is hidden - self.assertFalse(self.selenium.find_element(By.ID, 'calendarbox0').is_displayed()) + self.assertFalse( + self.selenium.find_element(By.ID, "calendarbox0").is_displayed() + ) # Click the calendar icon cal_icon.click() # The date picker is visible - self.assertTrue(self.selenium.find_element(By.ID, 'calendarbox0').is_displayed()) + self.assertTrue( + self.selenium.find_element(By.ID, "calendarbox0").is_displayed() + ) # Press the ESC key - self.selenium.find_element(By.TAG_NAME, 'body').send_keys([Keys.ESCAPE]) + self.selenium.find_element(By.TAG_NAME, "body").send_keys([Keys.ESCAPE]) # The date picker is hidden again - self.assertFalse(self.selenium.find_element(By.ID, 'calendarbox0').is_displayed()) + self.assertFalse( + self.selenium.find_element(By.ID, "calendarbox0").is_displayed() + ) # Click the calendar icon, then on the 15th of current month cal_icon.click() self.selenium.find_element(By.XPATH, "//a[contains(text(), '15')]").click() - self.assertFalse(self.selenium.find_element(By.ID, 'calendarbox0').is_displayed()) + self.assertFalse( + self.selenium.find_element(By.ID, "calendarbox0").is_displayed() + ) self.assertEqual( - self.selenium.find_element(By.ID, 'id_birthdate_0').get_attribute('value'), - datetime.today().strftime('%Y-%m-') + '15', + self.selenium.find_element(By.ID, "id_birthdate_0").get_attribute("value"), + datetime.today().strftime("%Y-%m-") + "15", ) # Then, with the time picker widget ---------------------------------- - time_icon = self.selenium.find_element(By.ID, 'clocklink0') + time_icon = self.selenium.find_element(By.ID, "clocklink0") # The time picker is hidden - self.assertFalse(self.selenium.find_element(By.ID, 'clockbox0').is_displayed()) + self.assertFalse(self.selenium.find_element(By.ID, "clockbox0").is_displayed()) # Click the time icon time_icon.click() # The time picker is visible - self.assertTrue(self.selenium.find_element(By.ID, 'clockbox0').is_displayed()) + self.assertTrue(self.selenium.find_element(By.ID, "clockbox0").is_displayed()) self.assertEqual( [ - x.text for x in - self.selenium.find_elements(By.XPATH, "//ul[@class='timelist']/li/a") + x.text + for x in self.selenium.find_elements( + By.XPATH, "//ul[@class='timelist']/li/a" + ) ], - ['Now', 'Midnight', '6 a.m.', 'Noon', '6 p.m.'] + ["Now", "Midnight", "6 a.m.", "Noon", "6 p.m."], ) # Press the ESC key - self.selenium.find_element(By.TAG_NAME, 'body').send_keys([Keys.ESCAPE]) + self.selenium.find_element(By.TAG_NAME, "body").send_keys([Keys.ESCAPE]) # The time picker is hidden again - self.assertFalse(self.selenium.find_element(By.ID, 'clockbox0').is_displayed()) + self.assertFalse(self.selenium.find_element(By.ID, "clockbox0").is_displayed()) # Click the time icon, then select the 'Noon' value time_icon.click() self.selenium.find_element(By.XPATH, "//a[contains(text(), 'Noon')]").click() - self.assertFalse(self.selenium.find_element(By.ID, 'clockbox0').is_displayed()) + self.assertFalse(self.selenium.find_element(By.ID, "clockbox0").is_displayed()) self.assertEqual( - self.selenium.find_element(By.ID, 'id_birthdate_1').get_attribute('value'), - '12:00:00', + self.selenium.find_element(By.ID, "id_birthdate_1").get_attribute("value"), + "12:00:00", ) def test_calendar_nonday_class(self): @@ -859,23 +948,26 @@ class DateTimePickerSeleniumTests(AdminWidgetSeleniumTestCase): Refs #4574. """ from selenium.webdriver.common.by import By - self.admin_login(username='super', password='secret', login_url='/') + + self.admin_login(username="super", password="secret", login_url="/") # Open a page that has a date and time picker widgets - self.selenium.get(self.live_server_url + reverse('admin:admin_widgets_member_add')) + self.selenium.get( + self.live_server_url + reverse("admin:admin_widgets_member_add") + ) # fill in the birth date. - self.selenium.find_element(By.ID, 'id_birthdate_0').send_keys('2013-06-01') + 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() + 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') + 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') + self.assertEqual(td.get_attribute("class"), "nonday") def test_calendar_selected_class(self): """ @@ -883,25 +975,28 @@ class DateTimePickerSeleniumTests(AdminWidgetSeleniumTestCase): Refs #4574. """ from selenium.webdriver.common.by import By - self.admin_login(username='super', password='secret', login_url='/') + + self.admin_login(username="super", password="secret", login_url="/") # Open a page that has a date and time picker widgets - self.selenium.get(self.live_server_url + reverse('admin:admin_widgets_member_add')) + self.selenium.get( + self.live_server_url + reverse("admin:admin_widgets_member_add") + ) # fill in the birth date. - self.selenium.find_element(By.ID, 'id_birthdate_0').send_keys('2013-06-01') + 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() + 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') + 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.get_attribute("class"), "selected") - self.assertEqual(selected.text, '1') + self.assertEqual(selected.text, "1") def test_calendar_no_selected_class(self): """ @@ -909,19 +1004,22 @@ class DateTimePickerSeleniumTests(AdminWidgetSeleniumTestCase): Refs #4574. """ from selenium.webdriver.common.by import By - self.admin_login(username='super', password='secret', login_url='/') + + self.admin_login(username="super", password="secret", login_url="/") # Open a page that has a date and time picker widgets - self.selenium.get(self.live_server_url + reverse('admin:admin_widgets_member_add')) + self.selenium.get( + self.live_server_url + reverse("admin:admin_widgets_member_add") + ) # Click the calendar icon - self.selenium.find_element(By.ID, 'calendarlink0').click() + 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') + 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'] + selected = [td for td in tds if td.get_attribute("class") == "selected"] self.assertEqual(len(selected), 0) @@ -931,18 +1029,23 @@ class DateTimePickerSeleniumTests(AdminWidgetSeleniumTestCase): supported by Django. """ from selenium.webdriver.common.by import By + self.selenium.set_window_size(1024, 768) - self.admin_login(username='super', password='secret', login_url='/') + self.admin_login(username="super", password="secret", login_url="/") # Enter test data - member = Member.objects.create(name='Bob', birthdate=datetime(1984, 5, 15), gender='M') + member = Member.objects.create( + name="Bob", birthdate=datetime(1984, 5, 15), gender="M" + ) # Get month name translations for every locale - month_string = 'May' - path = os.path.join(os.path.dirname(import_module('django.contrib.admin').__file__), 'locale') + month_string = "May" + 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]) + catalog = gettext.translation("djangojs", path, [language_code]) except OSError: continue if month_string in catalog._catalog: @@ -952,23 +1055,22 @@ class DateTimePickerSeleniumTests(AdminWidgetSeleniumTestCase): # Get the expected caption may_translation = month_name - expected_caption = '{:s} {:d}'.format(may_translation.upper(), 1984) + expected_caption = "{:s} {:d}".format(may_translation.upper(), 1984) # Test with every locale with override_settings(LANGUAGE_CODE=language_code): # Open a page that has a date picker widget - url = reverse('admin:admin_widgets_member_change', args=(member.pk,)) + url = reverse("admin:admin_widgets_member_change", args=(member.pk,)) self.selenium.get(self.live_server_url + url) # Click on the calendar icon - self.selenium.find_element(By.ID, 'calendarlink0').click() + self.selenium.find_element(By.ID, "calendarlink0").click() # Make sure that the right month and year are displayed - self.wait_for_text('#calendarin0 caption', expected_caption) + self.wait_for_text("#calendarin0 caption", expected_caption) -@override_settings(TIME_ZONE='Asia/Singapore') +@override_settings(TIME_ZONE="Asia/Singapore") class DateTimePickerShortcutsSeleniumTests(AdminWidgetSeleniumTestCase): - def test_date_time_picker_shortcuts(self): """ date/time/datetime picker shortcuts work in the current time zone. @@ -979,142 +1081,175 @@ class DateTimePickerShortcutsSeleniumTests(AdminWidgetSeleniumTestCase): the time zone to "Asia/Singapore". """ from selenium.webdriver.common.by import By - self.admin_login(username='super', password='secret', login_url='/') + + self.admin_login(username="super", password="secret", login_url="/") error_margin = timedelta(seconds=10) # If we are neighbouring a DST, we add an hour of error margin. - tz = zoneinfo.ZoneInfo('America/Chicago') - utc_now = datetime.now(zoneinfo.ZoneInfo('UTC')) + tz = zoneinfo.ZoneInfo("America/Chicago") + utc_now = datetime.now(zoneinfo.ZoneInfo("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) - self.selenium.get(self.live_server_url + reverse('admin:admin_widgets_member_add')) + self.selenium.get( + self.live_server_url + reverse("admin:admin_widgets_member_add") + ) - self.selenium.find_element(By.ID, 'id_name').send_keys('test') + 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') + shortcuts = self.selenium.find_elements( + By.CSS_SELECTOR, ".field-birthdate .datetimeshortcuts" + ) now = datetime.now() for shortcut in shortcuts: - shortcut.find_element(By.TAG_NAME, 'a').click() + shortcut.find_element(By.TAG_NAME, "a").click() # 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.assertCountSeleniumElements('.field-birthdate .timezonewarning', 1) + self.assertCountSeleniumElements(".field-birthdate .timezonewarning", 1) # Submit the form. with self.wait_page_loaded(): - self.selenium.find_element(By.NAME, '_save').click() + self.selenium.find_element(By.NAME, "_save").click() # Make sure that "now" in JavaScript is within 10 seconds # from "now" on the server side. - member = Member.objects.get(name='test') + member = Member.objects.get(name="test") self.assertGreater(member.birthdate, now - error_margin) self.assertLess(member.birthdate, now + error_margin) # The above tests run with Asia/Singapore which are on the positive side of # UTC. Here we test with a timezone on the negative side. -@override_settings(TIME_ZONE='US/Eastern') +@override_settings(TIME_ZONE="US/Eastern") class DateTimePickerAltTimezoneSeleniumTests(DateTimePickerShortcutsSeleniumTests): pass class HorizontalVerticalFilterSeleniumTests(AdminWidgetSeleniumTestCase): - def setUp(self): super().setUp() - self.lisa = Student.objects.create(name='Lisa') - self.john = Student.objects.create(name='John') - self.bob = Student.objects.create(name='Bob') - self.peter = Student.objects.create(name='Peter') - self.jenny = Student.objects.create(name='Jenny') - self.jason = Student.objects.create(name='Jason') - self.cliff = Student.objects.create(name='Cliff') - self.arthur = Student.objects.create(name='Arthur') - self.school = School.objects.create(name='School of Awesome') - - def assertActiveButtons(self, mode, field_name, choose, remove, choose_all=None, remove_all=None): - 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) + self.lisa = Student.objects.create(name="Lisa") + self.john = Student.objects.create(name="John") + self.bob = Student.objects.create(name="Bob") + self.peter = Student.objects.create(name="Peter") + self.jenny = Student.objects.create(name="Jenny") + self.jason = Student.objects.create(name="Jason") + self.cliff = Student.objects.create(name="Cliff") + self.arthur = Student.objects.create(name="Arthur") + self.school = School.objects.create(name="School of Awesome") + + def assertActiveButtons( + self, mode, field_name, choose, remove, choose_all=None, remove_all=None + ): + 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): from selenium.webdriver.common.by import By + original_url = self.selenium.current_url - 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 + 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( + 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)]) self.assertActiveButtons(mode, field_name, False, False, True, True) # Click 'Choose all' -------------------------------------------------- - if mode == 'horizontal': + if mode == "horizontal": self.selenium.find_element(By.ID, choose_all_link).click() - elif mode == 'vertical': + elif mode == "vertical": # There 's no 'Choose all' button in vertical mode, so individually # select all options and click 'Choose'. - for option in self.selenium.find_elements(By.CSS_SELECTOR, from_box + ' > option'): + for option in self.selenium.find_elements( + By.CSS_SELECTOR, from_box + " > option" + ): 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), - ]) + 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), + ], + ) self.assertActiveButtons(mode, field_name, False, False, False, True) # Click 'Remove all' -------------------------------------------------- - if mode == 'horizontal': + if mode == "horizontal": self.selenium.find_element(By.ID, remove_all_link).click() - elif mode == 'vertical': + elif mode == "vertical": # There 's no 'Remove all' button in vertical mode, so individually # select all options and click 'Remove'. - for option in self.selenium.find_elements(By.CSS_SELECTOR, to_box + ' > option'): + for option in self.selenium.find_elements( + By.CSS_SELECTOR, to_box + " > option" + ): 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( + 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, []) self.assertActiveButtons(mode, field_name, False, False, True, False) # Choose some options ------------------------------------------------ from_lisa_select_option = self.selenium.find_element( - By.CSS_SELECTOR, - '{} > option[value="{}"]'.format(from_box, self.lisa.id) + By.CSS_SELECTOR, '{} > option[value="{}"]'.format(from_box, 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')) + self.assertEqual( + from_lisa_select_option.get_attribute("title"), + from_lisa_select_option.get_attribute("text"), + ) self.select_option(from_box, str(self.lisa.id)) self.select_option(from_box, str(self.jason.id)) @@ -1124,21 +1259,33 @@ class HorizontalVerticalFilterSeleniumTests(AdminWidgetSeleniumTestCase): self.selenium.find_element(By.ID, choose_link).click() self.assertActiveButtons(mode, field_name, False, False, True, True) - 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), - ]) + 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), + ], + ) # Check the tooltip is still there after moving: ticket #20821 to_lisa_select_option = self.selenium.find_element( - By.CSS_SELECTOR, - '{} > option[value="{}"]'.format(to_box, self.lisa.id) + By.CSS_SELECTOR, '{} > option[value="{}"]'.format(to_box, self.lisa.id) + ) + self.assertEqual( + to_lisa_select_option.get_attribute("title"), + to_lisa_select_option.get_attribute("text"), ) - self.assertEqual(to_lisa_select_option.get_attribute('title'), to_lisa_select_option.get_attribute('text')) # Remove some options ------------------------------------------------- self.select_option(to_box, str(self.lisa.id)) @@ -1147,11 +1294,17 @@ class HorizontalVerticalFilterSeleniumTests(AdminWidgetSeleniumTestCase): self.selenium.find_element(By.ID, remove_link).click() self.assertActiveButtons(mode, field_name, False, False, True, True) - 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( + 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 -------------------------------------------- @@ -1159,14 +1312,24 @@ class HorizontalVerticalFilterSeleniumTests(AdminWidgetSeleniumTestCase): self.select_option(from_box, str(self.cliff.id)) 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), - ]) + 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), + ], + ) # Choose some more options -------------------------------------------- self.select_option(from_box, str(self.peter.id)) @@ -1199,23 +1362,33 @@ class HorizontalVerticalFilterSeleniumTests(AdminWidgetSeleniumTestCase): def test_basic(self): from selenium.webdriver.common.by import By + self.selenium.set_window_size(1024, 768) self.school.students.set([self.lisa, self.peter]) self.school.alumni.set([self.lisa, self.peter]) - self.admin_login(username='super', password='secret', login_url='/') - self.selenium.get(self.live_server_url + reverse('admin:admin_widgets_school_change', args=(self.school.id,))) + self.admin_login(username="super", password="secret", login_url="/") + self.selenium.get( + self.live_server_url + + reverse("admin:admin_widgets_school_change", args=(self.school.id,)) + ) self.wait_page_ready() - self.execute_basic_operations('vertical', 'students') - self.execute_basic_operations('horizontal', 'alumni') + self.execute_basic_operations("vertical", "students") + self.execute_basic_operations("horizontal", "alumni") # Save and check that everything is properly stored in the database --- self.selenium.find_element(By.XPATH, '//input[@value="Save"]').click() self.wait_page_ready() self.school = School.objects.get(id=self.school.id) # Reload from database - 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]) + 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], + ) def test_filter(self): """ @@ -1229,49 +1402,75 @@ class HorizontalVerticalFilterSeleniumTests(AdminWidgetSeleniumTestCase): self.school.students.set([self.lisa, self.peter]) self.school.alumni.set([self.lisa, self.peter]) - self.admin_login(username='super', password='secret', login_url='/') - self.selenium.get(self.live_server_url + reverse('admin:admin_widgets_school_change', args=(self.school.id,))) + self.admin_login(username="super", password="secret", login_url="/") + self.selenium.get( + self.live_server_url + + reverse("admin:admin_widgets_school_change", args=(self.school.id,)) + ) - for field_name in ['students', 'alumni']: - from_box = '#id_%s_from' % field_name - to_box = '#id_%s_to' % field_name - choose_link = 'id_%s_add_link' % field_name - remove_link = 'id_%s_remove_link' % field_name - input = self.selenium.find_element(By.ID, 'id_%s_input' % field_name) + for field_name in ["students", "alumni"]: + from_box = "#id_%s_from" % field_name + to_box = "#id_%s_to" % field_name + choose_link = "id_%s_add_link" % field_name + remove_link = "id_%s_remove_link" % field_name + input = self.selenium.find_element(By.ID, "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), - ]) + 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') + 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)]) + 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), - ]) + 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), + ], + ) # ----------------------------------------------------------------- # Choosing a filtered option sends it properly to the 'to' box. - input.send_keys('a') - self.assertSelectOptions(from_box, [str(self.arthur.id), str(self.jason.id)]) + input.send_keys("a") + self.assertSelectOptions( + from_box, [str(self.arthur.id), str(self.jason.id)] + ) self.select_option(from_box, str(self.jason.id)) self.selenium.find_element(By.ID, choose_link).click() self.assertSelectOptions(from_box, [str(self.arthur.id)]) - self.assertSelectOptions(to_box, [ - str(self.lisa.id), str(self.peter.id), str(self.jason.id), - ]) + self.assertSelectOptions( + to_box, + [ + str(self.lisa.id), + str(self.peter.id), + str(self.jason.id), + ], + ) self.select_option(to_box, str(self.lisa.id)) self.selenium.find_element(By.ID, remove_link).click() @@ -1279,11 +1478,17 @@ class HorizontalVerticalFilterSeleniumTests(AdminWidgetSeleniumTestCase): self.assertSelectOptions(to_box, [str(self.peter.id), str(self.jason.id)]) input.send_keys([Keys.BACK_SPACE]) # Clear text box - self.assertSelectOptions(from_box, [ - str(self.arthur.id), str(self.bob.id), - str(self.cliff.id), str(self.jenny.id), - str(self.john.id), str(self.lisa.id), - ]) + self.assertSelectOptions( + from_box, + [ + str(self.arthur.id), + str(self.bob.id), + str(self.cliff.id), + str(self.jenny.id), + str(self.john.id), + str(self.lisa.id), + ], + ) self.assertSelectOptions(to_box, [str(self.peter.id), str(self.jason.id)]) # ----------------------------------------------------------------- @@ -1291,7 +1496,7 @@ class HorizontalVerticalFilterSeleniumTests(AdminWidgetSeleniumTestCase): # the 'to' box. self.select_option(to_box, str(self.jason.id)) self.selenium.find_element(By.ID, remove_link).click() - input.send_keys('ja') + 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)]) @@ -1311,24 +1516,31 @@ class HorizontalVerticalFilterSeleniumTests(AdminWidgetSeleniumTestCase): filter_horizontal/filter_vertical widgets (#13614). """ from selenium.webdriver.common.by import By + self.school.students.set([self.lisa, self.peter]) self.school.alumni.set([self.lisa, self.peter]) - self.admin_login(username='super', password='secret', login_url='/') - change_url = reverse('admin:admin_widgets_school_change', args=(self.school.id,)) + self.admin_login(username="super", password="secret", login_url="/") + change_url = reverse( + "admin:admin_widgets_school_change", args=(self.school.id,) + ) self.selenium.get(self.live_server_url + change_url) # Navigate away and go back to the change form page. - self.selenium.find_element(By.LINK_TEXT, 'Home').click() + self.selenium.find_element(By.LINK_TEXT, "Home").click() self.selenium.back() expected_unselected_values = [ - str(self.arthur.id), str(self.bob.id), str(self.cliff.id), - str(self.jason.id), str(self.jenny.id), str(self.john.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), ] expected_selected_values = [str(self.lisa.id), str(self.peter.id)] # Everything is still in place - self.assertSelectOptions('#id_students_from', expected_unselected_values) - self.assertSelectOptions('#id_students_to', expected_selected_values) - self.assertSelectOptions('#id_alumni_from', expected_unselected_values) - self.assertSelectOptions('#id_alumni_to', expected_selected_values) + self.assertSelectOptions("#id_students_from", expected_unselected_values) + self.assertSelectOptions("#id_students_to", expected_selected_values) + self.assertSelectOptions("#id_alumni_from", expected_unselected_values) + self.assertSelectOptions("#id_alumni_to", expected_selected_values) def test_refresh_page(self): """ @@ -1338,11 +1550,13 @@ class HorizontalVerticalFilterSeleniumTests(AdminWidgetSeleniumTestCase): self.school.students.add(self.arthur, self.jason) self.school.alumni.add(self.arthur, self.jason) - self.admin_login(username='super', password='secret', login_url='/') - change_url = reverse('admin:admin_widgets_school_change', args=(self.school.id,)) + self.admin_login(username="super", password="secret", login_url="/") + change_url = reverse( + "admin:admin_widgets_school_change", args=(self.school.id,) + ) self.selenium.get(self.live_server_url + change_url) - self.assertCountSeleniumElements('#id_students_to > option', 2) + self.assertCountSeleniumElements("#id_students_to > option", 2) # self.selenium.refresh() or send_keys(Keys.F5) does hard reload and # doesn't replicate what happens when a user clicks the browser's @@ -1350,126 +1564,146 @@ class HorizontalVerticalFilterSeleniumTests(AdminWidgetSeleniumTestCase): with self.wait_page_loaded(): self.selenium.execute_script("location.reload()") - self.assertCountSeleniumElements('#id_students_to > option', 2) + self.assertCountSeleniumElements("#id_students_to > option", 2) class AdminRawIdWidgetSeleniumTests(AdminWidgetSeleniumTestCase): - def setUp(self): super().setUp() - Band.objects.create(id=42, name='Bogey Blues') - Band.objects.create(id=98, name='Green Potatoes') + Band.objects.create(id=42, name="Bogey Blues") + Band.objects.create(id=98, name="Green Potatoes") def test_ForeignKey(self): from selenium.webdriver.common.by import By - self.admin_login(username='super', password='secret', login_url='/') - self.selenium.get(self.live_server_url + reverse('admin:admin_widgets_event_add')) + + self.admin_login(username="super", password="secret", login_url="/") + self.selenium.get( + self.live_server_url + reverse("admin:admin_widgets_event_add") + ) 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'), '') + 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() + self.selenium.find_element(By.ID, "lookup_id_main_band").click() self.wait_for_and_switch_to_popup() - link = self.selenium.find_element(By.LINK_TEXT, 'Bogey Blues') - self.assertIn('/band/42/', link.get_attribute('href')) + link = self.selenium.find_element(By.LINK_TEXT, "Bogey Blues") + self.assertIn("/band/42/", link.get_attribute("href")) link.click() # The field now contains the selected band's id self.selenium.switch_to.window(main_window) - self.wait_for_value('#id_main_band', '42') + self.wait_for_value("#id_main_band", "42") # Reopen the popup window and click on another band - self.selenium.find_element(By.ID, 'lookup_id_main_band').click() + self.selenium.find_element(By.ID, "lookup_id_main_band").click() self.wait_for_and_switch_to_popup() - link = self.selenium.find_element(By.LINK_TEXT, 'Green Potatoes') - self.assertIn('/band/98/', link.get_attribute('href')) + link = self.selenium.find_element(By.LINK_TEXT, "Green Potatoes") + self.assertIn("/band/98/", link.get_attribute("href")) link.click() # The field now contains the other selected band's id self.selenium.switch_to.window(main_window) - self.wait_for_value('#id_main_band', '98') + self.wait_for_value("#id_main_band", "98") def test_many_to_many(self): from selenium.webdriver.common.by import By - self.admin_login(username='super', password='secret', login_url='/') - self.selenium.get(self.live_server_url + reverse('admin:admin_widgets_event_add')) + + self.admin_login(username="super", password="secret", login_url="/") + self.selenium.get( + self.live_server_url + reverse("admin:admin_widgets_event_add") + ) 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'), '') + self.assertEqual( + self.selenium.find_element(By.ID, "id_supporting_bands").get_attribute( + "value" + ), + "", + ) # Help text for the field is displayed self.assertEqual( - self.selenium.find_element(By.CSS_SELECTOR, '.field-supporting_bands div.help').text, - 'Supporting Bands.' + self.selenium.find_element( + By.CSS_SELECTOR, ".field-supporting_bands div.help" + ).text, + "Supporting Bands.", ) # Open the popup window and click on a band - self.selenium.find_element(By.ID, 'lookup_id_supporting_bands').click() + self.selenium.find_element(By.ID, "lookup_id_supporting_bands").click() self.wait_for_and_switch_to_popup() - link = self.selenium.find_element(By.LINK_TEXT, 'Bogey Blues') - self.assertIn('/band/42/', link.get_attribute('href')) + link = self.selenium.find_element(By.LINK_TEXT, "Bogey Blues") + self.assertIn("/band/42/", link.get_attribute("href")) link.click() # The field now contains the selected band's id self.selenium.switch_to.window(main_window) - self.wait_for_value('#id_supporting_bands', '42') + self.wait_for_value("#id_supporting_bands", "42") # Reopen the popup window and click on another band - self.selenium.find_element(By.ID, 'lookup_id_supporting_bands').click() + self.selenium.find_element(By.ID, "lookup_id_supporting_bands").click() self.wait_for_and_switch_to_popup() - link = self.selenium.find_element(By.LINK_TEXT, 'Green Potatoes') - self.assertIn('/band/98/', link.get_attribute('href')) + link = self.selenium.find_element(By.LINK_TEXT, "Green Potatoes") + self.assertIn("/band/98/", link.get_attribute("href")) link.click() # The field now contains the two selected bands' ids self.selenium.switch_to.window(main_window) - self.wait_for_value('#id_supporting_bands', '42,98') + self.wait_for_value("#id_supporting_bands", "42,98") class RelatedFieldWidgetSeleniumTests(AdminWidgetSeleniumTestCase): - def test_ForeignKey_using_to_field(self): from selenium.webdriver.common.by import By - self.admin_login(username='super', password='secret', login_url='/') - self.selenium.get(self.live_server_url + reverse('admin:admin_widgets_profile_add')) + + self.admin_login(username="super", password="secret", login_url="/") + self.selenium.get( + self.live_server_url + reverse("admin:admin_widgets_profile_add") + ) 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() + self.selenium.find_element(By.ID, "add_id_user").click() self.wait_for_and_switch_to_popup() - password_field = self.selenium.find_element(By.ID, 'id_password') - password_field.send_keys('password') + 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 = 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]' + 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) # The field now contains the new user - self.selenium.find_element(By.CSS_SELECTOR, '#id_user option[value=newuser]') + self.selenium.find_element(By.CSS_SELECTOR, "#id_user option[value=newuser]") # Click the Change User button to change it - self.selenium.find_element(By.ID, 'change_id_user').click() + self.selenium.find_element(By.ID, "change_id_user").click() self.wait_for_and_switch_to_popup() - username_field = self.selenium.find_element(By.ID, 'id_username') - username_value = 'changednewuser' + 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]' + 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) - self.selenium.find_element(By.CSS_SELECTOR, '#id_user option[value=changednewuser]') + self.selenium.find_element( + By.CSS_SELECTOR, "#id_user option[value=changednewuser]" + ) # Go ahead and submit the form to make sure it works self.selenium.find_element(By.CSS_SELECTOR, save_button_css_selector).click() - self.wait_for_text('li.success', 'The profile “changednewuser” was added successfully.') + self.wait_for_text( + "li.success", "The profile “changednewuser” was added successfully." + ) profiles = Profile.objects.all() self.assertEqual(len(profiles), 1) self.assertEqual(profiles[0].user.username, username_value) diff --git a/tests/admin_widgets/urls.py b/tests/admin_widgets/urls.py index d9372ac756..76012ddd85 100644 --- a/tests/admin_widgets/urls.py +++ b/tests/admin_widgets/urls.py @@ -3,5 +3,5 @@ from django.urls import path from . import widgetadmin urlpatterns = [ - path('', widgetadmin.site.urls), + path("", widgetadmin.site.urls), ] diff --git a/tests/admin_widgets/widgetadmin.py b/tests/admin_widgets/widgetadmin.py index a025bc82a7..d7bb62be99 100644 --- a/tests/admin_widgets/widgetadmin.py +++ b/tests/admin_widgets/widgetadmin.py @@ -1,8 +1,20 @@ from django.contrib import admin from .models import ( - Advisor, Album, Band, Bee, Car, CarTire, Event, Inventory, Member, Profile, - ReleaseEvent, School, User, VideoStream, + Advisor, + Album, + Band, + Bee, + Car, + CarTire, + Event, + Inventory, + Member, + Profile, + ReleaseEvent, + School, + User, + VideoStream, ) @@ -11,8 +23,8 @@ class WidgetAdmin(admin.AdminSite): class CarAdmin(admin.ModelAdmin): - list_display = ['make', 'model', 'owner'] - list_editable = ['owner'] + list_display = ["make", "model", "owner"] + list_editable = ["owner"] class CarTireAdmin(admin.ModelAdmin): @@ -24,20 +36,23 @@ class CarTireAdmin(admin.ModelAdmin): class EventAdmin(admin.ModelAdmin): - raw_id_fields = ['main_band', 'supporting_bands'] + raw_id_fields = ["main_band", "supporting_bands"] class AlbumAdmin(admin.ModelAdmin): - fields = ('name', 'cover_art',) - readonly_fields = ('cover_art',) + fields = ( + "name", + "cover_art", + ) + readonly_fields = ("cover_art",) class SchoolAdmin(admin.ModelAdmin): - filter_vertical = ('students',) - filter_horizontal = ('alumni',) + filter_vertical = ("students",) + filter_horizontal = ("alumni",) -site = WidgetAdmin(name='widget-admin') +site = WidgetAdmin(name="widget-admin") site.register(User) site.register(Car, CarAdmin) @@ -47,8 +62,8 @@ site.register(Member) site.register(Band) site.register(Event, EventAdmin) site.register(Album, AlbumAdmin) -site.register(ReleaseEvent, search_fields=['name']) -site.register(VideoStream, autocomplete_fields=['release_event']) +site.register(ReleaseEvent, search_fields=["name"]) +site.register(VideoStream, autocomplete_fields=["release_event"]) site.register(Inventory) |