about summary refs log tree commit diff
path: root/spec
diff options
context:
space:
mode:
Diffstat (limited to 'spec')
-rw-r--r--spec/controllers/api/v1/admin/trends/links/preview_card_providers_controller_spec.rb68
-rw-r--r--spec/controllers/api/v1/admin/trends/links_controller_spec.rb49
-rw-r--r--spec/controllers/api/v1/admin/trends/statuses_controller_spec.rb49
-rw-r--r--spec/controllers/api/v1/admin/trends/tags_controller_spec.rb49
-rw-r--r--spec/controllers/settings/aliases_controller_spec.rb46
-rw-r--r--spec/controllers/settings/featured_tags_controller_spec.rb37
-rw-r--r--spec/controllers/settings/migration/redirects_controller_spec.rb45
-rw-r--r--spec/controllers/settings/pictures_controller_spec.rb30
-rw-r--r--spec/controllers/settings/preferences/appearance_controller_spec.rb9
-rw-r--r--spec/controllers/settings/two_factor_authentication_methods_controller_spec.rb49
-rw-r--r--spec/fabricators/featured_tag_fabricator.rb7
-rw-r--r--spec/generators/post_deployment_migration_generator_spec.rb27
-rw-r--r--spec/mailers/notification_mailer_spec.rb10
-rw-r--r--spec/models/account_filter_spec.rb19
-rw-r--r--spec/services/reblog_service_spec.rb19
15 files changed, 481 insertions, 32 deletions
diff --git a/spec/controllers/api/v1/admin/trends/links/preview_card_providers_controller_spec.rb b/spec/controllers/api/v1/admin/trends/links/preview_card_providers_controller_spec.rb
new file mode 100644
index 000000000..883a55b7b
--- /dev/null
+++ b/spec/controllers/api/v1/admin/trends/links/preview_card_providers_controller_spec.rb
@@ -0,0 +1,68 @@
+# frozen_string_literal: true
+
+require 'rails_helper'
+
+describe Api::V1::Admin::Trends::Links::PreviewCardProvidersController do
+  render_views
+
+  let(:role)   { UserRole.find_by(name: 'Admin') }
+  let(:user)   { Fabricate(:user, role: role) }
+  let(:scopes) { 'admin:read admin:write' }
+  let(:token)   { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) }
+  let(:account) { Fabricate(:account) }
+  let(:preview_card_provider) { Fabricate(:preview_card_provider) }
+
+  before do
+    allow(controller).to receive(:doorkeeper_token) { token }
+  end
+
+  shared_examples 'forbidden for wrong scope' do |wrong_scope|
+    let(:scopes) { wrong_scope }
+
+    it 'returns http forbidden' do
+      expect(response).to have_http_status(403)
+    end
+  end
+
+  shared_examples 'forbidden for wrong role' do |wrong_role|
+    let(:role) { UserRole.find_by(name: wrong_role) }
+
+    it 'returns http forbidden' do
+      expect(response).to have_http_status(403)
+    end
+  end
+
+  describe 'GET #index' do
+    it 'returns http success' do
+      get :index, params: { account_id: account.id, limit: 2 }
+
+      expect(response).to have_http_status(200)
+    end
+  end
+
+  describe 'POST #approve' do
+    before do
+      post :approve, params: { id: preview_card_provider.id }
+    end
+
+    it_behaves_like 'forbidden for wrong scope', 'write:statuses'
+    it_behaves_like 'forbidden for wrong role', ''
+
+    it 'returns http success' do
+      expect(response).to have_http_status(200)
+    end
+  end
+
+  describe 'POST #reject' do
+    before do
+      post :reject, params: { id: preview_card_provider.id }
+    end
+
+    it_behaves_like 'forbidden for wrong scope', 'write:statuses'
+    it_behaves_like 'forbidden for wrong role', ''
+
+    it 'returns http success' do
+      expect(response).to have_http_status(200)
+    end
+  end
+end
diff --git a/spec/controllers/api/v1/admin/trends/links_controller_spec.rb b/spec/controllers/api/v1/admin/trends/links_controller_spec.rb
index a64292f06..9c144d3fa 100644
--- a/spec/controllers/api/v1/admin/trends/links_controller_spec.rb
+++ b/spec/controllers/api/v1/admin/trends/links_controller_spec.rb
@@ -5,14 +5,33 @@ require 'rails_helper'
 describe Api::V1::Admin::Trends::LinksController do
   render_views
 
