about summary refs log tree commit diff
path: root/spec
diff options
context:
space:
mode:
authorClaire <claire.github-309c@sitedethib.com>2023-03-31 21:30:27 +0200
committerClaire <claire.github-309c@sitedethib.com>2023-03-31 21:30:27 +0200
commit01d6f7529faef97c0209ef11bbca2e856961bbab (patch)
tree513ac21302befa1a08fc4968dcd4dca6b0e06360 /spec
parentcbdb25ab0343603165fc89fd28b07c9ca0f2ae6d (diff)
parentc6c03b49b255c4fe2183b94288a712ad7a66e2c2 (diff)
Merge branch 'main' into glitch-soc/merge-upstream
Conflicts:
- `README.md`:
  Upstream added a link to the roadmap, but we have a completely different README.
  Kept ours.
- `app/models/media_attachment.rb`:
  Upstream upped media attachment limits.
  Updated the default according to upstream's.
- `db/migrate/20180831171112_create_bookmarks.rb`:
  Upstream changed the migration compatibility level.
  Did so too.
- `config/initializers/content_security_policy.rb`:
  Upstream refactored this file but we have a different version.
  Kept our version.
- `app/controllers/settings/preferences_controller.rb`:
  Upstream completely refactored user settings storage, and glitch-soc has a
  different set of settings.
  The file does not directly references individual settings anymore.
  Applied upstream changes.
- `app/lib/user_settings_decorator.rb`:
  Upstream completely refactored user settings storage, and glitch-soc has a
  different set of settings.
  The file got removed entirely.
  Removed it as well.
- `app/models/user.rb`:
  Upstream completely refactored user settings storage, and glitch-soc has a
  different set of settings.
  References to individual settings have been removed from the file.
  Removed them as well.
- `app/views/settings/preferences/appearance/show.html.haml`:
  Upstream completely refactored user settings storage, and glitch-soc has a
  different set of settings.
  Applied upstream's changes and ported ours back.
- `app/views/settings/preferences/notifications/show.html.haml`:
  Upstream completely refactored user settings storage, and glitch-soc has a
  different set of settings.
  Applied upstream's changes and ported ours back.
- `app/views/settings/preferences/other/show.html.haml`:
  Upstream completely refactored user settings storage, and glitch-soc has a
  different set of settings.
  Applied upstream's changes and ported ours back.
- `config/settings.yml`:
  Upstream completely refactored user settings storage, and glitch-soc has a
  different set of settings.
  In particular, upstream removed user-specific and unused settings.
  Did the same in glitch-soc.
- `spec/controllers/application_controller_spec.rb`:
  Conflicts due to glitch-soc's theming system.
  Mostly kept our version, as upstream messed up the tests.
Diffstat (limited to 'spec')
-rw-r--r--spec/controllers/api/v1/accounts/credentials_controller_spec.rb1
-rw-r--r--spec/controllers/application_controller_spec.rb3
-rw-r--r--spec/controllers/settings/preferences/notifications_controller_spec.rb14
-rw-r--r--spec/controllers/settings/preferences/other_controller_spec.rb14
-rw-r--r--spec/controllers/settings/profiles_controller_spec.rb8
-rw-r--r--spec/lib/settings/extend_spec.rb16
-rw-r--r--spec/lib/settings/scoped_settings_spec.rb35
-rw-r--r--spec/lib/user_settings_decorator_spec.rb84
-rw-r--r--spec/models/user_settings/namespace_spec.rb25
-rw-r--r--spec/models/user_settings/setting_spec.rb106
-rw-r--r--spec/models/user_settings_spec.rb110
-rw-r--r--spec/models/user_spec.rb14
-rw-r--r--spec/services/notify_service_spec.rb7
-rw-r--r--spec/services/report_service_spec.rb3
-rw-r--r--spec/services/update_status_service_spec.rb9
-rw-r--r--spec/workers/poll_expiration_notify_worker_spec.rb61
16 files changed, 336 insertions, 174 deletions
diff --git a/spec/controllers/api/v1/accounts/credentials_controller_spec.rb b/spec/controllers/api/v1/accounts/credentials_controller_spec.rb
index e42f1de32..de08dd524 100644
--- a/spec/controllers/api/v1/accounts/credentials_controller_spec.rb
+++ b/spec/controllers/api/v1/accounts/credentials_controller_spec.rb
@@ -46,6 +46,7 @@ describe Api::V1::Accounts::CredentialsController do
         end
 
         it 'updates account info' do
