Rspec Undefined method 'should receive' - ruby-on-rails

I'm trying to use rspec with mongoid but I'm running across this error:
undefined method `should_receive' for ShortenedUrl:Class
Here's my spec_helper.rb file:
# This file is copied to spec/ when you run 'rails generate rspec:install'
ENV["RAILS_ENV"] ||= 'test'
require File.expand_path("../../config/environment", __FILE__)
require 'rspec/rails'
# Requires supporting ruby files with custom matchers and macros, etc,
# in spec/support/ and its subdirectories.
Dir[Rails.root.join("spec/support/**/*.rb")].each {|f| require f}
RSpec.configure do |config|
# == Mock Framework
#
# If you prefer to use mocha, flexmock or RR, uncomment the appropriate line:
#
# config.mock_with :mocha
# config.mock_with :flexmock
# config.mock_with :rr
config.mock_with :rspec
# Remove this line if you're not using ActiveRecord or ActiveRecord fixtures
# config.fixture_path = "#{::Rails.root}/spec/fixtures"
# If you're not using ActiveRecord, or you'd prefer not to run each of your
# examples within a transaction, remove the following line or assign false
# instead of true.
# config.use_transactional_fixtures = true
config.before(:each) do
Mongoid.master.collections.each(&:drop)
end
end
And here's my test file:
require 'spec_helper'
describe UrlsController do
describe "POST make_short" do
context "when posting a valid url" do
# url = mock('ShortenedUrl')
url = Struct.new('ShortenedUrl')
ShortenedUrl.should_receive(:new).with(:url => 'http://example.com').and_return(url)
url.should_receive(:save!)
post :make_short, :url => 'http://example.com'
end
end
end
Finally, here's the Gemfile:
source 'http://rubygems.org'
gem 'rails', '3.0.3'
gem "mongoid", ">= 2.0.0.beta.19"
gem "rspec-rails", ">= 2.0.1", :group => [:development, :test]
gem "cucumber-rails", :group => :test
gem "capybara", :group => :test
From what I understand, I should get this error if I wasn't using the rspec mock, but in my case I'm using it. Any ideas?

Your test needs to be inside an example or it block (they're the same method):
it "when posting a valid url" do
# url = mock('ShortenedUrl')
url = Struct.new('ShortenedUrl')
ShortenedUrl.should_receive(:new).with(:url => 'http://example.com').and_return(url)
url.should_receive(:save!)
post :make_short, :url => 'http://example.com'
end
A context block is used for grouping similar examples.

Related

Rspec undefined method `expects' for Object

