I have built out a controller spec for my user model, and it passes, although I feel like it should fail. The spec is below:
describe UsersController do
include Devise::TestHelpers
let (:user) do
FactoryGirl.create(:user)
end
let (:other_user) do
FactoryGirl.create(:user)
end
before :each do
#request.env["devise.mapping"] = Devise.mappings[:user]
sign_in user
end
describe "#index" do
it "can GET 'index'" do
get :index
response.should be_success
end
it "populates a list of users" do
get :index
expect(assigns(:users)).to eq([user])
end
end
end
The line "expect(assigns(:users)).to eq([user])" passes, but I feel like it should fail. After all, I've created two users (user and other_user) up at the top. I'm clearly misunderstanding what's going on, so can someone explain it?
let is lazy; it won't create the user until the first time it's called (at which point the result is memoized). Since you call user but not other_user, only the first user is actually created, and the spec passes.
Use let! if you want eager evaluation, or make sure you call other_user somewhere.
RSpec Documentation
Related
Im trying to set up a (basic) test for a new feature I am going to implement. I have a job controller and instead of default showing all jobs I like to hide all the ones which is archived. I tried different ways but it seems like i am missing a piece or two of this puzzle. First i tried with calling 'visit' but get the message it does not exist. Second approach is using 'render' but that also ends up in a error saying render does not exists. (can i even use these methods in a controller spec?)
Is it wrong to put this in a controller test?
2 last test are causing errors
require "rails_helper"
require "spec_helper"
describe JobsController, :type => :controller do
context 'GET index' do
it "should be successful" do
get :index
expect(response).to be_success
end
it "renders the index template" do
get :index
expect(response).to render_template("index")
end
it "should not show any archived jobs as default" do
visit jobs_path
page.should have_no_content("Archived")
end
it 'should show the headers' do
render :template => 'job/index', :layout => 'layouts/job'
rendered.should_not contain('Archived')
end
end
end
Capybara is used for feature specs, and its matchers can be used in view specs.
Controller specs, by default, don't actually render the view because they're the wrong place to be checking for page content - https://www.relishapp.com/rspec/rspec-rails/docs/controller-specs
You should probably move some of your tests to feature tests/view tests
I'm relatively new to testing and very new to Rails 4 and rSpec. I am trying to test a controller that uses Devise for authentication and I am stuck. All of the examples I can find are for Rails 3.
I'm using Rails 4.0.3, Devise 3.2.3, rSpec 2.14.1 and FactoryGirl 4.4.0.
class LessonPlansController < ApplicationController
before_action :authenticate_user!
# GET /lesson_plans
def index
#lesson_plans = current_user.lesson_plans.to_a
end
.
.
.
private
# Use callbacks to share common setup or constraints between actions.
def set_lesson_plan
#lesson_plan = LessonPlan.find(params[:id])
end
# Only allow a trusted parameter "white list" through.
def lesson_plan_params
params[:lesson_plan]
end
def lesson_plan_params
params.require(:lesson_plan).permit(:title, :synopsis)
end
end
Here are my factory definitions: (Maybe I don't need to define user_id in the lesson_plan factory?)
FactoryGirl.define do
factory :user do
sequence( :username ) { |n| "user#{n}" }
sequence( :email ) { |n| "foo#{n}#example.com" }
password 'foobarbaz'
password_confirmation 'foobarbaz'
created_at Time.now
updated_at Time.now
end
end
FactoryGirl.define do
factory :lesson_plan do
user_id 1
title "The French Revolution"
synopsis "Background and events leading up to the French Revolution"
end
end
And the test part is where I get stuck.
describe LessonPlansController do
let(:valid_attributes) { { } }
let(:valid_session) { {} }
# describe "GET index" do
it "assigns all lesson_plans as #lesson_plans" do
user=FactoryGirl.create(:user)
sign_in user
lesson_plan = LessonPlan.create! valid_attributes
get :index, {}, valid_session
assigns(:lesson_plans).should eq([lesson_plan])
end
end
I'm not sure what to put in valid_attributes and valid_session (or if I even need them). The test will get as far as signing in the user, but will fail on creation of the lesson_plan. Admittedly this is the default/generated test for rSpec, but I am not sure how to proceed.
Examples I have seen use a before block to set up the user. I haven't been able to find anything on the Devise wiki page covering how to write basic rSpec tests for a controller that requires the user to be logged in. Any pointers would be greatly appreciated!
"I'm not sure what to put in valid_attributes and valid_session (or if I even need them)."
Well that depends what you're testing for.. Say you're testing validations & want to ensure that a record not be created if x column is set to null... then you could try to specifically create a record with invalid attributes (e.g. column: nil) and expect the result to not return true; maybe you want to ensure that it IS created with valid attributes.
You can btw, use `attributes_for(:factory_name)`` since you're using FactoryGirl. And no you don't necessarily need to specify the user's id in your lesson plan factory; unless you always want it to reference user 1. You can simply reference user with no value. Check out http://everydayrails.com/2012/03/12/testing-series-intro.html and especially parts 3-5 for an introduction to testing with RSPec.. I found this a pretty easy to follow guide when I was getting started.
I want to test that my edit recipe page renders using rspec, though it doesn’t route to
recipes/edit
it routes to recipes/id/edit (id being replaced with a number)
my current test looks like this
describe "Show Edit Recipe Page" do
it "should display edit recipe page" do
get :edit
response.should be_success
response.should render_template(:edit)
end
end
how can i test this page correctly, at the moment my tests are failing
Problem
Your example doesn't include the code needed to actually test a controller object. RecipeController is not defined in your spec.
Solution
Make sure your controller specs live under spec/controllers or have an explicit type: :controller set. Then, actually describe a controller, either using the implicit subject or by setting up a controller instance in a before or test block. As the most basic example:
describe RecipeController do
# test something using the implied RecipeController.new
end
More Reading
RSpec Controller Specs
The get needs the id of the recipe passed in the params hash:
let(:recipe) { Factory.create(:recipe) }
it "should display edit recipe page" do
get :edit, :id => recipe.id
response.should be_success
response.should render_template(:edit)
end
I'm trying to move to rspec for testing, but I can't get controller testing to work with user authentication. Testing a route that doesn't require a user works.
require 'spec_helper'
describe UddsController do
include Devise::TestHelpers
render_views
before (:each) do
#user = User.new(:email => "test#user.com", :username => "test123")
#user.roles << Role.find_or_create_by_name("admin")
#user.save
sign_in #user
end
it "should get index" do
get :index
response.should be_success
end
I just get
2) UddsController should get index
Failure/Error: response.should be_success
expected success? to return true, got false
# ./spec/controllers/udds_controller_spec.rb:21
I'm not using factory_girl. All the example fixes here and on google seem to. I don't see why what I've done wouldn't work. Error is useless in debugging.
I know this question has been asked to death. I've read every blog and forum I can find. I'm at a dead end.
It might be redirecting. be_success returns false for any non-2xx status codes (like 302). Try checking the value of response.status -- if it's redirecting, it probably means your authentication or authorization scheme is producing an unexpected result.
Try adding puts response.body before your assertion, and see what the page you are requesting says. If you can't figure it out from there, perhaps edit your question to include the output?
If you are using devise's "confirmable" module which makes users click a link in an email to confirm their address, then when you use "sign_in" in the tests you also have to fake email confirming. It looks something like this:
sign_in #user
#user.confim!
I've got a few questions about Capybara. And I might as well ask here since the RDOC in the github page for Capybara is great to get it set up and running. But where is the API or list of available methods??
First. Per *_spec.rb file, should scenario only exist once? Or is it fine to have multiple scenario's in one file?
For example, in spec/request/user_spec.rb:
require 'spec_helper'
feature 'User actions' do
background do
data = {
:first_name => 'foo',
:last_name => 'bar',
...
}
user = User.new(data, :as => :user)
user.save
end
scenario 'User can browse home page' do
visit root_path
page.should have_content('Homepage')
end
scenario 'User should not be able to visit the dashboard' do
visit dashboard_root_path
page.should have_content('You are not authorized to access this page.')
end
end
If there is anything wrong with the code structure above, or if there is room for improvement. I am open feedback.
Second. I notice with the code above. If I have config.use_transactional_fixtures = false in spec/spec_helper.rb, it saves the user twice. This means, in my test database / user table, I would have 2 users named 'foo bar'. Is this normal?
Third. I have a form that has an HTML button. When user clicks on this button, jQuery submits the form. How would I test this with Capybara? I don't think click_button "Add" will do the trick.
Fourth. How would I sign in users in Capybara? I am using Devise. Would sign_in User.first do the trick? And would I be able to access current_user in Capybara?
Lastly, if anyone knows any "Getting Started" guides / tutorials on Rspec + Capybara. Please do mention.
I've also switched over to writing request specs ever since i decided that I was no longer liking Cucumber.
ONE) Having multiple scenarios is indeed fine. You get to use all the other great features of rspec, so I would suggest also using contexts as in the code at the bottom.
TWO) This can probably be solved by using the Rspec Set Gem And the Database Cleaner Gem. Also: The Original Rationale for Set
Warning: make sure you set up DatabaseCleaner correctly when you use set. My own setup (which may be a little overkill but is working for me):
config.before(:suite) do
DatabaseCleaner.clean_with :truncation
end
config.before(:all) do
DatabaseCleaner.clean_with :truncation
end
config.after(:all) do
DatabaseCleaner.clean_with :truncation
end
config.after(:suite) do
DatabaseCleaner.clean_with :truncation
end
THREE) yep! click_button "Add" should work! The complete capybara API is useful but took me a while to grok. Of most relevant importance are the actions and rspec matchers.
example:
click_button "Add"
page.should have_content("Successfully Added")
you can narrow the scope with element finders.
FOURTH) Devise provides helpers. there is a sign_in helper. read the dox :). Here's a demo:
feature 'User actions' do
background do
data = {
:first_name => 'foo',
:last_name => 'bar',
...
}
#user = User.new(data, :as => :user)
#user.save
end
context "no user is signed in" do
scenario 'User can browse home page' do
visit root_path
page.should have_content('Homepage')
end
scenario 'User should not be able to visit the dashboard' do
visit dashboard_root_path
page.should have_content('You are not authorized to access this page.')
end
end
context "user is signed in" do
before :each do
sign_in #user
end
[more scenarios]
end
end
ultimately of course, you'd prolly want to split this up into more specific features. Probably have a "Public Navigation" Feature for all the tests that are about guests seeing content, and then a separate feature for a user signing in, etc.
I am not aware of capybara, but a full list of available methods can be found here:
http://rubydoc.info/github/jnicklas/capybara/master#
hope, that helps