Django test for 404 erroring because Client expects 200? - python

I am trying to test my 404 page to ensure certain elements are present on it.
My test looks like this:
class TestApp404PageIncludesLink(TestCase):
def setUp(self):
superuser = UserFactory(is_superuser=True, is_staff=True)
self.client.force_login(superuser)
def test_superuser_can_see_link(self):
response = self.client.get("404")
self.assertTrue(response.status_code == 404)
self.assertContains(response, 'href="/special_link/">Specialty</a>')
I am running this test as a logged in user - other tests for other views work fine.
I'm trying to check the 404 page.
It fails with this:
Couldn't retrieve content: Response code was 404 (expected 200)
200 != 404
How do I set up the test so it knows I am trying to get a 404?

The issue had to do with me not reading the documentation thoroughly enough apparently.
The assertContains takes a status_code argument that by default assumes a status of 200, which a 404 is not. Once I added that to the assertion it was resolved.
def test_superuser_can_see_link(self):
response = self.client.get("404")
self.assertTrue(response.status_code == 404)
self.assertContains(response, 'href="/special_link/">Specialty</a>', status_code=404)

Related

Return Blank from Python flask API

I have an API that must return just blank and status as 200 OK in case there is no data available
I have tried following things and facing these error
if df.empty:
return '' , 200
This returns "" in the browser
if df.empty:
return json.loads('{}'), 200
This return {} in the browser
Send status as 204 (NO CONTENT) makes the previous content to be as it is on the browser
How can i return complete blank with status as 200?
I have found solution after thoroughly exploring Flask documents
from flask import Response
.....
if df.empty:
return Response(status = 200)
Your first example shows in my console, as others have mention in comments:
127.0.0.1 - - [05/Dec/2018 18:46:35] "GET / HTTP/1.1" 200 -
You can also see status of a document in a Network tab in Developers console.
I didn't see 204 - NO CONTENT until I explicitly defined it:
#app.route('/')
def index():
return '', 204
Your second example didn't work for me and gave me an error:
TypeError: 'dict' object is not callable
EDIT:
This is source of a page in opera (and chrome also).
And this is code for your second example, that I get an error from.
from flask import Flask, json
app = Flask(__name__)
#app.route('/')
def index():
return json.loads('{}'), 200

how to redirect to a external 404 page python flask

I am trying to redirect my 404 to a external URL like this:
#app.route('404')
def http_error_handler(error):
return flask.redirect("http://www.exemple.com/404"), 404
but it does not work. I keep getting:
Not Found
The requested URL was not found on the server. If you entered the URL manually please check your spelling and try again.
You should try something like this:
from flask import render_template
#app.errorhandler(404)
def page_not_found(e):
return render_template('404.html'), 404
Source http://flask.pocoo.org/docs/1.0/patterns/errorpages/
You cannot do this - the user-agent (in most cases, a browser) looks at the status code that is returned to determine what to do. When you return a 404 status code what you are saying to the user-agent is, "I don't know what this thing is you are requesting" and the user-agent can then:
Display what you return in the body of the response
Display its own error message to the end user
Do some combination of the above two options
redirect actually creates a little HTML response (via werkzeug.exceptions), which normally the end user doesn't see because the user-agent follows the Location header when it sees the 302 response. However, you override the status code when you provide your own status code (404).
The fix is to either:
Remove the status code (at the cost of sending the wrong signal to the end user, potentially)
or Send a 404 with a meta:refresh and / or JavaScript redirect (slightly better, still confusing):
return redirect("/where-ever"), 404, {"Refresh": "1; url=/where-ever"}
Try this instead of a route
from flask import request
#app.errorhandler(404)
def own_404_page(error):
pageName = request.args.get('url')
print(pageName)
print(error)
f = open('erreur404.tpl')
return f.read()

django - handler404 vs handler500