+          user.reload
           user.account.reload
 
           expect(user.account.display_name).to eq("Alice Isn't Dead")
diff --git a/spec/controllers/application_controller_spec.rb b/spec/controllers/application_controller_spec.rb
index dc742074c..1aabae0ea 100644
--- a/spec/controllers/application_controller_spec.rb
+++ b/spec/controllers/application_controller_spec.rb
@@ -101,7 +101,8 @@ describe ApplicationController, type: :controller do
 
     it 'returns user\'s flavour when it is set' do
       current_user = Fabricate(:user)
-      current_user.settings['flavour'] = 'glitch'
+      current_user.settings.update(flavour: 'glitch')
+      current_user.save
       sign_in current_user
 
       allow(Setting).to receive(:[]).with('skin').and_return 'default'
diff --git a/spec/controllers/settings/preferences/notifications_controller_spec.rb b/spec/controllers/settings/preferences/notifications_controller_spec.rb
index 66fb8c5eb..29b7b6aec 100644
--- a/spec/controllers/settings/preferences/notifications_controller_spec.rb
+++ b/spec/controllers/settings/preferences/notifications_controller_spec.rb
@@ -20,20 +20,22 @@ describe Settings::Preferences::NotificationsController do
 
   describe 'PUT #update' do
     it 'updates notifications settings' do
-      user.settings['notification_emails'] = user.settings['notification_emails'].merge('follow' => false)
-      user.settings['interactions'] = user.settings['interactions'].merge('must_be_follower' => true)
+      user.settings.update('notification_emails.follow': false, 'interactions.must_be_follower': true)
+      user.save
 
       put :update, params: {
         user: {
-          notification_emails: { follow: '1' },
-          interactions: { must_be_follower: '0' },
+          settings_attributes: {
+            'notification_emails.follow': '1',
+            'interactions.must_be_follower': '0',
+          },
         },
       }
 
       expect(response).to redirect_to(settings_preferences_notifications_path)
       user.reload
-      expect(user.settings['notification_emails']['follow']).to be true
-      expect(user.settings['interactions']['must_be_follower']).to be false
+      expect(user.settings['notification_emails.follow']).to be true
+      expect(user.settings['interactions.must_be_follower']).to be false
     end
   end
 end
diff --git a/spec/controllers/settings/preferences/other_controller_spec.rb b/spec/controllers/settings/preferences/other_controller_spec.rb
index 63eeefaf0..249d1b5b5 100644
--- a/spec/controllers/settings/preferences/other_controller_spec.rb
+++ b/spec/controllers/settings/preferences/other_controller_spec.rb
@@ -29,20 +29,22 @@ describe Settings::Preferences::OtherController do
     end
 
     it 'updates user settings' do
-      user.settings['boost_modal'] = false
-      user.settings['delete_modal'] = true
+      user.settings.update('web.reblog_modal': false, 'web.delete_modal': true)
+      user.save
 
       put :update, params: {
         user: {
-          setting_boost_modal: '1',
-          setting_delete_modal: '0',
+          settings_attributes: {
+            'web.reblog_modal': '1',
+            'web.delete_modal': '0',
+          },
         },
       }
 
       expect(response).to redirect_to(settings_preferences_other_path)
       user.reload
-      expect(user.settings['boost_modal']).to be true
-      expect(user.settings['delete_modal']).to be false
+      expect(user.settings['web.reblog_modal']).to be true
+      expect(user.settings['web.delete_modal']).to be false
     end
   end
 end
