I'm getting desperate because I can't seem to find a solution for what I thought would be used by everyone out there.
I want to test a simple login with selenium and pytest with a live_server url. According to pytest-django doc, a simple fixture called live_server
should do the trick (https://pytest-django.readthedocs.io/en/latest/helpers.html#live-server).
Unfortunately when I pass this fixture to my test and try to visit my website with it I get:
localhost refused to connect
for example for this:
def test_selenium(self, live_server, create_staff_user_in_db):
browser = webdriver.Remote(
command_executor='http://selenium:4444/wd/hub',
desired_capabilities=DesiredCapabilities.CHROME,
)
browser.get(live_server.url)
Leveraging this question Selenium unable to login to Django LiveServerTestCase I am trying to use a different server-fixture which then connects me and I can see my website in my VNC viewer.
@pytest.fixture
def test_server() -> LiveServer:
addr = socket.gethostbyname(socket.gethostname())
server = LiveServer(addr)
yield server
server.stop()
But with this I am now not able to login to my website if I create users in the db with my fixtures. Even though it seems like users are actually created. So my test now looks like:
def test_selenium(self, test_server, create_staff_user_in_db):
browser = webdriver.Remote(
command_executor='http://selenium:4444/wd/hub',
desired_capabilities=DesiredCapabilities.CHROME,
)
browser.get(f"{live_server.url}/login")
input_username = browser.find_element_by_name('username')
input_password = browser.find_element_by_name('password')
input_username.send_keys('testuserstaff')
input_password.send_keys('mypasswordstaff')
browser.find_element_by_xpath(
'//*[@id="page-top"]/div[1]/div/div/div/div/form/button'
).click()
And my user fixture is:
@pytest.fixture()
def create_staff_user_in_db():
User = get_user_model()
staff_user = User.objects.create_user(
username="testuserstaff",
password="mypasswordstaff",
)
staff_user.is_staff = True
staff_user.save()
return staff_user
The tests visits my login page and fails to log in. I am 100% certain that I am using the right credentials.
If I print out for debugging I also can verify that my user is in my db:
print(u.username) ==> testuserstaff
print(u.password) ==> igetthehashofthepassword
print(User.objects.count()) ==> 1
Thus I assume the db that is being created by pytest is filled with this user I pass as fixture. Now somehow my live server is either not using the db or not recognising the fixtures.
It must be connected to the live_server/test_server fixture. I would be supergrateful for any help. I feel like I am so close but I just can't seem to find out why it doesn't log in.
What else have I tried: 1) Login in with users that are in my development db. No success. So I am wondering: What db is then be used?
2) I tried to setup pytest-selenium library. If I try to load a page I get selenium.common.exceptions.SessionNotCreatedException: Message: Unable to create session
3) I tried to work with StaticLiveServerCase, but this is not an option since I need to pass fixtures as an argument.
4) I searched everywhere on the web and cannot find anything else
Also good to know:
I am running this in a docker environment (happy to share if it helps)
So my stack is basically: Docker, Django, Pytest, selenium
Again, would really appreciate a hand here. Thanks so much in advance
EDIT:
My docker-compose file:
version: '3'
volumes:
local_postgres_data: {}
local_postgres_data_backups: {}
services:
django:
build:
context: .
dockerfile: ./compose/local/django/Dockerfile
image: mywebsite_local_django
depends_on:
- postgres
volumes:
- .:/app
env_file:
- ./.envs/.local/.django
- ./.envs/.local/.postgres
ports:
- "8000:8000"
command: /start
selenium:
image: selenium/standalone-chrome-debug
ports:
- 4444:4444
- 5900:5900
postgres:
build:
context: .
dockerfile: ./compose/production/postgres/Dockerfile
image: mywebsite_production_postgres
volumes:
- local_postgres_data:/var/lib/postgresql/data
- local_postgres_data_backups:/backups
env_file:
- ./.envs/.local/.postgres
Turning the comment into an answer: by default, the tests avoid running db queries to not to slow down the test run, so User.objects.create_user
doesn't write to database. To ensure db commits, use the @pytest.mark.django_db(transaction=True)
marker in tests or the transactional_db
fixture in your fixtures:
@pytest.fixture()
def create_staff_user_in_db(transactional_db):
staff_user = User.objects.create_user(...)
...
I assume that the
live_server
fixture of django usestransactional_db
automatically but that thetest_server
doesn't?
Exactly - live_server
implies the transactional mode, but the custom impl of test_server
doesn't. Explicitly requesting the transactional_db
fixture in test_server
should fix it:
@pytest.fixture
def test_server(request) -> LiveServer:
request.getfixturevalue("transactional_db")
...
BTW if you just want to apply the live server address dynamically, you shouldn't need to define your own fixture; writing config values should suffice. Example:
# conftest.py
def pytest_configure(config):
config.option.liveserver = socket.gethostbyname(socket.gethostname())
This value will then be used by the builtin live_server
fixture. Put the conftest.py
into your project or tests root dir to make pytest
find the hookimpl early enough for it to be applied.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With