about summary refs log tree commit diff
path: root/spec
diff options
context:
space:
mode:
authorClaire <claire.github-309c@sitedethib.com>2022-03-08 20:22:54 +0100
committerClaire <claire.github-309c@sitedethib.com>2022-03-08 20:22:54 +0100
commit1fbd1fa5c4ad5fcfef8af0c76f04e06f39aadd33 (patch)
tree1647c091e5d45d1d8dc20e6b25b3a588c2f8aa1b /spec
parentf03148f441d8dfc1856451c4faa00b5e26b6e199 (diff)
parent8f6c67bfdeddd1c2c1085067e3dc549fb53f6ff4 (diff)
Merge branch 'main' into glitch-soc/merge-upstream
Conflicts:
- `app/controllers/settings/preferences_controller.rb`:
  Conflicts due to us having more user settings and upstream dropping
  `hide_network` (to replace it with an account attribute, properly migrated).
  Dropped `hide_network` like upstream.
- `app/lib/user_settings_decorator.rb`:
  Conflicts due to us having more user settings and upstream dropping
  `hide_network` (to replace it with an account attribute, properly migrated).
  Dropped `hide_network` like upstream.
- `app/models/status.rb`:
  Conflict because of slight change in how glitch-soc handles the scope to
  filter out local-only posts for anonymous viewers.
  Took upstream's changes and re-applied glitch-soc's change.
- `app/models/user.rb`:
  Conflicts due to us having more user settings and upstream dropping
  `hide_network` (to replace it with an account attribute, properly migrated).
  Dropped `hide_network` like upstream.
- `app/views/directories/index.html.haml`:
  Conflict because upstream redesigned that page while glitch-soc had a minor
  change to support hiding the number of followers.
  Ported glitch-soc's change on top of upstream's redesign.

Additional changes:
- `app/models/account_statuses_filter.rb`:
  See change to `app/models/status.rb`.
Diffstat (limited to 'spec')
-rw-r--r--spec/controllers/accounts_controller_spec.rb8
-rw-r--r--spec/controllers/activitypub/collections_controller_spec.rb6
-rw-r--r--spec/controllers/activitypub/outboxes_controller_spec.rb6
-rw-r--r--spec/controllers/activitypub/replies_controller_spec.rb4
-rw-r--r--spec/controllers/api/v1/accounts/notes_controller_spec.rb2
-rw-r--r--spec/controllers/api/v1/admin/accounts_controller_spec.rb2
-rw-r--r--spec/controllers/api/v1/statuses/favourited_by_accounts_controller_spec.rb2
-rw-r--r--spec/controllers/api/v1/statuses/reblogged_by_accounts_controller_spec.rb2
-rw-r--r--spec/controllers/api/v1/statuses_controller_spec.rb4
-rw-r--r--spec/controllers/application_controller_spec.rb20
-rw-r--r--spec/controllers/follower_accounts_controller_spec.rb2
-rw-r--r--spec/controllers/following_accounts_controller_spec.rb2
-rw-r--r--spec/controllers/statuses_controller_spec.rb6
-rw-r--r--spec/helpers/application_helper_spec.rb2
-rw-r--r--spec/lib/tag_manager_spec.rb26
-rw-r--r--spec/models/account_statuses_filter_spec.rb229
-rw-r--r--spec/models/report_spec.rb2
-rw-r--r--spec/models/status_spec.rb53
-rw-r--r--spec/policies/user_policy_spec.rb4
-rw-r--r--spec/presenters/familiar_followers_presenter_spec.rb58
-rw-r--r--spec/services/unsuspend_account_service_spec.rb16
-rw-r--r--spec/support/stories/profile_stories.rb2
22 files changed, 346 insertions, 112 deletions
diff --git a/spec/controllers/accounts_controller_spec.rb b/spec/controllers/accounts_controller_spec.rb
index 73d124029..662a89927 100644
--- a/spec/controllers/accounts_controller_spec.rb
+++ b/spec/controllers/accounts_controller_spec.rb
@@ -5,7 +5,7 @@ RSpec.describe AccountsController, type: :controller do
 
   let(:account) { Fabricate(:account) }
 
-  shared_examples 'cachable response' do
+  shared_examples 'cacheable response' do
     it 'does not set cookies' do
       expect(response.cookies).to be_empty
       expect(response.headers['Set-Cookies']).to be nil
@@ -374,7 +374,7 @@ RSpec.describe AccountsController, type: :controller do
           expect(response.media_type).to eq 'application/activity+json'
         end
 
-        it_behaves_like 'cachable response'
+        it_behaves_like 'cacheable response'
 
         it 'renders account' do
           json = body_as_json
@@ -432,7 +432,7 @@ RSpec.describe AccountsController, type: :controller do
           expect(response.media_type).to eq 'application/activity+json'
         end
 
