about summary refs log tree commit diff
path: root/spec
diff options
context:
space:
mode:
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/admin/email_domain_blocks_controller_spec.rb42
-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/reports_controller_spec.rb54
-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/api/v1/trends/tags_controller_spec.rb7
-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/fabricators/rule_fabricator.rb8
-rw-r--r--spec/helpers/application_helper_spec.rb2
-rw-r--r--spec/lib/scope_transformer_spec.rb89
-rw-r--r--spec/lib/tag_manager_spec.rb26
-rw-r--r--spec/mailers/previews/admin_mailer_preview.rb11
-rw-r--r--spec/models/account_statuses_filter_spec.rb229
-rw-r--r--spec/models/email_domain_block_spec.rb27
-rw-r--r--spec/models/report_spec.rb2
-rw-r--r--spec/models/status_spec.rb53
-rw-r--r--spec/models/trends/statuses_spec.rb110
-rw-r--r--spec/models/trends/tags_spec.rb6
-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/matchers/model/model_have_error_on_field.rb2
-rw-r--r--spec/support/stories/profile_stories.rb2
-rw-r--r--spec/validators/blacklisted_email_validator_spec.rb2
-rw-r--r--spec/validators/email_mx_validator_spec.rb56
-rw-r--r--spec/views/about/show.html.haml_spec.rb1
35 files changed, 681 insertions, 192 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/admin/email_domain_blocks_controller_spec.rb b/spec/controllers/admin/email_domain_blocks_controller_spec.rb
index 52db56f4e..cf194579d 100644
--- a/spec/controllers/admin/email_domain_blocks_controller_spec.rb
+++ b/spec/controllers/admin/email_domain_blocks_controller_spec.rb
@@ -17,43 +17,43 @@ RSpec.describe Admin::EmailDomainBlocksController, type: :controller do
       EmailDomainBlock.paginates_per default_per_page
     end
 
-    it 'renders email blacks' do
+    it 'returns http success' do
       2.times { Fabricate(:email_domain_block) }
-
       get :index, params: { page: 2 }
-
-      assigned = assigns(:email_domain_blocks)
-      expect(assigned.count).to eq 1
-      expect(assigned.klass).to be EmailDomainBlock
       expect(response).to have_http_status(200)
     end
   end
 
   describe 'GET #new' do
-    it 'assigns a new email black' do
+    it 'returns http success' do
       get :new
-
-      expect(assigns(:email_domain_block)).to be_instance_of(EmailDomainBlock)
       expect(response).to have_http_status(200)
     end
   end
 
   describe 'POST #create' do
-    it 'blocks the domain when succeeded to save' do
-      post :create, params: { email_domain_block: { domain: 'example.com' } }
-
-      expect(flash[:notice]).to eq I18n.t('admin.email_domain_blocks.created_msg')
-      expect(response).to redirect_to(admin_email_domain_blocks_path)
+    context 'when resolve button is pressed' do
+      before do
+        post :create, params: { email_domain_block: { domain: 'example.com' } }
+      end
+
+      it 'renders new template' do
+        expect(response).to render_template(:new)
+      end
     end
-  end
 
-  describe 'DELETE #destroy' do
-    it 'unblocks the domain' do
-      email_domain_block = Fabricate(:email_domain_block)
-      delete :destroy, params: { id: email_domain_block.id }
+    context 'when save button is pressed' do
+      before do
+        post :create, params: { email_domain_block: { domain: 'example.com' }, save: '' }
+      end
+
+      it 'blocks the domain' do
+        expect(EmailDomainBlock.find_by(domain: 'example.com')).to_not be_nil
+      end
 
-      expect(flash[:notice]).to eq I18n.t('admin.email_domain_blocks.destroyed_msg')
-      expect(response).to redirect_to(admin_email_domain_blocks_path)
+      it 'redirects to e-mail domain blocks' do
+        expect(response).to redirect_to(admin_email_domain_blocks_path)
+      end
     end
   end
 end
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/reports_controller_spec.rb b/spec/controllers/api/v1/reports_controller_spec.rb
index a13de1370..b5baf60e1 100644
--- a/spec/controllers/api/v1/reports_controller_spec.rb
+++ b/spec/controllers/api/v1/reports_controller_spec.rb
@@ -13,22 +13,64 @@ RSpec.describe Api::V1::ReportsController, type: :controller do
   end
 
   describe 'POST #create' do
