I've just started using rspec_api_documentation and cannot get it to work with my api. Created simple spec, as basic as first example in the readme but it keeps throwing undefined method 'call' for nil:NilClass error at me, and I have no idea what may cause the problem.
Here is full stack trace:
1) Users GET /api/v1/users Listing users
Failure/Error: do_request
NoMethodError:
undefined method `call' for nil:NilClass
# /home/swistak/.rvm/gems/ruby-2.2.2/gems/rack-test-0.6.3/lib/rack/mock_session.rb:30:in `request'
# /home/swistak/.rvm/gems/ruby-2.2.2/gems/rack-test-0.6.3/lib/rack/test.rb:244:in `process_request'
# /home/swistak/.rvm/gems/ruby-2.2.2/gems/rack-test-0.6.3/lib/rack/test.rb:58:in `get'
# /home/swistak/.rvm/gems/ruby-2.2.2/gems/rspec_api_documentation-4.7.0/lib/rspec_api_documentation/rack_test_client.rb:38:in `do_request'
# /home/swistak/.rvm/gems/ruby-2.2.2/gems/rspec_api_documentation-4.7.0/lib/rspec_api_documentation/client_base.rb:42:in `process'
# /home/swistak/.rvm/gems/ruby-2.2.2/gems/rspec_api_documentation-4.7.0/lib/rspec_api_documentation/client_base.rb:12:in `get'
# ./spec/acceptance/users_spec.rb:7:in `block (3 levels) in <top (required)>
Here is the spec
require 'spec_helper'
require 'rspec_api_documentation/dsl'
RSpec.resource 'Users' do
get '/api/v1/users' do
example 'Listing users' do
do_request
status.should == 200
end
end
end
and here is the controller
class Api::V1::UsersController < ApplicationController
skip_before_action :authenticate_with_token, only: %i(index show create)
expose(:users)
def index
render json: users, each_serializer: ::V1::UserSerializer
end
end
My api is under localhost:3000/api/v1/users
Any help appreciated
It seems that configuration block is required, so I've just created acceptance_helper.rb as in the example application and imported it in spec.
Related
I recently ran into an issue with an integration test using rspec.
RSpec.describe "Images", type: :request do
before(:each) do
#user = User.create(username: "sam", password: "password")
#tag = #user.tags.create(name: "outdoors")
post login_path, params: { username: "sam", password: "password" }
expect(session[:user_id]).to eql #user.id
#file = fixture_file_upload("/dingo.jpeg", "image/jpeg")
end
it "can show images" do
#image = #user.images.create(caption: "hello", image_file: #image)
get user_image_path(#user, #image)
expect(response).to be_success
end
end
The before each creates a valid user, tag and logs the user in. Then it loads an image file.
The test it's self creates a new image for the #user and assigns it a value for caption and the loaded file for its :image_file.
The Image model uses has_one_attached :image_file to associate an uploaded image with an image record
class Image < ApplicationRecord
belongs_to :user
has_and_belongs_to_many :tags
has_one_attached :image_file
end
the controller and action as follows:
class ImageController < ApplicationController
before_action :unauthorized_redirect
def show
#user = current_user
#image = Image.find(params[:id])
#tags = #user.tags.all
authorize #image, :show?
end
private
def image_params
params.require(:image).permit(:caption, :image_file, tag_ids: [])
end
end
When I run the test I get an error:
Failures:
1) Images can show images
Failure/Error: <%= image_tag #image.image_file, class: "img-fluid show-image" %>
ActionView::Template::Error:
Can't resolve image into URL: undefined method `persisted?' for nil:NilClass
# ./app/views/image/show.html.erb:7:in `_app_views_image_show_html_erb__3727703739275822003_20580'
# <internal:kernel>:90:in `tap'
# /home/sam/.rvm/gems/ruby-3.0.0/gems/actiontext-6.1.4.1/lib/action_text/rendering.rb:20:in `with_renderer'
# /home/sam/.rvm/gems/ruby-3.0.0/gems/actiontext-6.1.4.1/lib/action_text/engine.rb:59:in `block (4 levels) in <class:Engine>'
# /home/sam/.rvm/gems/ruby-3.0.0/gems/rack-2.2.3/lib/rack/tempfile_reaper.rb:15:in `call'
# /home/sam/.rvm/gems/ruby-3.0.0/gems/rack-2.2.3/lib/rack/etag.rb:27:in `call'
# /home/sam/.rvm/gems/ruby-3.0.0/gems/rack-2.2.3/lib/rack/conditional_get.rb:27:in `call'
# /home/sam/.rvm/gems/ruby-3.0.0/gems/rack-2.2.3/lib/rack/head.rb:12:in `call'
# /home/sam/.rvm/gems/ruby-3.0.0/gems/rack-2.2.3/lib/rack/session/abstract/id.rb:266:in `context'
# /home/sam/.rvm/gems/ruby-3.0.0/gems/rack-2.2.3/lib/rack/session/abstract/id.rb:260:in `call'
# /home/sam/.rvm/gems/ruby-3.0.0/gems/railties-6.1.4.1/lib/rails/rack/logger.rb:37:in `call_app'
# /home/sam/.rvm/gems/ruby-3.0.0/gems/railties-6.1.4.1/lib/rails/rack/logger.rb:26:in `block in call'
# /home/sam/.rvm/gems/ruby-3.0.0/gems/railties-6.1.4.1/lib/rails/rack/logger.rb:26:in `call'
# /home/sam/.rvm/gems/ruby-3.0.0/gems/rack-2.2.3/lib/rack/method_override.rb:24:in `call'
# /home/sam/.rvm/gems/ruby-3.0.0/gems/rack-2.2.3/lib/rack/runtime.rb:22:in `call'
# /home/sam/.rvm/gems/ruby-3.0.0/gems/rack-2.2.3/lib/rack/sendfile.rb:110:in `call'
# /home/sam/.rvm/gems/ruby-3.0.0/gems/railties-6.1.4.1/lib/rails/engine.rb:539:in `call'
# /home/sam/.rvm/gems/ruby-3.0.0/gems/rack-test-1.1.0/lib/rack/mock_session.rb:29:in `request'
# /home/sam/.rvm/gems/ruby-3.0.0/gems/rack-test-1.1.0/lib/rack/test.rb:266:in `process_request'
# /home/sam/.rvm/gems/ruby-3.0.0/gems/rack-test-1.1.0/lib/rack/test.rb:119:in `request'
# /home/sam/.rvm/gems/ruby-3.0.0/gems/rails-controller-testing-1.0.5/lib/rails/controller/testing/integration.rb:16:in `block (2 levels) in <module:Integration>'
# ./spec/requests/images_spec.rb:38:in `block (2 levels) in <main>'
# ------------------
# --- Caused by: ---
# NoMethodError:
# undefined method `persisted?' for nil:NilClass
# ./app/views/image/show.html.erb:7:in `_app_views_image_show_html_erb__3727703739275822003_20580'
Finished in 0.79372 seconds (files took 0.46552 seconds to load)
30 examples, 1 failure
Failed examples:
rspec ./spec/requests/images_spec.rb:36 # Images can show images
I have debugged this issue with breakpoints everywhere and I just don't understand why it's not working in test when it works in production. I hope I've provided enough information this bug has been driving me crazy for the past two days.
Thank you!
Versions:
rails: 6.1.4.1
rspec: 5.0.2
Changed one line and fixed it
it "can show images" do
#image = #user.images.create(caption: "hello", image_file: #image)
get user_image_path(#user, #image)
*expect(response).to be_success ----REMOVE*
expect(response.successful?).to eql true
end
This is kind of bizarre. I'm walking through chapter twelve of the ruby on rails tutorial (for reference: https://www.railstutorial.org/book/following_users) and got to section 12.2.4 with all tests passing. I then did the command rails generate controller Relationships and entered exactly the code in listings 12.30 and 12.31 to try and get the relationships controller test to pass, but I'm getting the following errors:
ERROR["test_destroy_should_require_logged-in_user", RelationshipsControllerTest, 2015-11-13 11:07:25 +0000]
test_destroy_should_require_logged-in_user#RelationshipsControllerTest (1447412845.16s)
NoMethodError: NoMethodError: undefined method `logged_in_user' for #<RelationshipsController:0x000000044f5bd8>
test/controllers/relationships_controller_test.rb:14:in `block (2 levels) in <class:RelationshipsControllerTest>'
test/controllers/relationships_controller_test.rb:13:in `block in <class:RelationshipsControllerTest>'
test/controllers/relationships_controller_test.rb:14:in `block (2 levels) in <class:RelationshipsControllerTest>'
test/controllers/relationships_controller_test.rb:13:in `block in <class:RelationshipsControllerTest>'
ERROR["test_create_should_require_logged-in_user", RelationshipsControllerTest, 2015-11-13 11:07:25 +0000]
test_create_should_require_logged-in_user#RelationshipsControllerTest (1447412845.22s)
NoMethodError: NoMethodError: undefined method `logged_in_user' for #<RelationshipsController:0x00000004db9990>
test/controllers/relationships_controller_test.rb:7:in `block (2 levels) in <class:RelationshipsControllerTest>'
test/controllers/relationships_controller_test.rb:6:in `block in <class:RelationshipsControllerTest>'
test/controllers/relationships_controller_test.rb:7:in `block (2 levels) in <class:RelationshipsControllerTest>'
test/controllers/relationships_controller_test.rb:6:in `block in <class:RelationshipsControllerTest>'
Why isn't it seeing the logged_in_user method from the users controller? I can put it in as
class RelationshipsController < ApplicationController
before_action :logged_in_user
def create
user = User.find(params[:followed_id])
current_user.follow(user)
redirect_to user
end
def destroy
user = Relationship.find(params[:id]).followed
current_user.unfollow(user)
redirect_to user
end
private
# Confirms a logged-in user.
def logged_in_user
unless logged_in?
store_location
flash[:danger] = "Please log in."
redirect_to login_url
end
end
end
and the test passes, but this kind of violates the Don't Repeat Yourself principle harped on throughout the tutorial. Any ideas what's going wrong?
Is that method logged_in_user on the in the UsersController or in the ApplicationsController? If it's in the UsersController it will not have access to it because of the hierarchal inheritance. Try putting that method into the ApplicationsController and then giving it whirl.
Doing this will give both the UsersController and the RelationshipsController access to this method because they both inherit from ApplicationsController
I wrote a custom OmniAuth strategy and am now trying to write Rspec tests around it, but I keep getting this error:
NoMethodError:
undefined method `authenticate' for nil:NilClass
# ./controllers/application_controller.rb:58:in `block in <class:ApplicationController>'
# ./lib/omniauth/custom_strategy.rb:135:in `block in callback_phase'
# ./lib/omniauth/custom_strategy.rb:119:in `callback_phase'
# ./spec/lib/omniauth/custom_strategy_spec.rb:62:in `block (3 levels) in <top (required)>'
After digging through the Devise code, I found that the error was originating in lib/devise/controllers/helpers.rb, where the current_user method gets defined in ApplicationController:
def current_#{mapping}
#current_#{mapping} ||= warden.authenticate(:scope => :#{mapping})
end
In this case, warden is defined as:
def warden
request.env['warden']
end
So, in my spec, since it's not a controller spec, I put in custom code to create a Rack app (as seen here: https://github.com/mkdynamic/omniauth/blob/master/spec/omniauth/strategies/developer_spec.rb) like so:
# Outside of the spec block:
RSpec.configure do |config|
config.include Rack::Test::Methods
end
# Inside the spec block:
let(:app){ Rack::Builder.new do |b|
b.use Rack::Session::Cookie
b.use OmniAuth::Strategies::CustomStrategy
b.run lambda{|env| [200, {}, ['Not Found']]}
end.to_app }
The problem here is that the Rack::Test::Methods don't include a request object, like Rspec provides in its controller tests. So, request.env is not defined and therefore warden is not defined.
I tried including Devise::TestHelpers, as described here (All Ruby tests raising: undefined method `authenticate' for nil:NilClass), but since #request is not defined, it throws an error.
I've also tried many other solutions, but none seem to deal with non-controller tests, since they all rely on a request object. Has anyone had experience with these issues and can shed some light on possible solutions?
Thanks in advance.
I'm currently going through the awesome Rails Tutorial, and after I did a git reset to return to a previous commit, something broke to my database and all of a sudden I get 5 failures when I run rspec.
Failures:
1) UsersController Get 'show' should be successfull
Failure/Error: get :show, :id => #user
ActionView::Template::Error:
undefined method `gravatar_for' for #<#<Class:0xaadc884>:0xaad9990>
# ./app/views/users/show.html.erb:5:in `_app_views_users_show_html_erb__463664834_89565070__435144589'
# ./spec/controllers/users_controller_spec.rb:13:in `block (3 levels) in <top (required)>'
2) UsersController Get 'show' should find the right user
Failure/Error: get :show, :id => #user
ActionView::Template::Error:
undefined method `gravatar_for' for #<#<Class:0xaadc884>:0xa820ca8>
# ./app/views/users/show.html.erb:5:in `_app_views_users_show_html_erb__463664834_89565070__435144589'
# ./spec/controllers/users_controller_spec.rb:18:in `block (3 levels) in <top (required)>'
3) UsersController Get 'show' should have the right title
Failure/Error: get :show, :id => #user
ActionView::Template::Error:
undefined method `gravatar_for' for #<#<Class:0xaadc884>:0x9f0e7b4>
# ./app/views/users/show.html.erb:5:in `_app_views_users_show_html_erb__463664834_89565070__435144589'
# ./spec/controllers/users_controller_spec.rb:23:in `block (3 levels) in <top (required)>'
4) UsersController Get 'show' should include the user's name
Failure/Error: get :show, :id => #user
ActionView::Template::Error:
undefined method `gravatar_for' for #<#<Class:0xaadc884>:0xb930cc8>
# ./app/views/users/show.html.erb:5:in `_app_views_users_show_html_erb__463664834_89565070__435144589'
# ./spec/controllers/users_controller_spec.rb:28:in `block (3 levels) in <top (required)>'
5) UsersController Get 'show' should have a profile image
Failure/Error: get :show, :id => #user
ActionView::Template::Error:
undefined method `gravatar_for' for #<#<Class:0xaadc884>:0xb9ade94>
# ./app/views/users/show.html.erb:5:in `_app_views_users_show_html_erb__463664834_89565070__435144589'
# ./spec/controllers/users_controller_spec.rb:33:in `block (3 levels) in <top (required)>'
I'm sure this easy to fix, but I honestly dont know where to even look at. Can anyone help?
This is your problem:
undefined method `gravatar_for' for #<#<Class:0xaadc884>:0xb9ade94>
You need to make sure the gravatar is specificed in your profile model.
You are calling gravatar_for, which is unknown, line 5 of: ./app/views/users/show.html.erb
Even if this is already an answer, please provide details so that we fix it.
I'm pretty sure you forgot to add the method to your User model.
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