diff --git a/spec/controllers/settings/profiles_controller_spec.rb b/spec/controllers/settings/profiles_controller_spec.rb
index e45596b1a..563e60271 100644
--- a/spec/controllers/settings/profiles_controller_spec.rb
+++ b/spec/controllers/settings/profiles_controller_spec.rb
@@ -44,12 +44,4 @@ RSpec.describe Settings::ProfilesController, type: :controller do
       expect(ActivityPub::UpdateDistributionWorker).to have_received(:perform_async).with(account.id)
     end
   end
-
-  describe 'PUT #update with oversized image' do
-    it 'gives the user an error message' do
-      allow(ActivityPub::UpdateDistributionWorker).to receive(:perform_async)
-      put :update, params: { account: { avatar: fixture_file_upload('4096x4097.png', 'image/png') } }
-      expect(response.body).to include('images are not supported')
-    end
-  end
 end
diff --git a/spec/lib/settings/extend_spec.rb b/spec/lib/settings/extend_spec.rb
deleted file mode 100644
index ea623137b..000000000
--- a/spec/lib/settings/extend_spec.rb
+++ /dev/null
@@ -1,16 +0,0 @@
-# frozen_string_literal: true
-
-require 'rails_helper'
-
-RSpec.describe Settings::Extend do
-  class User
-    include Settings::Extend
-  end
-
-  describe '#settings' do
-    it 'sets @settings as an instance of Settings::ScopedSettings' do
-      user = Fabricate(:user)
-      expect(user.settings).to be_a Settings::ScopedSettings
-    end
-  end
-end
diff --git a/spec/lib/settings/scoped_settings_spec.rb b/spec/lib/settings/scoped_settings_spec.rb
deleted file mode 100644
index 7566685b4..000000000
--- a/spec/lib/settings/scoped_settings_spec.rb
+++ /dev/null
@@ -1,35 +0,0 @@
-# frozen_string_literal: true
-
-require 'rails_helper'
-
-RSpec.describe Settings::ScopedSettings do
-  let(:object)         { Fabricate(:user) }
-  let(:scoped_setting) { described_class.new(object) }
-  let(:val)            { 'whatever' }
-  let(:methods)        { %i(auto_play_gif default_sensitive unfollow_modal boost_modal delete_modal reduce_motion system_font_ui noindex theme) }
-
-  describe '.initialize' do
-    it 'sets @object' do
-      scoped_setting = described_class.new(object)
-      expect(scoped_setting.instance_variable_get(:@object)).to be object
-    end
-  end
-
-  describe '#method_missing' do
-    it 'sets scoped_setting.method_name = val' do
-      methods.each do |key|
-        scoped_setting.send("#{key}=", val)
-        expect(scoped_setting.send(key)).to eq val
-      end
-    end
-  end
-
-  describe '#[]= and #[]' do
-    it 'sets [key] = val' do
-      methods.each do |key|
-        scoped_setting[key] = val
-        expect(scoped_setting[key]).to eq val
-      end
-    end
-  end
-end
diff --git a/spec/lib/user_settings_decorator_spec.rb b/spec/lib/user_settings_decorator_spec.rb
deleted file mode 100644
index 3b9b7ee2b..000000000
--- a/spec/lib/user_settings_decorator_spec.rb
+++ /dev/null
@@ -1,84 +0,0 @@
-# frozen_string_literal: true
-
-require 'rails_helper'
-
-describe UserSettingsDecorator do
-  describe 'update' do
-    let(:user) { Fabricate(:user) }
-    let(:settings) { described_class.new(user) }
-
-    it 'updates the user settings value for email notifications' do
-      values = { 'notification_emails' => { 'follow' => '1' } }
-
-      settings.update(values)
-      expect(user.settings['notification_emails']['follow']).to be true
-    end
-
-    it 'updates the user settings value for interactions' do
-      values = { 'interactions' => { 'must_be_follower' => '0' } }
-
-      settings.update(values)
-      expect(user.settings['interactions']['must_be_follower']).to be false
-    end
-
-    it 'updates the user settings value for privacy' do
-      values = { 'setting_default_privacy' => 'public' }
-
-      settings.update(values)
-      expect(user.settings['default_privacy']).to eq 'public'
-    end
-
-    it 'updates the user settings value for sensitive' do
-      values = { 'setting_default_sensitive' => '1' }
-
-      settings.update(values)
-      expect(user.settings['default_sensitive']).to be true
-    end
-
-    it 'updates the user settings value for unfollow modal' do
-      values = { 'setting_unfollow_modal' => '0' }
-
-      settings.update(values)
-      expect(user.settings['unfollow_modal']).to be false
-    end
-
-    it 'updates the user settings value for boost modal' do
-      values = { 'setting_boost_modal' => '1' }
-
-      settings.update(values)
-      expect(user.settings['boost_modal']).to be true
-    end
-
-    it 'updates the user settings value for delete toot modal' do
-      values = { 'setting_delete_modal' => '0' }
-
-      settings.update(values)
-      expect(user.settings['delete_modal']).to be false
-    end
-
-    it 'updates the user settings value for gif auto play' do
-      values = { 'setting_auto_play_gif' => '0' }
-
-      settings.update(values)
-      expect(user.settings['auto_play_gif']).to be false
-    end
-
-    it 'updates the user settings value for system font in UI' do
-      values = { 'setting_system_font_ui' => '0' }
-
-      settings.update(values)
-      expect(user.settings['system_font_ui']).to be false
-    end
-
-    it 'decoerces setting values before applying' do
-      values = {
-        'setting_delete_modal' => 'false',
-        'setting_boost_modal' => 'true',
-      }
-
-      settings.update(values)
-      expect(user.settings['delete_modal']).to be false
-      expect(user.settings['boost_modal']).to be true
-    end
-  end
-end
diff --git a/spec/models/user_settings/namespace_spec.rb b/spec/models/user_settings/namespace_spec.rb
new file mode 100644
index 000000000..ae2fa7b48
--- /dev/null
+++ b/spec/models/user_settings/namespace_spec.rb
@@ -0,0 +1,25 @@
+# frozen_string_literal: true
+
+require 'rails_helper'
+
+RSpec.describe UserSettings::Namespace do
+  subject { described_class.new(name) }
+
+  let(:name) { :foo }
+
+  describe '#setting' do
+    before do
+      subject.setting :bar, default: 'baz'
+    end
+
+    it 'adds setting to definitions' do
+      expect(subject.definitions[:'foo.bar']).to have_attributes(name: :bar, namespace: :foo, default_value: 'baz')
+    end
+  end
+
+  describe '#definitions' do
+    it 'returns a hash' do
+      expect(subject.definitions).to be_a Hash
+    end
+  end
+end
diff --git a/spec/models/user_settings/setting_spec.rb b/spec/models/user_settings/setting_spec.rb
new file mode 100644
index 000000000..9884ae4f8
--- /dev/null
+++ b/spec/models/user_settings/setting_spec.rb
@@ -0,0 +1,106 @@
+# frozen_string_literal: true
+
+require 'rails_helper'
+
+RSpec.describe UserSettings::Setting do
+  subject { described_class.new(name, options) }
+
+  let(:name)      { :foo }
+  let(:options)   { { default: default, namespace: namespace } }
+  let(:default)   { false }
+  let(:namespace) { nil }
+
+  describe '#default_value' do
+    context 'when default value is a primitive value' do
+      it 'returns default value' do
+        expect(subject.default_value).to eq default
+      end
+    end
+
+    context 'when default value is a proc' do
+      let(:default) { -> { 'bar' } }
+
+      it 'returns value from proc' do
+        expect(subject.default_value).to eq 'bar'
+      end
+    end
+  end
+
+  describe '#type' do
+    it 'returns a type' do
+      expect(subject.type).to be_a ActiveModel::Type::Value
+    end
+
+    context 'when default value is a boolean' do
+      let(:default) { false }
+
+      it 'returns boolean' do
+        expect(subject.type).to be_a ActiveModel::Type::Boolean
+      end
+    end
+
+    context 'when default value is a string' do
+      let(:default) { '' }
+
+      it 'returns string' do
+        expect(subject.type).to be_a ActiveModel::Type::String
+      end
+    end
+
+    context 'when default value is a lambda returning a boolean' do
+      let(:default) { -> { false } }
+
+      it 'returns boolean' do
+        expect(subject.type).to be_a ActiveModel::Type::Boolean
+      end
+    end
+
+    context 'when default value is a lambda returning a string' do
+      let(:default) { -> { '' } }
+
+      it 'returns boolean' do
+        expect(subject.type).to be_a ActiveModel::Type::String
+      end
+    end
+  end
+
+  describe '#type_cast' do
+    context 'when default value is a boolean' do
+      let(:default) { false }
+
+      it 'returns boolean' do
+        expect(subject.type_cast('1')).to be true
+      end
+    end
+
+    context 'when default value is a string' do
+      let(:default) { '' }
+
+      it 'returns string' do
+        expect(subject.type_cast(1)).to eq '1'
+      end
+    end
+  end
+
+  describe '#to_a' do
+    it 'returns an array' do
+      expect(subject.to_a).to eq [name, default]
+    end
+  end
+
+  describe '#key' do
+    context 'when there is no namespace' do
+      it 'returnsn a symbol' do
+        expect(subject.key).to eq :foo
+      end
+    end
+
+    context 'when there is a namespace' do
+      let(:namespace) { :bar }
+
+      it 'returns a symbol' do
+        expect(subject.key).to eq :'bar.foo'
+      end
+    end
+  end
+end
diff --git a/spec/models/user_settings_spec.rb b/spec/models/user_settings_spec.rb
new file mode 100644
index 000000000..f0e4272fd
--- /dev/null
+++ b/spec/models/user_settings_spec.rb
@@ -0,0 +1,110 @@
+# frozen_string_literal: true
+
+require 'rails_helper'
+
+RSpec.describe UserSettings do
+  subject { described_class.new(json) }
+
+  let(:json) { {} }
+
+  describe '#[]' do
+    context 'when setting is not set' do
+      it 'returns default value' do
+        expect(subject[:always_send_emails]).to be false
+      end
+    end
+
+    context 'when setting is set' do
+      let(:json) { { default_language: 'fr' } }
+
+      it 'returns value' do
+        expect(subject[:default_language]).to eq 'fr'
+      end
+    end
+
+    context 'when setting was not defined' do
+      it 'raises error' do
+        expect { subject[:foo] }.to raise_error UserSettings::KeyError
+      end
+    end
+  end
+
+  describe '#[]=' do
+    context 'when value matches type' do
+      before do
+        subject[:always_send_emails] = true
+      end
+
+      it 'updates value' do
+        expect(subject[:always_send_emails]).to be true
+      end
+    end
+
+    context 'when value needs to be type-cast' do
+      before do
+        subject[:always_send_emails] = '1'
+      end
+
+      it 'updates value with a type-cast' do
+        expect(subject[:always_send_emails]).to be true
+      end
+    end
+  end
+
+  describe '#update' do
+    before do
+      subject.update(always_send_emails: true, default_language: 'fr', default_privacy: nil)
+    end
+
+    it 'updates values' do
+      expect(subject[:always_send_emails]).to be true
+      expect(subject[:default_language]).to eq 'fr'
+    end
+
+    it 'does not set values that are nil' do
+      expect(subject.as_json).to_not include(default_privacy: nil)
+    end
+  end
+
+  describe '#as_json' do
+    let(:json) { { default_language: 'fr' } }
+
+    it 'returns hash' do
+      expect(subject.as_json).to eq json
+    end
+  end
+
+  describe '.keys' do
+    it 'returns an array' do
+      expect(described_class.keys).to be_a Array
+    end
+  end
+
+  describe '.definition_for' do
+    context 'when key is defined' do
+      it 'returns a setting' do
+        expect(described_class.definition_for(:always_send_emails)).to be_a UserSettings::Setting
+      end
+    end
+
+    context 'when key is not defined' do
+      it 'returns nil' do
+        expect(described_class.definition_for(:foo)).to be_nil
+      end
+    end
+  end
+
+  describe '.definition_for?' do
+    context 'when key is defined' do
+      it 'returns true' do
+        expect(described_class.definition_for?(:always_send_emails)).to be true
+      end
+    end
+
+    context 'when key is not defined' do
+      it 'returns false' do
+        expect(described_class.definition_for?(:foo)).to be false
+      end
+    end
+  end
+end
diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb
index 3e7b59f17..ab883927a 100644
--- a/spec/models/user_spec.rb
+++ b/spec/models/user_spec.rb
@@ -313,9 +313,9 @@ RSpec.describe User, type: :model do
   end
 
   describe 'settings' do
