about summary refs log tree commit diff
path: root/spec
diff options
context:
space:
mode:
Diffstat (limited to 'spec')
-rw-r--r--spec/controllers/account_follow_controller_spec.rb2
-rw-r--r--spec/controllers/admin/reports_controller_spec.rb20
-rw-r--r--spec/controllers/api/v1/statuses_controller_spec.rb46
-rw-r--r--spec/features/profile_spec.rb2
-rw-r--r--spec/helpers/admin/action_log_helper_spec.rb238
-rw-r--r--spec/lib/sanitize_config_spec.rb17
-rw-r--r--spec/rails_helper.rb2
-rw-r--r--spec/services/import_service_spec.rb8
-rw-r--r--spec/services/post_status_service_spec.rb7
9 files changed, 88 insertions, 254 deletions
diff --git a/spec/controllers/account_follow_controller_spec.rb b/spec/controllers/account_follow_controller_spec.rb
index ac15499be..9a93e1ebe 100644
--- a/spec/controllers/account_follow_controller_spec.rb
+++ b/spec/controllers/account_follow_controller_spec.rb
@@ -25,7 +25,7 @@ describe AccountFollowController do
       sign_in(user)
       subject
 
-      expect(service).to have_received(:call).with(user.account, 'alice')
+      expect(service).to have_received(:call).with(user.account, alice, with_rate_limit: true)
       expect(response).to redirect_to(account_path(alice))
     end
   end
diff --git a/spec/controllers/admin/reports_controller_spec.rb b/spec/controllers/admin/reports_controller_spec.rb
index b428299ee..49d3e9707 100644
--- a/spec/controllers/admin/reports_controller_spec.rb
+++ b/spec/controllers/admin/reports_controller_spec.rb
@@ -46,6 +46,26 @@ describe Admin::ReportsController do
     end
   end
 
+  describe 'POST #resolve' do
+    it 'resolves the report' do
+      report = Fabricate(:report)
+
+      put :resolve, params: { id: report }
+      expect(response).to redirect_to(admin_reports_path)
+      report.reload
+      expect(report.action_taken_by_account).to eq user.account
+      expect(report.action_taken).to eq true
+    end
+
+    it 'sets trust level when the report is an antispam one' do
+      report = Fabricate(:report, account: Account.representative)
+
+      put :resolve, params: { id: report }
+      report.reload
+      expect(report.target_account.trust_level).to eq Account::TRUST_LEVELS[:trusted]
+    end
+  end
+
   describe 'POST #reopen' do
     it 'reopens the report' do
       report = Fabricate(:report)
diff --git a/spec/controllers/api/v1/statuses_controller_spec.rb b/spec/controllers/api/v1/statuses_controller_spec.rb
index 9ff5fcd3b..df8037038 100644
--- a/spec/controllers/api/v1/statuses_controller_spec.rb
+++ b/spec/controllers/api/v1/statuses_controller_spec.rb
@@ -39,12 +39,50 @@ RSpec.describe Api::V1::StatusesController, type: :controller do
     describe 'POST #create' do
       let(:scopes) { 'write:statuses' }
 
-      before do
-        post :create, params: { status: 'Hello world' }
+      context do
+        before do
+          post :create, params: { status: 'Hello world' }
+        end
+
+        it 'returns http success' do
+          expect(response).to have_http_status(200)
+        end
+
+        it 'returns rate limit headers' do
+          expect(response.headers['X-RateLimit-Limit']).to eq RateLimiter::FAMILIES[:statuses][:limit].to_s
+          expect(response.headers['X-RateLimit-Remaining']).to eq (RateLimiter::FAMILIES[:statuses][:limit] - 1).to_s
+        end
       end
 
-      it 'returns http success' do
-        expect(response).to have_http_status(200)
+      context 'with missing parameters' do
+        before do
+          post :create, params: {}
+        end
+
+        it 'returns http unprocessable entity' do
+          expect(response).to have_http_status(422)
+        end
+
+        it 'returns rate limit headers' do
+          expect(response.headers['X-RateLimit-Limit']).to eq RateLimiter::FAMILIES[:statuses][:limit].to_s
+        end
+      end
+
+      context 'when exceeding rate limit' do
+        before do
+          rate_limiter = RateLimiter.new(user.account, family: :statuses)
+          300.times { rate_limiter.record! }
+          post :create, params: { status: 'Hello world' }
+        end
+
+        it 'returns http too many requests' do
+          expect(response).to have_http_status(429)
+        end
+
+        it 'returns rate limit headers' do
+          expect(response.headers['X-RateLimit-Limit']).to eq RateLimiter::FAMILIES[:statuses][:limit].to_s
+          expect(response.headers['X-RateLimit-Remaining']).to eq '0'
+        end
       end
     end
 
