Set local variable rspec helper - ruby-on-rails

I am trying to set local variable in view helper through rspec. My routine is as follow
def time_format(time)
now = Time.now.in_time_zone(current_user.timezone)
end
My spec file is as follow:
it 'return 12 hour format' do
user = User.first
assign(:current_user, user)
expect(helper.time_format(900)).to eq('9:00 AM')
end
Spec is failing throwing me error undefined local variable or method 'current_user'
'current_user' resided in application_controller

Problem
Your current_user method is not available in your rspec test. That's why you are getting the mentioned error.
Solution
You either can implement current_user method inside a test helper and then use that in your test, or you can stub current_user in your spec test like this:
let(:user) { User.new }
# RSpec version >= 3 syntax:
before { allow(controller).to receive(:current_user) { user } }
before { allow(view).to receive(:current_user) { user } }
# RSpec version <= 2 syntax:
before { controller.stub(:current_user) { user } }
before { view.stub(:current_user) { user } }
This should fix your problem.
Also, if you are using devise for authentication, then I would recommend you to take a look at: How To: Test controllers with Rails 3 and 4 (and RSpec).

The following was modified from the RSpec-core 3.10 docs.
Create a new setting for RSpec.configure called my_variable, and give it a value, like this:
# spec/spec_helper.rb
RSpec.configure do |config|
config.add_setting :my_variable
config.my_variable = "Value of my_variable"
end
Access settings like class variables in RSpec.configuration from your test:
# spec/my_spec.rb
RSpec.describe(MyModule) do
it "creates an instance of something" do
my_instance = MyModule::MyClass.new(RSpec.configuration.my_variable)
end
end

Related

How to stub zendesk_api current_user for a spec?

I have a model method which I am trying to write a spec for. The method is like this:
def my_method
puts current_user.user_attirbute
end
Where current_user is provided by an authentication gem, zendesk_api-1.14.4. To make this method testable, I changed it to this:
def my_method(user_attribute = nil)
if user_attribute = nil
user_attribute = current_user.user_attribute
end
puts user_attribute
end
This refactor works and is testable, but doesn't seem like a good practice. Ideally the gem would provide some sort of test helper to help stub/mock the current_user, but I haven't been able to find anything. Any suggestions?
You can go simple way and just test returning of proper value by current_user#user_attribute method. Example:
describe '#my_method' do
subject { instance.my_method } # instance is an instance of your class where #my_method is defined
let(:user) { instance_spy(ZendeskAPI::User, user_attribute: attr) }
let(:attr} { 'some-value' }
before do
allow(instance).to receive(:current_user).and_return(user)
end
it { is_expected.to eq(attr) }
end
But I would go with VCR cassette(vcr gem is here) because it is related 3rd party API response - to minimize a risk of false positive result. Next example demonstrates testing with recorded response(only in case if #current_user method performs a request to zendesk):
describe '#my_method', vcr: { cassette_name: 'zendesk_current_user' } do
subject { instance.my_method }
it { is_expected.to eq(user_attribute_value) } # You can find the value of user_attribute_value in recorded cassette
end
P.S. I assumed that you put puts in your method for debugging. If it is intentional and it is part of the logic - replace eq with output in my example.

Rspec: how to create a method to call and create all mocks?

I am using Rspec to test my rails application and FactoryBot (new nome for factory girl) to create mocks. But in each file I need to call a lot of mocks. And it's almost the something, call some mocks, create an user, login and confirm this user. Can I create a method to call all this mocks, login and confirm the user? Then I just need to call this method.
Here is what I call in each rspec file:
let!(:nivel_super) { create(:nivel_super) }
let!(:gestora_fox) { create(:gestora_fox) }
let!(:user_mock) { create(:simple_super) }
let!(:super_user) { create(:super_user,
nivel_acesso_id: nivel_super.id, gestora_id: gestora_fox.id) }
let!(:ponto_venda) { create(:ponto_venda1) }
let!(:tipo_op) { create(:tipo_op) }
before(:each) do
#request.env["devise.mapping"] = Devise.mappings[:user]
super_user.confirm
sign_in super_user
end
I'm thinking something like:
def call_mocks
# put the code above
end
Than in each rspec file:
RSpec.describe OrdemPrincipalsController, type: :controller do
describe 'Ordem Principal tests' do
call_mocks
it 'go to new page' do
# my test
end
end
end
You should simply use shared context for that
https://relishapp.com/rspec/rspec-core/v/3-4/docs/example-groups/shared-context
It is similar to shared_example but for context which is what you want
Nevertheless, you you got exactly the same setting for a lot of tests, consider putting them together in the same context
Enjoy :)

Cannot make rails spec for a request working : `undefined method 'call' for #<App:`