I am now a little bit confused.
There are handler404 and handler500 in Django which I can override. I thought, I can do this:
try:
mymodel = MyModel.objects.get(id=someid)
except MyModel.DoesNotExist:
raise Http404
But I would love to know what really caused this 404 - Server Error or just a wrong URL..
how would this be possible? can I have infos about 500 error inside handler404?
in case of 500, handler500 does have a RequestContext and things like {{STATIC_URL}} will stop workingin 500.html. thats why i thought, i will raise 404 instead and email the admin inside 404 handler about error. does this make sense?
The bottom line is this:
In order to generate/cause/raise a 500, you have to request a valid URL.
Its quite simple - the 404 will only be raised if there was no 500 error, because the 500 error would not prevent the link from being valid.
So if its 404, there is no chance for it to also raise a 500; because without you requesting a valid URL, no server side code is run; this thus cannot trigger a 500.
They are mutually exclusive.
In your particular case, here is what happens:
You request /foo/bar/1
This URL is mapped using the url patterns to a view, if it matches - that's it, you have no longer a chance to raise a 404.
The request is passed to the handler - now, at this stage, the request pipeline cannot generate a 404.
There was an error in your view code - now one of two things can happen:
You anticipate this error with a try/except, and then you can raise whatever
exception you like. If this exception also returns a response, then whatever
that response is - that is the error code you are sending back in your reply to the client. So, when you raise Http404, it will return a response, with 404 error code. You can happily return any other response and error code combination.
An error occurs that is not caught by your code, or your code does not return a proper response. In this case, the default exception handler for django will return a response and raise 500. This is the normal/default case.
As you can see from the flow, in any case, to return a 500 response, the URL has to be valid.

Django test returns 404 error

I'm using the django test framwork to test my API. I have a simple view that returns "ok" at the address GET http://localhost:8000/v1/ping/. When I run the server and I test this with Chrome, it works well. However, when I launch a test on it, I get a 404 error. This is my test:
def test_ping(self):
c = Client()
response = c.get('/v1/ping/')
print response.content
print response.status_code
and the response:
<h1>Not Found</h1><p>The requested URL /v1/ping/ was not found on this server.</p>
404
The get method on Django's Test Client takes a relative path as an argument. Have you tried response = c.get('/v1/ping/')?
I found the error: I use rest_framework_swagger and there was a test file in it. I deleted it and everything is OK now.

Django Test Client post() returns 302 despite error on view's post()

I'm currently writing up some basic tests to ensure pages in a medium sized Django application are GETting and POSTing correctly. However, using django.test.client.Client isn't reliably failing when it should be. It returns a 302 response even when there's obviously placed errors in my code.
in my app/urls.py:
url(r'^mymodel/create/$',
views.MyModelView.as_view(),
name = 'my_model_create'),
Then, in attempts to intentionally create a 500 response, I did the following:
class MyModelCreateView(MyModelView, CreateView):
def post(self, request, *args, **kwargs):
print self.hello
self.object = MyModel()
return super(MyModelCreateView, self).post(request, *args, **kwargs)
Obviously, the view doesn't have any object called hello. This fails as expected when trying to send the request through the browser.
and even went as far as replacing "print self.hello" with
return HttpResponse(status = 500)
and yet, I still get the following:
#We have a model called Client, so it
#is imported as RequestClient to avoid conflicts
In [1]: from django.test.client import Client as RequestClient
In [2]: client = RequestClient()
In [3]: response = client.post("/app/mymodel/create/")
In [4]: response.status_code
Out[4]: 302
Clearly the problem here is between the keyboard and the chair, since there's no reason Client()/RequestClient() shouldn't return a 500 error if done correctly. Even some problems arise as I receive 302 responses for POST requests instead of 200 responses, but that may be because we're using HttpRedirect.
Does anyone out there know what may be the problem here? For reference I'm on Python 2.7 and Django 1.5 (though I may need to be compatible with Django 1.4).
It's not totally clear why you're getting a redirect, but if you want to follow it you need to tell RequestClient to follow redirects - per the documentation:
If you set follow to True the client will follow any redirects and a
redirect_chain attribute will be set in the response object containing
tuples of the intermediate urls and status codes.
So your test code should look like:
response = client.post("/app/mymodel/create/", follow=True)
It'd be worth checking the request chain to see where exactly it was routed.

Categories

Resources