Repository: saleor/saleor

Issue:
Errors occur when update a page
### What I'm trying to achieve
Update a `Page`

### Steps to reproduce the problem
1.  Call `Mutation.pageUpdate ` with `input: {}`
```bash
web_1     | ERROR saleor.graphql.errors.unhandled A query failed unexpectedly [PID:8:Thread-52]
web_1     | Traceback (most recent call last):
web_1     |   File "/usr/local/lib/python3.8/site-packages/promise/promise.py", line 489, in _resolve_from_executor
web_1     |     executor(resolve, reject)
web_1     |   File "/usr/local/lib/python3.8/site-packages/promise/promise.py", line 756, in executor
web_1     |     return resolve(f(*args, **kwargs))
web_1     |   File "/usr/local/lib/python3.8/site-packages/graphql/execution/middleware.py", line 75, in make_it_promise
web_1     |     return next(*args, **kwargs)
web_1     |   File "/app/saleor/graphql/core/mutations.py", line 279, in mutate
web_1     |     response = cls.perform_mutation(root, info, **data)
web_1     |   File "/app/saleor/graphql/core/mutations.py", line 448, in perform_mutation
web_1     |     cleaned_input = cls.clean_input(info, instance, data)
web_1     |   File "/app/saleor/graphql/page/mutations.py", line 43, in clean_input
web_1     |     cleaned_input["slug"] = slugify(cleaned_input["title"])
web_1     | KeyError: 'title'
```

### What I expected to happen
should update a `Page` without error




Discussion:
Thanks for reporting, that's clearly a bug. This error also appears for the `pageCreate` mutation. Now the code assumes that `title` is always present while it's not required by the schema. It should be required when creating new pages and optional when updating existing ones.

Resolving patch:
diff --git a/saleor/graphql/page/mutations.py b/saleor/graphql/page/mutations.py
--- a/saleor/graphql/page/mutations.py
+++ b/saleor/graphql/page/mutations.py
@@ -39,8 +39,9 @@ class Meta:
     def clean_input(cls, info, instance, data):
         cleaned_input = super().clean_input(info, instance, data)
         slug = cleaned_input.get("slug", "")
-        if not slug:
-            cleaned_input["slug"] = slugify(cleaned_input["title"])
+        title = cleaned_input.get("title", "")
+        if title and not slug:
+            cleaned_input["slug"] = slugify(title)
         clean_seo_fields(cleaned_input)
         return cleaned_input
 


Test patch:
diff --git a/tests/api/test_page.py b/tests/api/test_page.py
--- a/tests/api/test_page.py
+++ b/tests/api/test_page.py
@@ -146,6 +146,21 @@ def test_page_create_mutation(staff_api_client, permission_manage_pages):
     assert data["page"]["isPublished"] == page_is_published
 
 
+def test_page_create_required_fields(staff_api_client, permission_manage_pages):
+    response = staff_api_client.post_graphql(
+        CREATE_PAGE_MUTATION, {}, permissions=[permission_manage_pages]
+    )
+    content = get_graphql_content(response)
+    errors = content["data"]["pageCreate"]["errors"]
+
+    err_msg = "This field cannot be blank."
+    title_error = {"field": "slug", "message": err_msg}
+    slug_error = {"field": "title", "message": err_msg}
+
+    assert title_error in errors
+    assert slug_error in errors
+
+
 def test_create_default_slug(staff_api_client, permission_manage_pages):
     # test creating root page
     title = "Spanish inquisition"