require "test_helper" class PromotionCodeTest < ActiveSupport::TestCase def setup @user = User.create!( email: "test@example.com", password: "password123", password_confirmation: "password123" ) @event = Event.create!( name: "Test Event", slug: "test-event", description: "A valid description for the test event that is long enough", latitude: 48.8566, longitude: 2.3522, venue_name: "Test Venue", venue_address: "123 Test Street", user: @user ) end # Test valid promotion code creation def test_valid_promotion_code promotion_code = PromotionCode.create( code: "DISCOUNT10", discount_amount_cents: 1000, # €10.00 expires_at: 1.month.from_now, active: true, user: @user, event: @event ) assert promotion_code.valid? assert_equal "DISCOUNT10", promotion_code.code assert_equal 1000, promotion_code.discount_amount_cents assert promotion_code.active? end # Test validation for required fields def test_validation_for_required_fields promotion_code = PromotionCode.new refute promotion_code.valid? assert_not_nil promotion_code.errors[:code] end # Test unique code validation def test_unique_code_validation PromotionCode.create(code: "UNIQUE123", discount_amount_cents: 500, user: @user, event: @event) duplicate_code = PromotionCode.new(code: "UNIQUE123", discount_amount_cents: 500, user: @user, event: @event) refute duplicate_code.valid? assert_not_nil duplicate_code.errors[:code] end # Test discount amount validation def test_discount_amount_validation promotion_code = PromotionCode.new(code: "VALID123", discount_amount_cents: -100, user: @user, event: @event) refute promotion_code.valid? assert_not_nil promotion_code.errors[:discount_amount_cents] end # Test active scope def test_active_scope active_code = PromotionCode.create(code: "ACTIVE123", discount_amount_cents: 500, active: true, user: @user, event: @event) inactive_code = PromotionCode.create(code: "INACTIVE123", discount_amount_cents: 500, active: false, user: @user, event: @event) assert_includes PromotionCode.active, active_code refute_includes PromotionCode.active, inactive_code end # Test expired scope def test_expired_scope expired_code = PromotionCode.create(code: "EXPIRED123", discount_amount_cents: 500, expires_at: 1.day.ago, user: @user, event: @event) future_code = PromotionCode.create(code: "FUTURE123", discount_amount_cents: 500, expires_at: 1.month.from_now, user: @user, event: @event) assert_includes PromotionCode.expired, expired_code refute_includes PromotionCode.expired, future_code end # Test valid scope def test_valid_scope valid_code = PromotionCode.create(code: "VALID123", discount_amount_cents: 500, active: true, expires_at: 1.month.from_now, user: @user, event: @event) invalid_code = PromotionCode.create(code: "INVALID123", discount_amount_cents: 500, active: false, expires_at: 1.day.ago, user: @user, event: @event) assert_includes PromotionCode.valid, valid_code refute_includes PromotionCode.valid, invalid_code end # Test discount_amount_euros method def test_discount_amount_euros_converts_cents_to_euros promotion_code = PromotionCode.new(discount_amount_cents: 1000) assert_equal 10.0, promotion_code.discount_amount_euros promotion_code = PromotionCode.new(discount_amount_cents: 550) assert_equal 5.5, promotion_code.discount_amount_euros end # Test active? method def test_active_method # Active and not expired active_code = PromotionCode.create( code: "ACTIVE1", discount_amount_cents: 500, active: true, expires_at: 1.month.from_now, user: @user, event: @event ) assert active_code.active? # Active but expired expired_active_code = PromotionCode.create( code: "ACTIVE2", discount_amount_cents: 500, active: true, expires_at: 1.day.ago, user: @user, event: @event ) assert_not expired_active_code.active? # Inactive but not expired inactive_code = PromotionCode.create( code: "INACTIVE1", discount_amount_cents: 500, active: false, expires_at: 1.month.from_now, user: @user, event: @event ) assert_not inactive_code.active? # Active with no expiration no_expiry_code = PromotionCode.create( code: "NOEXPIRY", discount_amount_cents: 500, active: true, expires_at: nil, user: @user, event: @event ) assert no_expiry_code.active? end # Test expired? method def test_expired_method # Expired code expired_code = PromotionCode.create( code: "EXPIRED1", discount_amount_cents: 500, expires_at: 1.day.ago, user: @user, event: @event ) assert expired_code.expired? # Future code future_code = PromotionCode.create( code: "FUTURE1", discount_amount_cents: 500, expires_at: 1.month.from_now, user: @user, event: @event ) assert_not future_code.expired? # No expiration no_expiry_code = PromotionCode.create( code: "NOEXPIRY1", discount_amount_cents: 500, expires_at: nil, user: @user, event: @event ) assert_not no_expiry_code.expired? end # Test can_be_used? method def test_can_be_used_method # Can be used: active, not expired, under usage limit usable_code = PromotionCode.create( code: "USABLE1", discount_amount_cents: 500, active: true, expires_at: 1.month.from_now, usage_limit: 10, uses_count: 0, user: @user, event: @event ) assert usable_code.can_be_used? # Cannot be used: inactive inactive_code = PromotionCode.create( code: "INACTIVE2", discount_amount_cents: 500, active: false, expires_at: 1.month.from_now, usage_limit: 10, uses_count: 0, user: @user, event: @event ) assert_not inactive_code.can_be_used? # Cannot be used: expired expired_code = PromotionCode.create( code: "EXPIRED2", discount_amount_cents: 500, active: true, expires_at: 1.day.ago, usage_limit: 10, uses_count: 0, user: @user, event: @event ) assert_not expired_code.can_be_used? # Cannot be used: at usage limit limit_reached_code = PromotionCode.create( code: "LIMIT1", discount_amount_cents: 500, active: true, expires_at: 1.month.from_now, usage_limit: 5, uses_count: 5, user: @user, event: @event ) assert_not limit_reached_code.can_be_used? # Can be used: no usage limit no_limit_code = PromotionCode.create( code: "NOLIMIT1", discount_amount_cents: 500, active: true, expires_at: 1.month.from_now, usage_limit: nil, uses_count: 100, user: @user, event: @event ) assert no_limit_code.can_be_used? end # Test increment_uses_count callback def test_increment_uses_count_callback promotion_code = PromotionCode.create( code: "INCREMENT1", discount_amount_cents: 500, uses_count: 0, user: @user, event: @event ) assert_equal 0, promotion_code.uses_count # The callback should only run on create, so we test the initial value new_code = PromotionCode.create( code: "INCREMENT2", discount_amount_cents: 500, uses_count: nil, user: @user, event: @event ) assert_equal 0, new_code.uses_count end end