Error in cancancan ability initializer when testing controllers - ruby-on-rails

I added cancancan gem to my app, but it broked all my controller and feature tests. The error start in ability.rb initialize: the user variable is nil.
Here is the error log of one of the tests:
14) TestCasesController DELETE #destroy when not logged-in redirects to sign-in page
Failure/Error: if user.teacher?
NoMethodError:
undefined method `teacher?' for nil:NilClass
# ./app/models/ability.rb:5:in `initialize'
# /usr/local/rvm/gems/ruby-2.3.1/gems/cancancan-1.15.0/lib/cancan/controller_additions.rb:361:in `new'
# /usr/local/rvm/gems/ruby-2.3.1/gems/cancancan-1.15.0/lib/cancan/controller_additions.rb:361:in `current_ability'
# /usr/local/rvm/gems/ruby-2.3.1/gems/cancancan-1.15.0/lib/cancan/controller_additions.rb:342:in `authorize!'
# /usr/local/rvm/gems/ruby-2.3.1/gems/cancancan-1.15.0/lib/cancan/controller_resource.rb:49:in `authorize_resource'
# /usr/local/rvm/gems/ruby-2.3.1/gems/cancancan-1.15.0/lib/cancan/controller_resource.rb:34:in `load_and_authorize_resource'
# /usr/local/rvm/gems/ruby-2.3.1/gems/cancancan-1.15.0/lib/cancan/controller_resource.rb:10:in `block in add_before_action'
# /usr/local/rvm/gems/ruby-2.3.1/gems/rails-controller-testing-1.0.1/lib/rails/controller/testing/template_assertions.rb:61:in `process'
# /usr/local/rvm/gems/ruby-2.3.1/gems/devise-4.2.0/lib/devise/test/controller_helpers.rb:33:in `block in process'
# /usr/local/rvm/gems/ruby-2.3.1/gems/devise-4.2.0/lib/devise/test/controller_helpers.rb:100:in `catch'
# /usr/local/rvm/gems/ruby-2.3.1/gems/devise-4.2.0/lib/devise/test/controller_helpers.rb:100:in `_catch_warden'
# /usr/local/rvm/gems/ruby-2.3.1/gems/devise-4.2.0/lib/devise/test/controller_helpers.rb:33:in `process'
# /usr/local/rvm/gems/ruby-2.3.1/gems/rails-controller-testing-1.0.1/lib/rails/controller/testing/integration.rb:12:in `block (2 levels) in <module:Integration>'
# ./spec/controllers/test_cases_controller_spec.rb:182:in `block (3 levels) in <top (required)>'
# ./spec/controllers/test_cases_controller_spec.rb:193:in `block (4 levels) in <top (required)>'
Here is the corresponding action:
describe "DELETE #destroy" do
let!(:test_case) { create(:test_case) }
subject { delete :destroy, params: { id: test_case } }
context "when not logged-in" do
before { subject }
it "redirects to sign-in page" do
expect(response).to redirect_to(new_user_session_url)
end
end
end
This is my controller:
class TestCasesController < ApplicationController
include ApplicationHelper
load_and_authorize_resource
before_action :authenticate_user!
before_action :find_test_case, only: [:show, :edit, :update, :destroy, :test]
before_action :find_question, only: [:index, :new, :create, :test_all]
def index
#test_cases = TestCase.where(question: #question)
end
def new
#test_case = TestCase.new
end
def create
#test_case = #question.test_cases.build(test_case_params)
if #test_case.save
flash[:success] = "Caso de teste criado!"
redirect_to #test_case
else
render 'new'
end
end
def show
end
def edit
end
def update
if #test_case.update_attributes(test_case_params)
flash[:success] = "Caso de teste atualizado!"
redirect_to #test_case
else
render 'edit'
end
end
def destroy
question = #test_case.question
#test_case.destroy
flash[:success] = "Caso de teste deletado!"
redirect_to question_test_cases_url(question)
end
def test
result = #test_case.test(plain_current_datetime, "pas", params[:source_code])
#output = result[:output]
#results = [ { title: #test_case.title, status: result[:status] } ]
respond_to { |format| format.js }
end
def test_all
#results = #question.test_all(plain_current_datetime, "pas", params[:source_code])
respond_to { |format| format.js }
end
private
def test_case_params
params.require(:test_case).permit(:title, :description, :input, :output, :question_id)
end
def find_test_case
#test_case = TestCase.find(params[:id])
end
def find_question
#question = Question.find(params[:question_id])
end
end
This is my ability class:
class Ability
include CanCan::Ability
def initialize(user)
if user.teacher?
can :manage, [Exercise, Question, TestCase]
can :manage, Team, owner: user
can [:read, :create], Team
can [:enroll], Team do |team|
!team.enrolled?(user)
end
can [:unenroll], Team do |team|
team.enrolled?(user)
end
end
end
end
This is my rails_helper (from rspec):
# 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'
# Add additional requires below this line. Rails is not loaded until this point!
require 'support/helpers/relationships'
# Requires supporting ruby files with custom matchers and macros, etc, in
# spec/support/ and its subdirectories. Files matching `spec/**/*_spec.rb` are
# run as spec files by default. This means that files in spec/support that end
# in _spec.rb will both be required and run as specs, causing the specs to be
# run twice. It is recommended that you do not name files matching this glob to
# end with _spec.rb. You can configure this pattern with the --pattern
# option on the command line or in ~/.rspec, .rspec or `.rspec-local`.
#
# The following line is provided for convenience purposes. It has the downside
# of increasing the boot-up time by auto-requiring all files in the support
# directory. Alternatively, in the individual `*_spec.rb` files, manually
# require only the support files necessary.
#
# Dir[Rails.root.join('spec/support/**/*.rb')].each { |f| require f }
# Checks for pending migration and applies them before tests are run.
# If you are not using ActiveRecord, you can remove this line.
ActiveRecord::Migration.maintain_test_schema!
RSpec.configure do |config|
# 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
# RSpec Rails can automatically mix in different behaviours to your tests
# based on their file location, for example enabling you to call `get` and
# `post` in specs under `spec/controllers`.
#
# You can disable this behaviour by removing the line below, and instead
# explicitly tag your specs with their type, e.g.:
#
# RSpec.describe UsersController, :type => :controller do
# # ...
# end
#
# The different available types are documented in the features, such as in
# https://relishapp.com/rspec/rspec-rails/docs
config.infer_spec_type_from_file_location!
# Helpers
config.include Helpers::Relationships, type: :model
config.include Devise::Test::ControllerHelpers, :type => :controller
config.include Warden::Test::Helpers
end
Any tips of how to fix that?
OBS: I'm using Devise for authentication, it provides me the required current_user to cancancan work.