-  let(:user)    { Fabricate(:user, role: UserRole.find_by(name: 'Admin')) }
-  let(:token)   { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: 'admin:read') }
+  let(:role)   { UserRole.find_by(name: 'Admin') }
+  let(:user)   { Fabricate(:user, role: role) }
+  let(:scopes) { 'admin:read admin:write' }
+  let(:token)   { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) }
   let(:account) { Fabricate(:account) }
+  let(:preview_card) { Fabricate(:preview_card) }
 
   before do
     allow(controller).to receive(:doorkeeper_token) { token }
   end
 
+  shared_examples 'forbidden for wrong scope' do |wrong_scope|
+    let(:scopes) { wrong_scope }
+
+    it 'returns http forbidden' do
+      expect(response).to have_http_status(403)
+    end
+  end
+
+  shared_examples 'forbidden for wrong role' do |wrong_role|
+    let(:role) { UserRole.find_by(name: wrong_role) }
+
+    it 'returns http forbidden' do
+      expect(response).to have_http_status(403)
+    end
+  end
+
   describe 'GET #index' do
     it 'returns http success' do
       get :index, params: { account_id: account.id, limit: 2 }
@@ -20,4 +39,30 @@ describe Api::V1::Admin::Trends::LinksController do
       expect(response).to have_http_status(200)
     end
   end
+
+  describe 'POST #approve' do
+    before do
+      post :approve, params: { id: preview_card.id }
+    end
+
+    it_behaves_like 'forbidden for wrong scope', 'write:statuses'
+    it_behaves_like 'forbidden for wrong role', ''
+
+    it 'returns http success' do
+      expect(response).to have_http_status(200)
+    end
+  end
+
+  describe 'POST #reject' do
+    before do
+      post :reject, params: { id: preview_card.id }
+    end
+
+    it_behaves_like 'forbidden for wrong scope', 'write:statuses'
+    it_behaves_like 'forbidden for wrong role', ''
+
+    it 'returns http success' do
+      expect(response).to have_http_status(200)
+    end
+  end
 end
diff --git a/spec/controllers/api/v1/admin/trends/statuses_controller_spec.rb b/spec/controllers/api/v1/admin/trends/statuses_controller_spec.rb
index 821cc499f..d25186b37 100644
--- a/spec/controllers/api/v1/admin/trends/statuses_controller_spec.rb
+++ b/spec/controllers/api/v1/admin/trends/statuses_controller_spec.rb
@@ -5,14 +5,33 @@ require 'rails_helper'
 describe Api::V1::Admin::Trends::StatusesController do
   render_views
 
-  let(:user)    { Fabricate(:user, role: UserRole.find_by(name: 'Admin')) }
-  let(:token)   { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: 'admin:read') }
+  let(:role)   { UserRole.find_by(name: 'Admin') }
+  let(:user)   { Fabricate(:user, role: role) }
+  let(:scopes) { 'admin:read admin:write' }
+  let(:token)   { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) }
   let(:account) { Fabricate(:account) }
+  let(:status)  { Fabricate(:status) }
 
   before do
     allow(controller).to receive(:doorkeeper_token) { token }
   end
 
+  shared_examples 'forbidden for wrong scope' do |wrong_scope|
+    let(:scopes) { wrong_scope }
+
+    it 'returns http forbidden' do
+      expect(response).to have_http_status(403)
+    end
+  end
+
+  shared_examples 'forbidden for wrong role' do |wrong_role|
+    let(:role) { UserRole.find_by(name: wrong_role) }
+
+    it 'returns http forbidden' do
+      expect(response).to have_http_status(403)
+    end
+  end
+
   describe 'GET #index' do
     it 'returns http success' do
       get :index, params: { account_id: account.id, limit: 2 }
