How to include view helper in RSpec - ruby-on-rails

I have a module with a custom view helper. Actually it uses the modified code of link_to helper. Just append a query string to the generated link. I have existing tests which fails because the custom helper cannot be found. How can I include it so it is available for RSpec? I tried the following approaches:
1.Using include:
describe MyClass do
include MyHelper
2.Using configure
RSpec.configure do |config|
config.include MyHelper
end
3.Adding it in spec_helper.rb
config.include MyHelper
Here is the error:
1) Mailer#calendar_item_notification should send email for task
Failure/Error: expect {Mailer.calendar_item_notification('User', #user.id).deliver}.to change { ActionMailer::Base.deliveries.count }.by(1)
ActionView::Template::Error:
undefined method `<<' for #<Proc:0x00000013102d28>
# ./app/helpers/mailer_helper.rb:88:in `link_username'
# ./app/views/user_mailer/calendar_item_notification.html.erb:137:in `_app_views_user_mailer_calendar_item_notification_html_erb___206027131771876632_159436760'
# ./app/mailers/user_mailer.rb:136:in `calendar_item_notification'
# ./spec/mailers/user_mailer_spec.rb:19:in `block (4 levels) in <top (required)>'
# ./spec/mailers/user_mailer_spec.rb:19:in `block (3 levels) in <top (required)>'
# ./spec/support/misc.rb:13:in `block in suppress_output'
# ./spec/support/misc.rb:12:in `tap'
# ./spec/support/misc.rb:12:in `suppress_output'
# -e:1:in `<main>'
Thanks

Related

Rspec 'trait not registered error when using Faker

I am trying to use Faker in FactoryBot in my Rails API tests.
The issue I am having that I keep getting this error:
KeyError:
Trait not registered: "first_name"
So far as I can tell I have configured everything right, based on Faker'd docs at least. So far as I can tell I have two actual traits, valid_user and invalid_user that I set like so...
let(:valid_attributes) { FactoryBot.attributes_for :api_v1_user, :valid_user }
let(:invalid_attributes) { FactoryBot.attributes_for :api_v1_user, :invalid_user }
Which are linked to the :api_v1_user factory.
What have I missed or done wrong?
Full Error:
8) /api/v1/users PATCH /update with invalid parameters renders a JSON response with errors for the api/v1_user
Failure/Error: let(:invalid_attributes) { FactoryBot.attributes_for(:api_v1_user, :invalid_user) }
KeyError:
Trait not registered: "first_name"
# /home/etherk1ll/.rvm/gems/ruby-2.7.0/gems/activesupport-6.0.2.2/lib/active_support/hash_with_indifferent_access.rb:191:in `fetch'
# /home/etherk1ll/.rvm/gems/ruby-2.7.0/gems/activesupport-6.0.2.2/lib/active_support/hash_with_indifferent_access.rb:191:in `fetch'
# /home/etherk1ll/.rvm/gems/ruby-2.7.0/gems/factory_bot-5.1.2/lib/factory_bot/registry.rb:23:in `find'
# /home/etherk1ll/.rvm/gems/ruby-2.7.0/gems/factory_bot-5.1.2/lib/factory_bot/decorator.rb:10:in `method_missing'
# /home/etherk1ll/.rvm/gems/ruby-2.7.0/gems/factory_bot-5.1.2/lib/factory_bot/internal.rb:49:in `trait_by_name'
# /home/etherk1ll/.rvm/gems/ruby-2.7.0/gems/factory_bot-5.1.2/lib/factory_bot/definition.rb:114:in `trait_by_name'
# /home/etherk1ll/.rvm/gems/ruby-2.7.0/gems/factory_bot-5.1.2/lib/factory_bot/definition.rb:106:in `block in base_traits'
# /home/etherk1ll/.rvm/gems/ruby-2.7.0/gems/factory_bot-5.1.2/lib/factory_bot/definition.rb:106:in `map'
# /home/etherk1ll/.rvm/gems/ruby-2.7.0/gems/factory_bot-5.1.2/lib/factory_bot/definition.rb:106:in `base_traits'
# /home/etherk1ll/.rvm/gems/ruby-2.7.0/gems/factory_bot-5.1.2/lib/factory_bot/definition.rb:51:in `block in compile'
# /home/etherk1ll/.rvm/gems/ruby-2.7.0/gems/factory_bot-5.1.2/lib/factory_bot/definition.rb:50:in `compile'
# /home/etherk1ll/.rvm/gems/ruby-2.7.0/gems/factory_bot-5.1.2/lib/factory_bot/definition.rb:130:in `aggregate_from_traits_and_self'
# /home/etherk1ll/.rvm/gems/ruby-2.7.0/gems/factory_bot-5.1.2/lib/factory_bot/definition.rb:34:in `to_create'
# /home/etherk1ll/.rvm/gems/ruby-2.7.0/gems/factory_bot-5.1.2/lib/factory_bot/trait.rb:17:in `to_create'
# /home/etherk1ll/.rvm/gems/ruby-2.7.0/gems/factory_bot-5.1.2/lib/factory_bot/definition.rb:135:in `map'
# /home/etherk1ll/.rvm/gems/ruby-2.7.0/gems/factory_bot-5.1.2/lib/factory_bot/definition.rb:135:in `aggregate_from_traits_and_self'
# /home/etherk1ll/.rvm/gems/ruby-2.7.0/gems/factory_bot-5.1.2/lib/factory_bot/definition.rb:34:in `to_create'
# /home/etherk1ll/.rvm/gems/ruby-2.7.0/gems/factory_bot-5.1.2/lib/factory_bot/definition_hierarchy.rb:16:in `build_from_definition'
# /home/etherk1ll/.rvm/gems/ruby-2.7.0/gems/factory_bot-5.1.2/lib/factory_bot/factory.rb:125:in `build_hierarchy'
# /home/etherk1ll/.rvm/gems/ruby-2.7.0/gems/factory_bot-5.1.2/lib/factory_bot/factory.rb:88:in `compile'
# /home/etherk1ll/.rvm/gems/ruby-2.7.0/gems/factory_bot-5.1.2/lib/factory_bot/factory.rb:32:in `run'
# /home/etherk1ll/.rvm/gems/ruby-2.7.0/gems/factory_bot-5.1.2/lib/factory_bot/factory_runner.rb:29:in `block in run'
# /home/etherk1ll/.rvm/gems/ruby-2.7.0/gems/activesupport-6.0.2.2/lib/active_support/notifications.rb:182:in `instrument'
# /home/etherk1ll/.rvm/gems/ruby-2.7.0/gems/factory_bot-5.1.2/lib/factory_bot/factory_runner.rb:28:in `run'
# /home/etherk1ll/.rvm/gems/ruby-2.7.0/gems/factory_bot-5.1.2/lib/factory_bot/strategy_syntax_method_registrar.rb:20:in `block in define_singular_strategy_method'
# ./spec/requests/api/v1/users_spec.rb:6:in `block (2 levels) in <top (required)>'
# ./spec/requests/api/v1/users_spec.rb:92:in `block (4 levels) in <top (required)>'
# ./spec/rails_helper.rb:19:in `block (3 levels) in <top (required)>'
# /home/etherk1ll/.rvm/gems/ruby-2.7.0/gems/database_cleaner-1.8.4/lib/database_cleaner/generic/base.rb:16:in `cleaning'
# /home/etherk1ll/.rvm/gems/ruby-2.7.0/gems/database_cleaner-1.8.4/lib/database_cleaner/configuration.rb:87:in `block (2 levels) in cleaning'
# /home/etherk1ll/.rvm/gems/ruby-2.7.0/gems/database_cleaner-1.8.4/lib/database_cleaner/configuration.rb:88:in `cleaning'
# ./spec/rails_helper.rb:18:in `block (2 levels) in <top (required)>'
# ------------------
# --- Caused by: ---
# KeyError:
# key not found: "first_name"
# /home/etherk1ll/.rvm/gems/ruby-2.7.0/gems/activesupport-6.0.2.2/lib/active_support/hash_with_indifferent_access.rb:191:in `fetch'
spec/factories/api/v1/users.rb
require 'faker'
FactoryBot.define do
factory :api_v1_user, class: 'Api::V1::User' do
trait :valid_user do
first_name { Faker::Name.first_name }
second_name { Faker::Name.second_name }
username { Faker::Internet.username }
email { Faker::Internet.safe_email }
password { Faker::Internet.password(min_length: 8) }
end
trait :invalid_user do
first_name nil
end
end
end
rails_helper.rb
# This file is copied to spec/ when you run 'rails generate rspec:install'
require 'spec_helper'
ENV['RAILS_ENV'] ||= 'test'
require File.expand_path('../config/environment', __dir__)
# Prevent database truncation if the environment is production
abort("The Rails environment is running in production mode!") if Rails.env.production?
require 'rspec/rails'
RSpec.configure do |config|
config.use_transactional_fixtures = false
DatabaseCleaner.strategy = :truncation
config.around(:each) do |example|
DatabaseCleaner.cleaning do
example.run
end
end
config.before(:all) do
DatabaseCleaner.start
end
config.after(:all) do
DatabaseCleaner.clean
end
end
users_spec.rb
Truncated
RSpec.describe "/api/v1/users", type: :request do
let(:valid_attributes) { FactoryBot.attributes_for :api_v1_user, :valid_user }
let(:invalid_attributes) { FactoryBot.attributes_for :api_v1_user, :invalid_user }
let(:valid_headers) {
{}
}
describe "PATCH /update" do
context "with invalid parameters" do
it "renders a JSON response with errors for the api/v1_user" do
user = Api::V1::User.create! valid_attributes
patch api_v1_user_url(user),
params: { api_v1_user: invalid_attributes }, headers: valid_headers, as: :json
expect(response).to have_http_status(:unprocessable_entity)
expect(response.content_type).to eq("application/json")
end
end
end
end
Try wrapping the nil in brackets. FactoryBot eliminated support for static attributes in version 5, so if you're using a newer version, that'll be your problem. Brackets are now required.
trait :invalid_user do
first_name { nil }
end

undefined method `header` in RSpec

To learn API by using Rails I'm reading this tutorial.
In a part of RSpec test there is a method like this:
spec/support/authentication_helper.rb
module AuthenticationHelper
def sign_in(user)
header('Authorization', "Token token=\"#{user.authentication_token}\", email=\"#{user.email}\"")
end
def create_and_sign_in_user
user = FactoryGirl.create(:user)
sign_in(user)
user
end
alias_method :create_and_sign_in_another_user, :create_and_sign_in_user
end
RSpec.configure do |config|
config.include AuthenticationHelper, type: :api
end
And the test failed by undefined method `header'.
Where is this header method defined?
This is the whole source code of this tutorial.
https://github.com/vasilakisfil/rails_tutorial_api/
spec/apis/users_spec.rb
require 'rails_helper'
describe Api::V1::UsersController, type: :api do
context :show do
before do
create_and_sign_in_user
#user = FactoryGirl.create(:user)
get api_v1_user_path(#user.id), format: :json
end
it 'returns the correct status' do
expect(last_response.status).to eql(200)
end
it 'returns the data in the body' do
body = HashWithIndifferentAccess.new(MultiJson.load(last_response.body))
expect(body[:user][:name]).to eql(#user.name)
expect(body[:user][:updated_at]).to eql(#user.updated_at.iso8601)
end
end
end
StackTrace
1) Api::V1::UsersController show returns the correct status
Failure/Error: create_and_sign_in_user
NameError:
undefined local variable or method `request' for #<RSpec::ExampleGroups::ApiV1UsersController::Show:0x007fcbfec91d60>
# ./spec/support/authentication_helper.rb:4:in `sign_in'
# ./spec/support/authentication_helper.rb:9:in `create_and_sign_in_user'
# ./spec/apis/user_spec.rb:6:in `block (3 levels) in <top (required)>'
# ./spec/rails_helper.rb:39:in `block (3 levels) in <top (required)>'
# ./spec/rails_helper.rb:38:in `block (2 levels) in <top (required)>'
# -e:1:in `<main>'
2) Api::V1::UsersController show returns the data in the body
Failure/Error: create_and_sign_in_user
NameError:
undefined local variable or method `request' for #<RSpec::ExampleGroups::ApiV1UsersController::Show:0x007fcbfb7cfa28>
# ./spec/support/authentication_helper.rb:4:in `sign_in'
# ./spec/support/authentication_helper.rb:9:in `create_and_sign_in_user'
# ./spec/apis/user_spec.rb:6:in `block (3 levels) in <top (required)>'
# ./spec/rails_helper.rb:39:in `block (3 levels) in <top (required)>'
# ./spec/rails_helper.rb:38:in `block (2 levels) in <top (required)>'
# -e:1:in `<main>'
I had to add api_helper.rb to use the methods.
module ApiHelper
include Rack::Test::Methods
def app
Rails.application
end
end
RSpec.configure do |config|
config.include ApiHelper, type: :api #apply to all spec for apis folder
config.include Rails.application.routes.url_helpers, type: :api
end
Here is source code in Github.
https://github.com/vasilakisfil/rails_tutorial_api/blob/008af67e88897a5bcde714ce13d39a26ec70fba7/spec/support/api_helper.rb
In spec/support/auth_helpers.rb, you can try something like this
module AuthHelpers
def authenticate_with_user(user)
request.headers['Authorization'] = "Token token=#{user.token}, email=#{user.email}"
end
def clear_authentication_token
request.headers['Authorization'] = nil
end
end
In Rspec's spec/rails_helper.rb
Rspec.configure do |config|
config.include AuthHelpers, file_path: /spec\/apis/
end
An example test in spec/apis/users_controller_spec.rb:
require 'rails_helper'
describe Api::V1::UsersController, type: :controller do
let(:user) { create(:user) }
context 'signed in' do
before do
authenticate_with_user user
end
it 'does something' # tests here
end
end
Hope it helps!
Edit: Note the type: :controller is important