-    let(:scopes)  { 'write:reports' }
-    let!(:status) { Fabricate(:status) }
-    let!(:admin)  { Fabricate(:user, admin: true) }
+    let!(:admin) { Fabricate(:user, admin: true) }
+
+    let(:scopes) { 'write:reports' }
+    let(:status) { Fabricate(:status) }
+    let(:target_account) { status.account }
+    let(:category) { nil }
+    let(:forward) { nil }
+    let(:rule_ids){ nil }
 
     before do
       allow(AdminMailer).to receive(:new_report).and_return(double('email', deliver_later: nil))
-      post :create, params: { status_ids: [status.id], account_id: status.account.id, comment: 'reasons' }
+      post :create, params: { status_ids: [status.id], account_id: target_account.id, comment: 'reasons', category: category, rule_ids: rule_ids, forward: forward }
     end
 
-    it 'creates a report' do
-      expect(status.reload.account.targeted_reports).not_to be_empty
+    it 'returns http success' do
       expect(response).to have_http_status(200)
     end
 
+    it 'creates a report' do
+      expect(target_account.targeted_reports).to_not be_empty
+    end
+
+    it 'saves comment' do
+      expect(target_account.targeted_reports.first.comment).to eq 'reasons'
+    end
+
     it 'sends e-mails to admins' do
       expect(AdminMailer).to have_received(:new_report).with(admin.account, Report)
     end
+
+    context 'when a status does not belong to the reported account' do
+      let(:target_account) { Fabricate(:account) }
+
+      it 'returns http not found' do
+        expect(response).to have_http_status(404)
+      end
+    end
+
+    context 'when a category is chosen' do
+      let(:category) { 'spam' }
+
+      it 'saves category' do
+        expect(target_account.targeted_reports.first.spam?).to be true
+      end
+    end
+
+    context 'when violated rules are chosen' do
+      let(:rule) { Fabricate(:rule) }
+      let(:category) { 'violation' }
+      let(:rule_ids) { [rule.id] }
+
+      it 'saves category' do
+        expect(target_account.targeted_reports.first.violation?).to be true
+      end
+
+      it 'saves rule_ids' do
+        expect(target_account.targeted_reports.first.rule_ids).to match_array([rule.id])
+      end
+    end
   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/api/v1/trends/tags_controller_spec.rb b/spec/controllers/api/v1/trends/tags_controller_spec.rb
index e2e26dcab..d29551c56 100644
--- a/spec/controllers/api/v1/trends/tags_controller_spec.rb
+++ b/spec/controllers/api/v1/trends/tags_controller_spec.rb
@@ -7,10 +7,9 @@ RSpec.describe Api::V1::Trends::TagsController, type: :controller do
 
   describe 'GET #index' do
     before do
-      trending_tags = double()
-
-      allow(trending_tags).to receive(:get).and_return(Fabricate.times(10, :tag))
-      allow(Trends).to receive(:tags).and_return(trending_tags)
+      Fabricate.times(10, :tag).each do |tag|
+        10.times { |i| Trends.tags.add(tag, i) }
+      end
 
       get :index
     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/fabricators/rule_fabricator.rb b/spec/fabricators/rule_fabricator.rb
index 4bdfd05e0..bc29bc48e 100644
--- a/spec/fabricators/rule_fabricator.rb
+++ b/spec/fabricators/rule_fabricator.rb
@@ -1,5 +1,5 @@
 Fabricator(:rule) do
