Testing User Model (Devise Authentication) with MiniTest - ruby-on-rails

I'm trying to test user model, for which I've devise authentication.
The problem I'm facing is,
1. Having 'password'/'password_confirmation' fields in fixtures is giving me invalid column 'password'/'password_confirmation' error.
If I remove these columns from fixture and add in user_test.rb
require 'test_helper'
class UserTest < ActiveSupport::TestCase
def setup
#user = User.new(name: "example user",
email: "example#example.com",
password: "Test123",
work_number: '1234567890',
cell_number: '1234567890')
end
test "should be valid" do
assert #user.valid?
end
test "name should be present" do
#user.name = "Example Name "
assert #user.valid?
end
end
The error I'm getting is:
test_0001_should be valid FAIL (0.74s)
Minitest::Assertion: Failed assertion, no message given.
test/models/user_test.rb:49:in `block in <class:UserTest>'
test_0002_name should be present FAIL (0.01s)
Minitest::Assertion: Failed assertion, no message given.
test/models/user_test.rb:54:in `block in <class:UserTest>'
Fabulous run in 0.75901s
2 tests, 2 assertions, 2 failures, 0 errors, 0 skips
I'm wondering why my user object is not valid?
Thanks

I got a work around after some investigation like below:
Add a helper method for fixture:
# test/helpers/fixture_file_helpers.rb
module FixtureFileHelpers
def encrypted_password(password = 'password123')
User.new.send(:password_digest, password)
end
end
# test/test_helper.rb
require './helpers/fixture_file_helpers.rb'
ActiveRecord::FixtureSet.context_class.send :include, FixtureFileHelpers
And make fixture like this:
default:
email: 'default#example.com'
name: "User name"
encrypted_password: <%= encrypted_password %>
work_number: '(911) 235-9871'
cell_number: '(911) 235-9871'
And use this fixture as user object in user test.
def setup
#user = users(:default)
end

Related

Minitest and Fixtures: Passing in the correct params?