The primary reason you're getting a nil:NilClass error is because current_user is nil unless you are signed in via Devise. Your ability needs to handle for when a user is not logged in, something like this:
def initialize(user)
return unless user.present?
if user.teacher?
...
end
end
If you return nil from your ability, the authorization fails and is handled accordingly.

Related

Capybara InfiniteRedirectError

I am getting the same behavior whether it's in the browser or running rspec... How can this issue get resolved?
I have tried removing the before_filter :authenticate_user! within application_controller.rb and the result remains the same. The failing example is the very first one within spec/features/subdomain_feature_spec.rb
Failures:
1) subdomains redirects invalid accounts
Failure/Error: visit root_url(subdomain: 'random-subdomain')
Capybara::InfiniteRedirectError:
redirected more than 5 times, check for infinite redirects.
# /home/benny/.rvm/gems/ruby-2.3.3/gems/capybara-2.13.0/lib/capybara/rack_test/browser.rb:41:in `process_and_follow_redirects'
# /home/benny/.rvm/gems/ruby-2.3.3/gems/capybara-2.13.0/lib/capybara/rack_test/browser.rb:22:in `visit'
# /home/benny/.rvm/gems/ruby-2.3.3/gems/capybara-2.13.0/lib/capybara/rack_test/driver.rb:43:in `visit'
# /home/benny/.rvm/gems/ruby-2.3.3/gems/capybara-2.13.0/lib/capybara/session.rb:254:in `visit'
# /home/benny/.rvm/gems/ruby-2.3.3/gems/capybara-2.13.0/lib/capybara/dsl.rb:52:in `block (2 levels) in <module:DSL>'
# ./spec/features/subdomain_feature_spec.rb:7:in `block (2 levels) in <top (required)>'
...
Failed examples:
rspec ./spec/features/subdomain_feature_spec.rb:6 # subdomains redirects invalid accounts
Relevant Files
spec/features/subdomain_feature_spec.rb
require 'rails_helper'
describe 'subdomains' do
let!(:account) { create(:account_with_schema) }
it 'redirects invalid accounts' do
visit root_url(subdomain: 'random-subdomain')
expect(page.current_url).to_not include('random-subdomain')
end
it 'allows valid accounts' do
visit root_url(subdomain: account.subdomain)
expect(page.current_url).to include(account.subdomain)
end
it 'forces user to login before accessing subdomain content' do
visit root_url(subdomain: account.subdomain)
expect(page).to have_content 'sign in or sign up before continuing'
end
end
config/routes.rb
class SubdomainPresent
def self.matches?(request)
request.subdomain.present?
end
end
class SubdomainBlank
def self.matches?(request)
request.subdomain.blank?
end
end
Rails.application.routes.draw do
constraints(SubdomainPresent) do
root 'projects#index', as: :subdomain_root
devise_for :users
end
# only allow certain routes when there isn't a subdomain
constraints(SubdomainBlank) do
root 'welcome#index'
resources :accounts, only: [:new, :create]
end
end
controllers/application_controller.rb
class ApplicationController < ActionController::Base
protect_from_forgery with: :exception
before_filter :load_schema, :authenticate_user!
private
def load_schema
Apartment::Tenant.switch!('public')
return unless request.subdomain.present?
account = Account.find_by(subdomain: request.subdomain)
if account
Apartment::Tenant.switch!(request.subdomain)
else
redirect_to root_url(subdomain: :false)
end
end
def after_sign_out_path_for(resource_or_scope)
new_user_session_path
end
end
controllers/welcome_controller.rb
class WelcomeController < ApplicationController
skip_before_filter :authenticate_user!, only: :index
def index
end
end
spec/factories/accounts.rb
FactoryGirl.define do
sequence(:subdomain) { |n| "subdomain#{n}" }
factory :account do
sequence(:subdomain) { |n| "subdomain#{n}" }
association :owner, factory: :user
factory :account_with_schema do
after(:build) do |account|
Apartment::Tenant.create(account.subdomain)
Apartment::Tenant.switch!(account.subdomain)
end
after(:create) do |account|
Apartment::Tenant.reset
end
end
end
end
spec/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?
# Add additional requires below this line. Rails is not loaded until this point!
require 'spec_helper'
require 'rspec/rails'
require 'capybara/poltergeist'
Capybara.javascript_driver = :poltergeist
ActiveRecord::Migration.maintain_test_schema!
RSpec.configure do |config|
# Remove this line if you're not using ActiveRecord or ActiveRecord fixtures
config.fixture_path = "#{::Rails.root}/spec/fixtures"
config.use_transactional_fixtures = false
config.infer_spec_type_from_file_location!
config.include FactoryGirl::Syntax::Methods
# Filter lines from Rails gems in backtraces.
config.filter_rails_from_backtrace!
# arbitrary gems may also be filtered via:
# config.filter_gems_from_backtrace("gem name")
end
# Capybara.register_driver :poltergeist do |app|
# Capybara::Poltergeist::Driver.new(app, options)
# end
The Capybara rack_test driver ignores hostnames so you're not going to be able to test subdomain behavior with it, you'll need to run those tests with one of the drivers that utilizes/mimics a full browser (selenium, poltergeist, capybara-webkit).
Additionally you want to write and url/path check using the Capybara have_current_path matcher rather than eq with `current_url'
expect(page).not_to have_current_path(/random-subdomain/, url: true)

Failure/Error: response.should render_template(:new) expecting <"new"> but rendering with <"">

posts_controller.rb
class PostsController < ApplicationController
respond_to :html, :xml, :json
before_filter :authenticate_user!, :except => [:show, :index]
before_filter :admin_only, :except => [:show, :index]
def new
#post = Post.new
end
end
spec_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__)
require 'rspec/rails'
require 'forgery'
require 'populators'
# 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.mock_with :rspec
# Remove this line if you're not using ActiveRecord or ActiveRecord fixtures
config.fixture_path = "#{::Rails.root}/test/fixtures"
config.before(:suite) do
DatabaseCleaner.strategy = :truncation
end
config.after(:suite) do
DatabaseCleaner.clean
end
# 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 = false
end
posts_controller_spec.rb
require File.dirname(__FILE__) + '/../spec_helper'
describe PostsController do
fixtures :all
include Devise::TestHelpers
render_views
before(:each) do
DatabaseCleaner.strategy = :truncation
DatabaseCleaner.start
end
after(:each) do
DatabaseCleaner.clean
end
it "new action should render new template" do
get :new
response.should render_template(:new)
end
end
ruby 1.8.7, rspec 2.11, Rails 3.2.19
I get this error expecting <"new"> but rendering with <""> how can I pass this case ... I tried many suggestions but didnt get any success .. Please Help Am stuck with it ... :(
NOTE: I cant change the code of a controller
# Use the sign_in helper to sign in a fixture `User` record.
user = users(:one)
#request.env['warden'].stub(:authenticate!).and_return(user)
#controller.stub(:current_user).and_return(user)
get :new
assert_template 'new'
this works for me using https://github.com/plataformatec/devise/wiki/How-To:-Stub-authentication-in-controller-specs and thanx #Зелёный for the direction :)

Functional Test Keeps Failing (Rspec, Devise)

I'm trying to implement an rspec functional test to check that a user is signed in with devise. I've looked through my code again and again and tried different solutions but so far nothing has worked.
I've included what I believe are the relevant files. Let me know if anything is missing. Any recommendations are appreciated.
spec/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?
# Add additional requires below this line. Rails is not loaded until this point!
require 'spec_helper'
require 'rspec/rails'
# note: require 'devise' after require 'rspec/rails'
require 'devise'
# Requires supporting ruby files with custom matchers and macros, etc, in
# spec/support/ and its subdirectories. Files matching `spec/**/*_spec.rb` are
# run as spec files by default. This means that files in spec/support that end
# in _spec.rb will both be required and run as specs, causing the specs to be
# run twice. It is recommended that you do not name files matching this glob to
# end with _spec.rb. You can configure this pattern with the --pattern
# option on the command line or in ~/.rspec, .rspec or `.rspec-local`.
#
# The following line is provided for convenience purposes. It has the downside
# of increasing the boot-up time by auto-requiring all files in the support
# directory. Alternatively, in the individual `*_spec.rb` files, manually
# require only the support files necessary.
#
# Dir[Rails.root.join('spec/support/**/*.rb')].each { |f| require f }
# Checks for pending migration and applies them before tests are run.
# If you are not using ActiveRecord, you can remove this line.
ActiveRecord::Migration.maintain_test_schema!
RSpec.configure do |config|
# 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
# RSpec Rails can automatically mix in different behaviours to your tests
# based on their file location, for example enabling you to call `get` and
# `post` in specs under `spec/controllers`.
#
# You can disable this behaviour by removing the line below, and instead
# explicitly tag your specs with their type, e.g.:
#
# RSpec.describe UsersController, :type => :controller do
# # ...
# end
#
# The different available types are documented in the features, such as in
# https://relishapp.com/rspec/rspec-rails/docs
config.infer_spec_type_from_file_location!
# Filter lines from Rails gems in backtraces.
config.filter_rails_from_backtrace!
# arbitrary gems may also be filtered via:
# config.filter_gems_from_backtrace("gem name")
#Added for Devise
config.include Devise::Test::ControllerHelpers, :type => :controller
end
spec/controllers/users_controller_spec.rb
require 'rails_helper'
describe UsersController, :type => :controller do
before do
#user = User.create!(email: 'example#example.com', password: 'example')
end
# let(:user) { User.create!(email: 'example#example.com', password: 'example') }
describe 'GET #show' do
context "when user is logged in" do
before do
sign_in #user
end
it "loads correct user details" do
get :show, id: #user.id
expect(response).to have_http_status(200)
expect(assigns(:user)).to eq #user
end
end
context "when no user is logged in" do
it "redirects to login" do
get :show, id: #user.id
expect(response).to redirect_to(root_path)
end
end
end
end
And my feedback from the terminal after running bundle exec rpsec
Failures:
1) UsersController GET #show when user is logged in loads correct user details
Failure/Error: elsif user?
NoMethodError:
undefined method `user?' for #<Ability:0x007fa1d784cb98>
# ./app/models/ability.rb:9:in `initialize'
# /Users/Admin/.rvm/gems/ruby-2.3.0/gems/cancancan-1.15.0/lib/cancan/controller_additions.rb:361:in `new'
# /Users/Admin/.rvm/gems/ruby-2.3.0/gems/cancancan-1.15.0/lib/cancan/controller_additions.rb:361:in `current_ability'
# /Users/Admin/.rvm/gems/ruby-2.3.0/gems/cancancan-1.15.0/lib/cancan/controller_additions.rb:342:in `authorize!'
# /Users/Admin/.rvm/gems/ruby-2.3.0/gems/cancancan-1.15.0/lib/cancan/controller_resource.rb:49:in `authorize_resource'
# /Users/Admin/.rvm/gems/ruby-2.3.0/gems/cancancan-1.15.0/lib/cancan/controller_resource.rb:34:in `load_and_authorize_resource'
# /Users/Admin/.rvm/gems/ruby-2.3.0/gems/cancancan-1.15.0/lib/cancan/controller_resource.rb:10:in `block in add_before_action'
# /Users/Admin/.rvm/gems/ruby-2.3.0/gems/rails-controller-testing-1.0.1/lib/rails/controller/testing/template_assertions.rb:61:in `process'
# /Users/Admin/.rvm/gems/ruby-2.3.0/gems/devise-4.2.0/lib/devise/test/controller_helpers.rb:33:in `block in process'
# /Users/Admin/.rvm/gems/ruby-2.3.0/gems/devise-4.2.0/lib/devise/test/controller_helpers.rb:100:in `catch'
# /Users/Admin/.rvm/gems/ruby-2.3.0/gems/devise-4.2.0/lib/devise/test/controller_helpers.rb:100:in `_catch_warden'
# /Users/Admin/.rvm/gems/ruby-2.3.0/gems/devise-4.2.0/lib/devise/test/controller_helpers.rb:33:in `process'
# /Users/Admin/.rvm/gems/ruby-2.3.0/gems/rails-controller-testing-1.0.1/lib/rails/controller/testing/integration.rb:12:in `block (2 levels) in <module:Integration>'
# ./spec/controllers/users_controller_spec.rb:19:in `block (4 levels) in <top (required)>'
2) UsersController GET #show when no user is logged in redirects to login
Failure/Error: expect(response).to redirect_to(root_path)
Expected response to be a redirect to <http://test.host/> but was a redirect to <http://test.host/users/sign_in>.
Expected "http://test.host/" to be === "http://test.host/users/sign_in".
# ./spec/controllers/users_controller_spec.rb:29:in `block (4 levels) in <top (required)>'
Finished in 0.90214 seconds (files took 11.05 seconds to load)
6 examples, 2 failures
Failed examples:
rspec ./spec/controllers/users_controller_spec.rb:18 # UsersController GET #show when user is logged in loads correct user details
rspec ./spec/controllers/users_controller_spec.rb:27 # UsersController GET #show when no user is logged in redirects to login
A friend actually helped me figure it out. Apparently there's some issue that involves the seperate gem cancancan. I had to go into the models/ability.rb file and change a line in it.
In the original code the line if !user.admin? was just user?
So if you run into this same issue, that's the fix!
class Ability
include CanCan::Ability
def initialize(user)
user ||= User.new #guest user (not logged in)
# can :manage, User, id: user.id
if user.admin?
can :manage, :all
elsif !user.admin?
can :manage, User, id: user.id
else
can :read, :all
end
end
end