-  priority   ""
-  deleted_at "2021-02-21 05:51:09"
-  text       "MyText"
-end
\ No newline at end of file
+  priority   0
+  deleted_at nil
+  text       { Faker::Lorem.paragraph }
+end
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/scope_transformer_spec.rb b/spec/lib/scope_transformer_spec.rb
new file mode 100644
index 000000000..e5a992144
--- /dev/null
+++ b/spec/lib/scope_transformer_spec.rb
@@ -0,0 +1,89 @@
+# frozen_string_literal: true
+
+require 'rails_helper'
+
+describe ScopeTransformer do
+  describe '#apply' do
+    subject { described_class.new.apply(ScopeParser.new.parse(input)) }
+
+    shared_examples 'a scope' do |namespace, term, access|
+      it 'parses the term' do
+        expect(subject.term).to eq term
+      end
+
+      it 'parses the namespace' do
+        expect(subject.namespace).to eq namespace
+      end
+
+      it 'parses the access' do
+        expect(subject.access).to eq access
+      end
+    end
+
+    context 'for scope "read"' do
+      let(:input) { 'read' }
+
+      it_behaves_like 'a scope', nil, 'all', 'read'
+    end
+
+    context 'for scope "write"' do
+      let(:input) { 'write' }
+
+      it_behaves_like 'a scope', nil, 'all', 'write'
+    end
+
+    context 'for scope "follow"' do
+      let(:input) { 'follow' }
+
+      it_behaves_like 'a scope', nil, 'follow', 'read/write'
+    end
+
+    context 'for scope "crypto"' do
+      let(:input) { 'crypto' }
+
+      it_behaves_like 'a scope', nil, 'crypto', 'read/write'
+    end
+
+    context 'for scope "push"' do
+      let(:input) { 'push' }
+
+      it_behaves_like 'a scope', nil, 'push', 'read/write'
+    end
+
+    context 'for scope "admin:read"' do
+      let(:input) { 'admin:read' }
+
+      it_behaves_like 'a scope', 'admin', 'all', 'read'
+    end
+
+    context 'for scope "admin:write"' do
+      let(:input) { 'admin:write' }
+
+      it_behaves_like 'a scope', 'admin', 'all', 'write'
+    end
+
+    context 'for scope "admin:read:accounts"' do
+      let(:input) { 'admin:read:accounts' }
+
+      it_behaves_like 'a scope', 'admin', 'accounts', 'read'
+    end
+
+    context 'for scope "admin:write:accounts"' do
+      let(:input) { 'admin:write:accounts' }
+
+      it_behaves_like 'a scope', 'admin', 'accounts', 'write'
+    end
+
+    context 'for scope "read:accounts"' do
+      let(:input) { 'read:accounts' }
+
+      it_behaves_like 'a scope', nil, 'accounts', 'read'
+    end
+
+    context 'for scope "write:accounts"' do
+      let(:input) { 'write:accounts' }
+
+      it_behaves_like 'a scope', nil, 'accounts', 'write'
+    end
+  end
+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/mailers/previews/admin_mailer_preview.rb b/spec/mailers/previews/admin_mailer_preview.rb
index 9c0372b47..01436ba7a 100644
--- a/spec/mailers/previews/admin_mailer_preview.rb
+++ b/spec/mailers/previews/admin_mailer_preview.rb
@@ -6,14 +6,9 @@ class AdminMailerPreview < ActionMailer::Preview
     AdminMailer.new_pending_account(Account.first, User.pending.first)
   end
 
-  # Preview this email at http://localhost:3000/rails/mailers/admin_mailer/new_trending_tags
-  def new_trending_tags
-    AdminMailer.new_trending_tags(Account.first, Tag.limit(3))
-  end
-
-  # Preview this email at http://localhost:3000/rails/mailers/admin_mailer/new_trending_links
-  def new_trending_links
-    AdminMailer.new_trending_links(Account.first, PreviewCard.limit(3))
+  # Preview this email at http://localhost:3000/rails/mailers/admin_mailer/new_trends
+  def new_trends
+    AdminMailer.new_trends(Account.first, PreviewCard.limit(3), Tag.limit(3), Status.where(reblog_of_id: nil).limit(3))
   end
 
   # Preview this email at http://localhost:3000/rails/mailers/admin_mailer/new_appeal
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/email_domain_block_spec.rb b/spec/models/email_domain_block_spec.rb
index efd2853a9..567a32c32 100644
--- a/spec/models/email_domain_block_spec.rb
+++ b/spec/models/email_domain_block_spec.rb
@@ -9,14 +9,29 @@ RSpec.describe EmailDomainBlock, type: :model do
   end
 
   describe 'block?' do
-    it 'returns true if the domain is registed' do
-      Fabricate(:email_domain_block, domain: 'example.com')
-      expect(EmailDomainBlock.block?('nyarn@example.com')).to eq true
+    let(:input) { nil }
+
+    context 'given an e-mail address' do
+      let(:input) { 'nyarn@example.com' }
+
+      it 'returns true if the domain is blocked' do
+        Fabricate(:email_domain_block, domain: 'example.com')
+        expect(EmailDomainBlock.block?(input)).to be true
+      end
+
+      it 'returns false if the domain is not blocked' do
+        Fabricate(:email_domain_block, domain: 'other-example.com')
+        expect(EmailDomainBlock.block?(input)).to be false
+      end
     end
 