-    it 'is instance of Settings::ScopedSettings' do
+    it 'is instance of UserSettings' do
       user = Fabricate(:user)
-      expect(user.settings).to be_a Settings::ScopedSettings
+      expect(user.settings).to be_a UserSettings
     end
   end
 
@@ -379,16 +379,6 @@ RSpec.describe User, type: :model do
     end
   end
 
-  it_behaves_like 'Settings-extended' do
-    def create!
-      User.create!(account: Fabricate(:account, user: nil), email: 'foo@mastodon.space', password: 'abcd1234', agreement: true)
-    end
-
-    def fabricate
-      Fabricate(:user)
-    end
-  end
-
   describe 'token_for_app' do
     let(:user) { Fabricate(:user) }
     let(:app) { Fabricate(:application, owner: user) }
diff --git a/spec/services/notify_service_spec.rb b/spec/services/notify_service_spec.rb
index da2857627..4d66f255c 100644
--- a/spec/services/notify_service_spec.rb
+++ b/spec/services/notify_service_spec.rb
@@ -54,7 +54,8 @@ RSpec.describe NotifyService, type: :service do
     let(:type)     { :mention }
 
     before do
-      user.settings.interactions = user.settings.interactions.merge('must_be_following_dm' => enabled)
+      user.settings.update('interactions.must_be_following_dm': enabled)
+      user.save
     end
 
     context 'if recipient is supposed to be following sender' do
