undefined method post for RSpec - ruby-on-rails

I have this route:
post 'create', to: 'applications#create'
this controller:
class ApplicationsController < ApplicationController
def create
end
end
and this test:
require "spec_helper"
describe ApplicationsController do
describe "routing" do
it 'routes to #create' do
post('/applications').should route_to('applications#create')
end
end
end
and this is my spec_helper:
ENV["RAILS_ENV"] ||= 'test'
require File.expand_path("../../config/environment", __FILE__)
require 'rspec/rails'
ActiveRecord::Migration.maintain_test_schema!
RSpec.configure do |config|
config.expect_with :rspec do |c|
c.syntax = :should
end
config.mock_with :rspec do |c|
c.syntax = :should
end
config.use_transactional_fixtures = true
config.infer_base_class_for_anonymous_controllers = false
config.order = "random"
end
Why when I run
rspec ./spec/routing
I get this error?
Failure/Error: post('/applications').should route_to('applications#create')
NoMethodError:
undefined method `post' for RSpec
I tried changing the test using expect but with no luck. neither with a different class name.
What should I do to test my routes?
UPDATE
If I do this:
it "should return status 200" do
post('/applications'), {}
response.status.should be(200)
end
I get the same error

I am not sure it can help you but I had the same problem when passing to Rspec 3
According to https://relishapp.com/rspec/rspec-rails/docs/directory-structure
we should enable that option to pass automatically metadata.
​# spec/rails_helper.rb
RSpec.configure do |config|
config.infer_spec_type_from_file_location!
end
Once this was added my specs passed.

Related

Rails - Singleton class troubles with rspec feature

I have a problem testing a functionality that depends of a Singleton class. That class (ERPDao) is a suite with diferent methods that helps application to connect with external ERP vía REST services using Faraday gem. URLMaker is a helper class for build requests strings. When i try to run a feature spec that depends of one of this methods i have the following message in rspec:
Failure/Error: result = ERPDao.instance.get_credit_info(erp_id)
NoMethodError:
undefined method `instance' for ERPDao:Class
Did you mean? instance_of?
Did you mean? instance_of?
My class ERPDao
class ERPDao
def initialize
#end_points = EndPoint.first
#connection = Faraday.new(:url => #end_points.url_base, request: {
open_timeout: 10, # opening a connection
timeout: 10 # waiting for response
})
end
##instance = ERPDao.new
def self.instance
return ##instance
end
def get_credit_info(erp_id)
begin
return #connection.get URLMaker.instance.get_uri('credit_info', erp_id)
rescue Faraday::Error::ConnectionFailed => e
puts "Connection failed: #{e}"
return 0, false, 0
end
end
...
end
My rails_helper.rb
require 'spec_helper'
ENV['RAILS_ENV'] ||= 'test'
require File.expand_path('../../config/environment', __FILE__)
abort("The Rails environment is running in production mode!") if Rails.env.production?
require 'rspec/rails'
require 'support/factory_bot'
require 'support/wait_for_ajax'
ActiveRecord::Migration.maintain_test_schema!
RSpec.configure do |config|
config.fixture_path = "#{::Rails.root}/spec/fixtures"
config.use_transactional_fixtures = false
config.before :suite do
DatabaseCleaner.strategy = :truncation
end
config.before :each do
DatabaseCleaner.clean
end
config.infer_spec_type_from_file_location!
config.filter_rails_from_backtrace!
config.include Warden::Test::Helpers
config.include Devise::TestHelpers, type: :controller
Shoulda::Matchers.configure do |config|
config.integrate do |with|
with.test_framework :rspec
with.library :rails
end
end
Capybara.javascript_driver = :webkit
Capybara::Webkit.configure do |config|
config.debug = false
config.allow_unknown_urls
config.skip_image_loading
config.timeout = 15
config.raise_javascript_errors = false
end
end
My version of rails is 4.2.6, ruby 2.3.1, factory_bot 4.8.2 and rspec-rails 3.7.
Someone knows about this error?
Thanks!
ERPDao is [also] being defined somewhere else. Maybe someone decided to add a method to it by re-opening the class like
class ERPDao
def some_new_method
...
end
end
Don't do that. Use modules and prepend instead.
module HasMyNewMethod
def some_new_method
...
end
end
ERPDau.prepend HasMyNewMethod
Otherwise you end up accidentally referencing the re-opening of the class and that becomes the definition - so the autoloader doesn't load it since it's already defined.
Search your codebase for 'class ERPDao'. Modify the ones that are not the initial declaration.