-    it 'returns true if the domain is not registed' do
-      Fabricate(:email_domain_block, domain: 'example.com')
-      expect(EmailDomainBlock.block?('nyarn@example.net')).to eq false
+    context 'given an array of domains' do
+      let(:input) { %w(foo.com mail.foo.com) }
+
+      it 'returns true if the domain is blocked' do
+        Fabricate(:email_domain_block, domain: 'mail.foo.com')
+        expect(EmailDomainBlock.block?(input)).to be true
+      end
     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/models/trends/statuses_spec.rb b/spec/models/trends/statuses_spec.rb
new file mode 100644
index 000000000..9cc67acbe
--- /dev/null
+++ b/spec/models/trends/statuses_spec.rb
@@ -0,0 +1,110 @@
+require 'rails_helper'
+
+RSpec.describe Trends::Statuses do
+  subject! { described_class.new(threshold: 5, review_threshold: 10, score_halflife: 8.hours) }
+
+  let!(:at_time) { DateTime.new(2021, 11, 14, 10, 15, 0) }
+
+  describe 'Trends::Statuses::Query' do
+    let!(:query) { subject.query }
+    let!(:today) { at_time }
+
+    let!(:status1) { Fabricate(:status, text: 'Foo', trendable: true, created_at: today) }
+    let!(:status2) { Fabricate(:status, text: 'Bar', trendable: true, created_at: today) }
+
+    before do
+      15.times { reblog(status1, today) }
+      12.times { reblog(status2, today) }
+
+      subject.refresh(today)
+    end
+
+    describe '#filtered_for' do
+      let(:account) { Fabricate(:account) }
+
+      it 'returns a composable query scope' do
+        expect(query.filtered_for(account)).to be_a Trends::Query
+      end
+
+      it 'filters out blocked accounts' do
+        account.block!(status1.account)
+        expect(query.filtered_for(account).to_a).to eq [status2]
+      end
+
+      it 'filters out muted accounts' do
+        account.mute!(status2.account)
+        expect(query.filtered_for(account).to_a).to eq [status1]
+      end
+
+      it 'filters out blocked-by accounts' do
+        status1.account.block!(account)
+        expect(query.filtered_for(account).to_a).to eq [status2]
+      end
+    end
+  end
+
+  describe '#add' do
+    let(:status) { Fabricate(:status) }
+
+    before do
+      subject.add(status, 1, at_time)
+    end
+
+    it 'records use' do
+      expect(subject.send(:recently_used_ids, at_time)).to eq [status.id]
+    end
+  end
+
+  describe '#query' do
+    it 'returns a composable query scope' do
+      expect(subject.query).to be_a Trends::Query
+    end
+
+    it 'responds to filtered_for' do
+      expect(subject.query).to respond_to(:filtered_for)
+    end
+  end
+
+  describe '#refresh' do
+    let!(:today) { at_time }
+    let!(:yesterday) { today - 1.day }
+
+    let!(:status1) { Fabricate(:status, text: 'Foo', trendable: true, created_at: yesterday) }
+    let!(:status2) { Fabricate(:status, text: 'Bar', trendable: true, created_at: today) }
+    let!(:status3) { Fabricate(:status, text: 'Baz', trendable: true, created_at: today) }
+
+    before do
+      13.times { reblog(status1, today) }
+      13.times { reblog(status2, today) }
+       4.times { reblog(status3, today) }
+    end
+
+    context do
+      before do
+        subject.refresh(today)
+      end
+
+      it 'calculates and re-calculates scores' do
+        expect(subject.query.limit(10).to_a).to eq [status2, status1]
+      end
+
+      it 'omits statuses below threshold' do
+        expect(subject.query.limit(10).to_a).to_not include(status3)
+      end
+    end
+
+    it 'decays scores' do
+      subject.refresh(today)
+      original_score = subject.score(status2.id)
+      expect(original_score).to be_a Float
+      subject.refresh(today + subject.options[:score_halflife])
+      decayed_score = subject.score(status2.id)
+      expect(decayed_score).to be <= original_score / 2
+    end
+  end
+
+  def reblog(status, at_time)
+    reblog = Fabricate(:status, reblog: status, created_at: at_time)
+    subject.add(status, reblog.account_id, at_time)
+  end
+end
diff --git a/spec/models/trends/tags_spec.rb b/spec/models/trends/tags_spec.rb
index 4f98c6aa4..f48c73503 100644
--- a/spec/models/trends/tags_spec.rb
+++ b/spec/models/trends/tags_spec.rb
@@ -21,7 +21,7 @@ RSpec.describe Trends::Tags do
     end
   end
 
