From f7c7d1fd838d8e2b0928873940a3ea177457ddb7 Mon Sep 17 00:00:00 2001 From: Jakub Mastalerz Date: Fri, 7 Jun 2024 11:32:40 +0100 Subject: [PATCH 1/6] make value fields nullable on chooser streamfield blocks --- CHANGELOG.md | 4 ++++ grapple/types/streamfield.py | 8 ++++---- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index de6d5f8e..2dd7441b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ ## Unreleased +### Changed + +- Make value fields nullable on `PageChooserBlock`, `SnippetChooserBlock`, `DocumentChooserBlock` and `ImageChooserBlock` + ## [0.25.1] - 2024-04-21 ### Changed diff --git a/grapple/types/streamfield.py b/grapple/types/streamfield.py index f62b9b74..71b79745 100644 --- a/grapple/types/streamfield.py +++ b/grapple/types/streamfield.py @@ -436,7 +436,7 @@ def register_streamfield_blocks(): from .snippets import SnippetTypes class PageChooserBlock(graphene.ObjectType): - page = graphene.Field(get_page_interface(), required=True) + page = graphene.Field(get_page_interface(), required=False) class Meta: interfaces = (StreamFieldInterface,) @@ -445,7 +445,7 @@ def resolve_page(self, info, **kwargs): return self.value.specific class DocumentChooserBlock(graphene.ObjectType): - document = graphene.Field(get_document_type(), required=True) + document = graphene.Field(get_document_type(), required=False) class Meta: interfaces = (StreamFieldInterface,) @@ -454,7 +454,7 @@ def resolve_document(self, info, **kwargs): return self.value class ImageChooserBlock(graphene.ObjectType): - image = graphene.Field(get_image_type(), required=True) + image = graphene.Field(get_image_type(), required=False) class Meta: interfaces = (StreamFieldInterface,) @@ -474,7 +474,7 @@ def resolve_image(self, info, **kwargs): if SnippetObjectType is not None: class SnippetChooserBlock(graphene.ObjectType): - snippet = graphene.Field(SnippetObjectType, required=True) + snippet = graphene.Field(SnippetObjectType, required=False) class Meta: interfaces = (StreamFieldInterface,) From 51b91bbd28ba31ed7239e5fcedb6d687f7ff52b5 Mon Sep 17 00:00:00 2001 From: Jakub Mastalerz Date: Mon, 10 Jun 2024 14:22:07 +0100 Subject: [PATCH 2/6] fix typo --- tests/test_interfaces.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_interfaces.py b/tests/test_interfaces.py index 374120ce..1ab7d826 100644 --- a/tests/test_interfaces.py +++ b/tests/test_interfaces.py @@ -80,7 +80,7 @@ def test_schema_for_page_with_graphql_interface(self): [{"name": "CustomInterface"}, {"name": "PageInterface"}], ) - def test_schem_for_snippet_with_graphql_interface(self): + def test_schema_for_snippet_with_graphql_interface(self): results = self.introspect_schema_by_type("Advert") self.assertListEqual( sorted(results["data"]["__type"]["interfaces"], key=lambda x: x["name"]), From 7015e4bca5d100c1299ec95b22bba0b25ce44e6c Mon Sep 17 00:00:00 2001 From: Jakub Mastalerz Date: Mon, 10 Jun 2024 17:18:54 +0100 Subject: [PATCH 3/6] add tests for chooser block fields --- tests/test_models_types.py | 56 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/tests/test_models_types.py b/tests/test_models_types.py index 305bf77a..ee98d6bd 100644 --- a/tests/test_models_types.py +++ b/tests/test_models_types.py @@ -1,7 +1,12 @@ import graphene from django.test import TestCase +from wagtail.blocks.field_block import PageChooserBlock +from wagtail.documents.blocks import DocumentChooserBlock +from wagtail.images.blocks import ImageChooserBlock +from wagtail.snippets.blocks import SnippetChooserBlock +from grapple import registry from grapple.actions import get_field_type from grapple.exceptions import IllegalDeprecation from grapple.models import ( @@ -183,3 +188,54 @@ def test_collection_field_required_deprecated(self): required=True, deprecation_reason=self.deprecation_reason, )() + + +class ChooserBlocksTest(TestCase): + """ + Test that "Chooser" blocks take null values to ensure correct handling + of deleted objects referenced in these blocks. + """ + + def test_snippet_chooser_block_value_field_not_required(self): + """ + Test the SnippetChooserBlock snippet field. + """ + block = registry.registry.streamfield_blocks[SnippetChooserBlock] + field = block.snippet + + # Check that field is not required by asserting type isn't `NonNull` + self.assertIsInstance(field, graphene.types.field.Field) + self.assertNotIsInstance(field, graphene.NonNull) + + def test_document_chooser_block_value_field_not_required(self): + """ + Test the DocumentChooserBlock document field. + """ + block = registry.registry.streamfield_blocks[DocumentChooserBlock] + field = block.document + + # Check that field is not required by asserting type isn't `NonNull` + self.assertIsInstance(field, graphene.types.field.Field) + self.assertNotIsInstance(field, graphene.NonNull) + + def test_image_chooser_block_value_field_not_required(self): + """ + Test the ImageChooserBlock image field. + """ + block = registry.registry.streamfield_blocks[ImageChooserBlock] + field = block.image + + # Check that field is not required by asserting type isn't `NonNull` + self.assertIsInstance(field, graphene.types.field.Field) + self.assertNotIsInstance(field, graphene.NonNull) + + def test_page_chooser_block_value_field_not_required(self): + """ + Test the PageChooserBlock page field. + """ + block = registry.registry.streamfield_blocks[PageChooserBlock] + field = block.page + + # Check that field is not required by asserting type isn't `NonNull` + self.assertIsInstance(field, graphene.types.field.Field) + self.assertNotIsInstance(field, graphene.NonNull) From 997c077e6149a08570f235c5b7afb1e2b516f44f Mon Sep 17 00:00:00 2001 From: Jakub Mastalerz Date: Mon, 10 Jun 2024 17:28:03 +0100 Subject: [PATCH 4/6] update changelog --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2dd7441b..3fc55826 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,7 @@ ### Changed -- Make value fields nullable on `PageChooserBlock`, `SnippetChooserBlock`, `DocumentChooserBlock` and `ImageChooserBlock` +- Make value fields nullable on `PageChooserBlock`, `SnippetChooserBlock`, `DocumentChooserBlock` and `ImageChooserBlock` ([#396](https://github.com/torchbox/wagtail-grapple/pull/396)) ## [0.25.1] - 2024-04-21 From 2667e0b59741848eacb8f313286d511aa9ebebde Mon Sep 17 00:00:00 2001 From: Jakub Mastalerz Date: Tue, 11 Jun 2024 13:59:04 +0100 Subject: [PATCH 5/6] update non null tests --- tests/test_models_types.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/test_models_types.py b/tests/test_models_types.py index ee98d6bd..da38e040 100644 --- a/tests/test_models_types.py +++ b/tests/test_models_types.py @@ -205,7 +205,7 @@ def test_snippet_chooser_block_value_field_not_required(self): # Check that field is not required by asserting type isn't `NonNull` self.assertIsInstance(field, graphene.types.field.Field) - self.assertNotIsInstance(field, graphene.NonNull) + self.assertNotIsInstance(field.type, graphene.NonNull) def test_document_chooser_block_value_field_not_required(self): """ @@ -216,7 +216,7 @@ def test_document_chooser_block_value_field_not_required(self): # Check that field is not required by asserting type isn't `NonNull` self.assertIsInstance(field, graphene.types.field.Field) - self.assertNotIsInstance(field, graphene.NonNull) + self.assertNotIsInstance(field.type, graphene.NonNull) def test_image_chooser_block_value_field_not_required(self): """ @@ -227,7 +227,7 @@ def test_image_chooser_block_value_field_not_required(self): # Check that field is not required by asserting type isn't `NonNull` self.assertIsInstance(field, graphene.types.field.Field) - self.assertNotIsInstance(field, graphene.NonNull) + self.assertNotIsInstance(field.type, graphene.NonNull) def test_page_chooser_block_value_field_not_required(self): """ @@ -238,4 +238,4 @@ def test_page_chooser_block_value_field_not_required(self): # Check that field is not required by asserting type isn't `NonNull` self.assertIsInstance(field, graphene.types.field.Field) - self.assertNotIsInstance(field, graphene.NonNull) + self.assertNotIsInstance(field.type, graphene.NonNull) From 62966cb26d879088caac16db32220842648f41f1 Mon Sep 17 00:00:00 2001 From: Jakub Mastalerz Date: Wed, 12 Jun 2024 10:47:43 +0100 Subject: [PATCH 6/6] update docstrings on chooser block tests --- tests/test_models_types.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/tests/test_models_types.py b/tests/test_models_types.py index da38e040..987df8d2 100644 --- a/tests/test_models_types.py +++ b/tests/test_models_types.py @@ -198,7 +198,8 @@ class ChooserBlocksTest(TestCase): def test_snippet_chooser_block_value_field_not_required(self): """ - Test the SnippetChooserBlock snippet field. + Test that the SnippetChooserBlock snippet field is nullable in the + GraphQL schema. """ block = registry.registry.streamfield_blocks[SnippetChooserBlock] field = block.snippet @@ -209,7 +210,8 @@ def test_snippet_chooser_block_value_field_not_required(self): def test_document_chooser_block_value_field_not_required(self): """ - Test the DocumentChooserBlock document field. + Test that the DocumentChooserBlock document field is nullable in the + GraphQL schema. """ block = registry.registry.streamfield_blocks[DocumentChooserBlock] field = block.document @@ -220,7 +222,8 @@ def test_document_chooser_block_value_field_not_required(self): def test_image_chooser_block_value_field_not_required(self): """ - Test the ImageChooserBlock image field. + Test that the ImageChooserBlock image field is nullable in the GraphQL + schema. """ block = registry.registry.streamfield_blocks[ImageChooserBlock] field = block.image @@ -231,7 +234,8 @@ def test_image_chooser_block_value_field_not_required(self): def test_page_chooser_block_value_field_not_required(self): """ - Test the PageChooserBlock page field. + Test that the PageChooserBlock page field is nullable in the GraphQL + schema. """ block = registry.registry.streamfield_blocks[PageChooserBlock] field = block.page