-        it_behaves_like 'cachable response'
+        it_behaves_like 'cacheable response'
 
         it 'renders account' do
           json = body_as_json
@@ -499,7 +499,7 @@ RSpec.describe AccountsController, type: :controller do
           expect(response).to have_http_status(200)
         end
 
-        it_behaves_like 'cachable response'
+        it_behaves_like 'cacheable response'
       end
 
       context do
diff --git a/spec/controllers/activitypub/collections_controller_spec.rb b/spec/controllers/activitypub/collections_controller_spec.rb
index 21a033945..4d87f80ce 100644
--- a/spec/controllers/activitypub/collections_controller_spec.rb
+++ b/spec/controllers/activitypub/collections_controller_spec.rb
@@ -7,7 +7,7 @@ RSpec.describe ActivityPub::CollectionsController, type: :controller do
   let!(:private_pinned) { Fabricate(:status, account: account, text: 'secret private stuff', visibility: :private) }
   let(:remote_account) { nil }
 
-  shared_examples 'cachable response' do
+  shared_examples 'cacheable response' do
     it 'does not set cookies' do
       expect(response.cookies).to be_empty
       expect(response.headers['Set-Cookies']).to be nil
@@ -48,7 +48,7 @@ RSpec.describe ActivityPub::CollectionsController, type: :controller do
           expect(response.media_type).to eq 'application/activity+json'
         end
 
-        it_behaves_like 'cachable response'
+        it_behaves_like 'cacheable response'
 
         it 'returns orderedItems with pinned statuses' do
           expect(body[:orderedItems]).to be_an Array
@@ -101,7 +101,7 @@ RSpec.describe ActivityPub::CollectionsController, type: :controller do
             expect(response.media_type).to eq 'application/activity+json'
           end
 
-          it_behaves_like 'cachable response'
+          it_behaves_like 'cacheable response'
 
           it 'returns orderedItems with pinned statuses' do
             json = body_as_json
diff --git a/spec/controllers/activitypub/outboxes_controller_spec.rb b/spec/controllers/activitypub/outboxes_controller_spec.rb
index 1722690db..04f036447 100644
--- a/spec/controllers/activitypub/outboxes_controller_spec.rb
+++ b/spec/controllers/activitypub/outboxes_controller_spec.rb
@@ -3,7 +3,7 @@ require 'rails_helper'
 RSpec.describe ActivityPub::OutboxesController, type: :controller do
   let!(:account) { Fabricate(:account) }
 
-  shared_examples 'cachable response' do
+  shared_examples 'cacheable response' do
     it 'does not set cookies' do
       expect(response.cookies).to be_empty
       expect(response.headers['Set-Cookies']).to be nil
@@ -53,7 +53,7 @@ RSpec.describe ActivityPub::OutboxesController, type: :controller do
           expect(body[:totalItems]).to eq 4
         end
 
-        it_behaves_like 'cachable response'
+        it_behaves_like 'cacheable response'
 
         it 'does not have a Vary header' do
           expect(response.headers['Vary']).to be_nil
@@ -98,7 +98,7 @@ RSpec.describe ActivityPub::OutboxesController, type: :controller do
           expect(body[:orderedItems].all? { |item| item[:to].include?(ActivityPub::TagManager::COLLECTIONS[:public]) || item[:cc].include?(ActivityPub::TagManager::COLLECTIONS[:public]) }).to be true
         end
 
-        it_behaves_like 'cachable response'
+        it_behaves_like 'cacheable response'
 
         it 'returns Vary header with Signature' do
           expect(response.headers['Vary']).to include 'Signature'
diff --git a/spec/controllers/activitypub/replies_controller_spec.rb b/spec/controllers/activitypub/replies_controller_spec.rb
index a2c7f336f..a35957f24 100644
--- a/spec/controllers/activitypub/replies_controller_spec.rb
+++ b/spec/controllers/activitypub/replies_controller_spec.rb
@@ -8,7 +8,7 @@ RSpec.describe ActivityPub::RepliesController, type: :controller do
   let(:remote_reply_id) { 'https://foobar.com/statuses/1234' }
   let(:remote_querier) { nil }
 
-  shared_examples 'cachable response' do
+  shared_examples 'cacheable response' do
     it 'does not set cookies' do
       expect(response.cookies).to be_empty
       expect(response.headers['Set-Cookies']).to be nil
@@ -93,7 +93,7 @@ RSpec.describe ActivityPub::RepliesController, type: :controller do
         expect(response.media_type).to eq 'application/activity+json'
       end
 
-      it_behaves_like 'cachable response'
+      it_behaves_like 'cacheable response'
 
       context 'without only_other_accounts' do
         it "returns items with thread author's replies" do
diff --git a/spec/controllers/api/v1/accounts/notes_controller_spec.rb b/spec/controllers/api/v1/accounts/notes_controller_spec.rb
index 47d595c70..42c2d8a86 100644
--- a/spec/controllers/api/v1/accounts/notes_controller_spec.rb
+++ b/spec/controllers/api/v1/accounts/notes_controller_spec.rb
@@ -31,7 +31,7 @@ describe Api::V1::Accounts::NotesController do
       end
     end
 
-    context 'when account note exceends allowed length' do
+    context 'when account note exceeds allowed length' do
       let(:comment) { 'a' * 2_001 }
 
       it 'returns 422' do
diff --git a/spec/controllers/api/v1/admin/accounts_controller_spec.rb b/spec/controllers/api/v1/admin/accounts_controller_spec.rb
index bf79ee520..3f61bbc0b 100644
--- a/spec/controllers/api/v1/admin/accounts_controller_spec.rb
+++ b/spec/controllers/api/v1/admin/accounts_controller_spec.rb
@@ -140,7 +140,7 @@ RSpec.describe Api::V1::Admin::AccountsController, type: :controller do
       expect(response).to have_http_status(200)
     end
 
-    it 'unsensitives account' do
+    it 'unsensitizes account' do
       expect(account.reload.sensitized?).to be false
     end
   end
diff --git a/spec/controllers/api/v1/statuses/favourited_by_accounts_controller_spec.rb b/spec/controllers/api/v1/statuses/favourited_by_accounts_controller_spec.rb
index 439a4738d..7cc77f430 100644
--- a/spec/controllers/api/v1/statuses/favourited_by_accounts_controller_spec.rb
+++ b/spec/controllers/api/v1/statuses/favourited_by_accounts_controller_spec.rb
@@ -56,7 +56,7 @@ RSpec.describe Api::V1::Statuses::FavouritedByAccountsController, type: :control
           Fabricate(:favourite, status: status)
         end
 
-        it 'returns http unautharized' do
+        it 'returns http unauthorized' do
           get :index, params: { status_id: status.id }
           expect(response).to have_http_status(404)
         end
diff --git a/spec/controllers/api/v1/statuses/reblogged_by_accounts_controller_spec.rb b/spec/controllers/api/v1/statuses/reblogged_by_accounts_controller_spec.rb
index 31320349d..8d4a6f91c 100644
--- a/spec/controllers/api/v1/statuses/reblogged_by_accounts_controller_spec.rb
+++ b/spec/controllers/api/v1/statuses/reblogged_by_accounts_controller_spec.rb
@@ -56,7 +56,7 @@ RSpec.describe Api::V1::Statuses::RebloggedByAccountsController, type: :controll
           Fabricate(:status, reblog_of_id: status.id)
         end
 
-        it 'returns http unautharized' do
+        it 'returns http unauthorized' do
           get :index, params: { status_id: status.id }
           expect(response).to have_http_status(404)
         end
diff --git a/spec/controllers/api/v1/statuses_controller_spec.rb b/spec/controllers/api/v1/statuses_controller_spec.rb
index 190dfad11..2eb30af74 100644
--- a/spec/controllers/api/v1/statuses_controller_spec.rb
+++ b/spec/controllers/api/v1/statuses_controller_spec.rb
@@ -130,7 +130,7 @@ RSpec.describe Api::V1::StatusesController, type: :controller do
       let(:status) { Fabricate(:status, account: user.account, visibility: :private) }
 
       describe 'GET #show' do
-        it 'returns http unautharized' do
+        it 'returns http unauthorized' do
           get :show, params: { id: status.id }
           expect(response).to have_http_status(404)
         end
@@ -141,7 +141,7 @@ RSpec.describe Api::V1::StatusesController, type: :controller do
           Fabricate(:status, account: user.account, thread: status)
         end
 
-        it 'returns http unautharized' do
+        it 'returns http unauthorized' do
           get :context, params: { id: status.id }
           expect(response).to have_http_status(404)
         end
diff --git a/spec/controllers/application_controller_spec.rb b/spec/controllers/application_controller_spec.rb
index a6a6871f7..851e58d60 100644
--- a/spec/controllers/application_controller_spec.rb
+++ b/spec/controllers/application_controller_spec.rb
@@ -191,30 +191,30 @@ describe ApplicationController, type: :controller do
     controller do
       before_action :require_admin!
 
-      def sucesss
+      def success
         head 200
       end
     end
 
     before do
-      routes.draw { get 'sucesss' => 'anonymous#sucesss' }
+      routes.draw { get 'success' => 'anonymous#success' }
     end
 
     it 'returns a 403 if current user is not admin' do
       sign_in(Fabricate(:user, admin: false))
-      get 'sucesss'
+      get 'success'
       expect(response).to have_http_status(403)
     end
 
     it 'returns a 403 if current user is only a moderator' do
       sign_in(Fabricate(:user, moderator: true))
-      get 'sucesss'
+      get 'success'
       expect(response).to have_http_status(403)
     end
 
     it 'does nothing if current user is admin' do
       sign_in(Fabricate(:user, admin: true))
-      get 'sucesss'
+      get 'success'
       expect(response).to have_http_status(200)
     end
   end
@@ -223,30 +223,30 @@ describe ApplicationController, type: :controller do
     controller do
       before_action :require_staff!
 
-      def sucesss
+      def success
         head 200
       end
     end
 
     before do
-      routes.draw { get 'sucesss' => 'anonymous#sucesss' }
+      routes.draw { get 'success' => 'anonymous#success' }
     end
 
     it 'returns a 403 if current user is not admin or moderator' do
       sign_in(Fabricate(:user, admin: false, moderator: false))
-      get 'sucesss'
+      get 'success'
       expect(response).to have_http_status(403)
     end
 
     it 'does nothing if current user is moderator' do
       sign_in(Fabricate(:user, moderator: true))
-      get 'sucesss'
+      get 'success'
       expect(response).to have_http_status(200)
     end
 
     it 'does nothing if current user is admin' do
       sign_in(Fabricate(:user, admin: true))
-      get 'sucesss'
+      get 'success'
       expect(response).to have_http_status(200)
     end
   end
diff --git a/spec/controllers/follower_accounts_controller_spec.rb b/spec/controllers/follower_accounts_controller_spec.rb
index eb095cf30..4d2a6e01a 100644
--- a/spec/controllers/follower_accounts_controller_spec.rb
+++ b/spec/controllers/follower_accounts_controller_spec.rb
@@ -103,7 +103,7 @@ describe FollowerAccountsController do
 
         context 'when account hides their network' do
           before do
-            alice.user.settings.hide_network = true
+            alice.update(hide_collections: true)
           end
 
           it 'returns followers count' do
diff --git a/spec/controllers/following_accounts_controller_spec.rb b/spec/controllers/following_accounts_controller_spec.rb
index af5ce0787..bb6d221ca 100644
--- a/spec/controllers/following_accounts_controller_spec.rb
+++ b/spec/controllers/following_accounts_controller_spec.rb
@@ -103,7 +103,7 @@ describe FollowingAccountsController do
 
         context 'when account hides their network' do
           before do
-            alice.user.settings.hide_network = true
+            alice.update(hide_collections: true)
           end
 
           it 'returns followers count' do
diff --git a/spec/controllers/statuses_controller_spec.rb b/spec/controllers/statuses_controller_spec.rb
index 9986efa51..05fae67fa 100644
--- a/spec/controllers/statuses_controller_spec.rb
+++ b/spec/controllers/statuses_controller_spec.rb
@@ -5,7 +5,7 @@ require 'rails_helper'
 describe StatusesController do
   render_views
 
-  shared_examples 'cachable response' do
+  shared_examples 'cacheable response' do
     it 'does not set cookies' do
       expect(response.cookies).to be_empty
       expect(response.headers['Set-Cookies']).to be nil
@@ -108,7 +108,7 @@ describe StatusesController do
           expect(response.headers['Vary']).to eq 'Accept'
         end
 
-        it_behaves_like 'cachable response'
+        it_behaves_like 'cacheable response'
 
         it 'returns Content-Type header' do
           expect(response.headers['Content-Type']).to include 'application/activity+json'
@@ -496,7 +496,7 @@ describe StatusesController do
             expect(response.headers['Vary']).to eq 'Accept'
           end
 
-          it_behaves_like 'cachable response'
+          it_behaves_like 'cacheable response'
 
           it 'returns Content-Type header' do
             expect(response.headers['Content-Type']).to include 'application/activity+json'
diff --git a/spec/helpers/application_helper_spec.rb b/spec/helpers/application_helper_spec.rb
index f09e32ecc..b9d38d8c6 100644
--- a/spec/helpers/application_helper_spec.rb
+++ b/spec/helpers/application_helper_spec.rb
@@ -60,7 +60,7 @@ describe ApplicationHelper do
   end
 
   describe 'favicon_path' do
-    it 'returns /favicon.ico on production enviromnent' do
+    it 'returns /favicon.ico on production environment' do
       expect(Rails.env).to receive(:production?).and_return(true)
       expect(helper.favicon_path).to eq '/favicon.ico'
     end
diff --git a/spec/lib/tag_manager_spec.rb b/spec/lib/tag_manager_spec.rb
index 2230f9710..cd9fb936c 100644
--- a/spec/lib/tag_manager_spec.rb
+++ b/spec/lib/tag_manager_spec.rb
@@ -6,7 +6,7 @@ RSpec.describe TagManager do
 
     around do |example|
       original_local_domain = Rails.configuration.x.local_domain