@@ -20,4 +39,30 @@ describe Api::V1::Admin::Trends::StatusesController do
       expect(response).to have_http_status(200)
     end
   end
+
+  describe 'POST #approve' do
+    before do
+      post :approve, params: { id: status.id }
+    end
+
+    it_behaves_like 'forbidden for wrong scope', 'write:statuses'
+    it_behaves_like 'forbidden for wrong role', ''
+
+    it 'returns http success' do
+      expect(response).to have_http_status(200)
+    end
+  end
+
+  describe 'POST #reject' do
+    before do
+      post :reject, params: { id: status.id }
+    end
+
+    it_behaves_like 'forbidden for wrong scope', 'write:statuses'
+    it_behaves_like 'forbidden for wrong role', ''
+
+    it 'returns http success' do
+      expect(response).to have_http_status(200)
+    end
+  end
 end
diff --git a/spec/controllers/api/v1/admin/trends/tags_controller_spec.rb b/spec/controllers/api/v1/admin/trends/tags_controller_spec.rb
index 480306ce7..5ee443d57 100644
--- a/spec/controllers/api/v1/admin/trends/tags_controller_spec.rb
+++ b/spec/controllers/api/v1/admin/trends/tags_controller_spec.rb
@@ -5,14 +5,33 @@ require 'rails_helper'
 describe Api::V1::Admin::Trends::TagsController do
   render_views
 
-  let(:user)    { Fabricate(:user, role: UserRole.find_by(name: 'Admin')) }
-  let(:token)   { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: 'admin:read') }
+  let(:role)   { UserRole.find_by(name: 'Admin') }
+  let(:user)   { Fabricate(:user, role: role) }
+  let(:scopes) { 'admin:read admin:write' }
+  let(:token)   { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) }
   let(:account) { Fabricate(:account) }
+  let(:tag)     { Fabricate(:tag) }
 
   before do
     allow(controller).to receive(:doorkeeper_token) { token }
   end
 
+  shared_examples 'forbidden for wrong scope' do |wrong_scope|
+    let(:scopes) { wrong_scope }
+
+    it 'returns http forbidden' do
+      expect(response).to have_http_status(403)
+    end
+  end
+
+  shared_examples 'forbidden for wrong role' do |wrong_role|
+    let(:role) { UserRole.find_by(name: wrong_role) }
+
+    it 'returns http forbidden' do
+      expect(response).to have_http_status(403)
+    end
+  end
+
   describe 'GET #index' do
     it 'returns http success' do
       get :index, params: { account_id: account.id, limit: 2 }
@@ -20,4 +39,30 @@ describe Api::V1::Admin::Trends::TagsController do
       expect(response).to have_http_status(200)
     end
   end
+
+  describe 'POST #approve' do
+    before do
+      post :approve, params: { id: tag.id }
+    end
+
+    it_behaves_like 'forbidden for wrong scope', 'write:statuses'
+    it_behaves_like 'forbidden for wrong role', ''
+
+    it 'returns http success' do
+      expect(response).to have_http_status(200)
+    end
+  end
+
+  describe 'POST #reject' do
+    before do
+      post :reject, params: { id: tag.id }
+    end
+
+    it_behaves_like 'forbidden for wrong scope', 'write:statuses'
+    it_behaves_like 'forbidden for wrong role', ''
+
+    it 'returns http success' do
+      expect(response).to have_http_status(200)
+    end
+  end
 end
diff --git a/spec/controllers/settings/aliases_controller_spec.rb b/spec/controllers/settings/aliases_controller_spec.rb
index 805f65988..ef8724faf 100644
--- a/spec/controllers/settings/aliases_controller_spec.rb
+++ b/spec/controllers/settings/aliases_controller_spec.rb
@@ -18,4 +18,50 @@ describe Settings::AliasesController do
       expect(response).to have_http_status(200)
     end
   end
