Django test Client simulate logged in user - django

I am new to Django test Client. I want to test a view that uses #login_required . I was wondering if I can do that using the simple Client() like this:
>>> from django.test import Client
>>> c = Client()
>>> r = c.get("/libros/nuevo_libro/perfil/farseer/")
But, of course, the response is always a 302:
>>> r.status_code
302
Cause the #login_required decorator redirects it to the login page.
Is it possible to simulate in this kind of tests that the user is logged in?

The test client has a login method.
c = Client()
c.login(username='fred', password='secret')
response = c.get("/libros/nuevo_libro/perfil/farseer/")

Related

Test password protected page django

I want to write test cases about password-protected pages.
I have /management/edit page. it is loginrequired page. My test case currently likes below, but it is failed. I am expecting to get 200 but instead of I got redirection(302)
Tests.py
from django.test import TestCase, Client
# Admin panel Test cases
class PageTest(TestCase):
# it will redirect user to loginpage
def test_admin_page(self):
response = self.client.get("/management/")
self.assertEquals(response.status_code, 302)
def test_edit(self):
c = Client()
c.login(username='admin', password='admin')
response = c.get("/management/edit/")
self.assertEquals(response.status_code,200)
I replaced login with force_login
c = self.client
testuser = User.objects.create_user(username='useresu', password='666pass')
c.force_login(testuser)

Unit Test Case of redirection after successful Login of auth login view in Django

I have used django auth login view and mentioned LOGIN_REDIRECT_URL = '/team/' in my settings.py. Now i want to write the unit test case if user successfully login then it should redirect to /team/. Can anybody help me.
Thanks in advance..
My Login Url is:
path('login/', auth_views.LoginView.as_view(template_name = 'accounts/login.html'), name="login"),
My Test Case is :
class TestTeamsListView(TestCase):
def setUp(self):
obj1 = User.objects.create(username='test',email= 'abc#gmail.com', first_name='t', last_name='u', password="password")
self.login_url = reverse('accounts:login')
def test_on_successful_login(self):
client = Client()
response = client.post(self.login_url,{'username':'test','password':'password'},format='text/html')
self.assertEqual(response.status_code, 302)
When i run test then i am getting this result:
AssertionError: 200 != 302
You created a user with a password that is not hashed, as a result the login fails, and it returns the form with errors. You should create the user with .create_user(…) [Django-doc]:
obj1 = User.objects.create_user(
username='test',
email='abc#gmail.com',
first_name='t',
last_name='u',
password='password'
)

Authlib - passing authorize url as json

I'm building a SPA using Flask as an api and Vue js as front end. I'm using Authlib for user authentication and planning to use Facebook OAuth. I've already tried the example with Facebook and it's working. But I want to build this in a RESTful way. What I'm trying to do is change this part from app.py from the example:
#app.route('/login')
def login():
redirect_uri = url_for('auth', _external=True)
return oauth.google.authorize_redirect(redirect_uri)
to a json.
Is there a method in the library to get the url of Facebook dialog so that I can pass that as json and do the redirection in Vue?
Do you mean that you want to return a url value in the JSON response?
resp = oauth.google.authorize_redirect(redirect_uri)
url = resp.location
return jsonify(url=url)
Like the above code?
Per the documentation:
>>> import requests_oauthlib
>>> from requests_oauthlib import OAuth2Session
>>> from requests_oauthlib.compliance_fixes import facebook_compliance_fix
>>> facebook = OAuth2Session(client_id='test', redirect_uri='https://test.me')
>>> facebook = facebook_compliance_fix(facebook)
>>> authorization_url, state = facebook.authorization_url('https://www.facebook.com/dialog/oauth')
>>> authorization_url
'https://www.facebook.com/dialog/oauth?response_type=code&client_id=test&redirect_uri=https%3A%2F%2Ftest.me&state=bfipsir5GsKc1CbdPZCgBT0jIn2eq6'

How to test for AnonymousUser in Django Unittesting

I'm testing a form
A user may be logged in, or anonymous, when presented with the form
If the form succeeds, the user will be logged in
If the form fails, the user will remain as they were
I'd like to confirm this behaviour by unit testing.
django.test.Client does have a login method for this kind of thing, but given a response object how do I determine who is logged in?
data = {'email':'john#example.com','password':'abc'}
c = Client()
# here was can assume `request.user` is the AnonymousUser
# or I can use `c.login(..)` to log someone in
r = c.post('/myform/', data)
Can my unittest determine who the request.user would now be if I were to submit a second request?
You can do this:
client = Client()
# here was can assume `request.user` is the AnonymousUser
# or I can use `c.login(..)` to log someone in
from django.contrib import auth
user = auth.get_user(client) # it returns User or AnonymousUser
if user.is_anonymous():
...
It works because client keeps a user session (client.session).