@@ -155,8 +156,8 @@ RSpec.describe NotifyService, type: :service do
     before do
       ActionMailer::Base.deliveries.clear
 
-      notification_emails = user.settings.notification_emails
-      user.settings.notification_emails = notification_emails.merge('follow' => enabled)
+      user.settings.update('notification_emails.follow': enabled)
+      user.save
     end
 
     context 'when email notification is enabled' do
diff --git a/spec/services/report_service_spec.rb b/spec/services/report_service_spec.rb
index 9d81bd971..452400f72 100644
--- a/spec/services/report_service_spec.rb
+++ b/spec/services/report_service_spec.rb
@@ -96,7 +96,8 @@ RSpec.describe ReportService, type: :service do
 
     before do
       ActionMailer::Base.deliveries.clear
-      source_account.user.settings.notification_emails['report'] = true
+      source_account.user.settings['notification_emails.report'] = true
+      source_account.user.save
     end
 
     it 'does not send an e-mail' do
diff --git a/spec/services/update_status_service_spec.rb b/spec/services/update_status_service_spec.rb
index e52a0e52b..d6923722a 100644
--- a/spec/services/update_status_service_spec.rb
+++ b/spec/services/update_status_service_spec.rb
@@ -120,7 +120,9 @@ RSpec.describe UpdateStatusService, type: :service do
     before do
       status.update(poll: poll)
       VoteService.new.call(voter, poll, [0])