+
+  describe 'POST #create' do
+    context 'with valid alias' do
+      before { stub_resolver }
+
+      it 'creates an alias for the user' do
+        expect do
+          post :create, params: { account_alias: { acct: 'new@example.com' } }
+        end.to change(AccountAlias, :count).by(1)
+
+        expect(response).to redirect_to(settings_aliases_path)
+      end
+    end
+
+    context 'with invalid alias' do
+      it 'does not create an alias for the user' do
+        expect do
+          post :create, params: { account_alias: { acct: 'format-wrong' } }
+        end.to_not change(AccountAlias, :count)
+
+        expect(response).to have_http_status(200)
+      end
+    end
+  end
+
+  describe 'DELETE #destroy' do
+    let(:account_alias) do
+      AccountAlias.new(account: user.account, acct: 'new@example.com').tap do |account_alias|
+        account_alias.save(validate: false)
+      end
+    end
+
+    it 'removes an alias' do
+      delete :destroy, params: { id: account_alias.id }
+
+      expect(response).to redirect_to(settings_aliases_path)
+      expect { account_alias.reload }.to raise_error(ActiveRecord::RecordNotFound)
+    end
+  end
+
+  private
+
+  def stub_resolver
+    resolver = instance_double(ResolveAccountService, call: Fabricate(:account))
+    allow(ResolveAccountService).to receive(:new).and_return(resolver)
+  end
 end
diff --git a/spec/controllers/settings/featured_tags_controller_spec.rb b/spec/controllers/settings/featured_tags_controller_spec.rb
index 5c61351af..fc25e7aa8 100644
--- a/spec/controllers/settings/featured_tags_controller_spec.rb
+++ b/spec/controllers/settings/featured_tags_controller_spec.rb
@@ -11,19 +11,19 @@ describe Settings::FeaturedTagsController do
     end
   end
 
-  describe 'POST #create' do
-    context 'when user is not sign in' do
-      subject { post :create }
+  context 'when user is not signed in' do
+    subject { post :create }
 
-      it_behaves_like 'authenticate user'
-    end
+    it_behaves_like 'authenticate user'
+  end
 
-    context 'when user is sign in' do
-      subject { post :create, params: { featured_tag: params } }
+  context 'when user is signed in' do
+    let(:user) { Fabricate(:user, password: '12345678') }
 
-      let(:user) { Fabricate(:user, password: '12345678') }
+    before { sign_in user, scope: :user }
 
-      before { sign_in user, scope: :user }
+    describe 'POST #create' do
+      subject { post :create, params: { featured_tag: params } }
 
       context 'when parameter is valid' do
         let(:params) { { name: 'test' } }
@@ -41,5 +41,24 @@ describe Settings::FeaturedTagsController do
         end
       end
     end
+
+    describe 'GET to #index' do
+      it 'responds with success' do
+        get :index
+
+        expect(response).to have_http_status(200)
+      end
+    end
+
+    describe 'DELETE to #destroy' do
+      let(:featured_tag) { Fabricate(:featured_tag, account: user.account) }
+
+      it 'removes the featured tag' do
+        delete :destroy, params: { id: featured_tag.id }
+
+        expect(response).to redirect_to(settings_featured_tags_path)
+        expect { featured_tag.reload }.to raise_error(ActiveRecord::RecordNotFound)
+      end
+    end
   end
 end
diff --git a/spec/controllers/settings/migration/redirects_controller_spec.rb b/spec/controllers/settings/migration/redirects_controller_spec.rb
index 50d9e1927..54897bb7f 100644
--- a/spec/controllers/settings/migration/redirects_controller_spec.rb
+++ b/spec/controllers/settings/migration/redirects_controller_spec.rb
@@ -5,7 +5,7 @@ require 'rails_helper'
 describe Settings::Migration::RedirectsController do
   render_views
 
-  let!(:user) { Fabricate(:user) }
+  let!(:user) { Fabricate(:user, password: 'testtest') }
 
   before do
     sign_in user, scope: :user
