I added an import method to a controller, and it works just fine when I test it manually from my website, but it is failing in rspec. Here is what my test looks like:
require 'spec_helper'
describe PropertiesController do
let!(:user) { FactoryGirl.create(:user) }
before :each do
sign_in user
end
describe "should upload user properties" do
before do
post :import, spreadsheet: fixture_file_upload("/files/property_upload_template.xlsx")
end
it "should have created records" do
expect(Property.count).to eq 3
# Some other assertions
end
end
end
When I add puts statements inside my import action, including on the very first line, none of them are apparently invoked. The test is generating no errors other than failing the assertions. Similarly, when I look at the test.log file, all that happens is the creation of my test user (and a devise confirmation email gets sent out), but it doesn't appear that the import action is ever hit. The test server seems to recognize the route fine, but it's not actually executing the action.
Is there something wrong with my test configuration?
I had been banging my head for a good couple hours, but I just figured it out. I needed to confirm the user in my user factory. I guess since I enabled the confirmable module in devise, and the user wasn't confirmed, it was silently not allowing me to authenticate...
... Would sure be nice if rspec/rails/devise generated some sort of error pointing me to the problem here.
For the sake of completeness, I'm adding in the code for confirming a user in the version of FactoryGirl at the time of that writing:
FactoryGirl.define do
factory :confirmed_user, :parent => :user do
after(:create) { |user| user.confirm! }
end
end
Related
I have never dabbled outside of model testing when it comes to testing, and I am currently learning how to create my own user authentication instead of relying on Devise. It has been a little bit of time since I have worked with RSpec and not only would I like a little sanity check for syntax, but I can not figure out a way to confirm that my log in and sign up is indeed disappearing when a user logs in.
Here is my current users_logins_spec.rb
require 'rails_helper'
RSpec.describe "UsersLogins", type: :request do
before(:each) do
#user = FactoryGirl.build(:user)
end
it "login with invalid information" do
get login_path
expect(response).to render_template(:new)
post login_path, session: { email: "", password: "" }
expect(response).to render_template(:new)
expect(flash).to be_present
get root_path
expect(flash).not_to be_present
end
it "login with valid information" do
get login_path
post login_path, session: { email: #user.email, password: "password"}
expect(response).to redirect_to(#user)
follow_redirect!
expect(response).to render_template('users/show')
# expect(page).to have_selector('a', login_path)
end
end
Emphasizing the last test because that is the one that fails. I believe that if I were to put ID's on the tags that I want to check I would be able to circumvent the problem that I am having with methods that I understand. My intention is to learn how to manipulate my tests without having to find workarounds that change my code outside of the test, despite how little of a change that would be.
The other question is dealing with redirects. When I want to redirect to the #user url_path of #user, how does RSpec different when interpreting the call? I know that in Rails if I had something like
= link_to "Profile", current_user
it would automatically interpret it as
= link_to "Profile", user_path(current_user)
assuming my user resources within routes.rb.
If anyone can recommend some good tutorials for Rspec with Capybara for Integration and Feature testing that would be awesome, and any help/advice would be greatly appreciated. I am trying to make this as a Integration test instead of a feature test (which to my understanding those are kept within the requests directory and are "less readable" because they aren't so much as user stories but still are checking functionality of the site)
EDIT:
So I figured out part of my problem. I put in a debugger and was able to figure out that my user wasn't actually logging in correctly.
Here is the method that I am using to digest a password within the factory.
user.rb
def User.digest(string)
cost = ActiveModel::SecurePassword.min_cost ? BCrypt::Engine::MIN_COST :
BCrypt::Engine.cost
BCrypt::Password.create(string, cost: cost)
end
factories.rb
FactoryGirl.define do
factory :user do
sequence(:id) { |n| n }
sequence(:name) { |n| "foo#{n}" }
email { "#{name}#example.com" }
password_digest User.digest('password')
end
end
The problem seems to be that my user login credentials are invalid and I am not exactly sure why.
FINAL EDIT - SOLVED
Okay, so I got it working. My problem with the user being incorrect was an easy fix. Instead of using password_digest within the factory I just did changed it to password and password_confirmation and it began the redirect. I originally had FactoryGirl.create(user) and have been switching between the two throughout testing, but in order for this to work with the confirmation it had to be create.
The next issue was actually with assert_select.
Here is the error:
NotImplementedError:
Implementing document_root_element makes assert_select work without needing to specify an element to select from.
I did end up finding a solution. Apparently this is with the latest version of RSpec and the solution that I had found was to set the document_root_element.
Within my spec/support I created a module
**spec/support/assert_select_root.rb
module AssertSelectRoot
def document_root_element
html_document.root
end
end
RSpec.configure do |config|
config.include AssertSelectRoot, :type => :request
end
I guess this was required for tests within spec/requests tests
Joe. You should keep in mind that FactoryGirl.build do not create database instance. So your Users table may be empty if you don't seed it before test.
I suggest you to use .create instead of .build.
This should be very simple to test, but for some reason my test is failing, please consider the following, model bit:
class User < ActiveRecord::Base
def active!
update_attribute(:active, true)
end
end
controller :
def activate
user = User.find_by_uuid(params[:id])
user.active!
puts "id #{user.id}"
end
test :
describe 'activate user' do
let(:user) { FactoryGirl.create(:user) }
before do
sign_in user
visit activate_user_path(id: user.uuid)
puts "id #{user.id}"
end
it 'should be true' do
save_and_open_page
user.active.should be_true
end
end
This test fails :
expected: true value
got: false
But when I do it with browser, the user gets activated without problems. What am I doing wrong? This really looks like a sily test but still doesn't pass, I've spend more than one hour trying out different stuff, none of which worked.
The problem is that the spec still holds the User in the user variable that was created via FactoryGirl and does not know that is was changed in the database. Just reload the user and it should work:
it 'should be true' do
save_and_open_page
user.reload.active.should be_true
end
Btw. if active is a boolean you can also spec it this way (what reads much nicer):
user.reload.should be_active
EDIT Read my comment to this question
I'm very new to rails, so please bear with me.
I've been trying to configure a test for Devise using factory girl and rspec. This has taken me the best part of 2 hours, and scouring half the internet to no avail. Even though there is loads of thread on what seems to be my issue, I just cant figure it out.
This is how my /spec files looks like.
GET Home Gives the correct status code
Failure/Error: sign_in user
NoMethodError:
undefined method `sign_in' for #<RSpec::Core::ExampleGroup::Nested_2:0x00000106f32558>
# ./spec/models/user_spec.rb:6:in `block (2 levels) in <top (required)>
This is the error message I get, trying to achieve the following test:
user_spec.rb:
require 'spec_helper'
describe "GET Home" do
before do
##I have tried all sorts of things here. I have also tried to define a module in devise.rb (see note below*), and then call that module here instead of the 2 lines below. But I get the same error, no local variable or undefined method for ...
user = FactoryGirl.create(:user)
sign_in user
end
describe "GET /Home"
it "Gives the correct status code" do
get root_path
response.status.should be(200)
end
end
in spec/factories/users.rb:
FactoryGirl.define do
factory :user do
name "Christoffer"
email "test#test2.com"
password "testtest"
password_confirmation "testtest"
end
end
And the folling lines is included in spec_helpers.rb
config.include FactoryGirl::Syntax::Methods
config.include Devise::TestHelpers, :type => :controller
Now, by doing this, i get the error above. Can anyone possibly explain what I'm doing wrong here? It might be something really obvious, as I'm not really that well rehearsed in the ways of Rails.
*Note (module I tried to define in devise.rb and insert in the before do):
module ValidUserRequestHelper
# Define a method which signs in as a valid user.
def sign_in_as_a_valid_user_nommels
# ASk factory girl to generate a valid user for us.
#user ||= FactoryGirl.create :user
# We action the login request using the parameters before we begin.
# The login requests will match these to the user we just created in the factory, and authenticate us.
post_via_redirect user_session_path, 'user[email]' => #user.email, 'user[password]' => #user.password
end
end
The purpose of 'spec/requests' is for integration tests. You would test features of your app from the user's perspective (ie. fill in certain info, then click button, then so and so should happen if certain inputs are valid or invalid). Spec/models and spec/controllers are usually for unit tests where you test for smaller parts of your app (ie. what happens if the password and password_confirmation params passed to your user model don't match)
I need to check if my API method sends an email. Based on various threads on SO, i ended up with something like this:
require 'spec_helper'
describe Api::V1::IntervieweesController do
before(:each) do
#project = FactoryGirl.create(:project)
end
describe "POST /api/v1/interviewees/remind_code" do
before(:each) do
#interviewee = FactoryGirl.create(:interviewee, project: #project)
end
it "sends email with code" do
post :remind_code, interviewee: { email: #interviewee.email }
ActionMailer::Base.deliveries.last.to.should == [#interviewee.email]
end
end
end
The problem is, ActionMailer::Base.deliveries is allways nil, even if that method sends that email (when i'm running that method in a 'normal' way in my browser, outside of rspec tests). What's more interesting - it works fine in model specs. Do you have any idea what am i possibly doing wrong?
Rails v4
Ruby v2
rspec v3.0.0.beta1
Please have in mind that the controller's action i'm testing above works fine and sends that email on production/development.
I'm currently new to RSpec and trying to implement some Controller testing with RSpec
In my Rails app, I'm using Devise as my authentication system. My question is, When we test a controller which uses some authentication system (in my case Devise), what is the standard practice?
Is it
1 - to skip the authentication
or
2 - to authenticate the controller
as per the question, following is my controller
require File.dirname(__FILE__) + '/../spec_helper'
describe ProjectsController do
include Devise::TestHelpers
p "starting..."
before(:each) do
p "in before method"
#request.env["devise.mapping"] = Devise.mappings[:user]
sign_in Factory.create(:user)
end
it "should create a project" do
p "should create a project"
end
after(:each) do
#user.destroy unless #user.nil?
end
end
I can only see 'starting', But why its not going to "in before method" and "should create a project"
I'm using Rspec2 and Rails2 on Ubuntu.
Check this: Stubbing Devise in rSpec and Rails3.
Standard practice is not skipping authentication, but effectively making sure that a correct user is logged in (for devise).
Referring to your code: have you tried to create some real test? E.g. something as simple as
it "gets index" do
get :index
response.status.should be == 200
end
I am not sure why you are not seeing the print-statements. Either rspec skips the empty step (there is no real code), or because something else went wrong. But honestly, I am not even sure if using p inside rspec works.
A tool like rubymine allows you to easily debug your specs if you want to step into it (which imho is a better approach then the scattered p statements).