Docs for Testing-Rails need update for request specs
brentgreeff opened this issue · 2 comments
This page https://github.com/Sorcery/sorcery/wiki/Testing-Rails needs updating.
For request specs (I dont need helpers for system specs - and I dont use controller specs)
I added:
config.include Sorcery::TestHelpers::Rails::Request, type: :request
- in rails_helper.rb
- post 'login' => "user_sessions#create"
+ post 'login' => "user_sessions#create", as: 'user_sessions'
I had to make this change - because I got undefined method user_sessions_url
Then using pry I figured out that the password assumed is secret
- which is not a good password since my user model has
validates :password, length: { minimum: 8 }, if: -> {
new_record? || changes[:crypted_password]
}
In my test - I added
User.class_eval do
clear_validators!
end
- which I dont really want to do.
Configuration
- Sorcery Version:
0.16.3
- Ruby Version:
3.0.4p208
- Framework:
rails-7.0.3.1
- Platform:
OSX
This messed up my user specs - so I changed it to
before do
User.class_eval { clear_validators! }
end
after do
Object.send(:remove_const, :User)
load 'app/models/user.rb'
end
So I decided to look in the code - https://github.com/Sorcery/sorcery/blob/master/lib/sorcery/test_helpers/rails/request.rb
def login_user(user = nil, password = 'secret', route = nil, http_method = :post)
I see the password param
My call is
login_user( create(:user), password: 'password' )
That doesnt work - using pry in user_sessions controller.
params
=> #<ActionController::Parameters {"email"=>"axs@gms-community.com", "password"=>#<ActionController::Parameters {"password"=>"password"} permitted: false>, "controller"=>"user_sessions", "action"=>"create"} permitted: false>
Unfortunately, Sorcery is pretty irksome in that you can't sign in a user until they're active... and if you create a user with an active state sorcery will overwrite the user's activation state and make them an inactive user before creating the record. I suspect you're running into that. You need to ensure activate!
is called on your user after creation by declaring it like let(:user) { create :user, &:activate! }
, or define a trait that will trigger activation after the record is created:
# spec/factories/users.rb
FactoryBot.define do
factory :user, class: 'User' do
password { 'MyDefaultFactoryPassword!' }
# Alternative:
# let(:user) { create :user, &:activate! }
trait :active do
transient do
activation_state { :active }
end
end
after :create do |user, evaluator|
user.activate! if evaluator.activation_state == :active
end
end
end
To support before { sign_in user }
in your regular specs, add a file with a sign in helper to spec/support (or rely on the rails request one + ensure your rspec config is loading it):
module Sorcery::TestHelpers::Rails
# Adapted from Sorcery::TestHelpers::Rails::Request
def sign_in(user, password = 'MyDefaultFactoryPassword!', route = nil, http_method = :post)
route ||= login_url
username_attr = user.sorcery_config.username_attribute_names.first
password_attr = user.sorcery_config.password_attribute_name
send(
http_method,
route,
params: {
username_attr => user.send(username_attr),
password_attr => password
}
)
end
end
But since you're testing actual login here, you would write something like:
describe '/user_sessions' do
subject { response }
let(:user) { create :user, :active, password: }
let(:password) { 'P@ssw0rd!' }
describe 'POST /login' do
let(:request) { post login_path(params: { email: user.email, password: }) }
it 'succeeds' do
request
should have_http_status(:success)
end
it 'logs in user' do
expect { request }.to change { user.reload.logged_in? }.from(false).to(true)
end
end
end