Home > front end >  AssertionError: 302 != 200 : Couldn't retrieve redirection page '/api/v2/app/nextdialog�
AssertionError: 302 != 200 : Couldn't retrieve redirection page '/api/v2/app/nextdialog�

Time:04-19

AssertionError: 302 != 200 : Couldn't retrieve redirection page '/api/v2/app/nextdialog': response code was 302 (expected 200)

In Django is it possible to have three views where each one redirects to the next. View 1 redirects to view 2 and view 2 redirects to view 3?

Views.py:

class ConversationLayerView(generics.GenericAPIView):
    permission_classes = (permissions.IsAuthenticated,)

    def post(self, request, *args, **kwargs):
        body = request.data
        cardType = body["cardType"]
        if cardType == "CHOICE":
            serializer = appChoiceTypeSerializer(body)
        elif cardType == "TEXT":
            serializer = appTextTypeSerializer(body)
        elif cardType == "INPUT":
            serializer = appInputTypeSerializer(body)
        else:
            serializer = StartAssessmentSerializer(body)
        validated_body = serializer.validate_value(body)
        url = get_endpoint(validated_body)
        reverse_url = encodeurl(body, url)
        return HttpResponseRedirect(reverse_url)
        

class NextDialog(generics.GenericAPIView):
    permission_classes = (permissions.AllowAny,)

    def get(self, request, *args, **kwargs):
        result = request.GET
        data = result.dict()
        contact_uuid = data["contact_uuid"]
        step = data["step"]
        value = data["value"]
        description = data["description"]
        title = data["title"]

        if data["cardType"] == "CHOICE":
            optionId = int(value) - 1
        else:
            optionId = data["optionId"]
        path = get_path(data)
        assessment_id = path.split("/")[-3]
        request = build_rp_request(data)
        app_response = post_to_app(request, path)
        if data["cardType"] != "TEXT":
            if data["cardType"] == "INPUT":
                optionId = None
            store_url_entry = appAssessments(
                contact_id=contact_uuid,
                assessment_id=assessment_id,
                title=title,
                description=description,
                step=step,
                user_input=value,
                optionId=optionId,
            )
            store_url_entry.save()
        pdf = pdf_ready(app_response)
        if pdf:
            response = pdf_endpoint(app_response)
            return HttpResponseRedirect(response)
        else:
            message = format_message(app_response)
            return Response(message, status=status.HTTP_200_OK)
            
            
class Reports(generics.GenericAPIView):
    permission_classes = (permissions.AllowAny,)

    def get(self, request, *args, **kwargs):
        report_id = request.GET.get("report_id")
        response = get_report(report_id)
        return Response(response, status=status.HTTP_200_OK)                    
        
    

Utils.py

def get_endpoint(payload):
   value = payload["value"]
   if value != "":
       if value == "back":
           url = reverse("app-previous-dialog")
       elif value == "abort":
           url = reverse("app-abort")
       else:
           url = reverse("app-next-dialog")
   elif value == "":
       url = reverse("app-start-assessment")
   return url

def encodeurl(payload, url):
   qs = "?"   urlencode(payload, safe="")
   reverse_url = url   qs
   return reverse_url

Code explanation: The app receives a json payload in the ConversationLayerView. It calls the endpoint method to know which endpoint to redirect to based on the 'value' key in the payload is set to.

The request looks something like this:

{
    "contact_uuid": "67460e74-02e3-11e8-b443-00163e990bdb",
    "choices": null,
    "value": "Charles",
    "cardType": "INPUT",
    "step": null,
    "optionId": null,
    "path": "",
    "title": "",
    "description": "What's your name",
    "message": ""
}

Since "value" is "Charles", the view redirects to "app-next-dialog" in the NextDialog view. In this view a POST request is done to an external application and a json response is received. If the response has a PDF key this view redirects to the third view. THis happens here:

if pdf:
    response = pdf_endpoint(app_response)
    return HttpResponseRedirect(response)