How to Create Session Variables in Selenium/Django Unit Test?

I'm trying to write a functional test that uses Selenium to test a Django view. When the user comes to a page ("page2"), the view that renders that page expects to find a session variable "uid" (user ID). I've read a half dozen articles on how this is supposed to be done but none of them have worked for me. The code below shows how the Django documentation says it should be done but it doesn't work for me either. When I run the test, the view never completes executing and I get a "server error occurred" message. Could someone please tell me what I'm doing wrong? Thank you.
views.py:
from django.shortcuts import render_to_response
def page2(request):
uid = request.session['uid']
return render_to_response('session_tests/page2.html', {'uid': uid})
test.py:
from django.test import LiveServerTestCase
from selenium import webdriver
from django.test.client import Client
class SessionTest(LiveServerTestCase):
def setUp(self):
self.browser = webdriver.Firefox()
self.browser.implicitly_wait(3)
self.client = Client()
self.session = self.client.session
self.session['uid'] = 1
def tearDown(self):
self.browser.implicitly_wait(3)
self.browser.quit()
def test_session(self):
self.browser.get(self.live_server_url + '/session_tests/page2/')
body = self.browser.find_element_by_tag_name('body')
self.assertIn('Page 2', body.text)
Here's how to solve this problem. James Aylett hinted at the solution when he mentioned the session ID above. jscn showed how to set up a session but he didn't mention the importance of the session key to a solution and he also didn't discuss how to link the session state to Selenium's browser object.
First, you have to understand that when you create a session key/value pair (e.g. 'uid'=1), Django's middleware will create a session key/data/expiration date record in your backend of choice (database, file, etc.). The response object will then send that session key in a cookie back to the client's browser. When the browser sends a subsequent request, it will send a cookie back that contains that key which is then used by the middleware to lookup the user's session items.
Thus, the solution required 1.) finding a way to obtain the session key that is generated when you create a session item and then; 2.) finding a way to pass that key back in a cookie via Selenium's Firefox webdriver browser object. Here's the code that does that:
selenium_test.py:
-----------------
from django.conf import settings
from django.test import LiveServerTestCase
from selenium import webdriver
from django.test.client import Client
import pdb
def create_session_store():
""" Creates a session storage object. """
from django.utils.importlib import import_module
engine = import_module(settings.SESSION_ENGINE)
# Implement a database session store object that will contain the session key.
store = engine.SessionStore()
store.save()
return store
class SeleniumTestCase(LiveServerTestCase):
def setUp(self):
self.browser = webdriver.Firefox()
self.browser.implicitly_wait(3)
self.client = Client()
def tearDown(self):
self.browser.implicitly_wait(3)
self.browser.quit()
def test_welcome_page(self):
#pdb.set_trace()
# Create a session storage object.
session_store = create_session_store()
# In pdb, you can do 'session_store.session_key' to view the session key just created.
# Create a session object from the session store object.
session_items = session_store
# Add a session key/value pair.
session_items['uid'] = 1
session_items.save()
# Go to the correct domain.
self.browser.get(self.live_server_url)
# Add the session key to the cookie that will be sent back to the server.
self.browser.add_cookie({'name': settings.SESSION_COOKIE_NAME, 'value': session_store.session_key})
# In pdb, do 'self.browser.get_cookies() to verify that it's there.'
# The client sends a request to the view that's expecting the session item.
self.browser.get(self.live_server_url + '/signup/')
body = self.browser.find_element_by_tag_name('body')
self.assertIn('Welcome', body.text)
There are a couple of tickets in Django's bug tracker around this kind of problem, the main one seems to be: https://code.djangoproject.com/ticket/10899 which hasn't had any movement on it for a few months. Basically, you need to do some extra set up to get the session to work properly. Here's what worked for me (may not work as is with your particular set up, as I wasn't using Selenium):
def setUp(self):
from django.conf import settings
engine = import_module(settings.SESSION_ENGINE)
store = engine.SessionStore()
store.save()
self.client.cookies[settings.SESSION_COOKIE_NAME] = store.session_key
Now you should be able to access self.client.session and it should remember any changes you make to it.
Here is my solution for django==2.2.
from importlib import import_module
from django.conf import settings
from django.contrib.auth import get_user_model
# create the session database instance
engine = import_module(settings.SESSION_ENGINE)
session = engine.SessionStore()
# create the user and instantly login
User = get_user_model()
temp_user = User.objects.create(username='admin')
temp_user.set_password('password')
self.client.login(username='admin', password='password')
# get session object and insert data
session = self.client.session
session[key] = value
session.save()
# update selenium instance with sessionID
selenium.add_cookie({'name': 'sessionid', 'value': session._SessionBase__session_key,
'secure': False, 'path': '/'})