diff --git a/spec/features/profile_spec.rb b/spec/features/profile_spec.rb
index 3202167ca..b6de3e9d1 100644
--- a/spec/features/profile_spec.rb
+++ b/spec/features/profile_spec.rb
@@ -39,7 +39,7 @@ feature 'Profile' do
     visit settings_profile_path
     fill_in 'Display name', with: 'Bob'
     fill_in 'Bio', with: 'Bob is silent'
-    click_on 'Save changes'
+    first('.btn[type=submit]').click
     is_expected.to have_content 'Changes successfully saved!'
 
     # View my own public profile and see the changes
diff --git a/spec/helpers/admin/action_log_helper_spec.rb b/spec/helpers/admin/action_log_helper_spec.rb
index d7af6b939..60f5ecdcc 100644
--- a/spec/helpers/admin/action_log_helper_spec.rb
+++ b/spec/helpers/admin/action_log_helper_spec.rb
@@ -31,242 +31,4 @@ RSpec.describe Admin::ActionLogsHelper, type: :helper do
       end
     end
   end
-
-  describe '#relevant_log_changes' do
-    let(:log) { double(target_type: target_type, action: log_action, recorded_changes: recorded_changes) }
-    let(:recorded_changes) { double }
-
-    after do
-      hoge.relevant_log_changes(log)
-    end
-
-    context "log.target_type == 'CustomEmoji' && [:enable, :disable, :destroy].include?(log.action)" do
-      let(:target_type) { 'CustomEmoji' }
-      let(:log_action)  { :enable }
-
-      it "calls log.recorded_changes.slice('domain')" do
-        expect(recorded_changes).to receive(:slice).with('domain')
-      end
-    end
-
-    context "log.target_type == 'CustomEmoji' && log.action == :update" do
-      let(:target_type) { 'CustomEmoji' }
-      let(:log_action)  { :update }
-
-      it "calls log.recorded_changes.slice('domain', 'visible_in_picker')" do
-        expect(recorded_changes).to receive(:slice).with('domain', 'visible_in_picker')
-      end
-    end
-
-    context "log.target_type == 'User' && [:promote, :demote].include?(log.action)" do
-      let(:target_type) { 'User' }
-      let(:log_action)  { :promote }
-
-      it "calls log.recorded_changes.slice('moderator', 'admin')" do
-        expect(recorded_changes).to receive(:slice).with('moderator', 'admin')
-      end
-    end
-
-    context "log.target_type == 'User' && [:change_email].include?(log.action)" do
-      let(:target_type) { 'User' }
-      let(:log_action)  { :change_email }
-
-      it "calls log.recorded_changes.slice('email', 'unconfirmed_email')" do
-        expect(recorded_changes).to receive(:slice).with('email', 'unconfirmed_email')
-      end
-    end
-
-    context "log.target_type == 'DomainBlock'" do
-      let(:target_type) { 'DomainBlock' }
-      let(:log_action)  { nil }
-
-      it "calls log.recorded_changes.slice('severity', 'reject_media')" do
-        expect(recorded_changes).to receive(:slice).with('severity', 'reject_media')
-      end
-    end
-
-    context "log.target_type == 'Status' && log.action == :update" do
-      let(:target_type) { 'Status' }
-      let(:log_action)  { :update }
-
-      it "log.recorded_changes.slice('sensitive')" do
-        expect(recorded_changes).to receive(:slice).with('sensitive')
-      end
-    end
-  end
-
-  describe '#log_extra_attributes' do
-    after do
-      hoge.log_extra_attributes(hoge: 'hoge')
-    end
-
-    it "calls content_tag(:span, key, class: 'diff-key')" do
-      allow(hoge).to receive(:log_change).with(anything)
-      expect(hoge).to receive(:content_tag).with(:span, :hoge, class: 'diff-key')
-    end
-
-    it 'calls safe_join twice' do
-      expect(hoge).to receive(:safe_join).with(
-        ['<span class="diff-key">hoge</span>',
-         '=',
-         '<span class="diff-neutral">hoge</span>']
-      )
-
-      expect(hoge).to receive(:safe_join).with([nil], ' ')
-    end
-  end
-
-  describe '#log_change' do
-    after do
-      hoge.log_change(val)
-    end
-
-    context '!val.is_a?(Array)' do
-      let(:val) { 'hoge' }
-
-      it "calls content_tag(:span, val, class: 'diff-neutral')" do
-        expect(hoge).to receive(:content_tag).with(:span, val, class: 'diff-neutral')
-      end
-    end
-
-    context 'val.is_a?(Array)' do
-      let(:val) { %w(foo bar) }
-
-      it 'calls #content_tag twice and #safe_join' do
-        expect(hoge).to receive(:content_tag).with(:span, 'foo', class: 'diff-old')
-        expect(hoge).to receive(:content_tag).with(:span, 'bar', class: 'diff-new')
-        expect(hoge).to receive(:safe_join).with([nil, nil], '→')
-      end
-    end
-  end
-
-  describe '#icon_for_log' do
-    subject   { hoge.icon_for_log(log) }
-
-    context "log.target_type == 'Account'" do
-      let(:log) { double(target_type: 'Account') }
-
-      it 'returns "user"' do
-        expect(subject).to be 'user'
-      end
-    end
-
-    context "log.target_type == 'User'" do
-      let(:log) { double(target_type: 'User') }
-
-      it 'returns "user"' do
-        expect(subject).to be 'user'
-      end
-    end
-
-    context "log.target_type == 'CustomEmoji'" do
-      let(:log) { double(target_type: 'CustomEmoji') }
-
-      it 'returns "file"' do
-        expect(subject).to be 'file'
-      end
-    end
-
-    context "log.target_type == 'Report'" do
-      let(:log) { double(target_type: 'Report') }
-
-      it 'returns "flag"' do
-        expect(subject).to be 'flag'
-      end
-    end
-
-    context "log.target_type == 'DomainBlock'" do
-      let(:log) { double(target_type: 'DomainBlock') }
-
-      it 'returns "lock"' do
-        expect(subject).to be 'lock'
-      end
-    end
-
-    context "log.target_type == 'EmailDomainBlock'" do
-      let(:log) { double(target_type: 'EmailDomainBlock') }
-
-      it 'returns "envelope"' do
-        expect(subject).to be 'envelope'
-      end
-    end
-
-    context "log.target_type == 'Status'" do
-      let(:log) { double(target_type: 'Status') }
-
-      it 'returns "pencil"' do
-        expect(subject).to be 'pencil'
-      end
-    end
-  end
-
-  describe '#class_for_log_icon' do
-    subject   { hoge.class_for_log_icon(log) }
-
-    %i(enable unsuspend unsilence confirm promote resolve).each do |action|
-      context "log.action == #{action}" do
-        let(:log) { double(action: action) }
-
-        it 'returns "positive"' do
-          expect(subject).to be 'positive'
-        end
-      end
-    end
-
-    context 'log.action == :create' do
-      context 'opposite_verbs?(log)' do
-        let(:log) { double(action: :create, target_type: 'DomainBlock') }
-
-        it 'returns "negative"' do
-          expect(subject).to be 'negative'
-        end
-      end
-
-      context '!opposite_verbs?(log)' do
-        let(:log) { double(action: :create, target_type: '') }
-
-        it 'returns "positive"' do
-          expect(subject).to be 'positive'
-        end
-      end
-    end
-
-    %i(update reset_password disable_2fa memorialize change_email).each do |action|
-      context "log.action == #{action}" do
-        let(:log) { double(action: action) }
-
-        it 'returns "neutral"' do
-          expect(subject).to be 'neutral'
-        end
-      end
-    end
-
-    %i(demote silence disable suspend remove_avatar remove_header reopen).each do |action|
-      context "log.action == #{action}" do
-        let(:log) { double(action: action) }
-
-        it 'returns "negative"' do
-          expect(subject).to be 'negative'
-        end
-      end
-    end
-
-    context 'log.action == :destroy' do
-      context 'opposite_verbs?(log)' do
-        let(:log) { double(action: :destroy, target_type: 'DomainBlock') }
-
-        it 'returns "positive"' do
-          expect(subject).to be 'positive'
-        end
-      end
-
-      context '!opposite_verbs?(log)' do
-        let(:log) { double(action: :destroy, target_type: '') }
-
-        it 'returns "negative"' do
-          expect(subject).to be 'negative'
-        end
-      end
-    end
-  end
 end
