def test_key_in_post(self): """ Ensure a key is in the post. """ self.client.login(username='******', password='******') data = { 'data': { 'type': 'users', 'id': encoding.force_text(self.miles.pk), 'attributes': { 'first-name': self.miles.first_name, 'last-name': self.miles.last_name, 'email': '*****@*****.**' }, } } response = self.client.put(self.detail_url, content_type='application/vnd.api+json', data=dump_json(data)) content_dump = redump_json(response.content) expected_dump = dump_json(data) assert expected_dump == content_dump # is it updated? self.assertEqual( get_user_model().objects.get(pk=self.miles.pk).email, '*****@*****.**')
def test_top_level_meta_for_detail_view(blog, client): expected = { "data": { "type": "blogs", "id": "1", "attributes": { "name": blog.name }, "links": { "self": "http://testserver/blogs/1" }, "meta": { "copyright": datetime.now().year }, }, "meta": { "apiDocs": "/docs/api/blogs" }, } response = client.get(reverse("blog-detail", kwargs={'pk': blog.pk})) content_dump = redump_json(response.content) expected_dump = dump_json(expected) assert content_dump == expected_dump
def test_model_serializer_with_implicit_fields(self, comment, client): expected = { "data": { "type": "comments", "id": str(comment.pk), "attributes": { "body": comment.body }, "relationships": { "entry": { "data": { "type": "entries", "id": str(comment.entry.pk) } }, "author": { "data": { "type": "authors", "id": str(comment.author.pk) } }, } } } response = client.get( reverse("comment-detail", kwargs={'pk': comment.pk})) assert response.status_code == 200 actual = redump_json(response.content) expected_json = dump_json(expected) assert actual == expected_json
def test_ember_expected_renderer(self): """ The :class:`UserEmber` ViewSet has the ``resource_name`` of 'data' so that should be the key in the JSON response. """ url = reverse('user-manual-resource-name', kwargs={'pk': self.miles.pk}) response = self.client.get(url) self.assertEqual(200, response.status_code) expected = { 'data': { 'type': 'data', 'id': '2', 'attributes': { 'first-name': 'Miles', 'last-name': 'Davis', 'email': '*****@*****.**' } } } content_dump = redump_json(response.content) expected_dump = dump_json(expected) assert expected_dump == content_dump
def test_default_validation_exceptions(self): """ Default validation exceptions should conform to json api spec """ expected = { 'errors': [ { 'status': '400', 'source': { 'pointer': '/data/attributes/email', }, 'detail': 'Enter a valid email address.', }, { 'status': '400', 'source': { 'pointer': '/data/attributes/first-name', }, 'detail': 'There\'s a problem with first name', } ] } response = self.client.post('/identities', { 'email': 'bar', 'first_name': 'alajflajaljalajlfjafljalj'}) content_dump = redump_json(response.content) expected_dump = dump_json(expected) assert expected_dump == content_dump
def test_custom_validation_exceptions(self): """ Exceptions should be able to be formatted manually """ expected = { 'errors': [ { 'id': 'armageddon101', 'detail': 'Hey! You need a last name!', 'meta': 'something', }, { 'status': '400', 'source': { 'pointer': '/data/attributes/email', }, 'detail': 'Enter a valid email address.', }, ] } response = self.client.post('/identities', { 'email': 'bar', 'last_name': 'alajflajaljalajlfjafljalj'}) content_dump = redump_json(response.content) expected_dump = dump_json(expected) assert expected_dump == content_dump
def test_default_validation_exceptions(self): """ Default validation exceptions should conform to json api spec """ expected = { 'errors': [{ 'status': '400', 'source': { 'pointer': '/data/attributes/email', }, 'detail': 'Enter a valid email address.', }, { 'status': '400', 'source': { 'pointer': '/data/attributes/first-name', }, 'detail': 'There\'s a problem with first name', }] } response = self.client.post('/identities', { 'email': 'bar', 'first_name': 'alajflajaljalajlfjafljalj' }) content_dump = redump_json(response.content) expected_dump = dump_json(expected) assert expected_dump == content_dump
def test_custom_validation_exceptions(self): """ Exceptions should be able to be formatted manually """ expected = { 'errors': [ { 'id': 'armageddon101', 'detail': 'Hey! You need a last name!', 'meta': 'something', }, { 'status': '400', 'source': { 'pointer': '/data/attributes/email', }, 'detail': 'Enter a valid email address.', }, ] } response = self.client.post('/identities', { 'email': 'bar', 'last_name': 'alajflajaljalajlfjafljalj' }) content_dump = redump_json(response.content) expected_dump = dump_json(expected) assert expected_dump == content_dump
def test_model_serializer_with_implicit_fields(self, comment, client): expected = { "data": { "type": "comments", "id": str(comment.pk), "attributes": { "body": comment.body }, "relationships": { "entry": { "data": { "type": "entries", "id": str(comment.entry.pk) } }, "author": { "data": { "type": "authors", "id": str(comment.author.pk) } }, } } } response = client.get(reverse("comment-detail", kwargs={'pk': comment.pk})) assert response.status_code == 200 actual = redump_json(response.content) expected_json = dump_json(expected) assert actual == expected_json
def test_top_level_meta_for_list_view(blog, client): expected = { "data": [{ "type": "blogs", "id": "1", "attributes": { "name": blog.name }, "links": { "self": 'http://testserver/blogs/1' }, "meta": { "copyright": datetime.now().year }, }], 'links': { 'first': 'http://testserver/blogs?page=1', 'last': 'http://testserver/blogs?page=1', 'next': None, 'prev': None }, 'meta': { 'pagination': {'count': 1, 'page': 1, 'pages': 1}, 'apiDocs': '/docs/api/blogs' } } response = client.get(reverse("blog-list")) content_dump = redump_json(response.content) expected_dump = dump_json(expected) assert content_dump == expected_dump
def test_patch_allow_field_type(author, author_type_factory, client): """ Verify that type field may be updated. """ author_type = author_type_factory() url = reverse('author-detail', args=[author.id]) data = { 'data': { 'id': author.id, 'type': 'authors', 'relationships': { 'data': { 'id': author_type.id, 'type': 'author-type' } } } } response = client.patch(url, content_type='application/vnd.api+json', data=dump_json(data)) assert response.status_code == 200
def test_model_resource_name_create(self, client): models.Comment.__bases__ += (_PatchedModel, ) models.Entry.__bases__ += (_PatchedModel, ) response = client.post(reverse("comment-list"), dump_json(self.create_data), content_type='application/vnd.api+json') assert response.status_code == status.HTTP_201_CREATED
def test_pagination_with_single_entry(single_entry, client): expected = { "data": [ { "type": "posts", "id": "1", "attributes": { "headline": single_entry.headline, "bodyText": single_entry.body_text, "pubDate": None, "modDate": None }, "meta": { "bodyFormat": "text" }, "relationships": { "blog": { "data": {"type": "blogs", "id": "1"} }, "authors": { "meta": {"count": 1}, "data": [{"type": "authors", "id": "1"}] }, "comments": { "meta": {"count": 1}, "data": [{"type": "comments", "id": "1"}] }, "suggested": { "data": [] } } }], "links": { "first": "http://testserver/entries?page=1", "last": "http://testserver/entries?page=1", "next": None, "prev": None, }, "meta": { "pagination": { "page": 1, "pages": 1, "count": 1 } } } response = client.get(reverse("entry-list")) content_dump = redump_json(response.content) expected_dump = dump_json(expected) assert content_dump == expected_dump
def test_page_range_in_list_result(self): """ Ensure that the range of a page can be changed from the client, tests pluralization as two objects means it converts ``user`` to ``users``. """ response = self.client.get(self.list_url, {'page_size': 2}) self.assertEqual(response.status_code, 200) users = get_user_model().objects.all() expected = { 'data': [ { 'type': 'users', 'id': encoding.force_text(users[0].pk), 'attributes': { 'first-name': users[0].first_name, 'last-name': users[0].last_name, 'email': users[0].email }, }, { 'type': 'users', 'id': encoding.force_text(users[1].pk), 'attributes': { 'first-name': users[1].first_name, 'last-name': users[1].last_name, 'email': users[1].email }, } ], 'links': { 'first': 'http://testserver/identities?page=1&page_size=2', 'last': 'http://testserver/identities?page=1&page_size=2', 'next': None, 'prev': None }, 'meta': { 'pagination': { 'page': 1, 'pages': 1, 'count': 2 } } } content_dump = redump_json(response.content) expected_dump = dump_json(expected) assert expected_dump == content_dump
def test_serializer_resource_name_create(self, client, monkeypatch): monkeypatch.setattr(serializers.CommentSerializer.Meta, 'resource_name', 'renamed_comments', False) monkeypatch.setattr(serializers.EntrySerializer.Meta, 'resource_name', 'renamed_entries', False) create_data = deepcopy(self.create_data) create_data['data']['type'] = 'renamed_comments' create_data['data']['relationships']['entry']['data'][ 'type'] = 'renamed_entries' response = client.post(reverse("comment-list"), dump_json(create_data), content_type='application/vnd.api+json') assert response.status_code == status.HTTP_201_CREATED
def test_patch_requires_id(self): """ Verify that 'id' is required to be passed in an update request. """ data = { 'data': { 'type': 'users', 'attributes': { 'first-name': 'DifferentName' } } } response = self.client.patch(self.detail_url, content_type='application/vnd.api+json', data=dump_json(data)) self.assertEqual(response.status_code, 400)
def test_default_rest_framework_behavior(self): """ This is more of an example really, showing default behavior """ url = reverse('user-default', kwargs={'pk': self.miles.pk}) response = self.client.get(url) self.assertEqual(200, response.status_code) expected = { 'id': 2, 'first_name': 'Miles', 'last_name': 'Davis', 'email': '*****@*****.**' } content_dump = redump_json(response.content) expected_dump = dump_json(expected) assert expected_dump == content_dump
def test_generic_validation_error(self): """ Check error formatting """ response = self.client.get(self.url) self.assertEqual(response.status_code, 400) expected = { 'errors': [{ 'status': '400', 'source': { 'pointer': '/data' }, 'detail': 'Oh nohs!' }] } content_dump = redump_json(response.content) expected_dump = dump_json(expected) assert expected_dump == content_dump
def test_key_in_list_result(self): """ Ensure the result has a 'user' key since that is the name of the model """ response = self.client.get(self.list_url) self.assertEqual(response.status_code, 200) user = get_user_model().objects.all()[0] expected = { 'data': [ { 'type': 'users', 'id': encoding.force_text(user.pk), 'attributes': { 'first-name': user.first_name, 'last-name': user.last_name, 'email': user.email }, } ], 'links': { 'first': 'http://testserver/identities?page=1', 'last': 'http://testserver/identities?page=2', 'next': 'http://testserver/identities?page=2', 'prev': None }, 'meta': { 'pagination': { 'page': 1, 'pages': 2, 'count': 2 } } } content_dump = redump_json(response.content) expected_dump = dump_json(expected) assert expected_dump == content_dump
def test_page_two_in_list_result(self): """ Ensure that the second page is reachable and is the correct data. """ response = self.client.get(self.list_url, {'page': 2}) self.assertEqual(response.status_code, 200) user = get_user_model().objects.all()[1] expected = { 'data': [ { 'type': 'users', 'id': encoding.force_text(user.pk), 'attributes': { 'first-name': user.first_name, 'last-name': user.last_name, 'email': user.email }, } ], 'links': { 'first': 'http://testserver/identities?page=1', 'last': 'http://testserver/identities?page=2', 'next': None, 'prev': 'http://testserver/identities?page=1', }, 'meta': { 'pagination': { 'page': 2, 'pages': 2, 'count': 2 } } } content_dump = redump_json(response.content) expected_dump = dump_json(expected) assert expected_dump == content_dump
def test_top_level_meta(blog, client): expected = { "data": { "type": "blogs", "id": "1", "attributes": { "name": blog.name }, "meta": { "copyright": datetime.now().year }, }, "meta": { "apiDocs": "/docs/api/blogs" }, } response = client.get(reverse("blog-detail", kwargs={'pk': blog.pk})) content_dump = redump_json(response.content) expected_dump = dump_json(expected) assert content_dump == expected_dump
def test_key_in_detail_result(self): """ Ensure the result has a 'user' key. """ response = self.client.get(self.detail_url) self.assertEqual(response.status_code, 200) expected = { 'data': { 'type': 'users', 'id': encoding.force_text(self.miles.pk), 'attributes': { 'first-name': self.miles.first_name, 'last-name': self.miles.last_name, 'email': self.miles.email }, } } content_dump = redump_json(response.content) expected_dump = dump_json(expected) assert expected_dump == content_dump
def test_multiple_entries_no_pagination(multiple_entries, rf): expected = { "data": [ { "type": "posts", "id": "1", "attributes": { "headline": multiple_entries[0].headline, "bodyText": multiple_entries[0].body_text, "pubDate": None, "modDate": None }, "meta": { "bodyFormat": "text" }, "relationships": { "blog": { "data": { "type": "blogs", "id": "1" } }, "authors": { "meta": { "count": 1 }, "data": [{ "type": "authors", "id": "1" }] }, "comments": { "meta": { "count": 1 }, "data": [{ "type": "comments", "id": "1" }] }, "suggested": { "data": [{ "type": "entries", "id": "2" }] } } }, { "type": "posts", "id": "2", "attributes": { "headline": multiple_entries[1].headline, "bodyText": multiple_entries[1].body_text, "pubDate": None, "modDate": None }, "meta": { "bodyFormat": "text" }, "relationships": { "blog": { "data": { "type": "blogs", "id": "2" } }, "authors": { "meta": { "count": 1 }, "data": [{ "type": "authors", "id": "2" }] }, "comments": { "meta": { "count": 1 }, "data": [{ "type": "comments", "id": "2" }] }, "suggested": { "data": [{ "type": "entries", "id": "1" }] } } }, ] } class NoPagination(PageNumberPagination): page_size = None class NonPaginatedEntryViewSet(EntryViewSet): pagination_class = NoPagination request = rf.get(reverse("entry-list")) view = NonPaginatedEntryViewSet.as_view({'get': 'list'}) response = view(request) response.render() content_dump = redump_json(response.content) expected_dump = dump_json(expected) assert content_dump == expected_dump
def test_pagination_with_single_entry(single_entry, client): expected = { "data": [{ "type": "posts", "id": "1", "attributes": { "headline": single_entry.headline, "bodyText": single_entry.body_text, "pubDate": None, "modDate": None }, "meta": { "bodyFormat": "text" }, "relationships": { "blog": { "data": { "type": "blogs", "id": "1" } }, "authors": { "meta": { "count": 1 }, "data": [{ "type": "authors", "id": "1" }] }, "comments": { "meta": { "count": 1 }, "data": [{ "type": "comments", "id": "1" }] } } }], "links": { "first": "http://testserver/entries?page=1", "last": "http://testserver/entries?page=1", "next": None, "prev": None, }, "meta": { "pagination": { "page": 1, "pages": 1, "count": 1 } } } response = client.get(reverse("entry-list")) content_dump = redump_json(response.content) expected_dump = dump_json(expected) assert content_dump == expected_dump
def test_multiple_entries_no_pagination(multiple_entries, rf): expected = { "data": [ { "type": "posts", "id": "1", "attributes": { "headline": multiple_entries[0].headline, "bodyText": multiple_entries[0].body_text, "pubDate": None, "modDate": None }, "meta": { "bodyFormat": "text" }, "relationships": { "blog": { "data": {"type": "blogs", "id": "1"} }, "authors": { "meta": {"count": 1}, "data": [{"type": "authors", "id": "1"}] }, "comments": { "meta": {"count": 1}, "data": [{"type": "comments", "id": "1"}] }, "suggested": { "data": [{"type": "entries", "id": "2"}] } } }, { "type": "posts", "id": "2", "attributes": { "headline": multiple_entries[1].headline, "bodyText": multiple_entries[1].body_text, "pubDate": None, "modDate": None }, "meta": { "bodyFormat": "text" }, "relationships": { "blog": { "data": {"type": "blogs", "id": "2"} }, "authors": { "meta": {"count": 1}, "data": [{"type": "authors", "id": "2"}] }, "comments": { "meta": {"count": 1}, "data": [{"type": "comments", "id": "2"}] }, "suggested": { "data": [{"type": "entries", "id": "1"}] } } }, ] } class NoPagination(PageNumberPagination): page_size = None class NonPaginatedEntryViewSet(EntryViewSet): pagination_class = NoPagination request = rf.get( reverse("entry-list")) view = NonPaginatedEntryViewSet.as_view({'get': 'list'}) response = view(request) response.render() content_dump = redump_json(response.content) expected_dump = dump_json(expected) assert content_dump == expected_dump