Browse Source

Add tests for `RevisionMixin`

Sage Abdullah 2 years ago
parent
commit
00c696d285

+ 85 - 0
wagtail/test/testapp/migrations/0072_revisablemodels.py

@@ -0,0 +1,85 @@
+# Generated by Django 4.0.4 on 2022-05-25 15:21
+
+from django.db import migrations, models
+import django.db.models.deletion
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ("wagtailcore", "0073_page_latest_revision"),
+        ("tests", "0071_alter_customrestaurantimage_file_hash"),
+    ]
+
+    operations = [
+        migrations.CreateModel(
+            name="RevisableModel",
+            fields=[
+                (
+                    "id",
+                    models.AutoField(
+                        auto_created=True,
+                        primary_key=True,
+                        serialize=False,
+                        verbose_name="ID",
+                    ),
+                ),
+                ("text", models.TextField()),
+                (
+                    "latest_revision",
+                    models.ForeignKey(
+                        blank=True,
+                        editable=False,
+                        null=True,
+                        on_delete=django.db.models.deletion.SET_NULL,
+                        related_name="+",
+                        to="wagtailcore.revision",
+                        verbose_name="latest revision",
+                    ),
+                ),
+            ],
+            options={
+                "abstract": False,
+            },
+        ),
+        migrations.CreateModel(
+            name="RevisableChildModel",
+            fields=[
+                (
+                    "revisablemodel_ptr",
+                    models.OneToOneField(
+                        auto_created=True,
+                        on_delete=django.db.models.deletion.CASCADE,
+                        parent_link=True,
+                        primary_key=True,
+                        serialize=False,
+                        to="tests.revisablemodel",
+                    ),
+                ),
+            ],
+            options={
+                "abstract": False,
+            },
+            bases=("tests.revisablemodel",),
+        ),
+        migrations.CreateModel(
+            name="RevisableGrandChildModel",
+            fields=[
+                (
+                    "revisablechildmodel_ptr",
+                    models.OneToOneField(
+                        auto_created=True,
+                        on_delete=django.db.models.deletion.CASCADE,
+                        parent_link=True,
+                        primary_key=True,
+                        serialize=False,
+                        to="tests.revisablechildmodel",
+                    ),
+                ),
+            ],
+            options={
+                "abstract": False,
+            },
+            bases=("tests.revisablechildmodel",),
+        ),
+    ]

+ 14 - 0
wagtail/test/testapp/models.py

@@ -58,6 +58,7 @@ from wagtail.models import (
     Page,
     PageManager,
     PageQuerySet,
+    RevisionMixin,
     Task,
     TranslatableMixin,
 )
@@ -938,6 +939,19 @@ class AdvertWithTabbedInterface(models.Model):
 register_snippet(AdvertWithTabbedInterface)
 
 
+# Models with RevisionMixin
+class RevisableModel(RevisionMixin, models.Model):
+    text = models.TextField()
+
+
+class RevisableChildModel(RevisableModel):
+    pass
+
+
+class RevisableGrandChildModel(RevisableChildModel):
+    pass
+
+
 class StandardIndex(Page):
     """Index for the site"""
 

+ 127 - 0
wagtail/tests/test_revision_model.py