diff --git a/spec/lib/sanitize_config_spec.rb b/spec/lib/sanitize_config_spec.rb
index 50558a0d8..7370c536b 100644
--- a/spec/lib/sanitize_config_spec.rb
+++ b/spec/lib/sanitize_config_spec.rb
@@ -7,6 +7,12 @@ describe Sanitize::Config do
   describe '::MASTODON_STRICT' do
     subject { Sanitize::Config::MASTODON_STRICT }
 
+    around do |example|
+      original_web_domain = Rails.configuration.x.web_domain
+      example.run
+      Rails.configuration.x.web_domain = original_web_domain
+    end
+
     it 'keeps h1' do
       expect(Sanitize.fragment('<h1>Foo</h1>', subject)).to eq '<h1>Foo</h1>'
     end
@@ -28,7 +34,16 @@ describe Sanitize::Config do
     end
 
     it 'keeps a with href' do
-      expect(Sanitize.fragment('<a href="http://example.com">Test</a>', subject)).to eq '<a href="http://example.com" rel="nofollow noopener tag noreferrer" target="_blank">Test</a>'
+      expect(Sanitize.fragment('<a href="http://example.com">Test</a>', subject)).to eq '<a href="http://example.com" rel="nofollow noopener noreferrer" target="_blank">Test</a>'
+    end
+
+    it 'keeps a with href and rel tag' do
+      expect(Sanitize.fragment('<a href="http://example.com" rel="tag">Test</a>', subject)).to eq '<a href="http://example.com" rel="tag nofollow noopener noreferrer" target="_blank">Test</a>'
+    end
+
+    it 'keeps a with href and rel tag, not adding to rel if url is local' do
+      Rails.configuration.x.web_domain = 'domain.test'
+      expect(Sanitize.fragment('<a href="http://domain.test/tags/foo" rel="tag">Test</a>', subject.merge(outgoing: true))).to eq '<a href="http://domain.test/tags/foo" rel="tag" target="_blank">Test</a>'
     end
   end
 end
