Selenium login test doesn't accept pytest fixtures for login or refuses to connect

萝らか妹 提交于 2020-04-10 09:09:55

问题


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

回答1:


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 uses transactional_db automatically but that the test_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.



来源:https://stackoverflow.com/questions/60744437/selenium-login-test-doesnt-accept-pytest-fixtures-for-login-or-refuses-to-conne

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!