def test_update_to_many_link(client): models.Person.objects.create(name="test") author = models.Person.objects.create(name="author") post = models.Post.objects.create(title="The Post", author=author) comment1 = models.Comment.objects.create(body="Comment 1", post=post) comment2 = models.Comment.objects.create(body="Comment 2", post=post) data = dump_json( { "people": { "name": "test", "links": {"favorite_post": None, "liked_comments": [str(comment1.pk), str(comment2.pk)]}, } } ) results = { "people": { "id": "1", "href": "http://testserver/people/1/", "name": "test", "links": {"favorite_post": None, "liked_comments": [str(comment1.pk), str(comment2.pk)]}, }, "links": { "people.favorite_post": {"href": "http://testserver/posts/{people.favorite_post}/", "type": "posts"}, "people.liked_comments": { "href": "http://testserver/comments/{people.liked_comments}/", "type": "comments", }, }, } response = client.put(reverse("people-full-detail", args=[1]), data, content_type="application/vnd.api+json") assert response.content == dump_json(results)
def test_django_non_field_validation_error(rf, monkeypatch): '''Django uses __all__ as the key for non-field errors Constant is django.core.exceptions.NON_FIELD_ERRORS ''' def clean(self): raise ValidationError("I'm not taking any new people today") monkeypatch.setattr(models.Person, 'clean', clean) data = dump_json({"people": {"name": "Jason Api"}}) request = rf.post(reverse("person-list"), data=data, content_type="application/vnd.api+json") view = PersonViewSet.as_view({'post': 'create'}) response = view(request) response.render() assert response.status_code == 400, response.content assert not models.Person.objects.exists() results = { "errors": [{ "status": "400", "path": "/-", "detail": "I'm not taking any new people today" }] } assert response.content == dump_json(results)
def test_django_non_field_validation_error(rf, monkeypatch): '''Django uses __all__ as the key for non-field errors Constant is django.core.exceptions.NON_FIELD_ERRORS ''' def clean(self): raise ValidationError("I'm not taking any new people today") monkeypatch.setattr(models.Person, 'clean', clean) data = dump_json({"people": {"name": "Jason Api"}}) request = rf.post( reverse("person-list"), data=data, content_type="application/vnd.api+json") view = PersonViewSet.as_view({'post': 'create'}) response = view(request) response.render() assert response.status_code == 400, response.content assert not models.Person.objects.exists() results = { "errors": [{ "status": "400", "path": "/-", "detail": "I'm not taking any new people today" }] } assert response.content == dump_json(results)
def test_update_attribute(client): models.Person.objects.create(name="test") data = dump_json({ "people": { "name": "new test", }, }) results = { "people": { "id": "1", "href": "http://testserver/people/1/", "name": "new test", "links": { "favorite_post": None, "liked_comments": [], } }, "links": { "people.favorite_post": { "href": "http://testserver/posts/{people.favorite_post}/", "type": "posts" }, "people.liked_comments": { "href": "http://testserver/comments/{people.liked_comments}/", "type": "comments" }, } } response = client.patch(reverse("people-full-detail", args=[1]), data, content_type="application/vnd.api+json") assert response.content == dump_json(results)
def test_update_attribute(client): models.Person.objects.create(name="test") data = dump_json({ "people": { "name": "new test", }, }) results = { "people": { "id": "1", "href": "http://testserver/people/1/", "name": "new test", "links": { "favorite_post": None, "liked_comments": [], } }, "links": { "people.favorite_post": { "href": "http://testserver/posts/{people.favorite_post}/", "type": "posts" }, "people.liked_comments": { "href": "http://testserver/comments/{people.liked_comments}/", "type": "comments" }, } } response = client.put( reverse("people-full-detail", args=[1]), data, content_type="application/vnd.api+json") assert response.content == dump_json(results)
def test_invalid_reverse_relation(client): author = models.Person.objects.create(name="The Author") assert not models.Comment.objects.exists() data = dump_json({ "posts": { "title": "This is the title", "author": "http://testserver/people/%d/" % author.pk, "comments": ["http://testserver/comments/1/"] } }) response = client.post( reverse("post-list"), data=data, content_type="application/vnd.api+json") assert response.status_code == 400, response.content assert response['content-type'] == 'application/vnd.api+json' results = { "errors": [{ "status": "400", "path": "/comments", "detail": "Invalid hyperlink - object does not exist." }] } assert response.content == dump_json(results)
def test_drf_non_field_validation_error(rf): '''DRF uses 'non_field_errors' as the key for non-field errors''' class LazyPersonSerializer(PersonSerializer): def validate(self, attr): raise ValidationError("Feeling lazy. Try again later.") class LazyPersonViewSet(PersonViewSet): serializer_class = LazyPersonSerializer data = dump_json({"people": {"name": "Jason Api"}}) request = rf.post(reverse("person-list"), data=data, content_type="application/vnd.api+json") view = LazyPersonViewSet.as_view({'post': 'create'}) response = view(request) response.render() assert response.status_code == 400, response.content assert not models.Person.objects.exists() results = { "errors": [{ "status": "400", "path": "/-", "detail": "Feeling lazy. Try again later." }] } assert response.content == dump_json(results)
def test_invalid_reverse_relation(client): author = models.Person.objects.create(name="The Author") assert not models.Comment.objects.exists() data = dump_json({ "posts": { "title": "This is the title", "author": "http://testserver/people/%d/" % author.pk, "comments": ["http://testserver/comments/1/"] } }) response = client.post(reverse("post-list"), data=data, content_type="application/vnd.api+json") assert response.status_code == 400, response.content assert response['content-type'] == 'application/vnd.api+json' results = { "errors": [{ "status": "400", "path": "/comments", "detail": does_not_exist }] } assert response.content == dump_json(results)
def test_drf_non_field_validation_error(rf): '''DRF uses 'non_field_errors' as the key for non-field errors''' class LazyPersonSerializer(PersonSerializer): def validate(self, attr): raise ValidationError("Feeling lazy. Try again later.") class LazyPersonViewSet(PersonViewSet): serializer_class = LazyPersonSerializer data = dump_json({"people": {"name": "Jason Api"}}) request = rf.post( reverse("person-list"), data=data, content_type="application/vnd.api+json") view = LazyPersonViewSet.as_view({'post': 'create'}) response = view(request) response.render() assert response.status_code == 400, response.content assert not models.Person.objects.exists() results = { "errors": [{ "status": "400", "path": "/-", "detail": "Feeling lazy. Try again later." }] } assert response.content == dump_json(results)
def test_invalid_forward_relation(client): assert not models.Person.objects.exists() data = dump_json({"posts": {"title": "This is the title", "author": "http://testserver/people/1/", "comments": []}}) response = client.post(reverse("post-list"), data=data, content_type="application/vnd.api+json") assert response.status_code == 400, response.content assert response["content-type"] == "application/vnd.api+json" assert not models.Post.objects.exists() results = {"errors": [{"status": "400", "path": "/author", "detail": does_not_exist}]} assert response.content == dump_json(results)
def test_required_field_omitted(client): data = {} data_json_api = dump_json({"people": data}) response = client.post(reverse("person-list"), data=data_json_api, content_type="application/vnd.api+json") assert response.status_code == 400, response.content assert not models.Person.objects.exists() result_data = {"name": ["This field is required."]} assert response.data == result_data results = {"errors": [{"path": "/name", "detail": "This field is required.", "status": "400"}]} assert response.content == dump_json(results)
def test_multiple(client): test_data = dump_json({ "people": [ { "name": "first", }, { "name": "second", }, ], }) output_data = [ { "name": "first", }, { "name": "second", }, ] response = client.generic("echo", reverse("person-list"), data=test_data, content_type="application/vnd.api+json", ) assert response.data == output_data
def test_multiple_links(client): author = models.Person.objects.create(name="test") post = models.Post.objects.create(author=author, title="Test post title") models.Comment.objects.create(post=post, body="Test comment one.") models.Comment.objects.create(post=post, body="Test comment two.") results = { "links": { "posts.author": { "href": "http://testserver/people/{posts.author}/", "type": "people", }, "posts.comments": { "href": "http://testserver/comments/{posts.comments}/", "type": "comments", } }, "posts": [ { "id": "1", "title": "Test post title", "href": "http://testserver/posts/1/", "links": { "author": "1", "comments": ["1", "2"] } }, ], } response = client.get(reverse("post-list")) assert response.content == dump_json(results)
def test_auth_required(rf): class RestrictedPersonViewSet(PersonViewSet): permission_classes = [IsAuthenticated] data = dump_json({"people": {"name": "Jason Api"}}) request = rf.post(reverse("person-list"), data=data, content_type="application/vnd.api+json") view = RestrictedPersonViewSet.as_view({"post": "create"}) response = view(request) response.render() assert response.status_code == 403, response.content assert not models.Person.objects.exists() results = {"errors": [{"status": "403", "title": "Authentication credentials were not provided."}]} assert response.content == dump_json(results)
def test_single_links(client): author = models.Person.objects.create(name="test") post = models.Post.objects.create(author=author, title="Test post title.") models.Comment.objects.create(post=post, body="Some text for testing.") results = { "links": { "comments.post": { "href": "http://testserver/posts/{comments.post}/", "type": "posts", }, }, "comments": [ { "id": "1", "body": "Some text for testing.", "href": "http://testserver/comments/1/", "links": { "post": "1", } }, ], } response = client.get(reverse("comment-list")) assert response.content == dump_json(results)
def test_object_with_optional_links(client): models.Person.objects.create(name="test") results = { "people": { "id": "1", "href": "http://testserver/people/1/", "name": "test", "links": { "favorite_post": None, "liked_comments": [], } }, "links": { "people.favorite_post": { "href": "http://testserver/posts/{people.favorite_post}/", "type": "posts" }, "people.liked_comments": { "href": "http://testserver/comments/{people.liked_comments}/", "type": "comments" }, } } response = client.get(reverse("people-full-detail", args=[1])) assert response.content == dump_json(results)
def test_pagination(rf): models.Person.objects.create(name="test") class PaginatedPersonViewSet(PersonViewSet): paginate_by = 10 request = rf.get( reverse("person-list"), content_type="application/vnd.api+json") view = PaginatedPersonViewSet.as_view({'get': 'list'}) response = view(request) response.render() assert response.status_code == 200, response.content results = { "people": [ { "id": "1", "href": "http://testserver/people/1/", "name": "test", }, ], "meta": { "pagination": { "people": { "count": 1, "next": None, "previous": None, } } } } assert response.content == dump_json(results)
def test_empty_list(client): results = { "posts": [], } response = client.get(reverse("post-list")) assert response.content == dump_json(results)
def test_object(client): models.Person.objects.create(name="test") results = {"people": {"id": "1", "href": "http://testserver/people/1/", "name": "test"}} response = client.get(reverse("person-detail", args=[1])) assert response.content == dump_json(results)
def test_update_to_one_pk_link(client): models.Person.objects.create(name="test") author = models.Person.objects.create(name="author") post = models.Post.objects.create(title="The Post", author=author) data = dump_json({"people": {"name": "test", "links": {"favorite_post": str(post.pk), "liked_comments": []}}}) results = { "people": { "id": "1", "href": "http://testserver/people/1/", "name": "test", "links": {"favorite_post": str(post.pk), "liked_comments": []}, }, "links": {"people.favorite_post": {"type": "posts"}, "people.liked_comments": {"type": "comments"}}, } response = client.put(reverse("pk-people-full-detail", args=[1]), data, content_type="application/vnd.api+json") assert response.content == dump_json(results)
def test_update_to_many_link(client): models.Person.objects.create(name="test") author = models.Person.objects.create(name="author") post = models.Post.objects.create(title="The Post", author=author) comment1 = models.Comment.objects.create(body="Comment 1", post=post) comment2 = models.Comment.objects.create(body="Comment 2", post=post) data = dump_json({ "people": { "name": "test", "links": { "favorite_post": None, "liked_comments": [str(comment1.pk), str(comment2.pk)], } }, }) results = { "people": { "id": "1", "href": "http://testserver/people/1/", "name": "test", "links": { "favorite_post": None, "liked_comments": [str(comment1.pk), str(comment2.pk)], } }, "links": { "people.favorite_post": { "href": "http://testserver/posts/{people.favorite_post}/", "type": "posts" }, "people.liked_comments": { "href": "http://testserver/comments/{people.liked_comments}/", "type": "comments" }, } } response = client.put(reverse("people-full-detail", args=[1]), data, content_type="application/vnd.api+json") assert response.content == dump_json(results)
def test_options(client): # DRF 3.x representation results = { "meta": { "actions": { "POST": { "author": { "choices": [], "label": "Author", "read_only": False, "required": True, "type": "field" }, "comments": { "choices": [], "label": "Comments", "read_only": False, "required": True, "type": "field" }, "id": { "label": "ID", "read_only": True, "required": False, "type": "integer" }, "title": { "label": "Title", "read_only": False, "required": True, "type": "string" }, "url": { "label": "Url", "read_only": True, "required": False, "type": "field" } } }, "description": "", "name": "Post List", "parses": ["application/vnd.api+json"], "renders": ["application/vnd.api+json"], } } # DRF 2.x representation - fields labels are lowercase, no choices ps = PostSerializer() if hasattr(ps, 'metadata'): results['meta']['actions']['POST'] = ps.metadata() response = client.options(reverse("post-list")) assert response.status_code == 200 assert response.content == dump_json(results)
def test_create_post_success(client): author = models.Person.objects.create(name="The Author") data = dump_json({ "posts": { "title": "This is the title", "links": { "author": author.pk, "comments": [], }, } }) response = client.post( reverse("post-list"), data=data, content_type="application/vnd.api+json") assert response.status_code == 201 assert response['content-type'] == 'application/vnd.api+json' post = models.Post.objects.get() results = { "posts": { "id": str(post.pk), "href": "http://testserver/posts/%s/" % post.pk, "title": "This is the title", "links": { "author": str(author.pk), "comments": [] } }, "links": { "posts.author": { "href": "http://testserver/people/{posts.author}/", "type": "people" }, "posts.comments": { "href": "http://testserver/comments/{posts.comments}/", "type": "comments" } }, } assert response.content == dump_json(results)
def test_update_to_one_pk_link(client): models.Person.objects.create(name="test") author = models.Person.objects.create(name="author") post = models.Post.objects.create(title="The Post", author=author) data = dump_json({ "people": { "name": "test", "links": { "favorite_post": str(post.pk), "liked_comments": [] } }, }) results = { "people": { "id": "1", "href": "http://testserver/people/1/", "name": "test", "links": { "favorite_post": str(post.pk), "liked_comments": [] } }, "links": { "people.favorite_post": { "type": "posts" }, "people.liked_comments": { "type": "comments" } } } response = client.put(reverse("pk-people-full-detail", args=[1]), data, content_type="application/vnd.api+json") assert response.content == dump_json(results)
def test_options(client): results = { "meta": { "actions": { "POST": { "author": { "choices": [], "label": "Author", "read_only": False, "required": True, "type": "field" }, "comments": { "choices": [], "label": "Comments", "read_only": False, "required": True, "type": "field" }, "id": { "label": "ID", "read_only": True, "required": False, "type": "integer" }, "title": { "label": "Title", "read_only": False, "required": True, "type": "string" }, "url": { "label": "Url", "read_only": True, "required": False, "type": "field" } } }, "description": "", "name": "Post List", "parses": ["application/vnd.api+json"], "renders": ["application/vnd.api+json"], } } response = client.options(reverse("post-list")) assert response.status_code == 200 assert response.content == dump_json(results)
def test_auth_required(rf): class RestrictedPersonViewSet(PersonViewSet): permission_classes = [IsAuthenticated] data = dump_json({"people": {"name": "Jason Api"}}) request = rf.post(reverse("person-list"), data=data, content_type="application/vnd.api+json") view = RestrictedPersonViewSet.as_view({'post': 'create'}) response = view(request) response.render() assert response.status_code == 403, response.content assert not models.Person.objects.exists() results = { "errors": [{ "status": "403", "title": "Authentication credentials were not provided." }] } assert response.content == dump_json(results)
def test_object(client): models.Person.objects.create(name="test") results = { "people": { "id": "1", "href": "http://testserver/people/1/", "name": "test", } } response = client.get(reverse("person-detail", args=[1])) assert response.content == dump_json(results)
def test_create_person_success(client): data = dump_json({ "people": { "name": "Jason Api" } }) results = { "people": { "id": "1", "href": "http://testserver/people/1/", "name": "Jason Api", } } response = client.post( reverse("person-list"), data=data, content_type="application/vnd.api+json") assert response.status_code == 201 assert response.content == dump_json(results) assert response['content-type'] == 'application/vnd.api+json' person = models.Person.objects.get() assert person.name == 'Jason Api'
def test_required_field_omitted(client): data = {} data_json_api = dump_json({"people": data}) response = client.post(reverse("person-list"), data=data_json_api, content_type="application/vnd.api+json") assert response.status_code == 400, response.content assert not models.Person.objects.exists() result_data = {"name": ["This field is required."]} assert response.data == result_data results = { "errors": [{ "path": "/name", "detail": "This field is required.", "status": "400" }] } assert response.content == dump_json(results)
def test_multiple_linked(client): author = models.Person.objects.create(name="test") post = models.Post.objects.create( author=author, title="One amazing test post.") models.Comment.objects.create( post=post, body="This is a test comment.") models.Comment.objects.create( post=post, body="One more comment.") results = { "posts": [ { "id": "1", "href": "http://testserver/posts/1/", "title": "One amazing test post.", "links": { "author": "1", "comments": ["1", "2"], }, }, ], "links": { "posts.author": { "href": "http://testserver/people/{posts.author}/", "type": "people", }, "posts.comments": { "href": "http://testserver/comments/{posts.comments}/", "type": "comments", } }, "linked": { "comments": [ { "id": "1", "href": "http://testserver/comments/1/", "body": "This is a test comment.", }, { "id": "2", "href": "http://testserver/comments/2/", "body": "One more comment.", }, ], }, } response = client.get(reverse("nested-post-list")) assert response.content == dump_json(results)
def test_multiple_linked(client): author = models.Person.objects.create(name="test") post = models.Post.objects.create(author=author, title="One amazing test post.") models.Comment.objects.create(post=post, body="This is a test comment.") models.Comment.objects.create(post=post, body="One more comment.") results = { "posts": [ { "id": "1", "href": "http://testserver/posts/1/", "title": "One amazing test post.", "links": { "author": "1", "comments": ["1", "2"], }, }, ], "links": { "posts.author": { "href": "http://testserver/people/{posts.author}/", "type": "people", }, "posts.comments": { "href": "http://testserver/comments/{posts.comments}/", "type": "comments", } }, "linked": { "comments": [ { "id": "1", "href": "http://testserver/comments/1/", "body": "This is a test comment.", }, { "id": "2", "href": "http://testserver/comments/2/", "body": "One more comment.", }, ], }, } response = client.get(reverse("nested-post-list")) assert response.content == dump_json(results)
def test_basic(client): test_data = dump_json({ "people": { "name": "test", }, }) output_data = { "name": "test", } response = client.generic("echo", reverse("person-list"), data=test_data, content_type="application/vnd.api+json") assert response.data == output_data
def test_single_item_list(client): models.Person.objects.create(name="test") results = { "people": [ { "id": "1", "href": "http://testserver/people/1/", "name": "test", }, ] } response = client.get(reverse("person-list")) assert response.content == dump_json(results)
def test_options(client): results = { "meta": { "actions": { "POST": { "author": { "label": "author", "read_only": False, "required": True, "type": "field" }, "comments": { "read_only": False, "required": True, "type": "field" }, "id": { "label": "ID", "read_only": True, "required": False, "type": "integer" }, "title": { "label": "title", "max_length": 100, "read_only": False, "required": True, "type": "string" }, "url": { "read_only": True, "required": False, "type": "field" } } }, "description": "", "name": "Post List", "parses": ["application/vnd.api+json"], "renders": ["application/vnd.api+json"], } } response = client.options(reverse("post-list")) assert response.status_code == 200 assert response.content == dump_json(results)
def test_bad_json(client): data = "{'people': {'name': 'Jason Api'}}" # Wrong quotes response = client.post(reverse("person-list"), data=data, content_type="application/vnd.api+json") assert response.status_code == 400, response.content assert response['content-type'] == 'application/vnd.api+json' results = { "errors": [{ "status": "400", "detail": ("JSON parse error - Expecting property name enclosed in" " double quotes: line 1 column 2 (char 1)"), }] } assert response.content == dump_json(results)
def test_bad_json(client): data = "{'people': {'name': 'Jason Api'}}" # Wrong quotes response = client.post( reverse("person-list"), data=data, content_type="application/vnd.api+json") assert response.status_code == 400, response.content assert response['content-type'] == 'application/vnd.api+json' results = { "errors": [{ "status": "400", "detail": ( "JSON parse error - Expecting property name enclosed in" " double quotes: line 1 column 2 (char 1)"), }] } assert response.content == dump_json(results)
def test_single_link(client): test_data = dump_json({ "comments": { "body": "This is a test comment.", "links": { "post": "1", }, }, }) output_data = { "body": "This is a test comment.", "post": "http://testserver/posts/1/", } response = client.generic("echo", reverse("comment-list"), data=test_data, content_type="application/vnd.api+json", ) assert response.data == output_data
def test_multiple_link(client): test_data = dump_json({ "posts": { "title": "Test post title", "links": { "comments": ["1", "2"], }, } }) output_data = { "title": "Test post title", "comments": [ "http://testserver/comments/1/", "http://testserver/comments/2/", ], } response = client.generic("echo", reverse("post-list"), data=test_data, content_type="application/vnd.api+json", ) assert response.data == output_data