From 61b530e5704b7faf4a59520d4d989e28658c5245 Mon Sep 17 00:00:00 2001 From: Mikalai Radchuk Date: Thu, 12 May 2016 23:59:13 +0300 Subject: [PATCH] Tests for configurable rich text widgets --- wagtail/contrib/wagtailstyleguide/views.py | 4 +- wagtail/tests/settings.py | 9 + ...blockfieldpage_defaultrichtextfieldpage.py | 63 ++++++ wagtail/tests/testapp/models.py | 41 +++- wagtail/tests/testapp/rich_text.py | 22 ++ wagtail/wagtailadmin/rich_text.py | 2 +- wagtail/wagtailadmin/tests/test_rich_text.py | 200 ++++++++++++++++++ wagtail/wagtailcore/blocks/field_block.py | 4 +- wagtail/wagtailcore/fields.py | 4 +- 9 files changed, 341 insertions(+), 8 deletions(-) create mode 100644 wagtail/tests/testapp/migrations/0005_customrichblockfieldpage_customrichtextfieldpage_defaultrichblockfieldpage_defaultrichtextfieldpage.py create mode 100644 wagtail/tests/testapp/rich_text.py create mode 100644 wagtail/wagtailadmin/tests/test_rich_text.py diff --git a/wagtail/contrib/wagtailstyleguide/views.py b/wagtail/contrib/wagtailstyleguide/views.py index ed62102c3a..e3dc224494 100644 --- a/wagtail/contrib/wagtailstyleguide/views.py +++ b/wagtail/contrib/wagtailstyleguide/views.py @@ -6,7 +6,7 @@ from django.shortcuts import render from django.utils.translation import ugettext as _ from wagtail.wagtailadmin import messages from wagtail.wagtailadmin.forms import SearchForm -from wagtail.wagtailadmin.rich_text import get_rich_text_editor +from wagtail.wagtailadmin.rich_text import get_rich_text_editor_widget from wagtail.wagtailadmin.widgets import ( AdminAutoHeightTextInput, AdminDateInput, AdminDateTimeInput, AdminPageChooser, AdminTimeInput) from wagtail.wagtailcore.models import Page @@ -26,7 +26,7 @@ class ExampleForm(forms.Form): self.fields['time'].widget = AdminTimeInput() self.fields['datetime'].widget = AdminDateTimeInput() self.fields['auto_height_text'].widget = AdminAutoHeightTextInput() - self.fields['default_rich_text'].widget = get_rich_text_editor('default') + self.fields['default_rich_text'].widget = get_rich_text_editor_widget('default') CHOICES = ( ('choice1', 'choice 1'), diff --git a/wagtail/tests/settings.py b/wagtail/tests/settings.py index 80e14acf6b..94deaf00be 100644 --- a/wagtail/tests/settings.py +++ b/wagtail/tests/settings.py @@ -166,3 +166,12 @@ WAGTAIL_SITE_NAME = "Test Site" # when the module gets loaded. The decorator 'override_settings' does not work # in this scenario. WAGTAIL_USER_CUSTOM_FIELDS = ['country'] + +WAGTAILADMIN_RICH_TEXT_EDITORS = { + 'default': { + 'WIDGET': 'wagtail.wagtailadmin.rich_text.HalloRichTextArea' + }, + 'custom': { + 'WIDGET': 'wagtail.tests.testapp.rich_text.CustomRichTextArea' + }, +} diff --git a/wagtail/tests/testapp/migrations/0005_customrichblockfieldpage_customrichtextfieldpage_defaultrichblockfieldpage_defaultrichtextfieldpage.py b/wagtail/tests/testapp/migrations/0005_customrichblockfieldpage_customrichtextfieldpage_defaultrichblockfieldpage_defaultrichtextfieldpage.py new file mode 100644 index 0000000000..df72c9f648 --- /dev/null +++ b/wagtail/tests/testapp/migrations/0005_customrichblockfieldpage_customrichtextfieldpage_defaultrichblockfieldpage_defaultrichtextfieldpage.py @@ -0,0 +1,63 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.9.6 on 2016-05-12 20:56 +from __future__ import unicode_literals + +from django.db import migrations, models +import django.db.models.deletion +import wagtail.wagtailcore.blocks +import wagtail.wagtailcore.fields + + +class Migration(migrations.Migration): + + dependencies = [ + ('wagtailcore', '0028_merge'), + ('tests', '0004_fileuploadsetting'), + ] + + operations = [ + migrations.CreateModel( + name='CustomRichBlockFieldPage', + fields=[ + ('page_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='wagtailcore.Page')), + ('body', wagtail.wagtailcore.fields.StreamField([('rich_text', wagtail.wagtailcore.blocks.RichTextBlock(editor='custom'))])), + ], + options={ + 'abstract': False, + }, + bases=('wagtailcore.page',), + ), + migrations.CreateModel( + name='CustomRichTextFieldPage', + fields=[ + ('page_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='wagtailcore.Page')), + ('body', wagtail.wagtailcore.fields.RichTextField()), + ], + options={ + 'abstract': False, + }, + bases=('wagtailcore.page',), + ), + migrations.CreateModel( + name='DefaultRichBlockFieldPage', + fields=[ + ('page_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='wagtailcore.Page')), + ('body', wagtail.wagtailcore.fields.StreamField([('rich_text', wagtail.wagtailcore.blocks.RichTextBlock())])), + ], + options={ + 'abstract': False, + }, + bases=('wagtailcore.page',), + ), + migrations.CreateModel( + name='DefaultRichTextFieldPage', + fields=[ + ('page_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='wagtailcore.Page')), + ('body', wagtail.wagtailcore.fields.RichTextField()), + ], + options={ + 'abstract': False, + }, + bases=('wagtailcore.page',), + ), + ] diff --git a/wagtail/tests/testapp/models.py b/wagtail/tests/testapp/models.py index f4e860e5fc..0918f5e228 100644 --- a/wagtail/tests/testapp/models.py +++ b/wagtail/tests/testapp/models.py @@ -16,7 +16,7 @@ from taggit.models import TaggedItemBase from wagtail.contrib.settings.models import BaseSetting, register_setting from wagtail.wagtailadmin.edit_handlers import ( - FieldPanel, InlinePanel, MultiFieldPanel, ObjectList, PageChooserPanel, TabbedInterface) + FieldPanel, InlinePanel, MultiFieldPanel, ObjectList, PageChooserPanel, TabbedInterface, StreamFieldPanel) from wagtail.wagtailadmin.forms import WagtailAdminPageForm from wagtail.wagtailcore.blocks import CharBlock, RichTextBlock from wagtail.wagtailcore.fields import RichTextField, StreamField @@ -668,3 +668,42 @@ class ValidatedPage(Page): content_panels = Page.content_panels + [ FieldPanel('foo'), ] + + +class DefaultRichTextFieldPage(Page): + body = RichTextField() + + content_panels = [ + FieldPanel('title', classname="full title"), + FieldPanel('body'), + ] + + +class DefaultRichBlockFieldPage(Page): + body = StreamField([ + ('rich_text', RichTextBlock()), + ]) + + content_panels = Page.content_panels + [ + StreamFieldPanel('body') + ] + + +class CustomRichTextFieldPage(Page): + body = RichTextField(editor='custom') + + content_panels = [ + FieldPanel('title', classname="full title"), + FieldPanel('body'), + ] + + +class CustomRichBlockFieldPage(Page): + body = StreamField([ + ('rich_text', RichTextBlock(editor='custom')), + ]) + + content_panels = [ + FieldPanel('title', classname="full title"), + StreamFieldPanel('body'), + ] diff --git a/wagtail/tests/testapp/rich_text.py b/wagtail/tests/testapp/rich_text.py new file mode 100644 index 0000000000..22353b98fc --- /dev/null +++ b/wagtail/tests/testapp/rich_text.py @@ -0,0 +1,22 @@ +from __future__ import absolute_import, unicode_literals + +import json + +from django.forms import widgets, Media +from wagtail.wagtailadmin.edit_handlers import RichTextFieldPanel + +from wagtail.utils.widgets import WidgetWithScript + + +class CustomRichTextArea(WidgetWithScript, widgets.Textarea): + def get_panel(self): + return RichTextFieldPanel + + def render_js_init(self, id_, name, value): + return "customEditorInitScript({0});".format(json.dumps(id_)) + + @property + def media(self): + return Media(js=[ + 'vendor/custom_editor.js' + ]) diff --git a/wagtail/wagtailadmin/rich_text.py b/wagtail/wagtailadmin/rich_text.py index 375030890d..115c72cac6 100644 --- a/wagtail/wagtailadmin/rich_text.py +++ b/wagtail/wagtailadmin/rich_text.py @@ -50,7 +50,7 @@ DEFAULT_RICH_TEXT_EDITORS = { } -def get_rich_text_editor(name='default'): +def get_rich_text_editor_widget(name='default'): editor_settings = getattr(settings, 'WAGTAILADMIN_RICH_TEXT_EDITORS', DEFAULT_RICH_TEXT_EDITORS) editor = editor_settings[name] diff --git a/wagtail/wagtailadmin/tests/test_rich_text.py b/wagtail/wagtailadmin/tests/test_rich_text.py new file mode 100644 index 0000000000..a64db6c06c --- /dev/null +++ b/wagtail/wagtailadmin/tests/test_rich_text.py @@ -0,0 +1,200 @@ +from __future__ import absolute_import, unicode_literals + +import unittest + +from django.conf import settings +from django.core.urlresolvers import reverse +from django.test import TestCase +from django.test.utils import override_settings + +from wagtail.tests.utils import WagtailTestUtils +from wagtail.wagtailcore.models import Page + +from wagtail.tests.testapp.rich_text import CustomRichTextArea +from wagtail.wagtailadmin.rich_text import get_rich_text_editor_widget, HalloRichTextArea + + +class TestGetRichTextEditorWidget(TestCase): + @override_settings() + def test_default(self): + # Simulate the absence of a setting + if hasattr(settings, 'WAGTAILADMIN_RICH_TEXT_EDITORS'): + del settings.WAGTAILADMIN_RICH_TEXT_EDITORS + + self.assertIsInstance(get_rich_text_editor_widget(), HalloRichTextArea) + + @override_settings(WAGTAILADMIN_RICH_TEXT_EDITORS={ + 'default': { + 'WIDGET': 'wagtail.tests.testapp.rich_text.CustomRichTextArea' + }, + }) + def test_overridden_default_editor(self): + self.assertIsInstance(get_rich_text_editor_widget(), CustomRichTextArea) + + @override_settings(WAGTAILADMIN_RICH_TEXT_EDITORS={ + 'custom': { + 'WIDGET': 'wagtail.tests.testapp.rich_text.CustomRichTextArea' + }, + }) + def test_custom_editor_without_default(self): + self.assertIsInstance(get_rich_text_editor_widget('custom'), CustomRichTextArea) + + @override_settings(WAGTAILADMIN_RICH_TEXT_EDITORS={ + 'default': { + 'WIDGET': 'wagtail.wagtailadmin.rich_text.HalloRichTextArea' + }, + 'custom': { + 'WIDGET': 'wagtail.tests.testapp.rich_text.CustomRichTextArea' + }, + }) + def test_custom_editor_with_default(self): + self.assertIsInstance(get_rich_text_editor_widget(), HalloRichTextArea) + self.assertIsInstance(get_rich_text_editor_widget('custom'), CustomRichTextArea) + + +@override_settings() +class TestDefaultRichText(TestCase, WagtailTestUtils): + + def setUp(self): + # Find root page + self.root_page = Page.objects.get(id=2) + + self.login() + + # Simulate the absence of a setting + if hasattr(settings, 'WAGTAILADMIN_RICH_TEXT_EDITORS'): + del settings.WAGTAILADMIN_RICH_TEXT_EDITORS + + def tearDown(self): + from wagtail.tests.testapp.models import DefaultRichBlockFieldPage + from wagtail.tests.testapp.models import DefaultRichTextFieldPage + + DefaultRichTextFieldPage.get_edit_handler()._form_class = None + + block_page_edit_handler = DefaultRichBlockFieldPage.get_edit_handler() + if block_page_edit_handler._form_class: + rich_text_block = block_page_edit_handler._form_class.base_fields['body'].block.child_blocks['rich_text'] + if hasattr(rich_text_block, 'field'): + del rich_text_block.field + block_page_edit_handler._form_class = None + + def test_default_editor_in_rich_text_field(self): + response = self.client.get(reverse( + 'wagtailadmin_pages:add', args=('tests', 'defaultrichtextfieldpage', self.root_page.id) + )) + + # Check status code + self.assertEqual(response.status_code, 200) + + # Check that hallo (default editor by now) + self.assertContains(response, 'makeHalloRichTextEditable("id_body");') + + def test_default_editor_in_rich_text_block(self): + response = self.client.get(reverse( + 'wagtailadmin_pages:add', args=('tests', 'defaultrichblockfieldpage', self.root_page.id) + )) + + # Check status code + self.assertEqual(response.status_code, 200) + + # Check that hallo (default editor by now) + self.assertContains(response, 'makeHalloRichTextEditable("__PREFIX__-value");') + + +@override_settings(WAGTAILADMIN_RICH_TEXT_EDITORS={ + 'default': { + 'WIDGET': 'wagtail.tests.testapp.rich_text.CustomRichTextArea' + }, +}) +class TestOverriddenDefaultRichText(TestCase, WagtailTestUtils): + + def setUp(self): + # Find root page + self.root_page = Page.objects.get(id=2) + + self.login() + + def tearDown(self): + from wagtail.tests.testapp.models import DefaultRichBlockFieldPage + from wagtail.tests.testapp.models import DefaultRichTextFieldPage + + DefaultRichTextFieldPage.get_edit_handler()._form_class = None + + block_page_edit_handler = DefaultRichBlockFieldPage.get_edit_handler() + if block_page_edit_handler._form_class: + rich_text_block = block_page_edit_handler._form_class.base_fields['body'].block.child_blocks['rich_text'] + if hasattr(rich_text_block, 'field'): + del rich_text_block.field + block_page_edit_handler._form_class = None + + def test_overridden_default_editor_in_rich_text_field(self): + response = self.client.get(reverse( + 'wagtailadmin_pages:add', args=('tests', 'defaultrichtextfieldpage', self.root_page.id) + )) + + # Check status code + self.assertEqual(response.status_code, 200) + + # Check that hallo (default editor by now) was replaced with fake editor + self.assertNotContains(response, 'makeHalloRichTextEditable("id_body");') + self.assertContains(response, 'customEditorInitScript("id_body");') + + def test_overridden_default_editor_in_rich_text_block(self): + response = self.client.get(reverse( + 'wagtailadmin_pages:add', args=('tests', 'defaultrichblockfieldpage', self.root_page.id) + )) + + # Check status code + self.assertEqual(response.status_code, 200) + + # Check that hallo (default editor by now) was replaced with fake editor + self.assertNotContains(response, 'makeHalloRichTextEditable("__PREFIX__-value");') + self.assertContains(response, 'customEditorInitScript("__PREFIX__-value");') + + +@override_settings(WAGTAILADMIN_RICH_TEXT_EDITORS={ + 'default': { + 'WIDGET': 'wagtail.wagtailadmin.rich_text.HalloRichTextArea' + }, + 'custom': { + 'WIDGET': 'wagtail.tests.testapp.rich_text.CustomRichTextArea' + }, +}) +class TestCustomDefaultRichText(TestCase, WagtailTestUtils): + + def setUp(self): + # Find root page + self.root_page = Page.objects.get(id=2) + + self.login() + + def tearDown(self): + from wagtail.tests.testapp.models import CustomRichBlockFieldPage + from wagtail.tests.testapp.models import CustomRichTextFieldPage + + CustomRichBlockFieldPage.get_edit_handler()._form_class = None + CustomRichTextFieldPage.get_edit_handler()._form_class = None + + def test_custom_editor_in_rich_text_field(self): + response = self.client.get(reverse( + 'wagtailadmin_pages:add', args=('tests', 'customrichtextfieldpage', self.root_page.id) + )) + + # Check status code + self.assertEqual(response.status_code, 200) + + # Check that hallo (default editor by now) was replaced with fake editor + self.assertNotContains(response, 'makeHalloRichTextEditable("id_body");') + self.assertContains(response, 'customEditorInitScript("id_body");') + + def test_custom_editor_in_rich_text_block(self): + response = self.client.get(reverse( + 'wagtailadmin_pages:add', args=('tests', 'customrichblockfieldpage', self.root_page.id) + )) + + # Check status code + self.assertEqual(response.status_code, 200) + + # Check that hallo (default editor by now) was replaced with fake editor + self.assertNotContains(response, 'makeHalloRichTextEditable("__PREFIX__-value");') + self.assertContains(response, 'customEditorInitScript("__PREFIX__-value");') diff --git a/wagtail/wagtailcore/blocks/field_block.py b/wagtail/wagtailcore/blocks/field_block.py index 8f9e097bfe..f622ba5a46 100644 --- a/wagtail/wagtailcore/blocks/field_block.py +++ b/wagtail/wagtailcore/blocks/field_block.py @@ -326,8 +326,8 @@ class RichTextBlock(FieldBlock): @cached_property def field(self): - from wagtail.wagtailadmin.rich_text import get_rich_text_editor - return forms.CharField(widget=get_rich_text_editor(self.editor), **self.field_options) + from wagtail.wagtailadmin.rich_text import get_rich_text_editor_widget + return forms.CharField(widget=get_rich_text_editor_widget(self.editor), **self.field_options) def value_for_form(self, value): # Rich text editors take the source-HTML string as input (and takes care diff --git a/wagtail/wagtailcore/fields.py b/wagtail/wagtailcore/fields.py index c301c3418f..253bbf00ea 100644 --- a/wagtail/wagtailcore/fields.py +++ b/wagtail/wagtailcore/fields.py @@ -15,8 +15,8 @@ class RichTextField(models.TextField): super(RichTextField, self).__init__(*args, **kwargs) def formfield(self, **kwargs): - from wagtail.wagtailadmin.rich_text import get_rich_text_editor - defaults = {'widget': get_rich_text_editor(self.editor)} + from wagtail.wagtailadmin.rich_text import get_rich_text_editor_widget + defaults = {'widget': get_rich_text_editor_widget(self.editor)} defaults.update(kwargs) return super(RichTextField, self).formfield(**defaults)