RSpec fails upon a namespaced model assigned to blog

I was doing the RSpec testing with Rails and it's failing due to the namespaced model that I assigned to its associations of the model.
CLI:
Failures:
1) Blog::BlobsController GET index assigns all blog/blobs as #blobs
Failure/Error: expect(assigns(:blog::blobs)).to eq([blog::blobs])
NoMethodError:
undefined method `blobs' for :blog:Symbol
# ./spec/controllers/blog/blobs_controller_spec.rb:8:in `block (3 levels) in <top (required)>'
spec/controllers/blog/blobs_controller_spec.rb
RSpec.describe Blog::BlobsController, type: :controller do
describe "GET index" do
it "assigns all blog/blobs as #blobs" do
blobs = Blog::Blob.create!
get :index, {}
expect(assigns(:blog::blobs)).to eq([blog::blobs])
end
end
end
routes.rb
# SNIPPED FOR BREVITY...
namespace :blog do
resources :blobs
end
app/controllers/blog/blobs_controller.rb
class Blog::BlobsController < ApplicationController
before_filter :authenticate_user!, except: [:index, :show]
def index
#blobs = Blog::Blob.all
end
def new
#blob = Blog::Blob.new
end
def edit
#blob = Blog::Blob.find(params[:id])
end
def create
#blob = Blog::Blob.new(blob_params)
if #blob.save
redirect_to #blob
else
render 'new'
end
end
def update
#blob = Blog::Blob.find(params[:id])
if #blob.update(blob_params)
redirect_to #blob
else
render 'edit'
end
end
def show
#blob = Blog::Blob.find(params[:id])
end
def destroy
#blob = Blog::Blob.find(params[:id])
#blob.destroy!
redirect_to blog_blobs_path
end
private
def blob_params
params.require(:blob).permit(:title, :body)
end
end
Is there a better way to test this controller with RSpec?
UPDATE:
Failures:
1) Blog::BlobsController GET #index assigns all widgets as #widgets
Failure/Error: expect(assigns(:blobs)).to eq([blob])
TypeError:
no implicit conversion of Symbol into Integer
# /usr/local/rvm/gems/ruby-2.1.5#rails4/gems/mongo-2.0.4/lib/mongo/server_selector.rb:56:in `[]'
# /usr/local/rvm/gems/ruby-2.1.5#rails4/gems/mongo-2.0.4/lib/mongo/server_selector.rb:56:in `get'
# /usr/local/rvm/gems/ruby-2.1.5#rails4/gems/mongo-2.0.4/lib/mongo/client.rb:170:in `read_preference'
# /usr/local/rvm/gems/ruby-2.1.5#rails4/gems/mongo-2.0.4/lib/mongo/collection/view/readable.rb:318:in `default_read'
# /usr/local/rvm/gems/ruby-2.1.5#rails4/gems/mongo-2.0.4/lib/mongo/collection/view/readable.rb:251:in `read'
# /usr/local/rvm/gems/ruby-2.1.5#rails4/gems/mongo-2.0.4/lib/mongo/collection/view/iterable.rb:38:in `each'
# /usr/local/rvm/gems/ruby-2.1.5#rails4/bundler/gems/mongoid-26f67146a7b7/lib/mongoid/query_cache.rb:207:in `each'
# /usr/local/rvm/gems/ruby-2.1.5#rails4/bundler/gems/mongoid-26f67146a7b7/lib/mongoid/contextual/mongo.rb:116:in `each'
# /usr/local/rvm/gems/ruby-2.1.5#rails4/bundler/gems/mongoid-26f67146a7b7/lib/mongoid/contextual.rb:20:in `each'
# /usr/local/rvm/gems/ruby-2.1.5#rails4/bundler/gems/mongoid-26f67146a7b7/lib/mongoid/criteria.rb:48:in `entries'
# /usr/local/rvm/gems/ruby-2.1.5#rails4/bundler/gems/mongoid-26f67146a7b7/lib/mongoid/criteria.rb:48:in `=='
# ./spec/controllers/blog/blobs_controller_spec.rb:8:in `block (3 levels) in <top (required)>'
Updated spec code:
require 'rails_helper'
RSpec.describe Blog::BlobsController, type: :controller do
describe "GET #index" do
it "assigns all blobs as #blobs" do
blob = Blog::Blob.create!
get :index, {}
expect(assigns(:blobs)).to eq([blob])
end
end
end
Your test says:
blobs = Blog::Blob.create!
This is confusing, because blobs is plural, but you're only creating one blob. So start by renaming that to blob. Then expect(assigns(:blog::blobs)).to eq([blog::blobs]) should be expect(assigns(:blobs)).to eq([blob]).
In the index action, you set #blobs = Blog::Blob.all. The assigns correspond to the controller's instance variables. There's no namespacing.

