Home > Software design >  Testing Django Wagtail - assert that a child of the given Page type with an image can be created und
Testing Django Wagtail - assert that a child of the given Page type with an image can be created und

Time:03-08

I've defined a custom page model (a blog post) as a child of a parent model (a blog index page) and I want to test that the child can be created under its parent.

The BlogPage and BlogIndexPage models are copied from the wagtail "basic blog" example in the documentation, and works as expected.

I'm trying to follow the documentation but I get the following error:

AssertionError: Creating a page failed for an unknown reason

Through trial and error, I know that the error is caused by including an InlinePanel that references another model (BlogPageGalleryImage). If I remove this panel from my BlogPost model definition then the test will pass. I don't understand why including the panel causes an error, or how to solve this problem.

Any help is much appreciated!

The problematic line:

...

InlinePanel("gallery_images", label="Gallery images"),

...

The models:

class BlogIndexPage(Page):
    template = "blog.html"
    intro = models.TextField(blank=True)
    subpage_types = ["cms.BlogPage", "cms.SimpleBlogPage", "cms.BlogTagIndexPage"]

    def get_context(self, request):
        # Update context to include only published posts, ordered by reverse-chron
        context = super().get_context(request)
        blogpages = self.get_children().live().order_by("-first_published_at")
        context["blogpages"] = blogpages
        return context

    content_panels = Page.content_panels   [FieldPanel("intro", classname="full")]


class BlogPage(Page):
    template = "blog-post.html"
    parent_page_types = ["cms.BlogIndexPage"]

    date = models.DateField("Post date")
    intro = models.CharField(max_length=250)
    body = RichTextField(blank=True)
    tags = ClusterTaggableManager(through=BlogPageTag, blank=True)
    categories = ParentalManyToManyField("cms.BlogCategory", blank=True)

    def main_image(self):
        gallery_item = self.gallery_images.first()
        if gallery_item:
            return gallery_item.image
        else:
            return None

    search_fields = Page.search_fields   [
        index.SearchField("intro"),
        index.SearchField("body"),
    ]

    content_panels = Page.content_panels   [
        MultiFieldPanel(
            [
                FieldPanel("date"),
                FieldPanel("tags"),
                FieldPanel("categories", widget=forms.CheckboxSelectMultiple),
            ],
            heading="Meta data",
        ),
        FieldPanel("intro"),
        FieldPanel("body"),
        InlinePanel("gallery_images", label="Gallery images"),
    ]


class BlogPageGalleryImage(Orderable):
    page = ParentalKey(BlogPage, on_delete=models.CASCADE, related_name="gallery_images")
    image = models.ForeignKey("wagtailimages.Image", on_delete=models.CASCADE, related_name=" ")
    caption = models.CharField(blank=True, max_length=250)

    panels = [
        ImageChooserPanel("image"),
        FieldPanel("caption"),
    ]

The test:

class MyPageTests(WagtailPageTests):
    def setUp(self):
        self.login()

        indexPage = BlogIndexPage(title="Home page", path="blog", pk=1, depth=1)
        indexPage.save()

        page = BlogPage(
            title="a blog post", intro="an intro", path="blog/post", depth=2, date="2022-02-23"
        )
        page.save()

        image = Image(height=1, width=1)
        image.save()

        galleryImage = BlogPageGalleryImage(pk=1, page=page, image=image, caption="foo")
        galleryImage.save()

        category = BlogCategory(name="cat1", pk=1)
        category.save()

    def test_create_blog_post(self):
        root_page = BlogIndexPage.objects.first()

        data = {
            "date": datetime.date(2022, 2, 28),
            "title": "the title",
            "intro": "the intro",
            "depth": 2,
        }

        self.assertCanCreate(root_page, BlogPage, data)

CodePudding user response:

The data passed to assertCanCreate is a dict of HTTP form submission data to be handled by the 'create' view. When you have an InlinePanel as part of the creation form - even if you're not passing any data into it - there's a bundle of extra form fields that needs to be present, to tell it how many child forms are being submitted.

You can use the inline_formset helper (in conjunction with the nested_form_data helper which flattens the nested structure into a plain set of form fields) from Wagtail's testing utilities to construct a compatible form submission:

from wagtail.tests.utils.form_data import inline_formset, nested_form_data

class MyPageTests(WagtailPageTests):
    # ...

    def test_create_blog_post(self):
        root_page = BlogIndexPage.objects.first()

        data = nested_form_data({
            "date": datetime.date(2022, 2, 28),
            "title": "the title",
            "intro": "the intro",
            "gallery_images": inline_formset([])
        })

        self.assertCanCreate(root_page, BlogPage, data)

(You shouldn't need to include depth in the form submission, as that's an internal database field used to keep track of the page's position in the page tree - and that's already taken care of in the assertCanCreate call as you've specified root_page as the parent page.)

  • Related