-  describe '#get' do
+  describe '#query' do
     pending
   end
 
@@ -47,11 +47,11 @@ RSpec.describe Trends::Tags do
       end
 
       it 'calculates and re-calculates scores' do
-        expect(subject.get(false, 10)).to eq [tag1, tag3]
+        expect(subject.query.limit(10).to_a).to eq [tag1, tag3]
       end
 
       it 'omits hashtags below threshold' do
-        expect(subject.get(false, 10)).to_not include(tag2)
+        expect(subject.query.limit(10).to_a).to_not include(tag2)
       end
     end
 
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/matchers/model/model_have_error_on_field.rb b/spec/support/matchers/model/model_have_error_on_field.rb
index a5dfbf457..85bdd8215 100644
--- a/spec/support/matchers/model/model_have_error_on_field.rb
+++ b/spec/support/matchers/model/model_have_error_on_field.rb
@@ -8,7 +8,7 @@ RSpec::Matchers.define :model_have_error_on_field do |expected|
   end
 
   failure_message do |record|
-    keys = record.errors.keys
+    keys = record.errors.attribute_names
 
     "expect record.errors(#{keys}) to include #{expected}"
   end
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,
diff --git a/spec/validators/blacklisted_email_validator_spec.rb b/spec/validators/blacklisted_email_validator_spec.rb
index f7d5e01bc..351de0707 100644
--- a/spec/validators/blacklisted_email_validator_spec.rb
+++ b/spec/validators/blacklisted_email_validator_spec.rb
@@ -4,7 +4,7 @@ require 'rails_helper'
 
 RSpec.describe BlacklistedEmailValidator, type: :validator do
   describe '#validate' do
-    let(:user)   { double(email: 'info@mail.com', errors: errors) }
+    let(:user)   { double(email: 'info@mail.com', sign_up_ip: '1.2.3.4', errors: errors) }
     let(:errors) { double(add: nil) }
 
     before do
diff --git a/spec/validators/email_mx_validator_spec.rb b/spec/validators/email_mx_validator_spec.rb
index 550e91996..af0eb98f5 100644
--- a/spec/validators/email_mx_validator_spec.rb
+++ b/spec/validators/email_mx_validator_spec.rb
@@ -4,24 +4,28 @@ require 'rails_helper'
 
 describe EmailMxValidator do
   describe '#validate' do
-    let(:user) { double(email: 'foo@example.com', errors: double(add: nil)) }
-
-    it 'does not add errors if there are no DNS records for an e-mail domain that is explicitly allowed' do
-      old_whitelist = Rails.configuration.x.email_domains_whitelist
-      Rails.configuration.x.email_domains_whitelist = 'example.com'
-
-      resolver = double
-
-      allow(resolver).to receive(:getresources).with('example.com', Resolv::DNS::Resource::IN::MX).and_return([])
-      allow(resolver).to receive(:getresources).with('example.com', Resolv::DNS::Resource::IN::A).and_return([])
-      allow(resolver).to receive(:getresources).with('example.com', Resolv::DNS::Resource::IN::AAAA).and_return([])
-      allow(resolver).to receive(:timeouts=).and_return(nil)
-      allow(Resolv::DNS).to receive(:open).and_yield(resolver)
-
-      subject.validate(user)
-      expect(user.errors).to_not have_received(:add)
-
-      Rails.configuration.x.email_domains_whitelist = old_whitelist
+    let(:user) { double(email: 'foo@example.com', sign_up_ip: '1.2.3.4', errors: double(add: nil)) }
+
+    context 'for an e-mail domain that is explicitly allowed' do
+      around do |block|
+        tmp = Rails.configuration.x.email_domains_whitelist
+        Rails.configuration.x.email_domains_whitelist = 'example.com'
+        block.call
+        Rails.configuration.x.email_domains_whitelist = tmp
+      end
+
+      it 'does not add errors if there are no DNS records' do
+        resolver = double
+
+        allow(resolver).to receive(:getresources).with('example.com', Resolv::DNS::Resource::IN::MX).and_return([])
+        allow(resolver).to receive(:getresources).with('example.com', Resolv::DNS::Resource::IN::A).and_return([])
+        allow(resolver).to receive(:getresources).with('example.com', Resolv::DNS::Resource::IN::AAAA).and_return([])
+        allow(resolver).to receive(:timeouts=).and_return(nil)
+        allow(Resolv::DNS).to receive(:open).and_yield(resolver)
+
+        subject.validate(user)
+        expect(user.errors).to_not have_received(:add)
+      end
     end
 
     it 'adds an error if there are no DNS records for the e-mail domain' do
