rails 3.1, capybara-webkit, how to execute javascript inside link?

情到浓时终转凉″ 提交于 2019-12-11 03:13:00

问题


Can I execute a javascript in a link with capybara click_link('next_page') ?

The link looks like this:

<a onclick="$('#submit_direction').attr('value', '1');$('#quizForm').submit()" id="next_page" href="#">Next Question</a>

I read at capybara at github that I can submit a form by click at its submit button like this:

click_on('Submit Answer')

But, in my case, I need to submit the form using javascript in a link, so, how to test the link that has javascript inside ? isn't click_link('next_page') sufficient ?

EDIT

after setting :js=> true my test looks like this:

   it "should pass when answering all correct", :js=>true  do

    login_as(student, :scope => :student)
    visit ("/student_courses")

    #page.execute_script("$('#submit_direction').attr('value', '1');$('#quizForm').submit()")

    trace "HTML:------------", page.html

  end

Before :js=> true, I could visit the page normally, But, I've noticed that the page cannot be visited after :js=> true, here is the error I got after visiting the page:

Started GET "/student_courses" for 127.0.0.1 at 2012-01-23 06:29:26 +0200 (5010.7ms) UPDATE "students" SET "last_sign_in_at" = '2012-01-23 04:29:26.274285', "current_sign_in_at" = '2012-01-23 04:29:26.274285', "last_sign_in_ip" = '127.0.0.1', "current_sign_in_ip" = '127.0.0.1', "sign_in_count" = 1, "updated_at" = '2012-01-23 04:29:26.276279' WHERE "students"."id" = 1 SQLite3::BusyException: database is locked: UPDATE "students" SET "last_sign_in_at" = '2012-01-23 04:29:26.274285', "current_sign_in_at" = '2012-01-23 04:29:26.274285', "last_sign_in_ip" = '127.0.0.1', "current_sign_in_ip" = '127.0.0.1', "sign_in_count" = 1, "updated_at" = '2012-01-23 04:29:26.276279' WHERE "students"."id" = 1 HTML:------------__ Internal Server Error

Internal Server Error

cannot rollback transaction - SQL statements in progress
WEBrick/1.3.1 (Ruby/1.9.3/2011-10-30) at 127.0.0.1:34718

so, why SQLite3::BusyException: database is locked now ?!


回答1:


I just spent 8 hours resolving a similar issue, and I found the solution. The fix is so simple, I could cry.

First, diagnosis

The reason you're getting "SQLite3::BusyException: database is locked" is that you are launching an asynchronous thread, namely a form submission, that ends up losing the "database write" race to your test's main thread. In effect, as your test has already completed and is running your "after each" database cleanup routine (defined in your spec_helper), the form action has only just begun trying to run the business logic (which relies on the data that your test after:each hook is busy destroying).

This problem is a lot more likely to occur with tests that click on an AJAX POST button and then terminate without asserting something about the view change.

Second, the fix

As it turns out, Capybara is designed to "synchronize" all your requests. But only if you implicitly let it. Notice that after your form submission, you're not having Capybara look at your page. Therefore it thinks you're done and takes your data out of scope (while your form submission thread is hanging in the background.)

Simply add the following line of code to the end of your test, and it should suddenly work:

page.should_not have_content "dude, you forgot to assert anything about the view"

Third, make it pretty

Don't use execute_script. That's what Capybara is for. But also don't rely on "click_on" because it's not a great abstraction. You need to know too much about its internals. Instead, use CSS selectors like so:

page.find("#submit_button").click

And one more thing - your test shouldn't try to manipulate the DOM. A good Selenium test assumes to have to follow the same steps a normal user follows.

So in conclusion

it "should pass when answering all correct", :js => true  do
    login_as(student, :scope => :student)
    visit ("/student_courses")
    page.find(".my-js-enabled-button").click
    page.find("#submit_button").click

    # Synchronizes your view to your database state before exiting test,
    # Therefore makes sure no threads remain unfinished before your teardown.
    page.should_not have_content "dude, you forgot to expect / assert anything."
end



回答2:


To expand on Alex's comment Capybara won't execute JS unless it's explicitly turned on for the given tests.

To do this, use :js => true on either your describe block or individual test eg.

describe "in such and such a context", :js => true do
   # some stuff
end



回答3:


It should work. with capybara, you are essentially test your application through the browser, and it will behave the same.



来源:https://stackoverflow.com/questions/8964537/rails-3-1-capybara-webkit-how-to-execute-javascript-inside-link

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