'Django user authentication fails in selenium tests
I'm writing tests for my djangocms app, first time using selenium to replicate the browser/user. I'm trying to test the login page, user simply fills out the username & password, but I can't get authenticate to work in the selenium tests. I can log in via the website myself & can even use authenticate in the test code block, but selenium isn't working, any tips? Anything i've read so far just involved the user password not being hashed on save, which mine is, so i don't have a clue here. I know the credentials are correct, the user exists, & the password is hashed in the db. This is also the only test i'm running, so no chance of any other tests affecting it. I also know from turning off 'headless' that the input fields are being filled out properly by selenium, it just won't authenticate. Also, don't think its relevant, but the submit button triggers a javascript method with vue.js, which makes an axios call (vue's version of ajax). But I know all of the JS code works or the message wouldn't appear on the page.
Here is where I create the user in setup
def create_user(role='competitor', username=None, email='[email protected]', password='password', superuser=False):
# if not given a username, we generate a random string since username's have to be unique
random_string = string.ascii_letters + string.digits
if not username:
username = 'username_' + (''.join(
(random.choice(random_string) for i in range(10))
))
group, created = Group.objects.get_or_create(name=role)
new_user = User(username=username, email=email)
new_user.set_password(password)
if superuser:
new_user.is_superuser = True
if role == 'admin':
new_user.is_staff = True
new_user.save()
group.user_set.add(new_user)
return new_user
Here is the actual tests. Note that authenticate works here, yet not in the browser with selenium
import time
from django.contrib.auth.models import User
from tests.utils.petrobowl_model_utils import create_user
from webdriver_manager.chrome import ChromeDriverManager
from selenium.webdriver.common.by import By
from django.test import LiveServerTestCase
from selenium import webdriver
from django.test.client import RequestFactory
request = RequestFactory()
class PetrobowlLoginTemplateTests(LiveServerTestCase):
# we set up our driver before any tests start
def setUp(self):
self.user = create_user(username='test_user', password='password')
time.sleep(2)
options = webdriver.ChromeOptions()
options.add_argument('headless')
self.driver = webdriver.Chrome(ChromeDriverManager().install(), options=options)
# here we test the login page works, and we can log in successfully
def test_login_form_works(self):
self.driver.get("http://127.0.0.1:8000/user/login/")
assert 'Login' in self.driver.page_source
username_input = self.driver.find_element(By.ID, "username_confirmation")
username_input.send_keys(self.user.username)
password_input = self.driver.find_element(By.ID, "password")
password_input.send_keys('password')
submit = self.driver.find_element(By.ID, "login_button")
# this works for some reason, exact same credentials.
from django.contrib.auth import authenticate
test = authenticate(request, username='test_user', password='password')
print('test = ', test)
submit.click()
time.sleep(1)
# these top two should fail & bottom two should pass, but the username/password never authenticates
assert 'Username or Password is incorrect' in self.driver.page_source
assert 'Login' in self.driver.page_source
assert 'Welcome to Petrobowl' in self.driver.page_source
assert 'Successfully logged in' in self.driver.page_source
In the view, it simply grabs the data, runs it through a form and fails here:
user = authenticate(request, username=form_data['username_confirmation'], password=form_data['password'])
When that line fails, it passes back 'Username or Password is incorrect' to the page, so I know that it fails exactly there. Any suggestions?
Solution 1:[1]
For anyone who runs into a similar issue, I found the issue & a solution to my problem. Selenium couldn't sign in because it was using the real database & server & not the test database. i had to change the self.driver.get line just below test_login_form_works, to the following. To that caused Selenium to use the port it's supposed to run on and use the test database.
self.driver.get('%s%s' % (self.live_server_url, '/user/login/'))
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | Jerrod |