@@ -37,7 +41,7 @@ describe EmailMxValidator do
       expect(user.errors).to have_received(:add)
     end
 
-    it 'adds an error if a MX record exists but does not lead to an IP' do
+    it 'adds an error if a MX record does not lead to an IP' do
       resolver = double
 
       allow(resolver).to receive(:getresources).with('example.com', Resolv::DNS::Resource::IN::MX).and_return([double(exchange: 'mail.example.com')])
@@ -53,7 +57,7 @@ describe EmailMxValidator do
     end
 
     it 'adds an error if the A record is blacklisted' do
-      EmailDomainBlock.create!(domain: '1.2.3.4')
+      EmailDomainBlock.create!(domain: 'alternate-example.com', ips: ['1.2.3.4'])
       resolver = double
 
       allow(resolver).to receive(:getresources).with('example.com', Resolv::DNS::Resource::IN::MX).and_return([])
@@ -67,7 +71,7 @@ describe EmailMxValidator do
     end
 
     it 'adds an error if the AAAA record is blacklisted' do
-      EmailDomainBlock.create!(domain: 'fd00::1')
+      EmailDomainBlock.create!(domain: 'alternate-example.com', ips: ['fd00::1'])
       resolver = double
 
       allow(resolver).to receive(:getresources).with('example.com', Resolv::DNS::Resource::IN::MX).and_return([])
@@ -80,8 +84,8 @@ describe EmailMxValidator do
       expect(user.errors).to have_received(:add)
     end
 
-    it 'adds an error if the MX record is blacklisted' do
-      EmailDomainBlock.create!(domain: '2.3.4.5')
+    it 'adds an error if the A record of the MX record is blacklisted' do
+      EmailDomainBlock.create!(domain: 'mail.other-domain.com', ips: ['2.3.4.5'])
       resolver = double
 
       allow(resolver).to receive(:getresources).with('example.com', Resolv::DNS::Resource::IN::MX).and_return([double(exchange: 'mail.example.com')])
@@ -96,8 +100,8 @@ describe EmailMxValidator do
       expect(user.errors).to have_received(:add)
     end
 
-    it 'adds an error if the MX IPv6 record is blacklisted' do
-      EmailDomainBlock.create!(domain: 'fd00::2')
+    it 'adds an error if the AAAA record of the MX record is blacklisted' do
+      EmailDomainBlock.create!(domain: 'mail.other-domain.com', ips: ['fd00::2'])
       resolver = double
 
       allow(resolver).to receive(:getresources).with('example.com', Resolv::DNS::Resource::IN::MX).and_return([double(exchange: 'mail.example.com')])
@@ -112,7 +116,7 @@ describe EmailMxValidator do
       expect(user.errors).to have_received(:add)
     end
 
-    it 'adds an error if the MX hostname is blacklisted' do
+    it 'adds an error if the MX record is blacklisted' do
       EmailDomainBlock.create!(domain: 'mail.example.com')
       resolver = double
 
diff --git a/spec/views/about/show.html.haml_spec.rb b/spec/views/about/show.html.haml_spec.rb
index d608bbf5d..140f3fd41 100644
--- a/spec/views/about/show.html.haml_spec.rb
+++ b/spec/views/about/show.html.haml_spec.rb
@@ -10,6 +10,7 @@ describe 'about/show.html.haml', without_verify_partial_doubles: true do
     allow(view).to receive(:site_title).and_return('example site')
     allow(view).to receive(:new_user).and_return(User.new)
     allow(view).to receive(:use_seamless_external_login?).and_return(false)
+    allow(view).to receive(:current_account).and_return(nil)
   end
 
   it 'has valid open graph tags' do