Rails 6 API Rspec request test - Conflicting behavior - ruby-on-rails
I need help with my current testing approach. I am currently testing my React-Rails app using Rspec and initially I setup this in my favourite_cocktail controller:
def destroy
#favouritecocktail = FavouriteCocktail.find(params[:id])
#favouritecocktail.delete
end
On testing the DELETE request using the code below:
describe 'DELETE /api/v1/favourite_cocktails/:id' do
let!(:users) { FactoryBot.create(:user) }
let!(:cocktails) { FactoryBot.create(:cocktail) }
let!(:favourite_cocktail) { FactoryBot.create_list(:favourite_cocktail, 10, cocktail: cocktails) }
let(:cocktail_id) { favourite_cocktail.first.id }
before do
sign_in users
end
before { delete "/api/v1/favourite_cocktails/#{cocktail_id}" }
it 'returns status code 204' do
expect(response).to have_http_status(204)
end
end
it passes, but on my app, the function responsible for deleting the user's favourite cocktail does not work. That is when I click a button to remove a users' favourite cocktail it does not work.
However, if I refactor the destroy action method in the favourite_cocktail controller to this:
def destroy
#favouritecocktail = current_user.favourite_cocktails.find_by(cocktail_id: params[:id])
#favouritecocktail.delete
end
the function responsible for deleting the user's favourite cocktail works on the application. But when I run the test again:
describe 'DELETE /api/v1/favourite_cocktails/:id' do
let!(:users) { FactoryBot.create(:user) }
let!(:cocktails) { FactoryBot.create(:cocktail) }
let!(:favourite_cocktail) { FactoryBot.create_list(:favourite_cocktail, 10, cocktail: cocktails) }
let(:cocktail_id) { favourite_cocktail.first.id }
before do
sign_in users
end
before { delete "/api/v1/favourite_cocktails/#{cocktail_id}" }
it 'returns status code 204' do
expect(response).to have_http_status(204)
end
end
it fails and this is the error message I get during the RSpec testing:
Api::V1::FavouriteCocktailsController DELETE /api/v1/favourite_cocktails/:id returns status code 204
Failure/Error: #favouritecocktail.delete
NoMethodError:
undefined method `delete' for nil:NilClass
# ./app/controllers/api/v1/favourite_cocktails_controller.rb:47:in `destroy'
# ./spec/requests/favourite_cocktails_spec.rb:80:in `block (3 levels) in <main>'
# ./spec/rails_helper.rb:112:in `block (3 levels) in <top (required)>'
# ./spec/rails_helper.rb:111:in `block (2 levels) in <top (required)>'
Now the preferred approach I want is such that my remove favourite_cocktail should work on the application and the Rspec test should hit the DELETE route such that it passes. I know that there is no record of favourite_cocktails created when using FactoryBot and my concern is how to make FactoryBot create a record to be deleted. Below are codes for the API:
Gemfile
ruby '2.6.1'
# Bundle edge Rails instead: gem 'rails', github: 'rails/rails'
gem 'rails', '~> 6.0.2', '>= 6.0.2.2'
# Use postgresql as the database for Active Record
gem 'pg', '>= 0.18', '< 2.0'
# Use Puma as the app server
gem 'puma', '~> 4.1'
# Use SCSS for stylesheets
gem 'sass-rails', '>= 6'
# Transpile app-like JavaScript. Read more: https://github.com/rails/webpacker
gem 'webpacker', '~> 4.0'
# Turbolinks makes navigating your web application faster. Read more: https://github.com/turbolinks/turbolinks
gem 'turbolinks', '~> 5'
# Build JSON APIs with ease. Read more: https://github.com/rails/jbuilder
gem 'jbuilder', '~> 2.7'
# Use Redis adapter to run Action Cable in production
# gem 'redis', '~> 4.0'
# Use Active Model has_secure_password
# gem 'bcrypt', '~> 3.1.7'
# Use Active Storage variant
# gem 'image_processing', '~> 1.2'
# Reduces boot times through caching; required in config/boot.rb
gem 'bootsnap', '>= 1.4.2', require: false
gem 'devise'
gem 'react-rails'
gem "font-awesome-rails"
gem 'foreman'
group :development, :test do
# Call 'byebug' anywhere in the code to stop execution and get a debugger console
gem 'byebug', platforms: [:mri, :mingw, :x64_mingw]
# gem 'rspec-rails', '~> 3.8'
gem 'rspec-rails', git: 'https://github.com/rspec/rspec-rails', branch: "4-0-maintenance"
end
group :development do
gem 'guard-rspec', require: false
gem 'listen', '>= 3.0.5', '< 3.2'
gem 'rb-fsevent', '~> 0.10.3'
gem 'spring'
gem 'spring-watcher-listen', '~> 2.0.0'
gem 'web-console', '>= 3.3.0'
end
group :test do
gem 'database_cleaner'
gem 'factory_bot_rails'
gem 'faker'
gem 'shoulda-matchers'
end
routes.rb
Rails.application.routes.draw do
devise_for :users
get 'landing/index'
get '/index', to: 'landing#index', as: 'index'
namespace :api do
namespace :v1 do
resources :cocktails do
put :favourite, on: :member
end
resources :favourite_cocktails, only: %i[create destroy]
resources :favourites_dashboard, only: %i[index]
end
end
root 'landing#app'
match '*path', to: 'landing#app', via: :all
end
Favourite_cocktails controller
module Api
module V1
class FavouriteCocktailsController < ApplicationController
skip_before_action :verify_authenticity_token
def index
#favouritecocktail = current_user.cocktails
if user_signed_in? && #favouritecocktail
render json: {status: 'SUCCESS', message: 'Loading all Favourite Cocktails', data: #favouritecocktail}, status: :ok
else
render json: {}, status: 401
end
end
def create
fav = FavouriteCocktail.new(favourite_params) do |c|
c.user = current_user
end
if fav.save!
render json: { message: 'created' }, status: :created
else
render json: { errors: fav.errors.full_messages },
status: :unprocessable_entity
end
end
def destroy
#favouritecocktail = current_user.favourite_cocktails.find_by(cocktail_id: params[:id])
#favouritecocktail.delete
end
private
def favourite_params
params.require(:favourite_cocktail).permit(:cocktail_id)
end
end
end
end
Favourite_cocktails factory
FactoryBot.define do
factory :favourite_cocktail do
user
cocktail
end
end
User Factory
FactoryBot.define do
factory :user do
username { Faker::Name.name }
email { Faker::Internet.safe_email }
password { 'foobar' }
password_confirmation { 'foobar' }
end
factory :random_user, class: User do
username { Faker::Name.name }
email { Faker::Internet.safe_email }
password { Faker::Password.password }
password_confirmation { Faker::Password.password_confirmation }
end
end
Cocktails factory
FactoryBot.define do
factory :cocktail do
name { Faker::Restaurant.name }
description { Faker::Lorem.sentence }
ingredients { Faker::Lorem.sentence }
image { Faker::Avatar.image }
end
end
Associations
Favourite_cocktails
class FavouriteCocktail < ApplicationRecord
belongs_to :user
belongs_to :cocktail
validates :user_id, uniqueness: { scope: :cocktail_id }
end
User
class User < ApplicationRecord
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable, :trackable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :validatable
has_many :favourite_cocktails
has_many :favourites, through: :favourite_cocktails, source: :cocktail
validates :username, presence: true, uniqueness: true, allow_blank: false, length: { minimum: 5 }
validates :email, presence: true, length: { minimum: 5 }
end
cocktail
class Cocktail < ApplicationRecord
has_many :favourite_cocktails
has_many :favourited, through: :favourite_cocktails, source: :user
validates :name, presence: true, allow_blank: false, length: { minimum: 5 }
validates :description, presence: true, allow_blank: false, length: { minimum: 10 }
validates :ingredients, presence: true, allow_blank: false, length: { minimum: 10 }
validates :image, presence: true
end
RSpec
Favourite Cocktail Request Spec
require 'rails_helper'
RSpec.describe Api::V1::FavouriteCocktailsController, type: :request do
describe 'POST Favourite Cocktails' do
let!(:users) { FactoryBot.create(:user) }
let!(:cocktails) { FactoryBot.create_list(:cocktail, 10) }
let!(:favourite_cocktail) { FactoryBot.create_list(:favourite_cocktail, 10) }
let(:cocktail_id) { cocktails.first.id }
let(:valid_params) do
{ favourite_cocktail: { cocktail_id: cocktails.first.id } }
end
before do
sign_in users
end
context 'when the request is valid' do
before { post '/api/v1/favourite_cocktails', params: valid_params }
it 'returns status code 201' do
expect(response).to have_http_status(201)
end
it 'returns a created status' do
expect(response).to have_http_status(:created)
end
end
end
describe 'GET all favourite cocktails' do
let!(:users) { FactoryBot.create(:user) }
let!(:favourite_cocktail) { FactoryBot.create_list(:favourite_cocktail, 10) }
let(:cocktail_id) { cocktails.first.id }
before do
sign_in users
get '/api/v1/favourite_cocktails'
end
it 'returns HTTP status 200' do
expect(response).to have_http_status 200
end
end
describe 'DELETE /api/v1/favourite_cocktails/:id' do
let!(:users) { FactoryBot.create(:user) }
let!(:cocktails) { FactoryBot.create(:cocktail) }
let!(:favourite_cocktail) { FactoryBot.create_list(:favourite_cocktail, 10, cocktail: cocktails) }
let(:cocktail_id) { favourite_cocktail.first.id }
before do
sign_in users
end
before { delete "/api/v1/favourite_cocktails/#{cocktail_id}" }
# thing = create(:thing)
# delete '/things', :thing => { :id => thing.id'}
it 'returns status code 204' do
expect(response).to have_http_status(204)
end
end
end
If there are other things you'd like to see to get this working please let me know. Thanks for your help.
It looks to me like your RSpec test setup isn't recreating a valid "happy path" scenario, as the cocktail you are trying to delete doesn't actually belong to the user you signed in as.
Here's a slight refactoring that I think should help fix the test:
describe 'DELETE /api/v1/favourite_cocktails/:id' do
let!(:user) { FactoryBot.create(:user) }
let!(:cocktail) { FactoryBot.create(:cocktail) }
# Adding `user: user` is the important bit here according to your factory
let!(:favourite_cocktail) { FactoryBot.create(:favourite_cocktail, user: user cocktail: cocktail) }
let(:cocktail_id) { favourite_cocktail.id }
before do
sign_in users
end
before { delete "/api/v1/favourite_cocktails/#{cocktail_id}" }
it 'returns status code 204' do
expect(response).to have_http_status(204)
end
end
And here's a change I'd make to the delete implementation so that trying to delete a cocktail you don't have as a favorite doesn't throw an exception and 500:
def destroy
#favouritecocktail = current_user.favourite_cocktails.find_by(cocktail_id: params[:id])
#favouritecocktail.delete if #favouritecocktail
end
Of course, this will return success even if it fails to delete, but you could easily send a 400-level response if that is preferable to your application.
Related
How to pass Rspec test has_many? [Shoulda-matchers]
I´m trying rails to develop a rest api. I´m using rspec and shoulda-matchers. The problem is that one of my test always fails. How can I correct my code, so the test passes (GREEN). user.rb class User < ActiveRecord::Base has_many :cards end card.rb class Card < ActiveRecord::Base belongs_to :user end user_spec.rb require 'rails_helper' RSpec.describe User, type: :model do before { #user = FactoryGirl.create(:user) } subject{ #user } # Columns it { should respond_to :name } # Associations it { should have_many :cards } end Gemfile source 'https://rubygems.org' gem 'rails', '4.2.0' gem 'rails-api' gem 'spring', :group => :development gem 'sqlite3' group :development, :test do gem 'factory_girl_rails' gem 'rspec-rails', '~> 3.0' gem 'shoulda-matchers', '~> 3.0' end Terminal ➜ my_api rspec spec/models/user_spec.rb .F Failures: 1) User should have many :cards Failure/Error: it { should have_many :cards } expected #<User:0x007f897ce0c0d8> to respond to `has_many?` # ./spec/models/user_spec.rb:12:in `block (2 levels) in <top (required)>' Finished in 0.04623 seconds (files took 2.45 seconds to load) 2 examples, 1 failure Failed examples: rspec ./spec/models/user_spec.rb:12 # User should have many :cards
You have to setup the association between the models properly in your user and card factories. factory :card do # ... association :user end Then, it should work. See this to know more about associations in factory-girl. If the above doesn't fix your problem, try doing this way: # spec/factories/user.rb Factory.define :user, :class => User do |u| u.cards { |c| [c.association(:card)] } end
Rspec-Rails-Capybara. "Response" object
I am reading M. Hart's Rails tutorial book now. Stopped at 9.2.1 because of error in testing redirection after patch request. Use Ruby on Rails 4.1 framework, my app's gems: ruby '2.0.0' gem 'rails', '4.1.0' ... gem 'selenium-webdriver', '2.35.1' gem 'capybara', '2.1.0' gem 'factory_girl_rails', '4.2.1' gem 'rspec-rails', '2.13.1' I have UsersController class UsersController < ApplicationController before_action :signed_in_user, only: [:edit, :update] #actions... private #strong parameters... def signed_in_user redirect_to signin_url, notice: "Please sign in." unless signed_in? end end My Rspec+Capybara test for redirection: describe "Authentication" do subject { page } describe "authorization" do describe "for non-signed-in users" do let(:user) { FactoryGirl.create(:user) } describe "in the Users controller" do #... describe "submitting to the update action" do before { patch user_path(user) } specify { expect(response).to redirect_to(signin_path) } end end #... end And when I run rspec spec/ 1) Authentication authorization for non-signed-in users in the Users controller submitting to the update action Failure/Error: specify { expect(response).to redirect_to(signin_path) } NoMethodError: undefined method `assertions' for #<RSpec::Rails::TestUnitAssertionAdapter::AssertionDelegator:0xae34810> # ./spec/requests/authentication_pages_spec.rb:23:in `block (6 levels) in <top (required)>' What's wrong?
Use: gem "rspec-rails", '~> 2.14.0' as per this previously answered question: Rails 4 and RSpec, undefined method `assertions' in routing spec Note that the gem is no longer an rc, so you should be able to use the release version.
rails rspec tests for lib class used by routes contains private methods
Simplecov detected that I was missing some tests on my lib/api_verson.rb class: class ApiVersion def initialize(version) #version = version end def matches?(request) versioned_accept_header?(request) || version_one?(request) end private def versioned_accept_header?(request) accept = request.headers['Accept'] accept && accept[/application\/vnd\.#{Rails.application.secrets.my_app_accept_header}-v#{#version}\+json/] end def unversioned_accept_header?(request) accept = request.headers['Accept'] accept.blank? || accept[/application\/vnd\.#{Rails.application.secrets.my_app_accept_header}/].nil? end def version_one?(request) #version == Rails.application.secrets.my_app_default_api_version && unversioned_accept_header?(request) end end This class is used by the routes file to help setup api versions: namespace :api, path: "", defaults: {format: :json} do scope module: :v1, constraints: ApiVersion.new(1) do get '/alive', to: 'api#alive' end scope module: :v2, constraints: ApiVersion.new(2) do get '/alive', to: 'api#alive' end end This setup was ported from versioning_your_ap_is. I am trying to test the methods here that simplecov is reporting as failures: require 'spec_helper' describe ApiVersion do before(:each) do #apiversion = ApiVersion.new(1) #request = ActionController::TestRequest.new(host: 'localhost') #request.headers["Accept"] = "application/vnd.#{Rails.application.secrets.my_app_accept_header}-#{Rails.application.secrets.my_app_default_api_version}+json" end describe 'Method #versioned_accept_header =>' do it 'Should return the correct accept header version' do binding.pry end end end I am trying to build this first test to attempt??? to #apiversion.send(:unversioned_accept_header, #request) and I am getting the error: #apiversion.send(:unversioned_accept_header, #request) NoMethodError: undefined method `unversioned_accept_header' for #<ApiVersion:0x007fae009bdad8 #version=1> from (pry):1:in `block (3 levels) in <top (required)>' Basically the following methods are flagged: "matches?, versioned_accept_header?, unversioned_accept_header?, and version_one?" I am not the rockstar at rspec and could use some pointers here. Thank you for your help. Btw, this is a rails 4 application running: group :development, :test do gem 'pry' gem 'pry-doc' gem 'pry-debugger' gem 'pry-rails' gem 'pry-plus' gem 'pry-rescue' gem 'pry-stack_explorer' gem 'pry-clipboard' gem 'pry-nav' gem 'rspec-rails' gem 'factory_girl_rails' gem 'faker' gem 'seedbank' gem 'capybara' end group :test do gem 'simplecov', '~> 0.7.1' gem 'shoulda-matchers' gem 'spork-rails' gem 'database_cleaner' gem 'email_spec' gem 'timecop' gem 'json_spec' end
You run this code #apiversion.send(:unversioned_accept_header, #request) but you have method: def unversioned_accept_header?(request) accept = request.headers['Accept'] accept.blank? || accept[/application\/vnd\.#{Rails.application.secrets.my_app_accept_header}/].nil? end try change #apiversion.send(:unversioned_accept_header, #request) -> #apiversion.send(:unversioned_accept_header?, #request) or change method name def unversioned_accept_header? -> def unversioned_accept_header
Undefined method 'patch' for #<Rspec::Core - Rails Tutorial Chapter 9
I'm getting the following error, and can't figure out how to fix it. There are some other pages on Stack Overflow addressing similar issues, but these don't seem to apply, or at least I'm not savvy enough to work it out. When I run the authentication_pages_spec, the issue appears to be with the use of "patch", resulting in the failure below. Note that I've experimented with replacing "patch" with "put" and get the same results. Failures: 1) Authentication authorization for non-signed-in users in the Users controller submitting to the update action Failure/Error: before { patch user_path(user) } NoMethodError: undefined method `patch' for #<RSpec::Core::ExampleGroup::Nested_1::Nested_3::Nested_1::Nested_1::Nested_2:0x007fa7e4df1e50> # ./spec/features/authentication_pages_spec.rb:59:in `block (6 levels) in <top (required)>' Finished in 0.34392 seconds 2 examples, 1 failure NOTE: based on discussion on Stack Overflow here and the blog it references here I elected to change my spec/requests folder to spec/features, since this appears to be what Capybara requires after version 2.0. Here is my Gemfile: source 'https://rubygems.org' ruby '2.0.0' #ruby-gemset=railstutorial_rails_4_0 gem 'rails', '4.0.0' gem 'bootstrap-sass', '2.3.2.0' gem 'pg', '0.15.1' gem 'bcrypt-ruby', '3.0.1' group :development, :test do gem 'rspec-rails', '2.13.1' gem 'guard-rspec', '2.5.0' gem 'spork-rails', github: 'sporkrb/spork-rails' gem 'guard-spork', '1.5.0' gem 'childprocess', '0.3.9' end group :test do gem 'selenium-webdriver', '2.0.0' gem 'capybara', '2.1.0' gem 'growl', '1.0.3' gem 'factory_girl_rails', '4.2.1' gem 'cucumber-rails', '1.3.0', :require => false gem 'database_cleaner', github: 'bmabey/database_cleaner' end gem 'sass-rails', '4.0.0' gem 'uglifier', '2.1.1' gem 'coffee-rails', '4.0.0' gem 'jquery-rails', '2.2.1' gem 'turbolinks', '1.1.1' gem 'jbuilder', '1.0.2' group :doc do gem 'sdoc', '0.3.20', require: false end group :production do gem 'pg', '0.15.1' gem 'rails_12factor', '0.0.2' end I modified my Guardfile to use the spec/features folder instead of the spec/requests folder: require 'active_support/inflector' guard 'spork', :cucumber_env => { 'RAILS_ENV' => 'test' }, :rspec_env => { 'RAILS_ENV' => 'test' } do watch('config/application.rb') watch('config/environment.rb') watch('config/environments/test.rb') watch(%r{^config/initializers/.+\.rb$}) watch('Gemfile') watch('Gemfile.lock') watch('spec/spec_helper.rb') { :rspec } watch('test/test_helper.rb') { :test_unit } watch(%r{features/support/}) { :cucumber } end guard 'rspec', all_after_pass: false, cli: '--drb' do watch(%r{^spec/.+_spec\.rb$}) watch(%r{^lib/(.+)\.rb$}) { |m| "spec/lib/#{m[1]}_spec.rb" } watch('spec/spec_helper.rb') { "spec" } # Rails example watch(%r{^app/(.+)\.rb$}) { |m| "spec/#{m[1]}_spec.rb" } watch(%r{^app/(.*)(\.erb|\.haml)$}) { |m| "spec/#{m[1]}#{m[2]}_spec.rb" } watch(%r{^app/controllers/(.+)_(controller)\.rb$}) { |m| ["spec/routing/#{m[1]}_routing_spec.rb", "spec/#{m[2]}s/#{m[1]}_#{m[2]}_spec.rb", "spec/acceptance/#{m[1]}_spec.rb"] } watch(%r{^spec/support/(.+)\.rb$}) { "spec" } watch('config/routes.rb') { "spec/routing" } watch('app/controllers/application_controller.rb') { "spec/controllers" } # Capybara features specs watch(%r{^app/views/(.+)/.*\.(erb|haml)$}) { |m| "spec/features/#{m[1]}_spec.rb" } # Turnip features and steps watch(%r{^spec/acceptance/(.+)\.feature$}) watch(%r{^spec/acceptance/steps/(.+)_steps\.rb$}) { |m| Dir[File.join("**/#{m[1]}.feature")][0] || 'spec/acceptance' } # Custom Rails Tutorial specs watch(%r{^app/controllers/(.+)_(controller)\.rb$}) do |m| ["spec/routing/#{m[1]}_routing_spec.rb", "spec/#{m[2]}s/#{m[1]}_#{m[2]}_spec.rb", "spec/acceptance/#{m[1]}_spec.rb", (m[1][/_pages/] ? "spec/features/#{m[1]}_spec.rb" : "spec/features/#{m[1].singularize}_pages_spec.rb")] end watch(%r{^app/controllers/sessions_controller\.rb$}) do |m| "spec/features/authentication_pages_spec.rb" end end Users controller here: class UsersController < ApplicationController attr_accessor :name, :email before_action :signed_in_user, only: [:edit, :update] def show #user = User.find(params[:id]) end def new #user = User.new end def create #user = User.new(user_params) if #user.save sign_in #user flash[:success] = "Welcome to the Sample App!" redirect_to #user else flash[:error] = "Oops!" render 'new' end end def edit #user = User.find(params[:id]) end def update #user = User.find(params[:id]) if #user.update_attributes(user_params) flash[:success] = "Profile updated" sign_in #user redirect_to #user else render 'edit' end end private def user_params params.require(:user).permit(:name, :email, :password, :password_confirmation) end # Before filters def signed_in_user redirect_to signin_url, notice: "Please sign in." unless signed_in? end end Spec helper file here: require 'rubygems' require 'spork' #uncomment the following line to use spork with the debugger #require 'spork/ext/ruby-debug' Spork.prefork do 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 } ActiveRecord::Migration.check_pending! if defined?(ActiveRecord::Migration) RSpec.configure do |config| config.fixture_path = "#{::Rails.root}/spec/fixtures" config.use_transactional_fixtures = true config.infer_base_class_for_anonymous_controllers = false config.order = "random" config.include Capybara::DSL # Added below myself, troubleshooting an 'undefined method 'patch'' message config.include Rails.application.routes.url_helpers end end Spork.each_run do # This code will be run each time you run your specs. end Finally, for good measure, the config/routes.rb file is here: SampleApp::Application.routes.draw do resources :users resources :sessions, only: [:new, :create, :destroy] root 'static_pages#home' match '/signup', to: 'users#new', via: 'get' match '/signin', to: 'sessions#new', via: 'get' match '/signout', to: 'sessions#destroy', via: 'delete' match '/help', to: 'static_pages#help', via: 'get' match '/about', to: 'static_pages#about', via: 'get' match '/contact', to: 'static_pages#contact', via: 'get' There is a similar discussion on Stack Overflow here, but the answer on that post is to move the tests from ./spec/requests to ./spec/features - which I've already done. Another related discussion here, where the answer is to use require 'spec_helper' in the top of the feature file...which I already have. One last observation: seems like much of the discussion on this topic indicates the issue is with Capybara needing tests located in the spec/features folder for it to be able to access the URL helpers - but my authentication_pages_spec.rb file seems to have no problem with 'visit'. Appreciate any insight! The Rails Tutorial for Rails 4.0 is in beta, have been trying to figure out if this is a bug. * UPDATE * Got everything passing green after implementing Peter's suggestion. Following is the revised code from the authentication_pages_spec file (partial, just the "authorization" section): describe "authorization", type: :request do . . . 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 "visiting Users#edit page" do before { visit edit_user_path(wrong_user) } it { should_not have_title(full_title('Edit user')) } end describe "submitting a PATCH request to the Users#update action" do before { patch user_path(wrong_user) } # NOTE: Rails Tutorial uses root_url below not root_path specify { expect(response).to redirect_to(root_path) } end end end end
get, put, patch, etc. are only defined for :controller and :request specs, not for a :feature spec, which your authentication_pages_spec.rb test implicitly became when you changed its location. If you include type: :request in your top level describe, it should work.
this answer also fixes this rspec test failing without error which is part of the Rails Tutorial Chapter 9 (spec/requests/authentication_pages_spec.rb) describe "submitting to the update action" do before { patch user_path(user) } specify { response.should redirect_to(signin_path) } end
Rails 3: uninitialized constant FactoryGirl
I am trying to create my first controller test using FactoryGirl for my Rails application, but I keep retrieving the following error: uninitialized constant FactoryGirl My Factories.rb file looks like this: FactoryGirl.define do factory :offer, class: "Offer" do |f| f.title "Some title" f.description "SomeDescription" end end And my controller test looks like this: require 'spec_helper' describe OffersController do def valid_session {} end describe "GET index" do before { #offer = FactoryGirl.create(:offer) } it "assigns all offers as #offers" do get :index, {}, valid_session assigns(:offers).should eq([#offer]) end end end My Gemfile looks like this: group :development, :test do gem 'sqlite3' gem 'rspec-rails' gem 'capybara', '1.1.2' gem 'factory_girl_rails', '>= 4.1.0', :require => false end What might I be missing since FactoryGirl isn't present?
You propably forgotten to require factory_girl in spec_helper.rb.