From 3778c476bb8b8f9972e0857d0c6bd0ea4ca2c235 Mon Sep 17 00:00:00 2001 From: Tom Talbot Date: Wed, 18 Jun 2014 17:16:04 +0100 Subject: [PATCH 1/6] Add unit tests for edit_handlers.py. Lint edit_handlers.py. --- .gitignore | 1 + wagtail/wagtailadmin/edit_handlers.py | 77 ++- .../wagtailadmin/tests/test_edit_handlers.py | 523 ++++++++++++++++++ 3 files changed, 572 insertions(+), 29 deletions(-) create mode 100644 wagtail/wagtailadmin/tests/test_edit_handlers.py diff --git a/.gitignore b/.gitignore index bd904efc9..57f9d0eab 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ *.pyc .DS_Store +/.ropeproject/ /.coverage /dist/ /MANIFEST diff --git a/wagtail/wagtailadmin/edit_handlers.py b/wagtail/wagtailadmin/edit_handlers.py index 245f7ad60..39f38d499 100644 --- a/wagtail/wagtailadmin/edit_handlers.py +++ b/wagtail/wagtailadmin/edit_handlers.py @@ -12,7 +12,11 @@ from django import forms from django.db import models from django.forms.models import fields_for_model from django.contrib.contenttypes.models import ContentType -from django.core.exceptions import ObjectDoesNotExist, ImproperlyConfigured, ValidationError +from django.core.exceptions import ( + ObjectDoesNotExist, + ImproperlyConfigured, + ValidationError +) from django.core.urlresolvers import reverse from django.conf import settings from django.utils.translation import ugettext as _ @@ -33,7 +37,8 @@ class FriendlyDateInput(forms.DateInput): if attrs: default_attrs.update(attrs) - super(FriendlyDateInput, self).__init__(attrs=default_attrs, format='%d %b %Y') + super(FriendlyDateInput, self).__init__(attrs=default_attrs, + format='%d %b %Y') class FriendlyTimeInput(forms.TimeInput): @@ -46,7 +51,8 @@ class FriendlyTimeInput(forms.TimeInput): if attrs: default_attrs.update(attrs) - super(FriendlyTimeInput, self).__init__(attrs=default_attrs, format='%I.%M%p') + super(FriendlyTimeInput, self).__init__(attrs=default_attrs, + format='%I.%M%p') class FriendlyTimeField(forms.CharField): @@ -87,7 +93,7 @@ class LocalizedDateInput(forms.DateInput): and adds class="friendly_date" to be picked up by jquery datepicker. """ def __init__(self, attrs=None): - default_attrs = {'class': 'localized_date', 'localize':True} + default_attrs = {'class': 'localized_date', 'localize': True} if attrs: default_attrs.update(attrs) @@ -104,7 +110,8 @@ class LocalizedTimeInput(forms.TimeInput): if attrs: default_attrs.update(attrs) # Just use 24-hour format - super(LocalizedTimeInput, self).__init__(attrs=default_attrs, format='%H:%M') + super(LocalizedTimeInput, self).__init__(attrs=default_attrs, + format='%H:%M') class LocalizedTimeField(forms.CharField): @@ -118,7 +125,7 @@ class LocalizedTimeField(forms.CharField): match = expr.match(time_string.lower()) if match: # Pull out values from string - hour_string, minute_string= match.groups() + hour_string, minute_string = match.groups() # Convert hours and minutes to integers hour = int(hour_string) @@ -126,31 +133,38 @@ class LocalizedTimeField(forms.CharField): minute = int(minute_string) else: minute = 0 - if hour>=24 or hour < 0 or minute >=60 or minute < 0: + if hour >= 24 or hour < 0 or minute >= 60 or minute < 0: raise ValidationError(_("Please type a valid time")) return datetime.time(hour=hour, minute=minute) else: - raise ValidationError(_("Please type a valid time") ) + raise ValidationError(_("Please type a valid time")) -if hasattr(settings, 'USE_L10N') and settings.USE_L10N==True: +if hasattr(settings, 'USE_L10N') and settings.USE_L10N is True: FORM_FIELD_OVERRIDES = { models.DateField: {'widget': LocalizedDateInput}, - models.TimeField: {'widget': LocalizedTimeInput, 'form_class': LocalizedTimeField}, + models.TimeField: {'widget': LocalizedTimeInput, + 'form_class': LocalizedTimeField}, } -else: # Fall back to friendly date/time +else: # Fall back to friendly date/time FORM_FIELD_OVERRIDES = { models.DateField: {'widget': FriendlyDateInput}, - models.TimeField: {'widget': FriendlyTimeInput, 'form_class': FriendlyTimeField}, + models.TimeField: {'widget': FriendlyTimeInput, + 'form_class': FriendlyTimeField}, } WIDGET_JS = { - FriendlyDateInput: (lambda id: "initFriendlyDateChooser(fixPrefix('%s'));" % id), - FriendlyTimeInput: (lambda id: "initFriendlyTimeChooser(fixPrefix('%s'));" % id), - LocalizedDateInput: (lambda id: "initLocalizedDateChooser(fixPrefix('%s'));" % id), - LocalizedTimeInput: (lambda id: "initLocalizedTimeChooser(fixPrefix('%s'));" % id), - RichTextArea: (lambda id: "makeRichTextEditable(fixPrefix('%s'));" % id), + FriendlyDateInput: (lambda id: "initFriendlyDateChooser(fixPrefix('%s'));" + % id), + FriendlyTimeInput: (lambda id: "initFriendlyTimeChooser(fixPrefix('%s'));" + % id), + LocalizedDateInput: (lambda id: "initLocalizedDateChooser(fixPrefix('%s'));" + % id), + LocalizedTimeInput: (lambda id: "initLocalizedTimeChooser(fixPrefix('%s'));" + % id), + RichTextArea: (lambda id: "makeRichTextEditable(fixPrefix('%s'));" + % id), TagWidget: ( lambda id: "initTagField(fixPrefix('%s'), '%s');" % ( id, addslashes(reverse('wagtailadmin_tag_autocomplete')) @@ -159,7 +173,8 @@ WIDGET_JS = { } -# Callback to allow us to override the default form fields provided for each model field. +# Callback to allow us to override the default form fields provided +# for each model field. def formfield_for_dbfield(db_field, **kwargs): # snarfed from django/contrib/admin/options.py @@ -177,13 +192,13 @@ def formfield_for_dbfield(db_field, **kwargs): class WagtailAdminModelFormMetaclass(ClusterFormMetaclass): # Override the behaviour of the regular ModelForm metaclass - # which handles the translation of model fields to form fields - - # to use our own formfield_for_dbfield function to do that translation. - # This is done by sneaking a formfield_callback property into the class - # being defined (unless the class already provides a formfield_callback - # of its own). + # to use our own formfield_for_dbfield function to do that + # translation. This is done by sneaking a formfield_callback + # property into the class being defined (unless the class already + # provides a formfield_callback of its own). - # while we're at it, we'll also set extra_form_count to 0, as we're creating - # extra forms in JS + # while we're at it, we'll also set extra_form_count to 0, as + # we're creating extra forms in JS extra_form_count = 0 def __new__(cls, name, bases, attrs): @@ -200,8 +215,8 @@ WagtailAdminModelForm = WagtailAdminModelFormMetaclass('WagtailAdminModelForm', def get_form_for_model( - model, - fields=None, exclude=None, formsets=None, exclude_formsets=None, widgets=None + model, fields=None, exclude=None, formsets=None, + exclude_formsets=None, widgets=None ): # django's modelform_factory with a bit of custom behaviour @@ -215,7 +230,8 @@ def get_form_for_model( if exclude is not None: attrs['exclude'] = exclude if issubclass(model, Page): - attrs['exclude'] = attrs.get('exclude', []) + ['content_type', 'path', 'depth', 'numchild'] + attrs['exclude'] = attrs.get('exclude', []) + ['content_type', 'path', + 'depth', 'numchild'] if widgets is not None: attrs['widgets'] = widgets @@ -232,7 +248,9 @@ def get_form_for_model( 'Meta': type('Meta', (object,), attrs) } - return WagtailAdminModelFormMetaclass(class_name, (WagtailAdminModelForm,), form_class_attrs) + return WagtailAdminModelFormMetaclass(class_name, + (WagtailAdminModelForm,), + form_class_attrs) def extract_panel_definitions_from_model_class(model, exclude=None): @@ -247,7 +265,8 @@ def extract_panel_definitions_from_model_class(model, exclude=None): if issubclass(model, Page): _exclude = ['content_type', 'path', 'depth', 'numchild'] - fields = fields_for_model(model, exclude=_exclude, formfield_callback=formfield_for_dbfield) + fields = fields_for_model(model, exclude=_exclude, + formfield_callback=formfield_for_dbfield) for field_name, field in fields.items(): try: diff --git a/wagtail/wagtailadmin/tests/test_edit_handlers.py b/wagtail/wagtailadmin/tests/test_edit_handlers.py new file mode 100644 index 000000000..45db35c5b --- /dev/null +++ b/wagtail/wagtailadmin/tests/test_edit_handlers.py @@ -0,0 +1,523 @@ +from mock import MagicMock + +from django.test import TestCase +from django.core.exceptions import ValidationError + +from wagtail.wagtailadmin.edit_handlers import ( + FriendlyDateInput, + FriendlyTimeInput, + FriendlyTimeField, + LocalizedTimeInput, + LocalizedDateInput, + LocalizedTimeField, + get_form_for_model, + extract_panel_definitions_from_model_class, + BaseFieldPanel, + FieldPanel, + RichTextFieldPanel, + EditHandler, + WagtailAdminModelForm, + BaseCompositeEditHandler, + BaseTabbedInterface, + TabbedInterface, + BaseObjectList, + ObjectList, + PageChooserPanel +) +from wagtail.wagtailcore.models import Page, Site + + +class TestFriendlyDateInput(TestCase): + def test_attrs(self): + """ + When the attrs argument is passed to FriendlyDateInput's + constructor, they should be set on the FriendlyDateInput + object along with the default attrs + """ + friendly = FriendlyDateInput(attrs={'awesome': 'sauce'}) + self.assertEqual(friendly.attrs, {'class': 'friendly_date', + 'awesome': 'sauce'}) + + +class TestFriendlyTimeInput(TestCase): + def test_attrs(self): + """ + When the attrs argument is passed to FriendlyDateInput's + constructor, they should be set on the FriendlyDateInput + object along with the default attrs + """ + friendly = FriendlyTimeInput(attrs={'awesome': 'sauce'}) + self.assertEqual(friendly.attrs, {'class': 'friendly_time', + 'awesome': 'sauce'}) + + +class TestFriendlyTimeField(TestCase): + def setUp(self): + self.friendly = FriendlyTimeField() + + def test_no_time_string(self): + """ + to_python() should return None if it is passed an empty + string + """ + result = self.friendly.to_python('') + self.assertEqual(result, None) + + def test_invalid_time_string(self): + """ + to_python() should raise a ValidationError if it is passed + an invalid time string + """ + self.assertRaises(ValidationError, self.friendly.to_python, 'bacon') + + def test_afternoon_time_string(self): + """ + to_python() should convert a time string that ends with 'pm' + to a 24-hour time in the afternoon + """ + python_time = self.friendly.to_python('3:49pm') + self.assertEqual(str(python_time), '15:49:00') + + def test_morning_time_string(self): + """ + to_python() should convert a time string that ends with 'am' + to a 24-hour time in the morning + """ + python_time = self.friendly.to_python('3:49am') + self.assertEqual(str(python_time), '03:49:00') + + def test_no_minutes_time_string(self): + """ + If minutes are not specified in the time string, they should + default to zero + """ + python_time = self.friendly.to_python('3am') + self.assertEqual(str(python_time), '03:00:00') + + +class TestLocalizedDateInput(TestCase): + def test_attrs(self): + """ + When the attrs argument is passed to LocalizedDateInput's + constructor, they should be set on the LocalizedDateInput + object along with the default attrs + """ + localized = LocalizedDateInput(attrs={'awesome': 'sauce'}) + self.assertEqual(localized.attrs, {'class': 'localized_date', + 'localize': True, + 'awesome': 'sauce'}) + + +class TestLocalizedTimeInput(TestCase): + def test_attrs(self): + """ + When the attrs argument is passed to LocalizedTimeInput's + constructor, they should be set on the LocalizedTimeInput + object along with the default attrs + """ + localized = LocalizedTimeInput(attrs={'awesome': 'sauce'}) + self.assertEqual(localized.attrs, {'class': 'localized_time', + 'awesome': 'sauce'}) + + +class TestLocalizedTimeField(TestCase): + def setUp(self): + self.localized = LocalizedTimeField() + + def test_no_time_string(self): + """ + to_python() should return None if it is passed an empty + string + """ + result = self.localized.to_python('') + self.assertEqual(result, None) + + def test_non_time_string(self): + """ + to_python() should raise a ValidationError if it is passed + a string that does not represent a time + """ + self.assertRaises(ValidationError, self.localized.to_python, 'bacon') + + def test_invalid_time_string(self): + """ + to_python() should raise a ValidationError if it is passed + an invalid time string + """ + self.assertRaises(ValidationError, self.localized.to_python, '99:99') + + def test_afternoon_time_string(self): + """ + to_python() should understand 24-hour time + """ + python_time = self.localized.to_python('15:49') + self.assertEqual(str(python_time), '15:49:00') + + def test_morning_time_string(self): + """ + to_python() should understand 24-hour time + """ + python_time = self.localized.to_python('3:49') + self.assertEqual(str(python_time), '03:49:00') + + def test_no_minutes_time_string(self): + """ + If minutes are not specified in the time string, they should + default to zero + """ + python_time = self.localized.to_python('3') + self.assertEqual(str(python_time), '03:00:00') + + +class TestGetFormForModel(TestCase): + class FakeClass(object): + _meta = MagicMock() + + def setUp(self): + self.mock_exclude = MagicMock() + + def test_get_form_for_model(self): + form = get_form_for_model(self.FakeClass, + fields=[], + exclude=[self.mock_exclude], + formsets=['baz'], + exclude_formsets=['quux'], + widgets=['bacon']) + self.assertEqual(form.Meta.exclude, [self.mock_exclude]) + self.assertEqual(form.Meta.formsets, ['baz']) + self.assertEqual(form.Meta.exclude_formsets, ['quux']) + self.assertEqual(form.Meta.widgets, ['bacon']) + + +class TestExtractPanelDefinitionsFromModelClass(TestCase): + class FakePage(Page): + pass + + def test_can_extract_panels(self): + mock = MagicMock() + mock.panels = 'foo' + result = extract_panel_definitions_from_model_class(mock) + self.assertEqual(result, 'foo') + + def test_exclude(self): + panels = extract_panel_definitions_from_model_class(Site, exclude=['hostname']) + for panel in panels: + self.assertNotEqual(panel.field_name, 'hostname') + + def test_extracted_objects_are_panels(self): + panels = extract_panel_definitions_from_model_class(self.FakePage) + for panel in panels: + self.assertTrue(issubclass(panel, BaseFieldPanel)) + + +class TestEditHandler(TestCase): + class FakeForm(dict): + def __init__(self, *args, **kwargs): + self.fields = self.fields_iterator() + + def fields_iterator(self): + for i in self: + yield i + + def setUp(self): + self.edit_handler = EditHandler(form=True, instance=True) + self.edit_handler.render = lambda: "foo" + + def test_widget_overrides(self): + result = EditHandler.widget_overrides() + self.assertEqual(result, {}) + + def test_required_formsets(self): + result = EditHandler.required_formsets() + self.assertEqual(result, []) + + def test_get_form_class(self): + result = EditHandler.get_form_class(Page) + self.assertTrue(issubclass(result, WagtailAdminModelForm)) + + def test_edit_handler_init_no_instance(self): + self.assertRaises(ValueError, EditHandler, form=True) + + def test_edit_handler_init_no_form(self): + self.assertRaises(ValueError, EditHandler, instance=True) + + def test_object_classnames(self): + result = self.edit_handler.object_classnames() + self.assertEqual(result, "") + + def test_field_classnames(self): + result = self.edit_handler.field_classnames() + self.assertEqual(result, "") + + def test_field_type(self): + result = self.edit_handler.field_type() + self.assertEqual(result, "") + + def test_render_as_object(self): + result = self.edit_handler.render_as_object() + self.assertEqual(result, "foo") + + def test_render_as_field(self): + result = self.edit_handler.render_as_field() + self.assertEqual(result, "foo") + + def test_render_js(self): + result = self.edit_handler.render_js() + self.assertEqual(result, "") + + def test_rendered_fields(self): + result = self.edit_handler.rendered_fields() + self.assertEqual(result, []) + + def test_render_missing_fields(self): + fake_form = self.FakeForm() + fake_form["foo"] = "bar" + self.edit_handler.form = fake_form + self.assertEqual(self.edit_handler.render_missing_fields(), "bar") + + def test_render_form_content(self): + fake_form = self.FakeForm() + fake_form["foo"] = "bar" + self.edit_handler.form = fake_form + self.assertEqual(self.edit_handler.render_form_content(), "foobar") + + +class TestBaseCompositeEditHandler(TestCase): + def setUp(self): + mock = MagicMock() + mock.widget_overrides.return_value = {'foo': 'bar'} + mock.required_formsets.return_value = {'baz': 'quux'} + BaseCompositeEditHandler.children = [mock] + self.base_composite_edit_handler = BaseCompositeEditHandler( + instance=True, + form=True) + + def tearDown(self): + BaseCompositeEditHandler.children = None + + def test_object_classnames_no_classname(self): + result = self.base_composite_edit_handler.object_classnames() + self.assertEqual(result, "multi-field") + + def test_object_classnames(self): + self.base_composite_edit_handler.classname = "foo" + result = self.base_composite_edit_handler.object_classnames() + self.assertEqual(result, "multi-field foo") + + def test_widget_overrides(self): + result = self.base_composite_edit_handler.widget_overrides() + self.assertEqual(result, {'foo': 'bar'}) + + def test_required_formsets(self): + result = self.base_composite_edit_handler.required_formsets() + self.assertEqual(result, ['baz']) + + +class TestBaseTabbedInterface(TestCase): + class FakeChild(object): + class FakeGrandchild(object): + def render_js(self): + return "foo" + + def rendered_fields(self): + return ["bar"] + + def __call__(self, *args, **kwargs): + fake_grandchild = self.FakeGrandchild() + return fake_grandchild + + def test_render(self): + mock = MagicMock() + BaseTabbedInterface.children = [mock] + self.base_tabbed_interface = BaseTabbedInterface( + instance=True, + form=True) + result = self.base_tabbed_interface.render() + self.assertRegexpMatches(result, 'label') + self.assertRegexpMatches(result, + '
  • ') + self.assertRegexpMatches(result, + '

    ') + + def test_render_js(self): + field = self.FakeField() + bound_field = self.FakeField() + widget = FriendlyDateInput() + field.widget = widget + bound_field.field = field + self.field_panel.bound_field = bound_field + result = self.field_panel.render_js() + self.assertEqual(result, + "initFriendlyDateChooser(fixPrefix('id for label'));") + + def test_render_js_unknown_widget(self): + field = self.FakeField() + bound_field = self.FakeField() + widget = self.FakeField() + field.widget = widget + bound_field.field = field + self.field_panel.bound_field = bound_field + result = self.field_panel.render_js() + self.assertEqual(result, + '') + + def test_render_as_field(self): + field = self.FakeField() + bound_field = self.FakeField() + bound_field.field = field + self.field_panel.bound_field = bound_field + result = self.field_panel.render_as_field() + self.assertRegexpMatches(result, + '

    help text

    ') + self.assertRegexpMatches(result, + 'errors') + + def test_rendered_fields(self): + result = self.field_panel.rendered_fields() + self.assertEqual(result, ['barbecue']) + + +class TestRichTextFieldPanel(TestCase): + class FakeField(object): + label = 'label' + help_text = 'help text' + errors = ['errors'] + id_for_label = 'id for label' + + def test_render_js(self): + fake_field = self.FakeField() + rich_text_field_panel = RichTextFieldPanel('barbecue')( + instance=True, + form={'barbecue': fake_field}) + result = rich_text_field_panel.render_js() + self.assertEqual(result, + "makeRichTextEditable(fixPrefix('id for label'));") + + +class TestPageChooserPanel(TestCase): + class FakeField(object): + label = 'label' + help_text = 'help text' + errors = ['errors'] + id_for_label = 'id for label' + + class FakeInstance(object): + class FakePage(object): + class FakeParent(object): + id = 1 + + def get_parent(self): + return self.FakeParent() + + def __init__(self): + fake_page = self.FakePage() + self.barbecue = fake_page + + + def setUp(self): + fake_field = self.FakeField() + fake_instance = self.FakeInstance() + self.page_chooser_panel = PageChooserPanel('barbecue')( + instance=fake_instance, + form={'barbecue': fake_field}) + + def test_render_js(self): + result = self.page_chooser_panel.render_js() + self.assertEqual(result, "createPageChooser(fixPrefix('id for label'), 'wagtailcore.page', 1);") From cd06b2c6e22666f523716866c9663d4012b2aae1 Mon Sep 17 00:00:00 2001 From: Tom Talbot Date: Wed, 18 Jun 2014 17:33:20 +0100 Subject: [PATCH 2/6] Remove broken test --- wagtail/wagtailadmin/tests/test_edit_handlers.py | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/wagtail/wagtailadmin/tests/test_edit_handlers.py b/wagtail/wagtailadmin/tests/test_edit_handlers.py index 8e0e4a7c5..cd21748b4 100644 --- a/wagtail/wagtailadmin/tests/test_edit_handlers.py +++ b/wagtail/wagtailadmin/tests/test_edit_handlers.py @@ -287,17 +287,6 @@ class TestFieldPanel(TestCase): self.assertRegexpMatches(result, '

    ') - def test_render_js(self): - field = self.FakeField() - bound_field = self.FakeField() - widget = FriendlyDateInput() - field.widget = widget - bound_field.field = field - self.field_panel.bound_field = bound_field - result = self.field_panel.render_js() - self.assertEqual(result, - "initFriendlyDateChooser(fixPrefix('id for label'));") - def test_render_js_unknown_widget(self): field = self.FakeField() bound_field = self.FakeField() From e87190f5bb2856a8f535ed343c68deac779d8133 Mon Sep 17 00:00:00 2001 From: Tom Talbot Date: Thu, 19 Jun 2014 17:23:36 +0100 Subject: [PATCH 3/6] Update edit handlers unit tests Add more tests. Clean up modified class properties after tests finish. Replace assertRegexpMatches with assertIn. --- .../wagtailadmin/tests/test_edit_handlers.py | 177 ++++++++++++++++-- 1 file changed, 160 insertions(+), 17 deletions(-) diff --git a/wagtail/wagtailadmin/tests/test_edit_handlers.py b/wagtail/wagtailadmin/tests/test_edit_handlers.py index cd21748b4..c5eef6b8c 100644 --- a/wagtail/wagtailadmin/tests/test_edit_handlers.py +++ b/wagtail/wagtailadmin/tests/test_edit_handlers.py @@ -1,6 +1,8 @@ from mock import MagicMock from django.test import TestCase +from django.core.exceptions import ImproperlyConfigured +from django.forms.widgets import HiddenInput from wagtail.wagtailadmin.edit_handlers import ( get_form_for_model, @@ -15,7 +17,8 @@ from wagtail.wagtailadmin.edit_handlers import ( TabbedInterface, BaseObjectList, ObjectList, - PageChooserPanel + PageChooserPanel, + InlinePanel ) from wagtail.wagtailcore.models import Page, Site @@ -144,7 +147,7 @@ class TestBaseCompositeEditHandler(TestCase): form=True) def tearDown(self): - BaseCompositeEditHandler.children = None + del BaseCompositeEditHandler.children def test_object_classnames_no_classname(self): result = self.base_composite_edit_handler.object_classnames() @@ -184,9 +187,10 @@ class TestBaseTabbedInterface(TestCase): instance=True, form=True) result = self.base_tabbed_interface.render() - self.assertRegexpMatches(result, 'label') - self.assertRegexpMatches(result, - '

  • ') - self.assertRegexpMatches(result, - '

    ') + self.assertIn('label', + result) + self.assertIn('

  • ', + result) + self.assertIn('

    ', + result) def test_render_js_unknown_widget(self): field = self.FakeField() @@ -304,10 +310,10 @@ class TestFieldPanel(TestCase): bound_field.field = field self.field_panel.bound_field = bound_field result = self.field_panel.render_as_field() - self.assertRegexpMatches(result, - '

    help text

    ') - self.assertRegexpMatches(result, - 'errors') + self.assertIn('

    help text

    ', + result) + self.assertIn('errors', + result) def test_rendered_fields(self): result = self.field_panel.rendered_fields() @@ -343,6 +349,8 @@ class TestPageChooserPanel(TestCase): class FakeParent(object): id = 1 + name = 'fake page' + def get_parent(self): return self.FakeParent() @@ -350,7 +358,6 @@ class TestPageChooserPanel(TestCase): fake_page = self.FakePage() self.barbecue = fake_page - def setUp(self): fake_field = self.FakeField() fake_instance = self.FakeInstance() @@ -360,4 +367,140 @@ class TestPageChooserPanel(TestCase): def test_render_js(self): result = self.page_chooser_panel.render_js() - self.assertEqual(result, "createPageChooser(fixPrefix('id for label'), 'wagtailcore.page', 1);") + self.assertEqual(result, + "createPageChooser(fixPrefix('id for label'), 'wagtailcore.page', 1);") + + def test_get_chosen_item(self): + result = self.page_chooser_panel.get_chosen_item() + self.assertEqual(result.name, 'fake page') + + def test_render_as_field(self): + result = self.page_chooser_panel.render_as_field() + self.assertIn('

    help text

    ', result) + self.assertIn('errors', result) + + def test_widget_overrides(self): + result = self.page_chooser_panel.widget_overrides() + self.assertEqual(result, {'barbecue': HiddenInput}) + + def test_target_content_type(self): + result = PageChooserPanel( + 'barbecue', + 'wagtailcore.site' + ).target_content_type() + self.assertEqual(result.name, 'site') + + def test_target_content_type_malformed_type(self): + result = PageChooserPanel( + 'barbecue', + 'snowman' + ) + self.assertRaises(ImproperlyConfigured, + result.target_content_type) + + def test_target_content_type_nonexistent_type(self): + result = PageChooserPanel( + 'barbecue', + 'snowman.lorry' + ) + self.assertRaises(ImproperlyConfigured, + result.target_content_type) + + +class TestInlinePanel(TestCase): + class FakeField(object): + class FakeFormset(object): + class FakeForm(object): + class FakeInstance(object): + def __repr__(self): + return 'fake instance' + fields = {'DELETE': MagicMock(), + 'ORDER': MagicMock()} + instance = FakeInstance() + + def __repr__(self): + return 'fake form' + + forms = [FakeForm()] + empty_form = FakeForm() + can_order = True + + label = 'label' + help_text = 'help text' + errors = ['errors'] + id_for_label = 'id for label' + formsets = {'formset': FakeFormset()} + + class FakeInstance(object): + class FakePage(object): + class FakeParent(object): + id = 1 + + name = 'fake page' + + def get_parent(self): + return self.FakeParent() + + def __init__(self): + fake_page = self.FakePage() + self.barbecue = fake_page + + def setUp(self): + self.fake_field = self.FakeField() + self.fake_instance = self.FakeInstance() + self.mock_panel = MagicMock() + self.mock_panel.name = 'mock panel' + self.mock_model = MagicMock() + self.mock_model.formset.related.model.panels = [self.mock_panel] + + def test_get_panel_definitions_no_panels(self): + """ + Check that get_panel_definitions returns the panels set on the model + when no panels are set on the InlinePanel + """ + inline_panel = InlinePanel(self.mock_model, 'formset')( + instance=self.fake_instance, + form=self.fake_field) + result = inline_panel.get_panel_definitions() + self.assertEqual(result[0].name, 'mock panel') + expected_calls = '[call(instance=fake instance, form=fake form),\n call(instance=fake instance, form=fake form)]' + self.assertEqual(str(self.mock_panel.mock_calls), expected_calls) + + def test_get_panel_definitions(self): + """ + Check that get_panel_definitions returns the panels set on + InlinePanel + """ + other_mock_panel = MagicMock() + other_mock_panel.name = 'other mock panel' + inline_panel = InlinePanel(self.mock_model, + 'formset', + panels=[other_mock_panel])( + instance=self.fake_instance, + form=self.fake_field) + result = inline_panel.get_panel_definitions() + self.assertEqual(result[0].name, 'other mock panel') + expected_calls = '[call(instance=fake instance, form=fake form),\n call(instance=fake instance, form=fake form)]' + self.assertEqual(str(other_mock_panel.mock_calls), expected_calls) + + def test_required_formsets(self): + inline_panel = InlinePanel(self.mock_model, 'formset')( + instance=self.fake_instance, + form=self.fake_field) + self.assertEqual(inline_panel.required_formsets(), ['formset']) + + def test_render(self): + inline_panel = InlinePanel(self.mock_model, + 'formset', + label='foo')( + instance=self.fake_instance, + form=self.fake_field) + self.assertIn('Add foo', inline_panel.render()) + + def test_render_js(self): + inline_panel = InlinePanel(self.mock_model, + 'formset')( + instance=self.fake_instance, + form=self.fake_field) + self.assertIn('var panel = InlinePanel({', + inline_panel.render_js()) From 2156c0ddd27722663456997c1ef57dee3db743f6 Mon Sep 17 00:00:00 2001 From: Tom Talbot Date: Fri, 20 Jun 2014 10:55:49 +0100 Subject: [PATCH 4/6] Fix Travis test failures --- .../wagtailadmin/tests/test_edit_handlers.py | 44 ++++++++++++++----- 1 file changed, 32 insertions(+), 12 deletions(-) diff --git a/wagtail/wagtailadmin/tests/test_edit_handlers.py b/wagtail/wagtailadmin/tests/test_edit_handlers.py index c5eef6b8c..19c117405 100644 --- a/wagtail/wagtailadmin/tests/test_edit_handlers.py +++ b/wagtail/wagtailadmin/tests/test_edit_handlers.py @@ -137,34 +137,54 @@ class TestEditHandler(TestCase): class TestBaseCompositeEditHandler(TestCase): - def setUp(self): + def test_object_classnames_no_classname(self): mock = MagicMock() mock.widget_overrides.return_value = {'foo': 'bar'} mock.required_formsets.return_value = {'baz': 'quux'} BaseCompositeEditHandler.children = [mock] - self.base_composite_edit_handler = BaseCompositeEditHandler( + base_composite_edit_handler = BaseCompositeEditHandler( instance=True, form=True) - - def tearDown(self): + result = base_composite_edit_handler.object_classnames() + self.assertEqual(result, "multi-field") del BaseCompositeEditHandler.children - def test_object_classnames_no_classname(self): - result = self.base_composite_edit_handler.object_classnames() - self.assertEqual(result, "multi-field") - def test_object_classnames(self): - self.base_composite_edit_handler.classname = "foo" - result = self.base_composite_edit_handler.object_classnames() + mock = MagicMock() + mock.widget_overrides.return_value = {'foo': 'bar'} + mock.required_formsets.return_value = {'baz': 'quux'} + BaseCompositeEditHandler.children = [mock] + base_composite_edit_handler = BaseCompositeEditHandler( + instance=True, + form=True) + base_composite_edit_handler.classname = "foo" + result = base_composite_edit_handler.object_classnames() self.assertEqual(result, "multi-field foo") + del BaseCompositeEditHandler.children def test_widget_overrides(self): - result = self.base_composite_edit_handler.widget_overrides() + mock = MagicMock() + mock.widget_overrides.return_value = {'foo': 'bar'} + mock.required_formsets.return_value = {'baz': 'quux'} + BaseCompositeEditHandler.children = [mock] + base_composite_edit_handler = BaseCompositeEditHandler( + instance=True, + form=True) + result = base_composite_edit_handler.widget_overrides() self.assertEqual(result, {'foo': 'bar'}) + del BaseCompositeEditHandler.children def test_required_formsets(self): - result = self.base_composite_edit_handler.required_formsets() + mock = MagicMock() + mock.widget_overrides.return_value = {'foo': 'bar'} + mock.required_formsets.return_value = {'baz': 'quux'} + BaseCompositeEditHandler.children = [mock] + base_composite_edit_handler = BaseCompositeEditHandler( + instance=True, + form=True) + result = base_composite_edit_handler.required_formsets() self.assertEqual(result, ['baz']) + del BaseCompositeEditHandler.children class TestBaseTabbedInterface(TestCase): From d68d764d911c9c291cbd74da3ad77fc675a1a296 Mon Sep 17 00:00:00 2001 From: Tom Talbot Date: Fri, 20 Jun 2014 12:37:20 +0100 Subject: [PATCH 5/6] Reorganise unit tests to obviate the use of del --- .../wagtailadmin/tests/test_edit_handlers.py | 129 ++++++------------ 1 file changed, 42 insertions(+), 87 deletions(-) diff --git a/wagtail/wagtailadmin/tests/test_edit_handlers.py b/wagtail/wagtailadmin/tests/test_edit_handlers.py index 19c117405..c930974fe 100644 --- a/wagtail/wagtailadmin/tests/test_edit_handlers.py +++ b/wagtail/wagtailadmin/tests/test_edit_handlers.py @@ -12,7 +12,6 @@ from wagtail.wagtailadmin.edit_handlers import ( RichTextFieldPanel, EditHandler, WagtailAdminModelForm, - BaseCompositeEditHandler, BaseTabbedInterface, TabbedInterface, BaseObjectList, @@ -136,107 +135,63 @@ class TestEditHandler(TestCase): self.assertEqual(self.edit_handler.render_form_content(), "foobar") -class TestBaseCompositeEditHandler(TestCase): - def test_object_classnames_no_classname(self): - mock = MagicMock() - mock.widget_overrides.return_value = {'foo': 'bar'} - mock.required_formsets.return_value = {'baz': 'quux'} - BaseCompositeEditHandler.children = [mock] - base_composite_edit_handler = BaseCompositeEditHandler( - instance=True, - form=True) - result = base_composite_edit_handler.object_classnames() - self.assertEqual(result, "multi-field") - del BaseCompositeEditHandler.children - - def test_object_classnames(self): - mock = MagicMock() - mock.widget_overrides.return_value = {'foo': 'bar'} - mock.required_formsets.return_value = {'baz': 'quux'} - BaseCompositeEditHandler.children = [mock] - base_composite_edit_handler = BaseCompositeEditHandler( - instance=True, - form=True) - base_composite_edit_handler.classname = "foo" - result = base_composite_edit_handler.object_classnames() - self.assertEqual(result, "multi-field foo") - del BaseCompositeEditHandler.children - - def test_widget_overrides(self): - mock = MagicMock() - mock.widget_overrides.return_value = {'foo': 'bar'} - mock.required_formsets.return_value = {'baz': 'quux'} - BaseCompositeEditHandler.children = [mock] - base_composite_edit_handler = BaseCompositeEditHandler( - instance=True, - form=True) - result = base_composite_edit_handler.widget_overrides() - self.assertEqual(result, {'foo': 'bar'}) - del BaseCompositeEditHandler.children - - def test_required_formsets(self): - mock = MagicMock() - mock.widget_overrides.return_value = {'foo': 'bar'} - mock.required_formsets.return_value = {'baz': 'quux'} - BaseCompositeEditHandler.children = [mock] - base_composite_edit_handler = BaseCompositeEditHandler( - instance=True, - form=True) - result = base_composite_edit_handler.required_formsets() - self.assertEqual(result, ['baz']) - del BaseCompositeEditHandler.children - - -class TestBaseTabbedInterface(TestCase): +class TestTabbedInterface(TestCase): class FakeChild(object): class FakeGrandchild(object): def render_js(self): - return "foo" + return "rendered js" def rendered_fields(self): - return ["bar"] + return ["rendered fields"] + + def widget_overrides(self): + return {'foo': 'bar'} + + def required_formsets(self): + return {'baz': 'quux'} def __call__(self, *args, **kwargs): fake_grandchild = self.FakeGrandchild() return fake_grandchild + def setUp(self): + fake_child = self.FakeChild() + self.TabbedInterfaceClass = TabbedInterface([fake_child]) + self.tabbed_interface = self.TabbedInterfaceClass(instance=True, + form=True) + + def test_tabbed_interface(self): + self.assertTrue(issubclass(self.TabbedInterfaceClass, + BaseTabbedInterface)) + + def test_object_classnames_no_classname(self): + result = self.tabbed_interface.object_classnames() + self.assertEqual(result, 'multi-field') + + def test_object_classnames(self): + self.tabbed_interface.classname = 'foo' + result = self.tabbed_interface.object_classnames() + self.assertEqual(result, 'multi-field foo') + + def test_widget_overrides(self): + result = self.tabbed_interface.widget_overrides() + self.assertEqual(result, {'foo': 'bar'}) + + def test_required_formsets(self): + result = self.tabbed_interface.required_formsets() + self.assertEqual(result, ['baz']) + def test_render(self): - mock = MagicMock() - BaseTabbedInterface.children = [mock] - self.base_tabbed_interface = BaseTabbedInterface( - instance=True, - form=True) - result = self.base_tabbed_interface.render() - self.assertIn('', result) def test_render_js(self): - fake_child = self.FakeChild() - BaseTabbedInterface.children = [fake_child] - self.base_tabbed_interface = BaseTabbedInterface( - instance=True, - form=True) - result = self.base_tabbed_interface.render_js() - self.assertEqual(result, "foo") - del BaseTabbedInterface.children + result = self.tabbed_interface.render_js() + self.assertEqual(result, 'rendered js') def test_rendered_fields(self): - fake_child = self.FakeChild() - BaseTabbedInterface.children = [fake_child] - self.base_tabbed_interface = BaseTabbedInterface( - instance=True, - form=True) - result = self.base_tabbed_interface.rendered_fields() - self.assertEqual(result, ["bar"]) - del BaseTabbedInterface.children - - -class TestTabbedInterface(TestCase): - def test_tabbed_interface(self): - tabbed_interface = TabbedInterface(['foo']) - self.assertTrue(issubclass(tabbed_interface, BaseTabbedInterface)) + result = self.tabbed_interface.rendered_fields() + self.assertEqual(result, ["rendered fields"]) class TestObjectList(TestCase): From b41a6d730fe61e1c5e01d9b669403982f374f4ad Mon Sep 17 00:00:00 2001 From: Karl Hobley Date: Tue, 24 Jun 2014 12:53:34 +0100 Subject: [PATCH 6/6] Revert "Merge pull request #335 from mope/edit-handlers-unit-tests" This reverts commit 7ad6be82f3913893dcd82dd2af904da4c654c3ff, reversing changes made to 4c77a4b18a8fef9abd3bcc1fccaf5627f1604522. --- .gitignore | 1 - wagtail/wagtailadmin/edit_handlers.py | 39 +- .../wagtailadmin/tests/test_edit_handlers.py | 481 ------------------ 3 files changed, 18 insertions(+), 503 deletions(-) delete mode 100644 wagtail/wagtailadmin/tests/test_edit_handlers.py diff --git a/.gitignore b/.gitignore index 57f9d0eab..bd904efc9 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,5 @@ *.pyc .DS_Store -/.ropeproject/ /.coverage /dist/ /MANIFEST diff --git a/wagtail/wagtailadmin/edit_handlers.py b/wagtail/wagtailadmin/edit_handlers.py index 7bbead9b1..a15440016 100644 --- a/wagtail/wagtailadmin/edit_handlers.py +++ b/wagtail/wagtailadmin/edit_handlers.py @@ -1,4 +1,6 @@ import copy +import re +import datetime from taggit.forms import TagWidget from modelcluster.forms import ClusterForm, ClusterFormMetaclass @@ -7,13 +9,13 @@ from django.template.loader import render_to_string from django.template.defaultfilters import addslashes from django.utils.safestring import mark_safe from django import forms +from django.db import models from django.forms.models import fields_for_model from django.contrib.contenttypes.models import ContentType -from django.core.exceptions import ( - ObjectDoesNotExist, - ImproperlyConfigured, -) +from django.core.exceptions import ObjectDoesNotExist, ImproperlyConfigured, ValidationError from django.core.urlresolvers import reverse +from django.conf import settings +from django.utils.translation import ugettext as _ from django.utils.translation import ugettext_lazy from wagtail.wagtailcore.models import Page @@ -36,8 +38,7 @@ WIDGET_JS = { } -# Callback to allow us to override the default form fields provided -# for each model field. +# Callback to allow us to override the default form fields provided for each model field. def formfield_for_dbfield(db_field, **kwargs): # snarfed from django/contrib/admin/options.py @@ -55,13 +56,13 @@ def formfield_for_dbfield(db_field, **kwargs): class WagtailAdminModelFormMetaclass(ClusterFormMetaclass): # Override the behaviour of the regular ModelForm metaclass - # which handles the translation of model fields to form fields - - # to use our own formfield_for_dbfield function to do that - # translation. This is done by sneaking a formfield_callback - # property into the class being defined (unless the class already - # provides a formfield_callback of its own). + # to use our own formfield_for_dbfield function to do that translation. + # This is done by sneaking a formfield_callback property into the class + # being defined (unless the class already provides a formfield_callback + # of its own). - # while we're at it, we'll also set extra_form_count to 0, as - # we're creating extra forms in JS + # while we're at it, we'll also set extra_form_count to 0, as we're creating + # extra forms in JS extra_form_count = 0 def __new__(cls, name, bases, attrs): @@ -78,8 +79,8 @@ WagtailAdminModelForm = WagtailAdminModelFormMetaclass('WagtailAdminModelForm', def get_form_for_model( - model, fields=None, exclude=None, formsets=None, - exclude_formsets=None, widgets=None + model, + fields=None, exclude=None, formsets=None, exclude_formsets=None, widgets=None ): # django's modelform_factory with a bit of custom behaviour @@ -93,8 +94,7 @@ def get_form_for_model( if exclude is not None: attrs['exclude'] = exclude if issubclass(model, Page): - attrs['exclude'] = attrs.get('exclude', []) + ['content_type', 'path', - 'depth', 'numchild'] + attrs['exclude'] = attrs.get('exclude', []) + ['content_type', 'path', 'depth', 'numchild'] if widgets is not None: attrs['widgets'] = widgets @@ -111,9 +111,7 @@ def get_form_for_model( 'Meta': type('Meta', (object,), attrs) } - return WagtailAdminModelFormMetaclass(class_name, - (WagtailAdminModelForm,), - form_class_attrs) + return WagtailAdminModelFormMetaclass(class_name, (WagtailAdminModelForm,), form_class_attrs) def extract_panel_definitions_from_model_class(model, exclude=None): @@ -128,8 +126,7 @@ def extract_panel_definitions_from_model_class(model, exclude=None): if issubclass(model, Page): _exclude = ['content_type', 'path', 'depth', 'numchild'] - fields = fields_for_model(model, exclude=_exclude, - formfield_callback=formfield_for_dbfield) + fields = fields_for_model(model, exclude=_exclude, formfield_callback=formfield_for_dbfield) for field_name, field in fields.items(): try: diff --git a/wagtail/wagtailadmin/tests/test_edit_handlers.py b/wagtail/wagtailadmin/tests/test_edit_handlers.py deleted file mode 100644 index c930974fe..000000000 --- a/wagtail/wagtailadmin/tests/test_edit_handlers.py +++ /dev/null @@ -1,481 +0,0 @@ -from mock import MagicMock - -from django.test import TestCase -from django.core.exceptions import ImproperlyConfigured -from django.forms.widgets import HiddenInput - -from wagtail.wagtailadmin.edit_handlers import ( - get_form_for_model, - extract_panel_definitions_from_model_class, - BaseFieldPanel, - FieldPanel, - RichTextFieldPanel, - EditHandler, - WagtailAdminModelForm, - BaseTabbedInterface, - TabbedInterface, - BaseObjectList, - ObjectList, - PageChooserPanel, - InlinePanel -) -from wagtail.wagtailcore.models import Page, Site - - -class TestGetFormForModel(TestCase): - class FakeClass(object): - _meta = MagicMock() - - def setUp(self): - self.mock_exclude = MagicMock() - - def test_get_form_for_model(self): - form = get_form_for_model(self.FakeClass, - fields=[], - exclude=[self.mock_exclude], - formsets=['baz'], - exclude_formsets=['quux'], - widgets=['bacon']) - self.assertEqual(form.Meta.exclude, [self.mock_exclude]) - self.assertEqual(form.Meta.formsets, ['baz']) - self.assertEqual(form.Meta.exclude_formsets, ['quux']) - self.assertEqual(form.Meta.widgets, ['bacon']) - - -class TestExtractPanelDefinitionsFromModelClass(TestCase): - class FakePage(Page): - pass - - def test_can_extract_panels(self): - mock = MagicMock() - mock.panels = 'foo' - result = extract_panel_definitions_from_model_class(mock) - self.assertEqual(result, 'foo') - - def test_exclude(self): - panels = extract_panel_definitions_from_model_class(Site, exclude=['hostname']) - for panel in panels: - self.assertNotEqual(panel.field_name, 'hostname') - - def test_extracted_objects_are_panels(self): - panels = extract_panel_definitions_from_model_class(self.FakePage) - for panel in panels: - self.assertTrue(issubclass(panel, BaseFieldPanel)) - - -class TestEditHandler(TestCase): - class FakeForm(dict): - def __init__(self, *args, **kwargs): - self.fields = self.fields_iterator() - - def fields_iterator(self): - for i in self: - yield i - - def setUp(self): - self.edit_handler = EditHandler(form=True, instance=True) - self.edit_handler.render = lambda: "foo" - - def test_widget_overrides(self): - result = EditHandler.widget_overrides() - self.assertEqual(result, {}) - - def test_required_formsets(self): - result = EditHandler.required_formsets() - self.assertEqual(result, []) - - def test_get_form_class(self): - result = EditHandler.get_form_class(Page) - self.assertTrue(issubclass(result, WagtailAdminModelForm)) - - def test_edit_handler_init_no_instance(self): - self.assertRaises(ValueError, EditHandler, form=True) - - def test_edit_handler_init_no_form(self): - self.assertRaises(ValueError, EditHandler, instance=True) - - def test_object_classnames(self): - result = self.edit_handler.object_classnames() - self.assertEqual(result, "") - - def test_field_classnames(self): - result = self.edit_handler.field_classnames() - self.assertEqual(result, "") - - def test_field_type(self): - result = self.edit_handler.field_type() - self.assertEqual(result, "") - - def test_render_as_object(self): - result = self.edit_handler.render_as_object() - self.assertEqual(result, "foo") - - def test_render_as_field(self): - result = self.edit_handler.render_as_field() - self.assertEqual(result, "foo") - - def test_render_js(self): - result = self.edit_handler.render_js() - self.assertEqual(result, "") - - def test_rendered_fields(self): - result = self.edit_handler.rendered_fields() - self.assertEqual(result, []) - - def test_render_missing_fields(self): - fake_form = self.FakeForm() - fake_form["foo"] = "bar" - self.edit_handler.form = fake_form - self.assertEqual(self.edit_handler.render_missing_fields(), "bar") - - def test_render_form_content(self): - fake_form = self.FakeForm() - fake_form["foo"] = "bar" - self.edit_handler.form = fake_form - self.assertEqual(self.edit_handler.render_form_content(), "foobar") - - -class TestTabbedInterface(TestCase): - class FakeChild(object): - class FakeGrandchild(object): - def render_js(self): - return "rendered js" - - def rendered_fields(self): - return ["rendered fields"] - - def widget_overrides(self): - return {'foo': 'bar'} - - def required_formsets(self): - return {'baz': 'quux'} - - def __call__(self, *args, **kwargs): - fake_grandchild = self.FakeGrandchild() - return fake_grandchild - - def setUp(self): - fake_child = self.FakeChild() - self.TabbedInterfaceClass = TabbedInterface([fake_child]) - self.tabbed_interface = self.TabbedInterfaceClass(instance=True, - form=True) - - def test_tabbed_interface(self): - self.assertTrue(issubclass(self.TabbedInterfaceClass, - BaseTabbedInterface)) - - def test_object_classnames_no_classname(self): - result = self.tabbed_interface.object_classnames() - self.assertEqual(result, 'multi-field') - - def test_object_classnames(self): - self.tabbed_interface.classname = 'foo' - result = self.tabbed_interface.object_classnames() - self.assertEqual(result, 'multi-field foo') - - def test_widget_overrides(self): - result = self.tabbed_interface.widget_overrides() - self.assertEqual(result, {'foo': 'bar'}) - - def test_required_formsets(self): - result = self.tabbed_interface.required_formsets() - self.assertEqual(result, ['baz']) - - def test_render(self): - result = self.tabbed_interface.render() - self.assertIn('
    ', result) - - def test_render_js(self): - result = self.tabbed_interface.render_js() - self.assertEqual(result, 'rendered js') - - def test_rendered_fields(self): - result = self.tabbed_interface.rendered_fields() - self.assertEqual(result, ["rendered fields"]) - - -class TestObjectList(TestCase): - def test_object_list(self): - object_list = ObjectList(['foo']) - self.assertTrue(issubclass(object_list, BaseObjectList)) - - -class TestBaseFieldPanel(TestCase): - class FakeClass(object): - required = False - - class FakeField(object): - label = 'label' - help_text = 'help text' - - def setUp(self): - fake_field = self.FakeField() - BaseFieldPanel.field_name = 'barbecue' - self.base_field_panel = BaseFieldPanel( - instance=True, - form={'barbecue': fake_field}) - - def test_object_classnames_no_classname(self): - result = self.base_field_panel.object_classnames() - self.assertEqual(result, "single-field") - - def test_object_classnames(self): - self.base_field_panel.classname = "bar" - result = self.base_field_panel.object_classnames() - self.assertEqual(result, "single-field bar") - - def test_field_type(self): - fake_object = self.FakeClass() - another_fake_object = self.FakeClass() - fake_object.field = another_fake_object - self.base_field_panel.bound_field = fake_object - self.assertEqual(self.base_field_panel.field_type(), 'fake_class') - - def test_field_classnames(self): - fake_object = self.FakeClass() - another_fake_object = self.FakeClass() - another_fake_object.required = True - fake_object.errors = True - fake_object.field = another_fake_object - self.base_field_panel.bound_field = fake_object - self.assertEqual(self.base_field_panel.field_classnames(), - 'fake_class required error') - - -class TestFieldPanel(TestCase): - class FakeClass(object): - required = False - - class FakeField(object): - label = 'label' - help_text = 'help text' - errors = ['errors'] - id_for_label = 'id for label' - - def setUp(self): - fake_field = self.FakeField() - fake_field.field = self.FakeClass() - self.field_panel = FieldPanel('barbecue', 'snowman')( - instance=True, - form={'barbecue': fake_field}) - - def test_render_as_object(self): - result = self.field_panel.render_as_object() - self.assertIn('label', - result) - self.assertIn('
  • ', - result) - self.assertIn('

    ', - result) - - def test_render_js_unknown_widget(self): - field = self.FakeField() - bound_field = self.FakeField() - widget = self.FakeField() - field.widget = widget - bound_field.field = field - self.field_panel.bound_field = bound_field - result = self.field_panel.render_js() - self.assertEqual(result, - '') - - def test_render_as_field(self): - field = self.FakeField() - bound_field = self.FakeField() - bound_field.field = field - self.field_panel.bound_field = bound_field - result = self.field_panel.render_as_field() - self.assertIn('

    help text

    ', - result) - self.assertIn('errors', - result) - - def test_rendered_fields(self): - result = self.field_panel.rendered_fields() - self.assertEqual(result, ['barbecue']) - - -class TestRichTextFieldPanel(TestCase): - class FakeField(object): - label = 'label' - help_text = 'help text' - errors = ['errors'] - id_for_label = 'id for label' - - def test_render_js(self): - fake_field = self.FakeField() - rich_text_field_panel = RichTextFieldPanel('barbecue')( - instance=True, - form={'barbecue': fake_field}) - result = rich_text_field_panel.render_js() - self.assertEqual(result, - "makeRichTextEditable(fixPrefix('id for label'));") - - -class TestPageChooserPanel(TestCase): - class FakeField(object): - label = 'label' - help_text = 'help text' - errors = ['errors'] - id_for_label = 'id for label' - - class FakeInstance(object): - class FakePage(object): - class FakeParent(object): - id = 1 - - name = 'fake page' - - def get_parent(self): - return self.FakeParent() - - def __init__(self): - fake_page = self.FakePage() - self.barbecue = fake_page - - def setUp(self): - fake_field = self.FakeField() - fake_instance = self.FakeInstance() - self.page_chooser_panel = PageChooserPanel('barbecue')( - instance=fake_instance, - form={'barbecue': fake_field}) - - def test_render_js(self): - result = self.page_chooser_panel.render_js() - self.assertEqual(result, - "createPageChooser(fixPrefix('id for label'), 'wagtailcore.page', 1);") - - def test_get_chosen_item(self): - result = self.page_chooser_panel.get_chosen_item() - self.assertEqual(result.name, 'fake page') - - def test_render_as_field(self): - result = self.page_chooser_panel.render_as_field() - self.assertIn('

    help text

    ', result) - self.assertIn('errors', result) - - def test_widget_overrides(self): - result = self.page_chooser_panel.widget_overrides() - self.assertEqual(result, {'barbecue': HiddenInput}) - - def test_target_content_type(self): - result = PageChooserPanel( - 'barbecue', - 'wagtailcore.site' - ).target_content_type() - self.assertEqual(result.name, 'site') - - def test_target_content_type_malformed_type(self): - result = PageChooserPanel( - 'barbecue', - 'snowman' - ) - self.assertRaises(ImproperlyConfigured, - result.target_content_type) - - def test_target_content_type_nonexistent_type(self): - result = PageChooserPanel( - 'barbecue', - 'snowman.lorry' - ) - self.assertRaises(ImproperlyConfigured, - result.target_content_type) - - -class TestInlinePanel(TestCase): - class FakeField(object): - class FakeFormset(object): - class FakeForm(object): - class FakeInstance(object): - def __repr__(self): - return 'fake instance' - fields = {'DELETE': MagicMock(), - 'ORDER': MagicMock()} - instance = FakeInstance() - - def __repr__(self): - return 'fake form' - - forms = [FakeForm()] - empty_form = FakeForm() - can_order = True - - label = 'label' - help_text = 'help text' - errors = ['errors'] - id_for_label = 'id for label' - formsets = {'formset': FakeFormset()} - - class FakeInstance(object): - class FakePage(object): - class FakeParent(object): - id = 1 - - name = 'fake page' - - def get_parent(self): - return self.FakeParent() - - def __init__(self): - fake_page = self.FakePage() - self.barbecue = fake_page - - def setUp(self): - self.fake_field = self.FakeField() - self.fake_instance = self.FakeInstance() - self.mock_panel = MagicMock() - self.mock_panel.name = 'mock panel' - self.mock_model = MagicMock() - self.mock_model.formset.related.model.panels = [self.mock_panel] - - def test_get_panel_definitions_no_panels(self): - """ - Check that get_panel_definitions returns the panels set on the model - when no panels are set on the InlinePanel - """ - inline_panel = InlinePanel(self.mock_model, 'formset')( - instance=self.fake_instance, - form=self.fake_field) - result = inline_panel.get_panel_definitions() - self.assertEqual(result[0].name, 'mock panel') - expected_calls = '[call(instance=fake instance, form=fake form),\n call(instance=fake instance, form=fake form)]' - self.assertEqual(str(self.mock_panel.mock_calls), expected_calls) - - def test_get_panel_definitions(self): - """ - Check that get_panel_definitions returns the panels set on - InlinePanel - """ - other_mock_panel = MagicMock() - other_mock_panel.name = 'other mock panel' - inline_panel = InlinePanel(self.mock_model, - 'formset', - panels=[other_mock_panel])( - instance=self.fake_instance, - form=self.fake_field) - result = inline_panel.get_panel_definitions() - self.assertEqual(result[0].name, 'other mock panel') - expected_calls = '[call(instance=fake instance, form=fake form),\n call(instance=fake instance, form=fake form)]' - self.assertEqual(str(other_mock_panel.mock_calls), expected_calls) - - def test_required_formsets(self): - inline_panel = InlinePanel(self.mock_model, 'formset')( - instance=self.fake_instance, - form=self.fake_field) - self.assertEqual(inline_panel.required_formsets(), ['formset']) - - def test_render(self): - inline_panel = InlinePanel(self.mock_model, - 'formset', - label='foo')( - instance=self.fake_instance, - form=self.fake_field) - self.assertIn('Add foo', inline_panel.render()) - - def test_render_js(self): - inline_panel = InlinePanel(self.mock_model, - 'formset')( - instance=self.fake_instance, - form=self.fake_field) - self.assertIn('var panel = InlinePanel({', - inline_panel.render_js())