This seems to be a common issue, but I've looked at undefined method `visit' when using RSpec and Capybara in rails and Rails Rspec error - undefined method `visit' and neither solution works for me.
Capybara is working just fine for the Cucumber tests I have under /features.
My RSpec test is in /spec/features and begins:
require 'rails_helper'
describe 'session_project', type: :controller do
before(:each) do
#user = User.create(
username: 'user',
password: 'test',
password_confirmation: 'test',
email: 'user#example.com',
role: 3
)
#project = Project.create(name: 'Project 1', active: true, user_id: #user.id)
end
context 'when I am on the view Project 1 page' do
before do
visit '/projects'
find(:xpath, %{//tr[td='Project 1']/td[#class='list_actions']/a[text()='View']}).click
end
# ... and so on.
The line visit '/projects' is giving me the error Undefined method 'visit
If I include config.include Capybara::DSL in my RSpec configuration it complains that Capybara is an undefined constant, so perhaps RSpec is looking in the wrong place for it?
Any ideas on how I can get RSpec working with Capybara?
Your test is a feature test (it describes how a user interacts with the app in a browser), and yet it's tagged with type: :controller. Change it to type: :feature.
Feature specs also include Capybara by default.
https://www.relishapp.com/rspec/rspec-rails/v/3-1/docs/feature-specs/feature-spec
Related
I have AWS and Paperclip working successfully in one model, now I am trying to add it to another. Currently I am getting a undefined method "fields" for nil:NilClass error on this bit of code in my projects/form:
<%= form_for #project, html: { multipart: true, class: "directUpload", data: {
'form-data' => (#s3_direct_post.fields), // <-- err: #s3_direct_post is nil
'url' => #s3_direct_post.url,
'host' => URI.parse(#s3_direct_post.url).host }
} do |f| %>
In my projects controller I have included this private method:
def set_s3_direct_post
#s3_direct_post = S3_BUCKET.presigned_post(key: "uploads/#{SecureRandom.uuid}/${filename}", success_action_status: '201', acl: 'public-read')
end
and included :image in my controllers params.require()
Unfortunately I am not finding many threads on this error on SO and none have a conclusive solution. This same bit of code is currently working fine in the other model, yet it seems that the method in the projects controller (only) is not being read? It's the exact same code and setup as the Users controller. How do I fix this?
Some additional info:
I am reusing the code in application.js, config/initializers/aws.rb, and I am using the same bucket for multiple controllers (for now), as well as the same AWS credentials as I did for the model in which paperclip/aws is working
I have restarted my server a couple times
I am using rails 4.2.3, paperclip 5.0 and aws-sdk 2.3
Any additional info needed I will be happy to supply. Thanks :)
Answer: I forgot to set my before_action in my controller
before_action :set_s3_direct_post, only: [:new, :edit, :create, :update]
I've got a rails 4.2 application with rspec-rails 3.5.1
I've got feature specs in spec/features/<module>/<feature>_spec.rb
When I run
bin/rspec
or
bin/rake spec
the feature specs do not run.
They run fine if I do
bin/rspec spec/features/*/*_spec.rb
How can I include this path in the default spec?
Update
Here's one of the specs in brief
require 'rails_helper'
Rspec.describe 'User logs in', :type => :feature do
let(:user) { FactoryGirl.create(:user) }
scenario 'with valid credentials' do
... setup ...
expect(page).to have_content "Success"
end
end
I've also tried replacing Rspec.describe with describe, feature, Rspec.feature. The spec doesn't run in the default specs.
I have an rails application where i used slugged urls. How can i test those urls with Rspec.
rake routes is generating following results
new_user_session GET /login(.:format) sessions#new
user_session POST /login(.:format) sessions#create
bays GET /:slug/bays(.:format) bays#index
POST /:slug/bays(.:format) bays#create
new_bay GET /:slug/bays/new(.:format) bays#new
edit_bay GET /:slug/bays/:id/edit(.:format) bays#edit
bay GET /:slug/bays/:id(.:format) bays#show
PATCH /:slug/bays/:id(.:format) bays#update
PUT /:slug/bays/:id(.:format) bays#update
DELETE /:slug/bays/:id(.:format) bays#destroy
Now when i run rpec for bays controller, i caught with following error.
Failure/Error: get :index, {}, valid_session
ActionController::UrlGenerationError:
No route matches {:action=>"index", :controller=>"bays"}
Using
rspec-rails (3.0.1)
rails (4.0.0)
As you have defined it... bays index requires a :slug parameter. According to the error message, you have passed no slug to this route. You must either pass :slug (eg get :index, :slug => "1234", valid_session) or redefine the route to not need it.
for testing routes in rspec... That's a basic part of rspec: rspec routing specs
in your case it'd be something like:
{ :get => "/1234/bays" }.
should route_to(
:controller => "bays",
:slug => "1234"
)
For rspec 3.x you can go with:
scenario 'get correct slug', :type => :routing do
expect(get("/models/slug")).to route_to(:controller => "controller_name", :action => 'action_name', :id => "your_slug_name")
end
Note the type: :routing definition before the block.
More info here.
I'm stuck (again!) at Chapter 9 (this time in section 9.2.2) of the Rails tutorial. I am getting
bundle exec rspec spec/
................................FFF........................
Failures:
1) Authentication authorization as wrong user submitting a GET request to the Users#edit action
Failure/Error: before {sign_in user, no_capybara: true}
NoMethodError:
undefined method `new_remember_token' for #<User:0x007f8181815448>
# ./spec/support/utilities.rb:13:in `sign_in'
# ./spec/requests/authentication_pages_spec.rb:71:in `block (4 levels) in <top (required)>'
The other 2 errors are of the same type.
Here is spec causing the errors:
describe "as wrong user" do
let(:user) {FactoryGirl.create(:user)}
let(:wrong_user) {FactoryGirl.create(:user, email: "wrong#example.com")}
before {sign_in user, no_capybara: true}
describe "submitting a GET request to the Users#edit action" do
before {get edit_user_path(wrong_user)}
specify { expect(response.body).not_to match(full_title('Edit user'))}
specify { expect(response).to redirect_to(root_url)}
end
describe "submitting a PATCH request to the Users#update action" do
before { patch user_path(wrong_user)}
specify { expect(response).to redirect_to(root_url)}
end
end
And here is the method (utilities.rb) the error message is complaining about:
def sign_in (user, options={})
if options[:no_capybara]
# Sign in when not using Capybara
remember_token = User.new_remember_token
cookies[:remember_token]
user.update_attribute(:remember_token, User.digest(remember_token))
else
visit signin_path
fill_in "Email", with: user.email
fill_in "Password", with: user.password
click_button "Sign in"
end
end
The code for the model (User.rb) is here:
class User < ActiveRecord::Base
before_save { self.email = email.downcase}
before_create :create_remember_token
validates :name, presence: true, length: { maximum: 50 }
VALID_EMAIL_REGEX = /\A[\w+\-.]+#[a-z\d\-.]+\.[a-z]+\z/i
validates :email, presence: true, format: { with: VALID_EMAIL_REGEX }, uniqueness: { case_sensitive: false }
validates :password, length: {minimum: 6}
has_secure_password
def User.new_remember_token
SecureRandom.urlsafe_base64
end
def User.digest(token)
Digest::SHA1.hexdigest(token.to_s)
end
private
def create_remember_token
self.remember_token = User.digest(User.new_remember_token)
end
end
I had previously trouble with the sign_in method but it miraculously disappeared. What am I doing wrong?
I finally found the culprit for the erratic test results that I have been observing in this case and, quite likely, on previous occasions (Failure/Error: sign_in user undefined method `sign_in', Rails named route not recognized). The problem seems to be that rails does not clear by default the cache between tests. Which is, actually, downright scary. It seems you cannot really trust the test results. I realised this by commenting out the method that rails was complaining about and re-running the test. The error persisted which meant one thing - rspec was simply working with some cached versions of the files and thus disregarding the changes which I am making. So even if the tests pass you can't be sure that they really do. This is really bizarre. After realising the problem with a bit of googling I found how to force rails to clean the cache - check jaustin's answer here: is Rails.cache purged between tests?
I am trying to write Rspec tests in Rails, using Devise helper methods for signing in and out. The sign_in method is not working. However, it had been working earlier, before a slew of changes to the app.
Things I have tried:
I am including the test helpers in Rspec.configure.
Using Warden's login_as
Clearing the Rails cache.
Getting rid of Capybara to see if that were causing the issue
I am not setting the session explicitly in my controller specs (e.g. no valid_session)
So far, no dice. What do I need to do differently to test my controllers with a signed-in user?
Error message:
OrderItemsController GET #index renders the :index view
Failure/Error: sign_in :admin
NoMethodError:
undefined method `sign_in' for # <RSpec::ExampleGroups::OrderItemsController_2::GETIndex:0x00000102c002d0>
# ./spec/controllers/order_items_controller_spec.rb:6:in `block (2 levels) in <top (required)>'
Controller Spec
require 'spec_helper'
describe OrderItemsController do
before (:each) do
admin = create(:admin)
sign_in :admin
end
describe "GET #index" do
it "renders the :index view" do
get :index
expect( response ).to render_template :index
end
end
end
spec_helper.rb
require 'rspec/rails'
require 'capybara/rspec'
RSpec.configure do |config|
config.include ApplicationHelper
config.include ControllersHelper
config.include UsersHelper
config.include Devise::TestHelpers, type: :controller
config.include FactoryGirl::Syntax::Methods
end
Gemfile
group :development, :test do
gem 'rspec-rails', '~> 3.0.0.beta'
gem 'capybara'
gem 'factory_girl_rails'
gem 'faker'
gem 'dotenv-rails'
gem 'guard'
gem 'guard-annotate'
gem 'guard-rspec', require: false
gem 'guard-livereload', require: false
gem 'foreman'
end
factories/user.rb
FactoryGirl.define do
factory :user do
first { Faker::Name.first_name }
last { Faker::Name.last_name }
email { Faker::Internet.email }
admin false
password "secrets1"
password_confirmation "secrets1"
confirmed_at Date.today
factory :admin do
admin true
end
end
end
Thanks in advance.
Did you recently upgrade to RSpec 3 like I did? This is from the RSpec 3 documentation:
Automatically Adding Metadata
RSpec versions before 3.0.0 automatically added metadata to specs based on
their location on the filesystem. This was both confusing to new users and not
desirable for some veteran users.
In RSpec 3, this behavior must be explicitly enabled:
# spec/rails_helper.rb
RSpec.configure do |config|
config.infer_spec_type_from_file_location!
end
Since this assumed behavior is so prevalent in tutorials, the default
configuration generated by rails generate rspec:install enables this.
If you follow the above listed canonical directory structure and have
configured infer_spec_type_from_file_location!, RSpec will automatically
include the correct support functions for each type.
After I add that configuration snippet, I no longer have to specify the spec type (e.g. type: :controller).
I figured out a solution. I explicitly defined the controller's Describe block as a controller type.
describe OrderItemsController, :type => :controller do
I still don't understand why this code worked earlier but now needs this (seemingly redundant) explicit declaration. Regardless, I'd appreciate learning what happened here. Thanks!
I can provide you an example (works for me - rspec / capybara / simplecov etc..)
spec/spec_helper.rb
require 'capybara/rspec'
require 'capybara/rails'
RSpec.configure do |config|
config.use_transactional_fixtures = true
config.infer_base_class_for_anonymous_controllers = false
config.include FactoryGirl::Syntax::Methods
config.include Devise::TestHelpers, type: :controller
config.include Capybara::DSL
config.include Warden::Test::Helpers
config.include Rails.application.routes.url_helpers
end
spec/integration/user_flow_spec.rb
require 'spec_helper'
feature 'Verify contract' do
# Create employee
let(:employee) { create(:employee) }
let (:book) { create(:book) }
# Sign in employee before each test!
before :each do
login_as employee, scope: :user
end
scenario 'create book' do
# Visit Index and click to create
visit employee_books_path
click_link 'Create'
expect(current_path).to eq(employee_books_path)
end
end
I hope it will be ok :) I think your problem is missing Warden test helpers...
You can use the Devise helper in the file spec/spec_helper.rb:
RSpec.configure do |config|
config.include Devise::TestHelpers, type: :controller
end
If you need the sign_in method in a request spec file, then you should include this:
config.include Devise::Test::IntegrationHelpers, type: :request
For Rails 5 and Rspec 3 you need to add this into your spec_helper.rb
config.include Devise::Test::ControllerHelpers, type: :controller
You can use login_as method instead like this:
# rails_helper.rb
RSpec.configure do |config|
config.include Warden::Test::Helpers
end
In your spec file use:
#spec/integration/user_flow_spec.rb
before :each do
employee = create(:employee)
login_as employee, scope: :user
end