-      subject.call(status, status.account_id, text: 'Foo', poll: { options: %w(Bar Baz Foo), expires_in: 5.days.to_i })
+      Sidekiq::Testing.fake! do
+        subject.call(status, status.account_id, text: 'Foo', poll: { options: %w(Bar Baz Foo), expires_in: 5.days.to_i })
+      end
     end
 
     it 'updates poll' do
@@ -138,6 +140,11 @@ RSpec.describe UpdateStatusService, type: :service do
     it 'saves edit history' do
       expect(status.edits.pluck(:poll_options)).to eq [%w(Foo Bar), %w(Bar Baz Foo)]
     end
+
+    it 'requeues expiration notification' do
+      poll = status.poll.reload
+      expect(PollExpirationNotifyWorker).to have_enqueued_sidekiq_job(poll.id).at(poll.expires_at + 5.minutes)
+    end
   end
 
   context 'when mentions in text change' do
diff --git a/spec/workers/poll_expiration_notify_worker_spec.rb b/spec/workers/poll_expiration_notify_worker_spec.rb
index 8229db815..78cbc1ee4 100644
--- a/spec/workers/poll_expiration_notify_worker_spec.rb
+++ b/spec/workers/poll_expiration_notify_worker_spec.rb
@@ -4,10 +4,69 @@ require 'rails_helper'
 
 describe PollExpirationNotifyWorker do
   let(:worker) { described_class.new }
