Search code examples
ruby-on-railsfunctional-testing

Rails: multiple get requests in a single functional test


I would like to group some get requests in the same tests but I get erratic behavior. I have the following two tests:

test 'index for local seller (same site)' do
  seller = FactoryGirl.create :seller, business_site: @open_or.business_site
  get :index, nil, {user_id: seller.to_param }
  assert_select "table#order_requests tr##{@controller.view_context.dom_id @open_or}"
end
test 'index for local seller (different site)' do
  seller = FactoryGirl.create :seller_local
  get :index, nil, {user_id: seller.to_param }
  assert_select "table#order_requests tr##{@controller.view_context.dom_id @open_or}", false
end

which I would like to combine under one test but if I do so, the second assert will wrongly fail (Expected exactly 0 elements matching "table#order_requests tr#order_request_1000244799", found 1.). I don't really understand why? Something might not be reset properly for the second 'get' call. I looked for ways to 'reset' the request without success.

Related: making two requests to the same controller in rails integrations specs


Solution

  • One important distinction I've noticed in functional tests (as opposed to integration) is that the state of a controller does not seem to be reset between requests, which can lead to unexpected results. For example, consider this (contrived) controller:

    class ThingyController < ApplicationController
      def one 
        @thingy = Thingy.first
        render :nothing => true
      end 
    
      def two 
        render :nothing => true
      end 
    end
    

    Action 'one' sets @thingy, while action 'two' doesn't. However, this functional test fails:

    test "thingy should not exist in second request" do
      get :one
      assert_not_nil assigns(:thingy), "thingy should exist in get_one"
      get :two
      assert_nil assigns(:thingy), "thingy should be absent in get_two"
    end
    

    Presumably, it is because the @thingy from the first request remains as an instance variable in the controller for the duration of the test method.

    While you can certainly make multiple get/put/etc calls within one test, I think they are not designed to test more than one action per test method. Per the Rails API TestCase docs:

    Functional tests allow you to test a single controller action per test method. This should not be confused with integration tests (see ActionDispatch::IntegrationTest), which are more like “stories” that can involve multiple controllers and multiple actions (i.e. multiple different HTTP requests).

    If you really wish to combine the two actions, perhaps an integration test would be a better approach.