diff --git a/wagtail/tests/utils.py b/wagtail/tests/utils.py index c44549401..9360f2206 100644 --- a/wagtail/tests/utils.py +++ b/wagtail/tests/utils.py @@ -1,4 +1,5 @@ from django.contrib.auth.models import User +from django.utils import six # We need to make sure that we're using the same unittest library that Django uses internally # Otherwise, we get issues with the "SkipTest" and "ExpectedFailure" exceptions being recognised as errors @@ -21,3 +22,6 @@ class WagtailTestUtils(object): self.client.login(username='test', password='password') return user + + def assertRegex(self, *args, **kwargs): + six.assertRegex(self, *args, **kwargs) diff --git a/wagtail/wagtailadmin/edit_handlers.py b/wagtail/wagtailadmin/edit_handlers.py index ba6edc4fa..d2eb181c3 100644 --- a/wagtail/wagtailadmin/edit_handlers.py +++ b/wagtail/wagtailadmin/edit_handlers.py @@ -575,6 +575,11 @@ class BaseInlinePanel(EditHandler): child_edit_handler_class(instance=subform.instance, form=subform) ) + # if this formset is valid, it may have been re-ordered; respect that + # in case the parent form errored and we need to re-render + if self.formset.can_order and self.formset.is_valid(): + self.children = sorted(self.children, key=lambda x: x.form.cleaned_data['ORDER']) + empty_form = self.formset.empty_form empty_form.fields['DELETE'].widget = forms.HiddenInput() if self.formset.can_order: diff --git a/wagtail/wagtailadmin/tests/test_edit_handlers.py b/wagtail/wagtailadmin/tests/test_edit_handlers.py index 48e24aff2..8b499378c 100644 --- a/wagtail/wagtailadmin/tests/test_edit_handlers.py +++ b/wagtail/wagtailadmin/tests/test_edit_handlers.py @@ -312,6 +312,10 @@ class TestInlinePanel(TestCase): 'ORDER': MagicMock()} instance = FakeInstance() + cleaned_data = { + 'ORDER': 0, + } + def __repr__(self): return 'fake form' @@ -319,6 +323,9 @@ class TestInlinePanel(TestCase): empty_form = FakeForm() can_order = True + def is_valid(self): + return True + label = 'label' help_text = 'help text' errors = ['errors'] diff --git a/wagtail/wagtailadmin/tests/test_pages_views.py b/wagtail/wagtailadmin/tests/test_pages_views.py index 9e95e50b1..1551eaab2 100644 --- a/wagtail/wagtailadmin/tests/test_pages_views.py +++ b/wagtail/wagtailadmin/tests/test_pages_views.py @@ -7,8 +7,8 @@ from django.core import mail from django.core.paginator import Paginator from django.utils import timezone -from wagtail.tests.models import SimplePage, EventPage, StandardIndex, BusinessIndex, BusinessChild, BusinessSubIndex -from wagtail.tests.utils import WagtailTestUtils +from wagtail.tests.models import SimplePage, EventPage, EventPageCarouselItem, StandardIndex, BusinessIndex, BusinessChild, BusinessSubIndex +from wagtail.tests.utils import unittest, WagtailTestUtils from wagtail.wagtailcore.models import Page, PageRevision from wagtail.wagtailcore.signals import page_published from wagtail.wagtailusers.models import UserProfile @@ -654,6 +654,115 @@ class TestPageEdit(TestCase, WagtailTestUtils): self.assertContains(response, "I've been edited!") +class TestPageEditReordering(TestCase, WagtailTestUtils): + def setUp(self): + # Find root page + self.root_page = Page.objects.get(id=2) + + # Add event page + self.event_page = EventPage() + self.event_page.title = "Event page" + self.event_page.slug = "event-page" + self.event_page.carousel_items = [ + EventPageCarouselItem(caption='1234567', sort_order=1), + EventPageCarouselItem(caption='7654321', sort_order=2), + EventPageCarouselItem(caption='abcdefg', sort_order=3), + ] + self.root_page.add_child(instance=self.event_page) + + # Login + self.user = self.login() + + def check_order(self, response, expected_order): + inline_panel = response.context['edit_handler'].children[0].children[9] + order = [child.form.instance.caption for child in inline_panel.children] + self.assertEqual(order, expected_order) + + def test_order(self): + response = self.client.get(reverse('wagtailadmin_pages_edit', args=(self.event_page.id, ))) + + self.assertEqual(response.status_code, 200) + self.check_order(response, ['1234567', '7654321', 'abcdefg']) + + def test_reorder(self): + post_data = { + 'title': "Event page", + 'slug': 'event-page', + + 'date_from': '01/01/2014', + 'cost': '$10', + 'audience': 'public', + 'location': 'somewhere', + + 'related_links-INITIAL_FORMS': 0, + 'related_links-MAX_NUM_FORMS': 1000, + 'related_links-TOTAL_FORMS': 0, + + 'speakers-INITIAL_FORMS': 0, + 'speakers-MAX_NUM_FORMS': 1000, + 'speakers-TOTAL_FORMS': 0, + + 'carousel_items-INITIAL_FORMS': 3, + 'carousel_items-MAX_NUM_FORMS': 1000, + 'carousel_items-TOTAL_FORMS': 3, + 'carousel_items-0-id': self.event_page.carousel_items.all()[0].id, + 'carousel_items-0-caption': self.event_page.carousel_items.all()[0].caption, + 'carousel_items-0-ORDER': 2, + 'carousel_items-1-id': self.event_page.carousel_items.all()[1].id, + 'carousel_items-1-caption': self.event_page.carousel_items.all()[1].caption, + 'carousel_items-1-ORDER': 3, + 'carousel_items-2-id': self.event_page.carousel_items.all()[2].id, + 'carousel_items-2-caption': self.event_page.carousel_items.all()[2].caption, + 'carousel_items-2-ORDER': 1, + } + response = self.client.post(reverse('wagtailadmin_pages_edit', args=(self.event_page.id, )), post_data) + + # Should be redirected to explorer page + self.assertRedirects(response, reverse('wagtailadmin_explore', args=(self.root_page.id, ))) + + # Check order + response = self.client.get(reverse('wagtailadmin_pages_edit', args=(self.event_page.id, ))) + + self.assertEqual(response.status_code, 200) + self.check_order(response, ['abcdefg', '1234567', '7654321']) + + def test_reorder_with_validation_error(self): + post_data = { + 'title': "", # Validation error + 'slug': 'event-page', + + 'date_from': '01/01/2014', + 'cost': '$10', + 'audience': 'public', + 'location': 'somewhere', + + 'related_links-INITIAL_FORMS': 0, + 'related_links-MAX_NUM_FORMS': 1000, + 'related_links-TOTAL_FORMS': 0, + + 'speakers-INITIAL_FORMS': 0, + 'speakers-MAX_NUM_FORMS': 1000, + 'speakers-TOTAL_FORMS': 0, + + 'carousel_items-INITIAL_FORMS': 3, + 'carousel_items-MAX_NUM_FORMS': 1000, + 'carousel_items-TOTAL_FORMS': 3, + 'carousel_items-0-id': self.event_page.carousel_items.all()[0].id, + 'carousel_items-0-caption': self.event_page.carousel_items.all()[0].caption, + 'carousel_items-0-ORDER': 2, + 'carousel_items-1-id': self.event_page.carousel_items.all()[1].id, + 'carousel_items-1-caption': self.event_page.carousel_items.all()[1].caption, + 'carousel_items-1-ORDER': 3, + 'carousel_items-2-id': self.event_page.carousel_items.all()[2].id, + 'carousel_items-2-caption': self.event_page.carousel_items.all()[2].caption, + 'carousel_items-2-ORDER': 1, + } + response = self.client.post(reverse('wagtailadmin_pages_edit', args=(self.event_page.id, )), post_data) + + self.assertEqual(response.status_code, 200) + self.check_order(response, ['abcdefg', '1234567', '7654321']) + + class TestPageDelete(TestCase, WagtailTestUtils): def setUp(self): # Find root page