Proper way to wait for a second page to load with Capybara when the first has the same field as the second

Here are a couple of ways using which you can solve it:

  1. Use another locator that is present only at the second page to select "Email" field:

    find('#second_page #email').set('[email protected]')
    
  2. Write a statement that will wait for a second page to be loaded instead of sleep:

    visit new_front_form_subscription_path(@web_form_2.id)
    expect(page).to have_css('locator_present_only_at_second_page')
    fill_in "Email", with: "[email protected]"
    

The above answers are correct, but difficult to implement if you have a large test suite, because you have to find a unique element on each page. If you are a graduate from the Michael Hartl school of rails there is an easy way to solve this. Hartl teaches setting a different @title instance variable for every controller action. This is then used in application.html.erb to set an html title element for every page.

I certainly do, and it allowed a very easy way to fix up all my flaky tests that failed because the page had not loaded properly. You cannot find the title tag because it is not visible. So what I did was put at the bottom of the application.html.erb, the following code;

<%= content_tag :div, "[#{title}]", class: 'rspec_eyes_only' if Rails.env.test? %>

This inserts, if you are in test mode, a div with title text, surrounded by square brackets. Then I wrote a helper that goes in rails_helper.rb

def wait_for_page_load(title)
  find('div.rspec_eyes_only', text: title)
end

I already has another helper to test for the correct title, so I modified it to add in wait_for_page_load i.e;

def title_is_correct(title)
  full_title = "#{BaseTitle} | #{title}"
  wait_for_page_load "[#{full_title}]"
  expect(page.title).to eq full_title
end

These simple changes cleared up almost all of my flaky tests.