I have recently upgraded my ruby on rails project to rails 5.0.7 and ruby 2.5.1 and I am getting an RSPEC error undefined methodexpects' for` different objects I am testing.
I have tried adding a configuration in the spec_helper.rb file as suggested here (although I did a quick search and didn't find :should defined anywhere), here and here:
config.expect_with :rspec do |expectations|
expectations.syntax = [:expect, :expects]
end
Also tried including include RSpec::Matchers in my spec_helper.rb, but then I get even more errors:
`only the `receive`, `have_received` and `receive_messages` matchers are supported with `expect(...).to`, but you have provided: #<RSpec::Matchers::BuiltIn::Eq:0x00007f962b3db058>`
An example of how I am using expect:
describe "process" do
before :each do
#item = Item.new
end
it "parses the uploaded file and extract the correct report data" do
item_a_data = {"name" => "one"}
item_b_data = {"name" => "two"}
file_contents = {"items" => [item_a_data, item_b_data]}
#item.data_file = double("file", :read => file_contents.to_json)
#item.name = item_a_data["name"]
#item.expects(:interpret_json_file).with(#item.data_file).returns(file_contents)
#item.expects(:save).returns(true)
expect(#item.process_data_file).to be_truthy
expect(#item.data).to eq item_a_data.to_json
end
Notice that the error occurs when I call #item.expects
In my Gemfile I have the following gems (among others):
group :development, :test do
gem 'byebug'
gem 'sqlite3'
gem 'rspec-rails'
gem 'rb-fsevent', '~> 0.9.1'
gem 'guard-rspec', '4.7.3'
gem 'guard-spork', '2.1.0'
gem 'spork', '0.9.2'
gem 'jasmine-rails'
gem 'teaspoon-jasmine'
end
group :test do
gem 'capybara'
gem 'cucumber-rails', :require => false
gem 'database_cleaner'
gem 'factory_girl_rails', '4.1.0'
gem 'launchy'
gem 'poltergeist'
gem 'timecop'
gem 'webmock'
gem 'simplecov', '~> 0.16.0'
gem 'rails-controller-testing'
end
spec_helper.rb:
require 'rubygems'
require 'spork'
#uncomment the following line to use spork with the debugger
#require 'spork/ext/ruby-debug'
Spork.prefork do
require 'simplecov'
SimpleCov.start 'rails'
# This file is copied to spec/ when you run 'rails generate rspec:install'
ENV["RAILS_ENV"] ||= 'test'
require File.expand_path("../../config/environment", __FILE__)
require 'rspec/rails'
require 'devise'
require './spec/controllers/controller_helpers.rb'
# Requires supporting ruby files with custom matchers and macros, etc,
# in spec/support/ and its subdirectories.
Dir[Rails.root.join("spec/support/**/*.rb")].each {|f| require f}
RSpec.configure do |config|
config.include Devise::Test::ControllerHelpers, type: :controller
config.include ControllerHelpers, type: :controller
config.include Capybara::DSL
# Remove this line if you're not using ActiveRecord or ActiveRecord fixtures
config.fixture_path = "#{::Rails.root}/spec/fixtures"
# If you're not using ActiveRecord, or you'd prefer not to run each of your
# examples within a transaction, remove the following line or assign false
# instead of true.
config.use_transactional_fixtures = true
# If true, the base class of anonymous controllers will be inferred
# automatically. This will be the default behavior in future versions of
# rspec-rails.
config.infer_base_class_for_anonymous_controllers = false
config.infer_spec_type_from_file_location!
# Run specs in random order to surface order dependencies. If you find an
# order dependency and want to debug it, you can fix the order by providing
# the seed, which is printed after each run.
# --seed 1234
config.order = "random"
config.include FactoryGirl::Syntax::Methods
# config.expect_with :rspec do |expectations|
# expectations.syntax = :expect
# end
end
end
Spork.each_run do
# This code will be run each time you run your specs.
end
The solution would be to re-write it to the following syntax:
expect(#item).to receive(:interpret_json_file).with(#item.data_file) { file_contents }
expect(#item).to receive(:save) { true }
Basically ActiveRecord model does not know about rspec expectations and it should not. If that specs were working before then you might used some decoration for ActiveRecord models and that is why it worked previously.

Factory not registered: user (ArgumentError)

I am using rspec-rails, factory_girl_rails and mogoid_rspec gems. After adding factory girl gem, I keep getting the error Factory not registered: user (ArgumentError) for my user factory. Following are the related code snippets:
In my Gemfile:
group :development, :test do
gem 'byebug'
gem 'rspec-rails'
gem 'mongoid-rspec', '~> 2.1.0'
end
group :test do
gem 'database_cleaner'
gem 'faker'
gem 'shoulda-matchers'
gem 'factory_girl_rails'
end
rails_helper.rb
# This file is copied to spec/ when you run 'rails generate rspec:install'
ENV['RAILS_ENV'] ||= 'test'
require File.expand_path('../../config/environment', __FILE__)
# Prevent database truncation if the environment is production
abort("The Rails environment is running in production mode!") if Rails.env.production?
require 'spec_helper'
require 'rspec/rails'
require 'factory_girl_rails'
FactoryGirl.definition_file_paths = [File.expand_path('../factories', __FILE__)]
FactoryGirl.find_definitions
require 'support/mongoid'
require 'support/factory_girl'
require 'support/disable_active_record_fixtures'
require 'mongoid-rspec'
ENV["RAILS_ENV"] ||= 'test'
RSpec.configure do |config|
config.before(:all) do
FactoryGirl.reload
end
config.include Mongoid::Matchers, type: :model
config.before(:suite) do
DatabaseCleaner[:mongoid].strategy = :truncation
end
config.before(:each) do
DatabaseCleaner[:mongoid].start
end
config.after(:each) do
DatabaseCleaner[:mongoid].clean
end
config.use_transactional_fixtures = false
config.infer_spec_type_from_file_location!
end
factories/user.rb
FactoryGirl.define do
factory :user do
first_name Faker::Name.first_name
last_name Faker::Name.last_name
email Faker::Internet.email
end
end
spec/support/factory_girl.rb
RSpec.configure do |config|
config.include FactoryGirl::Syntax::Methods
end
spec_helper.rb
RSpec.configure do |config|
config.expect_with :rspec do |expectations|
expectations.include_chain_clauses_in_custom_matcher_descriptions = true
end
config.mock_with :rspec do |mocks|
mocks.verify_partial_doubles = true
end
end
Any help would be much appreciated. Thanks in advance! :)
As we've discussed, I'm pasting my proposition of what you could change in your code (including good practices).
Define factory_girl_rails gem inside group :test, :development.
#Gemfile
group :development, :test do
gem 'byebug'
gem 'rspec-rails'
gem 'factory_girl_rails'
gem 'faker'
gem 'mongoid-rspec', '~> 2.1.0'
end
group :test do
gem 'database_cleaner'
gem 'shoulda-matchers'
end
Require your support files in one single line instead of multiply
definitions.
# spec/rails_helper.rb
ENV['RAILS_ENV'] ||= 'test'
require 'spec_helper'
require File.expand_path('../../config/environment', __FILE__)
require 'rspec/rails'
# Prevent database truncation if the environment is production
abort("The Rails environment is running in production mode!") if Rails.env.production?
Dir[Rails.root.join('spec/support/**/*.rb')].each { |f| require f }
RSpec.configure do |config|
config.before(:all) do
FactoryGirl.reload
end
config.include Mongoid::Matchers, type: :model
config.before(:suite) do
DatabaseCleaner[:mongoid].strategy = :truncation
end
config.before(:each) do
DatabaseCleaner[:mongoid].start
end
config.after(:each) do
DatabaseCleaner[:mongoid].clean
end
config.use_transactional_fixtures = false
config.infer_spec_type_from_file_location!
end
Create your .rspec file (or edit yours if you already have it) to
require spec_helper and rails_helper without having to call it manually in every single spec.
I'd also suggest for everyone to
color and format the spec output.
# .rspec
--color
--format documentation
--require spec_helper
--require rails_helper

Factory Not Registered in rspec but found in console

I have the followed
group :test, :development do
gem 'rspec-rails', '~> 3.0'
gem "guard-rspec"
gem 'capybara'
gem 'factory_girl_rails'
gem 'turn'
gem 'guard' # NOTE: this is necessary in newer versions
gem 'poltergeist'
gem 'phantomjs', :require => 'phantomjs/poltergeist'
gem 'selenium-webdriver'
gem 'capybara-screenshot'
gem 'capybara-webkit'
gem 'zeus'
gem "parallel_tests"
gem 'launchy'
gem 'email_spec'
gem 'action_mailer_cache_delivery'
gem 'protractor-rails'
gem 'database_cleaner'
and in my spec_helper.rb
require 'capybara/rspec'
require 'factory_girl_rails'
require 'support/request_helpers'
RSpec.configure do |config|
config.include FactoryGirl::Syntax::Methods
config.include RequestHelpers
config.expect_with :rspec do |expectations|
expectations.include_chain_clauses_in_custom_matcher_descriptions = true
end
config.mock_with :rspec do |mocks|
mocks.verify_partial_doubles = true
end
end
Finally I have such a spec helper in the spec/support/request_helper.rb
module RequestHelpers
def create_logged_in_user
user = create(:user)
login(user)
user
end
def login(user)
login_as user, scope: :user
end
end
and factories.rb
# /spec/factories/factories.rb
FactoryGirl.define do
factory :user do
first "John"
last 'Smith'
email 'test#example.com'
password 'johnsmith123'
end
end
Yes everytime I run rpsec it shows that
Factory not registered: user
And when I rune FactoryGirl.factories in the rails console, i can see 'user' is registered
=> #<FactoryGirl::Registry:0x007fa4e0e18160
#items=
{
:user=>
#<FactoryGirl::Factory:0x007fa4e2371200
#aliases=[],
#class_name=nil,
#compiled=false,
#definition=
#<FactoryGirl::Definition:0x007fa4e2370f58
#additional_traits=[],
#attributes=nil,
#base_traits=[],
#callbacks=[],
#compiled=false,
#constructor=nil,
#declarations=
#<FactoryGirl::DeclarationList:0x007fa4e2370ee0
#declarations=
[#<FactoryGirl::Declaration::Static:0x007fa4e2370b48 #ignored=false, #name=:first, #value="john">,
#<FactoryGirl::Declaration::Static:0x007fa4e2370a80 #ignored=false, #name=:last, #value="smith">,
#<FactoryGirl::Declaration::Static:0x007fa4e23709b8 #ignored=false, #name=:email, #value="test#example.com">,
I read through the Github setup docs for factory_girl_rails, rspec-rails multiple times but found no solution.
Does anyone know where I should look to detect the problem?
Thanks!
EDITED added contents of spec/rails_helper.rb updated Wed, 10 Jun 2015
ENV['RAILS_ENV'] ||= 'test'
require 'spec_helper'
require File.expand_path('../../config/environment', __FILE__)
require 'rspec/rails'
require 'capybara/poltergeist'
require 'capybara-screenshot/rspec'
Capybara.register_driver :poltergeist do |app|
Capybara::Poltergeist::Driver.new(app, :phantomjs => Phantomjs.path, :inspector => true)
end
Capybara.javascript_driver = :webkit
include Warden::Test::Helpers
RSpec.configure do |config|
config.infer_spec_type_from_file_location!
end
I had the same issue
Why is FactoryBot not finding our factories only inside RSpec, I do not know.
But making FactoryBot explicitly find my definitions worked.
So you just need to add this to your spec_helper:
FactoryBot.find_definitions
in my case, I followed the general instructions in this answer:
https://stackoverflow.com/a/49436531/8790125
So I create a file spec/support/factory_bot.rb
with this code (note the find_definitions):
require 'factory_bot'
RSpec.configure do |config|
config.include FactoryBot::Syntax::Methods
FactoryBot.find_definitions
end
and then required on rails_helper:
# ...
require 'rspec/rails'
require 'support/factory_bot'
# ...

undefined method `use_transactional_fixtures

I was following a long with this tutorial on how to test rails apps and I came across this error:
/home/***/***/***/spec/spec_helper.rb:27:in `block in <top (required)>': undefined method `use_transactional_fixtures=' for #<RSpec::Core::Configuration:0x9fe8824> (NoMethodError)
My gems are as follows:
gem "rspec-rails", :group => [:test, :development]
group :test do
gem "factory_girl_rails"
gem "capybara"
gem "guard-rspec"
end
and my config file is as follows:
# This file is copied to spec/ when you run 'rails generate rspec:install'
ENV["RAILS_ENV"] ||= 'test'
require File.expand_path("../../config/environment", __FILE__)
require 'rspec/rails'
require 'rspec/autorun'
require 'capybara/rspec'
# Requires supporting ruby files with custom matchers and macros, etc,
# in spec/support/ and its subdirectories.
Dir[Rails.root.join("spec/support/**/*.rb")].each {|f| require f}
RSpec.configure do |config|
# ## Mock Framework
#
# If you prefer to use mocha, flexmock or RR, uncomment the appropriate line:
#
# config.mock_with :mocha
# config.mock_with :flexmock
# config.mock_with :rr
# Remove this line if you're not using ActiveRecord or ActiveRecord fixtures
# config.fixture_path = "#{::Rails.root}/spec/fixtures"
# If you're not using ActiveRecord, or you'd prefer not to run each of your
# examples within a transaction, remove the following line or assign false
# instead of true.
config.use_transactional_fixtures = true
# If true, the base class of anonymous controllers will be inferred
# automatically. This will be the default behavior in future versions of
# rspec-rails.
config.infer_base_class_for_anonymous_controllers = false
# Run specs in random order to surface order dependencies. If you find an
# order dependency and want to debug it, you can fix the order by providing
# the seed, which is printed after each run.
# --seed 1234
config.order = "random"
end
so why am I getting this error when ever guard is run?
Might be because you are not using ActiveRecord (e.g you are using MongoId) and if that's the case you need to comment out *config.use_transactional_fixtures* in spec_helper
spec_helper.rb
# Remove this line if you're not using ActiveRecord or ActiveRecord fixtures
# config.fixture_path = "#{::Rails.root}/spec/fixtures"
# If you're not using ActiveRecord, or you'd prefer not to run each of your
# examples within a transaction, remove the following line or assign false
# instead of true.
# config.use_transactional_fixtures = true

Stub ssl_required so my RSpec will pass

I'm using bartt-ssl_requirement in a Rails 3.0.9 app.
The ssl_required and ssl_allowed statements at the top of my controllers are breaking my rspec with their redirects. How do I fix that?
From poking around, I can "stub" the ssl_required method in my spec_helper.rb (a new concept to me I don't thoroughly understand) to just return true and not do a redirect.
Gemfile (relevant):
gem 'rails', '3.0.9'
gem 'bartt-ssl_requirement', '~>1.4.0', :require => 'ssl_requirement'
group :test do
gem 'rspec-rails', '2.6.1'
gem 'spork', '0.9.0.rc8'
end
Controller:
class PagesController < ApplicationController
ssl_required :about
def about
#title = "About Us"
end
end
spec_helper.rb:
require 'rubygems'
require 'spork'
Spork.prefork do
ENV["RAILS_ENV"] ||= 'test'
require File.expand_path("../../config/environment", __FILE__)
require 'rspec/rails'
Dir[Rails.root.join("spec/support/**/*.rb")].each {|f| require f}
RSpec.configure do |config|
config.mock_with :rspec
config.fixture_path = "#{::Rails.root}/spec/fixtures"
config.use_transactional_fixtures = true
config.before(:each, :type => :controller) do
controller.stub(:ssl_required).and_return(:true)
end
end
end
If I comment out ssl_required in my controller, my tests pass. Otherwise they're still redirecting and ruining my shoulds.
Well, it doesn't answer my question about how to configure a stub in spec_helper.rb or whether that's even a good idea, but all I needed to do was add SslRequirement.disable_ssl_check = true to my test.rb environment.

Resources