简体   繁体   中英

How can I test in Capybara that a page has *not* reloaded (JavaScript onClick intercept has worked)?

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?

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.

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

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 a wait 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 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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM