This commit is contained in:
Dan Milne
2025-10-26 22:03:03 +11:00
parent b5b1d94d47
commit e4e7a0873e
4 changed files with 697 additions and 0 deletions

View File

@@ -0,0 +1,90 @@
require "test_helper"
class ApplicationJobTest < ActiveJob::TestCase
test "should inherit from ActiveJob::Base" do
assert ApplicationJob < ActiveJob::Base
end
test "should have proper job configuration" do
# Test that the ApplicationJob is properly configured
assert_respond_to ApplicationJob, :perform_now
assert_respond_to ApplicationJob, :perform_later
end
test "should handle job execution" do
# Create a simple test job to verify the base functionality
test_job = Class.new(ApplicationJob) do
def perform(*args)
args
end
end
# Test synchronous execution
result = test_job.perform_now("test", "data")
assert_equal ["test", "data"], result
# Test asynchronous execution using the test helper
assert_enqueued_jobs 1 do
test_job.perform_later("test", "data")
end
end
test "should queue jobs with proper arguments" do
test_job = Class.new(ApplicationJob) do
def perform(*args)
# No-op for testing
end
end
assert_enqueued_jobs 1 do
test_job.perform_later("arg1", "arg2", { key: "value" })
end
# Job class name may be nil in test environment, focus on args
assert_equal ["arg1", "arg2", { key: "value" }], enqueued_jobs.last[:args]
end
test "should have default queue configuration" do
# Test that jobs have proper queue configuration
test_job = Class.new(ApplicationJob) do
def perform(*args)
# No-op
end
end
job_instance = test_job.new
assert_respond_to job_instance, :queue_name
end
test "should handle job serialization and deserialization" do
# Test that Active Record objects can be properly serialized
user = users(:alice)
test_job = Class.new(ApplicationJob) do
def perform(user_record)
user_record.email_address
end
end
assert_enqueued_jobs 1 do
test_job.perform_later(user)
end
# Verify the job was queued with user (handling serialization)
args = enqueued_jobs.last[:args]
if args.is_a?(Array) && args.first.is_a?(Hash)
# GlobalID serialization format
assert_equal user.to_global_id.to_s, args.first['_aj_globalid']
else
# Direct object serialization
assert_equal user.id, args.first.id
end
end
test "should respect retry configuration" do
# This tests the framework for retry configuration
# Individual jobs should inherit this behavior
assert_respond_to ApplicationJob, :retry_on
assert_respond_to ApplicationJob, :discard_on
end
end

View File

@@ -0,0 +1,123 @@
require "test_helper"
class InvitationsMailerTest < ActionMailer::TestCase
setup do
@user = users(:alice)
@invitation_mail = InvitationsMailer.invite_user(@user)
end
test "should queue invitation email job" do
# Note: In test environment, deliver_later might not enqueue jobs the same way
# This test focuses on the mail delivery functionality
assert_nothing_raised do
InvitationsMailer.invite_user(@user).deliver_later
end
end
test "should deliver invitation email successfully" do
assert_emails 1 do
InvitationsMailer.invite_user(@user).deliver_now
end
end
test "should have correct email content" do
email = @invitation_mail
assert_equal "You're invited to join Clinch", email.subject
assert_equal [@user.email_address], email.to
assert_equal [], email.cc
assert_equal [], email.bcc
# From address is configured in ApplicationMailer
assert_not_nil email.from
assert email.from.is_a?(Array)
end
test "should include user data in email body" do
email = @invitation_mail
# Use text_part to get the readable content
email_text = email.text_part&.decoded || email.body.decoded
# Should include invitation-related text
assert_includes email_text, "invited"
assert_includes email_text, "Clinch"
end
test "should handle different user statuses" do
# Test with pending user
pending_user = users(:bob)
pending_user.status = :pending_invitation
pending_user.save!
assert_emails 1 do
InvitationsMailer.invite_user(pending_user).deliver_now
end
end
test "should queue multiple invitation emails" do
users = [users(:alice), users(:bob)]
# Test that multiple deliveries don't raise errors
assert_nothing_raised do
users.each { |user| InvitationsMailer.invite_user(user).deliver_later }
end
# Test synchronous delivery to verify functionality
assert_emails 2 do
users.each { |user| InvitationsMailer.invite_user(user).deliver_now }
end
end
test "should handle job with invalid user" do
# Test behavior when user doesn't exist
invalid_user_id = User.maximum(:id) + 1000
# This should not raise an error immediately (job is queued)
assert_nothing_raised do
assert_enqueued_jobs 1 do
# Create a mail with non-persisted user for testing
temp_user = User.new(id: invalid_user_id, email_address: "invalid@test.com")
InvitationsMailer.invite_user(temp_user).deliver_later
end
end
end
test "should respect mailer configuration" do
# Test that the mailer inherits from ApplicationMailer properly
assert InvitationsMailer < ApplicationMailer
assert_respond_to InvitationsMailer, :default
end
test "should handle concurrent email deliveries" do
# Simulate concurrent invitation deliveries
users = User.limit(3)
# Test that multiple deliveries don't raise errors
assert_nothing_raised do
users.each do |user|
InvitationsMailer.invite_user(user).deliver_later
end
end
# Test synchronous delivery to verify functionality
assert_emails users.count do
users.each do |user|
InvitationsMailer.invite_user(user).deliver_now
end
end
end
test "should have proper email headers" do
email = @invitation_mail
# Test common email headers
assert_not_nil email.message_id
assert_not_nil email.date
# Test content-type
if email.html_part
assert_includes email.content_type, "text/html"
elsif email.text_part
assert_includes email.content_type, "text/plain"
end
end
end