@@ -0,0 +1,127 @@
+from django.contrib.contenttypes.models import ContentType
+from django.test import TestCase
+
+from wagtail.models import Page, Revision, get_default_page_content_type
+from wagtail.test.testapp.models import (
+    RevisableGrandChildModel,
+    RevisableModel,
+    SimplePage,
+)
+
+
+class TestRevisableModel(TestCase):
+    @classmethod
+    def setUpTestData(cls):
+        cls.instance = RevisableModel.objects.create(text="foo")
+        cls.content_type = ContentType.objects.get_for_model(RevisableModel)
+
+    @classmethod
+    def create_page(cls):
+        homepage = Page.objects.get(url_path="/home/")
+        hello_page = SimplePage(
+            title="Hello world", slug="hello-world", content="hello"
+        )
+        homepage.add_child(instance=hello_page)
+        return hello_page
+
+    def test_can_save_revision(self):
+        self.instance.text = "updated"
+        revision = self.instance.save_revision()
+        revision_from_db = self.instance.revisions.first()
+        self.instance.refresh_from_db()
+
+        self.assertEqual(revision, revision_from_db)
+        # The latest revision should be set
+        self.assertEqual(self.instance.latest_revision, revision_from_db)
+        # The revision should have the updated data
+        self.assertEqual(revision_from_db.content["text"], "updated")
+        # Only saving a revision should not update the instance itself
+        self.assertEqual(self.instance.text, "foo")
+
+    def test_get_latest_revision_exists(self):
+        self.instance.text = "updated"
+        revision = self.instance.save_revision()
+        self.instance.text = "updated twice"
+        revision = self.instance.save_revision()
+        self.instance.refresh_from_db()
+
+        with self.assertNumQueries(1):
+            # Should be able to query directly using latest_revision ForeignKey
+            revision_from_db = self.instance.get_latest_revision()
+
+        self.assertEqual(revision, revision_from_db)
+        self.assertEqual(revision_from_db.content["text"], "updated twice")
+
+    def test_content_type_without_inheritance(self):
+        self.instance.text = "updated"
+        revision = self.instance.save_revision()
+
+        revision_from_db = Revision.objects.filter(
+            base_content_type=self.content_type,
+            content_type=self.content_type,
+            object_id=self.instance.pk,
+        ).first()
+
+        self.assertEqual(revision, revision_from_db)
+        self.assertEqual(self.instance.get_base_content_type(), self.content_type)
+        self.assertEqual(self.instance.get_content_type(), self.content_type)
+
+    def test_content_type_with_inheritance(self):
+        instance = RevisableGrandChildModel.objects.create(text="test")
+        instance.text = "test updated"
+        revision = instance.save_revision()
+
+        base_content_type = self.content_type
+        content_type = ContentType.objects.get_for_model(RevisableGrandChildModel)
+        revision_from_db = Revision.objects.filter(
+            base_content_type=base_content_type,
+            content_type=content_type,
+            object_id=instance.pk,
+        ).first()
+
+        self.assertEqual(revision, revision_from_db)
+        self.assertEqual(instance.get_base_content_type(), base_content_type)
+        self.assertEqual(instance.get_content_type(), content_type)
+
+    def test_content_type_for_page_model(self):
+        hello_page = self.create_page()
+        hello_page.content = "Updated world"
+        revision = hello_page.save_revision()
+
+        base_content_type = get_default_page_content_type()
+        content_type = ContentType.objects.get_for_model(SimplePage)
+        revision_from_db = Revision.objects.filter(
+            base_content_type=base_content_type,
+            content_type=content_type,
+            object_id=hello_page.pk,
+        ).first()
+
+        self.assertEqual(revision, revision_from_db)
+        self.assertEqual(hello_page.get_base_content_type(), base_content_type)
+        self.assertEqual(hello_page.get_content_type(), content_type)
+
+    def test_as_object(self):
+        self.instance.text = "updated"
+        self.instance.save_revision()
+        self.instance.refresh_from_db()
+        revision = self.instance.revisions.first()
+        instance = revision.as_object()
+
+        self.assertIsInstance(instance, RevisableModel)
+        # The instance created from the revision should be updated
+        self.assertEqual(instance.text, "updated")
+        # Only saving a revision should not update the instance itself
+        self.assertEqual(self.instance.text, "foo")
+
+    def test_as_object_with_page(self):
+        hello_page = self.create_page()
+        hello_page.content = "updated"
+        hello_page.save_revision()
+        hello_page.refresh_from_db()
+        revision = hello_page.revisions.first()
+        instance = revision.as_object()
+
+        # The instance should be of the specific page class.
+        self.assertIsInstance(instance, SimplePage)
+        self.assertEqual(instance.content, "updated")
+        self.assertEqual(hello_page.content, "hello")