RSpec test not hitting view with render_view

I am getting this error when using RSpec to test an index action and response in a Rails controller:
JSON::ParserError:
A JSON text must at least contain two octets!
The most common fix -- including render_views -- is not working and nil is not being passed in. The test is not hitting the view. When I insert render json: {test: 'hello world'}, status: 200 and return in the index action of the controller, and a pry in the view (index.json.jbuilder) and after the get :index in the test, I can see there is a response body. If I amend the test expectation to expect(response).to render_template '[]' I can see the empty array that should be in the response body. Why is render_views failing and how to I get it working again?
Here is the index_spec.rb:
require 'rails_helper'
RSpec.describe ThingsController, type: :controller do
render_views
let(:json_response) { JSON.parse(response.body) }
let(:status) { response.status }
let(:user) { create(:user_with_associations) }
subject{ ThingsController }
describe "GET #index" do
context "(success cases)" do
before(:each) do
expect_any_instance_of(subject).to receive(:set_user_by_token).and_return(user)
end
context "and when there are no things" do
before(:each) do
get :index
end
it "returns a 200 status" do
expect(status).to eq 200
end
it "returns a top level key of data with an empty array" do
expect(json_response["data"]).to eq []
end
end
end
end
Here is the rails_helper.rb:
ENV["RAILS_ENV"] ||= 'test'
require_relative 'spec_helper'
require File.expand_path("../../config/environment", __FILE__)
require 'rspec/rails'
ActiveRecord::Migration.maintain_test_schema!
RSpec.configure do |config|
config.fixture_path = "#{::Rails.root}/spec/fixtures"
config.use_transactional_fixtures = true
config.before(:suite) do
DatabaseCleaner.strategy = :transaction
DatabaseCleaner.clean_with(:truncation)
end
config.before(:each) do
DatabaseCleaner.start
end
config.after(:each) do
DatabaseCleaner.clean
end
config.infer_spec_type_from_file_location!
end
And here is the spec_helper.rb
ENV["RAILS_ENV"] ||= 'test'
require 'factory_girl_rails'
require 'faker'
include ActionDispatch::TestProcess
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
config.include FactoryGirl::Syntax::Methods
config.before do
FactoryGirl.factories.clear
FactoryGirl.find_definitions
end
end
And here's the controller action under test things_controller.rb:
class ThingsController < ApplicationController
before_action :authenticate_user!, only: [ :index ]
before_action -> {check_last_updated("Thing")}, only: [ :index ]
def index
#things = #current_user.things.in_last_three_months.approved_and_unapproved.order(start_time: :asc)
end
end
Rails 4.2.0
Ruby 2.1.2
RSpec 3.5.4
This is my first question here, so let me know if there is other information that should be included.
You're not correctly stubbing out the authentication in your spec. You say
expect_any_instance_of(subject).to receive(:set_user_by_token).and_return(user)
but you should say
allow_any_instance_of(subject).to receive(:set_user_by_token).and_return(user)
As a general rule, *_any_instance_of methods should be avoided if possible because they can be ambiguous in more nuanced situations. In controller specs, you can use controller to access the instance of the controller being tested. e.g.
allow(controller).to receive(:set_user_by_token).and_return(user)

Why do I receive this RSpec error when I try to create a factory?