@@ -17,4 +17,47 @@ describe Settings::Migration::RedirectsController do
       expect(response).to have_http_status(200)
     end
   end
+
+  describe 'POST #create' do
+    context 'with valid params' do
+      before { stub_resolver }
+
+      it 'redirects to the settings migration path' do
+        post :create, params: { form_redirect: { acct: 'new@host.com', current_password: 'testtest' } }
+
+        expect(response).to redirect_to(settings_migration_path)
+      end
+    end
+
+    context 'with non valid params' do
+      it 'returns success and renders the new page' do
+        post :create, params: { form_redirect: { acct: '' } }
+
+        expect(response).to have_http_status(200)
+        expect(response).to render_template(:new)
+      end
+    end
+  end
+
+  describe 'DELETE #destroy' do
+    let(:account) { Fabricate(:account) }
+
+    before do
+      user.account.update(moved_to_account_id: account.id)
+    end
+
+    it 'resets the account and sends an update' do
+      delete :destroy
+
+      expect(response).to redirect_to(settings_migration_path)
+      expect(user.account.reload.moved_to_account).to be_nil
+    end
+  end
+
+  private
+
+  def stub_resolver
+    resolver = instance_double(ResolveAccountService, call: Fabricate(:account))
+    allow(ResolveAccountService).to receive(:new).and_return(resolver)
+  end
 end
diff --git a/spec/controllers/settings/pictures_controller_spec.rb b/spec/controllers/settings/pictures_controller_spec.rb
index 2368dc55d..705878f03 100644
--- a/spec/controllers/settings/pictures_controller_spec.rb
+++ b/spec/controllers/settings/pictures_controller_spec.rb
@@ -18,5 +18,35 @@ describe Settings::PicturesController do
         expect(response).to have_http_status(400)
       end
     end
+
+    context 'with valid picture id' do
+      context 'when account updates correctly' do
+        let(:service) { instance_double(UpdateAccountService, call: true) }
+
+        before do
+          allow(UpdateAccountService).to receive(:new).and_return(service)
+        end
+
+        it 'updates the account' do
+          delete :destroy, params: { id: 'avatar' }
+          expect(response).to redirect_to(settings_profile_path)
+          expect(response).to have_http_status(303)
+          expect(service).to have_received(:call).with(user.account, { 'avatar' => nil, 'avatar_remote_url' => '' })
+        end
+      end
+
+      context 'when account cannot update' do
+        let(:service) { instance_double(UpdateAccountService, call: false) }
+
+        before do
+          allow(UpdateAccountService).to receive(:new).and_return(service)
+        end
+
+        it 'redirects to profile' do
+          delete :destroy, params: { id: 'avatar' }
+          expect(response).to redirect_to(settings_profile_path)
+        end
+      end
+    end
   end
 end
diff --git a/spec/controllers/settings/preferences/appearance_controller_spec.rb b/spec/controllers/settings/preferences/appearance_controller_spec.rb
index 7c7f716b7..df0237a6b 100644
--- a/spec/controllers/settings/preferences/appearance_controller_spec.rb
+++ b/spec/controllers/settings/preferences/appearance_controller_spec.rb
@@ -14,7 +14,16 @@ describe Settings::Preferences::AppearanceController do
   describe 'GET #show' do
     it 'returns http success' do
       get :show
+
       expect(response).to have_http_status(200)
     end
   end
+
+  describe 'PUT #update' do
+    it 'redirects correctly' do
+      put :update, params: { user: { setting_theme: 'contrast' } }
+
+      expect(response).to redirect_to(settings_preferences_appearance_path)
+    end
+  end
 end
diff --git a/spec/controllers/settings/two_factor_authentication_methods_controller_spec.rb b/spec/controllers/settings/two_factor_authentication_methods_controller_spec.rb
index 66ffe89f3..153eca1a5 100644
--- a/spec/controllers/settings/two_factor_authentication_methods_controller_spec.rb
+++ b/spec/controllers/settings/two_factor_authentication_methods_controller_spec.rb
@@ -5,14 +5,24 @@ require 'rails_helper'
 describe Settings::TwoFactorAuthenticationMethodsController do
   render_views
 
