Search code examples
ruby-on-railsturbolinks

Follow Turblinks.visit() in rails controller test


I have a create.js.erb template with the following:

<% if @conversation.errors.any? %>
  $("#form").html("<%= j render(partial: 'form') %>");
<% else %>
  Turbolinks.visit("<%= conversation_url @conversation %>");
<% end %>

I can test the sad path easily using assert_select_jquery like so:

test 'sad path' do
  # code that causes failure ommitted

  # test that the error explanation div appears
  assert_select_jquery :html, '#form' do
    assert_select 'li', "Body can't be blank"
  end  
end

I'm having trouble testing the happy path:

test "happy path" do
  post conversations_url, params: { conversation: attrs }, xhr: true

  # Test that Turbolinks takes us to 
  # the mailbox after successful post 
  assert_select '.flash', "Message sent successfully."
end

The test fails because the flash div containing the success message only appears after the Turbolinks call. The best I can do so far is test that the response body contains a call to Turblinks.visit():

expected_response = "Turbolinks.visit(\"#{conversation_url conversation}\");"
assert_match /#{expected_response}/, response.body.chomp

But this is totally gross. Is there a rails way for telling controller tests to execute any Turblinks directives contained in js.erb files that might be rendered during the request?

execute_javascript_on_page
assert_select :h1, 'xyz'

Solution

  • You need a browser to execute JavaScript so you need a browser test with something like capybara. I'm not sure which Rails version you use but in Rails 5 browser tests are provided by default. See System Testing in Rails Guides. In previous versions, you need to install capybara yourself.

    That being said, I do not think testing for a call to Turbolinks.visit is that bad. My only concern is that it might be a bit unreadable so I'd define a custom assertion like:

    def assert_turbolinks_visit(target_url)
      assert_match(%r{Turbolinks.visit("#{target_url}")}, response.body)
    end
    

    and then use it like:

    assert_turbolinks_visit(conversation_url(conversation))
    

    It might get more problematic if the argument to Turbolinks.visit isn't a literal. In this case, a browser test may be necessary.