I am using Capybara, Cucumber and Poltergeist. I am testing a JavaScript function that is attached to a form submit button, which is intended to catch the submit event and prevent it (doing an AJAX request in the background). With and without AJAX, the page will end up looking the same, but the AJAX approach is much faster and does not interrupt the browsing experience etc.
What can I do to test that the form was indeed not submitted, and that the changes are the result of a dynamic AJAX call rather than a reload?
I am using Capybara, Cucumber and Poltergeist. I am testing a JavaScript function that is attached to a form submit button, which is intended to catch the submit event and prevent it (doing an AJAX request in the background). With and without AJAX, the page will end up looking the same, but the AJAX approach is much faster and does not interrupt the browsing experience etc.
What can I do to test that the form was indeed not submitted, and that the changes are the result of a dynamic AJAX call rather than a reload?
Share Improve this question asked Nov 27, 2013 at 13:00 Matt GibsonMatt Gibson 14.9k7 gold badges51 silver badges80 bronze badges5 Answers
Reset to default 2I had the same issue and came up with a solution, probably not the best one–but it works :)
#support/reload.rb
def init_reload_check
page.evaluate_script "window.not_reloaded = 'not reloaded';"
end
def not_reloaded
page.evaluate_script("window.not_reloaded") == "not reloaded"
end
#Ajax Test
it "should not reload the page", js: true do
init_reload_check
click_link "Ajax Link"
expect(not_reloaded).to be_truthy
end
Modified version of @jules' answer:
describe "My page", :js do
it "reloads when it should" do
visit "/"
expect_page_to_reload do
click_link "Reload me"
end
end
def expect_page_to_reload
page.evaluate_script "$(document.body).addClass('not-reloaded')"
yield
expect(page).not_to have_selector("body.not-reloaded")
end
end
EDIT 2017-01-19:
I found this old answer of mine which strangely did not seem to answer the actual question, but instead the opposite (check that the page has reloaded). This is what we do currently in our app to check that a page does not reload:
def expect_page_not_to_reload
page.evaluate_script %{$(document.body).addClass("not-reloaded")}
expect(page).to have_selector("body.not-reloaded")
yield
sleep 0.5 # Give it a chance to reload before we check.
expect(page).to have_selector("body.not-reloaded")
end
Both answers rely on jQuery for adding the class.
And here's my version of Henrik N's answer. Doesn't rely on jQuery or whatever assertion library he's using.
def assert_page_reloads(message = "page should reload")
page.evaluate_script "document.body.classList.add('not-reloaded')"
yield
if has_selector? "body.not-reloaded"
assert false, message
end
end
def assert_page_does_not_reload(message = "page should not reload")
page.evaluate_script "document.body.classList.add('not-reloaded')"
yield
unless has_selector? "body.not-reloaded"
assert false, message
end
page.evaluate_script "document.body.classList.remove('not-reloaded')"
end
Capybara is intended for user-level functional testing. There isn't an easy way to test an implementation detail such as whether a form uses AJAX or a traditional form submission. It encourages you to write your tests in terms of the end-user experience.
There are a couple of things you can do:
Capybara supports a wait time for finders and assertions. There are a few ways to set it, using
Capybara.default_wait_time
,Capybara.using_wait_time
, or passing await
option to your assertion methods. If you set a low wait time, you can be sure that the results of clicking the submit button return quickly.Look into JavaScript unit and integration testing frameworks such as Jasmine. This can be used to test the JavaScript code that sets up the event binding and AJAX call. You can use a spy to ensure that the expected AJAX call is made when the button is clicked.
feature "User creates ment", do
context "with JavaScript enabled", js: true do
scenario "creates ment via AJAX" do
initial_page_id = assign_page_id
# Perform AJAX action
...
page_reloaded = current_page_id != initial_page_id
expect(page_reloaded).to eq(false)
end
def assign_page_id
page_id = SecureRandom.hex
page.evaluate_script "window.pageIdForTesting = '#{page_id}'"
end
def current_page_id
page.evaluate_script("window.pageIdForTesting")
end
end
context "without JavaScript" do
# Can be used if progressively enhancing
...
end
end