-  let(:user) { Fabricate(:user) }
+  context 'when not signed in' do
+    describe 'GET to #index' do
+      it 'redirects' do
+        get :index
 
-  describe 'GET #index' do
-    context 'when signed in' do
-      before do
-        sign_in user, scope: :user
+        expect(response).to redirect_to '/auth/sign_in'
       end
+    end
+  end
+
+  context 'when signed in' do
+    let(:user) { Fabricate(:user) }
 
+    before do
+      sign_in user, scope: :user
+    end
+
+    describe 'GET #index' do
       describe 'when user has enabled otp' do
         before do
           user.update(otp_required_for_login: true)
@@ -38,11 +48,32 @@ describe Settings::TwoFactorAuthenticationMethodsController do
       end
     end
 
-    context 'when not signed in' do
-      it 'redirects' do
-        get :index
+    describe 'POST to #disable' do
+      before do
+        user.update(otp_required_for_login: true)
+      end
 
-        expect(response).to redirect_to '/auth/sign_in'
+      context 'when user has not passed challenge' do
+        it 'renders challenge page' do
+          post :disable
+
+          expect(response).to have_http_status(200)
+          expect(response).to render_template('auth/challenges/new')
+        end
+      end
+
+      context 'when user has passed challenge' do
+        before do
+          mailer = instance_double(ApplicationMailer::MessageDelivery, deliver_later!: true)
+          allow(UserMailer).to receive(:two_factor_disabled).with(user).and_return(mailer)
+        end
+
+        it 'redirects to settings page' do
+          post :disable, session: { challenge_passed_at: 10.minutes.ago }
+
+          expect(UserMailer).to have_received(:two_factor_disabled).with(user)
+          expect(response).to redirect_to(settings_otp_authentication_path)
+        end
       end
     end
   end
diff --git a/spec/fabricators/featured_tag_fabricator.rb b/spec/fabricators/featured_tag_fabricator.rb
new file mode 100644
index 000000000..747d8e36a
--- /dev/null
+++ b/spec/fabricators/featured_tag_fabricator.rb
@@ -0,0 +1,7 @@
+# frozen_string_literal: true
+
+Fabricator(:featured_tag) do
+  account
+  tag
+  name 'Tag'
+end
diff --git a/spec/generators/post_deployment_migration_generator_spec.rb b/spec/generators/post_deployment_migration_generator_spec.rb
new file mode 100644
index 000000000..d552880e3
--- /dev/null
+++ b/spec/generators/post_deployment_migration_generator_spec.rb
@@ -0,0 +1,27 @@
+# frozen_string_literal: true
+
+require 'rails_helper'
+require 'rails/generators/testing/behaviour'
+require 'rails/generators/testing/assertions'
+
+require 'generators/post_deployment_migration/post_deployment_migration_generator'
+
+describe PostDeploymentMigrationGenerator, type: :generator do
+  include Rails::Generators::Testing::Behaviour
+  include Rails::Generators::Testing::Assertions
+  include FileUtils
+
+  tests described_class
+  destination File.expand_path('../../tmp', __dir__)
+  before { prepare_destination }
+  after { rm_rf(destination_root) }
+
+  describe 'the migration' do
+    it 'generates expected file' do
+      run_generator %w(Changes)
+
+      assert_migration('db/post_migrate/changes.rb', /disable_ddl/)
+      assert_migration('db/post_migrate/changes.rb', /change/)
+    end
+  end
+end
diff --git a/spec/mailers/notification_mailer_spec.rb b/spec/mailers/notification_mailer_spec.rb
index a6db08d85..341fe6f23 100644
--- a/spec/mailers/notification_mailer_spec.rb
+++ b/spec/mailers/notification_mailer_spec.rb
@@ -29,7 +29,7 @@ RSpec.describe NotificationMailer, type: :mailer do
 
     it 'renders the headers' do
       expect(mail.subject).to eq('You were mentioned by bob')
