Search code examples
pythondjangoseleniumlettuce

How can I sync the html/session used between Django's 'Client' and Selenium's webdriver


I'm trying to test that logged in users can log out on my Django site with Lettuce, Selenium and lettuce_webdriver.

In my terrain.py I have:

@before.all
def setup_browser():
    profile = webdriver.FirefoxProfile()
    profile.set_preference('network.dns.disableIPv6', True)
    world.browser = webdriver.Firefox(profile)
    world.client = Client(HTTP_USER_AGENT='Mozilla/5.0')

And then when I 'login':

@step(r'I am logged in as "(\w*)"')
def log_in(step, name):
    world.client.login(username=name, password=name)

And I go to my site:

And I go to "localhost:8000"
    I find a link called "Logout ?" that goes to "/logout"

@step(r'I find a link called "(.*?)" that goes to "(.*?)"$')
def find_link(step, link_name, link_url):
    print(world.browser.page_source)
    elem = world.browser.find_element_by_xpath(r'//a[@href="%s"]' % link_url)
    eq_(elem.text, link_name)

But my page_source shows I am not logged in. This kind of makes sense...in that client and browser aren't talking to each other. But is this possible, or do I need to login 'manually' by clicking links with selenium etc?

I'd like to do this:

 world.browser.page_source = world.client.get(world.browser.current_url).content

But page_source can't be changed. Can I feed Selenium from django's client some how?

Edit: Following Loius' advice below, my 'I am logged in as ...' step is as below. I added the if/else to just check my suspicions. My client is still setup as above (see setup_browser step above)

@step(r'I am logged in as "(\w*)"')
def log_in(step, name):
    world.client.login(username=name, password=name)
    if world.client.cookies:
        session_key = world.client.cookies["sessionid"].value
        world.browser.add_cookie({'name':'sessionid', 'value':session_key})
        world.browser.refresh()
    else: 
        raise Exception("No Cookies!")

All the advice I've seen is to login first. Without my check, I get this:

  Scenario: Logged in users can logout                       # \gantt_charts\features\index.feature:12
    Given I am logged in as "elsepeth"                                # \gantt_charts\features\steps.py:25
    Traceback (most recent call last):
      File "C:\Python34\lib\site-packages\lettuce\core.py", line 144, in __call__
        ret = self.function(self.step, *args, **kw)
      File "D:\Django_Projects\gAnttlr\gantt_charts\features\steps.py", line 27, in log_in
        session_key = world.client.cookies["sessionid"].value
    KeyError: 'sessionid'

Solution

  • I've not tried doing exactly what you are trying to do but I've done something similar. What you need to do is set a cookie like this on your Selenium instance after you've logged into your Django site with your Client instance:

    driver.add_cookie({'name': 'sessionid', 'value': session_key})
    

    The name should be equal to your SESSION_COOKIE_NAME setting on the Django site (sessionid is the default). You need to figure out the value of session_key.

    You can obtain it from a Client instance like this:

        session_key = client.cookies["sessionid"].value
    

    Note that Selenium won't be able to set the cookie for some browsers if SESSION_COOKIE_SECURE is True. You should have this setting be True for your production server but if you want your Selenium tests to set your session cookie, then you have to make it False for testing.

    Once your Selenium instance has the cookie, it will look to Django as if you had logged into it with Selenium. As I said, I do something similar in my test suites. (I use something else than Client but the principle is the same.)