Rspec - Undefined method 'allow' - ruby-on-rails

I am trying to stub the env variable to access Rails.env.production?
context 'Rails environment is production' do
it 'returns the correct api production service' do
allow(ENV).to receive(:[]).with('RAILS_ENV').and_return('production')
expect(application.api_domain).to eql('https://api.some_url.com')
end
end
but I always get this error
NoMethodError:
undefined method `allow' for #<RSpec::ExampleGroups::CesidApplication::CesidApplication::RailsEnvironmentIsDevelopment:0x00007fcc48cec518>
Did you mean? all
Module method im testing
module Cesid
module Application
def api_domain
uri = URI.parse(marketing_suite_url)
domain = PublicSuffix.parse(uri.host)
Rails.env.production? ? "https://api.#{domain.name}" : "https://api-#{domain.name}"
end
end
end
Rspec version
3.5.4
Any ideas?

Configure the expect syntax in spec_helper.rb like:
# spec_helper.rb
RSpec.configure do |config|
config.expect_with :rspec do |c|
c.syntax = :expect
end
end
Then the allow will work

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: FactoryBot is seeing duplicate definitions

I'm still new to using FactoryBot so I might be missing something. I am getting this error message:
Could it be due to improper set up in the spec_helper.rb file?
As for defining the user.rb factory, I tried including "associations: contracts" in the user.rb file. I'm still not sure if I should be doing that or is this current format fine for Rspec to pick up the association with contracts.rb?
Any help is appreciated! Thanks!
spec_helper.rb
require 'factory_bot_rails'
RSpec.configure do |config|
config.include FactoryBot::Syntax::Methods
FactoryBot.definition_file_paths = [File.expand_path('../factories', __FILE__)]
FactoryBot.find_definitions
# rspec-expectations config goes here. You can use an alternate
# assertion/expectation library such as wrong or the stdlib/minitest
# assertions if you prefer.
config.expect_with :rspec do |expectations|
spec/factories/users.rb
FactoryBot.define do
factory :user do
full_name "Test tester"
email "test#tester.com"
password "123456"
end
end
spec/factories/contracts.rb
FactoryBot.define do
factory :contract do
vendor "O2"
starts_on "2019-03-08"
ends_on "2019-03-10"
price 30
end
end
spec/requests/contracts_api_spec.rb
require 'rails_helper'
RSpec.describe "ContractsApi", type: :request do
describe "POST #create" do
before(:each) do
#user = FactoryBot.create(:user)
#current_user = AuthenticateUserCommand.call(#user.email, #user.password)
#contract = #current_user.contracts.create(vendor: "Lebara", starts_on: "2018-12-12", ends_on: "2018-12-14", price: "15")
end
it 'creates a new contract' do
expect { post api_v1_contracts_path, params: #contract }.to change(Contract, :count).by(1)
end
end
end
I believe you don't need to configure FactoryBot in your spec_helper.rb and what you are doing there maybe be causing FactoryBot to load the factories twice.
Try changing the content of spec_helper.rb to just:
RSpec.configure do |config|
config.include FactoryBot::Syntax::Methods
# rspec-expectations config goes here. You can use an alternate
# assertion/expectation library such as wrong or the stdlib/minitest
# assertions if you prefer.
config.expect_with :rspec do |expectations|
Also, considering that you are including FactoryBot::Syntax::Methods, in your tests you can simply use #user = create(:user) instead of #user = FactoryBot.create(:user)

Capybara error with Poltergeist and RSpec

I am trying to write a simple spec with Capybara using the Poltergeist driver in RSpec. There doesn't seem to be a problem when tests should fail , however when I am expecting a passing test I get the following error:
~/.rbenv/versions/2.2.3/lib/
ruby/gems/2.2.0/gems/poltergeist-1.6.0/lib/capybara/poltergeist/errors.rb:17:in
`initialize': wrong number of arguments (0 for 2) (ArgumentError)
I navigated to where the the line of code the error was indicating:
class JSErrorItem
attr_reader :message, :stack
def initialize(message, stack)
#message = message
#stack = stack
end
def to_s
[message, stack].join("\n")
end
end
But I was unable to find anywhere that I should be interacting with this constructor.
This is the spec that I am writing
describe 'Sign Up', type: :feature do
it 'should allow user creation through the signup form' do
visit new_user_url host: 'http://localhost:3000'
within('.form') do
fill_in('user[username]', with: 'Example')
fill_in('user[password]', with: 'Password')
fill_in('user[password_confirmation]', with: 'Password')
find(".submit-button").click
puts page.body
expect(page).to have_content('Welcome')
User.last.destroy!
end
end
end
The puts page prints the content of the page as expected but after the error occurs and the remainder of the lines in the spec are not run. Oddly enough the error only occurs when I am expecting the spec to pass. When I am expecting a failing test the entire spec runs without error.
My spec helper was set up as below:
RSpec.configure do |config|
require 'capybara/rspec'
require 'capybara/poltergeist'
require 'capybara/dsl'
Capybara.register_driver :poltergeist do |app|
Capybara::Poltergeist::Driver.new(app, time_out: 120, phantomjs_options: ['--ignore-ssl-errors=yes'], js_errors: false)
end
Capybara.configure do |c|
c.javascript_driver = :poltergeist
c.default_driver = :poltergeist
c.app_host = 'http://localhost:3000'
end
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
I upgraded Poltergeist to 1.9 and PhantomJS to 2.1 as suggested in the comments and it fixed the issue.

