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 ?!
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
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
It should work. with capybara, you are essentially test your application through the browser, and it will behave the same.