From 28d309fd860b28b0eaec8d62cab7f3c7b3971138 Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Fri, 20 Dec 2024 03:21:34 -0500 Subject: [PATCH] Add shared example for `Expireable` concern (#33369) --- spec/models/custom_filter_spec.rb | 2 + spec/models/invite_spec.rb | 2 + spec/models/ip_block_spec.rb | 2 + spec/models/mute_spec.rb | 18 +++ spec/models/poll_spec.rb | 2 + .../examples/models/concerns/expireable.rb | 110 ++++++++++++++++++ 6 files changed, 136 insertions(+) create mode 100644 spec/models/mute_spec.rb create mode 100644 spec/support/examples/models/concerns/expireable.rb diff --git a/spec/models/custom_filter_spec.rb b/spec/models/custom_filter_spec.rb index 517cc4f6ae..168cbb7c91 100644 --- a/spec/models/custom_filter_spec.rb +++ b/spec/models/custom_filter_spec.rb @@ -3,6 +3,8 @@ require 'rails_helper' RSpec.describe CustomFilter do + include_examples 'Expireable' + describe 'Validations' do it { is_expected.to validate_presence_of(:title) } it { is_expected.to validate_presence_of(:context) } diff --git a/spec/models/invite_spec.rb b/spec/models/invite_spec.rb index 4ad589f2c7..e85885a8d8 100644 --- a/spec/models/invite_spec.rb +++ b/spec/models/invite_spec.rb @@ -3,6 +3,8 @@ require 'rails_helper' RSpec.describe Invite do + include_examples 'Expireable' + describe '#valid_for_use?' do it 'returns true when there are no limitations' do invite = Fabricate(:invite, max_uses: nil, expires_at: nil) diff --git a/spec/models/ip_block_spec.rb b/spec/models/ip_block_spec.rb index b85856780a..93ee72423b 100644 --- a/spec/models/ip_block_spec.rb +++ b/spec/models/ip_block_spec.rb @@ -3,6 +3,8 @@ require 'rails_helper' RSpec.describe IpBlock do + include_examples 'Expireable' + describe 'Validations' do subject { Fabricate.build :ip_block } diff --git a/spec/models/mute_spec.rb b/spec/models/mute_spec.rb new file mode 100644 index 0000000000..33aa4f15dc --- /dev/null +++ b/spec/models/mute_spec.rb @@ -0,0 +1,18 @@ +# frozen_string_literal: true + +require 'rails_helper' + +RSpec.describe Mute do + include_examples 'Expireable' + + describe 'Associations' do + it { is_expected.to belong_to(:account).required } + it { is_expected.to belong_to(:target_account).required } + end + + describe 'Validations' do + subject { Fabricate.build :mute } + + it { is_expected.to validate_uniqueness_of(:account_id).scoped_to(:target_account_id) } + end +end diff --git a/spec/models/poll_spec.rb b/spec/models/poll_spec.rb index 0a4892eba4..e4e1a36c48 100644 --- a/spec/models/poll_spec.rb +++ b/spec/models/poll_spec.rb @@ -3,6 +3,8 @@ require 'rails_helper' RSpec.describe Poll do + include_examples 'Expireable' + describe 'Scopes' do let(:status) { Fabricate(:status) } let(:attached_poll) { Fabricate(:poll, status: status) } diff --git a/spec/support/examples/models/concerns/expireable.rb b/spec/support/examples/models/concerns/expireable.rb new file mode 100644 index 0000000000..098b98375a --- /dev/null +++ b/spec/support/examples/models/concerns/expireable.rb @@ -0,0 +1,110 @@ +# frozen_string_literal: true + +RSpec.shared_examples 'Expireable' do + subject { described_class.new(expires_at: expires_at) } + + let(:expires_at) { nil } + + describe 'Scopes' do + let!(:expired_record) do + travel_to 2.days.ago do + Fabricate factory_name, expires_at: 1.day.from_now + end + end + let!(:un_expired_record) { Fabricate factory_name, expires_at: 10.days.from_now } + + describe '.expired' do + it 'returns expired records' do + expect(described_class.expired) + .to include(expired_record) + .and not_include(un_expired_record) + end + end + end + + describe '#expires_in' do + context 'when expires at is nil' do + let(:expires_at) { nil } + + it 'returns nil' do + expect(subject.expires_in) + .to be_nil + end + end + end + + describe '#expires_in=' do + let(:record) { Fabricate.build factory_name } + + context 'when set to nil' do + it 'sets expires_at to nil' do + record.expires_in = nil + expect(record.expires_at) + .to be_nil + end + end + + context 'when set to empty' do + it 'sets expires_at to nil' do + record.expires_in = '' + expect(record.expires_at) + .to be_nil + end + end + + context 'when set to a value' do + it 'sets expires_at to expected future time' do + record.expires_in = 60 + expect(record.expires_at) + .to be_within(0.1).of(60.seconds.from_now) + end + end + end + + describe '#expired?' do + context 'when expires_at is nil' do + let(:expires_at) { nil } + + it { is_expected.to_not be_expired } + end + + context 'when expires_at is in the past' do + let(:expires_at) { 5.days.ago } + + it { is_expected.to be_expired } + end + + context 'when expires_at is in the future' do + let(:expires_at) { 5.days.from_now } + + it { is_expected.to_not be_expired } + end + + describe '#expire!' do + subject { Fabricate factory_name } + + it 'updates the timestamp' do + expect { subject.expire! } + .to change(subject, :expires_at) + end + end + + describe '#expires?' do + context 'when value is missing' do + let(:expires_at) { nil } + + it { is_expected.to_not be_expires } + end + + context 'when value is present' do + let(:expires_at) { 3.days.from_now } + + it { is_expected.to be_expires } + end + end + end + + def factory_name + described_class.name.underscore.to_sym + end +end