Skip to content
Janko Marohnić edited this page Dec 25, 2023 · 7 revisions

System tests

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

Request tests (ActionDispatch::IntegrationTest)

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

Controller tests (ActionController::TestCase)

Note: Rails now discourages these tests in favor of ActionDispatch::Integration tests.

Since these tests don't load the middleware stack, Rodauth routes won't be available here. To authenticate the session, you can call Rodauth methods directly:

# 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

  # Call `rodauth(:admin)` if you want to use a secondary :admin configuration
  def login(account)
    rodauth.account_from_login(account.email)
    rodauth.login_session("password")
  end

  def logout
    rodauth.logout
  end
end

If you're using RSpec, you'll need to first include the controller test helpers:

RSpec.configure do |config|
  config.include Rodauth::Rails::Test::Controller, type: :controller
end

Emails

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