Reputation: 11023
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
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
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
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