-      Rails.configuration.x.local_domain = 'domain.test'
+      Rails.configuration.x.local_domain = 'domain.example.com'
 
       example.run
 
@@ -18,11 +18,11 @@ RSpec.describe TagManager do
     end
 
     it 'returns true if the slash-stripped string equals to local domain' do
-      expect(TagManager.instance.local_domain?('DoMaIn.Test/')).to eq true
+      expect(TagManager.instance.local_domain?('DoMaIn.Example.com/')).to eq true
     end
 
     it 'returns false for irrelevant string' do
-      expect(TagManager.instance.local_domain?('DoMaIn.Test!')).to eq false
+      expect(TagManager.instance.local_domain?('DoMaIn.Example.com!')).to eq false
     end
   end
 
@@ -31,7 +31,7 @@ RSpec.describe TagManager do
 
     around do |example|
       original_web_domain = Rails.configuration.x.web_domain
-      Rails.configuration.x.web_domain = 'domain.test'
+      Rails.configuration.x.web_domain = 'domain.example.com'
 
       example.run
 
@@ -43,11 +43,11 @@ RSpec.describe TagManager do
     end
 
     it 'returns true if the slash-stripped string equals to web domain' do
-      expect(TagManager.instance.web_domain?('DoMaIn.Test/')).to eq true
+      expect(TagManager.instance.web_domain?('DoMaIn.Example.com/')).to eq true
     end
 
     it 'returns false for string with irrelevant characters' do
-      expect(TagManager.instance.web_domain?('DoMaIn.Test!')).to eq false
+      expect(TagManager.instance.web_domain?('DoMaIn.Example.com!')).to eq false
     end
   end
 
@@ -57,7 +57,7 @@ RSpec.describe TagManager do
     end
 
     it 'returns normalized domain' do
-      expect(TagManager.instance.normalize_domain('DoMaIn.Test/')).to eq 'domain.test'
+      expect(TagManager.instance.normalize_domain('DoMaIn.Example.com/')).to eq 'domain.example.com'
     end
   end
 
@@ -69,18 +69,18 @@ RSpec.describe TagManager do
     end
 
     it 'returns true if the normalized string with port is local URL' do
-      Rails.configuration.x.web_domain = 'domain.test:42'
-      expect(TagManager.instance.local_url?('https://DoMaIn.Test:42/')).to eq true
+      Rails.configuration.x.web_domain = 'domain.example.com:42'
+      expect(TagManager.instance.local_url?('https://DoMaIn.Example.com:42/')).to eq true
     end
 
     it 'returns true if the normalized string without port is local URL' do
-      Rails.configuration.x.web_domain = 'domain.test'
-      expect(TagManager.instance.local_url?('https://DoMaIn.Test/')).to eq true
+      Rails.configuration.x.web_domain = 'domain.example.com'
+      expect(TagManager.instance.local_url?('https://DoMaIn.Example.com/')).to eq true
     end
 
     it 'returns false for string with irrelevant characters' do
-      Rails.configuration.x.web_domain = 'domain.test'
-      expect(TagManager.instance.local_url?('https://domainn.test/')).to eq false
+      Rails.configuration.x.web_domain = 'domain.example.com'
+      expect(TagManager.instance.local_url?('https://domain.example.net/')).to eq false
     end
   end
 end
