0

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.

mammothbane
  • 275
  • 5
  • 11

1 Answers1

0

What about stubing env on Rails, not test? etc. on env.

before do 
  rails_env = "test".inquirer
  allow(Rails).to receive(:env).and_return(rails_env)
end
Kris
  • 19,188
  • 9
  • 91
  • 111