开发者

how to select li from autocomplete

In a text box, as you type, we have autocomplete that generates a list taking this structure:

<div class="results">
  <ul>
    <li class="even">
    <li class="odd">
    <li class="even">
    etc...

I'm writing tests with Cucumber (plus Capybara and Webdriver) and I need to select the first li.

page.execute_script isn'开发者_运维知识库t getting passed the right jQuery, I guess, because the following code snippet keeps returning null.

page.execute_script %Q{ $('li').eq(1).trigger("mouseenter").click(); }

That is, I'm getting this error:

TypeError: $("li") is null (Selenium::WebDriver::Error::UnexpectedJavascriptError)

I've only just picked up jQuery, so will anyone tell me what's wrong, why it's wrong and possibly how to fix it?

The li element exists on the page and I looked at the source to make sure, so I'm really confused that it can't find it.


I probably wouldn't try clicking on the autocomplete list item using the page.execute_script method. Ideally the When steps of cucumber should always 100% mimick what a user is capable of doing. And I would not expect them to open up a javascript console and start typing scripts to execute to select list items ;)

Obviously I know that isn't what you are going for, but that is what you are testing with your method.

A better method would be something like the following in one of your cucumber step definitions.:

When /^I follow the autocomplete link containing "([^"]*)"$/ do |link_text|
  page.find(:css, ".results ul li", :text => link_text).click
end

I believe that that should work, and it's better than trying to hack in JS code in your cucumber step.

Note that the page.find method returns a Capybara::Node::Element (I believe). The :text hash option tells capybara to only find the element that contains the specified text. If the element is not found, capybara will raise an exception.

If for whatever reason your li doesn't actually have clickable text in it, you could change the selector to ".results ul li:first", but ideally you can use the definition for more than just selecting the first item.

There is a bug that you may encounter (something about 'node' method not found or some shinanigans). If you get a strange error that you can't explain when doing this, and it's not immediately obvious what it is, then you may need to comment out the following line in env.rb of your cucumber's support directory:

require 'cucumber/rails/capybara_javascript_emulation'

The monkeypatch cucumber put in there broke when capybara got upgraded and last I checked hasn't been deployed as a stable release yet.

Hopefully this resolves your issue :)

EDIT TO ADD:

I just looked at your question again and felt like I might want to let you know why $("li") would be returning null. When you added the "And I should see..." step before this script execution, capybara has built-in wait-for-element-to-appear default timeouts that it uses when you look for an element on the page that isn't there yet. If it doesn't appear in the specified time (I think 5 seconds by default?) then capybara will give you a failed test.

However, when you run the execute_script call you are bypassing all of Capybara's awesome framework and attempting to interact with the DOM directly using jquery - except that Capybara hasn't 'waited' for the object to appear yet, so your javascript probably isn't going to find it.

I believe that the solution I have posted using page.find will work for you, because that method does wait for the element to appear on the page before raising an error. Finders are explained in more detail here: https://github.com/jnicklas/capybara under the "Finding" subheading down where the readme is displayed.


Possible because the autocomplete is generated (after) the page is rendered and thus the execute script possibly won't pick it up.

try using the jQuery command live to attach triggers to items rendered after document.ready.


The following code works for me. I have striped out all the extra code. The key point to remember is that the list item exists when the function is called (i.e. I am accessing it once the page is 'ready')

In your case, you should only execute $('li') once the auto-suggest has been populated otherwise it will be null. Also note that eq() is zero based - so the first element is eq(0), not eq(1).

<head>
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.5.1/jquery.min.js"></script>
    <script>
        $(document).ready(function() {
            console.log($('li').eq(0)); // outputs the first list element Item 1
        });
    </script>
</head>
<body>

    <div class="results">
        <ul>
            <li class="even">Item 1</li>
            <li class="odd">Item 2</li>
            <li class="even">Item 3</li>
            <li class="odd">Item 4</li>
        </ul>
    </div>

</body>
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