+  let(:account) { Fabricate(:account, domain: remote? ? 'example.com' : nil) }
+  let(:status) { Fabricate(:status, account: account) }
+  let(:poll) { Fabricate(:poll, status: status, account: account) }
+  let(:remote?) { false }
+  let(:poll_vote) { Fabricate(:poll_vote, poll: poll) }
+
+  describe '#perform' do
+    around do |example|
+      Sidekiq::Testing.fake! do
+        example.run
+      end
+    end
 
-  describe 'perform' do
     it 'runs without error for missing record' do
       expect { worker.perform(nil) }.to_not raise_error
     end
+
+    context 'when poll is not expired' do
+      it 'requeues job' do
+        worker.perform(poll.id)
+        expect(described_class.sidekiq_options_hash['lock']).to be :until_executing
+        expect(described_class).to have_enqueued_sidekiq_job(poll.id).at(poll.expires_at + 5.minutes)
+      end
+    end
+
+    context 'when poll is expired' do
+      before do
+        poll_vote
+
+        travel_to poll.expires_at + 5.minutes
+
+        worker.perform(poll.id)
+      end
+
+      context 'when poll is local' do
+        it 'notifies voters' do
+          expect(ActivityPub::DistributePollUpdateWorker).to have_enqueued_sidekiq_job(poll.status.id)
+        end
+
+        it 'notifies owner' do
+          expect(LocalNotificationWorker).to have_enqueued_sidekiq_job(poll.account.id, poll.id, 'Poll', 'poll')
+        end
+
+        it 'notifies local voters' do
+          expect(LocalNotificationWorker).to have_enqueued_sidekiq_job(poll_vote.account.id, poll.id, 'Poll', 'poll')
+        end
+      end
+
+      context 'when poll is remote' do
+        let(:remote?) { true }
+
+        it 'does not notify remote voters' do
+          expect(ActivityPub::DistributePollUpdateWorker).to_not have_enqueued_sidekiq_job(poll.status.id)
+        end
+
+        it 'does not notify owner' do
+          expect(LocalNotificationWorker).to_not have_enqueued_sidekiq_job(poll.account.id, poll.id, 'Poll', 'poll')
+        end
+
+        it 'notifies local voters' do
+          expect(LocalNotificationWorker).to have_enqueued_sidekiq_job(poll_vote.account.id, poll.id, 'Poll', 'poll')
+        end
+      end
+    end
   end
 end