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.

Resources