diff options
Diffstat (limited to 'spec')
37 files changed, 1021 insertions, 132 deletions
diff --git a/spec/controllers/api/v1/accounts/credentials_controller_spec.rb b/spec/controllers/api/v1/accounts/credentials_controller_spec.rb index 461b8b34b..247420d08 100644 --- a/spec/controllers/api/v1/accounts/credentials_controller_spec.rb +++ b/spec/controllers/api/v1/accounts/credentials_controller_spec.rb @@ -51,7 +51,9 @@ describe Api::V1::Accounts::CredentialsController do describe 'with invalid data' do before do - patch :update, params: { note: 'This is too long. ' * 10 } + note = 'This is too long. ' + note = note + 'a' * (Account::MAX_NOTE_LENGTH - note.length + 1) + patch :update, params: { note: note } end it 'returns http unprocessable entity' do diff --git a/spec/controllers/api/v1/accounts/relationships_controller_spec.rb b/spec/controllers/api/v1/accounts/relationships_controller_spec.rb index 431fc2194..f25b86ac1 100644 --- a/spec/controllers/api/v1/accounts/relationships_controller_spec.rb +++ b/spec/controllers/api/v1/accounts/relationships_controller_spec.rb @@ -32,7 +32,7 @@ describe Api::V1::Accounts::RelationshipsController do json = body_as_json expect(json).to be_a Enumerable - expect(json.first[:following]).to be true + expect(json.first[:following]).to be_truthy expect(json.first[:followed_by]).to be false end end @@ -51,7 +51,7 @@ describe Api::V1::Accounts::RelationshipsController do expect(json).to be_a Enumerable expect(json.first[:id]).to eq simon.id.to_s - expect(json.first[:following]).to be true + expect(json.first[:following]).to be_truthy expect(json.first[:followed_by]).to be false expect(json.first[:muting]).to be false expect(json.first[:requested]).to be false diff --git a/spec/controllers/api/v1/accounts_controller_spec.rb b/spec/controllers/api/v1/accounts_controller_spec.rb index c770649ec..f3b879421 100644 --- a/spec/controllers/api/v1/accounts_controller_spec.rb +++ b/spec/controllers/api/v1/accounts_controller_spec.rb @@ -31,10 +31,10 @@ RSpec.describe Api::V1::AccountsController, type: :controller do expect(response).to have_http_status(:success) end - it 'returns JSON with following=true and requested=false' do + it 'returns JSON with following=truthy and requested=false' do json = body_as_json - expect(json[:following]).to be true + expect(json[:following]).to be_truthy expect(json[:requested]).to be false end @@ -50,11 +50,11 @@ RSpec.describe Api::V1::AccountsController, type: :controller do expect(response).to have_http_status(:success) end - it 'returns JSON with following=false and requested=true' do + it 'returns JSON with following=false and requested=truthy' do json = body_as_json expect(json[:following]).to be false - expect(json[:requested]).to be true + expect(json[:requested]).to be_truthy end it 'creates a follow request relation between user and target user' do @@ -137,6 +137,35 @@ RSpec.describe Api::V1::AccountsController, type: :controller do it 'creates a muting relation' do expect(user.account.muting?(other_account)).to be true end + + it 'mutes notifications' do + expect(user.account.muting_notifications?(other_account)).to be true + end + end + + describe 'POST #mute with notifications set to false' do + let(:other_account) { Fabricate(:user, email: 'bob@example.com', account: Fabricate(:account, username: 'bob')).account } + + before do + user.account.follow!(other_account) + post :mute, params: {id: other_account.id, notifications: false } + end + + it 'returns http success' do + expect(response).to have_http_status(:success) + end + + it 'does not remove the following relation between user and target user' do + expect(user.account.following?(other_account)).to be true + end + + it 'creates a muting relation' do + expect(user.account.muting?(other_account)).to be true + end + + it 'does not mute notifications' do + expect(user.account.muting_notifications?(other_account)).to be false + end end describe 'POST #unmute' do diff --git a/spec/controllers/api/v1/mutes_controller_spec.rb b/spec/controllers/api/v1/mutes_controller_spec.rb index 3e6fa887b..7387b9d2d 100644 --- a/spec/controllers/api/v1/mutes_controller_spec.rb +++ b/spec/controllers/api/v1/mutes_controller_spec.rb @@ -7,7 +7,7 @@ RSpec.describe Api::V1::MutesController, type: :controller do let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: 'follow') } before do - Fabricate(:mute, account: user.account) + Fabricate(:mute, account: user.account, hide_notifications: false) allow(controller).to receive(:doorkeeper_token) { token } end @@ -18,4 +18,24 @@ RSpec.describe Api::V1::MutesController, type: :controller do expect(response).to have_http_status(:success) end end + + describe 'GET #details' do + before do + get :details, params: { limit: 1 } + end + + let(:mutes) { JSON.parse(response.body) } + + it 'returns http success' do + expect(response).to have_http_status(:success) + end + + it 'returns one mute' do + expect(mutes.size).to be(1) + end + + it 'returns whether the mute hides notifications' do + expect(mutes.first["hide_notifications"]).to be(false) + end + end end diff --git a/spec/controllers/settings/applications_controller_spec.rb b/spec/controllers/settings/applications_controller_spec.rb index ca66f8d23..90e6a63d5 100644 --- a/spec/controllers/settings/applications_controller_spec.rb +++ b/spec/controllers/settings/applications_controller_spec.rb @@ -2,10 +2,10 @@ require 'rails_helper' describe Settings::ApplicationsController do render_views - + let!(:user) { Fabricate(:user) } let!(:app) { Fabricate(:application, owner: user) } - + before do sign_in user, scope: :user end @@ -21,7 +21,7 @@ describe Settings::ApplicationsController do end end - + describe 'GET #show' do it 'returns http success' do get :show, params: { id: app.id } @@ -110,7 +110,7 @@ describe Settings::ApplicationsController do end end end - + describe 'PATCH #update' do context 'success' do let(:opts) { @@ -131,7 +131,7 @@ describe Settings::ApplicationsController do call_update expect(app.reload.website).to eql(opts[:website]) end - + it 'redirects back to applications page' do expect(call_update).to redirect_to(settings_applications_path) end diff --git a/spec/controllers/settings/keyword_mutes_controller_spec.rb b/spec/controllers/settings/keyword_mutes_controller_spec.rb new file mode 100644 index 000000000..a8c37a072 --- /dev/null +++ b/spec/controllers/settings/keyword_mutes_controller_spec.rb @@ -0,0 +1,5 @@ +require 'rails_helper' + +RSpec.describe Settings::KeywordMutesController, type: :controller do + +end diff --git a/spec/fabricators/glitch_keyword_mute_fabricator.rb b/spec/fabricators/glitch_keyword_mute_fabricator.rb new file mode 100644 index 000000000..20d393320 --- /dev/null +++ b/spec/fabricators/glitch_keyword_mute_fabricator.rb @@ -0,0 +1,2 @@ +Fabricator('Glitch::KeywordMute') do +end diff --git a/spec/fabricators/setting_fabricator.rb b/spec/fabricators/setting_fabricator.rb new file mode 100644 index 000000000..336d7c355 --- /dev/null +++ b/spec/fabricators/setting_fabricator.rb @@ -0,0 +1,4 @@ +# frozen_string_literal: true + +Fabricator(:setting) do +end diff --git a/spec/fixtures/requests/attachment1.txt b/spec/fixtures/requests/attachment1.txt index 77fd9c836..30bd456be 100644 --- a/spec/fixtures/requests/attachment1.txt +++ b/spec/fixtures/requests/attachment1.txt Binary files differdiff --git a/spec/fixtures/requests/attachment2.txt b/spec/fixtures/requests/attachment2.txt index 917a1d398..2a252d2de 100644 --- a/spec/fixtures/requests/attachment2.txt +++ b/spec/fixtures/requests/attachment2.txt Binary files differdiff --git a/spec/fixtures/requests/avatar.txt b/spec/fixtures/requests/avatar.txt index d57b0984f..d771f5dda 100644 --- a/spec/fixtures/requests/avatar.txt +++ b/spec/fixtures/requests/avatar.txt Binary files differdiff --git a/spec/fixtures/requests/idn.txt b/spec/fixtures/requests/idn.txt index 3c76c59c0..5d07f2b79 100644 --- a/spec/fixtures/requests/idn.txt +++ b/spec/fixtures/requests/idn.txt @@ -6,7 +6,7 @@ Content-Length: 38111 Last-Modified: Wed, 20 Jul 2016 02:50:52 GMT Connection: keep-alive Accept-Ranges: bytes - + <!DOCTYPE html> <html> <head> @@ -21,16 +21,16 @@ Accept-Ranges: bytes var s = document.getElementsByTagName("script")[0]; s.parentNode.insertBefore(hm, s); })(); - + </script> - - + + <link rel="stylesheet" type="text/css" href="css/common.css"/> <script src="js/jquery-1.11.1.min.js" type="text/javascript" charset="utf-8"></script> <script src="js/common.js" type="text/javascript" charset="utf-8"></script> <script src="js/carousel.js" type="text/javascript" charset="utf-8"></script> <title>中国域名网站</title> - + </head> <body> <div class="head-tips" id="headTip"> @@ -453,7 +453,7 @@ Accept-Ranges: bytes <li><a href="http://新疆农业大学.中国" target="_blank">新疆农业大学.中国</a></li> <li><a href="http://浙江万里学院.中国" target="_blank">浙江万里学院.中国</a></li> <li><a href="http://重庆大学.中国" target="_blank">重庆大学.中国</a></li> - + </ul> </div> </div> @@ -472,7 +472,7 @@ Accept-Ranges: bytes <script> $("#headTip").hide() var hostname = window.location.hostname || ""; - + var tips = "您所访问的域名 <font size='' color='#ff0000'>" + hostname +"</font> 无法到达,您可以尝试重新访问,或使用搜索相关信息" if (hostname != "导航.中国") { $("#headTip").html(tips); diff --git a/spec/helpers/settings/keyword_mutes_helper_spec.rb b/spec/helpers/settings/keyword_mutes_helper_spec.rb new file mode 100644 index 000000000..a19d518dd --- /dev/null +++ b/spec/helpers/settings/keyword_mutes_helper_spec.rb @@ -0,0 +1,15 @@ +require 'rails_helper' + +# Specs in this file have access to a helper object that includes +# the Settings::KeywordMutesHelper. For example: +# +# describe Settings::KeywordMutesHelper do +# describe "string concat" do +# it "concats two strings with spaces" do +# expect(helper.concat_strings("this","that")).to eq("this that") +# end +# end +# end +RSpec.describe Settings::KeywordMutesHelper, type: :helper do + pending "add some examples to (or delete) #{__FILE__}" +end diff --git a/spec/helpers/stream_entries_helper_spec.rb b/spec/helpers/stream_entries_helper_spec.rb index 2c0d7b239..1de6691ba 100644 --- a/spec/helpers/stream_entries_helper_spec.rb +++ b/spec/helpers/stream_entries_helper_spec.rb @@ -77,7 +77,7 @@ RSpec.describe StreamEntriesHelper, type: :helper do params[:controller] = StreamEntriesHelper::EMBEDDED_CONTROLLER params[:action] = StreamEntriesHelper::EMBEDDED_ACTION end - + describe '#style_classes' do it do status = double(reblog?: false) @@ -202,7 +202,7 @@ RSpec.describe StreamEntriesHelper, type: :helper do expect(css_class).to eq 'h-cite' end end - + describe '#rtl?' do it 'is false if text is empty' do expect(helper).not_to be_rtl '' diff --git a/spec/lib/feed_manager_spec.rb b/spec/lib/feed_manager_spec.rb index 0f97a579e..715d85306 100644 --- a/spec/lib/feed_manager_spec.rb +++ b/spec/lib/feed_manager_spec.rb @@ -56,6 +56,13 @@ RSpec.describe FeedManager do expect(FeedManager.instance.filter?(:home, reblog, bob.id)).to be true end + it 'returns true for reblog from account with reblogs disabled' do + status = Fabricate(:status, text: 'Hello world', account: jeff) + reblog = Fabricate(:status, reblog: status, account: alice) + bob.follow!(alice, reblogs: false) + expect(FeedManager.instance.filter?(:home, reblog, bob.id)).to be true + end + it 'returns false for reply by followee to another followee' do status = Fabricate(:status, text: 'Hello world', account: jeff) reply = Fabricate(:status, text: 'Nay', thread: status, account: alice) @@ -105,6 +112,13 @@ RSpec.describe FeedManager do expect(FeedManager.instance.filter?(:home, status, bob.id)).to be true end + it 'returns true for status by followee mentioning muted account' do + bob.mute!(jeff) + bob.follow!(alice) + status = PostStatusService.new.call(alice, 'Hey @jeff') + expect(FeedManager.instance.filter?(:home, status, bob.id)).to be true + end + it 'returns true for reblog of a personally blocked domain' do alice.block_domain!('example.com') alice.follow!(jeff) @@ -112,6 +126,44 @@ RSpec.describe FeedManager do reblog = Fabricate(:status, reblog: status, account: jeff) expect(FeedManager.instance.filter?(:home, reblog, alice.id)).to be true end + + it 'returns true for a status containing a muted keyword' do + Fabricate('Glitch::KeywordMute', account: alice, keyword: 'take') + status = Fabricate(:status, text: 'This is a hot take', account: bob) + + expect(FeedManager.instance.filter?(:home, status, alice.id)).to be true + end + + it 'returns true for a reply containing a muted keyword' do + Fabricate('Glitch::KeywordMute', account: alice, keyword: 'take') + s1 = Fabricate(:status, text: 'Something', account: alice) + s2 = Fabricate(:status, text: 'This is a hot take', thread: s1, account: bob) + + expect(FeedManager.instance.filter?(:home, s2, alice.id)).to be true + end + + it 'returns true for a status whose spoiler text contains a muted keyword' do + Fabricate('Glitch::KeywordMute', account: alice, keyword: 'take') + status = Fabricate(:status, spoiler_text: 'This is a hot take', account: bob) + + expect(FeedManager.instance.filter?(:home, status, alice.id)).to be true + end + + it 'returns true for a reblog containing a muted keyword' do + Fabricate('Glitch::KeywordMute', account: alice, keyword: 'take') + status = Fabricate(:status, text: 'This is a hot take', account: bob) + reblog = Fabricate(:status, reblog: status, account: jeff) + + expect(FeedManager.instance.filter?(:home, reblog, alice.id)).to be true + end + + it 'returns true for a reblog whose spoiler text contains a muted keyword' do + Fabricate('Glitch::KeywordMute', account: alice, keyword: 'take') + status = Fabricate(:status, spoiler_text: 'This is a hot take', account: bob) + reblog = Fabricate(:status, reblog: status, account: jeff) + + expect(FeedManager.instance.filter?(:home, reblog, alice.id)).to be true + end end context 'for mentions feed' do @@ -140,6 +192,13 @@ RSpec.describe FeedManager do bob.follow!(alice) expect(FeedManager.instance.filter?(:mentions, status, bob.id)).to be false end + + it 'returns true for status that contains a muted keyword' do + Fabricate('Glitch::KeywordMute', account: bob, keyword: 'take') + status = Fabricate(:status, text: 'This is a hot take', account: alice) + bob.follow!(alice) + expect(FeedManager.instance.filter?(:mentions, status, bob.id)).to be true + end end end diff --git a/spec/lib/settings/scoped_settings_spec.rb b/spec/lib/settings/scoped_settings_spec.rb new file mode 100644 index 000000000..7566685b4 --- /dev/null +++ b/spec/lib/settings/scoped_settings_spec.rb @@ -0,0 +1,35 @@ +# frozen_string_literal: true + +require 'rails_helper' + +RSpec.describe Settings::ScopedSettings do + let(:object) { Fabricate(:user) } + let(:scoped_setting) { described_class.new(object) } + let(:val) { 'whatever' } + let(:methods) { %i(auto_play_gif default_sensitive unfollow_modal boost_modal delete_modal reduce_motion system_font_ui noindex theme) } + + describe '.initialize' do + it 'sets @object' do + scoped_setting = described_class.new(object) + expect(scoped_setting.instance_variable_get(:@object)).to be object + end + end + + describe '#method_missing' do + it 'sets scoped_setting.method_name = val' do + methods.each do |key| + scoped_setting.send("#{key}=", val) + expect(scoped_setting.send(key)).to eq val + end + end + end + + describe '#[]= and #[]' do + it 'sets [key] = val' do + methods.each do |key| + scoped_setting[key] = val + expect(scoped_setting[key]).to eq val + end + end + end +end diff --git a/spec/lib/user_settings_decorator_spec.rb b/spec/lib/user_settings_decorator_spec.rb index 6fbf6536b..fee875373 100644 --- a/spec/lib/user_settings_decorator_spec.rb +++ b/spec/lib/user_settings_decorator_spec.rb @@ -62,7 +62,7 @@ describe UserSettingsDecorator do settings.update(values) expect(user.settings['auto_play_gif']).to eq false end - + it 'updates the user settings value for system font in UI' do values = { 'setting_system_font_ui' => '0' } diff --git a/spec/models/account_spec.rb b/spec/models/account_spec.rb index 9c1492c90..7501c498c 100644 --- a/spec/models/account_spec.rb +++ b/spec/models/account_spec.rb @@ -636,8 +636,8 @@ RSpec.describe Account, type: :model do expect(account).to model_have_error_on_field(:display_name) end - it 'is invalid if the note is longer than 160 characters' do - account = Fabricate.build(:account, note: Faker::Lorem.characters(161)) + it 'is invalid if the note is longer than 500 characters' do + account = Fabricate.build(:account, note: Faker::Lorem.characters(501)) account.valid? expect(account).to model_have_error_on_field(:note) end @@ -676,8 +676,8 @@ RSpec.describe Account, type: :model do expect(account).not_to model_have_error_on_field(:display_name) end - it 'is valid even if the note is longer than 160 characters' do - account = Fabricate.build(:account, domain: 'domain', note: Faker::Lorem.characters(161)) + it 'is valid even if the note is longer than 500 characters' do + account = Fabricate.build(:account, domain: 'domain', note: Faker::Lorem.characters(501)) account.valid? expect(account).not_to model_have_error_on_field(:note) end diff --git a/spec/models/concerns/account_interactions_spec.rb b/spec/models/concerns/account_interactions_spec.rb new file mode 100644 index 000000000..1e238e27c --- /dev/null +++ b/spec/models/concerns/account_interactions_spec.rb @@ -0,0 +1,75 @@ +require 'rails_helper' + +describe AccountInteractions do + describe 'muting an account' do + let(:me) { Fabricate(:account, username: 'Me') } + let(:you) { Fabricate(:account, username: 'You') } + + context 'with the notifications option unspecified' do + before do + me.mute!(you) + end + + it 'defaults to muting notifications' do + expect(me.muting_notifications?(you)).to be true + end + end + + context 'with the notifications option set to false' do + before do + me.mute!(you, notifications: false) + end + + it 'does not mute notifications' do + expect(me.muting_notifications?(you)).to be false + end + end + + context 'with the notifications option set to true' do + before do + me.mute!(you, notifications: true) + end + + it 'does mute notifications' do + expect(me.muting_notifications?(you)).to be true + end + end + end + + describe 'ignoring reblogs from an account' do + before do + @me = Fabricate(:account, username: 'Me') + @you = Fabricate(:account, username: 'You') + end + + context 'with the reblogs option unspecified' do + before do + @me.follow!(@you) + end + + it 'defaults to showing reblogs' do + expect(@me.muting_reblogs?(@you)).to be(false) + end + end + + context 'with the reblogs option set to false' do + before do + @me.follow!(@you, reblogs: false) + end + + it 'does mute reblogs' do + expect(@me.muting_reblogs?(@you)).to be(true) + end + end + + context 'with the reblogs option set to true' do + before do + @me.follow!(@you, reblogs: true) + end + + it 'does not mute reblogs' do + expect(@me.muting_reblogs?(@you)).to be(false) + end + end + end +end diff --git a/spec/models/email_domain_block_spec.rb b/spec/models/email_domain_block_spec.rb index 5f5d189d9..efd2853a9 100644 --- a/spec/models/email_domain_block_spec.rb +++ b/spec/models/email_domain_block_spec.rb @@ -13,9 +13,10 @@ RSpec.describe EmailDomainBlock, type: :model do Fabricate(:email_domain_block, domain: 'example.com') expect(EmailDomainBlock.block?('nyarn@example.com')).to eq true end + it 'returns true if the domain is not registed' do - Fabricate(:email_domain_block, domain: 'domain') - expect(EmailDomainBlock.block?('example')).to eq false + Fabricate(:email_domain_block, domain: 'example.com') + expect(EmailDomainBlock.block?('nyarn@example.net')).to eq false end end end diff --git a/spec/models/follow_request_spec.rb b/spec/models/follow_request_spec.rb index 1436501e9..7bc93a2aa 100644 --- a/spec/models/follow_request_spec.rb +++ b/spec/models/follow_request_spec.rb @@ -7,10 +7,31 @@ RSpec.describe FollowRequest, type: :model do let(:target_account) { Fabricate(:account) } it 'calls Account#follow!, MergeWorker.perform_async, and #destroy!' do - expect(account).to receive(:follow!).with(target_account) + expect(account).to receive(:follow!).with(target_account, reblogs: true) expect(MergeWorker).to receive(:perform_async).with(target_account.id, account.id) expect(follow_request).to receive(:destroy!) follow_request.authorize! end + + it 'generates a Follow' do + follow_request = Fabricate.create(:follow_request) + follow_request.authorize! + target = follow_request.target_account + expect(follow_request.account.following?(target)).to be true + end + + it 'correctly passes show_reblogs when true' do + follow_request = Fabricate.create(:follow_request, show_reblogs: true) + follow_request.authorize! + target = follow_request.target_account + expect(follow_request.account.muting_reblogs?(target)).to be false + end + + it 'correctly passes show_reblogs when false' do + follow_request = Fabricate.create(:follow_request, show_reblogs: false) + follow_request.authorize! + target = follow_request.target_account + expect(follow_request.account.muting_reblogs?(target)).to be true + end end end diff --git a/spec/models/glitch/keyword_mute_spec.rb b/spec/models/glitch/keyword_mute_spec.rb new file mode 100644 index 000000000..9685c6493 --- /dev/null +++ b/spec/models/glitch/keyword_mute_spec.rb @@ -0,0 +1,96 @@ +require 'rails_helper' + +RSpec.describe Glitch::KeywordMute, type: :model do + let(:alice) { Fabricate(:account, username: 'alice').tap(&:save!) } + let(:bob) { Fabricate(:account, username: 'bob').tap(&:save!) } + + describe '.matcher_for' do + let(:matcher) { Glitch::KeywordMute.matcher_for(alice) } + + describe 'with no mutes' do + before do + Glitch::KeywordMute.delete_all + end + + it 'does not match' do + expect(matcher =~ 'This is a hot take').to be_falsy + end + end + + describe 'with mutes' do + it 'does not match keywords set by a different account' do + Glitch::KeywordMute.create!(account: bob, keyword: 'take') + + expect(matcher =~ 'This is a hot take').to be_falsy + end + + it 'does not match if no keywords match the status text' do + Glitch::KeywordMute.create!(account: alice, keyword: 'cold') + + expect(matcher =~ 'This is a hot take').to be_falsy + end + + it 'considers word boundaries when matching' do + Glitch::KeywordMute.create!(account: alice, keyword: 'bob', whole_word: true) + + expect(matcher =~ 'bobcats').to be_falsy + end + + it 'matches substrings if whole_word is false' do + Glitch::KeywordMute.create!(account: alice, keyword: 'take', whole_word: false) + + expect(matcher =~ 'This is a shiitake mushroom').to be_truthy + end + + it 'matches keywords at the beginning of the text' do + Glitch::KeywordMute.create!(account: alice, keyword: 'take') + + expect(matcher =~ 'Take this').to be_truthy + end + + it 'matches keywords at the end of the text' do + Glitch::KeywordMute.create!(account: alice, keyword: 'take') + + expect(matcher =~ 'This is a hot take').to be_truthy + end + + it 'matches if at least one keyword case-insensitively matches the text' do + Glitch::KeywordMute.create!(account: alice, keyword: 'hot') + + expect(matcher =~ 'This is a HOT take').to be_truthy + end + + it 'maintains case-insensitivity when combining keywords into a single matcher' do + Glitch::KeywordMute.create!(account: alice, keyword: 'hot') + Glitch::KeywordMute.create!(account: alice, keyword: 'cold') + + expect(matcher =~ 'This is a HOT take').to be_truthy + end + + it 'matches keywords surrounded by non-alphanumeric ornamentation' do + Glitch::KeywordMute.create!(account: alice, keyword: 'hot') + + expect(matcher =~ '(hot take)').to be_truthy + end + + it 'escapes metacharacters in keywords' do + Glitch::KeywordMute.create!(account: alice, keyword: '(hot take)') + + expect(matcher =~ '(hot take)').to be_truthy + end + + it 'uses case-folding rules appropriate for more than just English' do + Glitch::KeywordMute.create!(account: alice, keyword: 'großeltern') + + expect(matcher =~ 'besuch der grosseltern').to be_truthy + end + + it 'matches keywords that are composed of multiple words' do + Glitch::KeywordMute.create!(account: alice, keyword: 'a shiitake') + + expect(matcher =~ 'This is a shiitake').to be_truthy + expect(matcher =~ 'This is shiitake').to_not be_truthy + end + end + end +end diff --git a/spec/models/remote_follow_spec.rb b/spec/models/remote_follow_spec.rb index 0b3adc9f9..72c580f9f 100644 --- a/spec/models/remote_follow_spec.rb +++ b/spec/models/remote_follow_spec.rb @@ -3,83 +3,65 @@ require 'rails_helper' RSpec.describe RemoteFollow do + before do + stub_request(:get, 'https://quitter.no/.well-known/webfinger?resource=acct:gargron@quitter.no').to_return(request_fixture('webfinger.txt')) + end + + let(:attrs) { nil } + let(:remote_follow) { described_class.new(attrs) } + describe '.initialize' do - let(:remote_follow) { RemoteFollow.new(option) } + subject { remote_follow.acct } - context 'option with acct' do - let(:option) { { acct: 'hoge@example.com' } } + context 'attrs with acct' do + let(:attrs) { { acct: 'gargron@quitter.no' } } - it 'sets acct' do - expect(remote_follow.acct).to eq 'hoge@example.com' + it 'returns acct' do + is_expected.to eq 'gargron@quitter.no' end end - context 'option without acct' do - let(:option) { {} } + context 'attrs without acct' do + let(:attrs) { {} } - it 'does not set acct' do - expect(remote_follow.acct).to be_nil + it do + is_expected.to be_nil end end end describe '#valid?' do - let(:remote_follow) { RemoteFollow.new } - - context 'super is falsy' do - module InvalidSuper - def valid? - nil - end - end + subject { remote_follow.valid? } - before do - class RemoteFollow - include InvalidSuper - end - end + context 'attrs with acct' do + let(:attrs) { { acct: 'gargron@quitter.no' }} - it 'returns false without calling #populate_template and #errors' do - expect(remote_follow).not_to receive(:populate_template) - expect(remote_follow).not_to receive(:errors) - expect(remote_follow.valid?).to be false + it do + is_expected.to be true end end - context 'super is truthy' do - module ValidSuper - def valid? - true - end - end + context 'attrs without acct' do + let(:attrs) { { } } - before do - class RemoteFollow - include ValidSuper - end - end - - it 'calls #populate_template and #errors.empty?' do - expect(remote_follow).to receive(:populate_template) - expect(remote_follow).to receive_message_chain(:errors, :empty?) - remote_follow.valid? + it do + is_expected.to be false end end end describe '#subscribe_address_for' do before do - allow(remote_follow).to receive(:addressable_template).and_return(addressable_template) + remote_follow.valid? end - let(:account) { instance_double('Account', local_username_and_domain: local_username_and_domain) } - let(:addressable_template) { instance_double('Addressable::Template') } - let(:local_username_and_domain) { 'hoge@example.com' } - let(:remote_follow) { RemoteFollow.new } + let(:attrs) { { acct: 'gargron@quitter.no' } } + let(:account) { Fabricate(:account, username: 'alice') } + + subject { remote_follow.subscribe_address_for(account) } - it 'calls Addressable::Template#expand.to_s' do - expect(addressable_template).to receive_message_chain(:expand, :to_s).with(uri: local_username_and_domain).with(no_args) - remote_follow.subscribe_address_for(account) + it 'returns subscribe address' do + is_expected.to eq 'https://quitter.no/main/ostatussub?profile=alice%40cb6e6126.ngrok.io' end end end diff --git a/spec/models/setting_spec.rb b/spec/models/setting_spec.rb new file mode 100644 index 000000000..e99dfc0d7 --- /dev/null +++ b/spec/models/setting_spec.rb @@ -0,0 +1,184 @@ +# frozen_string_literal: true + +require 'rails_helper' + +RSpec.describe Setting, type: :model do + describe '#to_param' do + let(:setting) { Fabricate(:setting, var: var) } + let(:var) { 'var' } + + it 'returns setting.var' do + expect(setting.to_param).to eq var + end + end + + describe '.[]' do + before do + allow(described_class).to receive(:rails_initialized?).and_return(rails_initialized) + end + + let(:key) { 'key' } + + context 'rails_initialized? is falsey' do + let(:rails_initialized) { false } + + it 'calls RailsSettings::Base#[]' do + expect(RailsSettings::Base).to receive(:[]).with(key) + described_class[key] + end + end + + context 'rails_initialized? is truthy' do + before do + allow(RailsSettings::Base).to receive(:cache_key).with(key, nil).and_return(cache_key) + end + + let(:rails_initialized) { true } + let(:cache_key) { 'cache-key' } + let(:cache_value) { 'cache-value' } + + it 'calls not RailsSettings::Base#[]' do + expect(RailsSettings::Base).not_to receive(:[]).with(key) + described_class[key] + end + + it 'calls Rails.cache.fetch' do + expect(Rails).to receive_message_chain(:cache, :fetch).with(cache_key) + described_class[key] + end + + context 'Rails.cache does not exists' do + before do + allow(RailsSettings::Settings).to receive(:object).with(key).and_return(object) + allow(described_class).to receive(:default_settings).and_return(default_settings) + allow_any_instance_of(Settings::ScopedSettings).to receive(:thing_scoped).and_return(records) + Rails.cache.clear(cache_key) + end + + let(:object) { nil } + let(:default_value) { 'default_value' } + let(:default_settings) { { key => default_value } } + let(:records) { [Fabricate(:setting, var: key, value: nil)] } + + it 'calls RailsSettings::Settings.object' do + expect(RailsSettings::Settings).to receive(:object).with(key) + described_class[key] + end + + context 'RailsSettings::Settings.object returns truthy' do + let(:object) { db_val } + let(:db_val) { double(value: 'db_val') } + + context 'default_value is a Hash' do + let(:default_value) { { default_value: 'default_value' } } + + it 'calls default_value.with_indifferent_access.merge!' do + expect(default_value).to receive_message_chain(:with_indifferent_access, :merge!) + .with(db_val.value) + + described_class[key] + end + end + + context 'default_value is not a Hash' do + let(:default_value) { 'default_value' } + + it 'returns db_val.value' do + expect(described_class[key]).to be db_val.value + end + end + end + + context 'RailsSettings::Settings.object returns falsey' do + let(:object) { nil } + + it 'returns default_settings[key]' do + expect(described_class[key]).to be default_settings[key] + end + end + end + + context 'Rails.cache exists' do + before do + Rails.cache.write(cache_key, cache_value) + end + + it 'returns the cached value' do + expect(described_class[key]).to eq cache_value + end + end + end + end + + describe '.all_as_records' do + before do + allow_any_instance_of(Settings::ScopedSettings).to receive(:thing_scoped).and_return(records) + allow(described_class).to receive(:default_settings).and_return(default_settings) + end + + let(:key) { 'key' } + let(:default_value) { 'default_value' } + let(:default_settings) { { key => default_value } } + let(:original_setting) { Fabricate(:setting, var: key, value: nil) } + let(:records) { [original_setting] } + + it 'returns a Hash' do + expect(described_class.all_as_records).to be_kind_of Hash + end + + context 'records includes Setting with var as the key' do + let(:records) { [original_setting] } + + it 'includes the original Setting' do + setting = described_class.all_as_records[key] + expect(setting).to eq original_setting + end + end + + context 'records includes nothing' do + let(:records) { [] } + + context 'default_value is not a Hash' do + it 'includes Setting with value of default_value' do + setting = described_class.all_as_records[key] + + expect(setting).to be_kind_of Setting + expect(setting).to have_attributes(var: key) + expect(setting).to have_attributes(value: 'default_value') + end + end + + context 'default_value is a Hash' do + let(:default_value) { { 'foo' => 'fuga' } } + + it 'returns {}' do + expect(described_class.all_as_records).to eq({}) + end + end + end + end + + describe '.default_settings' do + before do + allow(RailsSettings::Default).to receive(:enabled?).and_return(enabled) + end + + subject { described_class.default_settings } + + context 'RailsSettings::Default.enabled? is false' do + let(:enabled) { false } + + it 'returns {}' do + is_expected.to eq({}) + end + end + + context 'RailsSettings::Settings.enabled? is true' do + let(:enabled) { true } + + it 'returns instance of RailsSettings::Default' do + is_expected.to be_kind_of RailsSettings::Default + end + end + end +end diff --git a/spec/models/site_upload_spec.rb b/spec/models/site_upload_spec.rb index 8745d54b8..f7ea06921 100644 --- a/spec/models/site_upload_spec.rb +++ b/spec/models/site_upload_spec.rb @@ -1,5 +1,13 @@ +# frozen_string_literal: true + require 'rails_helper' RSpec.describe SiteUpload, type: :model do + describe '#cache_key' do + let(:site_upload) { SiteUpload.new(var: 'var') } + it 'returns cache_key' do + expect(site_upload.cache_key).to eq 'site_uploads/var' + end + end end diff --git a/spec/models/status_spec.rb b/spec/models/status_spec.rb index 9cb71d715..89ad3adcf 100644 --- a/spec/models/status_spec.rb +++ b/spec/models/status_spec.rb @@ -47,8 +47,27 @@ RSpec.describe Status, type: :model do end describe '#verb' do - it 'is always post' do - expect(subject.verb).to be :post + context 'if destroyed?' do + it 'returns :delete' do + subject.destroy! + expect(subject.verb).to be :delete + end + end + + context 'unless destroyed?' do + context 'if reblog?' do + it 'returns :share' do + subject.reblog = other + expect(subject.verb).to be :share + end + end + + context 'unless reblog?' do + it 'returns :post' do + subject.reblog = nil + expect(subject.verb).to be :post + end + end end end @@ -69,6 +88,36 @@ RSpec.describe Status, type: :model do end end + describe '#hidden?' do + context 'if private_visibility?' do + it 'returns true' do + subject.visibility = :private + expect(subject.hidden?).to be true + end + end + + context 'if direct_visibility?' do + it 'returns true' do + subject.visibility = :direct + expect(subject.hidden?).to be true + end + end + + context 'if public_visibility?' do + it 'returns false' do + subject.visibility = :public + expect(subject.hidden?).to be false + end + end + + context 'if unlisted_visibility?' do + it 'returns false' do + subject.visibility = :unlisted + expect(subject.hidden?).to be false + end + end + end + describe '#content' do it 'returns the text of the status if it is not a reblog' do expect(subject.content).to eql subject.text @@ -232,6 +281,55 @@ RSpec.describe Status, type: :model do end end + describe '.as_direct_timeline' do + let(:account) { Fabricate(:account) } + let(:followed) { Fabricate(:account) } + let(:not_followed) { Fabricate(:account) } + + before do + Fabricate(:follow, account: account, target_account: followed) + + @self_public_status = Fabricate(:status, account: account, visibility: :public) + @self_direct_status = Fabricate(:status, account: account, visibility: :direct) + @followed_public_status = Fabricate(:status, account: followed, visibility: :public) + @followed_direct_status = Fabricate(:status, account: followed, visibility: :direct) + @not_followed_direct_status = Fabricate(:status, account: not_followed, visibility: :direct) + + @results = Status.as_direct_timeline(account) + end + + it 'does not include public statuses from self' do + expect(@results).to_not include(@self_public_status) + end + + it 'includes direct statuses from self' do + expect(@results).to include(@self_direct_status) + end + + it 'does not include public statuses from followed' do + expect(@results).to_not include(@followed_public_status) + end + + it 'includes direct statuses mentioning recipient from followed' do + Fabricate(:mention, account: account, status: @followed_direct_status) + expect(@results).to include(@followed_direct_status) + end + + it 'does not include direct statuses not mentioning recipient from followed' do + expect(@results).to_not include(@followed_direct_status) + end + + it 'includes direct statuses mentioning recipient from non-followed' do + Fabricate(:mention, account: account, status: @not_followed_direct_status) + expect(@results).to include(@not_followed_direct_status) + end + + it 'does not include direct statuses not mentioning recipient from non-followed' do + expect(@results).to_not include(@not_followed_direct_status) + end + + end + describe '.as_public_timeline' do it 'only includes statuses with public visibility' do public_status = Fabricate(:status, visibility: :public) diff --git a/spec/models/stream_entry_spec.rb b/spec/models/stream_entry_spec.rb index 3b7ff5143..8f8bfbd58 100644 --- a/spec/models/stream_entry_spec.rb +++ b/spec/models/stream_entry_spec.rb @@ -6,6 +6,121 @@ RSpec.describe StreamEntry, type: :model do let(:status) { Fabricate(:status, account: alice) } let(:reblog) { Fabricate(:status, account: bob, reblog: status) } let(:reply) { Fabricate(:status, account: bob, thread: status) } + let(:stream_entry) { Fabricate(:stream_entry, activity: activity) } + let(:activity) { reblog } + + describe '#object_type' do + before do + allow(stream_entry).to receive(:orphaned?).and_return(orphaned) + allow(stream_entry).to receive(:targeted?).and_return(targeted) + end + + subject { stream_entry.object_type } + + context 'orphaned? is true' do + let(:orphaned) { true } + let(:targeted) { false } + + it 'returns :activity' do + is_expected.to be :activity + end + end + + context 'targeted? is true' do + let(:orphaned) { false } + let(:targeted) { true } + + it 'returns :activity' do + is_expected.to be :activity + end + end + + context 'orphaned? and targeted? are false' do + let(:orphaned) { false } + let(:targeted) { false } + + context 'activity is reblog' do + let(:activity) { reblog } + + it 'returns :note' do + is_expected.to be :note + end + end + + context 'activity is reply' do + let(:activity) { reply } + + it 'returns :comment' do + is_expected.to be :comment + end + end + end + end + + describe '#verb' do + before do + allow(stream_entry).to receive(:orphaned?).and_return(orphaned) + end + + subject { stream_entry.verb } + + context 'orphaned? is true' do + let(:orphaned) { true } + + it 'returns :delete' do + is_expected.to be :delete + end + end + + context 'orphaned? is false' do + let(:orphaned) { false } + + context 'activity is reblog' do + let(:activity) { reblog } + + it 'returns :share' do + is_expected.to be :share + end + end + + context 'activity is reply' do + let(:activity) { reply } + + it 'returns :post' do + is_expected.to be :post + end + end + end + end + + describe '#mentions' do + before do + allow(stream_entry).to receive(:orphaned?).and_return(orphaned) + end + + subject { stream_entry.mentions } + + context 'orphaned? is true' do + let(:orphaned) { true } + + it 'returns []' do + is_expected.to eq [] + end + end + + context 'orphaned? is false' do + before do + reblog.mentions << Fabricate(:mention, account: alice) + reblog.mentions << Fabricate(:mention, account: bob) + end + + let(:orphaned) { false } + + it 'returns [Account] includes alice and bob' do + is_expected.to eq [alice, bob] + end + end + end describe '#targeted?' do it 'returns true for a reblog' do diff --git a/spec/models/tag_spec.rb b/spec/models/tag_spec.rb index f727fa1dd..1ca50cc29 100644 --- a/spec/models/tag_spec.rb +++ b/spec/models/tag_spec.rb @@ -35,6 +35,13 @@ RSpec.describe Tag, type: :model do end end + describe '#to_param' do + it 'returns name' do + tag = Fabricate(:tag, name: 'foo') + expect(tag.to_param).to eq 'foo' + end + end + describe '.search_for' do it 'finds tag records with matching names' do tag = Fabricate(:tag, name: "match") diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb index 99aeca01b..77a12c26d 100644 --- a/spec/models/user_spec.rb +++ b/spec/models/user_spec.rb @@ -177,27 +177,10 @@ RSpec.describe User, type: :model do end end - describe '#setting_auto_play_gif' do - it 'returns auto-play gif setting' do + describe 'settings' do + it 'is instance of Settings::ScopedSettings' do user = Fabricate(:user) - user.settings[:auto_play_gif] = false - expect(user.setting_auto_play_gif).to eq false - end - end - - describe '#setting_system_font_ui' do - it 'returns system font ui setting' do - user = Fabricate(:user) - user.settings[:system_font_ui] = false - expect(user.setting_system_font_ui).to eq false - end - end - - describe '#setting_boost_modal' do - it 'returns boost modal setting' do - user = Fabricate(:user) - user.settings[:boost_modal] = false - expect(user.setting_boost_modal).to eq false + expect(user.settings).to be_kind_of Settings::ScopedSettings end end @@ -219,22 +202,6 @@ RSpec.describe User, type: :model do end end - describe '#setting_unfollow_modal' do - it 'returns unfollow modal setting' do - user = Fabricate(:user) - user.settings[:unfollow_modal] = true - expect(user.setting_unfollow_modal).to eq true - end - end - - describe '#setting_delete_modal' do - it 'returns delete modal setting' do - user = Fabricate(:user) - user.settings[:delete_modal] = false - expect(user.setting_delete_modal).to eq false - end - end - describe 'whitelist' do around(:each) do |example| old_whitelist = Rails.configuration.x.email_whitelist diff --git a/spec/policies/status_policy_spec.rb b/spec/policies/status_policy_spec.rb index bacb8fd9e..a90e22aad 100644 --- a/spec/policies/status_policy_spec.rb +++ b/spec/policies/status_policy_spec.rb @@ -71,6 +71,12 @@ RSpec.describe StatusPolicy, type: :model do expect(subject).to_not permit(viewer, status) end + + it 'denies access when local-only and the viewer is not logged in' do + allow(status).to receive(:local_only?) { true } + + expect(subject).to_not permit(nil, status) + end end permissions :reblog? do diff --git a/spec/services/activitypub/fetch_remote_status_service_spec.rb b/spec/services/activitypub/fetch_remote_status_service_spec.rb index ebf422392..51f3fe3a1 100644 --- a/spec/services/activitypub/fetch_remote_status_service_spec.rb +++ b/spec/services/activitypub/fetch_remote_status_service_spec.rb @@ -27,7 +27,7 @@ RSpec.describe ActivityPub::FetchRemoteStatusService do it 'creates status' do status = sender.statuses.first - + expect(status).to_not be_nil expect(status.text).to eq 'Lorem ipsum' end diff --git a/spec/services/follow_service_spec.rb b/spec/services/follow_service_spec.rb index ceb39e5e6..e59a2f1a6 100644 --- a/spec/services/follow_service_spec.rb +++ b/spec/services/follow_service_spec.rb @@ -13,8 +13,20 @@ RSpec.describe FollowService do subject.call(sender, bob.acct) end - it 'creates a follow request' do - expect(FollowRequest.find_by(account: sender, target_account: bob)).to_not be_nil + it 'creates a follow request with reblogs' do + expect(FollowRequest.find_by(account: sender, target_account: bob, show_reblogs: true)).to_not be_nil + end + end + + describe 'locked account, no reblogs' do + let(:bob) { Fabricate(:user, email: 'bob@example.com', account: Fabricate(:account, locked: true, username: 'bob')).account } + + before do + subject.call(sender, bob.acct, reblogs: false) + end + + it 'creates a follow request without reblogs' do + expect(FollowRequest.find_by(account: sender, target_account: bob, show_reblogs: false)).to_not be_nil end end @@ -25,8 +37,22 @@ RSpec.describe FollowService do subject.call(sender, bob.acct) end - it 'creates a following relation' do + it 'creates a following relation with reblogs' do + expect(sender.following?(bob)).to be true + expect(sender.muting_reblogs?(bob)).to be false + end + end + + describe 'unlocked account, no reblogs' do + let(:bob) { Fabricate(:user, email: 'bob@example.com', account: Fabricate(:account, username: 'bob')).account } + + before do + subject.call(sender, bob.acct, reblogs: false) + end + + it 'creates a following relation without reblogs' do expect(sender.following?(bob)).to be true + expect(sender.muting_reblogs?(bob)).to be true end end @@ -42,6 +68,32 @@ RSpec.describe FollowService do expect(sender.following?(bob)).to be true end end + + describe 'already followed account, turning reblogs off' do + let(:bob) { Fabricate(:user, email: 'bob@example.com', account: Fabricate(:account, username: 'bob')).account } + + before do + sender.follow!(bob, reblogs: true) + subject.call(sender, bob.acct, reblogs: false) + end + + it 'disables reblogs' do + expect(sender.muting_reblogs?(bob)).to be true + end + end + + describe 'already followed account, turning reblogs on' do + let(:bob) { Fabricate(:user, email: 'bob@example.com', account: Fabricate(:account, username: 'bob')).account } + + before do + sender.follow!(bob, reblogs: false) + subject.call(sender, bob.acct, reblogs: true) + end + + it 'disables reblogs' do + expect(sender.muting_reblogs?(bob)).to be false + end + end end context 'remote OStatus account' do diff --git a/spec/services/mute_service_spec.rb b/spec/services/mute_service_spec.rb index 8097cb250..800140b6f 100644 --- a/spec/services/mute_service_spec.rb +++ b/spec/services/mute_service_spec.rb @@ -32,4 +32,36 @@ RSpec.describe MuteService do account.muting?(target_account) }.from(false).to(true) end + + context 'without specifying a notifications parameter' do + it 'mutes notifications from the account' do + is_expected.to change { + account.muting_notifications?(target_account) + }.from(false).to(true) + end + end + + context 'with a true notifications parameter' do + subject do + -> { described_class.new.call(account, target_account, notifications: true) } + end + + it 'mutes notifications from the account' do + is_expected.to change { + account.muting_notifications?(target_account) + }.from(false).to(true) + end + end + + context 'with a false notifications parameter' do + subject do + -> { described_class.new.call(account, target_account, notifications: false) } + end + + it 'does not mute notifications from the account' do + is_expected.to_not change { + account.muting_notifications?(target_account) + }.from(false) + end + end end diff --git a/spec/services/notify_service_spec.rb b/spec/services/notify_service_spec.rb index 7a66bd0fe..a8ebc16b8 100644 --- a/spec/services/notify_service_spec.rb +++ b/spec/services/notify_service_spec.rb @@ -17,6 +17,16 @@ RSpec.describe NotifyService do is_expected.to_not change(Notification, :count) end + it 'does not notify when sender is muted with hide_notifications' do + recipient.mute!(sender, notifications: true) + is_expected.to_not change(Notification, :count) + end + + it 'does notify when sender is muted without hide_notifications' do + recipient.mute!(sender, notifications: false) + is_expected.to change(Notification, :count) + end + it 'does not notify when sender\'s domain is blocked' do recipient.block_domain!(sender.domain) is_expected.to_not change(Notification, :count) @@ -38,6 +48,59 @@ RSpec.describe NotifyService do is_expected.to_not change(Notification, :count) end + describe 'reblogs' do + let(:status) { Fabricate(:status, account: Fabricate(:account)) } + let(:activity) { Fabricate(:status, account: sender, reblog: status) } + + it 'shows reblogs by default' do + recipient.follow!(sender) + is_expected.to change(Notification, :count) + end + + it 'shows reblogs when explicitly enabled' do + recipient.follow!(sender, reblogs: true) + is_expected.to change(Notification, :count) + end + + it 'hides reblogs when disabled' do + recipient.follow!(sender, reblogs: false) + is_expected.to_not change(Notification, :count) + end + end + + context 'for direct messages' do + let(:activity) { Fabricate(:mention, account: recipient, status: Fabricate(:status, account: sender, visibility: :direct)) } + + before do + user.settings.interactions = user.settings.interactions.merge('must_be_following_dm' => enabled) + end + + context 'if recipient is supposed to be following sender' do + let(:enabled) { true } + + it 'does not notify' do + is_expected.to_not change(Notification, :count) + end + + context 'if the message chain initiated by recipient' do + let(:reply_to) { Fabricate(:status, account: recipient) } + let(:activity) { Fabricate(:mention, account: recipient, status: Fabricate(:status, account: sender, visibility: :direct, thread: reply_to)) } + + it 'does notify' do + is_expected.to change(Notification, :count) + end + end + end + + context 'if recipient is NOT supposed to be following sender' do + let(:enabled) { false } + + it 'does notify' do + is_expected.to change(Notification, :count) + end + end + end + context do let(:asshole) { Fabricate(:account, username: 'asshole') } let(:reply_to) { Fabricate(:status, account: asshole) } 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 5d5fe1c7b..a5dfbf457 100644 --- a/spec/support/matchers/model/model_have_error_on_field.rb +++ b/spec/support/matchers/model/model_have_error_on_field.rb @@ -9,7 +9,7 @@ RSpec::Matchers.define :model_have_error_on_field do |expected| failure_message do |record| keys = record.errors.keys - + "expect record.errors(#{keys}) to include #{expected}" end end diff --git a/spec/validators/status_length_validator_spec.rb b/spec/validators/status_length_validator_spec.rb index e2d1a15ec..9355c7e3f 100644 --- a/spec/validators/status_length_validator_spec.rb +++ b/spec/validators/status_length_validator_spec.rb @@ -7,26 +7,31 @@ describe StatusLengthValidator do it 'does not add errors onto remote statuses' it 'does not add errors onto local reblogs' - it 'adds an error when content warning is over 500 characters' do - status = double(spoiler_text: 'a' * 520, text: '', errors: double(add: nil), local?: true, reblog?: false) + it 'adds an error when content warning is over MAX_CHARS characters' do + chars = StatusLengthValidator::MAX_CHARS + 1 + status = double(spoiler_text: 'a' * chars, text: '', errors: double(add: nil), local?: true, reblog?: false) subject.validate(status) expect(status.errors).to have_received(:add) end - it 'adds an error when text is over 500 characters' do - status = double(spoiler_text: '', text: 'a' * 520, errors: double(add: nil), local?: true, reblog?: false) + it 'adds an error when text is over MAX_CHARS characters' do + chars = StatusLengthValidator::MAX_CHARS + 1 + status = double(spoiler_text: '', text: 'a' * chars, errors: double(add: nil), local?: true, reblog?: false) subject.validate(status) expect(status.errors).to have_received(:add) end - it 'adds an error when text and content warning are over 500 characters total' do - status = double(spoiler_text: 'a' * 250, text: 'b' * 251, errors: double(add: nil), local?: true, reblog?: false) + it 'adds an error when text and content warning are over MAX_CHARS characters total' do + chars1 = 20 + chars2 = StatusLengthValidator::MAX_CHARS + 1 - chars1 + status = double(spoiler_text: 'a' * chars1, text: 'b' * chars2, errors: double(add: nil), local?: true, reblog?: false) subject.validate(status) expect(status.errors).to have_received(:add) end it 'counts URLs as 23 characters flat' do - text = ('a' * 476) + " http://#{'b' * 30}.com/example" + chars = StatusLengthValidator::MAX_CHARS - 1 - 23 + text = ('a' * chars) + " http://#{'b' * 30}.com/example" status = double(spoiler_text: '', text: text, errors: double(add: nil), local?: true, reblog?: false) subject.validate(status) @@ -34,7 +39,9 @@ describe StatusLengthValidator do end it 'counts only the front part of remote usernames' do - text = ('a' * 475) + " @alice@#{'b' * 30}.com" + username = '@alice' + chars = StatusLengthValidator::MAX_CHARS - 1 - username.length + text = ('a' * 475) + " #{username}@#{'b' * 30}.com" status = double(spoiler_text: '', text: text, errors: double(add: nil), local?: true, reblog?: false) subject.validate(status) diff --git a/spec/views/about/show.html.haml_spec.rb b/spec/views/about/show.html.haml_spec.rb index 724643cbc..ca59fa9e3 100644 --- a/spec/views/about/show.html.haml_spec.rb +++ b/spec/views/about/show.html.haml_spec.rb @@ -3,6 +3,8 @@ require 'rails_helper' describe 'about/show.html.haml', without_verify_partial_doubles: true do + let(:commit_hash) { '8925731c9869f55780644304e4420a1998e52607' } + before do allow(view).to receive(:site_hostname).and_return('example.com') allow(view).to receive(:site_title).and_return('example site') @@ -16,7 +18,9 @@ describe 'about/show.html.haml', without_verify_partial_doubles: true do source_url: 'https://github.com/tootsuite/mastodon', open_registrations: false, thumbnail: nil, - closed_registrations_message: 'yes') + closed_registrations_message: 'yes', + commit_hash: commit_hash) + assign(:instance_presenter, instance_presenter) render |