undefined method post for RSpec

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.

Warden not available in rspec tests when using Grape as a Rack application

I am having a problem getting the Warden's hash to appear in the request hash in my RSpec tests. When I run my application in development mode the Warden keys are there, but in the test environment everything is nil. I have included my basic rspec config below. If anyone has any ideas where I am going wrong I'd really like to know, I've been fiddling with this for almost a full-day.
When running in development mode Warden is found, but when running in test mode env['warden'] is always nil
Here is an example of what I get when I inpsect the warden hash inside request object during development mode:
request['warden']
=> Warden::Proxy:70272688271480 #config={:default_scope=>:default, :scope_defaults=>{}, :default_strategies=>{:_all=>[:password, :basic]}, :intercept_401=>true, :failure_app=>GrapeApe::BadAuthentication}
Here is what I get when I inspect the warden hash inside the request object during tests:
request['warden']
=> nil
Spec Helper File
require 'rubygems'
ENV["RACK_ENV"] ||= 'test'
require 'rack/test'
require 'capybara/rspec'
require 'factory_girl'
require File.expand_path("../../config/environment", __FILE__)
FactoryGirl.find_definitions
RSpec.configure do |config|
config.mock_with :rspec
config.expect_with :rspec
config.include Capybara::DSL
config.include Rack::Test::Methods
config.include Warden::Test::Helpers
config.after :each do
Warden.test_reset!
end
end
Capybara.configure do |config|
config.app = GrapeApe::App.new
config.server_port = 9293
end
Example Spec where warden should throw a 403 response because the user has not been authenticated.
it "should get a specfic sketch" do
get "/api/v1/sketches/#{#sketch.id}"
JSON.parse(last_response.body)['files'].should == ["foo"]
end
Example Error:
Failure/Error: JSON.parse(last_response.body)['files'].should == ["foo"]
JSON::ParserError:
756: unexpected token at 'undefined method `authenticated?' for nil:NilClass'
Relevant Grape helper methods where the warden keys are inspected
module GrapeApe
module Helpers
def warden
env['warden']
end
def authenticated
if warden.authenticated?
return true
elsif params[:access_token] and
User.find_for_token_authentication("access_token" => params[:access_token])
return true
else
error!('401 Unauthorized', 401)
end
end
def current_user
warden.user || User.find_for_token_authentication("access_token" => params[:access_token])
end
def authenticated_user
authenticated
error!('401 Unauthorized', 401) unless current_user
end
end
end

Resources