else:
    message = format_message(app_response)
    return Response(message, status=status.HTTP_200_OK)

If the key is present then redirect to "response" whose output is "/api/v2/app/reports?report_id=/reports/17340f51604cb35bd2c6b7b9b16f3aec" otherwise do not redirect but return a 200.

Error:

AssertionError: 302 != 200 : Couldn't retrieve redirection page '/api/v2/app/nextdialog': response code was 302 (expected 200)

Url.py

path(
    "api/v2/app/assessments",
    views.PresentationLayerView.as_view(),
    name="app-assessments",
),
path("api/v2/app/nextdialog", views.NextDialog.as_view(), name="app-next-dialog"),
path("api/v2/app/reports", views.Reports.as_view(), name="app-reports"),

test_views.py:

class appAssessmentReport(APITestCase):
    data = {
        "contact_uuid": "67460e74-02e3-11e8-b443-00163e990bdd",
        "choices": None,
        "message": (
            "How old are you?\n\nReply *back* to go to "
            "the previous question or *abort* to "
            "end the assessment"
        ),
        "explanations": "",
        "step": 39,
        "value": "27",
        "optionId": None,
        "path": "/assessments/f9d4be32-78fa-48e0-b9a3-e12e305e73ce/dialog/next",
        "cardType": "INPUT",
        "title": "Patient Information",
        "description": "How old are you?",
    }

    start_url = reverse("app-assessments")
    next_dialog_url = reverse("app-next-dialog")
    pdf_url = reverse("app-reports")
    
    destination_url = (
        "/api/v2/app/nextdialog?contact_uuid="
        "67460e74-02e3-11e8-b443-00163e990bdd&"
        "choices=None&message=How old are you?"
        "

Reply *back* to go to the "
        "previous question or *abort* to end"
        " the assessment&explanations=&step="
        "39&value=27&optionId=None&path=/"
        "assessments/f9d4be32-78fa-48e0-b9a3"
        "-e12e305e73ce/dialog/next&cardType"
        "=INPUT&title=Patient Information&"
        "description=How old are you?"
    )
    
    @patch("app.views.pdf_ready")
    @patch("app.views.post_to_app")
    def test_assessment_report(self, mock_post_to_app, mock_pdf_ready):
        mock_post_to_app.return_value = {
            "cardType": "CHOICE",
            "step": 40,
            "title": {"en-US": "YOUR REPORT"},
            "description": {"en-US": ""},
            "options": [
                {"optionId": 0, "text": {"en-US": "Option 1"}},
                {"optionId": 1, "text": {"en-US": "Option 2"}},
                {"optionId": 2, "text": {"en-US": "Option 3"}},
            ],
            "_links": {
                "self": {
                    "method": "GET",
                    "href": "/assessments/898d915e-229f-48f2-9b98-cfd760ba8965",
                },
                "report": {
                    "method": "GET",
                    "href": "/reports/17340f51604cb35bd2c6b7b9b16f3aec",
                },
            },
        }
        mock_pdf_ready.return_value = utils.pdf_ready(mock_post_to_app.return_value)
        user = get_user_model().objects.create_user("test")
        self.client.force_authenticate(user)
        response = self.client.post(self.start_url, self.data, format="json")
        print(response)
        self.assertRedirects(response, self.destination_url)

So far this isn't working. In summary I'm just trying to start in view 1, redirect to view 2 and redirect to view 3 from view 2. Is this possible in Django? Thanks.

CodePudding user response:

The problem is with your tests, rather than with the view logic - it's perfectly possible to have a chain of redirects.

assertRedirects checks the status of the response, and by default requires it to be a HTTP 200 response. Because you have a chain of redirects, the response is 302 (another redirect) instead of 200, which is why the test fails with the error "response code was 302 (expected 200)".

You need to modify the target_status_code argument to tell assertRedirects that you are expecting the response to have a 302 status code:

self.assertRedirects(response, self.destination_url, target_status_code=302)
  • Related