I've got a confirmable devise
model that I'm trying to write a spec for, and it's got some code that skips the confirmation if we're in a staging or development environment. To test it, I'm trying to stub the Rails.env.*?
environment methods, so I defined a method as a helper to handle all the cases:
def enable_environment(env)
if env == :staging
stub_env('STAGING', 'true')
end
# clear all environments
allow(Rails.env).to receive(:test?) { false }
allow(Rails.env).to receive(:development?) { false }
allow(Rails.env).to receive(:production?) { false }
# turn on environment of choice
if env == :production || env == :staging
allow(Rails.env).to receive(:production?) { true }
elsif env == :development
allow(Rails.env).to receive(:development?) { true }
elsif env == :test
allow(Rails.env).to receive(:test?) { true }
else
raise 'no such environment'
end
end
However, it's looking like these stubs are only scoped to the method--if I call enable_environment(:staging)
in an example and debug with byebug
right after, Rails.env.test?
returns true
and Rails.env.production?
returns false
. ENV['STAGING']
also returns nil
. Is there any way to do this, or will I just have to copy-paste the code in each example?
Edit: So, the second layer of the problem seems to be another scoping issue. I was testing by calling User.create
, which calls my skip_conf!
method off the after_create
hook. This fails because the Rails.env
that I've stubbed doesn't affect that hook (it seems).
Next, I tried just building a User
model with User.new
then directly calling skip_conf!
on it. This fails because skip_conf!
has side-effects (I get a NoMethodError: undefined method '+' for nil:NilClass
). I've tried other methods (skip_conf
, for instance, without side-effects), and they work. My User
model looks like this:
class User < ActiveRecord::Base
after_create :skip_conf!
# ...
def skip_conf!
self.confirm unless (Rails.env.production? && !ENV['STAGING'] == 'true') || Rails.env.test?
end
end
New testing code:
context 'in testing' do
before :each do
@user = User.new(
# params
)
end
it 'shouldn\'t skip confirmation' do
allow(Rails).to receive(:env).and_return(ActiveSupport::StringInquirer.new('development'))
@user.skip_conf!
expect(@user.confirmed?).to be_falsey
end
end
If I change user.skip_conf!
to user.skip_conf
(and write an empty skip_conf
method in my User
model), the test runs. Any ideas? I'm fine with just running this as an integration test if necessary, but I feel like it shouldn't be difficult to test a simple method with side-effects in RSpec.