View File

@@ -0,0 +1,197 @@
require "test_helper"
class PasswordsMailerTest < ActionMailer::TestCase
setup do
@user = users(:alice)
@reset_mail = PasswordsMailer.reset(@user)
end
test "should queue password reset email job" do
# Note: In test environment, deliver_later might not enqueue jobs the same way
# This test focuses on the mail delivery functionality
assert_nothing_raised do
PasswordsMailer.reset(@user).deliver_later
end
end
test "should deliver password reset email successfully" do
assert_emails 1 do
PasswordsMailer.reset(@user).deliver_now
end
end
test "should have correct email content" do
email = @reset_mail
assert_equal "Reset your password", email.subject
assert_equal [@user.email_address], email.to
assert_equal [], email.cc
assert_equal [], email.bcc
# From address is configured in ApplicationMailer
assert_not_nil email.from
assert email.from.is_a?(Array)
end
test "should include user data and reset token in email body" do
# Set a password reset token for testing
@user.generate_token_for(:password_reset)
@user.save!
email = PasswordsMailer.reset(@user)
email_body = email.body.encoded
# Should include user's email address
assert_includes email_body, @user.email_address
# Should include reset link structure
assert_includes email_body, "reset"
assert_includes email_body, "password"
# Use text_part to get readable content
email_text = email.text_part&.decoded || email.body.decoded
# Should include reset-related text
assert_includes email_text, "reset"
assert_includes email_text, "password"
end
test "should handle users with different statuses" do
# Test with active user
active_user = users(:bob)
assert active_user.status == "active"
assert_emails 1 do
PasswordsMailer.reset(active_user).deliver_now
end
# Test with disabled user (should still send reset if they request it)
active_user.status = :disabled
active_user.save!
assert_emails 1 do
PasswordsMailer.reset(active_user).deliver_now
end
end
test "should queue multiple password reset emails" do
users = [users(:alice), users(:bob)]
# Test that multiple deliveries don't raise errors
assert_nothing_raised do
users.each do |user|
user.generate_token_for(:password_reset)
PasswordsMailer.reset(user).deliver_later
end
end
# Test synchronous delivery to verify functionality
assert_emails 2 do
users.each do |user|
user.generate_token_for(:password_reset)
PasswordsMailer.reset(user).deliver_now
end
end
end
test "should handle user with reset token" do
# User should have a reset token for the email to be useful
assert_respond_to @user, :password_reset_token
# Generate token and test email content
@user.generate_token_for(:password_reset)
@user.save!
email = PasswordsMailer.reset(@user)
email_text = email.text_part&.decoded || email.body.decoded
assert_not_nil @user.password_reset_token
assert_includes email_text, "reset"
end
test "should handle expired reset tokens gracefully" do
# Test email generation even with expired tokens
@user.generate_token_for(:password_reset)
# Manually expire the token by updating its created_at time
@user.instance_variable_set(:@password_reset_token_created_at, 25.hours.ago)
# Email should still generate (validation happens elsewhere)
assert_emails 1 do
PasswordsMailer.reset(@user).deliver_now
end
end
test "should respect mailer configuration" do
# Test that the mailer inherits from ApplicationMailer properly
assert PasswordsMailer < ApplicationMailer
assert_respond_to PasswordsMailer, :default
end
test "should handle concurrent password reset deliveries" do
# Simulate concurrent password reset deliveries
users = User.limit(3)
# Test that multiple deliveries don't raise errors
assert_nothing_raised do
users.each do |user|
user.generate_token_for(:password_reset)
PasswordsMailer.reset(user).deliver_later
end
end
# Test synchronous delivery to verify functionality
assert_emails users.count do
users.each do |user|
user.generate_token_for(:password_reset)
PasswordsMailer.reset(user).deliver_now
end
end
end
test "should have proper email headers and security" do
email = @reset_mail
# Test common email headers
assert_not_nil email.message_id
assert_not_nil email.date
# Test content-type
if email.html_part
assert_includes email.content_type, "text/html"
elsif email.text_part
assert_includes email.content_type, "text/plain"
end
# Should not include sensitive data in headers
email.header.each do |key, value|
refute_includes value.to_s.downcase, "password"
refute_includes value.to_s.downcase, "token"
end
end
test "should handle users with different email formats" do
# Test with different email formats to ensure proper handling
test_emails = [
"user+tag@example.com",
"user.name@example.com",
"user@example.co.uk",
"123user@example.com"
]
test_emails.each do |email_address|
temp_user = User.new(
email_address: email_address,
password: "password123",
status: :active
)
temp_user.save!(validate: false) # Skip validation for testing
assert_emails 1 do
PasswordsMailer.reset(temp_user).deliver_now
end
email = PasswordsMailer.reset(temp_user)
assert_equal [email_address], email.to
end
end
end