diff --git a/spec/models/account_statuses_filter_spec.rb b/spec/models/account_statuses_filter_spec.rb
new file mode 100644
index 000000000..03f0ffeb0
--- /dev/null
+++ b/spec/models/account_statuses_filter_spec.rb
@@ -0,0 +1,229 @@
+# frozen_string_literal: true
+
+require 'rails_helper'
+
+RSpec.describe AccountStatusesFilter do
+  let(:account) { Fabricate(:account) }
+  let(:current_account) { nil }
+  let(:params) { {} }
+
+  subject { described_class.new(account, current_account, params) }
+
+  def status!(visibility)
+    Fabricate(:status, account: account, visibility: visibility)
+  end
+
+  def status_with_tag!(visibility, tag)
+    Fabricate(:status, account: account, visibility: visibility, tags: [tag])
+  end
+
+  def status_with_parent!(visibility)
+    Fabricate(:status, account: account, visibility: visibility, thread: Fabricate(:status))
+  end
+
+  def status_with_reblog!(visibility)
+    Fabricate(:status, account: account, visibility: visibility, reblog: Fabricate(:status))
+  end
+
+  def status_with_mention!(visibility, mentioned_account = nil)
+    Fabricate(:status, account: account, visibility: visibility).tap do |status|
+      Fabricate(:mention, status: status, account: mentioned_account || Fabricate(:account))
+    end
+  end
+
+  def status_with_media_attachment!(visibility)
+    Fabricate(:status, account: account, visibility: visibility).tap do |status|
+      Fabricate(:media_attachment, account: account, status: status)
+    end
+  end
+
+  describe '#results' do
+    let(:tag) { Fabricate(:tag) }
+
+    before do
+      status!(:public)
+      status!(:unlisted)
+      status!(:private)
+      status_with_parent!(:public)
+      status_with_reblog!(:public)
+      status_with_tag!(:public, tag)
+      status_with_mention!(:direct)
+      status_with_media_attachment!(:public)
+    end
+
+    shared_examples 'filter params' do
+      context 'with only_media param' do
+        let(:params) { { only_media: true } }
+
+        it 'returns only statuses with media' do
+          expect(subject.results.all?(&:with_media?)).to be true
+        end
+      end
+
+      context 'with tagged param' do
+        let(:params) { { tagged: tag.name } }
+
+        it 'returns only statuses with tag' do
+          expect(subject.results.all? { |s| s.tags.include?(tag) }).to be true
+        end
+      end
+
+      context 'with exclude_replies param' do
+        let(:params) { { exclude_replies: true } }
+
+        it 'returns only statuses that are not replies' do
+          expect(subject.results.none?(&:reply?)).to be true
+        end
+      end
+
+      context 'with exclude_reblogs param' do
+        let(:params) { { exclude_reblogs: true } }
+
+        it 'returns only statuses that are not reblogs' do
+          expect(subject.results.none?(&:reblog?)).to be true
+        end
+      end
+    end
+
+    context 'when accessed anonymously' do
+      let(:current_account) { nil }
+      let(:direct_status) { nil }
+
+      it 'returns only public statuses' do
+        expect(subject.results.pluck(:visibility).uniq).to match_array %w(unlisted public)
+      end
+
+      it 'returns public replies' do
+        expect(subject.results.pluck(:in_reply_to_id)).to_not be_empty
+      end
+
+      it 'returns public reblogs' do
+        expect(subject.results.pluck(:reblog_of_id)).to_not be_empty
+      end
+
+      it_behaves_like 'filter params'
+    end
+
+    context 'when accessed with a blocked account' do
+      let(:current_account) { Fabricate(:account) }
+
+      before do
+        account.block!(current_account)
+      end
+
+      it 'returns nothing' do
+        expect(subject.results.to_a).to be_empty
+      end
+    end
+
+    context 'when accessed by self' do
+      let(:current_account) { account }
+
+      it 'returns everything' do
+        expect(subject.results.pluck(:visibility).uniq).to match_array %w(direct private unlisted public)
+      end
+
+      it 'returns replies' do
+        expect(subject.results.pluck(:in_reply_to_id)).to_not be_empty
+      end
+
+      it 'returns reblogs' do
+        expect(subject.results.pluck(:reblog_of_id)).to_not be_empty
+      end
+
+      it_behaves_like 'filter params'
+    end
+
+    context 'when accessed by a follower' do
+      let(:current_account) { Fabricate(:account) }
+
+      before do
+        current_account.follow!(account)
+      end
+
+      it 'returns private statuses' do
+        expect(subject.results.pluck(:visibility).uniq).to match_array %w(private unlisted public)
+      end
+
+      it 'returns replies' do
+        expect(subject.results.pluck(:in_reply_to_id)).to_not be_empty
+      end
+
+      it 'returns reblogs' do
+        expect(subject.results.pluck(:reblog_of_id)).to_not be_empty
+      end
+
+      context 'when there is a direct status mentioning the non-follower' do
+        let!(:direct_status) { status_with_mention!(:direct, current_account) }
+
+        it 'returns the direct status' do
+          expect(subject.results.pluck(:id)).to include(direct_status.id)
+        end
+      end
+
+      it_behaves_like 'filter params'
+    end
+
+    context 'when accessed by a non-follower' do
+      let(:current_account) { Fabricate(:account) }
+
+      it 'returns only public statuses' do
+        expect(subject.results.pluck(:visibility).uniq).to match_array %w(unlisted public)
+      end
+
+      it 'returns public replies' do
+        expect(subject.results.pluck(:in_reply_to_id)).to_not be_empty
+      end
+
+      it 'returns public reblogs' do
+        expect(subject.results.pluck(:reblog_of_id)).to_not be_empty
+      end
+
+      context 'when there is a private status mentioning the non-follower' do
+        let!(:private_status) { status_with_mention!(:private, current_account) }
+
+        it 'returns the private status' do
+          expect(subject.results.pluck(:id)).to include(private_status.id)
+        end
+      end
+
+      context 'when blocking a reblogged account' do
+        let(:reblog) { status_with_reblog!('public') }
+
+        before do
+          current_account.block!(reblog.reblog.account)
+        end
+
+        it 'does not return reblog of blocked account' do
+          expect(subject.results.pluck(:id)).to_not include(reblog.id)
+        end
+      end
+
+      context 'when muting a reblogged account' do
+        let(:reblog) { status_with_reblog!('public') }
+
+        before do
+          current_account.mute!(reblog.reblog.account)
+        end
+
+        it 'does not return reblog of muted account' do
+          expect(subject.results.pluck(:id)).to_not include(reblog.id)
+        end
+      end
+
+      context 'when blocked by a reblogged account' do
+        let(:reblog) { status_with_reblog!('public') }
+
+        before do
+          reblog.reblog.account.block!(current_account)
+        end
+
+        it 'does not return reblog of blocked-by account' do
+          expect(subject.results.pluck(:id)).to_not include(reblog.id)
+        end
+      end
+
+      it_behaves_like 'filter params'
+    end
+  end
+end
diff --git a/spec/models/report_spec.rb b/spec/models/report_spec.rb
index 3d29c0219..df32a7c9d 100644
--- a/spec/models/report_spec.rb
+++ b/spec/models/report_spec.rb
@@ -119,7 +119,7 @@ describe Report do
     end
   end
 
