Pregunta

I have this route to the user_friendships controller's block action:

block_user_friendship PUT    /user_friendships/:id/block(.:format)     user_friendships#block

All you need to know is that the block action requires an :id.

I can test the action's resulting view in an rspec spec like this:

require 'spec_helper'
it "should not display the names of users who have a state of pending or requested" do
    visit "/user_friendships/1/block"
    page.should have_content("user with id of 1 blocked!")
end

But this is a bit of a brittle spec because the URL is hardcoded. How can I populate the :id entry of the params hash using the block_user_friendship_path variable?

This, for example, doesn't work:

require 'spec_helper'
it "should not display the names of users who have a state of pending or requested" do
    visit block_user_friendship_path, id: "/23"
    page.should have_content("user with id of 23 blocked!")
end

(Results in No route matches {:action=>"block", :controller=>"user_friendships"} missing required keys: [:id] )

¿Fue útil?

Solución 2

Capybara is intended to be used for full-stack integration tests, so the recommended approach would be to avoid hardcoding URLs and instead drive Capybara to navigate through your app as a user would. This ensures that the links to the block path that are supposed to appear in your app where they're supposed to, and that they work when you click them.

Visiting the URL directly skips that, and if you need to make a PUT request instead of a GET request, it won't work correctly since visit is the equivalent of pasting a URL into your browser address bar: it always issues a GET request.

If it is working with a fully hardcoded URL, then you might want to check your routes definition. If blocking a user works on a simple GET request, this could be used in a CSRF attack. Destructive operations should never be triggered by GET requests.

Alex Lynham's answer describes a Rails/RSpec controller test, not a Capybara integration test, and if you want something lower level that does not exercise the entire stack, a controller test like the one suggested in that answer is a good way to go.

Otros consejos

The reason why visit block_user_friendship_path, id: "/23" does not work is the syntax.

visit block_user_friendship_path, id: "/23" means: pass the hash with id: "/23" to the visit-method.

What you intended to do (and thus the correct answer) is

visit block_user_friendship_path(id: "23")

which means: send the id of 23 to the path-helper-method.

As well as the visit method in capybara, I know that you get the post method, so I assume there's also a put method. You can then post a specific request with params and then use the subject method to test the special response object:

  context "post request" do
    before do
      post 'show', format: :txt, start_at: start_at, end_at: end_at, id: user.id
    end

    subject { response }

    its(:body) do
      should include(user.name)
    end
  end

The above is roughly speaking production code I used to test a post request with params and then test the response body. Hopefully it should work for you (or at least point you in the right direction). Good luck!

EDIT: The post line obviously has some other params you don't need, I left them in illustratively in case there's anything else that you'd want to pass. Also note that this should be inside of a controller spec, not a request spec.

You can add arguments to the helper methods and the controller can read them as usual.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top