Paperclip Shoulda Matchers for Miniteset

The Paperclip Documentation provides instruction for setting up Paperclip's Shoulda matchers for RSpec and Test::Unit. However when I tried to set them up for Minitest I wasn't successful (I followed the same instructions as for Test::Unit).
Does anyone knows what requires to make Papercips Shoulda matchers work with Minitest?
In case anyone comes here from Google like I did...this ended up working for me with minitest-spec-rails & some custom assertions
# test_helper.rb
require 'paperclip/matchers'
class ActiveSupport::TestCase
extend Paperclip::Shoulda::Matchers
include Paperclip::Shoulda::Matchers
# ... other code
end
module Minitest
module Assertions
##
# Passes if matcher.matches?(subject) returns true
#
# Example:
#
# def test_validations
# assert_must be_valid, #user
# end
def assert_must(matcher, subject, msg = nil)
msg = message(msg) do
if matcher.respond_to? :failure_message
matcher.failure_message # RSpec 3.x, 1.1
else
matcher.failure_message_for_should # RSpec 2.x, 1.2
end
end
assert matcher.matches?(subject), msg
end
##
# Facilitator to assert_must for use with minitest-spec. If no subject
# given, defaults to matching against the current `subject` or the
# instance variable `#subject`.
#
# Example:
#
# subject { Order.new }
#
# it "should have associations" do
# must belong_to :account
# must have_many :line_items
# end
def must(matcher, subject = #subject || subject, msg = nil)
assert_must matcher, subject, msg
end
##
# Passes if matcher.matches?(subject) returns false
#
# Example:
#
# def test_validations
# assert_wont be_valid, #user
# end
def assert_wont(matcher, subject, msg = nil)
msg = message(msg) do
if matcher.respond_to? :failure_message_when_negated # RSpec 3.x
matcher.failure_message_when_negated # RSpec 3.x
elsif matcher.respond_to? :failure_message_for_should_not
matcher.failure_message_for_should_not # RSpec 2.x, 1.2
else
matcher.negative_failure_message # RSpec 1.1
end
end
if matcher.respond_to? :does_not_match?
assert matcher.does_not_match?(subject), msg
else
refute matcher.matches?(subject), msg
end
end
##
# Facilitator to assert_wont for use with minitest-spec. If no subject
# given, defaults to matching against the current `subject` or the
# instance variable `#subject`.
#
# Example:
#
# subject { User.new }
#
# it "should validate" do
# wont have_valid(:email).when("foo", "foo#bar", "#bar.com")
# end
def wont(matcher, subject = #subject || subject, msg = nil)
assert_wont matcher, subject, msg
end
end
end
I've created a gem for this: https://github.com/cschramm/rspec2minitest
Just include it on your Gemfile and put require 'rspec2minitest/paperclip' in your test_helper.

Resources