Why is my define_method not working?

I have two methods in my Designer class (in my rails app):
def add_specialty(specialty)
specialty_list.add(specialty)
save
end
def add_qualification(qualification)
qualification_list.add(qualification)
save
end
Here are specs I have for them that are passing:
context 'adding specialties' do
it "can add a new specialty" do
expect { designer.add_specialty("interior design") }.to change {designer.specialty_list.count}.by(1)
expect(designer.specialty_list).to include("interior design")
end
end
context 'adding qualifications' do
it "can add a new qualification" do
expect { designer.add_qualification("architect") }.to change {designer.qualification_list.count}.by(1)
expect(designer.qualification_list).to include("architect")
end
end
Now I want to refactor to this implementation:
["specialty", "qualification"].each do |attr|
define_method("add_#{attr}") do |arg|
"#{attr}_list".add(arg)
save
end
end
This fails. I get failures:
1) Designer adding qualifications can add a new qualification
Failure/Error: expect { designer.add_qualification("architect") }.to change {designer.qualification_list.count}.by(1)
NoMethodError:
undefined method `add' for "qualification_list":String
# ./app/models/designer.rb:93:in `block (2 levels) in <class:Designer>'
# ./spec/models/designer_spec.rb:79:in `block (4 levels) in <top (required)>'
# ./spec/models/designer_spec.rb:79:in `block (3 levels) in <top (required)>'
# -e:1:in `<main>'
2) Designer adding specialties can add a new specialty
Failure/Error: expect { designer.add_specialty("interior design") }.to change {designer.specialty_list.count}.by(1)
NoMethodError:
undefined method `add' for "specialty_list":String
# ./app/models/designer.rb:93:in `block (2 levels) in <class:Designer>'
# ./spec/models/designer_spec.rb:72:in `block (4 levels) in <top (required)>'
# ./spec/models/designer_spec.rb:72:in `block (3 levels) in <top (required)>'
# -e:1:in `<main>'
What am I doing wrong in my define_method implementation?
"#{attr}_list" by itself is just the string "specialty_list" or "qualification_list", and strings don't have an add method. I think you want to the send the specialty_list method e.g.
%w{ specialty qualification }.each do |attr|
define_method("add_#{attr}") do |arg|
send("#{attr}_list").add(arg)
save
end
end
Ok: I got it working like this:
["specialty", "qualification"].each do |attr|
define_method("add_#{attr}") do |arg|
instance_eval("#{attr}_list").send(:add, arg)
save
end
end
Not sure why this worked though or if its the right way to do it. Would anyone care to contribute towards a better understanding?

