# -*- coding: utf-8 -*- from __future__ import unicode_literals from django.contrib.admin.tests import AdminSeleniumWebDriverTestCase from django.core.urlresolvers import reverse from django.forms import ( CheckboxSelectMultiple, ClearableFileInput, RadioSelect, TextInput, ) from django.forms.widgets import ( ChoiceFieldRenderer, ChoiceInput, RadioFieldRenderer, ) from django.test import SimpleTestCase, override_settings from django.utils import six from django.utils.encoding import force_text, python_2_unicode_compatible from django.utils.safestring import SafeData from ..models import Article class FormsWidgetTests(SimpleTestCase): def test_radiofieldrenderer(self): # RadioSelect uses a RadioFieldRenderer to render the individual radio inputs. # You can manipulate that object directly to customize the way the RadioSelect # is rendered. w = RadioSelect() r = w.get_renderer('beatle', 'J', choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo'))) inp_set1 = [] inp_set2 = [] inp_set3 = [] inp_set4 = [] for inp in r: inp_set1.append(str(inp)) inp_set2.append('%s
' % inp) inp_set3.append('

%s %s

' % (inp.tag(), inp.choice_label)) inp_set4.append( '%s %s %s %s %s' % ( inp.name, inp.value, inp.choice_value, inp.choice_label, inp.is_checked(), ) ) self.assertHTMLEqual('\n'.join(inp_set1), """ """) self.assertHTMLEqual('\n'.join(inp_set2), """



""") self.assertHTMLEqual('\n'.join(inp_set3), """

John

Paul

George

Ringo

""") self.assertHTMLEqual('\n'.join(inp_set4), """beatle J J John True beatle J P Paul False beatle J G George False beatle J R Ringo False""") # A RadioFieldRenderer object also allows index access to individual RadioChoiceInput w = RadioSelect() r = w.get_renderer('beatle', 'J', choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo'))) self.assertHTMLEqual(str(r[1]), '') self.assertHTMLEqual( str(r[0]), '' ) self.assertTrue(r[0].is_checked()) self.assertFalse(r[1].is_checked()) self.assertEqual((r[1].name, r[1].value, r[1].choice_value, r[1].choice_label), ('beatle', 'J', 'P', 'Paul')) # These individual widgets can accept extra attributes if manually rendered. self.assertHTMLEqual( r[1].render(attrs={'extra': 'value'}), '' ) with self.assertRaises(IndexError): r[10] # You can create your own custom renderers for RadioSelect to use. class MyRenderer(RadioFieldRenderer): def render(self): return '
\n'.join(six.text_type(choice) for choice in self) w = RadioSelect(renderer=MyRenderer) self.assertHTMLEqual( w.render('beatle', 'G', choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo'))), """


""" ) # Or you can use custom RadioSelect fields that use your custom renderer. class CustomRadioSelect(RadioSelect): renderer = MyRenderer w = CustomRadioSelect() self.assertHTMLEqual( w.render('beatle', 'G', choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo'))), """


""" ) # You can customize rendering with outer_html/inner_html renderer variables (#22950) class MyRenderer(RadioFieldRenderer): # str is just to test some Python 2 issue with bytestrings outer_html = str('{content}') inner_html = '

{choice_value}{sub_widgets}

' w = RadioSelect(renderer=MyRenderer) output = w.render('beatle', 'J', choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo')), attrs={'id': 'bar'}) self.assertIsInstance(output, SafeData) self.assertHTMLEqual( output, """

""") def test_subwidget(self): # Each subwidget tag gets a separate ID when the widget has an ID specified self.assertHTMLEqual("\n".join(c.tag() for c in CheckboxSelectMultiple(attrs={'id': 'abc'}).subwidgets('letters', list('ac'), choices=zip(list('abc'), list('ABC')))), """ """) # Each subwidget tag does not get an ID if the widget does not have an ID specified self.assertHTMLEqual("\n".join(c.tag() for c in CheckboxSelectMultiple().subwidgets('letters', list('ac'), choices=zip(list('abc'), list('ABC')))), """ """) # The id_for_label property of the subwidget should return the ID that is used on the subwidget's tag self.assertHTMLEqual("\n".join('' % (c.choice_value, c.id_for_label) for c in CheckboxSelectMultiple(attrs={'id': 'abc'}).subwidgets('letters', [], choices=zip(list('abc'), list('ABC')))), """ """) def test_sub_widget_html_safe(self): widget = TextInput() subwidget = next(widget.subwidgets('username', 'John Doe')) self.assertTrue(hasattr(subwidget, '__html__')) self.assertEqual(force_text(subwidget), subwidget.__html__()) def test_choice_input_html_safe(self): widget = ChoiceInput('choices', 'CHOICE1', {}, ('CHOICE1', 'first choice'), 0) self.assertTrue(hasattr(ChoiceInput, '__html__')) self.assertEqual(force_text(widget), widget.__html__()) def test_choice_field_renderer_html_safe(self): renderer = ChoiceFieldRenderer('choices', 'CHOICE1', {}, [('CHOICE1', 'first_choice')]) renderer.choice_input_class = lambda *args: args self.assertTrue(hasattr(ChoiceFieldRenderer, '__html__')) self.assertEqual(force_text(renderer), renderer.__html__()) @override_settings(ROOT_URLCONF='forms_tests.urls') class LiveWidgetTests(AdminSeleniumWebDriverTestCase): available_apps = ['forms_tests'] + AdminSeleniumWebDriverTestCase.available_apps def test_textarea_trailing_newlines(self): """ Test that a roundtrip on a ModelForm doesn't alter the TextField value """ article = Article.objects.create(content="\nTst\n") self.selenium.get('%s%s' % (self.live_server_url, reverse('article_form', args=[article.pk]))) self.selenium.find_element_by_id('submit').submit() article = Article.objects.get(pk=article.pk) # Should be "\nTst\n" after #19251 is fixed self.assertEqual(article.content, "\r\nTst\r\n") @python_2_unicode_compatible class FakeFieldFile(object): """ Quacks like a FieldFile (has a .url and unicode representation), but doesn't require us to care about storages etc. """ url = 'something' def __str__(self): return self.url class ClearableFileInputTests(SimpleTestCase): def test_render_custom_template(self): widget = ClearableFileInput() widget.template_with_initial = ( '%(initial_text)s: %(initial)s ' '%(clear_template)s
%(input_text)s: %(input)s' ) self.assertHTMLEqual( widget.render('myfile', FakeFieldFile()), 'Currently: something ' ' ' '
Change: ' )