Merge remote-tracking branch 'parent/main' into upstream-20240319
This commit is contained in:
commit
76598bd542
496 changed files with 5795 additions and 3709 deletions
|
@ -3,10 +3,6 @@
|
|||
require 'rails_helper'
|
||||
|
||||
describe Api::BaseController do
|
||||
before do
|
||||
stub_const('FakeService', Class.new)
|
||||
end
|
||||
|
||||
controller do
|
||||
def success
|
||||
head 200
|
||||
|
@ -72,36 +68,4 @@ describe Api::BaseController do
|
|||
expect(response).to have_http_status(403)
|
||||
end
|
||||
end
|
||||
|
||||
describe 'error handling' do
|
||||
before do
|
||||
routes.draw { get 'failure' => 'api/base#failure' }
|
||||
end
|
||||
|
||||
{
|
||||
ActiveRecord::RecordInvalid => 422,
|
||||
ActiveRecord::RecordNotFound => 404,
|
||||
ActiveRecord::RecordNotUnique => 422,
|
||||
Date::Error => 422,
|
||||
HTTP::Error => 503,
|
||||
Mastodon::InvalidParameterError => 400,
|
||||
Mastodon::NotPermittedError => 403,
|
||||
Mastodon::RaceConditionError => 503,
|
||||
Mastodon::RateLimitExceededError => 429,
|
||||
Mastodon::UnexpectedResponseError => 503,
|
||||
Mastodon::ValidationError => 422,
|
||||
OpenSSL::SSL::SSLError => 503,
|
||||
Seahorse::Client::NetworkingError => 503,
|
||||
Stoplight::Error::RedLight => 503,
|
||||
}.each do |error, code|
|
||||
it "Handles error class of #{error}" do
|
||||
allow(FakeService).to receive(:new).and_raise(error)
|
||||
|
||||
get :failure
|
||||
|
||||
expect(response).to have_http_status(code)
|
||||
expect(FakeService).to have_received(:new)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,105 +0,0 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'rails_helper'
|
||||
|
||||
describe Api::V1::Accounts::CredentialsController do
|
||||
render_views
|
||||
|
||||
let(:user) { Fabricate(:user) }
|
||||
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) }
|
||||
|
||||
context 'with an oauth token' do
|
||||
before do
|
||||
allow(controller).to receive(:doorkeeper_token) { token }
|
||||
end
|
||||
|
||||
describe 'GET #show' do
|
||||
let(:scopes) { 'read:accounts' }
|
||||
|
||||
it 'returns http success' do
|
||||
get :show
|
||||
expect(response).to have_http_status(200)
|
||||
end
|
||||
end
|
||||
|
||||
describe 'PATCH #update' do
|
||||
let(:scopes) { 'write:accounts' }
|
||||
|
||||
describe 'with valid data' do
|
||||
before do
|
||||
allow(ActivityPub::UpdateDistributionWorker).to receive(:perform_async)
|
||||
|
||||
patch :update, params: {
|
||||
display_name: "Alice Isn't Dead",
|
||||
note: "Hi!\n\nToot toot!",
|
||||
avatar: fixture_file_upload('avatar.gif', 'image/gif'),
|
||||
header: fixture_file_upload('attachment.jpg', 'image/jpeg'),
|
||||
source: {
|
||||
privacy: 'unlisted',
|
||||
sensitive: true,
|
||||
},
|
||||
}
|
||||
end
|
||||
|
||||
it 'updates account info', :aggregate_failures do
|
||||
expect(response).to have_http_status(200)
|
||||
|
||||
user.reload
|
||||
user.account.reload
|
||||
|
||||
expect(user.account.display_name).to eq("Alice Isn't Dead")
|
||||
expect(user.account.note).to eq("Hi!\n\nToot toot!")
|
||||
expect(user.account.avatar).to exist
|
||||
expect(user.account.header).to exist
|
||||
expect(user.setting_default_privacy).to eq('unlisted')
|
||||
expect(user.setting_default_sensitive).to be(true)
|
||||
|
||||
expect(ActivityPub::UpdateDistributionWorker).to have_received(:perform_async).with(user.account_id)
|
||||
end
|
||||
end
|
||||
|
||||
describe 'with empty source list' do
|
||||
before do
|
||||
patch :update, params: {
|
||||
display_name: "I'm a cat",
|
||||
source: {},
|
||||
}, as: :json
|
||||
end
|
||||
|
||||
it 'returns http success' do
|
||||
expect(response).to have_http_status(200)
|
||||
end
|
||||
end
|
||||
|
||||
describe 'with invalid data' do
|
||||
before do
|
||||
patch :update, params: { note: 'This is too long. ' * 30 }
|
||||
end
|
||||
|
||||
it 'returns http unprocessable entity' do
|
||||
expect(response).to have_http_status(422)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'without an oauth token' do
|
||||
before do
|
||||
allow(controller).to receive(:doorkeeper_token).and_return(nil)
|
||||
end
|
||||
|
||||
describe 'GET #show' do
|
||||
it 'returns http unauthorized' do
|
||||
get :show
|
||||
expect(response).to have_http_status(401)
|
||||
end
|
||||
end
|
||||
|
||||
describe 'PATCH #update' do
|
||||
it 'returns http unauthorized' do
|
||||
patch :update, params: { note: 'Foo' }
|
||||
expect(response).to have_http_status(401)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
51
spec/controllers/concerns/api/error_handling_spec.rb
Normal file
51
spec/controllers/concerns/api/error_handling_spec.rb
Normal file
|
@ -0,0 +1,51 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'rails_helper'
|
||||
|
||||
describe Api::ErrorHandling do
|
||||
before do
|
||||
stub_const('FakeService', Class.new)
|
||||
end
|
||||
|
||||
controller(Api::BaseController) do
|
||||
def failure
|
||||
FakeService.new
|
||||
end
|
||||
end
|
||||
|
||||
describe 'error handling' do
|
||||
before do
|
||||
routes.draw { get 'failure' => 'api/base#failure' }
|
||||
end
|
||||
|
||||
{
|
||||
ActiveRecord::RecordInvalid => 422,
|
||||
ActiveRecord::RecordNotFound => 404,
|
||||
ActiveRecord::RecordNotUnique => 422,
|
||||
Date::Error => 422,
|
||||
HTTP::Error => 503,
|
||||
Mastodon::InvalidParameterError => 400,
|
||||
Mastodon::NotPermittedError => 403,
|
||||
Mastodon::RaceConditionError => 503,
|
||||
Mastodon::RateLimitExceededError => 429,
|
||||
Mastodon::UnexpectedResponseError => 503,
|
||||
Mastodon::ValidationError => 422,
|
||||
OpenSSL::SSL::SSLError => 503,
|
||||
Seahorse::Client::NetworkingError => 503,
|
||||
Stoplight::Error::RedLight => 503,
|
||||
}.each do |error, code|
|
||||
it "Handles error class of #{error}" do
|
||||
allow(FakeService)
|
||||
.to receive(:new)
|
||||
.and_raise(error)
|
||||
|
||||
get :failure
|
||||
|
||||
expect(response)
|
||||
.to have_http_status(code)
|
||||
expect(FakeService)
|
||||
.to have_received(:new)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -41,6 +41,14 @@ RSpec.describe InstanceActorsController do
|
|||
|
||||
it_behaves_like 'shared behavior'
|
||||
end
|
||||
|
||||
context 'with a suspended instance actor' do
|
||||
let(:authorized_fetch_mode) { false }
|
||||
|
||||
before { Account.representative.update(suspended_at: 10.days.ago) }
|
||||
|
||||
it_behaves_like 'shared behavior'
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -61,15 +61,11 @@ describe 'Using OAuth from an external app' do
|
|||
expect(page).to have_content(I18n.t('auth.login'))
|
||||
|
||||
# Failing to log-in presents the form again
|
||||
fill_in 'user_email', with: email
|
||||
fill_in 'user_password', with: 'wrong password'
|
||||
click_on I18n.t('auth.login')
|
||||
fill_in_auth_details(email, 'wrong password')
|
||||
expect(page).to have_content(I18n.t('auth.login'))
|
||||
|
||||
# Logging in redirects to an authorization page
|
||||
fill_in 'user_email', with: email
|
||||
fill_in 'user_password', with: password
|
||||
click_on I18n.t('auth.login')
|
||||
fill_in_auth_details(email, password)
|
||||
expect(page).to have_content(I18n.t('doorkeeper.authorizations.buttons.authorize'))
|
||||
|
||||
# Upon authorizing, it redirects to the apps' callback URL
|
||||
|
@ -88,15 +84,11 @@ describe 'Using OAuth from an external app' do
|
|||
expect(page).to have_content(I18n.t('auth.login'))
|
||||
|
||||
# Failing to log-in presents the form again
|
||||
fill_in 'user_email', with: email
|
||||
fill_in 'user_password', with: 'wrong password'
|
||||
click_on I18n.t('auth.login')
|
||||
fill_in_auth_details(email, 'wrong password')
|
||||
expect(page).to have_content(I18n.t('auth.login'))
|
||||
|
||||
# Logging in redirects to an authorization page
|
||||
fill_in 'user_email', with: email
|
||||
fill_in 'user_password', with: password
|
||||
click_on I18n.t('auth.login')
|
||||
fill_in_auth_details(email, password)
|
||||
expect(page).to have_content(I18n.t('doorkeeper.authorizations.buttons.authorize'))
|
||||
|
||||
# Upon denying, it redirects to the apps' callback URL
|
||||
|
@ -118,25 +110,19 @@ describe 'Using OAuth from an external app' do
|
|||
expect(page).to have_content(I18n.t('auth.login'))
|
||||
|
||||
# Failing to log-in presents the form again
|
||||
fill_in 'user_email', with: email
|
||||
fill_in 'user_password', with: 'wrong password'
|
||||
click_on I18n.t('auth.login')
|
||||
fill_in_auth_details(email, 'wrong password')
|
||||
expect(page).to have_content(I18n.t('auth.login'))
|
||||
|
||||
# Logging in redirects to a two-factor authentication page
|
||||
fill_in 'user_email', with: email
|
||||
fill_in 'user_password', with: password
|
||||
click_on I18n.t('auth.login')
|
||||
fill_in_auth_details(email, password)
|
||||
expect(page).to have_content(I18n.t('simple_form.hints.sessions.otp'))
|
||||
|
||||
# Filling in an incorrect two-factor authentication code presents the form again
|
||||
fill_in 'user_otp_attempt', with: 'wrong'
|
||||
click_on I18n.t('auth.login')
|
||||
fill_in_otp_details('wrong')
|
||||
expect(page).to have_content(I18n.t('simple_form.hints.sessions.otp'))
|
||||
|
||||
# Filling in the correct TOTP code redirects to an app authorization page
|
||||
fill_in 'user_otp_attempt', with: user.current_otp
|
||||
click_on I18n.t('auth.login')
|
||||
fill_in_otp_details(user.current_otp)
|
||||
expect(page).to have_content(I18n.t('doorkeeper.authorizations.buttons.authorize'))
|
||||
|
||||
# Upon authorizing, it redirects to the apps' callback URL
|
||||
|
@ -155,25 +141,19 @@ describe 'Using OAuth from an external app' do
|
|||
expect(page).to have_content(I18n.t('auth.login'))
|
||||
|
||||
# Failing to log-in presents the form again
|
||||
fill_in 'user_email', with: email
|
||||
fill_in 'user_password', with: 'wrong password'
|
||||
click_on I18n.t('auth.login')
|
||||
fill_in_auth_details(email, 'wrong password')
|
||||
expect(page).to have_content(I18n.t('auth.login'))
|
||||
|
||||
# Logging in redirects to a two-factor authentication page
|
||||
fill_in 'user_email', with: email
|
||||
fill_in 'user_password', with: password
|
||||
click_on I18n.t('auth.login')
|
||||
fill_in_auth_details(email, password)
|
||||
expect(page).to have_content(I18n.t('simple_form.hints.sessions.otp'))
|
||||
|
||||
# Filling in an incorrect two-factor authentication code presents the form again
|
||||
fill_in 'user_otp_attempt', with: 'wrong'
|
||||
click_on I18n.t('auth.login')
|
||||
fill_in_otp_details('wrong')
|
||||
expect(page).to have_content(I18n.t('simple_form.hints.sessions.otp'))
|
||||
|
||||
# Filling in the correct TOTP code redirects to an app authorization page
|
||||
fill_in 'user_otp_attempt', with: user.current_otp
|
||||
click_on I18n.t('auth.login')
|
||||
fill_in_otp_details(user.current_otp)
|
||||
expect(page).to have_content(I18n.t('doorkeeper.authorizations.buttons.authorize'))
|
||||
|
||||
# Upon denying, it redirects to the apps' callback URL
|
||||
|
@ -185,6 +165,19 @@ describe 'Using OAuth from an external app' do
|
|||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def fill_in_auth_details(email, password)
|
||||
fill_in 'user_email', with: email
|
||||
fill_in 'user_password', with: password
|
||||
click_on I18n.t('auth.login')
|
||||
end
|
||||
|
||||
def fill_in_otp_details(value)
|
||||
fill_in 'user_otp_attempt', with: value
|
||||
click_on I18n.t('auth.login')
|
||||
end
|
||||
|
||||
# TODO: external auth
|
||||
end
|
||||
end
|
||||
|
|
|
@ -3,30 +3,6 @@
|
|||
require 'rails_helper'
|
||||
|
||||
describe ApplicationHelper do
|
||||
describe 'active_nav_class' do
|
||||
it 'returns active when on the current page' do
|
||||
allow(helper).to receive(:current_page?).and_return(true)
|
||||
|
||||
result = helper.active_nav_class('/test')
|
||||
expect(result).to eq 'active'
|
||||
end
|
||||
|
||||
it 'returns active when on a current page' do
|
||||
allow(helper).to receive(:current_page?).with('/foo').and_return(false)
|
||||
allow(helper).to receive(:current_page?).with('/test').and_return(true)
|
||||
|
||||
result = helper.active_nav_class('/foo', '/test')
|
||||
expect(result).to eq 'active'
|
||||
end
|
||||
|
||||
it 'returns empty string when not on current page' do
|
||||
allow(helper).to receive(:current_page?).and_return(false)
|
||||
|
||||
result = helper.active_nav_class('/test')
|
||||
expect(result).to eq ''
|
||||
end
|
||||
end
|
||||
|
||||
describe 'body_classes' do
|
||||
context 'with a body class string from a controller' do
|
||||
before { helper.extend controller_helpers }
|
||||
|
@ -103,36 +79,6 @@ describe ApplicationHelper do
|
|||
end
|
||||
end
|
||||
|
||||
describe 'show_landing_strip?', :without_verify_partial_doubles do
|
||||
describe 'when signed in' do
|
||||
before do
|
||||
allow(helper).to receive(:user_signed_in?).and_return(true)
|
||||
end
|
||||
|
||||
it 'does not show landing strip' do
|
||||
expect(helper.show_landing_strip?).to be false
|
||||
end
|
||||
end
|
||||
|
||||
describe 'when signed out' do
|
||||
before do
|
||||
allow(helper).to receive(:user_signed_in?).and_return(false)
|
||||
end
|
||||
|
||||
it 'does not show landing strip on single user instance' do
|
||||
allow(helper).to receive(:single_user_mode?).and_return(true)
|
||||
|
||||
expect(helper.show_landing_strip?).to be false
|
||||
end
|
||||
|
||||
it 'shows landing strip on multi user instance' do
|
||||
allow(helper).to receive(:single_user_mode?).and_return(false)
|
||||
|
||||
expect(helper.show_landing_strip?).to be true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'available_sign_up_path' do
|
||||
context 'when registrations are closed' do
|
||||
before do
|
||||
|
|
|
@ -29,26 +29,6 @@ describe StatusesHelper do
|
|||
I18n.t('statuses.content_warning', warning: status.spoiler_text)
|
||||
end
|
||||
|
||||
describe 'link_to_newer' do
|
||||
it 'returns a link to newer content' do
|
||||
url = 'https://example.com'
|
||||
result = helper.link_to_newer(url)
|
||||
|
||||
expect(result).to match('load-more')
|
||||
expect(result).to match(I18n.t('statuses.show_newer'))
|
||||
end
|
||||
end
|
||||
|
||||
describe 'link_to_older' do
|
||||
it 'returns a link to older content' do
|
||||
url = 'https://example.com'
|
||||
result = helper.link_to_older(url)
|
||||
|
||||
expect(result).to match('load-more')
|
||||
expect(result).to match(I18n.t('statuses.show_older'))
|
||||
end
|
||||
end
|
||||
|
||||
describe 'fa_visibility_icon' do
|
||||
context 'with a status that is public' do
|
||||
let(:status) { Status.new(visibility: 'public') }
|
||||
|
|
|
@ -50,7 +50,7 @@ RSpec.describe ActivityPub::Activity::Add do
|
|||
end
|
||||
|
||||
it 'fetches the status and pins it' do
|
||||
allow(service_stub).to receive(:call) do |uri, id: true, on_behalf_of: nil, request_id: nil| # rubocop:disable Lint/UnusedBlockArgument
|
||||
allow(service_stub).to receive(:call) do |uri, id: true, on_behalf_of: nil, **|
|
||||
expect(uri).to eq 'https://example.com/unknown'
|
||||
expect(id).to be true
|
||||
expect(on_behalf_of&.following?(sender)).to be true
|
||||
|
@ -64,7 +64,7 @@ RSpec.describe ActivityPub::Activity::Add do
|
|||
|
||||
context 'when there is no local follower' do
|
||||
it 'tries to fetch the status' do
|
||||
allow(service_stub).to receive(:call) do |uri, id: true, on_behalf_of: nil, request_id: nil| # rubocop:disable Lint/UnusedBlockArgument
|
||||
allow(service_stub).to receive(:call) do |uri, id: true, on_behalf_of: nil, **|
|
||||
expect(uri).to eq 'https://example.com/unknown'
|
||||
expect(id).to be true
|
||||
expect(on_behalf_of).to be_nil
|
||||
|
|
|
@ -11,7 +11,7 @@ RSpec.describe FeedManager do
|
|||
end
|
||||
|
||||
it 'tracks at least as many statuses as reblogs', :skip_stub do
|
||||
expect(FeedManager::REBLOG_FALLOFF).to be <= FeedManager::MAX_ITEMS
|
||||
expect(described_class::REBLOG_FALLOFF).to be <= described_class::MAX_ITEMS
|
||||
end
|
||||
|
||||
describe '#key' do
|
||||
|
@ -262,12 +262,12 @@ RSpec.describe FeedManager do
|
|||
it 'trims timelines if they will have more than FeedManager::MAX_ITEMS' do
|
||||
account = Fabricate(:account)
|
||||
status = Fabricate(:status)
|
||||
members = Array.new(FeedManager::MAX_ITEMS) { |count| [count, count] }
|
||||
members = Array.new(described_class::MAX_ITEMS) { |count| [count, count] }
|
||||
redis.zadd("feed:home:#{account.id}", members)
|
||||
|
||||
described_class.instance.push_to_home(account, status)
|
||||
|
||||
expect(redis.zcard("feed:home:#{account.id}")).to eq FeedManager::MAX_ITEMS
|
||||
expect(redis.zcard("feed:home:#{account.id}")).to eq described_class::MAX_ITEMS
|
||||
end
|
||||
|
||||
context 'with reblogs' do
|
||||
|
@ -297,7 +297,7 @@ RSpec.describe FeedManager do
|
|||
described_class.instance.push_to_home(account, reblogged)
|
||||
|
||||
# Fill the feed with intervening statuses
|
||||
FeedManager::REBLOG_FALLOFF.times do
|
||||
described_class::REBLOG_FALLOFF.times do
|
||||
described_class.instance.push_to_home(account, Fabricate(:status))
|
||||
end
|
||||
|
||||
|
@ -358,7 +358,7 @@ RSpec.describe FeedManager do
|
|||
described_class.instance.push_to_home(account, reblogs.first)
|
||||
|
||||
# Fill the feed with intervening statuses
|
||||
FeedManager::REBLOG_FALLOFF.times do
|
||||
described_class::REBLOG_FALLOFF.times do
|
||||
described_class.instance.push_to_home(account, Fabricate(:status))
|
||||
end
|
||||
|
||||
|
@ -504,7 +504,7 @@ RSpec.describe FeedManager do
|
|||
status = Fabricate(:status, reblog: reblogged)
|
||||
|
||||
described_class.instance.push_to_home(receiver, reblogged)
|
||||
FeedManager::REBLOG_FALLOFF.times { described_class.instance.push_to_home(receiver, Fabricate(:status)) }
|
||||
described_class::REBLOG_FALLOFF.times { described_class.instance.push_to_home(receiver, Fabricate(:status)) }
|
||||
described_class.instance.push_to_home(receiver, status)
|
||||
|
||||
# The reblogging status should show up under normal conditions.
|
||||
|
|
|
@ -15,6 +15,23 @@ describe Mastodon::CLI::Domains do
|
|||
describe '#purge' do
|
||||
let(:action) { :purge }
|
||||
|
||||
context 'with invalid limited federation mode argument' do
|
||||
let(:arguments) { ['example.host'] }
|
||||
let(:options) { { limited_federation_mode: true } }
|
||||
|
||||
it 'warns about usage and exits' do
|
||||
expect { subject }
|
||||
.to raise_error(Thor::Error, /DOMAIN parameter not supported/)
|
||||
end
|
||||
end
|
||||
|
||||
context 'without a domains argument' do
|
||||
it 'warns about usage and exits' do
|
||||
expect { subject }
|
||||
.to raise_error(Thor::Error, 'No domain(s) given')
|
||||
end
|
||||
end
|
||||
|
||||
context 'with accounts from the domain' do
|
||||
let(:domain) { 'host.example' }
|
||||
let!(:account) { Fabricate(:account, domain: domain) }
|
||||
|
|
|
@ -33,6 +33,17 @@ describe Mastodon::CLI::Search do
|
|||
end
|
||||
end
|
||||
|
||||
context 'when server communication raises an error' do
|
||||
let(:options) { { reset_chewy: true } }
|
||||
|
||||
before { allow(Chewy::Stash::Specification).to receive(:reset!).and_raise(Elasticsearch::Transport::Transport::Errors::InternalServerError) }
|
||||
|
||||
it 'Exits with error message' do
|
||||
expect { subject }
|
||||
.to raise_error(Thor::Error, /issue connecting to the search/)
|
||||
end
|
||||
end
|
||||
|
||||
context 'without options' do
|
||||
before { stub_search_indexes }
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@ require 'rails_helper'
|
|||
|
||||
describe Sanitize::Config do
|
||||
describe '::MASTODON_STRICT' do
|
||||
subject { Sanitize::Config::MASTODON_STRICT }
|
||||
subject { described_class::MASTODON_STRICT }
|
||||
|
||||
it 'converts h1 to p strong' do
|
||||
expect(Sanitize.fragment('<h1>Foo</h1>', subject)).to eq '<p><strong>Foo</strong></p>'
|
||||
|
|
|
@ -27,7 +27,7 @@ RSpec.describe SignatureParser do
|
|||
let(:header) { 'hello this is malformed!' }
|
||||
|
||||
it 'raises an error' do
|
||||
expect { subject }.to raise_error(SignatureParser::ParsingError)
|
||||
expect { subject }.to raise_error(described_class::ParsingError)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -13,7 +13,26 @@ RSpec.describe Vacuum::ImportsVacuum do
|
|||
|
||||
describe '#perform' do
|
||||
it 'cleans up the expected imports' do
|
||||
expect { subject.perform }.to change { BulkImport.pluck(:id) }.from([old_unconfirmed, new_unconfirmed, recent_ongoing, recent_finished, old_finished].map(&:id)).to([new_unconfirmed, recent_ongoing, recent_finished].map(&:id))
|
||||
expect { subject.perform }
|
||||
.to change { ordered_bulk_imports.pluck(:id) }
|
||||
.from(original_import_ids)
|
||||
.to(remaining_import_ids)
|
||||
end
|
||||
|
||||
def ordered_bulk_imports
|
||||
BulkImport.order(id: :asc)
|
||||
end
|
||||
|
||||
def original_import_ids
|
||||
[old_unconfirmed, new_unconfirmed, recent_ongoing, recent_finished, old_finished].map(&:id)
|
||||
end
|
||||
|
||||
def vacuumed_import_ids
|
||||
[old_unconfirmed, old_finished].map(&:id)
|
||||
end
|
||||
|
||||
def remaining_import_ids
|
||||
original_import_ids - vacuumed_import_ids
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -46,7 +46,7 @@ describe WebfingerResource do
|
|||
|
||||
expect do
|
||||
described_class.new(resource).username
|
||||
end.to raise_error(WebfingerResource::InvalidRequest)
|
||||
end.to raise_error(described_class::InvalidRequest)
|
||||
end
|
||||
|
||||
it 'finds the username in a valid https route' do
|
||||
|
@ -137,7 +137,7 @@ describe WebfingerResource do
|
|||
|
||||
expect do
|
||||
described_class.new(resource).username
|
||||
end.to raise_error(WebfingerResource::InvalidRequest)
|
||||
end.to raise_error(described_class::InvalidRequest)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -901,7 +901,7 @@ RSpec.describe Account do
|
|||
end
|
||||
|
||||
describe 'MENTION_RE' do
|
||||
subject { Account::MENTION_RE }
|
||||
subject { described_class::MENTION_RE }
|
||||
|
||||
it 'matches usernames in the middle of a sentence' do
|
||||
expect(subject.match('Hello to @alice from me')[1]).to eq 'alice'
|
||||
|
@ -1111,7 +1111,7 @@ RSpec.describe Account do
|
|||
{ username: 'b', domain: 'b' },
|
||||
].map(&method(:Fabricate).curry(2).call(:account))
|
||||
|
||||
expect(described_class.where('id > 0').alphabetic).to eq matches
|
||||
expect(described_class.without_internal.alphabetic).to eq matches
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -1162,7 +1162,7 @@ RSpec.describe Account do
|
|||
it 'returns an array of accounts who do not have a domain' do
|
||||
local_account = Fabricate(:account, domain: nil)
|
||||
_account_with_domain = Fabricate(:account, domain: 'example.com')
|
||||
expect(described_class.where('id > 0').local).to contain_exactly(local_account)
|
||||
expect(described_class.without_internal.local).to contain_exactly(local_account)
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -1173,14 +1173,14 @@ RSpec.describe Account do
|
|||
matches[index] = Fabricate(:account, domain: matches[index])
|
||||
end
|
||||
|
||||
expect(described_class.where('id > 0').partitioned).to match_array(matches)
|
||||
expect(described_class.without_internal.partitioned).to match_array(matches)
|
||||
end
|
||||
end
|
||||
|
||||
describe 'recent' do
|
||||
it 'returns a relation of accounts sorted by recent creation' do
|
||||
matches = Array.new(2) { Fabricate(:account) }
|
||||
expect(described_class.where('id > 0').recent).to match_array(matches)
|
||||
expect(described_class.without_internal.recent).to match_array(matches)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -1,6 +1,100 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
# Reverted this commit.temporarily because load issues.
|
||||
# Whenever a manual merge occurs, be sure to check the following commits.
|
||||
# Hash: ee8d0b94473df357677cd1f82581251ce0423c01
|
||||
# Message: Fix follow suggestions potentially including silenced or blocked accounts (#29306)
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe AccountSuggestions::FriendsOfFriendsSource do
|
||||
describe '#get' do
|
||||
subject { described_class.new }
|
||||
|
||||
let!(:bob) { Fabricate(:account, discoverable: true, hide_collections: false) }
|
||||
let!(:alice) { Fabricate(:account, discoverable: true, hide_collections: true) }
|
||||
let!(:eve) { Fabricate(:account, discoverable: true, hide_collections: false) }
|
||||
let!(:mallory) { Fabricate(:account, discoverable: false, hide_collections: false) }
|
||||
let!(:eugen) { Fabricate(:account, discoverable: true, hide_collections: false) }
|
||||
let!(:neil) { Fabricate(:account, discoverable: true, hide_collections: false) }
|
||||
let!(:john) { Fabricate(:account, discoverable: true, hide_collections: false) }
|
||||
let!(:jerk) { Fabricate(:account, discoverable: true, hide_collections: false) }
|
||||
let!(:larry) { Fabricate(:account, discoverable: true, hide_collections: false) }
|
||||
|
||||
context 'with follows and blocks' do
|
||||
before do
|
||||
bob.block!(jerk)
|
||||
FollowRecommendationMute.create!(account: bob, target_account: neil)
|
||||
|
||||
# bob follows eugen, alice and larry
|
||||
[eugen, alice, larry].each { |account| bob.follow!(account) }
|
||||
|
||||
# alice follows eve and mallory
|
||||
[john, mallory].each { |account| alice.follow!(account) }
|
||||
|
||||
# eugen follows eve, john, jerk, larry and neil
|
||||
[eve, mallory, jerk, larry, neil].each { |account| eugen.follow!(account) }
|
||||
end
|
||||
|
||||
it 'returns eligible accounts', :aggregate_failures do
|
||||
results = subject.get(bob)
|
||||
|
||||
# eve is returned through eugen
|
||||
expect(results).to include([eve.id, :friends_of_friends])
|
||||
|
||||
# john is not reachable because alice hides who she follows
|
||||
expect(results).to_not include([john.id, :friends_of_friends])
|
||||
|
||||
# mallory is not discoverable
|
||||
expect(results).to_not include([mallory.id, :friends_of_friends])
|
||||
|
||||
# larry is not included because he's followed already
|
||||
expect(results).to_not include([larry.id, :friends_of_friends])
|
||||
|
||||
# jerk is blocked
|
||||
expect(results).to_not include([jerk.id, :friends_of_friends])
|
||||
|
||||
# the suggestion for neil has already been rejected
|
||||
expect(results).to_not include([neil.id, :friends_of_friends])
|
||||
end
|
||||
end
|
||||
|
||||
context 'with deterministic order' do
|
||||
before do
|
||||
# bob follows eve and mallory
|
||||
[eve, mallory].each { |account| bob.follow!(account) }
|
||||
|
||||
# eve follows eugen, john, and jerk
|
||||
[jerk, eugen, john].each { |account| eve.follow!(account) }
|
||||
|
||||
# mallory follows eugen, john, and neil
|
||||
[neil, eugen, john].each { |account| mallory.follow!(account) }
|
||||
|
||||
john.follow!(eugen)
|
||||
john.follow!(neil)
|
||||
end
|
||||
|
||||
it 'returns eligible accounts in the expected order' do
|
||||
expect(subject.get(bob)).to eq expected_results
|
||||
end
|
||||
|
||||
it 'contains correct underlying source data' do
|
||||
expect(source_query_values)
|
||||
.to contain_exactly(
|
||||
[john.id, 2, 2], # Followed by 2 friends of bob (eve, mallory), 2 followers total (breaks tie)
|
||||
[eugen.id, 2, 3], # Followed by 2 friends of bob (eve, mallory), 3 followers total
|
||||
[jerk.id, 1, 1], # Followed by 1 friends of bob (eve), 1 followers total (breaks tie)
|
||||
[neil.id, 1, 2] # Followed by 1 friends of bob (mallory), 2 followers total
|
||||
)
|
||||
end
|
||||
|
||||
def expected_results
|
||||
[
|
||||
[john.id, :friends_of_friends],
|
||||
[eugen.id, :friends_of_friends],
|
||||
[jerk.id, :friends_of_friends],
|
||||
[neil.id, :friends_of_friends],
|
||||
]
|
||||
end
|
||||
|
||||
def source_query_values
|
||||
subject.source_query(bob).to_a
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -32,4 +32,12 @@ RSpec.describe CustomFilter do
|
|||
expect(record).to model_have_error_on_field(:context)
|
||||
end
|
||||
end
|
||||
|
||||
describe 'Normalizations' do
|
||||
it 'cleans up context values' do
|
||||
record = described_class.new(context: ['home', 'notifications', 'public ', ''])
|
||||
|
||||
expect(record.context).to eq(%w(home notifications public))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -30,7 +30,7 @@ RSpec.describe Form::Import do
|
|||
|
||||
it 'has errors' do
|
||||
subject.validate
|
||||
expect(subject.errors[:data]).to include(I18n.t('imports.errors.over_rows_processing_limit', count: Form::Import::ROWS_PROCESSING_LIMIT))
|
||||
expect(subject.errors[:data]).to include(I18n.t('imports.errors.over_rows_processing_limit', count: described_class::ROWS_PROCESSING_LIMIT))
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -8,7 +8,7 @@ describe PrivacyPolicy do
|
|||
it 'has the privacy text' do
|
||||
policy = described_class.current
|
||||
|
||||
expect(policy.text).to eq(PrivacyPolicy::DEFAULT_PRIVACY_POLICY)
|
||||
expect(policy.text).to eq(described_class::DEFAULT_PRIVACY_POLICY)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -22,7 +22,7 @@ RSpec.describe Tag do
|
|||
end
|
||||
|
||||
describe 'HASHTAG_RE' do
|
||||
subject { Tag::HASHTAG_RE }
|
||||
subject { described_class::HASHTAG_RE }
|
||||
|
||||
it 'does not match URLs with anchors with non-hashtag characters' do
|
||||
expect(subject.match('Check this out https://medium.com/@alice/some-article#.abcdef123')).to be_nil
|
||||
|
|
|
@ -8,7 +8,7 @@ RSpec.describe UserRole do
|
|||
describe '#can?' do
|
||||
context 'with a single flag' do
|
||||
it 'returns true if any of them are present' do
|
||||
subject.permissions = UserRole::FLAGS[:manage_reports]
|
||||
subject.permissions = described_class::FLAGS[:manage_reports]
|
||||
expect(subject.can?(:manage_reports)).to be true
|
||||
end
|
||||
|
||||
|
@ -19,7 +19,7 @@ RSpec.describe UserRole do
|
|||
|
||||
context 'with multiple flags' do
|
||||
it 'returns true if any of them are present' do
|
||||
subject.permissions = UserRole::FLAGS[:manage_users]
|
||||
subject.permissions = described_class::FLAGS[:manage_users]
|
||||
expect(subject.can?(:manage_reports, :manage_users)).to be true
|
||||
end
|
||||
|
||||
|
@ -51,7 +51,7 @@ RSpec.describe UserRole do
|
|||
|
||||
describe '#permissions_as_keys' do
|
||||
before do
|
||||
subject.permissions = UserRole::FLAGS[:invite_users] | UserRole::FLAGS[:view_dashboard] | UserRole::FLAGS[:manage_reports]
|
||||
subject.permissions = described_class::FLAGS[:invite_users] | described_class::FLAGS[:view_dashboard] | described_class::FLAGS[:manage_reports]
|
||||
end
|
||||
|
||||
it 'returns an array' do
|
||||
|
@ -70,7 +70,7 @@ RSpec.describe UserRole do
|
|||
let(:input) { %w(manage_users) }
|
||||
|
||||
it 'sets permission flags' do
|
||||
expect(subject.permissions).to eq UserRole::FLAGS[:manage_users]
|
||||
expect(subject.permissions).to eq described_class::FLAGS[:manage_users]
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -78,7 +78,7 @@ RSpec.describe UserRole do
|
|||
let(:input) { %w(manage_users manage_reports) }
|
||||
|
||||
it 'sets permission flags' do
|
||||
expect(subject.permissions).to eq UserRole::FLAGS[:manage_users] | UserRole::FLAGS[:manage_reports]
|
||||
expect(subject.permissions).to eq described_class::FLAGS[:manage_users] | described_class::FLAGS[:manage_reports]
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -86,7 +86,7 @@ RSpec.describe UserRole do
|
|||
let(:input) { %w(foo) }
|
||||
|
||||
it 'does not set permission flags' do
|
||||
expect(subject.permissions).to eq UserRole::Flags::NONE
|
||||
expect(subject.permissions).to eq described_class::Flags::NONE
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -96,7 +96,7 @@ RSpec.describe UserRole do
|
|||
subject { described_class.nobody }
|
||||
|
||||
it 'returns none' do
|
||||
expect(subject.computed_permissions).to eq UserRole::Flags::NONE
|
||||
expect(subject.computed_permissions).to eq described_class::Flags::NONE
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -110,11 +110,11 @@ RSpec.describe UserRole do
|
|||
|
||||
context 'when role has the administrator flag' do
|
||||
before do
|
||||
subject.permissions = UserRole::FLAGS[:administrator]
|
||||
subject.permissions = described_class::FLAGS[:administrator]
|
||||
end
|
||||
|
||||
it 'returns all permissions' do
|
||||
expect(subject.computed_permissions).to eq UserRole::Flags::ALL
|
||||
expect(subject.computed_permissions).to eq described_class::Flags::ALL
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -159,7 +159,7 @@ RSpec.describe UserRole do
|
|||
end
|
||||
|
||||
it 'has no permissions' do
|
||||
expect(subject.permissions).to eq UserRole::Flags::NONE
|
||||
expect(subject.permissions).to eq described_class::Flags::NONE
|
||||
end
|
||||
|
||||
it 'has negative position' do
|
||||
|
|
|
@ -24,7 +24,7 @@ RSpec.describe UserSettings do
|
|||
|
||||
context 'when setting was not defined' do
|
||||
it 'raises error' do
|
||||
expect { subject[:foo] }.to raise_error UserSettings::KeyError
|
||||
expect { subject[:foo] }.to raise_error described_class::KeyError
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -93,7 +93,7 @@ RSpec.describe UserSettings do
|
|||
describe '.definition_for' do
|
||||
context 'when key is defined' do
|
||||
it 'returns a setting' do
|
||||
expect(described_class.definition_for(:always_send_emails)).to be_a UserSettings::Setting
|
||||
expect(described_class.definition_for(:always_send_emails)).to be_a described_class::Setting
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -21,6 +21,7 @@ require 'paperclip/matchers'
|
|||
require 'capybara/rspec'
|
||||
require 'chewy/rspec'
|
||||
require 'email_spec/rspec'
|
||||
require 'test_prof/recipes/rspec/before_all'
|
||||
|
||||
Dir[Rails.root.join('spec', 'support', '**', '*.rb')].each { |f| require f }
|
||||
|
||||
|
|
|
@ -15,15 +15,11 @@ RSpec.describe 'credentials API' do
|
|||
|
||||
it_behaves_like 'forbidden for wrong scope', 'write write:accounts'
|
||||
|
||||
it 'returns http success' do
|
||||
subject
|
||||
|
||||
expect(response).to have_http_status(200)
|
||||
end
|
||||
|
||||
it 'returns the expected content' do
|
||||
it 'returns http success with expected content' do
|
||||
subject
|
||||
|
||||
expect(response)
|
||||
.to have_http_status(200)
|
||||
expect(body_as_json).to include({
|
||||
source: hash_including({
|
||||
discoverable: false,
|
||||
|
@ -34,24 +30,55 @@ RSpec.describe 'credentials API' do
|
|||
end
|
||||
end
|
||||
|
||||
describe 'POST /api/v1/accounts/update_credentials' do
|
||||
describe 'PATCH /api/v1/accounts/update_credentials' do
|
||||
subject do
|
||||
patch '/api/v1/accounts/update_credentials', headers: headers, params: params
|
||||
end
|
||||
|
||||
let(:params) { { discoverable: true, locked: false, indexable: true } }
|
||||
before { allow(ActivityPub::UpdateDistributionWorker).to receive(:perform_async) }
|
||||
|
||||
let(:params) do
|
||||
{
|
||||
avatar: fixture_file_upload('avatar.gif', 'image/gif'),
|
||||
discoverable: true,
|
||||
display_name: "Alice Isn't Dead",
|
||||
header: fixture_file_upload('attachment.jpg', 'image/jpeg'),
|
||||
indexable: true,
|
||||
locked: false,
|
||||
note: 'Hello!',
|
||||
source: {
|
||||
privacy: 'unlisted',
|
||||
sensitive: true,
|
||||
},
|
||||
}
|
||||
end
|
||||
|
||||
it_behaves_like 'forbidden for wrong scope', 'read read:accounts'
|
||||
|
||||
it 'returns http success' do
|
||||
subject
|
||||
describe 'with empty source list' do
|
||||
let(:params) { { display_name: "I'm a cat", source: {} } }
|
||||
|
||||
expect(response).to have_http_status(200)
|
||||
it 'returns http success' do
|
||||
subject
|
||||
expect(response).to have_http_status(200)
|
||||
end
|
||||
end
|
||||
|
||||
it 'returns JSON with updated attributes' do
|
||||
describe 'with invalid data' do
|
||||
let(:params) { { note: 'This is too long. ' * 30 } }
|
||||
|
||||
it 'returns http unprocessable entity' do
|
||||
subject
|
||||
expect(response).to have_http_status(422)
|
||||
end
|
||||
end
|
||||
|
||||
it 'returns http success with updated JSON attributes' do
|
||||
subject
|
||||
|
||||
expect(response)
|
||||
.to have_http_status(200)
|
||||
|
||||
expect(body_as_json).to include({
|
||||
source: hash_including({
|
||||
discoverable: true,
|
||||
|
@ -59,6 +86,27 @@ RSpec.describe 'credentials API' do
|
|||
}),
|
||||
locked: false,
|
||||
})
|
||||
|
||||
expect(ActivityPub::UpdateDistributionWorker)
|
||||
.to have_received(:perform_async).with(user.account_id)
|
||||
end
|
||||
|
||||
def expect_account_updates
|
||||
expect(user.account.reload)
|
||||
.to have_attributes(
|
||||
display_name: eq("Alice Isn't Dead"),
|
||||
note: 'Hello!',
|
||||
avatar: exist,
|
||||
header: exist
|
||||
)
|
||||
end
|
||||
|
||||
def expect_user_updates
|
||||
expect(user.reload)
|
||||
.to have_attributes(
|
||||
setting_default_privacy: eq('unlisted'),
|
||||
setting_default_sensitive: be(true)
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -38,16 +38,14 @@ RSpec.describe 'Blocks' do
|
|||
expect(body_as_json.size).to eq(params[:limit])
|
||||
end
|
||||
|
||||
it 'sets the correct pagination header for the prev path' do
|
||||
it 'sets correct link header pagination' do
|
||||
subject
|
||||
|
||||
expect(response.headers['Link'].find_link(%w(rel prev)).href).to eq(api_v1_blocks_url(limit: params[:limit], since_id: blocks.last.id))
|
||||
end
|
||||
|
||||
it 'sets the correct pagination header for the next path' do
|
||||
subject
|
||||
|
||||
expect(response.headers['Link'].find_link(%w(rel next)).href).to eq(api_v1_blocks_url(limit: params[:limit], max_id: blocks[1].id))
|
||||
expect(response)
|
||||
.to include_pagination_headers(
|
||||
prev: api_v1_blocks_url(limit: params[:limit], since_id: blocks.last.id),
|
||||
next: api_v1_blocks_url(limit: params[:limit], max_id: blocks.second.id)
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -42,9 +42,14 @@ RSpec.describe 'Bookmarks' do
|
|||
it 'paginates correctly', :aggregate_failures do
|
||||
subject
|
||||
|
||||
expect(body_as_json.size).to eq(params[:limit])
|
||||
expect(response.headers['Link'].find_link(%w(rel prev)).href).to eq(api_v1_bookmarks_url(limit: params[:limit], min_id: bookmarks.last.id))
|
||||
expect(response.headers['Link'].find_link(%w(rel next)).href).to eq(api_v1_bookmarks_url(limit: params[:limit], max_id: bookmarks[1].id))
|
||||
expect(body_as_json.size)
|
||||
.to eq(params[:limit])
|
||||
|
||||
expect(response)
|
||||
.to include_pagination_headers(
|
||||
prev: api_v1_bookmarks_url(limit: params[:limit], min_id: bookmarks.last.id),
|
||||
next: api_v1_bookmarks_url(limit: params[:limit], max_id: bookmarks.second.id)
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -45,16 +45,14 @@ RSpec.describe 'Favourites' do
|
|||
expect(body_as_json.size).to eq(params[:limit])
|
||||
end
|
||||
|
||||
it 'sets the correct pagination header for the prev path' do
|
||||
it 'sets the correct pagination headers' do
|
||||
subject
|
||||
|
||||
expect(response.headers['Link'].find_link(%w(rel prev)).href).to eq(api_v1_favourites_url(limit: params[:limit], min_id: favourites.last.id))
|
||||
end
|
||||
|
||||
it 'sets the correct pagination header for the next path' do
|
||||
subject
|
||||
|
||||
expect(response.headers['Link'].find_link(%w(rel next)).href).to eq(api_v1_favourites_url(limit: params[:limit], max_id: favourites[1].id))
|
||||
expect(response)
|
||||
.to include_pagination_headers(
|
||||
prev: api_v1_favourites_url(limit: params[:limit], min_id: favourites.last.id),
|
||||
next: api_v1_favourites_url(limit: params[:limit], max_id: favourites.second.id)
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -49,16 +49,14 @@ RSpec.describe 'Followed tags' do
|
|||
expect(body_as_json.size).to eq(params[:limit])
|
||||
end
|
||||
|
||||
it 'sets the correct pagination header for the prev path' do
|
||||
it 'sets the correct pagination headers' do
|
||||
subject
|
||||
|
||||
expect(response.headers['Link'].find_link(%w(rel prev)).href).to eq(api_v1_followed_tags_url(limit: params[:limit], since_id: tag_follows.last.id))
|
||||
end
|
||||
|
||||
it 'sets the correct pagination header for the next path' do
|
||||
subject
|
||||
|
||||
expect(response.headers['Link'].find_link(%w(rel next)).href).to eq(api_v1_followed_tags_url(limit: params[:limit], max_id: tag_follows.last.id))
|
||||
expect(response)
|
||||
.to include_pagination_headers(
|
||||
prev: api_v1_followed_tags_url(limit: params[:limit], since_id: tag_follows.last.id),
|
||||
next: api_v1_followed_tags_url(limit: params[:limit], max_id: tag_follows.last.id)
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -44,10 +44,11 @@ RSpec.describe 'Mutes' do
|
|||
it 'sets the correct pagination headers', :aggregate_failures do
|
||||
subject
|
||||
|
||||
headers = response.headers['Link']
|
||||
|
||||
expect(headers.find_link(%w(rel prev)).href).to eq(api_v1_mutes_url(limit: params[:limit], since_id: mutes.last.id.to_s))
|
||||
expect(headers.find_link(%w(rel next)).href).to eq(api_v1_mutes_url(limit: params[:limit], max_id: mutes.last.id.to_s))
|
||||
expect(response)
|
||||
.to include_pagination_headers(
|
||||
prev: api_v1_mutes_url(limit: params[:limit], since_id: mutes.last.id),
|
||||
next: api_v1_mutes_url(limit: params[:limit], max_id: mutes.last.id)
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -98,9 +98,14 @@ RSpec.describe 'Notifications' do
|
|||
|
||||
notifications = user.account.notifications
|
||||
|
||||
expect(body_as_json.size).to eq(params[:limit])
|
||||
expect(response.headers['Link'].find_link(%w(rel prev)).href).to eq(api_v1_notifications_url(limit: params[:limit], min_id: notifications.last.id.to_s))
|
||||
expect(response.headers['Link'].find_link(%w(rel next)).href).to eq(api_v1_notifications_url(limit: params[:limit], max_id: notifications[2].id.to_s))
|
||||
expect(body_as_json.size)
|
||||
.to eq(params[:limit])
|
||||
|
||||
expect(response)
|
||||
.to include_pagination_headers(
|
||||
prev: api_v1_notifications_url(limit: params[:limit], min_id: notifications.last.id),
|
||||
next: api_v1_notifications_url(limit: params[:limit], max_id: notifications[2].id)
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -55,10 +55,11 @@ describe 'Home', :sidekiq_inline do
|
|||
it 'sets the correct pagination headers', :aggregate_failures do
|
||||
subject
|
||||
|
||||
headers = response.headers['Link']
|
||||
|
||||
expect(headers.find_link(%w(rel prev)).href).to eq(api_v1_timelines_home_url(limit: 1, min_id: ana.statuses.first.id.to_s))
|
||||
expect(headers.find_link(%w(rel next)).href).to eq(api_v1_timelines_home_url(limit: 1, max_id: ana.statuses.first.id.to_s))
|
||||
expect(response)
|
||||
.to include_pagination_headers(
|
||||
prev: api_v1_timelines_home_url(limit: params[:limit], min_id: ana.statuses.first.id),
|
||||
next: api_v1_timelines_home_url(limit: params[:limit], max_id: ana.statuses.first.id)
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -106,10 +106,11 @@ describe 'Public' do
|
|||
it 'sets the correct pagination headers', :aggregate_failures do
|
||||
subject
|
||||
|
||||
headers = response.headers['Link']
|
||||
|
||||
expect(headers.find_link(%w(rel prev)).href).to eq(api_v1_timelines_public_url(limit: 1, min_id: media_status.id.to_s))
|
||||
expect(headers.find_link(%w(rel next)).href).to eq(api_v1_timelines_public_url(limit: 1, max_id: media_status.id.to_s))
|
||||
expect(response)
|
||||
.to include_pagination_headers(
|
||||
prev: api_v1_timelines_public_url(limit: params[:limit], min_id: media_status.id),
|
||||
next: api_v1_timelines_public_url(limit: params[:limit], max_id: media_status.id)
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -71,10 +71,11 @@ RSpec.describe 'Tag' do
|
|||
it 'sets the correct pagination headers', :aggregate_failures do
|
||||
subject
|
||||
|
||||
headers = response.headers['Link']
|
||||
|
||||
expect(headers.find_link(%w(rel prev)).href).to eq(api_v1_timelines_tag_url(limit: 1, min_id: love_status.id.to_s))
|
||||
expect(headers.find_link(%w(rel next)).href).to eq(api_v1_timelines_tag_url(limit: 1, max_id: love_status.id.to_s))
|
||||
expect(response)
|
||||
.to include_pagination_headers(
|
||||
prev: api_v1_timelines_tag_url(limit: params[:limit], min_id: love_status.id),
|
||||
next: api_v1_timelines_tag_url(limit: params[:limit], max_id: love_status.id)
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -2,25 +2,20 @@
|
|||
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe Api::V2::Filters::KeywordsController do
|
||||
render_views
|
||||
|
||||
RSpec.describe 'API V2 Filters Keywords' do
|
||||
let(:user) { Fabricate(:user) }
|
||||
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) }
|
||||
let(:filter) { Fabricate(:custom_filter, account: user.account) }
|
||||
let(:other_user) { Fabricate(:user) }
|
||||
let(:other_filter) { Fabricate(:custom_filter, account: other_user.account) }
|
||||
let(:headers) { { 'Authorization' => "Bearer #{token.token}" } }
|
||||
|
||||
before do
|
||||
allow(controller).to receive(:doorkeeper_token) { token }
|
||||
end
|
||||
|
||||
describe 'GET #index' do
|
||||
describe 'GET /api/v2/filters/:filter_id/keywords' do
|
||||
let(:scopes) { 'read:filters' }
|
||||
let!(:keyword) { Fabricate(:custom_filter_keyword, custom_filter: filter) }
|
||||
|
||||
it 'returns http success' do
|
||||
get :index, params: { filter_id: filter.id }
|
||||
get "/api/v2/filters/#{filter.id}/keywords", headers: headers
|
||||
expect(response).to have_http_status(200)
|
||||
expect(body_as_json)
|
||||
.to contain_exactly(
|
||||
|
@ -30,18 +25,18 @@ RSpec.describe Api::V2::Filters::KeywordsController do
|
|||
|
||||
context "when trying to access another's user filters" do
|
||||
it 'returns http not found' do
|
||||
get :index, params: { filter_id: other_filter.id }
|
||||
get "/api/v2/filters/#{other_filter.id}/keywords", headers: headers
|
||||
expect(response).to have_http_status(404)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'POST #create' do
|
||||
describe 'POST /api/v2/filters/:filter_id/keywords' do
|
||||
let(:scopes) { 'write:filters' }
|
||||
let(:filter_id) { filter.id }
|
||||
|
||||
before do
|
||||
post :create, params: { filter_id: filter_id, keyword: 'magic', whole_word: false }
|
||||
post "/api/v2/filters/#{filter_id}/keywords", headers: headers, params: { keyword: 'magic', whole_word: false }
|
||||
end
|
||||
|
||||
it 'creates a filter', :aggregate_failures do
|
||||
|
@ -65,12 +60,12 @@ RSpec.describe Api::V2::Filters::KeywordsController do
|
|||
end
|
||||
end
|
||||
|
||||
describe 'GET #show' do
|
||||
describe 'GET /api/v2/filters/keywords/:id' do
|
||||
let(:scopes) { 'read:filters' }
|
||||
let(:keyword) { Fabricate(:custom_filter_keyword, keyword: 'foo', whole_word: false, custom_filter: filter) }
|
||||
|
||||
before do
|
||||
get :show, params: { id: keyword.id }
|
||||
get "/api/v2/filters/keywords/#{keyword.id}", headers: headers
|
||||
end
|
||||
|
||||
it 'responds with the keyword', :aggregate_failures do
|
||||
|
@ -90,12 +85,12 @@ RSpec.describe Api::V2::Filters::KeywordsController do
|
|||
end
|
||||
end
|
||||
|
||||
describe 'PUT #update' do
|
||||
describe 'PUT /api/v2/filters/keywords/:id' do
|
||||
let(:scopes) { 'write:filters' }
|
||||
let(:keyword) { Fabricate(:custom_filter_keyword, custom_filter: filter) }
|
||||
|
||||
before do
|
||||
get :update, params: { id: keyword.id, keyword: 'updated' }
|
||||
put "/api/v2/filters/keywords/#{keyword.id}", headers: headers, params: { keyword: 'updated' }
|
||||
end
|
||||
|
||||
it 'updates the keyword', :aggregate_failures do
|
||||
|
@ -113,12 +108,12 @@ RSpec.describe Api::V2::Filters::KeywordsController do
|
|||
end
|
||||
end
|
||||
|
||||
describe 'DELETE #destroy' do
|
||||
describe 'DELETE /api/v2/filters/keywords/:id' do
|
||||
let(:scopes) { 'write:filters' }
|
||||
let(:keyword) { Fabricate(:custom_filter_keyword, custom_filter: filter) }
|
||||
|
||||
before do
|
||||
delete :destroy, params: { id: keyword.id }
|
||||
delete "/api/v2/filters/keywords/#{keyword.id}", headers: headers
|
||||
end
|
||||
|
||||
it 'destroys the keyword', :aggregate_failures do
|
|
@ -2,25 +2,20 @@
|
|||
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe Api::V2::Filters::StatusesController do
|
||||
render_views
|
||||
|
||||
RSpec.describe 'API V2 Filters Statuses' do
|
||||
let(:user) { Fabricate(:user) }
|
||||
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) }
|
||||
let(:filter) { Fabricate(:custom_filter, account: user.account) }
|
||||
let(:other_user) { Fabricate(:user) }
|
||||
let(:other_filter) { Fabricate(:custom_filter, account: other_user.account) }
|
||||
let(:headers) { { 'Authorization' => "Bearer #{token.token}" } }
|
||||
|
||||
before do
|
||||
allow(controller).to receive(:doorkeeper_token) { token }
|
||||
end
|
||||
|
||||
describe 'GET #index' do
|
||||
describe 'GET /api/v2/filters/:filter_id/statuses' do
|
||||
let(:scopes) { 'read:filters' }
|
||||
let!(:status_filter) { Fabricate(:custom_filter_status, custom_filter: filter) }
|
||||
|
||||
it 'returns http success' do
|
||||
get :index, params: { filter_id: filter.id }
|
||||
get "/api/v2/filters/#{filter.id}/statuses", headers: headers
|
||||
expect(response).to have_http_status(200)
|
||||
expect(body_as_json)
|
||||
.to contain_exactly(
|
||||
|
@ -30,7 +25,7 @@ RSpec.describe Api::V2::Filters::StatusesController do
|
|||
|
||||
context "when trying to access another's user filters" do
|
||||
it 'returns http not found' do
|
||||
get :index, params: { filter_id: other_filter.id }
|
||||
get "/api/v2/filters/#{other_filter.id}/statuses", headers: headers
|
||||
expect(response).to have_http_status(404)
|
||||
end
|
||||
end
|
||||
|
@ -42,7 +37,7 @@ RSpec.describe Api::V2::Filters::StatusesController do
|
|||
let!(:status) { Fabricate(:status) }
|
||||
|
||||
before do
|
||||
post :create, params: { filter_id: filter_id, status_id: status.id }
|
||||
post "/api/v2/filters/#{filter_id}/statuses", headers: headers, params: { status_id: status.id }
|
||||
end
|
||||
|
||||
it 'creates a filter', :aggregate_failures do
|
||||
|
@ -65,12 +60,12 @@ RSpec.describe Api::V2::Filters::StatusesController do
|
|||
end
|
||||
end
|
||||
|
||||
describe 'GET #show' do
|
||||
describe 'GET /api/v2/filters/statuses/:id' do
|
||||
let(:scopes) { 'read:filters' }
|
||||
let!(:status_filter) { Fabricate(:custom_filter_status, custom_filter: filter) }
|
||||
|
||||
before do
|
||||
get :show, params: { id: status_filter.id }
|
||||
get "/api/v2/filters/statuses/#{status_filter.id}", headers: headers
|
||||
end
|
||||
|
||||
it 'responds with the filter', :aggregate_failures do
|
||||
|
@ -89,12 +84,12 @@ RSpec.describe Api::V2::Filters::StatusesController do
|
|||
end
|
||||
end
|
||||
|
||||
describe 'DELETE #destroy' do
|
||||
describe 'DELETE /api/v2/filters/statuses/:id' do
|
||||
let(:scopes) { 'write:filters' }
|
||||
let(:status_filter) { Fabricate(:custom_filter_status, custom_filter: filter) }
|
||||
|
||||
before do
|
||||
delete :destroy, params: { id: status_filter.id }
|
||||
delete "/api/v2/filters/statuses/#{status_filter.id}", headers: headers
|
||||
end
|
||||
|
||||
it 'destroys the filter', :aggregate_failures do
|
|
@ -39,7 +39,7 @@ module TestEndpoints
|
|||
/api/v1/accounts/lookup?acct=alice
|
||||
/api/v1/statuses/110224538612341312
|
||||
/api/v1/statuses/110224538612341312/context
|
||||
/api/v1/polls/12345
|
||||
/api/v1/polls/123456789
|
||||
/api/v1/trends/statuses
|
||||
/api/v1/directory
|
||||
).freeze
|
||||
|
@ -166,14 +166,18 @@ describe 'Caching behavior' do
|
|||
ActionController::Base.allow_forgery_protection = old
|
||||
end
|
||||
|
||||
let(:alice) { Fabricate(:account, username: 'alice') }
|
||||
let(:user) { Fabricate(:user, role: UserRole.find_by(name: 'Moderator')) }
|
||||
let(:alice) { Account.find_by(username: 'alice') }
|
||||
let(:user) { User.find_by(email: 'user@host.example') }
|
||||
let(:token) { Doorkeeper::AccessToken.find_by(resource_owner_id: user.id) }
|
||||
|
||||
before do
|
||||
status = Fabricate(:status, account: alice, id: '110224538612341312')
|
||||
Fabricate(:status, account: alice, id: '110224538643211312', visibility: :private)
|
||||
before_all do
|
||||
alice = Fabricate(:account, username: 'alice')
|
||||
user = Fabricate(:user, email: 'user@host.example', role: UserRole.find_by(name: 'Moderator'))
|
||||
status = Fabricate(:status, account: alice, id: 110_224_538_612_341_312)
|
||||
Fabricate(:status, account: alice, id: 110_224_538_643_211_312, visibility: :private)
|
||||
Fabricate(:invite, code: 'abcdef')
|
||||
Fabricate(:poll, status: status, account: alice, id: '12345')
|
||||
Fabricate(:poll, status: status, account: alice, id: 123_456_789)
|
||||
Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: 'read')
|
||||
|
||||
user.account.follow!(alice)
|
||||
end
|
||||
|
@ -321,8 +325,6 @@ describe 'Caching behavior' do
|
|||
end
|
||||
|
||||
context 'with an auth token' do
|
||||
let!(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: 'read') }
|
||||
|
||||
TestEndpoints::ALWAYS_CACHED.each do |endpoint|
|
||||
describe endpoint do
|
||||
before do
|
||||
|
@ -585,8 +587,6 @@ describe 'Caching behavior' do
|
|||
end
|
||||
|
||||
context 'with an auth token' do
|
||||
let!(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: 'read') }
|
||||
|
||||
TestEndpoints::ALWAYS_CACHED.each do |endpoint|
|
||||
describe endpoint do
|
||||
before do
|
||||
|
|
|
@ -3,25 +3,38 @@
|
|||
require 'rails_helper'
|
||||
|
||||
describe 'Content-Security-Policy' do
|
||||
it 'sets the expected CSP headers' do
|
||||
allow(SecureRandom).to receive(:base64).with(16).and_return('ZbA+JmE7+bK8F5qvADZHuQ==')
|
||||
before { allow(SecureRandom).to receive(:base64).with(16).and_return('ZbA+JmE7+bK8F5qvADZHuQ==') }
|
||||
|
||||
it 'sets the expected CSP headers' do
|
||||
get '/'
|
||||
expect(response.headers['Content-Security-Policy'].split(';').map(&:strip)).to contain_exactly(
|
||||
"base-uri 'none'",
|
||||
"default-src 'none'",
|
||||
"frame-ancestors 'none'",
|
||||
"font-src 'self' https://cb6e6126.ngrok.io",
|
||||
"img-src 'self' data: blob: https://cb6e6126.ngrok.io",
|
||||
"style-src 'self' https://cb6e6126.ngrok.io 'nonce-ZbA+JmE7+bK8F5qvADZHuQ=='",
|
||||
"media-src 'self' data: https://cb6e6126.ngrok.io",
|
||||
"frame-src 'self' https:",
|
||||
"manifest-src 'self' https://cb6e6126.ngrok.io",
|
||||
"form-action 'self'",
|
||||
"child-src 'self' blob: https://cb6e6126.ngrok.io",
|
||||
"worker-src 'self' blob: https://cb6e6126.ngrok.io",
|
||||
"connect-src 'self' data: blob: https://cb6e6126.ngrok.io ws://cb6e6126.ngrok.io:4000",
|
||||
"script-src 'self' https://cb6e6126.ngrok.io 'wasm-unsafe-eval'"
|
||||
)
|
||||
|
||||
expect(response_csp_headers)
|
||||
.to match_array(expected_csp_headers)
|
||||
end
|
||||
|
||||
def response_csp_headers
|
||||
response
|
||||
.headers['Content-Security-Policy']
|
||||
.split(';')
|
||||
.map(&:strip)
|
||||
end
|
||||
|
||||
def expected_csp_headers
|
||||
<<~CSP.split("\n").map(&:strip)
|
||||
base-uri 'none'
|
||||
child-src 'self' blob: https://cb6e6126.ngrok.io
|
||||
connect-src 'self' data: blob: https://cb6e6126.ngrok.io ws://cb6e6126.ngrok.io:4000
|
||||
default-src 'none'
|
||||
font-src 'self' https://cb6e6126.ngrok.io
|
||||
form-action 'self'
|
||||
frame-ancestors 'none'
|
||||
frame-src 'self' https:
|
||||
img-src 'self' data: blob: https://cb6e6126.ngrok.io
|
||||
manifest-src 'self' https://cb6e6126.ngrok.io
|
||||
media-src 'self' data: https://cb6e6126.ngrok.io
|
||||
script-src 'self' https://cb6e6126.ngrok.io 'wasm-unsafe-eval'
|
||||
style-src 'self' https://cb6e6126.ngrok.io 'nonce-ZbA+JmE7+bK8F5qvADZHuQ=='
|
||||
worker-src 'self' blob: https://cb6e6126.ngrok.io
|
||||
CSP
|
||||
end
|
||||
end
|
||||
|
|
|
@ -21,7 +21,7 @@ describe Account::StatusesSearch, :sidekiq_inline do
|
|||
account.indexable = true
|
||||
account.save!
|
||||
|
||||
expect(PublicStatusesIndex.filter(term: { account_id: account.id }).count).to eq(account.statuses.where(visibility: :public).count)
|
||||
expect(PublicStatusesIndex.filter(term: { account_id: account.id }).count).to eq(account.statuses.public_visibility.count)
|
||||
expect(StatusesIndex.filter(term: { account_id: account.id }).count).to eq(account.statuses.count)
|
||||
end
|
||||
end
|
||||
|
@ -32,7 +32,7 @@ describe Account::StatusesSearch, :sidekiq_inline do
|
|||
|
||||
context 'when picking an indexable account' do
|
||||
it 'has statuses in the PublicStatusesIndex' do
|
||||
expect(PublicStatusesIndex.filter(term: { account_id: account.id }).count).to eq(account.statuses.where(visibility: :public).count)
|
||||
expect(PublicStatusesIndex.filter(term: { account_id: account.id }).count).to eq(account.statuses.public_visibility.count)
|
||||
end
|
||||
|
||||
it 'has statuses in the StatusesIndex' do
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
require 'rails_helper'
|
||||
|
||||
describe AccountSearchService, type: :service do
|
||||
describe AccountSearchService do
|
||||
describe '#call' do
|
||||
context 'with a query to ignore' do
|
||||
it 'returns empty array for missing query' do
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
require 'rails_helper'
|
||||
|
||||
describe AccountStatusesCleanupService, type: :service do
|
||||
describe AccountStatusesCleanupService do
|
||||
let(:account) { Fabricate(:account, username: 'alice', domain: nil) }
|
||||
let(:account_policy) { Fabricate(:account_statuses_cleanup_policy, account: account) }
|
||||
let!(:unrelated_status) { Fabricate(:status, created_at: 3.years.ago) }
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe ActivityPub::FetchFeaturedCollectionService, type: :service do
|
||||
RSpec.describe ActivityPub::FetchFeaturedCollectionService do
|
||||
subject { described_class.new }
|
||||
|
||||
let(:actor) { Fabricate(:account, domain: 'example.com', uri: 'https://example.com/account', featured_collection_url: 'https://example.com/account/pinned') }
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe ActivityPub::FetchFeaturedTagsCollectionService, type: :service do
|
||||
RSpec.describe ActivityPub::FetchFeaturedTagsCollectionService do
|
||||
subject { described_class.new }
|
||||
|
||||
let(:collection_url) { 'https://example.com/account/tags' }
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe ActivityPub::FetchRemoteAccountService, type: :service do
|
||||
RSpec.describe ActivityPub::FetchRemoteAccountService do
|
||||
subject { described_class.new }
|
||||
|
||||
let!(:actor) do
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe ActivityPub::FetchRemoteActorService, type: :service do
|
||||
RSpec.describe ActivityPub::FetchRemoteActorService do
|
||||
subject { described_class.new }
|
||||
|
||||
let!(:actor) do
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe ActivityPub::FetchRemoteKeyService, type: :service do
|
||||
RSpec.describe ActivityPub::FetchRemoteKeyService do
|
||||
subject { described_class.new }
|
||||
|
||||
let(:webfinger) { { subject: 'acct:alice@example.com', links: [{ rel: 'self', href: 'https://example.com/alice' }] } }
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe ActivityPub::FetchRemoteStatusService, type: :service do
|
||||
RSpec.describe ActivityPub::FetchRemoteStatusService do
|
||||
include ActionView::Helpers::TextHelper
|
||||
|
||||
subject { described_class.new }
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe ActivityPub::FetchRepliesService, type: :service do
|
||||
RSpec.describe ActivityPub::FetchRepliesService do
|
||||
subject { described_class.new }
|
||||
|
||||
let(:actor) { Fabricate(:account, domain: 'example.com', uri: 'http://example.com/account') }
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe ActivityPub::ProcessAccountService, type: :service do
|
||||
RSpec.describe ActivityPub::ProcessAccountService do
|
||||
subject { described_class.new }
|
||||
|
||||
before do
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe ActivityPub::ProcessCollectionService, type: :service do
|
||||
RSpec.describe ActivityPub::ProcessCollectionService do
|
||||
subject { described_class.new }
|
||||
|
||||
let(:actor) { Fabricate(:account, domain: 'example.com', uri: 'http://example.com/account') }
|
||||
|
|
|
@ -6,7 +6,7 @@ def poll_option_json(name, votes)
|
|||
{ type: 'Note', name: name, replies: { type: 'Collection', totalItems: votes } }
|
||||
end
|
||||
|
||||
RSpec.describe ActivityPub::ProcessStatusUpdateService, type: :service do
|
||||
RSpec.describe ActivityPub::ProcessStatusUpdateService do
|
||||
subject { described_class.new }
|
||||
|
||||
let(:thread) { nil }
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe ActivityPub::SynchronizeFollowersService, type: :service do
|
||||
RSpec.describe ActivityPub::SynchronizeFollowersService do
|
||||
subject { described_class.new }
|
||||
|
||||
let(:actor) { Fabricate(:account, domain: 'example.com', uri: 'http://example.com/account', inbox_url: 'http://example.com/inbox') }
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe AfterBlockDomainFromAccountService, type: :service do
|
||||
RSpec.describe AfterBlockDomainFromAccountService do
|
||||
subject { described_class.new }
|
||||
|
||||
let!(:wolf) { Fabricate(:account, username: 'wolf', domain: 'evil.org', inbox_url: 'https://evil.org/inbox', protocol: :activitypub) }
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe AfterBlockService, type: :service do
|
||||
RSpec.describe AfterBlockService do
|
||||
subject { described_class.new.call(account, target_account) }
|
||||
|
||||
let(:account) { Fabricate(:account) }
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe AppSignUpService, type: :service do
|
||||
RSpec.describe AppSignUpService do
|
||||
subject { described_class.new }
|
||||
|
||||
let(:app) { Fabricate(:application, scopes: 'read write') }
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe AuthorizeFollowService, type: :service do
|
||||
RSpec.describe AuthorizeFollowService do
|
||||
subject { described_class.new }
|
||||
|
||||
let(:sender) { Fabricate(:account, username: 'alice') }
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe BackupService, type: :service do
|
||||
RSpec.describe BackupService do
|
||||
subject(:service_call) { described_class.new.call(backup) }
|
||||
|
||||
let!(:user) { Fabricate(:user) }
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe BatchedRemoveStatusService, :sidekiq_inline, type: :service do
|
||||
RSpec.describe BatchedRemoveStatusService, :sidekiq_inline do
|
||||
subject { described_class.new }
|
||||
|
||||
let!(:alice) { Fabricate(:account) }
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe BlockDomainService, type: :service do
|
||||
RSpec.describe BlockDomainService do
|
||||
subject { described_class.new }
|
||||
|
||||
let!(:bad_account) { Fabricate(:account, username: 'badguy666', domain: 'evil.org') }
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe BlockService, type: :service do
|
||||
RSpec.describe BlockService do
|
||||
subject { described_class.new }
|
||||
|
||||
let(:sender) { Fabricate(:account, username: 'alice') }
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe BootstrapTimelineService, type: :service do
|
||||
RSpec.describe BootstrapTimelineService do
|
||||
subject { described_class.new }
|
||||
|
||||
context 'when the new user has registered from an invite' do
|
||||
|
|
|
@ -110,7 +110,7 @@ RSpec.describe BulkImportRowService do
|
|||
end
|
||||
|
||||
it 'adds the target account to the list' do
|
||||
expect { subject.call(import_row) }.to change { ListAccount.joins(:list).exists?(account_id: target_account.id, list: { title: 'my list' }) }.from(false).to(true)
|
||||
expect { subject.call(import_row) }.to add_target_account_to_list
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -124,7 +124,7 @@ RSpec.describe BulkImportRowService do
|
|||
end
|
||||
|
||||
it 'adds the target account to the list' do
|
||||
expect { subject.call(import_row) }.to change { ListAccount.joins(:list).exists?(account_id: target_account.id, list: { title: 'my list' }) }.from(false).to(true)
|
||||
expect { subject.call(import_row) }.to add_target_account_to_list
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -134,7 +134,7 @@ RSpec.describe BulkImportRowService do
|
|||
end
|
||||
|
||||
it 'adds the target account to the list' do
|
||||
expect { subject.call(import_row) }.to change { ListAccount.joins(:list).exists?(account_id: target_account.id, list: { title: 'my list' }) }.from(false).to(true)
|
||||
expect { subject.call(import_row) }.to add_target_account_to_list
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -146,9 +146,24 @@ RSpec.describe BulkImportRowService do
|
|||
end
|
||||
|
||||
it 'adds the target account to the list' do
|
||||
expect { subject.call(import_row) }.to change { ListAccount.joins(:list).exists?(account_id: target_account.id, list: { title: 'my list' }) }.from(false).to(true)
|
||||
expect { subject.call(import_row) }.to add_target_account_to_list
|
||||
end
|
||||
end
|
||||
|
||||
def add_target_account_to_list
|
||||
change { target_account_on_list? }
|
||||
.from(false)
|
||||
.to(true)
|
||||
end
|
||||
|
||||
def target_account_on_list?
|
||||
ListAccount
|
||||
.joins(:list)
|
||||
.exists?(
|
||||
account_id: target_account.id,
|
||||
list: { title: 'my list' }
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the list does not exist yet' do
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe ClearDomainMediaService, type: :service do
|
||||
RSpec.describe ClearDomainMediaService do
|
||||
subject { described_class.new }
|
||||
|
||||
let!(:bad_account) { Fabricate(:account, username: 'badguy666', domain: 'evil.org') }
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe DeleteAccountService, type: :service do
|
||||
RSpec.describe DeleteAccountService do
|
||||
shared_examples 'common behavior' do
|
||||
subject { described_class.new.call(account) }
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe FanOutOnWriteService, type: :service do
|
||||
RSpec.describe FanOutOnWriteService do
|
||||
subject { described_class.new }
|
||||
|
||||
let(:ltl_enabled) { true }
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe FavouriteService, type: :service do
|
||||
RSpec.describe FavouriteService do
|
||||
subject { described_class.new }
|
||||
|
||||
let(:sender) { Fabricate(:account, username: 'alice') }
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe FetchLinkCardService, type: :service do
|
||||
RSpec.describe FetchLinkCardService do
|
||||
subject { described_class.new }
|
||||
|
||||
let(:html) { '<!doctype html><title>Hello world</title>' }
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
require 'rails_helper'
|
||||
|
||||
describe FetchOEmbedService, type: :service do
|
||||
describe FetchOEmbedService do
|
||||
subject { described_class.new }
|
||||
|
||||
before do
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe FetchRemoteStatusService, type: :service do
|
||||
RSpec.describe FetchRemoteStatusService do
|
||||
let(:account) { Fabricate(:account, domain: 'example.org', uri: 'https://example.org/foo') }
|
||||
let(:prefetched_body) { nil }
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe FetchResourceService, type: :service do
|
||||
RSpec.describe FetchResourceService do
|
||||
describe '#call' do
|
||||
subject { described_class.new.call(url) }
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe FollowService, type: :service do
|
||||
RSpec.describe FollowService do
|
||||
subject { described_class.new }
|
||||
|
||||
let(:sender) { Fabricate(:account, username: 'alice') }
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe ImportService, :sidekiq_inline, type: :service do
|
||||
RSpec.describe ImportService, :sidekiq_inline do
|
||||
include RoutingHelper
|
||||
|
||||
let!(:account) { Fabricate(:account, locked: false) }
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe MuteService, type: :service do
|
||||
RSpec.describe MuteService do
|
||||
subject { described_class.new.call(account, target_account) }
|
||||
|
||||
let(:account) { Fabricate(:account) }
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe NotifyService, type: :service do
|
||||
RSpec.describe NotifyService do
|
||||
subject { described_class.new.call(recipient, type, activity) }
|
||||
|
||||
let(:user) { Fabricate(:user) }
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe PostStatusService, type: :service do
|
||||
RSpec.describe PostStatusService do
|
||||
subject { described_class.new }
|
||||
|
||||
it 'creates a new status' do
|
||||
|
@ -481,7 +481,7 @@ RSpec.describe PostStatusService, type: :service do
|
|||
|
||||
expect do
|
||||
subject.call(account, text: '@alice hm, @bob is really annoying lately', allowed_mentions: [mentioned_account.id])
|
||||
end.to raise_error(an_instance_of(PostStatusService::UnexpectedMentionsError).and(having_attributes(accounts: [unexpected_mentioned_account])))
|
||||
end.to raise_error(an_instance_of(described_class::UnexpectedMentionsError).and(having_attributes(accounts: [unexpected_mentioned_account])))
|
||||
end
|
||||
|
||||
it 'processes duplicate mentions correctly' do
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe PrecomputeFeedService, type: :service do
|
||||
RSpec.describe PrecomputeFeedService do
|
||||
subject { described_class.new }
|
||||
|
||||
describe 'call' do
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe ProcessMentionsService, type: :service do
|
||||
RSpec.describe ProcessMentionsService do
|
||||
subject { described_class.new }
|
||||
|
||||
let(:account) { Fabricate(:account, username: 'alice') }
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe PurgeDomainService, type: :service do
|
||||
RSpec.describe PurgeDomainService do
|
||||
subject { described_class.new }
|
||||
|
||||
let(:domain) { 'obsolete.org' }
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe ReblogService, type: :service do
|
||||
RSpec.describe ReblogService do
|
||||
let(:alice) { Fabricate(:account, username: 'alice') }
|
||||
|
||||
context 'when creates a reblog with appropriate visibility' do
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe RejectFollowService, type: :service do
|
||||
RSpec.describe RejectFollowService do
|
||||
subject { described_class.new }
|
||||
|
||||
let(:sender) { Fabricate(:account, username: 'alice') }
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe RemoveFromFollowersService, type: :service do
|
||||
RSpec.describe RemoveFromFollowersService do
|
||||
subject { described_class.new }
|
||||
|
||||
let(:bob) { Fabricate(:account, username: 'bob') }
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe RemoveStatusService, :sidekiq_inline, type: :service do
|
||||
RSpec.describe RemoveStatusService, :sidekiq_inline do
|
||||
subject { described_class.new }
|
||||
|
||||
let!(:alice) { Fabricate(:account) }
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe ReportService, type: :service do
|
||||
RSpec.describe ReportService do
|
||||
subject { described_class.new }
|
||||
|
||||
let(:source_account) { Fabricate(:account) }
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe ResolveAccountService, type: :service do
|
||||
RSpec.describe ResolveAccountService do
|
||||
subject { described_class.new }
|
||||
|
||||
before do
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
require 'rails_helper'
|
||||
|
||||
describe ResolveURLService, type: :service do
|
||||
describe ResolveURLService do
|
||||
subject { described_class.new }
|
||||
|
||||
describe '#call' do
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
require 'rails_helper'
|
||||
|
||||
describe SearchService, type: :service do
|
||||
describe SearchService do
|
||||
subject { described_class.new }
|
||||
|
||||
describe '#call' do
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe SoftwareUpdateCheckService, type: :service do
|
||||
RSpec.describe SoftwareUpdateCheckService do
|
||||
subject { described_class.new }
|
||||
|
||||
shared_examples 'when the feature is enabled' do
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe SuspendAccountService, :sidekiq_inline, type: :service do
|
||||
RSpec.describe SuspendAccountService, :sidekiq_inline do
|
||||
shared_examples 'common behavior' do
|
||||
subject { described_class.new.call(account) }
|
||||
|
||||
|
|
21
spec/services/tag_search_service_spec.rb
Normal file
21
spec/services/tag_search_service_spec.rb
Normal file
|
@ -0,0 +1,21 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe TagSearchService do
|
||||
describe '#call' do
|
||||
let!(:one) { Fabricate(:tag, name: 'one') }
|
||||
|
||||
before { Fabricate(:tag, name: 'two') }
|
||||
|
||||
it 'runs a search for tags' do
|
||||
results = subject.call('#one', limit: 5)
|
||||
|
||||
expect(results)
|
||||
.to have_attributes(
|
||||
size: 1,
|
||||
first: eq(one)
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe TranslateStatusService, type: :service do
|
||||
RSpec.describe TranslateStatusService do
|
||||
subject(:service) { described_class.new }
|
||||
|
||||
let(:status) { Fabricate(:status, text: text, spoiler_text: spoiler_text, language: 'en', preloadable_poll: poll, media_attachments: media_attachments) }
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe UnallowDomainService, type: :service do
|
||||
RSpec.describe UnallowDomainService do
|
||||
subject { described_class.new }
|
||||
|
||||
let(:bad_domain) { 'evil.org' }
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
require 'rails_helper'
|
||||
|
||||
describe UnblockDomainService, type: :service do
|
||||
describe UnblockDomainService do
|
||||
subject { described_class.new }
|
||||
|
||||
describe 'call' do
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe UnblockService, type: :service do
|
||||
RSpec.describe UnblockService do
|
||||
subject { described_class.new }
|
||||
|
||||
let(:sender) { Fabricate(:account, username: 'alice') }
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe UnfollowService, type: :service do
|
||||
RSpec.describe UnfollowService do
|
||||
subject { described_class.new }
|
||||
|
||||
let(:sender) { Fabricate(:account, username: 'alice') }
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe UnsuspendAccountService, type: :service do
|
||||
RSpec.describe UnsuspendAccountService do
|
||||
shared_context 'with common context' do
|
||||
subject { described_class.new.call(account) }
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe UpdateAccountService, type: :service do
|
||||
RSpec.describe UpdateAccountService do
|
||||
subject { described_class.new }
|
||||
|
||||
describe 'switching form locked to unlocked accounts', :sidekiq_inline do
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe UpdateStatusService, type: :service do
|
||||
RSpec.describe UpdateStatusService do
|
||||
subject { described_class.new }
|
||||
|
||||
context 'when nothing changes' do
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe VerifyLinkService, type: :service do
|
||||
RSpec.describe VerifyLinkService do
|
||||
subject { described_class.new }
|
||||
|
||||
context 'when given a local account' do
|
||||
|
|
13
spec/support/matchers/api_pagination.rb
Normal file
13
spec/support/matchers/api_pagination.rb
Normal file
|
@ -0,0 +1,13 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
RSpec::Matchers.define :include_pagination_headers do |links|
|
||||
match do |response|
|
||||
links.map do |key, value|
|
||||
response.headers['Link'].find_link(['rel', key.to_s]).href == value
|
||||
end.all?
|
||||
end
|
||||
|
||||
failure_message do |header|
|
||||
"expected that #{header} would have the same values as #{links}."
|
||||
end
|
||||
end
|
|
@ -56,7 +56,7 @@ RSpec.describe FollowLimitValidator do
|
|||
|
||||
follow.valid?
|
||||
|
||||
expect(follow.errors[:base]).to include(I18n.t('users.follow_limit_reached', limit: FollowLimitValidator::LIMIT))
|
||||
expect(follow.errors[:base]).to include(I18n.t('users.follow_limit_reached', limit: described_class::LIMIT))
|
||||
end
|
||||
end
|
||||
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue