mahatmanich
mahatmanich

Reputation: 11023

Set request variables for functional testing of controllers in rails with minitest

When doing functional tests for controllers in rails how can I provide dynamic application instance variables to my test which live in the request.

I have a @station object that is initialized in a before action in my application controller (available in all other controllers), however the @station object is defined by the domain entry of the user e.g.: blue.mydomain.com. So it could have 3 different flavors, and the controller actions params[:id] are only valid for a certain flavor.

Further if I don't give my @station a flavor for my test environment it will fail utterly: (Here code from a helper that gets called in a before action in my application_controller.rb)

def init_station
    if Rails.env == "test"
      @station=Station.new('blue')
    else
      @station=Station.new(domain_flavor_picker)
    end
end


ApplicationController
 ....
 before_action :init_station
 .....

end

Thus I can only test for 'blue' or switch the flavor in my before action and then mock for different id!

test:

describe MyController do

    before do
        @id="10215d8da3f4f278cec747f09985b5528ec9e"         
    end

    it "should get index action" do
        p assigns(:station) # is nil
        get :artist_biography, id: @id, locale: I18n.available_locales.sample
        assert_response :success
        assert_not_nil assigns(:meta)           
        assert_not_nil assigns(:nav)
        assert_not_nil assigns(:content)
    end
end

As you can see I am also in need of providing a locale variable. I managed to mix up that call with I18n.available_locales.sample

How can I dynamically switch or manipulate my @station instance variable?

Upvotes: 1

Views: 1994

Answers (2)

mahatmanich
mahatmanich

Reputation: 11023

My issue was that I needed to provide minitest with an initial host! From @smathy answer I knew that I needed a Mock Request for the Controller!

Turns out that it is quite easy to set it in MiniTest if you know how!

Rails provides an ActionDispatch::TestRequest object which in itself seems to be a Rack::MockRequest object:

DEFAULT_ENV = Rack::MockRequest.env_for('/', 'HTTP_HOST' => 'test.host', 'REMOTE_ADDR' => '0.0.0.0', 'HTTP_USER_AGENT' => 'Rails Testing' )

So all I had to do in my test was:

before do
  @request.env['HTTP_HOST'] = %w(blue.mydomain.com red.mydomain.com green.mydomain.com).sample
end

to initialize my @station object with a sample of flavored domains.

Upvotes: 2

smathy
smathy

Reputation: 27961

assigns :station will only return a value after you do the request, ie. after the get line. Until you've done the request none of your controller code has been run for that test.

You also shouldn't use @vars in rspec, use let instead, and a few other things that I've shown below, many of which I learned from BetterSpecs

The Crux of your Issue

Assuming that domain_flavor_picker is a method in your controller then you should just mock that so you can different tests for the different return values of it. So, this shows the context for one of the return values of domain_flavor_picker, but you'd add other contexts for other values:

describe MyController do

  let(:id) { "10215d8da3f4f278cec747f09985b5528ec9e" }

  describe "GET /artist_biography" do
    context "when domain_flavor is blue" do
      before do
        allow(controller).to receive(:domain_flavor_picker) { "blue" } # <-- MOCK!
      end

      context "when valid id" do
        before { get :artist_biography, id: id, locale: I18n.available_locales.sample }

        subject { response }
        it { is_expected.to be_success }
        it "should assign :meta" do
          expect(assigns :meta).to be_present     # better to have an actual matcher here
        end
        it "should assign :nav" do
          expect(assigns :nav).to be_present      # ditto
        end
        it "should assign :content" do
          expect(assigns :content).to be_present  # ditto
        end
      end
    end
  end
end

Upvotes: 0

Related Questions