Search code examples
pythonseleniumxpathlettuce

Lettuce Webdriver can't find my link by xpath


Lettuce picks up Behaviour Driven 'sentences' and executes code for use in tests.

There is a 'web-driver' that integrates this quite nicely with selenium.

My link is like so:

<div class="pull-right">
    <a href="/logout">Logout ?</a>
</div>

And I'm trying to use (either of) the steps described in github readme:

I should see a link to "Google" with the url "http://google.com/"
I should see a link that contains the text "Foobar" and the url "http://foobar.com/"

Which corresponds with this code:

@step('I should see a link to "(.*?)" with the url "(.*?)"$')
def should_see_link_text(step, link_text, link_url):
    assert_true(step,
                world.browser.find_element_by_xpath(str(
                    '//a[@href="%s"][./text()="%s"]' %
                    (link_url, link_text))))


@step('I should see a link that contains the text "(.*?)" '
      'and the url "(.*?)"$')
def should_include_link_text(step, link_text, link_url):
    return world.browser.find_element_by_xpath(str(
        '//a[@href="%s"][contains(., %s)]' %
        (link_url, link_text)))

But when I select my link in Chrome Dev Tools, it comes up as this x-path:

//*[@id="bs-example-navbar-collapse-1"]/div/div[2]/a

Which is nothing like: '//a[@href="%s"][contains(., %s)]' or '//a[@href="%s"][./text()="%s"]'.

So which step should I use to capture my link, and do I need to change my html to match what is available in lettuce-webdriver (hint: this would not be good!)? Preferably without having to specify an id or class etc.

Edit: the Error LWD gives it:

    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 "C:\Python34\lib\site-packages\lettuce_webdriver\webdriver.py", line 107, in should_include_link_text(link_url, link_text)))
      File "C:\Python34\lib\site-packages\selenium\webdriver\remote\webdriver.py", line 230, in find_element_by_xpath return self.find_element(by=By.XPATH, value=xpath)
      File "C:\Python34\lib\site-packages\selenium\webdriver\remote\webdriver.py", line 662, in find_element {'using': by, 'value': value})['value']
      File "C:\Python34\lib\site-packages\selenium\webdriver\remote\webdriver.py", line 173, in execute self.error_handler.check_response(response)
      File "C:\Python34\lib\site-packages\selenium\webdriver\remote\errorhandler.py", line 166, in check_response raise exception_class(message, screen, stacktrace) selenium.common.exceptions.NoSuchElementException: Message: Unable to locate element: {"method":"xpath","selector":"//a[@href=\"/logout\"][contains(., \"Logout ?\")]"}
    Stacktrace:
        at FirefoxDriver.prototype.findElementInternal_ (file:///D:/Users/CAStone/AppData/Local/Temp/tmpkxv5zfva/extensi
ons/fxdriver@googlecode.com/components/driver-component.js:9641:26)
        at FirefoxDriver.prototype.findElement (file:///D:/Users/CAStone/AppData/Local/Temp/tmpkxv5zfva/extensions/fxdri
ver@googlecode.com/components/driver-component.js:9650:3)
        at DelayedCommand.prototype.executeInternal_/h (file:///D:/Users/CAStone/AppData/Local/Temp/tmpkxv5zfva/extensio
ns/fxdriver@googlecode.com/components/command-processor.js:11635:16)
        at DelayedCommand.prototype.executeInternal_ (file:///D:/Users/CAStone/AppData/Local/Temp/tmpkxv5zfva/extensions
/fxdriver@googlecode.com/components/command-processor.js:11640:7)
        at DelayedCommand.prototype.execute/< (file:///D:/Users/CAStone/AppData/Local/Temp/tmpkxv5zfva/extensions/fxdriv
er@googlecode.com/components/command-processor.js:11582:5)

What worries me is the auto-escaping of my "selector":"//a[@href=\"/logout\"][contains(., \"Logout ?\")]" snip. If it's looking for the exact string of \"/logout\" and \"Logout ?\" then it clearly won't work.


Solution

  • It turns out that logging in the django's client class, will not effect selenium. So the page selenium sees is not logged in.

    The reason my 'I'm logged in' step fails is because I'm not logged in.