-  describe 'validatiions' do
+  describe 'validations' do
     it 'has a valid fabricator' do
       report = Fabricate(:report)
       report.valid?
diff --git a/spec/models/status_spec.rb b/spec/models/status_spec.rb
index 029789a11..d3b23726d 100644
--- a/spec/models/status_spec.rb
+++ b/spec/models/status_spec.rb
@@ -435,59 +435,6 @@ RSpec.describe Status, type: :model do
     end
   end
 
-  describe '.permitted_for' do
-    subject { described_class.permitted_for(target_account, account).pluck(:visibility) }
-
-    let(:target_account) { alice }
-    let(:account) { bob }
-    let!(:public_status) { Fabricate(:status, account: target_account, visibility: 'public') }
-    let!(:unlisted_status) { Fabricate(:status, account: target_account, visibility: 'unlisted') }
-    let!(:private_status) { Fabricate(:status, account: target_account, visibility: 'private') }
-
-    let!(:direct_status) do
-      Fabricate(:status, account: target_account, visibility: 'direct').tap do |status|
-        Fabricate(:mention, status: status, account: account)
-      end
-    end
-
-    let!(:other_direct_status) do
-      Fabricate(:status, account: target_account, visibility: 'direct').tap do |status|
-        Fabricate(:mention, status: status)
-      end
-    end
-
-    context 'given nil' do
-      let(:account) { nil }
-      let(:direct_status) { nil }
-      it { is_expected.to eq(%w(unlisted public)) }
-    end
-
-    context 'given blocked account' do
-      before do
-        target_account.block!(account)
-      end
-
-      it { is_expected.to be_empty }
-    end
-
-    context 'given same account' do
-      let(:account) { target_account }
-      it { is_expected.to eq(%w(direct direct private unlisted public)) }
-    end
-
-    context 'given followed account' do
-      before do
-        account.follow!(target_account)
-      end
-
-      it { is_expected.to eq(%w(direct private unlisted public)) }
-    end
-
-    context 'given unfollowed account' do
-      it { is_expected.to eq(%w(direct unlisted public)) }
-    end
-  end
-
   describe 'before_validation' do
     it 'sets account being replied to correctly over intermediary nodes' do
       first_status = Fabricate(:status, account: bob)
diff --git a/spec/policies/user_policy_spec.rb b/spec/policies/user_policy_spec.rb
index 1933ee014..731c041d1 100644
--- a/spec/policies/user_policy_spec.rb
+++ b/spec/policies/user_policy_spec.rb
@@ -114,13 +114,13 @@ RSpec.describe UserPolicy do
 
   permissions :promote? do
     context 'admin?' do
-      context 'promoteable?' do
+      context 'promotable?' do
         it 'permits' do
           expect(subject).to permit(admin, john.user)
         end
       end
 
-      context '!promoteable?' do
+      context '!promotable?' do
         it 'denies' do
           expect(subject).to_not permit(admin, admin.user)
         end
