-
-
Notifications
You must be signed in to change notification settings - Fork 40
Testing
Janko Marohnić edited this page Sep 21, 2023
·
7 revisions
System (browser) tests for Rodauth actions could look something like this:
# test/system/authentication_test.rb
require "test_helper"
class AuthenticationTest < ActionDispatch::SystemTestCase
include ActiveJob::TestHelper
driven_by :rack_test
test "creating and verifying an account" do
create_account
assert_match "An email has been sent to you with a link to verify your account", page.text
verify_account
assert_match "Your account has been verified", page.text
end
test "logging in and logging out" do
create_account(verify: true)
logout
assert_match "You have been logged out", page.text
login
assert_match "You have been logged in", page.text
end
private
def create_account(email: "user@example.com", password: "secret", verify: false)
visit "/create-account"
fill_in "Login", with: email
fill_in "Password", with: password
fill_in "Confirm Password", with: password
click_on "Create Account"
verify_account if verify
end
def verify_account
perform_enqueued_jobs # run enqueued email deliveries
email = ActionMailer::Base.deliveries.last
verify_account_link = email.body.to_s[/\S+verify-account\S+/]
visit verify_account_link
click_on "Verify Account"
end
def login(email: "user@example.com", password: "secret")
visit "/login"
fill_in "Login", with: email
fill_in "Password", with: password
click_on "Login"
end
def logout
visit "/logout"
click_on "Logout"
end
end
While request tests in JSON API mode with JWT tokens could look something like this:
# test/integration/authentication_test.rb
require "test_helper"
class AuthenticationTest < ActionDispatch::IntegrationTest
test "creating and verifying an account" do
create_account
assert_response :success
assert_match "An email has been sent to you with a link to verify your account", JSON.parse(body)["success"]
verify_account
assert_response :success
assert_match "Your account has been verified", JSON.parse(body)["success"]
end
test "logging in and logging out" do
create_account(verify: true)
logout
assert_response :success
assert_match "You have been logged out", JSON.parse(body)["success"]
login
assert_response :success
assert_match "You have been logged in", JSON.parse(body)["success"]
end
private
def create_account(email: "user@example.com", password: "secret", verify: false)
post "/create-account", as: :json, params: { email: email, password: password, "password-confirm": password }
verify_account if verify
end
def verify_account
perform_enqueued_jobs # run enqueued email deliveries
email = ActionMailer::Base.deliveries.last
verify_account_key = email.body.to_s[/verify-account\?key=(\S+)/, 1]
post "/verify-account", as: :json, params: { key: verify_account_key }
end
def login(email: "user@example.com", password: "secret")
post "/login", as: :json, params: { email: email, password: password }
end
def logout
post "/logout", as: :json, headers: { "Authorization" => headers["Authorization"] }
end
end
Note: Rails now discourages these tests in favor of ActionDispatch::Integration
tests.
In an ActionController::TestCase
to authenticate a request, the session can be
manipulated as follows:
# test/controllers/articles_controller_test.rb
class ArticlesControllerTest < ActionController::TestCase
test "required authentication" do
get :index
assert_response 302
assert_redirected_to "/login"
assert_equal "Please login to continue", flash[:alert]
account = Account.create!(email: "user@example.com", password: "secret123", status: "verified")
login(account)
get :index
assert_response 200
logout
get :index
assert_response 302
assert_equal "Please login to continue", flash[:alert]
end
private
# Manually modify the session into what Rodauth expects.
def login(account)
controller.rodauth.account_from_login(account.email) # [Winston Feb2023] I needed this also to get it working.
session[:account_id] = account.id
session[:authenticated_by] = ["password"] # or ["password", "totp"] for MFA
end
def logout
session.clear
end
end
If you're using multiple configurations with different session prefixes, you'll need to make sure to use those in controller tests as well:
class RodauthAdmin < Rodauth::Rails::Auth
configure do
session_key_prefix "admin_"
end
end
# in a controller test:
session[:admin_account_id] = account.id
session[:admin_authenticated_by] = ["password"]
If you want to access the Rodauth instance in controller tests, you can do so through the controller instance:
# in a controller test:
@controller.rodauth #=> #<RodauthMain ...>
@controller.rodauth(:admin) #=> #<RodauthAdmin ...>
If you're delivering emails in the background, make sure to set Active Job
queue adapter to :test
or :inline
:
# config/environments/test.rb
Rails.application.configure do |config|
# ...
config.active_job.queue_adapter = :test # or :inline
# ...
end