**Update*: Scroll to very bottom for reproducible error in bare minimum rails app*
I am testing a rails task with Rspec, the fantaskspec gem, and the Factory Girl. When I try to run tests I receive this error:
1) update_account_reverification_table update_account_reverification_table
Failure/Error: account = create(:account, twitter_id: 1234567890)
NoMethodError:
undefined method `create' for #<RSpec::ExampleGroups::UpdateAccountReverificationTable:0x007fda1bd07710>
# ./spec/lib/tasks/account_reverification_spec.rb:18:in `block (2 levels) in <top (required)>'
On line, 18 of my account_reverification_spec.rb file I have this test.
it 'update_account_reverification_table' do
# binding.pry
account = create(:account, twitter_id: 1234567890)
Account.first.reverification.twitter_reverification_sent_at.must_equal Time.now
Account.first.reverification.twitter_reverified.must_equal true
end
I have also tried this variation but the test continues to fail:
account = FactoryGirl.create(:account, twitter_id: 1234567890)
However I receive a different error:
1) update_account_reverification_table update_account_reverification_table
Failure/Error: account = FactoryGirl.create(:account, twitter_id: 1234567890)
ArgumentError:
Factory not registered: account
Here is my spec_helper.rb and my rails_helper.rb
require 'fantaskspec'
require 'factory_girl_rails'
require 'pry-rails'
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
config.infer_rake_task_specs_from_file_location!
end
and rails_helper.rb
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'
ActiveRecord::Migration.maintain_test_schema!
RSpec.configure do |config|
# Remove this line if you're not using ActiveRecord or ActiveRecord fixtures
config.include FactoryGirl::Syntax::Methods
FactoryGirl.definition_file_paths = [File.expand_path('../factories', __FILE__)]
FactoryGirl.find_definitions
config.fixture_path = "#{::Rails.root}/spec/fixtures"
config.use_transactional_fixtures = true
end
Note that I have these lines in my rails_helper.rb file:
config.include FactoryGirl::Syntax::Methods
FactoryGirl.definition_file_paths = [File.expand_path('../factories', __FILE__)]
FactoryGirl.find_definitions
I grabbed this from a previous answer on a different problem referenced here Specific config problem Any ideas?
-----EDIT #2------
I have created a brand new basic example app to help figure out where this problem could potentially be. I have followed the instructions to set up my directory and tree structure using these documentation links.
Rspec
Factory Girl Rails
Fantaskspec
Tutorial on Rspec and Fantaskspec
Directory tree structure:
spec
- factories
- accounts.rb
- lib
- tasks
- account_reverification_spec.rb
- support
- factory_girl.rb
- rails_helper.rb
- spec-helper.rb
Contents of spec/support/factory_girl.rb
RSpec.configure do |config|
config.include FactoryGirl::Syntax::Methods
end
Contents of spec/factories/accounts.rb
FactoryGirl.define do
sequence :account_login do |n|
"login-#{ n }"
end
factory :account do
sequence :email do |n|
"someone#{n}#gmail.com"
end
email_confirmation { |account| account.send :email }
url { Faker::Internet.url }
login { generate(:account_login) }
password { Faker::Internet.password }
password_confirmation { |account| account.send(:password) }
current_password { |account| account.send(:password) }
twitter_account 'openhub'
name { Faker::Name.name + rand(999_999).to_s }
about_raw { Faker::Lorem.characters(10) }
activated_at { Time.current }
activation_code nil
country_code 'us'
email_master true
email_kudos true
email_posts true
end
end
Contents of spec/lib/tasks/account_reverification_spec.rb
require 'rails_helper'
RSpec.describe 'update_account_reverification_table' do
let(:task_name) { 'update_account_reverification_table' }
it 'correct task is called' do
expect(subject).to be_a(Rake::Task)
expect(subject.name).to eq("update_account_reverification_table")
expect(subject).to eq(task)
end
it 'update_account_reverification_table' do
account = create(:account, twitter_id: 1234567890)
end
end
Contents of rails_helper.rb
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 'fantaskspec'
ActiveRecord::Migration.maintain_test_schema!
RSpec.configure do |config|
Rails.application.load_tasks
config.infer_rake_task_specs_from_file_location!
config.fixture_path = "#{::Rails.root}/spec/fixtures"
config.use_transactional_fixtures = true
end
Contents of 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
Try adding the following line to your spec_helper.rb file:
require 'factory_girl'
Also, add these lines to your spec_helper.rb:
FactoryGirl.definition_file_paths.clear
FactoryGirl.definition_file_paths << File.expand_path('../factories', __FILE__)
FactoryGirl.find_definitions
and remove them from RSpec.configure do |config| block.
Also, make sure you defined your factories in the correct file. It should be defined in factories.rb in your test folder (spec) if you use rspec.
Update
FactoryGirl.definition_file_paths.clear
FactoryGirl.definition_file_paths << "./spec/factories"
FactoryGirl.find_definitions
These lines should go to your spec/support/factory_girl.rb file and remove them from anywhere else.
Also, add the following in your spec_helper.rb:
config.before(:all) do
FactoryGirl.reload
end
In your spec_helper.rb the Rspec.configure block should look like this:
RSpec.configure do |config|
config.mock_with :rspec
config.run_all_when_everything_filtered = true
config.filter_run :focus
config.include FactoryGirl::Syntax::Methods
end
Update
Add this to your rails_helper.rb:
require_relative 'support/factory_girl.rb'
And then it should work.

Include custom module in RSpec