undefined method 'env' for nil:NilClass

This is what my spec file looks like: spec/api/v1/projects_spec.rb
require "spec_helper"
describe "/api/v1/projects", :type => :api do
context "projects viewable by this user" do
it "JSON" do
end
end
end
It contained a lot more but I deleted a lot of lines in an unsuccessful attempt to find the error which goes like this:
Failure/Error: Unable to find matching line from backtrace
NoMethodError: undefined method `env' for nil:NilClass
This piece of code is from the "Rails 3 in Action" by Ryan Bigg. The only other file it includes is: spec/support/api/helper.rb
module ApiHelper
include Rack::Test::Methods
def app
Rails.application
end
end
RSpec.configure do |c|
c.include ApiHelper, :type => :api
end
I've been trying to google the error for the past 1 hr and the closest thing that I found was this and as a result I deleted the code which used Devise::Test_Helpers. Sadly, its still not working.
Any help would be appreciated. Thank you so much.
Stack Trace
# /home/prakhar/.rvm/gems/ruby-1.9.2-p290/gems/devise-2.0.4/lib/devise/test_helpers.rb:24:in `setup_controller_for_warden'
# /home/prakhar/.rvm/gems/ruby-1.9.2-p290/gems/rspec-rails-2.8.1/lib/rspec/rails/adapters.rb:15:in `block (2 levels) in setup'
# /home/prakhar/.rvm/gems/ruby-1.9.2-p290/gems/rspec-core-2.8.0/lib/rspec/core/hooks.rb:35:in `instance_eval'
# /home/prakhar/.rvm/gems/ruby-1.9.2-p290/gems/rspec-core-2.8.0/lib/rspec/core/hooks.rb:35:in `run_in'
# /home/prakhar/.rvm/gems/ruby-1.9.2-p290/gems/rspec-core-2.8.0/lib/rspec/core/hooks.rb:70:in `block in run_all'
# /home/prakhar/.rvm/gems/ruby-1.9.2-p290/gems/rspec-core-2.8.0/lib/rspec/core/hooks.rb:70:in `each'
# /home/prakhar/.rvm/gems/ruby-1.9.2-p290/gems/rspec-core-2.8.0/lib/rspec/core/hooks.rb:70:in `run_all'
# /home/prakhar/.rvm/gems/ruby-1.9.2-p290/gems/rspec-core-2.8.0/lib/rspec/core/hooks.rb:368:in `run_hook'
# /home/prakhar/.rvm/gems/ruby-1.9.2-p290/gems/rspec-core-2.8.0/lib/rspec/core/example_group.rb:292:in `block in run_before_each_hooks'
# /home/prakhar/.rvm/gems/ruby-1.9.2-p290/gems/rspec-core-2.8.0/lib/rspec/core/example_group.rb:292:in `each'
# /home/prakhar/.rvm/gems/ruby-1.9.2-p290/gems/rspec-core-2.8.0/lib/rspec/core/example_group.rb:292:in `run_before_each_hooks'
# /home/prakhar/.rvm/gems/ruby-1.9.2-p290/gems/rspec-core-2.8.0/lib/rspec/core/example.rb:217:in `run_before_each'
# /home/prakhar/.rvm/gems/ruby-1.9.2-p290/gems/rspec-core-2.8.0/lib/rspec/core/example.rb:79:in `block in run'
# /home/prakhar/.rvm/gems/ruby-1.9.2-p290/gems/rspec-core-2.8.0/lib/rspec/core/example.rb:173:in `with_around_hooks'
# /home/prakhar/.rvm/gems/ruby-1.9.2-p290/gems/rspec-core-2.8.0/lib/rspec/core/example.rb:77:in `run'
# /home/prakhar/.rvm/gems/ruby-1.9.2-p290/gems/rspec-core-2.8.0/lib/rspec/core/example_group.rb:355:in `block in run_examples'
# /home/prakhar/.rvm/gems/ruby-1.9.2-p290/gems/rspec-core-2.8.0/lib/rspec/core/example_group.rb:351:in `map'
# /home/prakhar/.rvm/gems/ruby-1.9.2-p290/gems/rspec-core-2.8.0/lib/rspec/core/example_group.rb:351:in `run_examples'
# /home/prakhar/.rvm/gems/ruby-1.9.2-p290/gems/rspec-core-2.8.0/lib/rspec/core/example_group.rb:337:in `run'
# /home/prakhar/.rvm/gems/ruby-1.9.2-p290/gems/rspec-core-2.8.0/lib/rspec/core/example_group.rb:338:in `block in run'
# /home/prakhar/.rvm/gems/ruby-1.9.2-p290/gems/rspec-core-2.8.0/lib/rspec/core/example_group.rb:338:in `map'
# /home/prakhar/.rvm/gems/ruby-1.9.2-p290/gems/rspec-core-2.8.0/lib/rspec/core/example_group.rb:338:in `run'
# /home/prakhar/.rvm/gems/ruby-1.9.2-p290/gems/rspec-core-2.8.0/lib/rspec/core/command_line.rb:28:in `block (2 levels) in run'
# /home/prakhar/.rvm/gems/ruby-1.9.2-p290/gems/rspec-core-2.8.0/lib/rspec/core/command_line.rb:28:in `map'
# /home/prakhar/.rvm/gems/ruby-1.9.2-p290/gems/rspec-core-2.8.0/lib/rspec/core/command_line.rb:28:in `block in run'
# /home/prakhar/.rvm/gems/ruby-1.9.2-p290/gems/rspec-core-2.8.0/lib/rspec/core/reporter.rb:34:in `report'
# /home/prakhar/.rvm/gems/ruby-1.9.2-p290/gems/rspec-core-2.8.0/lib/rspec/core/command_line.rb:25:in `run'
# /home/prakhar/.rvm/gems/ruby-1.9.2-p290/gems/rspec-core-2.8.0/lib/rspec/core/runner.rb:80:in `run_in_process'
# /home/prakhar/.rvm/gems/ruby-1.9.2-p290/gems/rspec-core-2.8.0/lib/rspec/core/runner.rb:69:in `run'
# /home/prakhar/.rvm/gems/ruby-1.9.2-p290/gems/rspec-core-2.8.0/lib/rspec/core/runner.rb:10:in `block in autorun'
You're still including Devise::TestHelpers somewhere. Check and see what "spec_helper" is loading.
Instead of just including the Devise Test Helper, you can specify it's type, so that it's not included in routing spec:
config.include Devise::TestHelpers, :type => :helper
config.include Devise::TestHelpers, :type => :controller

Undefined method 'action' running single RSpec file for a rails controller

I have a peculiar situation - an rspec file fails when run independently, but run okay when run as part of the entire suite.
Failure/Error: visit oauth_callback_path
NoMethodError:
undefined method `action' for MyController:Class
# <internal:prelude>:10:in `synchronize'
# ./spec/requests/login_spec.rb:xx:in `block (5 levels) in <top (required)>'
# ./spec/requests/login_spec.rb:xx:in `block (4 levels) in <top (required)>'
Simplified spec:
require 'spec_helper'
class MyController
def oauth_response
sign_in(
ENV['TEST_ACCESS_TOKEN'],
ENV['TEST_ACCESS_SECRET'])
redirect_to root_path
end
end
describe 'logging in' do
it 'login' do
visit oauth_callback_path
response.should be_success
end
end
I believe the problem is that MyController is not extending ApplicationController. That's why the method action is not defined for MyController.
The class MyController appears to be blocking Rails magic class loading. Either the test should explicitly require the controller, or the extension should be defined with MyController.class_eval

Resources