import datetime from django.forms import ChoiceField, Form, MultiWidget, Select, TextInput from django.test import override_settings from django.utils.safestring import mark_safe from .test_choicewidget import ChoiceWidgetTest class SelectTest(ChoiceWidgetTest): widget = Select def test_render(self): html = """ """ for choices in (self.beatles, dict(self.beatles)): with self.subTest(choices): self.check_html(self.widget(choices=choices), "beatle", "J", html=html) def test_render_none(self): """ If the value is None, none of the options are selected. """ self.check_html( self.widget(choices=self.beatles), "beatle", None, html=( """""" ), ) def test_render_label_value(self): """ If the value corresponds to a label (but not to an option value), none of the options are selected. """ self.check_html( self.widget(choices=self.beatles), "beatle", "John", html=( """""" ), ) def test_render_selected(self): """ Only one option can be selected (#8103). """ choices = [("0", "0"), ("1", "1"), ("2", "2"), ("3", "3"), ("0", "extra")] self.check_html( self.widget(choices=choices), "choices", "0", html=( """""" ), ) def test_constructor_attrs(self): """ Select options shouldn't inherit the parent widget attrs. """ widget = Select( attrs={"class": "super", "id": "super"}, choices=[(1, 1), (2, 2), (3, 3)], ) self.check_html( widget, "num", 2, html=( """""" ), ) def test_compare_to_str(self): """ The value is compared to its str(). """ self.check_html( self.widget(choices=[("1", "1"), ("2", "2"), ("3", "3")]), "num", 2, html=( """""" ), ) self.check_html( self.widget(choices=[(1, 1), (2, 2), (3, 3)]), "num", "2", html=( """""" ), ) self.check_html( self.widget(choices=[(1, 1), (2, 2), (3, 3)]), "num", 2, html=( """""" ), ) def test_choices_constructor(self): widget = Select(choices=[(1, 1), (2, 2), (3, 3)]) self.check_html( widget, "num", 2, html=( """""" ), ) def test_choices_constructor_generator(self): """ If choices is passed to the constructor and is a generator, it can be iterated over multiple times without getting consumed. """ def get_choices(): for i in range(5): yield (i, i) widget = Select(choices=get_choices()) self.check_html( widget, "num", 2, html=( """""" ), ) self.check_html( widget, "num", 3, html=( """""" ), ) def test_choices_escaping(self): choices = (("bad", "you & me"), ("good", mark_safe("you > me"))) self.check_html( self.widget(choices=choices), "escape", None, html=( """""" ), ) def test_choices_unicode(self): self.check_html( self.widget(choices=[("ŠĐĆŽćžšđ", "ŠĐabcĆŽćžšđ"), ("ćžšđ", "abcćžšđ")]), "email", "ŠĐĆŽćžšđ", html=( """ """ ), ) def test_choices_optgroup(self): """ Choices can be nested one level in order to create HTML optgroups. """ html = """ """ for widget in self.nested_widgets: with self.subTest(widget): self.check_html(widget, "nestchoice", None, html=html) def test_choices_select_outer(self): html = """ """ for widget in self.nested_widgets: with self.subTest(widget): self.check_html(widget, "nestchoice", "outer1", html=html) def test_choices_select_inner(self): html = """ """ for widget in self.nested_widgets: with self.subTest(widget): self.check_html(widget, "nestchoice", "inner1", html=html) @override_settings(USE_THOUSAND_SEPARATOR=True) def test_doesnt_localize_option_value(self): choices = [ (1, "One"), (1000, "One thousand"), (1000000, "One million"), ] html = """ """ self.check_html(self.widget(choices=choices), "number", None, html=html) choices = [ (datetime.time(0, 0), "midnight"), (datetime.time(12, 0), "noon"), ] html = """ """ self.check_html(self.widget(choices=choices), "time", None, html=html) def _test_optgroups(self, choices): groups = list( self.widget(choices=choices).optgroups( "name", ["vhs"], attrs={"class": "super"}, ) ) audio, video, unknown = groups label, options, index = audio self.assertEqual(label, "Audio") self.assertEqual( options, [ { "value": "vinyl", "type": "select", "attrs": {}, "index": "0_0", "label": "Vinyl", "template_name": "django/forms/widgets/select_option.html", "name": "name", "selected": False, "wrap_label": True, }, { "value": "cd", "type": "select", "attrs": {}, "index": "0_1", "label": "CD", "template_name": "django/forms/widgets/select_option.html", "name": "name", "selected": False, "wrap_label": True, }, ], ) self.assertEqual(index, 0) label, options, index = video self.assertEqual(label, "Video") self.assertEqual( options, [ { "value": "vhs", "template_name": "django/forms/widgets/select_option.html", "label": "VHS Tape", "attrs": {"selected": True}, "index": "1_0", "name": "name", "selected": True, "type": "select", "wrap_label": True, }, { "value": "dvd", "template_name": "django/forms/widgets/select_option.html", "label": "DVD", "attrs": {}, "index": "1_1", "name": "name", "selected": False, "type": "select", "wrap_label": True, }, ], ) self.assertEqual(index, 1) label, options, index = unknown self.assertIsNone(label) self.assertEqual( options, [ { "value": "unknown", "selected": False, "template_name": "django/forms/widgets/select_option.html", "label": "Unknown", "attrs": {}, "index": "2", "name": "name", "type": "select", "wrap_label": True, } ], ) self.assertEqual(index, 2) def test_optgroups(self): choices_dict = { "Audio": [ ("vinyl", "Vinyl"), ("cd", "CD"), ], "Video": [ ("vhs", "VHS Tape"), ("dvd", "DVD"), ], "unknown": "Unknown", } choices_list = list(choices_dict.items()) choices_nested_dict = { k: dict(v) if isinstance(v, list) else v for k, v in choices_dict.items() } for choices in (choices_dict, choices_list, choices_nested_dict): with self.subTest(choices): self._test_optgroups(choices) def test_doesnt_render_required_when_impossible_to_select_empty_field(self): widget = self.widget(choices=[("J", "John"), ("P", "Paul")]) self.assertIs(widget.use_required_attribute(initial=None), False) def test_doesnt_render_required_when_no_choices_are_available(self): widget = self.widget(choices=[]) self.assertIs(widget.use_required_attribute(initial=None), False) def test_render_as_subwidget(self): """A RadioSelect as a subwidget of MultiWidget.""" choices = (("", "------"),) + self.beatles self.check_html( MultiWidget([self.widget(choices=choices), TextInput()]), "beatle", ["J", "Some text"], html=( """ """ ), ) def test_fieldset(self): class TestForm(Form): template_name = "forms_tests/use_fieldset.html" field = ChoiceField(widget=self.widget, choices=self.beatles) form = TestForm() self.assertIs(self.widget.use_fieldset, False) self.assertHTMLEqual( '
' '
', form.render(), )