I read tutorial from How-To:-Stub-authentication-in-controller-specs
And try to write some code but it didn't work. Can anybody help me to understand? Thank you
spec/support/authen_helper.rb
module AuthenHelper
def sign_in(user = double('user'))
if user.nil?
allow(request.env['warden']).to receive(:authenticate!).and_throw(:warden, {:scope => :user})
allow(controller).to receive(:current_user).and_return(nil)
else
allow(request.env['warden']).to receive(:authenticate!).and_return(user)
allow(controller).to receive(:current_user).and_return(user)
end
end
def sign_in_as_admin(user = double('user'))
allow(user).to receive(:role?).with('admin').and_return(true)
allow(request.env['warden']).to receive(:authenticate!).and_return(user)
allow(controller).to receive(:current_user).and_return(user)
end
end
rails_helper.rb
ENV["RAILS_ENV"] ||= 'test'
require 'spec_helper'
require File.expand_path("../../config/environment", __FILE__)
ActiveRecord::Migration.maintain_test_schema!
RSpec.configure do |config|
config.fixture_path = "#{::Rails.root}/spec/fixtures"
end
spec_helper.rb
require 'rubygems'
ENV["RAILS_ENV"] ||= 'test'
require File.expand_path("../../config/environment", __FILE__)
require 'rspec/rails'
require 'rspec/autorun'
Dir[Rails.root.join("spec/support/**/*.rb")].each {|f| require f}
RSpec.configure do |config|
config.expect_with :rspec
config.mock_with :rspec
config.filter_run :focus
config.run_all_when_everything_filtered = true
config.order = :random
config.color = true
config.use_transactional_fixtures = false
config.infer_spec_type_from_file_location!
config.include AuthenHelper, :type => :controller
end
spec/controllers/api/v1/user_controller_spec.rb
require 'rails_helper'
module API
module V1
describe User, :type => :controller do
sign_in
end
end
end
Error:
undefined local variable or method `sign_in' for RSpec::ExampleGroups::APIV1User:Class (NameError)
You should write the test inside an it block:
describe User, :type => :controller do
it 'signs in' do
sign_in
end
end
If you want to do this before any test, you should do it inside a before block:
describe User, :type => :controller do
before(:each) do
sign_in
end
end

FactoryGirl objects not being dropped after tests. Please review my test setup

Objects are persisting after tests run. I confirmed by doing a PowerUp.all.count test and the count increases by 2 on each run, which a number equal to the objects created for the test on each run. I don't know if I'm misusing FactoryGirl, or if I have a misconfigured spec_helper.
spec/support/factory_girl.rb:
RSpec.configure do |config|
config.include FactoryGirl::Syntax::Methods
end
spec/rails_helper.rb:
ENV["RAILS_ENV"] ||= 'test'
require 'spec_helper'
require File.expand_path("../../config/environment", __FILE__)
require 'rspec/rails'
Dir[Rails.root.join("spec/support/**/*.rb")].each { |f| require f }
ActiveRecord::Migration.maintain_test_schema!
RSpec.configure do |config|
config.fixture_path = "#{::Rails.root}/spec/fixtures"
config.use_transactional_fixtures = false
config.infer_base_class_for_anonymous_controllers = false
config.infer_spec_type_from_file_location!
end
spec/spec_helper.rb:
ENV["RAILS_ENV"] ||= 'test'
require File.expand_path("../../config/environment", __FILE__)
require 'rspec/rails'
require 'factory_girl'
RSpec.configure do |config|
config.order = :random
config.before(:all) do
FactoryGirl.reload
end
Kernel.srand config.seed
config.expect_with :rspec do |expectations|
expectations.syntax = :expect
end
config.mock_with :rspec do |mocks|
mocks.syntax = :expect
mocks.verify_partial_doubles = true
end
end
spec/api/power_up_spec.rb:
describe Api::PowerUpsController, :type => :controller do
describe "GET power_ups" do
it "returns all power-ups" do
FactoryGirl.create :power_up, name: "Increase rate of take", description: "You gain points more quickly"
FactoryGirl.create :power_up, name: "Decrease rate of give", description: "You lose points more slowly"
get :index, :format => :json
expect(response.status).to eq 200
body = JSON.parse(response.body)
power_up_names = body.map { |m| m["name"] }
expect(power_up_names).to match_array(["Increase rate of take",
"Decrease rate of give"])
end
end
end
config.use_transactional_fixtures = false
This turns off the default behavior, which is to rollback transactions after each example. When set to false RSpec does not attempt to manage the test database.
You can use database_cleaner to remove the rows created by tests when RSpec is not using transactions. This is often used when writing feature specs.

Resources