-      expect(mail.to).to eq([receiver.email])
+      expect(mail[:to].value).to eq("#{receiver.account.username} <#{receiver.email}>")
     end
 
     it 'renders the body' do
@@ -46,7 +46,7 @@ RSpec.describe NotificationMailer, type: :mailer do
 
     it 'renders the headers' do
       expect(mail.subject).to eq('bob is now following you')
-      expect(mail.to).to eq([receiver.email])
+      expect(mail[:to].value).to eq("#{receiver.account.username} <#{receiver.email}>")
     end
 
     it 'renders the body' do
@@ -62,7 +62,7 @@ RSpec.describe NotificationMailer, type: :mailer do
 
     it 'renders the headers' do
       expect(mail.subject).to eq('bob favourited your post')
-      expect(mail.to).to eq([receiver.email])
+      expect(mail[:to].value).to eq("#{receiver.account.username} <#{receiver.email}>")
     end
 
     it 'renders the body' do
@@ -79,7 +79,7 @@ RSpec.describe NotificationMailer, type: :mailer do
 
     it 'renders the headers' do
       expect(mail.subject).to eq('bob boosted your post')
-      expect(mail.to).to eq([receiver.email])
+      expect(mail[:to].value).to eq("#{receiver.account.username} <#{receiver.email}>")
     end
 
     it 'renders the body' do
@@ -96,7 +96,7 @@ RSpec.describe NotificationMailer, type: :mailer do
 
     it 'renders the headers' do
       expect(mail.subject).to eq('Pending follower: bob')
-      expect(mail.to).to eq([receiver.email])
+      expect(mail[:to].value).to eq("#{receiver.account.username} <#{receiver.email}>")
     end
 
     it 'renders the body' do
diff --git a/spec/models/account_filter_spec.rb b/spec/models/account_filter_spec.rb
index 3032260fe..cb00e7609 100644
--- a/spec/models/account_filter_spec.rb
+++ b/spec/models/account_filter_spec.rb
@@ -44,4 +44,23 @@ describe AccountFilter do
       expect(filter.results).to match_array [remote_account_one]
     end
   end
+
+  describe 'with username' do
+    let!(:local_account) { Fabricate(:account, domain: nil, username: 'validUserName') }
+
+    it 'works with @ at the beginning of the username' do
+      filter = described_class.new(username: '@validUserName')
+      expect(filter.results).to match_array [local_account]
+    end
+
+    it 'does not work with more than one @ at the beginning of the username' do
+      filter = described_class.new(username: '@@validUserName')
+      expect(filter.results).to_not match_array [local_account]
+    end
+
+    it 'does not work with @ outside the beginning of the username' do
+      filter = described_class.new(username: 'validUserName@')
+      expect(filter.results).to_not match_array [local_account]
+    end
+  end
 end
diff --git a/spec/services/reblog_service_spec.rb b/spec/services/reblog_service_spec.rb
index c00472229..2ad6d30f6 100644
--- a/spec/services/reblog_service_spec.rb
+++ b/spec/services/reblog_service_spec.rb
@@ -35,10 +35,25 @@ RSpec.describe ReblogService, type: :service do
   end
 
   context 'when the reblogged status is discarded in the meantime' do
-    let(:status) { Fabricate(:status, account: alice, visibility: :public) }
+    let(:status) { Fabricate(:status, account: alice, visibility: :public, text: 'discard-status-text') }
 
+    # Add a callback to discard the status being reblogged after the
+    # validations pass but before the database commit is executed.
     before do
-      status.discard
+      Status.class_eval do
+        before_save :discard_status
+        def discard_status
+          Status
+            .where(id: reblog_of_id)
+            .where(text: 'discard-status-text')
+            .update_all(deleted_at: Time.now.utc) # rubocop:disable Rails/SkipsModelValidations
+        end
+      end
+    end
+
+    # Remove race condition simulating `discard_status` callback.
+    after do
+      Status._save_callbacks.delete(:discard_status)
     end
 
     it 'raises an exception' do