问题
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?
回答1:
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.
回答2:
I 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
回答3:
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
回答4:
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.
回答5:
feature "User creates comment", do
context "with JavaScript enabled", js: true do
scenario "creates comment 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
来源:https://stackoverflow.com/questions/20243208/how-can-i-test-in-capybara-that-a-page-has-not-reloaded-javascript-onclick-in