I’m trying to create a unit test for a POST request. If I don’t allow the request to follow, I get a 302 with the URL pointing to the same URL I’m trying to post to. If I do allow the request to follow it is redirected to the view I’m trying to hit but loses all data and becomes a GET request.
Here is my unit test:
import uuid
from django.contrib.auth import get_user
from django.contrib.auth.models import User
from django.urls import reverse
from rest_framework.test import APITestCase, force_authenticate
class MeetingChatAPITest(APITestCase):
USERNAME = "test_username"
EMAIL = "a@b.com"
PASSWORD = "password"
def setUp(self):
self.user = User.objects.get(username=self.USERNAME)
def test_meeting_chat_with_text_input(self):
url = "/meeting-chat/"
request_payload = {
"foo": "bar"
}
self.asertTrue(self.client.login(username=self.USERNAME, password=self.PASSWORD))
response = self.client.post(url, request_payload, format="json", follow=True)
self.assertEqual(response.status_code, 200)
@login_required
@require_POST
@csrf_exempt
def chat_meeting(request):
try:
payload = json.loads(request.body.decode('utf-8'))
except json.JSONDecodeError:
return JsonResponse({'error': 'Invalid JSON'}, status=400) # This line is only hit if I do follow=True on the request and remove the @require_POST decoration
Check your URL formatting & APPEND_SLASH
If the URL pattern uses a trailing slash (path('meeting-chat/', ...)), the test must post to /meeting-chat/
Conversely, if there’s no trailing slash, make your test use /meeting-chat and you should set APPEND_SLASH = False to avoid Django auto-redirecting POSTs
By default, APPEND_SLASH = True — a POST without the slash triggers a redirect with status 301/302, stripping the body and changing to a GET
I don’t think so, unless I’m misunderstanding what you mean. The request in the test is being sent to url = "/meeting-chat/". I did try all 4 combinations of slashes or no slashes at either end, all of which result in the same response of 302.
For brevity and confidentiality, I did not include the full view, but I doubt the issue is within the view as with a debugger I can confirm that no line is executed (it is only executed if I remove the require_POST decorator and allow follow=True). The full view always returns a JsonResponse as the one shown, or a one with a 200 status code in the case of the happy path.
You’re using login_required . The remaining possibility is that the request is being made with an anonymous session, which is causing a redirect to the login page. Try either removing login_required or making the request with a logged-in session.
I’m logging in just above the request line, using: self.asertTrue(self.client.login(username=self.USERNAME, password=self.PASSWORD))
I have also tried to remove the login-required decorator, to no success. And the location being redirected to is the original url itself (/meeting_chat/), not the login page.
I apologize if my need for confidentiality makes it seem like I’m not cooperating. It is not my intention. While I can’t disclose the full code of the view, I can confirm that the problem persists when the code is reduced to what has been shown here before:
Additionally, the print at the top of the view is not printed (and breakpoints placed by the debugger are not caught), so I don’t believe the code of the view is the cause.
Thank you again for your time in your responses.
I have since also tested the same view function but replacing @login_required with @login_not_required and the same redirect happens, so the problem is likely not due to login.