diff --git a/spec/rails_helper.rb b/spec/rails_helper.rb
index 6fbceca53..40ddf1f95 100644
--- a/spec/rails_helper.rb
+++ b/spec/rails_helper.rb
@@ -15,7 +15,7 @@ ActiveRecord::Migration.maintain_test_schema!
 WebMock.disable_net_connect!(allow: Chewy.settings[:host])
 Redis.current = Redis::Namespace.new("mastodon_test#{ENV['TEST_ENV_NUMBER']}", redis: Redis.current)
 Sidekiq::Testing.inline!
-Sidekiq::Logging.logger = nil
+Sidekiq.logger = nil
 
 Devise::Test::ControllerHelpers.module_eval do
   alias_method :original_sign_in, :sign_in
diff --git a/spec/services/import_service_spec.rb b/spec/services/import_service_spec.rb
index 5355133f4..7618e9076 100644
--- a/spec/services/import_service_spec.rb
+++ b/spec/services/import_service_spec.rb
@@ -91,10 +91,6 @@ RSpec.describe ImportService, type: :service do
 
     let(:csv) { attachment_fixture('mute-imports.txt') }
 
-    before do
-      allow(NotificationWorker).to receive(:perform_async)
-    end
-
     describe 'when no accounts are followed' do
       let(:import) { Import.create(account: account, type: 'following', data: csv) }
       it 'follows the listed accounts, including boosts' do
@@ -135,10 +131,6 @@ RSpec.describe ImportService, type: :service do
 
     let(:csv) { attachment_fixture('new-following-imports.txt') }
 
-    before do
-      allow(NotificationWorker).to receive(:perform_async)
-    end
-
     describe 'when no accounts are followed' do
       let(:import) { Import.create(account: account, type: 'following', data: csv) }
       it 'follows the listed accounts, respecting boosts' do
diff --git a/spec/services/post_status_service_spec.rb b/spec/services/post_status_service_spec.rb
index 025a3da40..147a59fc3 100644
--- a/spec/services/post_status_service_spec.rb
+++ b/spec/services/post_status_service_spec.rb
@@ -79,6 +79,13 @@ RSpec.describe PostStatusService, type: :service do
     expect(status.spoiler_text).to eq spoiler_text
   end
 
+  it 'creates a sensitive status when there is a CW but no text' do
+    status = subject.call(Fabricate(:account), text: '', spoiler_text: 'foo')
+
+    expect(status).to be_persisted
+    expect(status).to be_sensitive
+  end
+
   it 'creates a status with empty default spoiler text' do
     status = create_status_with_options(spoiler_text: nil)