So I am trying to create a simple integration test in Rails. I want to test my login form. I just can't really figure out how to pass my params correctly. My .yml file is called agents.yml. My fixture file is:
one:
first_name: firstNameTest
last_name: lastNameTest
email: test#test.com
encrypted_password: <%= Devise::Encryptor.digest(Agent, '123456') %>
that should be ok.
Two tests I tried which both give me an error. The first one, following the Ruby.docs:
class FlowsTest < ActionDispatch::IntegrationTest
test "Login and navigate" do
get "/agents/sign_in"
post "/agents/sign_in", email: agents(:one).email, password:
agents(:one).password
follow_redirect!
end
end
the second version:
class FlowsTest < ActionDispatch::IntegrationTest
test "Login and navigate" do
get "/agents/sign_in"
post "/agents/sign_in", agent: {email: agents(:one).email, password: '123456'}
follow_redirect!
end
end
Both throw me an error:
Error:
FlowsTest#test_Login_and_navigate:
ArgumentError: unknown keywords: email, password
test/integration/Flows_test.rb:6:in `block in <class:FlowsTest>'
I guess I'm passing in the params in a wrong way. Because email and password should be taken from the fixtures, or am I wrong? Can anyone help? Would be very much appreciated. Thank you all in advance!
Solved by:
require 'test_helper'
class FlowsTest < ActionDispatch::IntegrationTest
fixtures :agents
def test_login
get "/agents/sign_in"
assert_equal 200, status
post "/agents/sign_in", params: { email: agents(:one).email,
password: agents(:one).password }
follow_redirect!
assert_equal 200, status
assert_equal "/", path
end
end

Import a helper function within an integration test

I have an integration test where I need to call the log_in function (defined in Session Helper) whose parameter is a user created within a fixture.
app/helpers/sessions_helper
module SessionsHelper
def log_in(user)
session[:user_id] = user.id
end
.
.
.
end
Then I have the following fixture test/fixtures/user.yml
johndoe:
first_name: John
last_name: Doe
email: john#doe.com
password_digest: <%= User.digest('password') %>
And then the following integration test test/integration/user_navigation_test
require 'test_helper'
class UserNavigationTest < ActionDispatch::IntegrationTest
def setup
#user = users(:johndoe)
end
test "login with invalid information" do
log_in #user
end
end
When I run the test, I have the following error.
ERROR["test_login_with_invalid_information", UserNavigationTest, 1.2090159619983751]
test_login_with_invalid_information#UserNavigationTest (1.21s)
NoMethodError: NoMethodError: undefined method `log_in' for #<UserNavigationTest:0x000000065cb3f8>
test/integration/user_navigation_test.rb:10:in `block in <class:UserNavigationTest>'
I've tried to declare the log_in function within the test_helper but it didn't work either ; something to do with the configuration apparently.
How can I handle this?

How do I write this spec in MiniTest/shoulda syntax?

I have this spec that I want to translate to MiniTest.
describe User do
subject { build(:user, provider: 'foo') }
# don't validate presence of password when provider is present
it do
should_not validate_presence_of(:password)
end
end
I tried this. I am getting an error of undefined method 'should_not' for UserTest
class UserTest < ActiveSupport::TestCase
def setup
#user = build_stubbed(:user)
end
test "responds to name" do
assert_respond_to #user, :name
end
should validate_presence_of(:password)
test "do not validate presence of password when provider is present" do
build_stubbed(:user, provider: 'foo')
should_not validate_presence_of(:password)
end
end
I want to change the context for one test, where the subject gets a provider attribute, which should disable the presence validator on the password field.
Here's the full error:
UserTest#test_presence_of_password:
NoMethodError: undefined method `should_not' for #<UserTest:0x007feaa82c1c68>
test/models/user_test.rb:45:in `block in <class:UserTest>'
I found that the better way to do this is to revert to good old MiniTest:
test "uniqueness of email with a different provider" do
email_user = create(:user, email: "foo#bar.com")
facebook_user = build_stubbed(:facebook_user, email: "foo#bar.com")
assert facebook_user.valid?, "should be valid with same email if provider is different"
end
Take a look at the minitest-rails-shoulda gem. If you use it I assume the test would look like this:
describe User do
subject { build_stubbed(:user) }
it { must validate_presence_of(:password) }
describe "when a provider is present" do
subject { build_stubbed(:user, provider: 'foo') }
it { wont validate_presence_of(:password) }
end
end

FactoryGirl Sequences aren't working

I'm doing exactly what is says in the documentation, but still getting a validation error:
Validation failed: Email has already been taken
FactoryGirl.define do
sequence :email do |n|
"test#{n}#factory.com"
end
factory :user do
email
password '12345678'
password_confirmation '12345678'
goal_id 1
experience_level_id 1
gender 'Female'
end
end
Anyone know what I'm doing wrong here?
EDIT:
Here is the failing spec. It works fine if you uncomment subject block and comment out the FactoryGirl stuff. I'm trying to switch to using FactoryGirl.
require 'spec_helper'
require 'cancan/matchers'
describe User do
# subject(:user) do
# Program.create!(name: 'test', gender: 'Female', goal_id: '1', experience_id: '1')
# User.create!(email: 'test#test.com', password: '12345678', password_confirmation: '12345678', goal_id: '1', experience_level_id: '1', gender: 'Female')
# end
FactoryGirl.create(:program)
puts FactoryGirl.create(:user).inspect
it "should be assigned a program when it's created" do
user.programs.should exist
end
it "should be valid with a name, goal, password, password_confirmation, experience_level, and gender" do
user.should be_valid
end
it { should respond_to(:programs) }
its('programs.last.name') {should == 'Test'}
it "should be assigned imperial as the default measurement_units" do
user.measurement_units.should eq("imperial")
end
it 'validates presence of gender, goal_id, and experience_level_id' do
user = User.new(gender: nil)
user.should validate_presence_of(:gender)
user.should validate_presence_of(:goal_id)
user.should validate_presence_of(:experience_level_id)
end
end
Edit 2:
I've updated my spec following the suggestion of one of the answers, so now my spec runs, but I get a failing test with a validation error. Here is the updated code:
describe User do
subject(:user) do
# Program.create!(name: 'test', gender: 'Female', goal_id: '1', experience_id: '1')
# User.create!(email: 'test#test.com', password: '12345678', password_confirmation: '12345678', goal_id: '1', experience_level_id: '1', gender: 'Female')
FactoryGirl.create(:program)
FactoryGirl.create(:user)
end
it "should be assigned a program when it's created" do
user.programs.should exist
end
And the message from the failing test:
Failures:
1) User should be assigned a program when it's created
Failure/Error: FactoryGirl.create(:user)
ActiveRecord::RecordInvalid:
Validation failed: Email has already been taken
# ./spec/models/user_spec.rb:9:in `block (2 levels) in <top (required)>'
# ./spec/models/user_spec.rb:13:in `block (2 levels) in <top (required)>'
Any ideas?
You can't just create Factory instances in the middle of a test class like that. FactoryGirl is a replacement for the instantiation you had in the code before - leave the subject block, and simply replace the two create lines with the FactoryGirl calls.
(even better, they should be let blocks not a subject block, but that's a different story)
If you are not doing things in a context Rspec knows about, it has no way of cleaning up afterwards.
What do you have in your Gemfile? I have better success using this
gem 'factory_girl_rails', :group => :test
and not listing it in the "group :development, :test do" section.

Rails Rspec Model Spec User :email ActiveRecord::RecordInvalid

Trying to figure out why my rspec test is failing. Most notable is the Failure message that seems contradictory. Stating I have an ActiveRecord::RecordInvalid error and that is exactly what I'm asserting should happen.
Here is my user.rb
...
validates_presence_of :email
...
Here is my users_spec.rb
...
it "is invalid without email" do
Factory(:user, email: nil).should raise_error(ActiveRecord::RecordInvalid)
end
...
here is the output:
Failures:
1) User a user (in general) is invalid without email
Failure/Error: Factory(:user, email: nil).should raise_error(ActiveRecord::RecordInvalid)
ActiveRecord::RecordInvalid:
Validation failed: Email is invalid, Email can't be blank
# ./spec/models/user_spec.rb:34:in `block (3 levels) in <top (required)>'
Originally I was testing it this way but it kept failing, so I decided to specify on what error I was expecting.
it "is invalid without email" do
Factory(:user, email: nil).should_not be_valid
end
The reason your code isn't working is that you're trying to create an invalid model before actually testing it for validity. What you want to do is to create a valid model, change something and check that it is invalid, like this:
it "is invalid without email" do
user = Factory(:user)
user.email = nil
user.should_not be_valid
end
I personally like to define my model in a before block, set is as the subject and then change attributes in each spec and check for validity, like this:
before do
#user = FactoryGirl.create(:user)
end
subject { #user }
it "is invalid without email" do
subject.email = nil
should_not be_valid
end
For the record, if you wanted to test that the record creation raised an error (which is definitely not the advisable way to do this), you could do it by wrapping the Factory call in a lambda, like this:
lambda {
Factory(:user, :email => nil)
}.should raise_error(ActiveRecord::RecordInvalid)

Resources