I'm trying make the specs work on a project. There was a setup for specs but was not maintain.
I have a simple post for a request spec
require 'rails_helper'
RSpec.describe 'Cars API', type: :request do
let(:organization) { Fabricate(:organization, owner: user) }
let(:app) { Fabricate(:app, organization: organization, owner: user) }
let(:user) { Fabricate(:user) }
before do
#login_api(user)
end
describe 'create' do
describe 'car type' do
it 'should create a car of type CarType1' do
expect(Car.count).to eql(0)
id = '123'
post("/api/1/organization/#{id}/cars")
expect(Car.count).to eql(1)
car = Car.first
expect(car.type).to eql(Car::CarType1)
end
end
end
end
And I get
#<NoMethodError: undefined method `call' for #<App:0x007fee64557080>>
I've tried to debug the issue but with no luck.
The issue happens at the line post("/api/1/organization/#{id}/cars").
Where might the problem be ?
I had such problem ;) (and spent several hours for debugging sources)
Try to rename app to ap or similar variable.
# "bad" name
let(:app) { ... }
# "better" name
let(:ap) { ... }
# or
let(:my_app) { ... }
As I understood the problem in variable name when RSpec initializes your lazy block let. Not sure but I think at that moment App has already initialized and RSpec send method call not to block from let but to another object.
Note: you can use before block and use instance variable #app
This issue is occuring because you are overriding the Rails app variable. Rename the variable to something else. It will work.
By default in rails, app variable is your Rails application which has call method that will be invoked whenever your application receives any request from Rack middleware.

Passing a model instance to a helper method in rspec testing

I have a helper method in my app located in spec/support/utilities.rb
I am trying to pass an instance of a model object to it but I haven't succeeded so the tests fail
here is the helper method
def attribute_not_present(model_instance,model_attrib)
describe "when #{model_attrib} is not present" do
before { model_instance.send("#{model_attrib}=", " ") }
it { should_not be_valid }
end
end
in spec/model/tool_spec.rb i have this
require 'spec_helper'
describe Tool do
before do
#tool = FactoryGirl.create(:tool)
end
#attribute_array = ["kind", "serial_number", "department", "size",
"description", "hours", "length"]
subject { #tool }
#checks for absence of any of the required attributes
#attribute_array.each { |tool_attribute|
attribute_not_present(#tool,tool_attribute)
}
end
the #tool seems not to be recognized in the helper
the sample failure is this
1) Tool when size is not present
Failure/Error: before { model_instance.send("#{model_attrib}=", " ") }
NoMethodError:
undefined method `size=' for nil:NilClass
# ./spec/support/utilities.rb:3:in `block (2 levels) in attribute_not_present'
I am rails newbie
At the point where attribute_not_present is called, #tool does not yet exist. Moreover, in one case self is the example group, where when the spec is actually run (and inside your before blocks) self is an instance of the example group.
You don't need to pass model_instance through at all though - you could instead just use subject i.e.
before { subject.send("#{model_attrib}=", " ") }
however.
You may also want to look at shared examples.
Ok - I think I understand what you're trying to do here. You're trying to do unit tests, specifically validations on your Tool class, is that right?
If so, I personally like to use the shoulda_matchers gem which I find to be very idiomatic with exactly this.
As an example, you could do:
describe Tool do
it { should validate_presence_of(:kind) }
it { should validate_presnece_of(:serial_number) }
end
You can even do more with the validations, say you knew the :serial_number can only be an integer, you could do:
it { should validate_numericality_of(:serial_number).only_integer }
This is probably a better way to do unit level validations than a helper method as it's more Ruby-like.

Rspec-rails 4 error: ActiveModel::ForbiddenAttributesError

I have an application running in rails 4.1 using mongoid as the orm. I created a model called User which has an attribute email. I am using RSpec for tests. I created the following spec
require 'spec_helper'
describe 'User' do
before(:each) do
#attr = {
user: {
email: "rahul#gmail.com"
}
}
end
it "should create a valid User instance" do
param = ActionController::Parameters.new(#attr)
param.require(:user).permit!
User.create!(param)
end
end
when I run the spec, I get the following error
Failure/Error: User.create!(param)
ActiveModel::ForbiddenAttributesError:
ActiveModel::ForbiddenAttributesError
I know this is related to strong parameters but couldn't figure out what I am doing wrong.
From the fine manual:
require(key)
[...] returns the parameter at the given key [...]
So saying param.require(:user) does nothing at all to param, it merely does an existence check and returns param[:user].
I think you want to say something more like this:
param = ActionController::Parameters.new(#attr)
User.create!(param.require(:user).permit!)
That usage would match the usual:
def some_controller_method
#user = User.create(user_param)
end
def user_param
param.require(:user).permit!
end
usage in controllers.

Resources