diff --git a/spec/presenters/familiar_followers_presenter_spec.rb b/spec/presenters/familiar_followers_presenter_spec.rb
new file mode 100644
index 000000000..17be4b971
--- /dev/null
+++ b/spec/presenters/familiar_followers_presenter_spec.rb
@@ -0,0 +1,58 @@
+# frozen_string_literal: true
+
+require 'rails_helper'
+
+RSpec.describe FamiliarFollowersPresenter do
+  describe '#accounts' do
+    let(:account) { Fabricate(:account) }
+    let(:familiar_follower) { Fabricate(:account) }
+    let(:requested_accounts) { Fabricate.times(2, :account) }
+
+    subject { described_class.new(requested_accounts, account.id) }
+
+    before do
+      familiar_follower.follow!(requested_accounts.first)
+      account.follow!(familiar_follower)
+    end
+
+    it 'returns a result for each requested account' do
+      expect(subject.accounts.map(&:id)).to eq requested_accounts.map(&:id)
+    end
+
+    it 'returns followers you follow' do
+      result = subject.accounts.first
+
+      expect(result).to_not be_nil
+      expect(result.id).to eq requested_accounts.first.id
+      expect(result.accounts).to match_array([familiar_follower])
+    end
+
+    context 'when requested account hides followers' do
+      before do
+        requested_accounts.first.update(hide_collections: true)
+      end
+
+      it 'does not return followers you follow' do
+        result = subject.accounts.first
+
+        expect(result).to_not be_nil
+        expect(result.id).to eq requested_accounts.first.id
+        expect(result.accounts).to be_empty
+      end
+    end
+
+    context 'when familiar follower hides follows' do
+      before do
+        familiar_follower.update(hide_collections: true)
+      end
+
+      it 'does not return followers you follow' do
+        result = subject.accounts.first
+
+        expect(result).to_not be_nil
+        expect(result.id).to eq requested_accounts.first.id
+        expect(result.accounts).to be_empty
+      end
+    end
+  end
+end
diff --git a/spec/services/unsuspend_account_service_spec.rb b/spec/services/unsuspend_account_service_spec.rb
index d52cb6cc0..0593beb6f 100644
--- a/spec/services/unsuspend_account_service_spec.rb
+++ b/spec/services/unsuspend_account_service_spec.rb
@@ -63,20 +63,20 @@ RSpec.describe UnsuspendAccountService, type: :service do
   describe 'unsuspending a remote account' do
     include_examples 'common behavior' do
       let!(:account)                 { Fabricate(:account, domain: 'bob.com', uri: 'https://bob.com', inbox_url: 'https://bob.com/inbox', protocol: :activitypub) }
-      let!(:reslove_account_service) { double }
+      let!(:resolve_account_service) { double }
 
       before do
-        allow(ResolveAccountService).to receive(:new).and_return(reslove_account_service)
+        allow(ResolveAccountService).to receive(:new).and_return(resolve_account_service)
       end
 
       context 'when the account is not remotely suspended' do
         before do
-          allow(reslove_account_service).to receive(:call).with(account).and_return(account)
+          allow(resolve_account_service).to receive(:call).with(account).and_return(account)
         end
 
         it 're-fetches the account' do
           subject.call
-          expect(reslove_account_service).to have_received(:call).with(account)
+          expect(resolve_account_service).to have_received(:call).with(account)
         end
 
         it "merges back into local followers' feeds" do
@@ -92,7 +92,7 @@ RSpec.describe UnsuspendAccountService, type: :service do
 
       context 'when the account is remotely suspended' do
         before do
-          allow(reslove_account_service).to receive(:call).with(account) do |account|
+          allow(resolve_account_service).to receive(:call).with(account) do |account|
             account.suspend!(origin: :remote)
             account
           end
@@ -100,7 +100,7 @@ RSpec.describe UnsuspendAccountService, type: :service do
 
         it 're-fetches the account' do
           subject.call
-          expect(reslove_account_service).to have_received(:call).with(account)
+          expect(resolve_account_service).to have_received(:call).with(account)
         end
 
         it "does not merge back into local followers' feeds" do
@@ -116,12 +116,12 @@ RSpec.describe UnsuspendAccountService, type: :service do
 
       context 'when the account is remotely deleted' do
         before do
-          allow(reslove_account_service).to receive(:call).with(account).and_return(nil)
+          allow(resolve_account_service).to receive(:call).with(account).and_return(nil)
         end
 
         it 're-fetches the account' do
           subject.call
-          expect(reslove_account_service).to have_received(:call).with(account)
+          expect(resolve_account_service).to have_received(:call).with(account)
         end
 
         it "does not merge back into local followers' feeds" do
diff --git a/spec/support/stories/profile_stories.rb b/spec/support/stories/profile_stories.rb
index 75b413330..0c4a14d1c 100644
--- a/spec/support/stories/profile_stories.rb
+++ b/spec/support/stories/profile_stories.rb
@@ -22,7 +22,7 @@ module ProfileStories
   def with_alice_as_local_user
     @alice_bio = '@alice and @bob are fictional characters commonly used as'\
                  'placeholder names in #cryptology, as well as #science and'\
-                 'engineering 📖 literature. Not affilated with @pepe.'
+                 'engineering 📖 literature. Not affiliated with @pepe.'
 
     @alice = Fabricate(
       :user,