0

New to Ruby, Rails and TDD. I'm using RSpec with Capybara and Capybara webkit.

Trying to test if a div element exists on a page.

Test Code:

require 'spec_helper'
describe "Login module" do

    before do 
        visit root_path
    end

    it "should have a module container with id mLogin" do
        page.should have_css('div#mLogin')
    end

    it "should have a module container with id mLogin", :js => true do
        page.evaluate_script('$("div#mLogin").attr("id")').should eq "mLogin"
    end

end

The first test passes but the second test fails with:

Login module should have a module container with id mLogin
     Failure/Error: page.evaluate_script('$("div#mLogin").attr("id")').should eq "mLogin"

       expected: "mLogin"
            got: nil

Ran the JS in browser dev tools and get "mLogin" rather than nil.

Any ideas? Thanks.

Adam Waite
  • 19,175
  • 22
  • 126
  • 148

2 Answers2

0
find('div#mLogin')[:id].should eq 'mLogin'

See this from doc:

#evaluate_script
Evaluate the given JavaScript and return the result. Be careful when using this with scripts that return complex objects, such as jQuery statements. execute_script might be a better alternative.

evaluate_script always return nil, as far as I remember.

Anyway, your second test seems like is testing if capybara works, because your first test is enough.

sites
  • 21,417
  • 17
  • 87
  • 146
  • yeh I'm just trying to see if I can get it working. It's the other way round I think, evaluate returns a result and execute doesn't. It's strange because: page.evaluate_script('1+1').should eq 2 works but my id get script fails – Adam Waite Apr 27 '13 at 11:10
  • `execute_script` always returns nil- `evaluate_script` returns the evaluated script, as the docs you referenced say... – Matt Luongo Jan 02 '14 at 21:37
0

One likely problem is that the have_css matcher supports Capybara's synchronization feature. If the selector isn't found right away, it will wait and retry until it is found or a timeout elapses.

There's more documentation about this at http://rubydoc.info/github/jnicklas/capybara#Asynchronous_JavaScript__Ajax_and_friends_

On the other hand, evaluate_script runs immediately. Since this is the first thing you do after visiting the page, there's a race condition: it's possible that it executes this script before the page has finished loading.

You can fix this by trying to find an element on the page that won't appear until the page is loaded before you call evaluate_script.

Alternately, you can wrap your call in a call to synchronize to explicitly retry, but this is not generally recommended. For situations like this, you're much better off using Capybara's built-in matchers. The evaluate_script method should only be used as a last resort when there is no built-in way to accomplish what you need to do, and you need to take a lot of care to avoid race conditions.

Tim Moore
  • 8,958
  • 2
  • 23
  • 34