Merge remote-tracking branch 'parent/main' into kb-upstream-20231014

This commit is contained in:
KMY 2023-10-14 08:18:57 +09:00
commit 60195928e1
76 changed files with 1282 additions and 1205 deletions

View file

@ -16,37 +16,63 @@ describe Rack::Attack, type: :request do
# https://github.com/rack/rack-attack/blob/v6.6.1/lib/rack/attack/cache.rb#L64-L66
# So we want to minimize `Time.now.to_i % period`
travel_to Time.zone.at((Time.now.to_i / period.seconds).to_i * period.seconds)
travel_to Time.zone.at(counter_prefix * period.seconds)
end
context 'when the number of requests is lower than the limit' do
before do
below_limit.times { increment_counter }
end
it 'does not change the request status' do
limit.times do
request.call
expect(response).to_not have_http_status(429)
end
expect { request.call }.to change { throttle_count }.by(1)
expect(response).to_not have_http_status(429)
end
end
context 'when the number of requests is higher than the limit' do
before do
above_limit.times { increment_counter }
end
it 'returns http too many requests after limit and returns to normal status after period' do
(limit * 2).times do |i|
request.call
expect(response).to have_http_status(429) if i > limit
end
expect { request.call }.to change { throttle_count }.by(1)
expect(response).to have_http_status(429)
travel period
request.call
expect { request.call }.to change { throttle_count }.by(1)
expect(response).to_not have_http_status(429)
end
end
def below_limit
limit - 1
end
def above_limit
limit * 2
end
def throttle_count
described_class.cache.read("#{counter_prefix}:#{throttle}:#{remote_ip}") || 0
end
def counter_prefix
(Time.now.to_i / period.seconds).to_i
end
def increment_counter
described_class.cache.count("#{throttle}:#{remote_ip}", period)
end
end
let(:remote_ip) { '1.2.3.5' }
describe 'throttle excessive sign-up requests by IP address' do
context 'when accessed through the website' do
let(:throttle) { 'throttle_sign_up_attempts/ip' }
let(:limit) { 25 }
let(:period) { 5.minutes }
let(:request) { -> { post path, headers: { 'REMOTE_ADDR' => remote_ip } } }
@ -65,6 +91,7 @@ describe Rack::Attack, type: :request do
end
context 'when accessed through the API' do
let(:throttle) { 'throttle_api_sign_up' }
let(:limit) { 5 }
let(:period) { 30.minutes }
let(:request) { -> { post path, headers: { 'REMOTE_ADDR' => remote_ip } } }
@ -87,6 +114,7 @@ describe Rack::Attack, type: :request do
end
describe 'throttle excessive sign-in requests by IP address' do
let(:throttle) { 'throttle_login_attempts/ip' }
let(:limit) { 25 }
let(:period) { 5.minutes }
let(:request) { -> { post path, headers: { 'REMOTE_ADDR' => remote_ip } } }

View file

@ -14,11 +14,8 @@ RSpec.describe Api::OEmbedController do
get :show, params: { url: short_account_status_url(alice, status) }, format: :json
end
it 'returns http success' do
it 'returns private cache control headers', :aggregate_failures do
expect(response).to have_http_status(200)
end
it 'returns private cache control headers' do
expect(response.headers['Cache-Control']).to include('private, no-store')
end
end

View file

@ -41,11 +41,9 @@ describe Api::V1::Accounts::CredentialsController do
}
end
it 'returns http success' do
it 'updates account info', :aggregate_failures do
expect(response).to have_http_status(200)
end
it 'updates account info' do
user.reload
user.account.reload
@ -55,9 +53,7 @@ describe Api::V1::Accounts::CredentialsController do
expect(user.account.header).to exist
expect(user.setting_default_privacy).to eq('unlisted')
expect(user.setting_default_sensitive).to be(true)
end
it 'queues up an account update distribution' do
expect(ActivityPub::UpdateDistributionWorker).to have_received(:perform_async).with(user.account_id)
end
end

View file

@ -18,23 +18,19 @@ describe Api::V1::Accounts::FollowerAccountsController do
end
describe 'GET #index' do
it 'returns http success' do
it 'returns accounts following the given account', :aggregate_failures do
get :index, params: { account_id: account.id, limit: 2 }
expect(response).to have_http_status(200)
end
it 'returns accounts following the given account' do
get :index, params: { account_id: account.id, limit: 2 }
expect(body_as_json.size).to eq 2
expect([body_as_json[0][:id], body_as_json[1][:id]]).to contain_exactly(alice.id.to_s, bob.id.to_s)
end
it 'does not return blocked users' do
it 'does not return blocked users', :aggregate_failures do
user.account.block!(bob)
get :index, params: { account_id: account.id, limit: 2 }
expect(response).to have_http_status(200)
expect(body_as_json.size).to eq 1
expect(body_as_json[0][:id]).to eq alice.id.to_s
end

View file

@ -18,23 +18,19 @@ describe Api::V1::Accounts::FollowingAccountsController do
end
describe 'GET #index' do
it 'returns http success' do
it 'returns accounts followed by the given account', :aggregate_failures do
get :index, params: { account_id: account.id, limit: 2 }
expect(response).to have_http_status(200)
end
it 'returns accounts followed by the given account' do
get :index, params: { account_id: account.id, limit: 2 }
expect(body_as_json.size).to eq 2
expect([body_as_json[0][:id], body_as_json[1][:id]]).to contain_exactly(alice.id.to_s, bob.id.to_s)
end
it 'does not return blocked users' do
it 'does not return blocked users', :aggregate_failures do
user.account.block!(bob)
get :index, params: { account_id: account.id, limit: 2 }
expect(response).to have_http_status(200)
expect(body_as_json.size).to eq 1
expect(body_as_json[0][:id]).to eq alice.id.to_s
end

View file

@ -19,30 +19,24 @@ describe Api::V1::Accounts::NotesController do
post :create, params: { account_id: account.id, comment: comment }
end
context 'when account note has reasonable length' do
context 'when account note has reasonable length', :aggregate_failures do
let(:comment) { 'foo' }
it 'returns http success' do
subject
expect(response).to have_http_status(200)
end
it 'updates account note' do
subject
expect(response).to have_http_status(200)
expect(AccountNote.find_by(account_id: user.account.id, target_account_id: account.id).comment).to eq comment
end
end
context 'when account note exceeds allowed length' do
context 'when account note exceeds allowed length', :aggregate_failures do
let(:comment) { 'a' * 2_001 }
it 'returns 422' do
subject
expect(response).to have_http_status(422)
end
it 'does not create account note' do
subject
expect(response).to have_http_status(422)
expect(AccountNote.where(account_id: user.account.id, target_account_id: account.id)).to_not exist
end
end

View file

@ -15,14 +15,11 @@ RSpec.describe Api::V1::Accounts::PinsController do
describe 'POST #create' do
subject { post :create, params: { account_id: kevin.account.id } }
it 'returns 200' do
expect(response).to have_http_status(200)
end
it 'creates account_pin' do
it 'creates account_pin', :aggregate_failures do
expect do
subject
end.to change { AccountPin.where(account: john.account, target_account: kevin.account).count }.by(1)
expect(response).to have_http_status(200)
end
end
@ -33,14 +30,11 @@ RSpec.describe Api::V1::Accounts::PinsController do
Fabricate(:account_pin, account: john.account, target_account: kevin.account)
end
it 'returns 200' do
expect(response).to have_http_status(200)
end
it 'destroys account_pin' do
it 'destroys account_pin', :aggregate_failures do
expect do
subject
end.to change { AccountPin.where(account: john.account, target_account: kevin.account).count }.by(-1)
expect(response).to have_http_status(200)
end
end
end

View file

@ -26,13 +26,10 @@ describe Api::V1::Accounts::RelationshipsController do
get :index, params: { id: simon.id }
end
it 'returns http success' do
expect(response).to have_http_status(200)
end
it 'returns JSON with correct data' do
it 'returns JSON with correct data', :aggregate_failures do
json = body_as_json
expect(response).to have_http_status(200)
expect(json).to be_a Enumerable
expect(json.first[:following]).to be true
expect(json.first[:followed_by]).to be false
@ -51,11 +48,14 @@ describe Api::V1::Accounts::RelationshipsController do
context 'when there is returned JSON data' do
let(:json) { body_as_json }
it 'returns an enumerable json' do
it 'returns an enumerable json with correct elements', :aggregate_failures do
expect(json).to be_a Enumerable
expect_simon_item_one
expect_lewis_item_two
end
it 'returns a correct first element' do
def expect_simon_item_one
expect(json.first[:id]).to eq simon.id.to_s
expect(json.first[:following]).to be true
expect(json.first[:showing_reblogs]).to be true
@ -65,7 +65,7 @@ describe Api::V1::Accounts::RelationshipsController do
expect(json.first[:domain_blocking]).to be false
end
it 'returns a correct second element' do
def expect_lewis_item_two
expect(json.second[:id]).to eq lewis.id.to_s
expect(json.second[:following]).to be false
expect(json.second[:showing_reblogs]).to be false

View file

@ -14,15 +14,10 @@ describe Api::V1::Accounts::StatusesController do
end
describe 'GET #index' do
it 'returns http success' do
it 'returns expected headers', :aggregate_failures do
get :index, params: { account_id: user.account.id, limit: 1 }
expect(response).to have_http_status(200)
end
it 'returns expected headers' do
get :index, params: { account_id: user.account.id, limit: 1 }
expect(response.headers['Link'].links.size).to eq(2)
end
@ -44,14 +39,11 @@ describe Api::V1::Accounts::StatusesController do
get :index, params: { account_id: user.account.id, exclude_replies: true }
end
it 'returns http success' do
expect(response).to have_http_status(200)
end
it 'returns posts along with self replies' do
it 'returns posts along with self replies', :aggregate_failures do
json = body_as_json
post_ids = json.map { |item| item[:id].to_i }.sort
expect(response).to have_http_status(200)
expect(post_ids).to eq [status.id, status_self_reply.id]
end
end

View file

@ -25,15 +25,10 @@ RSpec.describe Api::V1::AccountsController do
context 'when given truthy agreement' do
let(:agreement) { 'true' }
it 'returns http success' do
it 'creates a user', :aggregate_failures do
expect(response).to have_http_status(200)
end
it 'returns a new access token as JSON' do
expect(body_as_json[:access_token]).to_not be_blank
end
it 'creates a user' do
user = User.find_by(email: 'hello@world.tld')
expect(user).to_not be_nil
expect(user.created_by_application_id).to eq app.id
@ -65,18 +60,14 @@ RSpec.describe Api::V1::AccountsController do
context 'with unlocked account' do
let(:locked) { false }
it 'returns http success' do
it 'creates a following relation between user and target user', :aggregate_failures do
expect(response).to have_http_status(200)
end
it 'returns JSON with following=true and requested=false' do
json = body_as_json
expect(json[:following]).to be true
expect(json[:requested]).to be false
end
it 'creates a following relation between user and target user' do
expect(user.account.following?(other_account)).to be true
end
@ -86,18 +77,14 @@ RSpec.describe Api::V1::AccountsController do
context 'with locked account' do
let(:locked) { true }
it 'returns http success' do
it 'creates a follow request relation between user and target user', :aggregate_failures do
expect(response).to have_http_status(200)
end
it 'returns JSON with following=false and requested=true' do
json = body_as_json
expect(json[:following]).to be false
expect(json[:requested]).to be true
end
it 'creates a follow request relation between user and target user' do
expect(user.account.requested?(other_account)).to be true
end
@ -177,11 +164,8 @@ RSpec.describe Api::V1::AccountsController do
post :unfollow, params: { id: other_account.id }
end
it 'returns http success' do
it 'removes the following relation between user and target user', :aggregate_failures do
expect(response).to have_http_status(200)
end
it 'removes the following relation between user and target user' do
expect(user.account.following?(other_account)).to be false
end
@ -197,11 +181,8 @@ RSpec.describe Api::V1::AccountsController do
post :remove_from_followers, params: { id: other_account.id }
end
it 'returns http success' do
it 'removes the followed relation between user and target user', :aggregate_failures do
expect(response).to have_http_status(200)
end
it 'removes the followed relation between user and target user' do
expect(user.account.followed_by?(other_account)).to be false
end
@ -217,15 +198,9 @@ RSpec.describe Api::V1::AccountsController do
post :block, params: { id: other_account.id }
end
it 'returns http success' do
it 'creates a blocking relation', :aggregate_failures do
expect(response).to have_http_status(200)
end
it 'removes the following relation between user and target user' do
expect(user.account.following?(other_account)).to be false
end
it 'creates a blocking relation' do
expect(user.account.blocking?(other_account)).to be true
end
@ -241,11 +216,8 @@ RSpec.describe Api::V1::AccountsController do
post :unblock, params: { id: other_account.id }
end
it 'returns http success' do
it 'removes the blocking relation between user and target user', :aggregate_failures do
expect(response).to have_http_status(200)
end
it 'removes the blocking relation between user and target user' do
expect(user.account.blocking?(other_account)).to be false
end
@ -261,19 +233,10 @@ RSpec.describe Api::V1::AccountsController do
post :mute, params: { id: other_account.id }
end
it 'returns http success' do
it 'mutes notifications', :aggregate_failures do
expect(response).to have_http_status(200)
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 'mutes notifications' do
expect(user.account.muting_notifications?(other_account)).to be true
end
@ -289,19 +252,10 @@ RSpec.describe Api::V1::AccountsController do
post :mute, params: { id: other_account.id, notifications: false }
end
it 'returns http success' do
it 'does not mute notifications', :aggregate_failures do
expect(response).to have_http_status(200)
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
@ -317,19 +271,10 @@ RSpec.describe Api::V1::AccountsController do
post :mute, params: { id: other_account.id, duration: 300 }
end
it 'returns http success' do
it 'mutes notifications', :aggregate_failures do
expect(response).to have_http_status(200)
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 'mutes notifications' do
expect(user.account.muting_notifications?(other_account)).to be true
end
@ -345,11 +290,8 @@ RSpec.describe Api::V1::AccountsController do
post :unmute, params: { id: other_account.id }
end
it 'returns http success' do
it 'removes the muting relation between user and target user', :aggregate_failures do
expect(response).to have_http_status(200)
end
it 'removes the muting relation between user and target user' do
expect(user.account.muting?(other_account)).to be false
end

View file

@ -44,11 +44,9 @@ RSpec.describe Api::V1::Admin::AccountsController do
context "when called with #{params.inspect}" do
let(:params) { params }
it 'returns http success' do
it "returns the correct accounts (#{expected_results.inspect})", :aggregate_failures do
expect(response).to have_http_status(200)
end
it "returns the correct accounts (#{expected_results.inspect})" do
json = body_as_json
expect(json.map { |a| a[:id].to_i }).to eq(expected_results.map { |symbol| send(symbol).id })
@ -79,15 +77,10 @@ RSpec.describe Api::V1::Admin::AccountsController do
it_behaves_like 'forbidden for wrong scope', 'write:statuses'
it_behaves_like 'forbidden for wrong role', ''
it 'returns http success' do
it 'approves user', :aggregate_failures do
expect(response).to have_http_status(200)
end
it 'approves user' do
expect(account.reload.user_approved?).to be true
end
it 'logs action' do
log_item = Admin::ActionLog.last
expect(log_item).to_not be_nil
@ -106,15 +99,10 @@ RSpec.describe Api::V1::Admin::AccountsController do
it_behaves_like 'forbidden for wrong scope', 'write:statuses'
it_behaves_like 'forbidden for wrong role', ''
it 'returns http success' do
it 'removes user', :aggregate_failures do
expect(response).to have_http_status(200)
end
it 'removes user' do
expect(User.where(id: account.user.id).count).to eq 0
end
it 'logs action' do
log_item = Admin::ActionLog.last
expect(log_item).to_not be_nil
@ -133,11 +121,8 @@ RSpec.describe Api::V1::Admin::AccountsController do
it_behaves_like 'forbidden for wrong scope', 'write:statuses'
it_behaves_like 'forbidden for wrong role', ''
it 'returns http success' do
it 'enables user', :aggregate_failures do
expect(response).to have_http_status(200)
end
it 'enables user' do
expect(account.reload.user_disabled?).to be false
end
end
@ -151,11 +136,8 @@ RSpec.describe Api::V1::Admin::AccountsController do
it_behaves_like 'forbidden for wrong scope', 'write:statuses'
it_behaves_like 'forbidden for wrong role', ''
it 'returns http success' do
it 'unsuspends account', :aggregate_failures do
expect(response).to have_http_status(200)
end
it 'unsuspends account' do
expect(account.reload.suspended?).to be false
end
end
@ -169,11 +151,8 @@ RSpec.describe Api::V1::Admin::AccountsController do
it_behaves_like 'forbidden for wrong scope', 'write:statuses'
it_behaves_like 'forbidden for wrong role', ''
it 'returns http success' do
it 'unsensitizes account', :aggregate_failures do
expect(response).to have_http_status(200)
end
it 'unsensitizes account' do
expect(account.reload.sensitized?).to be false
end
end
@ -187,11 +166,8 @@ RSpec.describe Api::V1::Admin::AccountsController do
it_behaves_like 'forbidden for wrong scope', 'write:statuses'
it_behaves_like 'forbidden for wrong role', ''
it 'returns http success' do
it 'unsilences account', :aggregate_failures do
expect(response).to have_http_status(200)
end
it 'unsilences account' do
expect(account.reload.silenced?).to be false
end
end

View file

@ -1,52 +0,0 @@
# frozen_string_literal: true
require 'rails_helper'
describe Api::V1::Admin::Trends::LinksController do
render_views
let(:role) { UserRole.find_by(name: 'Admin') }
let(:user) { Fabricate(:user, role: role) }
let(:scopes) { 'admin:read admin:write' }
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) }
let(:account) { Fabricate(:account) }
let(:preview_card) { Fabricate(:preview_card) }
before do
allow(controller).to receive(:doorkeeper_token) { token }
end
describe 'GET #index' do
it 'returns http success' do
get :index, params: { account_id: account.id, limit: 2 }
expect(response).to have_http_status(200)
end
end
describe 'POST #approve' do
before do
post :approve, params: { id: preview_card.id }
end
it_behaves_like 'forbidden for wrong scope', 'write:statuses'
it_behaves_like 'forbidden for wrong role', ''
it 'returns http success' do
expect(response).to have_http_status(200)
end
end
describe 'POST #reject' do
before do
post :reject, params: { id: preview_card.id }
end
it_behaves_like 'forbidden for wrong scope', 'write:statuses'
it_behaves_like 'forbidden for wrong role', ''
it 'returns http success' do
expect(response).to have_http_status(200)
end
end
end

View file

@ -25,11 +25,8 @@ RSpec.describe Api::V1::Announcements::ReactionsController do
put :update, params: { announcement_id: announcement.id, id: '😂' }
end
it 'returns http success' do
it 'creates reaction', :aggregate_failures do
expect(response).to have_http_status(200)
end
it 'creates reaction' do
expect(announcement.announcement_reactions.find_by(name: '😂', account: user.account)).to_not be_nil
end
end
@ -53,11 +50,8 @@ RSpec.describe Api::V1::Announcements::ReactionsController do
delete :destroy, params: { announcement_id: announcement.id, id: '😂' }
end
it 'returns http success' do
it 'creates reaction', :aggregate_failures do
expect(response).to have_http_status(200)
end
it 'creates reaction' do
expect(announcement.announcement_reactions.find_by(name: '😂', account: user.account)).to be_nil
end
end

View file

@ -47,11 +47,8 @@ RSpec.describe Api::V1::AnnouncementsController do
post :dismiss, params: { id: announcement.id }
end
it 'returns http success' do
it 'dismisses announcement', :aggregate_failures do
expect(response).to have_http_status(200)
end
it 'dismisses announcement' do
expect(announcement.announcement_mutes.find_by(account: user.account)).to_not be_nil
end
end

View file

@ -12,45 +12,48 @@ RSpec.describe Api::V1::BlocksController do
before { allow(controller).to receive(:doorkeeper_token) { token } }
describe 'GET #index' do
it 'limits according to limit parameter' do
it 'limits according to limit parameter', :aggregate_failures do
Array.new(2) { Fabricate(:block, account: user.account) }
get :index, params: { limit: 1 }
expect(response).to have_http_status(200)
expect(body_as_json.size).to eq 1
end
it 'queries blocks in range according to max_id' do
it 'queries blocks in range according to max_id', :aggregate_failures do
blocks = Array.new(2) { Fabricate(:block, account: user.account) }
get :index, params: { max_id: blocks[1] }
expect(response).to have_http_status(200)
expect(body_as_json.size).to eq 1
expect(body_as_json[0][:id]).to eq blocks[0].target_account_id.to_s
end
it 'queries blocks in range according to since_id' do
it 'queries blocks in range according to since_id', :aggregate_failures do
blocks = Array.new(2) { Fabricate(:block, account: user.account) }
get :index, params: { since_id: blocks[0] }
expect(response).to have_http_status(200)
expect(body_as_json.size).to eq 1
expect(body_as_json[0][:id]).to eq blocks[1].target_account_id.to_s
end
it 'sets pagination header for next path' do
it 'sets pagination header for next path', :aggregate_failures do
blocks = Array.new(2) { Fabricate(:block, account: user.account) }
get :index, params: { limit: 1, since_id: blocks[0] }
expect(response).to have_http_status(200)
expect(response.headers['Link'].find_link(%w(rel next)).href).to eq api_v1_blocks_url(limit: 1, max_id: blocks[1])
end
it 'sets pagination header for previous path' do
it 'sets pagination header for previous path', :aggregate_failures do
block = Fabricate(:block, account: user.account)
get :index
expect(response.headers['Link'].find_link(%w(rel prev)).href).to eq api_v1_blocks_url(since_id: block)
end
it 'returns http success' do
get :index
expect(response).to have_http_status(200)
expect(response.headers['Link'].find_link(%w(rel prev)).href).to eq api_v1_blocks_url(since_id: block)
end
context 'with wrong scopes' do

View file

@ -21,17 +21,14 @@ RSpec.describe Api::V1::ConversationsController do
PostStatusService.new.call(user.account, text: 'Hey, nobody here', visibility: 'direct')
end
it 'returns http success' do
get :index
expect(response).to have_http_status(200)
end
it 'returns pagination headers' do
it 'returns pagination headers', :aggregate_failures do
get :index, params: { limit: 1 }
expect(response).to have_http_status(200)
expect(response.headers['Link'].links.size).to eq(2)
end
it 'returns conversations' do
it 'returns conversations', :aggregate_failures do
get :index
json = body_as_json
expect(json.size).to eq 2

View file

@ -1,80 +0,0 @@
# frozen_string_literal: true
require 'rails_helper'
RSpec.describe Api::V1::FavouritesController do
render_views
let(:user) { Fabricate(:user) }
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: 'read') }
describe 'GET #index' do
context 'without token' do
it 'returns http unauthorized' do
get :index
expect(response).to have_http_status 401
end
end
context 'with token' do
context 'without read scope' do
before do
allow(controller).to receive(:doorkeeper_token) do
Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: '')
end
end
it 'returns http forbidden' do
get :index
expect(response).to have_http_status 403
end
end
context 'without valid resource owner' do
before do
token = Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: 'read')
user.destroy!
allow(controller).to receive(:doorkeeper_token) { token }
end
it 'returns http unprocessable entity' do
get :index
expect(response).to have_http_status 422
end
end
context 'with read scope and valid resource owner' do
before do
allow(controller).to receive(:doorkeeper_token) do
Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: 'read:favourites')
end
end
it 'shows favourites owned by the user' do
favourite_by_user = Fabricate(:favourite, account: user.account)
favourite_by_others = Fabricate(:favourite)
get :index
expect(assigns(:statuses)).to contain_exactly(favourite_by_user.status)
end
it 'adds pagination headers if necessary' do
favourite = Fabricate(:favourite, account: user.account)
get :index, params: { limit: 1 }
expect(response.headers['Link'].find_link(%w(rel next)).href).to eq "http://test.host/api/v1/favourites?limit=1&max_id=#{favourite.id}"
expect(response.headers['Link'].find_link(%w(rel prev)).href).to eq "http://test.host/api/v1/favourites?limit=1&min_id=#{favourite.id}"
end
it 'does not add pagination headers if not necessary' do
get :index
expect(response.headers['Link']).to be_nil
end
end
end
end
end

View file

@ -31,12 +31,10 @@ RSpec.describe Api::V1::FiltersController do
post :create, params: { phrase: 'magic', context: %w(home), irreversible: irreversible, whole_word: whole_word }
end
it 'returns http success' do
expect(response).to have_http_status(200)
end
it 'creates a filter' do
it 'creates a filter', :aggregate_failures do
filter = user.account.custom_filters.first
expect(response).to have_http_status(200)
expect(filter).to_not be_nil
expect(filter.keywords.pluck(:keyword, :whole_word)).to eq [['magic', whole_word]]
expect(filter.context).to eq %w(home)
@ -48,12 +46,10 @@ RSpec.describe Api::V1::FiltersController do
let(:irreversible) { false }
let(:whole_word) { true }
it 'returns http success' do
expect(response).to have_http_status(200)
end
it 'creates a filter' do
it 'creates a filter', :aggregate_failures do
filter = user.account.custom_filters.first
expect(response).to have_http_status(200)
expect(filter).to_not be_nil
expect(filter.keywords.pluck(:keyword, :whole_word)).to eq [['magic', whole_word]]
expect(filter.context).to eq %w(home)
@ -83,11 +79,8 @@ RSpec.describe Api::V1::FiltersController do
put :update, params: { id: keyword.id, phrase: 'updated' }
end
it 'returns http success' do
it 'updates the filter', :aggregate_failures do
expect(response).to have_http_status(200)
end
it 'updates the filter' do
expect(keyword.reload.phrase).to eq 'updated'
end
end
@ -101,11 +94,8 @@ RSpec.describe Api::V1::FiltersController do
delete :destroy, params: { id: keyword.id }
end
it 'returns http success' do
it 'removes the filter', :aggregate_failures do
expect(response).to have_http_status(200)
end
it 'removes the filter' do
expect { keyword.reload }.to raise_error ActiveRecord::RecordNotFound
end
end

View file

@ -1,25 +0,0 @@
# frozen_string_literal: true
require 'rails_helper'
RSpec.describe Api::V1::FollowedTagsController do
render_views
let(:user) { Fabricate(:user) }
let(:scopes) { 'read:follows' }
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) }
before { allow(controller).to receive(:doorkeeper_token) { token } }
describe 'GET #index' do
let!(:tag_follows) { Fabricate.times(5, :tag_follow, account: user.account) }
before do
get :index, params: { limit: 1 }
end
it 'returns http success' do
expect(response).to have_http_status(:success)
end
end
end

View file

@ -5,7 +5,7 @@ require 'rails_helper'
describe Api::V1::Instances::TranslationLanguagesController do
describe 'GET #show' do
context 'when no translation service is configured' do
it 'returns empty language matrix' do
it 'returns empty language matrix', :aggregate_failures do
get :show
expect(response).to have_http_status(200)
@ -19,7 +19,7 @@ describe Api::V1::Instances::TranslationLanguagesController do
allow(TranslationService).to receive_messages(configured?: true, configured: service)
end
it 'returns language matrix' do
it 'returns language matrix', :aggregate_failures do
get :show
expect(response).to have_http_status(200)

View file

@ -35,11 +35,8 @@ describe Api::V1::Lists::AccountsController do
post :create, params: { list_id: list.id, account_ids: [bob.id] }
end
it 'returns http success' do
it 'adds account to the list', :aggregate_failures do
expect(response).to have_http_status(200)
end
it 'adds account to the list' do
expect(list.accounts.include?(bob)).to be true
end
end
@ -50,11 +47,8 @@ describe Api::V1::Lists::AccountsController do
post :create, params: { list_id: list.id, account_ids: [bob.id] }
end
it 'returns http success' do
it 'adds account to the list', :aggregate_failures do
expect(response).to have_http_status(200)
end
it 'adds account to the list' do
expect(list.accounts.include?(bob)).to be true
end
end
@ -64,11 +58,8 @@ describe Api::V1::Lists::AccountsController do
post :create, params: { list_id: list.id, account_ids: [bob.id] }
end
it 'returns http not found' do
it 'does not add the account to the list', :aggregate_failures do
expect(response).to have_http_status(404)
end
it 'does not add the account to the list' do
expect(list.accounts.include?(bob)).to be false
end
end
@ -81,11 +72,8 @@ describe Api::V1::Lists::AccountsController do
delete :destroy, params: { list_id: list.id, account_ids: [list.accounts.first.id] }
end
it 'returns http success' do
it 'removes account from the list', :aggregate_failures do
expect(response).to have_http_status(200)
end
it 'removes account from the list' do
expect(list.accounts.count).to eq 0
end
end

View file

@ -18,13 +18,10 @@ RSpec.describe Api::V1::MarkersController do
get :index, params: { timeline: %w(home notifications) }
end
it 'returns http success' do
expect(response).to have_http_status(200)
end
it 'returns markers' do
it 'returns markers', :aggregate_failures do
json = body_as_json
expect(response).to have_http_status(200)
expect(json.key?(:home)).to be true
expect(json[:home][:last_read_id]).to eq '123'
expect(json.key?(:notifications)).to be true
@ -38,11 +35,8 @@ RSpec.describe Api::V1::MarkersController do
post :create, params: { home: { last_read_id: '69420' } }
end
it 'returns http success' do
it 'creates a marker', :aggregate_failures do
expect(response).to have_http_status(200)
end
it 'creates a marker' do
expect(user.markers.first.timeline).to eq 'home'
expect(user.markers.first.last_read_id).to eq 69_420
end
@ -54,11 +48,8 @@ RSpec.describe Api::V1::MarkersController do
post :create, params: { home: { last_read_id: '70120' } }
end
it 'returns http success' do
it 'updates a marker', :aggregate_failures do
expect(response).to have_http_status(200)
end
it 'updates a marker' do
expect(user.markers.first.timeline).to eq 'home'
expect(user.markers.first.last_read_id).to eq 70_120
end

View file

@ -38,19 +38,10 @@ RSpec.describe Api::V1::MediaController do
post :create, params: { file: fixture_file_upload('attachment.jpg', 'image/jpeg') }
end
it 'returns http success' do
it 'creates a media attachment', :aggregate_failures do
expect(response).to have_http_status(200)
end
it 'creates a media attachment' do
expect(MediaAttachment.first).to_not be_nil
end
it 'uploads a file' do
expect(MediaAttachment.first).to have_attached_file(:file)
end
it 'returns media ID in JSON' do
expect(body_as_json[:id]).to eq MediaAttachment.first.id.to_s
end
end
@ -60,19 +51,10 @@ RSpec.describe Api::V1::MediaController do
post :create, params: { file: fixture_file_upload('attachment.gif', 'image/gif') }
end
it 'returns http success' do
it 'creates a media attachment', :aggregate_failures do
expect(response).to have_http_status(200)
end
it 'creates a media attachment' do
expect(MediaAttachment.first).to_not be_nil
end
it 'uploads a file' do
expect(MediaAttachment.first).to have_attached_file(:file)
end
it 'returns media ID in JSON' do
expect(body_as_json[:id]).to eq MediaAttachment.first.id.to_s
end
end
@ -82,17 +64,10 @@ RSpec.describe Api::V1::MediaController do
post :create, params: { file: fixture_file_upload('attachment.webm', 'video/webm') }
end
it do
# returns http success
it 'creates a media attachment', :aggregate_failures do
expect(response).to have_http_status(200)
# creates a media attachment
expect(MediaAttachment.first).to_not be_nil
# uploads a file
expect(MediaAttachment.first).to have_attached_file(:file)
# returns media ID in JSON
expect(body_as_json[:id]).to eq MediaAttachment.first.id.to_s
end
end

View file

@ -18,18 +18,13 @@ RSpec.describe Api::V1::Polls::VotesController do
post :create, params: { poll_id: poll.id, choices: %w(1) }
end
it 'returns http success' do
it 'creates a vote', :aggregate_failures do
expect(response).to have_http_status(200)
end
it 'creates a vote' do
vote = poll.votes.where(account: user.account).first
expect(vote).to_not be_nil
expect(vote.choice).to eq 1
end
it 'updates poll tallies' do
expect(poll.reload.cached_tallies).to eq [0, 1]
end
end

View file

@ -1,75 +0,0 @@
# frozen_string_literal: true
require 'rails_helper'
RSpec.describe Api::V1::ReportsController do
render_views
let(:user) { Fabricate(:user) }
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) }
before do
allow(controller).to receive(:doorkeeper_token) { token }
end
describe 'POST #create' do
let!(:admin) { Fabricate(:user, role: UserRole.find_by(name: 'Admin')) }
let(:scopes) { 'write:reports' }
let(:status) { Fabricate(:status) }
let(:target_account) { status.account }
let(:category) { nil }
let(:forward) { nil }
let(:rule_ids) { nil }
before do
post :create, params: { status_ids: [status.id], account_id: target_account.id, comment: 'reasons', category: category, rule_ids: rule_ids, forward: forward }
end
it 'returns http success' do
expect(response).to have_http_status(200)
end
it 'creates a report' do
expect(target_account.targeted_reports).to_not be_empty
end
it 'saves comment' do
expect(target_account.targeted_reports.first.comment).to eq 'reasons'
end
it 'sends e-mails to admins' do
expect(ActionMailer::Base.deliveries.first.to).to eq([admin.email])
end
context 'when a status does not belong to the reported account' do
let(:target_account) { Fabricate(:account) }
it 'returns http not found' do
expect(response).to have_http_status(404)
end
end
context 'when a category is chosen' do
let(:category) { 'spam' }
it 'saves category' do
expect(target_account.targeted_reports.first.spam?).to be true
end
end
context 'when violated rules are chosen' do
let(:rule) { Fabricate(:rule) }
let(:category) { 'violation' }
let(:rule_ids) { [rule.id] }
it 'saves category' do
expect(target_account.targeted_reports.first.violation?).to be true
end
it 'saves rule_ids' do
expect(target_account.targeted_reports.first.rule_ids).to contain_exactly(rule.id)
end
end
end
end

View file

@ -21,11 +21,8 @@ describe Api::V1::Statuses::MutesController do
post :create, params: { status_id: status.id }
end
it 'returns http success' do
it 'creates a conversation mute', :aggregate_failures do
expect(response).to have_http_status(200)
end
it 'creates a conversation mute' do
expect(ConversationMute.find_by(account: user.account, conversation_id: status.conversation_id)).to_not be_nil
end
end
@ -38,11 +35,8 @@ describe Api::V1::Statuses::MutesController do
post :destroy, params: { status_id: status.id }
end
it 'returns http success' do
it 'destroys the conversation mute', :aggregate_failures do
expect(response).to have_http_status(200)
end
it 'destroys the conversation mute' do
expect(ConversationMute.find_by(account: user.account, conversation_id: status.conversation_id)).to be_nil
end
end

View file

@ -24,14 +24,12 @@ RSpec.describe Api::V1::Statuses::RebloggedByAccountsController do
Fabricate(:status, account: bob, reblog_of_id: status.id)
end
it 'returns http success' do
it 'returns accounts who reblogged the status', :aggregate_failures do
get :index, params: { status_id: status.id, limit: 2 }
expect(response).to have_http_status(200)
expect(response.headers['Link'].links.size).to eq(2)
end
it 'returns accounts who reblogged the status' do
get :index, params: { status_id: status.id, limit: 2 }
expect(body_as_json.size).to eq 2
expect([body_as_json[0][:id], body_as_json[1][:id]]).to contain_exactly(alice.id.to_s, bob.id.to_s)
end

View file

@ -28,19 +28,13 @@ describe Api::V1::Statuses::ReblogsController do
end
context 'with public status' do
it 'returns http success' do
it 'reblogs the status', :aggregate_failures do
expect(response).to have_http_status(200)
end
it 'updates the reblogs count' do
expect(status.reblogs.count).to eq 1
end
it 'updates the reblogged attribute' do
expect(user.account.reblogged?(status)).to be true
end
it 'returns json with updated attributes' do
hash_body = body_as_json
expect(hash_body[:reblog][:id]).to eq status.id.to_s
@ -67,19 +61,13 @@ describe Api::V1::Statuses::ReblogsController do
post :destroy, params: { status_id: status.id }
end
it 'returns http success' do
it 'destroys the reblog', :aggregate_failures do
expect(response).to have_http_status(200)
end
it 'updates the reblogs count' do
expect(status.reblogs.count).to eq 0
end
it 'updates the reblogged attribute' do
expect(user.account.reblogged?(status)).to be false
end
it 'returns json with updated attributes' do
hash_body = body_as_json
expect(hash_body[:id]).to eq status.id.to_s
@ -97,19 +85,13 @@ describe Api::V1::Statuses::ReblogsController do
post :destroy, params: { status_id: status.id }
end
it 'returns http success' do
it 'destroys the reblog', :aggregate_failures do
expect(response).to have_http_status(200)
end
it 'updates the reblogs count' do
expect(status.reblogs.count).to eq 0
end
it 'updates the reblogged attribute' do
expect(user.account.reblogged?(status)).to be false
end
it 'returns json with updated attributes' do
hash_body = body_as_json
expect(hash_body[:id]).to eq status.id.to_s

View file

@ -1,29 +0,0 @@
# frozen_string_literal: true
require 'rails_helper'
describe Api::V1::Statuses::SourcesController do
render_views
let(:user) { Fabricate(:user) }
let(:app) { Fabricate(:application, name: 'Test app', website: 'http://testapp.com') }
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: 'read:statuses', application: app) }
context 'with an oauth token' do
before do
allow(controller).to receive(:doorkeeper_token) { token }
end
describe 'GET #show' do
let(:status) { Fabricate(:status, account: user.account) }
before do
get :show, params: { status_id: status.id }
end
it 'returns http success' do
expect(response).to have_http_status(200)
end
end
end
end

View file

@ -30,14 +30,11 @@ RSpec.describe Api::V1::StatusesController do
user.account.custom_filters.create!(phrase: 'filter1', context: %w(home), action: :hide, keywords_attributes: [{ keyword: 'banned' }, { keyword: 'irrelevant' }])
end
it 'returns http success' do
get :show, params: { id: status.id }
expect(response).to have_http_status(200)
end
it 'returns filter information' do
it 'returns filter information', :aggregate_failures do
get :show, params: { id: status.id }
json = body_as_json
expect(response).to have_http_status(200)
expect(json[:filtered][0]).to include({
filter: a_hash_including({
id: user.account.custom_filters.first.id.to_s,
@ -57,14 +54,11 @@ RSpec.describe Api::V1::StatusesController do
filter.statuses.create!(status_id: status.id)
end
it 'returns http success' do
get :show, params: { id: status.id }
expect(response).to have_http_status(200)
end
it 'returns filter information' do
it 'returns filter information', :aggregate_failures do
get :show, params: { id: status.id }
json = body_as_json
expect(response).to have_http_status(200)
expect(json[:filtered][0]).to include({
filter: a_hash_including({
id: user.account.custom_filters.first.id.to_s,
@ -83,14 +77,11 @@ RSpec.describe Api::V1::StatusesController do
user.account.custom_filters.create!(phrase: 'filter1', context: %w(home), action: :hide, keywords_attributes: [{ keyword: 'banned' }, { keyword: 'irrelevant' }])
end
it 'returns http success' do
get :show, params: { id: status.id }
expect(response).to have_http_status(200)
end
it 'returns filter information' do
it 'returns filter information', :aggregate_failures do
get :show, params: { id: status.id }
json = body_as_json
expect(response).to have_http_status(200)
expect(json[:reblog][:filtered][0]).to include({
filter: a_hash_including({
id: user.account.custom_filters.first.id.to_s,
@ -125,11 +116,8 @@ RSpec.describe Api::V1::StatusesController do
post :create, params: { status: 'Hello world' }
end
it 'returns http success' do
it 'returns rate limit headers', :aggregate_failures do
expect(response).to have_http_status(200)
end
it 'returns rate limit headers' do
expect(response.headers['X-RateLimit-Limit']).to eq RateLimiter::FAMILIES[:statuses][:limit].to_s
expect(response.headers['X-RateLimit-Remaining']).to eq (RateLimiter::FAMILIES[:statuses][:limit] - 1).to_s
end
@ -143,11 +131,8 @@ RSpec.describe Api::V1::StatusesController do
post :create, params: { status: '@alice hm, @bob is really annoying lately', allowed_mentions: [alice.id] }
end
it 'returns http unprocessable entity' do
it 'returns serialized extra accounts in body', :aggregate_failures do
expect(response).to have_http_status(422)
end
it 'returns serialized extra accounts in body' do
expect(body_as_json[:unexpected_accounts].map { |a| a.slice(:id, :acct) }).to eq [{ id: bob.id.to_s, acct: bob.acct }]
end
end
@ -157,11 +142,8 @@ RSpec.describe Api::V1::StatusesController do
post :create, params: {}
end
it 'returns http unprocessable entity' do
it 'returns rate limit headers', :aggregate_failures do
expect(response).to have_http_status(422)
end
it 'returns rate limit headers' do
expect(response.headers['X-RateLimit-Limit']).to eq RateLimiter::FAMILIES[:statuses][:limit].to_s
end
end
@ -173,11 +155,8 @@ RSpec.describe Api::V1::StatusesController do
post :create, params: { status: 'Hello world' }
end
it 'returns http too many requests' do
it 'returns rate limit headers', :aggregate_failures do
expect(response).to have_http_status(429)
end
it 'returns rate limit headers' do
expect(response.headers['X-RateLimit-Limit']).to eq RateLimiter::FAMILIES[:statuses][:limit].to_s
expect(response.headers['X-RateLimit-Remaining']).to eq '0'
end
@ -192,11 +171,8 @@ RSpec.describe Api::V1::StatusesController do
post :destroy, params: { id: status.id }
end
it 'returns http success' do
it 'removes the status', :aggregate_failures do
expect(response).to have_http_status(200)
end
it 'removes the status' do
expect(Status.find_by(id: status.id)).to be_nil
end
end
@ -209,11 +185,8 @@ RSpec.describe Api::V1::StatusesController do
put :update, params: { id: status.id, status: 'I am updated' }
end
it 'returns http success' do
it 'updates the status', :aggregate_failures do
expect(response).to have_http_status(200)
end
it 'updates the status' do
expect(status.reload.text).to eq 'I am updated'
end
end

View file

@ -1,71 +0,0 @@
# frozen_string_literal: true
require 'rails_helper'
describe Api::V1::Timelines::TagController do
render_views
let(:user) { Fabricate(:user) }
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: 'read:statuses') }
before do
allow(controller).to receive(:doorkeeper_token) { token }
end
describe 'GET #show' do
subject do
get :show, params: { id: 'test' }
end
before do
PostStatusService.new.call(user.account, text: 'It is a #test')
end
context 'when the instance allows public preview' do
context 'when the user is not authenticated' do
let(:token) { nil }
it 'returns http success', :aggregate_failures do
subject
expect(response).to have_http_status(200)
expect(response.headers['Link'].links.size).to eq(2)
end
end
context 'when the user is authenticated' do
it 'returns http success', :aggregate_failures do
subject
expect(response).to have_http_status(200)
expect(response.headers['Link'].links.size).to eq(2)
end
end
end
context 'when the instance does not allow public preview' do
before do
Form::AdminSettings.new(timeline_preview: false).save
end
context 'when the user is not authenticated' do
let(:token) { nil }
it 'returns http unauthorized' do
subject
expect(response).to have_http_status(401)
end
end
context 'when the user is authenticated' do
it 'returns http success', :aggregate_failures do
subject
expect(response).to have_http_status(200)
expect(response.headers['Link'].links.size).to eq(2)
end
end
end
end
end

View file

@ -44,14 +44,14 @@ RSpec.describe Api::V2::Admin::AccountsController do
context "when called with #{params.inspect}" do
let(:params) { params }
it 'returns http success' do
it "returns the correct accounts (#{expected_results.inspect})" do
expect(response).to have_http_status(200)
expect(body_json_ids).to eq(expected_results.map { |symbol| send(symbol).id })
end
it "returns the correct accounts (#{expected_results.inspect})" do
json = body_as_json
expect(json.map { |a| a[:id].to_i }).to eq(expected_results.map { |symbol| send(symbol).id })
def body_json_ids
body_as_json.map { |a| a[:id].to_i }
end
end
end

View file

@ -40,17 +40,13 @@ RSpec.describe Api::V2::Filters::KeywordsController do
post :create, params: { filter_id: filter_id, keyword: 'magic', whole_word: false }
end
it 'returns http success' do
it 'creates a filter', :aggregate_failures do
expect(response).to have_http_status(200)
end
it 'returns a keyword' do
json = body_as_json
expect(json[:keyword]).to eq 'magic'
expect(json[:whole_word]).to be false
end
it 'creates a keyword' do
filter = user.account.custom_filters.first
expect(filter).to_not be_nil
expect(filter.keywords.pluck(:keyword)).to eq ['magic']
@ -73,11 +69,9 @@ RSpec.describe Api::V2::Filters::KeywordsController do
get :show, params: { id: keyword.id }
end
it 'returns http success' do
it 'responds with the keyword', :aggregate_failures do
expect(response).to have_http_status(200)
end
it 'returns expected data' do
json = body_as_json
expect(json[:keyword]).to eq 'foo'
expect(json[:whole_word]).to be false
@ -100,11 +94,9 @@ RSpec.describe Api::V2::Filters::KeywordsController do
get :update, params: { id: keyword.id, keyword: 'updated' }
end
it 'returns http success' do
it 'updates the keyword', :aggregate_failures do
expect(response).to have_http_status(200)
end
it 'updates the keyword' do
expect(keyword.reload.keyword).to eq 'updated'
end
@ -125,11 +117,9 @@ RSpec.describe Api::V2::Filters::KeywordsController do
delete :destroy, params: { id: keyword.id }
end
it 'returns http success' do
it 'destroys the keyword', :aggregate_failures do
expect(response).to have_http_status(200)
end
it 'removes the filter' do
expect { keyword.reload }.to raise_error ActiveRecord::RecordNotFound
end

View file

@ -41,16 +41,12 @@ RSpec.describe Api::V2::Filters::StatusesController do
post :create, params: { filter_id: filter_id, status_id: status.id }
end
it 'returns http success' do
it 'creates a filter', :aggregate_failures do
expect(response).to have_http_status(200)
end
it 'returns a status filter' do
json = body_as_json
expect(json[:status_id]).to eq status.id.to_s
end
it 'creates a status filter' do
filter = user.account.custom_filters.first
expect(filter).to_not be_nil
expect(filter.statuses.pluck(:status_id)).to eq [status.id]
@ -73,11 +69,9 @@ RSpec.describe Api::V2::Filters::StatusesController do
get :show, params: { id: status_filter.id }
end
it 'returns http success' do
it 'responds with the filter', :aggregate_failures do
expect(response).to have_http_status(200)
end
it 'returns expected data' do
json = body_as_json
expect(json[:status_id]).to eq status_filter.status_id.to_s
end
@ -99,11 +93,9 @@ RSpec.describe Api::V2::Filters::StatusesController do
delete :destroy, params: { id: status_filter.id }
end
it 'returns http success' do
it 'destroys the filter', :aggregate_failures do
expect(response).to have_http_status(200)
end
it 'removes the filter' do
expect { status_filter.reload }.to raise_error ActiveRecord::RecordNotFound
end

View file

@ -0,0 +1,81 @@
# frozen_string_literal: true
require 'rails_helper'
describe 'Admin::Accounts' do
let(:current_user) { Fabricate(:user, role: UserRole.find_by(name: 'Admin')) }
before do
sign_in current_user
end
describe 'Performing batch updates' do
let(:unapproved_user_account) { Fabricate(:account) }
let(:approved_user_account) { Fabricate(:account) }
before do
unapproved_user_account.user.update(approved: false)
approved_user_account.user.update(approved: true)
visit admin_accounts_path
end
context 'without selecting any accounts' do
it 'displays a notice about account selection' do
click_on button_for_suspend
expect(page).to have_content(selection_error_text)
end
end
context 'with action of `suspend`' do
it 'suspends the account' do
batch_checkbox_for(approved_user_account).check
click_on button_for_suspend
expect(approved_user_account.reload).to be_suspended
end
end
context 'with action of `approve`' do
it 'approves the account user' do
batch_checkbox_for(unapproved_user_account).check
click_on button_for_approve
expect(unapproved_user_account.reload.user).to be_approved
end
end
context 'with action of `reject`' do
it 'rejects and removes the account' do
batch_checkbox_for(unapproved_user_account).check
click_on button_for_reject
expect { unapproved_user_account.reload }.to raise_error(ActiveRecord::RecordNotFound)
end
end
def button_for_suspend
I18n.t('admin.accounts.perform_full_suspension')
end
def button_for_approve
I18n.t('admin.accounts.approve')
end
def button_for_reject
I18n.t('admin.accounts.reject')
end
def selection_error_text
I18n.t('admin.accounts.no_account_selected')
end
def batch_checkbox_for(account)
find("#form_account_batch_account_ids_#{account.id}")
end
end
end

View file

@ -0,0 +1,33 @@
# frozen_string_literal: true
require 'rails_helper'
describe 'Admin::CustomEmojis' do
let(:current_user) { Fabricate(:user, role: UserRole.find_by(name: 'Admin')) }
before do
sign_in current_user
end
describe 'Performing batch updates' do
before do
visit admin_custom_emojis_path
end
context 'without selecting any records' do
it 'displays a notice about selection' do
click_on button_for_enable
expect(page).to have_content(selection_error_text)
end
end
def button_for_enable
I18n.t('admin.custom_emojis.enable')
end
def selection_error_text
I18n.t('admin.custom_emojis.no_emoji_selected')
end
end
end

View file

@ -0,0 +1,33 @@
# frozen_string_literal: true
require 'rails_helper'
describe 'Admin::EmailDomainBlocks' do
let(:current_user) { Fabricate(:user, role: UserRole.find_by(name: 'Admin')) }
before do
sign_in current_user
end
describe 'Performing batch updates' do
before do
visit admin_email_domain_blocks_path
end
context 'without selecting any records' do
it 'displays a notice about selection' do
click_on button_for_delete
expect(page).to have_content(selection_error_text)
end
end
def button_for_delete
I18n.t('admin.email_domain_blocks.delete')
end
def selection_error_text
I18n.t('admin.email_domain_blocks.no_email_domain_block_selected')
end
end
end

View file

@ -0,0 +1,33 @@
# frozen_string_literal: true
require 'rails_helper'
describe 'Admin::IpBlocks' do
let(:current_user) { Fabricate(:user, role: UserRole.find_by(name: 'Admin')) }
before do
sign_in current_user
end
describe 'Performing batch updates' do
before do
visit admin_ip_blocks_path
end
context 'without selecting any records' do
it 'displays a notice about selection' do
click_on button_for_delete
expect(page).to have_content(selection_error_text)
end
end
def button_for_delete
I18n.t('admin.ip_blocks.delete')
end
def selection_error_text
I18n.t('admin.ip_blocks.no_ip_block_selected')
end
end
end

View file

@ -0,0 +1,34 @@
# frozen_string_literal: true
require 'rails_helper'
describe 'Admin::Statuses' do
let(:current_user) { Fabricate(:user, role: UserRole.find_by(name: 'Admin')) }
before do
sign_in current_user
end
describe 'Performing batch updates' do
before do
_status = Fabricate(:status, account: current_user.account)
visit admin_account_statuses_path(account_id: current_user.account_id)
end
context 'without selecting any records' do
it 'displays a notice about selection' do
click_on button_for_report
expect(page).to have_content(selection_error_text)
end
end
def button_for_report
I18n.t('admin.statuses.batch.report')
end
def selection_error_text
I18n.t('admin.statuses.no_status_selected')
end
end
end

View file

@ -0,0 +1,33 @@
# frozen_string_literal: true
require 'rails_helper'
describe 'Admin::Trends::Links::PreviewCardProviders' do
let(:current_user) { Fabricate(:user, role: UserRole.find_by(name: 'Admin')) }
before do
sign_in current_user
end
describe 'Performing batch updates' do
before do
visit admin_trends_links_preview_card_providers_path
end
context 'without selecting any records' do
it 'displays a notice about selection' do
click_on button_for_allow
expect(page).to have_content(selection_error_text)
end
end
def button_for_allow
I18n.t('admin.trends.allow')
end
def selection_error_text
I18n.t('admin.trends.links.publishers.no_publisher_selected')
end
end
end

View file

@ -0,0 +1,33 @@
# frozen_string_literal: true
require 'rails_helper'
describe 'Admin::Trends::Links' do
let(:current_user) { Fabricate(:user, role: UserRole.find_by(name: 'Admin')) }
before do
sign_in current_user
end
describe 'Performing batch updates' do
before do
visit admin_trends_links_path
end
context 'without selecting any records' do
it 'displays a notice about selection' do
click_on button_for_allow
expect(page).to have_content(selection_error_text)
end
end
def button_for_allow
I18n.t('admin.trends.links.allow')
end
def selection_error_text
I18n.t('admin.trends.links.no_link_selected')
end
end
end

View file

@ -0,0 +1,33 @@
# frozen_string_literal: true
require 'rails_helper'
describe 'Admin::Trends::Statuses' do
let(:current_user) { Fabricate(:user, role: UserRole.find_by(name: 'Admin')) }
before do
sign_in current_user
end
describe 'Performing batch updates' do
before do
visit admin_trends_statuses_path
end
context 'without selecting any records' do
it 'displays a notice about selection' do
click_on button_for_allow
expect(page).to have_content(selection_error_text)
end
end
def button_for_allow
I18n.t('admin.trends.statuses.allow')
end
def selection_error_text
I18n.t('admin.trends.statuses.no_status_selected')
end
end
end

View file

@ -0,0 +1,33 @@
# frozen_string_literal: true
require 'rails_helper'
describe 'Admin::Trends::Tags' do
let(:current_user) { Fabricate(:user, role: UserRole.find_by(name: 'Admin')) }
before do
sign_in current_user
end
describe 'Performing batch updates' do
before do
visit admin_trends_tags_path
end
context 'without selecting any records' do
it 'displays a notice about selection' do
click_on button_for_allow
expect(page).to have_content(selection_error_text)
end
end
def button_for_allow
I18n.t('admin.trends.allow')
end
def selection_error_text
I18n.t('admin.trends.tags.no_tag_selected')
end
end
end

View file

@ -562,6 +562,44 @@ RSpec.describe FeedManager do
end
end
describe '#unmerge_tag_from_home' do
let(:receiver) { Fabricate(:account) }
let(:tag) { Fabricate(:tag) }
it 'leaves a tagged status' do
status = Fabricate(:status)
status.tags << tag
described_class.instance.push_to_home(receiver, status)
described_class.instance.unmerge_tag_from_home(tag, receiver)
expect(redis.zrange("feed:home:#{receiver.id}", 0, -1)).to_not include(status.id.to_s)
end
it 'remains a tagged status written by receiver\'s followee' do
followee = Fabricate(:account)
receiver.follow!(followee)
status = Fabricate(:status, account: followee)
status.tags << tag
described_class.instance.push_to_home(receiver, status)
described_class.instance.unmerge_tag_from_home(tag, receiver)
expect(redis.zrange("feed:home:#{receiver.id}", 0, -1)).to include(status.id.to_s)
end
it 'remains a tagged status written by receiver' do
status = Fabricate(:status, account: receiver)
status.tags << tag
described_class.instance.push_to_home(receiver, status)
described_class.instance.unmerge_tag_from_home(tag, receiver)
expect(redis.zrange("feed:home:#{receiver.id}", 0, -1)).to include(status.id.to_s)
end
end
describe '#clear_from_home' do
let(:account) { Fabricate(:account) }
let(:followed_account) { Fabricate(:account) }

View file

@ -54,26 +54,6 @@ Devise::Test::ControllerHelpers.module_eval do
end
end
module SignedRequestHelpers
def get(path, headers: nil, sign_with: nil, **args)
return super path, headers: headers, **args if sign_with.nil?
headers ||= {}
headers['Date'] = Time.now.utc.httpdate
headers['Host'] = ENV.fetch('LOCAL_DOMAIN')
signed_headers = headers.merge('(request-target)' => "get #{path}").slice('(request-target)', 'Host', 'Date')
key_id = ActivityPub::TagManager.instance.key_uri_for(sign_with)
keypair = sign_with.keypair
signed_string = signed_headers.map { |key, value| "#{key.downcase}: #{value}" }.join("\n")
signature = Base64.strict_encode64(keypair.sign(OpenSSL::Digest.new('SHA256'), signed_string))
headers['Signature'] = "keyId=\"#{key_id}\",algorithm=\"rsa-sha256\",headers=\"#{signed_headers.keys.join(' ').downcase}\",signature=\"#{signature}\""
super path, headers: headers, **args
end
end
RSpec.configure do |config|
# This is set before running spec:system, see lib/tasks/tests.rake
config.filter_run_excluding type: lambda { |type|

View file

@ -51,14 +51,9 @@ RSpec.describe 'Account actions' do
it_behaves_like 'a successful notification delivery'
it_behaves_like 'a successful logged action', :disable, :user
it 'returns http success' do
subject
expect(response).to have_http_status(200)
end
it 'disables the target account' do
expect { subject }.to change { target_account.reload.user_disabled? }.from(false).to(true)
expect(response).to have_http_status(200)
end
end
@ -70,14 +65,9 @@ RSpec.describe 'Account actions' do
it_behaves_like 'a successful notification delivery'
it_behaves_like 'a successful logged action', :sensitive, :account
it 'returns http success' do
subject
expect(response).to have_http_status(200)
end
it 'marks the target account as sensitive' do
expect { subject }.to change { target_account.reload.sensitized? }.from(false).to(true)
expect(response).to have_http_status(200)
end
end
@ -89,14 +79,9 @@ RSpec.describe 'Account actions' do
it_behaves_like 'a successful notification delivery'
it_behaves_like 'a successful logged action', :silence, :account
it 'returns http success' do
subject
expect(response).to have_http_status(200)
end
it 'marks the target account as silenced' do
expect { subject }.to change { target_account.reload.silenced? }.from(false).to(true)
expect(response).to have_http_status(200)
end
end
@ -108,14 +93,9 @@ RSpec.describe 'Account actions' do
it_behaves_like 'a successful notification delivery'
it_behaves_like 'a successful logged action', :suspend, :account
it 'returns http success' do
subject
expect(response).to have_http_status(200)
end
it 'marks the target account as suspended' do
expect { subject }.to change { target_account.reload.suspended? }.from(false).to(true)
expect(response).to have_http_status(200)
end
end

View file

@ -92,15 +92,10 @@ RSpec.describe 'Canonical Email Blocks' do
it_behaves_like 'forbidden for wrong role', 'Moderator'
context 'when the requested canonical email block exists' do
it 'returns http success' do
it 'returns the requested canonical email block data correctly', :aggregate_failures do
subject
expect(response).to have_http_status(200)
end
it 'returns the requested canonical email block data correctly' do
subject
json = body_as_json
expect(json[:id]).to eq(canonical_email_block.id.to_s)
@ -142,29 +137,19 @@ RSpec.describe 'Canonical Email Blocks' do
context 'when there is a matching canonical email block' do
let!(:canonical_email_block) { CanonicalEmailBlock.create(params) }
it 'returns http success' do
it 'returns the expected canonical email hash', :aggregate_failures do
subject
expect(response).to have_http_status(200)
end
it 'returns the expected canonical email hash' do
subject
expect(body_as_json[0][:canonical_email_hash]).to eq(canonical_email_block.canonical_email_hash)
end
end
context 'when there is no matching canonical email block' do
it 'returns http success' do
it 'returns an empty list', :aggregate_failures do
subject
expect(response).to have_http_status(200)
end
it 'returns an empty list' do
subject
expect(body_as_json).to be_empty
end
end
@ -183,15 +168,10 @@ RSpec.describe 'Canonical Email Blocks' do
it_behaves_like 'forbidden for wrong role', ''
it_behaves_like 'forbidden for wrong role', 'Moderator'
it 'returns http success' do
it 'returns the canonical_email_hash correctly', :aggregate_failures do
subject
expect(response).to have_http_status(200)
end
it 'returns the canonical_email_hash correctly' do
subject
expect(body_as_json[:canonical_email_hash]).to eq(canonical_email_block.canonical_email_hash)
end
@ -208,15 +188,10 @@ RSpec.describe 'Canonical Email Blocks' do
context 'when the canonical_email_hash param is provided instead of email' do
let(:params) { { canonical_email_hash: 'dd501ce4e6b08698f19df96f2f15737e48a75660b1fa79b6ff58ea25ee4851a4' } }
it 'returns http success' do
it 'returns the correct canonical_email_hash', :aggregate_failures do
subject
expect(response).to have_http_status(200)
end
it 'returns the correct canonical_email_hash' do
subject
expect(body_as_json[:canonical_email_hash]).to eq(params[:canonical_email_hash])
end
end
@ -224,15 +199,10 @@ RSpec.describe 'Canonical Email Blocks' do
context 'when both email and canonical_email_hash params are provided' do
let(:params) { { email: 'example@email.com', canonical_email_hash: 'dd501ce4e6b08698f19df96f2f15737e48a75660b1fa79b6ff58ea25ee4851a4' } }
it 'returns http success' do
it 'ignores the canonical_email_hash param', :aggregate_failures do
subject
expect(response).to have_http_status(200)
end
it 'ignores the canonical_email_hash param' do
subject
expect(body_as_json[:canonical_email_hash]).to eq(canonical_email_block.canonical_email_hash)
end
end
@ -262,15 +232,10 @@ RSpec.describe 'Canonical Email Blocks' do
it_behaves_like 'forbidden for wrong role', ''
it_behaves_like 'forbidden for wrong role', 'Moderator'
it 'returns http success' do
it 'deletes the canonical email block', :aggregate_failures do
subject
expect(response).to have_http_status(200)
end
it 'deletes the canonical email block' do
subject
expect(CanonicalEmailBlock.find_by(id: canonical_email_block.id)).to be_nil
end

View file

@ -75,15 +75,10 @@ RSpec.describe 'Domain Allows' do
it_behaves_like 'forbidden for wrong role', ''
it_behaves_like 'forbidden for wrong role', 'Moderator'
it 'returns http success' do
it 'returns the expected allowed domain name', :aggregate_failures do
subject
expect(response).to have_http_status(200)
end
it 'returns the expected allowed domain name' do
subject
expect(body_as_json[:domain]).to eq domain_allow.domain
end
@ -108,21 +103,11 @@ RSpec.describe 'Domain Allows' do
it_behaves_like 'forbidden for wrong role', 'Moderator'
context 'with a valid domain name' do
it 'returns http success' do
it 'returns the expected domain name', :aggregate_failures do
subject
expect(response).to have_http_status(200)
end
it 'returns the expected domain name' do
subject
expect(body_as_json[:domain]).to eq 'foo.bar.com'
end
it 'creates a domain allow' do
subject
expect(DomainAllow.find_by(domain: 'foo.bar.com')).to be_present
end
end
@ -171,15 +156,10 @@ RSpec.describe 'Domain Allows' do
it_behaves_like 'forbidden for wrong role', ''
it_behaves_like 'forbidden for wrong role', 'Moderator'
it 'returns http success' do
it 'deletes the allowed domain', :aggregate_failures do
subject
expect(response).to have_http_status(200)
end
it 'deletes the allowed domain' do
subject
expect(DomainAllow.find_by(id: domain_allow.id)).to be_nil
end

View file

@ -143,16 +143,23 @@ RSpec.describe 'Domain Blocks' do
it_behaves_like 'forbidden for wrong role', ''
it_behaves_like 'forbidden for wrong role', 'Moderator'
it 'returns http success' do
it 'returns the expected domain block content', :aggregate_failures do
subject
expect(response).to have_http_status(200)
end
it 'returns the expected domain block content' do
subject
expect(body_as_json).to eq(expected_response)
expect(body_as_json).to eq(
{
id: domain_block.id.to_s,
domain: domain_block.domain,
created_at: domain_block.created_at.strftime('%Y-%m-%dT%H:%M:%S.%LZ'),
severity: domain_block.severity.to_s,
reject_media: domain_block.reject_media,
reject_reports: domain_block.reject_reports,
private_comment: domain_block.private_comment,
public_comment: domain_block.public_comment,
obfuscate: domain_block.obfuscate,
}
)
end
context 'when the requested domain block does not exist' do
@ -175,27 +182,18 @@ RSpec.describe 'Domain Blocks' do
it_behaves_like 'forbidden for wrong role', ''
it_behaves_like 'forbidden for wrong role', 'Moderator'
it 'returns http success' do
subject
expect(response).to have_http_status(200)
end
it 'returns expected domain name and severity' do
it 'returns expected domain name and severity', :aggregate_failures do
subject
body = body_as_json
expect(response).to have_http_status(200)
expect(body).to match a_hash_including(
{
domain: 'foo.bar.com',
severity: 'silence',
}
)
end
it 'creates a domain block' do
subject
expect(DomainBlock.find_by(domain: 'foo.bar.com')).to be_present
end
@ -205,15 +203,10 @@ RSpec.describe 'Domain Blocks' do
Fabricate(:domain_block, domain: 'bar.com', severity: :suspend)
end
it 'returns http unprocessable entity' do
it 'returns existing domain block in error', :aggregate_failures do
subject
expect(response).to have_http_status(422)
end
it 'returns existing domain block in error' do
subject
expect(body_as_json[:existing_domain_block][:domain]).to eq('bar.com')
end
end
@ -241,15 +234,10 @@ RSpec.describe 'Domain Blocks' do
it_behaves_like 'forbidden for wrong role', ''
it_behaves_like 'forbidden for wrong role', 'Moderator'
it 'returns http success' do
it 'returns the updated domain block', :aggregate_failures do
subject
expect(response).to have_http_status(200)
end
it 'returns the updated domain block' do
subject
expect(body_as_json).to match a_hash_including(
{
id: domain_block.id.to_s,
@ -283,15 +271,10 @@ RSpec.describe 'Domain Blocks' do
it_behaves_like 'forbidden for wrong role', ''
it_behaves_like 'forbidden for wrong role', 'Moderator'
it 'returns http success' do
it 'deletes the domain block', :aggregate_failures do
subject
expect(response).to have_http_status(200)
end
it 'deletes the domain block' do
subject
expect(DomainBlock.find_by(id: domain_block.id)).to be_nil
end

View file

@ -93,15 +93,10 @@ RSpec.describe 'Email Domain Blocks' do
it_behaves_like 'forbidden for wrong role', 'Moderator'
context 'when email domain block exists' do
it 'returns http success' do
it 'returns the correct blocked domain', :aggregate_failures do
subject
expect(response).to have_http_status(200)
end
it 'returns the correct blocked domain' do
subject
expect(body_as_json[:domain]).to eq(email_domain_block.domain)
end
end
@ -126,15 +121,10 @@ RSpec.describe 'Email Domain Blocks' do
it_behaves_like 'forbidden for wrong role', ''
it_behaves_like 'forbidden for wrong role', 'Moderator'
it 'returns http success' do
it 'returns the correct blocked email domain', :aggregate_failures do
subject
expect(response).to have_http_status(200)
end
it 'returns the correct blocked email domain' do
subject
expect(body_as_json[:domain]).to eq(params[:domain])
end
@ -182,21 +172,11 @@ RSpec.describe 'Email Domain Blocks' do
it_behaves_like 'forbidden for wrong role', ''
it_behaves_like 'forbidden for wrong role', 'Moderator'
it 'returns http success' do
it 'deletes email domain block', :aggregate_failures do
subject
expect(response).to have_http_status(200)
end
it 'returns an empty body' do
subject
expect(body_as_json).to be_empty
end
it 'deletes email domain block' do
subject
expect(EmailDomainBlock.find_by(id: email_domain_block.id)).to be_nil
end

View file

@ -84,15 +84,10 @@ RSpec.describe 'IP Blocks' do
it_behaves_like 'forbidden for wrong role', ''
it_behaves_like 'forbidden for wrong role', 'Moderator'
it 'returns http success' do
it 'returns the correct ip block', :aggregate_failures do
subject
expect(response).to have_http_status(200)
end
it 'returns the correct ip block' do
subject
json = body_as_json
expect(json[:ip]).to eq("#{ip_block.ip}/#{ip_block.ip.prefix}")
@ -119,15 +114,10 @@ RSpec.describe 'IP Blocks' do
it_behaves_like 'forbidden for wrong role', ''
it_behaves_like 'forbidden for wrong role', 'Moderator'
it 'returns http success' do
it 'returns the correct ip block', :aggregate_failures do
subject
expect(response).to have_http_status(200)
end
it 'returns the correct ip block' do
subject
json = body_as_json
expect(json[:ip]).to eq("#{params[:ip]}/32")
@ -186,15 +176,10 @@ RSpec.describe 'IP Blocks' do
let!(:ip_block) { IpBlock.create(ip: '185.200.13.3', severity: 'no_access', comment: 'Spam', expires_in: 48.hours) }
let(:params) { { severity: 'sign_up_requires_approval', comment: 'Decreasing severity' } }
it 'returns http success' do
it 'returns the correct ip block', :aggregate_failures do
subject
expect(response).to have_http_status(200)
end
it 'returns the correct ip block' do
subject
expect(body_as_json).to match(hash_including({
ip: "#{ip_block.ip}/#{ip_block.ip.prefix}",
severity: 'sign_up_requires_approval',
@ -226,21 +211,11 @@ RSpec.describe 'IP Blocks' do
let!(:ip_block) { IpBlock.create(ip: '185.200.13.3', severity: 'no_access') }
it 'returns http success' do
it 'deletes the ip block', :aggregate_failures do
subject
expect(response).to have_http_status(200)
end
it 'returns an empty body' do
subject
expect(body_as_json).to be_empty
end
it 'deletes the ip block' do
subject
expect(IpBlock.find_by(id: ip_block.id)).to be_nil
end

View file

@ -122,15 +122,10 @@ RSpec.describe 'Reports' do
it_behaves_like 'forbidden for wrong scope', 'write:statuses'
it_behaves_like 'forbidden for wrong role', ''
it 'returns http success' do
it 'returns the requested report content', :aggregate_failures do
subject
expect(response).to have_http_status(200)
end
it 'returns the requested report content' do
subject
expect(body_as_json).to include(
{
id: report.id.to_s,
@ -155,18 +150,10 @@ RSpec.describe 'Reports' do
let!(:report) { Fabricate(:report, category: :other) }
let(:params) { { category: 'spam' } }
it 'returns http success' do
subject
it 'updates the report category', :aggregate_failures do
expect { subject }.to change { report.reload.category }.from('other').to('spam')
expect(response).to have_http_status(200)
end
it 'updates the report category' do
expect { subject }.to change { report.reload.category }.from('other').to('spam')
end
it 'returns the updated report content' do
subject
report.reload
@ -196,14 +183,9 @@ RSpec.describe 'Reports' do
it_behaves_like 'forbidden for wrong scope', 'write:statuses'
it_behaves_like 'forbidden for wrong role', ''
it 'returns http success' do
subject
expect(response).to have_http_status(200)
end
it 'marks report as resolved' do
it 'marks report as resolved', :aggregate_failures do
expect { subject }.to change { report.reload.unresolved? }.from(true).to(false)
expect(response).to have_http_status(200)
end
end
@ -217,14 +199,9 @@ RSpec.describe 'Reports' do
it_behaves_like 'forbidden for wrong scope', 'write:statuses'
it_behaves_like 'forbidden for wrong role', ''
it 'returns http success' do
subject
expect(response).to have_http_status(200)
end
it 'marks report as unresolved' do
it 'marks report as unresolved', :aggregate_failures do
expect { subject }.to change { report.reload.unresolved? }.from(false).to(true)
expect(response).to have_http_status(200)
end
end
@ -238,14 +215,9 @@ RSpec.describe 'Reports' do
it_behaves_like 'forbidden for wrong scope', 'write:statuses'
it_behaves_like 'forbidden for wrong role', ''
it 'returns http success' do
subject
expect(response).to have_http_status(200)
end
it 'assigns report to the requesting user' do
it 'assigns report to the requesting user', :aggregate_failures do
expect { subject }.to change { report.reload.assigned_account_id }.from(nil).to(user.account.id)
expect(response).to have_http_status(200)
end
end
@ -259,14 +231,9 @@ RSpec.describe 'Reports' do
it_behaves_like 'forbidden for wrong scope', 'write:statuses'
it_behaves_like 'forbidden for wrong role', ''
it 'returns http success' do
subject
expect(response).to have_http_status(200)
end
it 'unassigns report from assignee' do
it 'unassigns report from assignee', :aggregate_failures do
expect { subject }.to change { report.reload.assigned_account_id }.from(user.account.id).to(nil)
expect(response).to have_http_status(200)
end
end
end

View file

@ -0,0 +1,129 @@
# frozen_string_literal: true
require 'rails_helper'
describe 'Links' do
let(:role) { UserRole.find_by(name: 'Admin') }
let(:user) { Fabricate(:user, role: role) }
let(:scopes) { 'admin:read admin:write' }
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) }
let(:headers) { { 'Authorization' => "Bearer #{token.token}" } }
describe 'GET /api/v1/admin/trends/links' do
subject do
get '/api/v1/admin/trends/links', headers: headers
end
it 'returns http success' do
subject
expect(response).to have_http_status(200)
end
end
describe 'POST /api/v1/admin/trends/links/:id/approve' do
subject do
post "/api/v1/admin/trends/links/#{preview_card.id}/approve", headers: headers
end
let(:preview_card) { Fabricate(:preview_card, trendable: false) }
it_behaves_like 'forbidden for wrong scope', 'read write'
it_behaves_like 'forbidden for wrong role', ''
it 'returns http success' do
subject
expect(response).to have_http_status(200)
end
it 'sets the link as trendable' do
expect { subject }.to change { preview_card.reload.trendable }.from(false).to(true)
end
it 'returns the link data' do
subject
expect(body_as_json).to match(
a_hash_including(
url: preview_card.url,
title: preview_card.title,
description: preview_card.description,
type: 'link',
requires_review: false
)
)
end
context 'when the link does not exist' do
it 'returns http not found' do
post '/api/v1/admin/trends/links/-1/approve', headers: headers
expect(response).to have_http_status(404)
end
end
context 'without an authorization header' do
let(:headers) { {} }
it 'returns http forbidden' do
subject
expect(response).to have_http_status(403)
end
end
end
describe 'POST /api/v1/admin/trends/links/:id/reject' do
subject do
post "/api/v1/admin/trends/links/#{preview_card.id}/reject", headers: headers
end
let(:preview_card) { Fabricate(:preview_card, trendable: false) }
it_behaves_like 'forbidden for wrong scope', 'read write'
it_behaves_like 'forbidden for wrong role', ''
it 'returns http success' do
subject
expect(response).to have_http_status(200)
end
it 'does not set the link as trendable' do
expect { subject }.to_not(change { preview_card.reload.trendable })
end
it 'returns the link data' do
subject
expect(body_as_json).to match(
a_hash_including(
url: preview_card.url,
title: preview_card.title,
description: preview_card.description,
type: 'link',
requires_review: false
)
)
end
context 'when the link does not exist' do
it 'returns http not found' do
post '/api/v1/admin/trends/links/-1/reject', headers: headers
expect(response).to have_http_status(404)
end
end
context 'without an authorization header' do
let(:headers) { {} }
it 'returns http forbidden' do
subject
expect(response).to have_http_status(403)
end
end
end
end

View file

@ -12,14 +12,10 @@ describe 'Credentials' do
let(:token) { Fabricate(:accessible_access_token, scopes: 'read', application: Fabricate(:application)) }
let(:headers) { { 'Authorization' => "Bearer #{token.token}" } }
it 'returns http success' do
it 'returns the app information correctly', :aggregate_failures do
subject
expect(response).to have_http_status(200)
end
it 'returns the app information correctly' do
subject
expect(body_as_json).to match(
a_hash_including(

View file

@ -23,20 +23,11 @@ RSpec.describe 'Apps' do
end
context 'with valid params' do
it 'returns http success' do
it 'creates an OAuth app', :aggregate_failures do
subject
expect(response).to have_http_status(200)
end
it 'creates an OAuth app' do
subject
expect(Doorkeeper::Application.find_by(name: client_name)).to be_present
end
it 'returns client ID and client secret' do
subject
body = body_as_json
@ -58,15 +49,10 @@ RSpec.describe 'Apps' do
context 'with many duplicate scopes' do
let(:scopes) { (%w(read) * 40).join(' ') }
it 'returns http success' do
it 'only saves the scope once', :aggregate_failures do
subject
expect(response).to have_http_status(200)
end
it 'only saves the scope once' do
subject
expect(Doorkeeper::Application.find_by(name: client_name).scopes.to_s).to eq 'read'
end
end

View file

@ -22,15 +22,10 @@ RSpec.describe 'Domain blocks' do
it_behaves_like 'forbidden for wrong scope', 'write:blocks'
it 'returns http success' do
it 'returns the domains blocked by the requesting user', :aggregate_failures do
subject
expect(response).to have_http_status(200)
end
it 'returns the domains blocked by the requesting user' do
subject
expect(body_as_json).to match_array(blocked_domains)
end
@ -54,15 +49,10 @@ RSpec.describe 'Domain blocks' do
it_behaves_like 'forbidden for wrong scope', 'read read:blocks'
it 'returns http success' do
it 'creates a domain block', :aggregate_failures do
subject
expect(response).to have_http_status(200)
end
it 'creates a domain block' do
subject
expect(user.account.domain_blocking?(params[:domain])).to be(true)
end
@ -100,15 +90,10 @@ RSpec.describe 'Domain blocks' do
it_behaves_like 'forbidden for wrong scope', 'read read:blocks'
it 'returns http success' do
it 'deletes the specified domain block', :aggregate_failures do
subject
expect(response).to have_http_status(200)
end
it 'deletes the specified domain block' do
subject
expect(user.account.domain_blocking?('example.com')).to be(false)
end

View file

@ -0,0 +1,71 @@
# frozen_string_literal: true
require 'rails_helper'
RSpec.describe 'Favourites' do
let(:user) { Fabricate(:user) }
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) }
let(:scopes) { 'read:favourites' }
let(:headers) { { Authorization: "Bearer #{token.token}" } }
describe 'GET /api/v1/favourites' do
subject do
get '/api/v1/favourites', headers: headers, params: params
end
let(:params) { {} }
let!(:favourites) { Fabricate.times(3, :favourite, account: user.account) }
let(:expected_response) do
favourites.map do |favourite|
a_hash_including(id: favourite.status.id.to_s, account: a_hash_including(id: favourite.status.account.id.to_s))
end
end
it_behaves_like 'forbidden for wrong scope', 'write'
it 'returns http success' do
subject
expect(response).to have_http_status(200)
end
it 'returns the favourites' do
subject
expect(body_as_json).to match_array(expected_response)
end
context 'with limit param' do
let(:params) { { limit: 2 } }
it 'returns only the requested number of favourites' do
subject
expect(body_as_json.size).to eq(params[:limit])
end
it 'sets the correct pagination header for the prev path' 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))
end
end
context 'without an authorization header' do
let(:headers) { {} }
it 'returns http unauthorized' do
subject
expect(response).to have_http_status(401)
end
end
end
end

View file

@ -32,15 +32,10 @@ RSpec.describe 'Follow requests' do
it_behaves_like 'forbidden for wrong scope', 'write write:follows'
it 'returns http success' do
it 'returns the expected content from accounts requesting to follow', :aggregate_failures do
subject
expect(response).to have_http_status(200)
end
it 'returns the expected content from accounts requesting to follow' do
subject
expect(body_as_json).to match_array(expected_response)
end
@ -68,19 +63,9 @@ RSpec.describe 'Follow requests' do
it_behaves_like 'forbidden for wrong scope', 'read read:follows'
it 'returns http success' do
subject
expect(response).to have_http_status(200)
end
it 'allows the requesting follower to follow' do
it 'allows the requesting follower to follow', :aggregate_failures do
expect { subject }.to change { follower.following?(user.account) }.from(false).to(true)
end
it 'returns JSON with followed_by set to true' do
subject
expect(response).to have_http_status(200)
expect(body_as_json[:followed_by]).to be true
end
end
@ -98,21 +83,11 @@ RSpec.describe 'Follow requests' do
it_behaves_like 'forbidden for wrong scope', 'read read:follows'
it 'returns http success' do
it 'removes the follow request', :aggregate_failures do
subject
expect(response).to have_http_status(200)
end
it 'removes the follow request' do
subject
expect(FollowRequest.where(target_account: user.account, account: follower)).to_not exist
end
it 'returns JSON with followed_by set to false' do
subject
expect(body_as_json[:followed_by]).to be false
end
end

View file

@ -0,0 +1,65 @@
# frozen_string_literal: true
require 'rails_helper'
RSpec.describe 'Followed tags' do
let(:user) { Fabricate(:user) }
let(:scopes) { 'read:follows' }
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) }
let(:headers) { { 'Authorization' => "Bearer #{token.token}" } }
describe 'GET /api/v1/followed_tags' do
subject do
get '/api/v1/followed_tags', headers: headers, params: params
end
let!(:tag_follows) { Fabricate.times(5, :tag_follow, account: user.account) }
let(:params) { {} }
let(:expected_response) do
tag_follows.map do |tag_follow|
a_hash_including(name: tag_follow.tag.name, following: true)
end
end
before do
Fabricate(:tag_follow)
end
it_behaves_like 'forbidden for wrong scope', 'write write:follows'
it 'returns http success' do
subject
expect(response).to have_http_status(:success)
end
it 'returns the followed tags correctly' do
subject
expect(body_as_json).to match_array(expected_response)
end
context 'with limit param' do
let(:params) { { limit: 3 } }
it 'returns only the requested number of follow tags' do
subject
expect(body_as_json.size).to eq(params[:limit])
end
it 'sets the correct pagination header for the prev path' 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[2].id))
end
end
end
end

View file

@ -51,16 +51,11 @@ RSpec.describe 'Lists' do
it_behaves_like 'forbidden for wrong scope', 'write write:lists'
it 'returns http success' do
it 'returns the expected lists', :aggregate_failures do
subject
expect(response).to have_http_status(200)
end
it 'returns the expected lists' do
subject
expect(body_as_json).to match_array(expected_response_with_antennas)
expect(body_as_json).to match_array(expected_response)
end
end
@ -73,15 +68,10 @@ RSpec.describe 'Lists' do
it_behaves_like 'forbidden for wrong scope', 'write write:lists'
it 'returns http success' do
it 'returns the requested list correctly', :aggregate_failures do
subject
expect(response).to have_http_status(200)
end
it 'returns the requested list correctly' do
subject
expect(body_as_json).to eq({
id: list.id.to_s,
title: list.title,
@ -119,21 +109,11 @@ RSpec.describe 'Lists' do
it_behaves_like 'forbidden for wrong scope', 'read read:lists'
it 'returns http success' do
it 'returns the new list', :aggregate_failures do
subject
expect(response).to have_http_status(200)
end
it 'returns the new list' do
subject
expect(body_as_json).to match(a_hash_including(title: 'my list', replies_policy: 'none', exclusive: true))
end
it 'creates a list' do
subject
expect(List.where(account: user.account).count).to eq(1)
end
@ -168,15 +148,10 @@ RSpec.describe 'Lists' do
it_behaves_like 'forbidden for wrong scope', 'read read:lists'
it 'returns http success' do
it 'returns the updated list', :aggregate_failures do
subject
expect(response).to have_http_status(200)
end
it 'returns the updated list' do
subject
list.reload
expect(body_as_json).to eq({
@ -228,15 +203,10 @@ RSpec.describe 'Lists' do
it_behaves_like 'forbidden for wrong scope', 'read read:lists'
it 'returns http success' do
it 'deletes the list', :aggregate_failures do
subject
expect(response).to have_http_status(200)
end
it 'deletes the list' do
subject
expect(List.where(id: list.id)).to_not exist
end

View file

@ -0,0 +1,89 @@
# frozen_string_literal: true
require 'rails_helper'
RSpec.describe 'Reports' do
let(:user) { Fabricate(:user) }
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) }
let(:scopes) { 'write:reports' }
let(:headers) { { 'Authorization' => "Bearer #{token.token}" } }
describe 'POST /api/v1/reports' do
subject do
post '/api/v1/reports', headers: headers, params: params
end
let!(:admin) { Fabricate(:user, role: UserRole.find_by(name: 'Admin')) }
let(:status) { Fabricate(:status) }
let(:target_account) { status.account }
let(:category) { 'other' }
let(:forward) { nil }
let(:rule_ids) { nil }
let(:params) do
{
status_ids: [status.id],
account_id: target_account.id,
comment: 'reasons',
category: category,
rule_ids: rule_ids,
forward: forward,
}
end
it_behaves_like 'forbidden for wrong scope', 'read read:reports'
it 'creates a report', :aggregate_failures do
perform_enqueued_jobs do
subject
expect(response).to have_http_status(200)
expect(body_as_json).to match(
a_hash_including(
status_ids: [status.id.to_s],
category: category,
comment: 'reasons'
)
)
expect(target_account.targeted_reports).to_not be_empty
expect(target_account.targeted_reports.first.comment).to eq 'reasons'
expect(ActionMailer::Base.deliveries.first.to).to eq([admin.email])
end
end
context 'when a status does not belong to the reported account' do
let(:target_account) { Fabricate(:account) }
it 'returns http not found' do
subject
expect(response).to have_http_status(404)
end
end
context 'when a category is chosen' do
let(:category) { 'spam' }
it 'saves category' do
subject
expect(target_account.targeted_reports.first.spam?).to be true
end
end
context 'when violated rules are chosen' do
let(:rule) { Fabricate(:rule) }
let(:category) { 'violation' }
let(:rule_ids) { [rule.id] }
it 'saves category and rule_ids' do
subject
expect(target_account.targeted_reports.first.violation?).to be true
expect(target_account.targeted_reports.first.rule_ids).to contain_exactly(rule.id)
end
end
end
end

View file

@ -0,0 +1,72 @@
# frozen_string_literal: true
require 'rails_helper'
RSpec.describe 'Sources' do
let(:user) { Fabricate(:user) }
let(:scopes) { 'read:statuses' }
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) }
let(:headers) { { 'Authorization' => "Bearer #{token.token}" } }
describe 'GET /api/v1/statuses/:status_id/source' do
subject do
get "/api/v1/statuses/#{status.id}/source", headers: headers
end
let(:status) { Fabricate(:status) }
it_behaves_like 'forbidden for wrong scope', 'write write:statuses'
context 'with public status' do
it 'returns the source properties of the status', :aggregate_failures do
subject
expect(response).to have_http_status(200)
expect(body_as_json).to eq({
id: status.id.to_s,
text: status.text,
spoiler_text: status.spoiler_text,
})
end
end
context 'with private status of non-followed account' do
let(:status) { Fabricate(:status, visibility: :private) }
it 'returns http not found' do
subject
expect(response).to have_http_status(404)
end
end
context 'with private status of followed account' do
let(:status) { Fabricate(:status, visibility: :private) }
before do
user.account.follow!(status.account)
end
it 'returns the source properties of the status', :aggregate_failures do
subject
expect(response).to have_http_status(200)
expect(body_as_json).to eq({
id: status.id.to_s,
text: status.text,
spoiler_text: status.spoiler_text,
})
end
end
context 'without an authorization header' do
let(:headers) { {} }
it 'returns http unauthorized' do
subject
expect(response).to have_http_status(401)
end
end
end
end

View file

@ -17,15 +17,10 @@ RSpec.describe 'Tags' do
let!(:tag) { Fabricate(:tag) }
let(:name) { tag.name }
it 'returns http success' do
it 'returns the tag', :aggregate_failures do
subject
expect(response).to have_http_status(200)
end
it 'returns the tag' do
subject
expect(body_as_json[:name]).to eq(name)
end
end
@ -62,15 +57,10 @@ RSpec.describe 'Tags' do
it_behaves_like 'forbidden for wrong scope', 'read read:follows'
context 'when the tag exists' do
it 'returns http success' do
it 'creates follow', :aggregate_failures do
subject
expect(response).to have_http_status(:success)
end
it 'creates follow' do
subject
expect(TagFollow.where(tag: tag, account: user.account)).to exist
end
end
@ -78,21 +68,11 @@ RSpec.describe 'Tags' do
context 'when the tag does not exist' do
let(:name) { 'hoge' }
it 'returns http success' do
it 'creates a new tag with the specified name', :aggregate_failures do
subject
expect(response).to have_http_status(200)
end
it 'creates a new tag with the specified name' do
subject
expect(Tag.where(name: name)).to exist
end
it 'creates follow' do
subject
expect(TagFollow.where(tag: Tag.find_by(name: name), account: user.account)).to exist
end
end
@ -133,15 +113,10 @@ RSpec.describe 'Tags' do
it_behaves_like 'forbidden for wrong scope', 'read read:follows'
it 'returns http success' do
it 'removes the follow', :aggregate_failures do
subject
expect(response).to have_http_status(200)
end
it 'removes the follow' do
subject
expect(TagFollow.where(tag: tag, account: user.account)).to_not exist
end

View file

@ -0,0 +1,112 @@
# frozen_string_literal: true
require 'rails_helper'
RSpec.describe 'Tag' do
let(:user) { Fabricate(:user) }
let(:scopes) { 'read:statuses' }
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) }
let(:headers) { { 'Authorization' => "Bearer #{token.token}" } }
shared_examples 'a successful request to the tag timeline' do
it 'returns the expected statuses', :aggregate_failures do
subject
expect(response).to have_http_status(200)
expect(body_as_json.pluck(:id)).to match_array(expected_statuses.map { |status| status.id.to_s })
end
end
describe 'GET /api/v1/timelines/tag/:hashtag' do
subject do
get "/api/v1/timelines/tag/#{hashtag}", headers: headers, params: params
end
let(:account) { Fabricate(:account) }
let!(:private_status) { PostStatusService.new.call(account, visibility: :private, text: '#life could be a dream') } # rubocop:disable RSpec/LetSetup
let!(:life_status) { PostStatusService.new.call(account, text: 'tell me what is my #life without your #love') }
let!(:war_status) { PostStatusService.new.call(user.account, text: '#war, war never changes') }
let!(:love_status) { PostStatusService.new.call(account, text: 'what is #love?') }
let(:params) { {} }
let(:hashtag) { 'life' }
context 'when given only one hashtag' do
let(:expected_statuses) { [life_status] }
it_behaves_like 'a successful request to the tag timeline'
end
context 'with any param' do
let(:expected_statuses) { [life_status, love_status] }
let(:params) { { any: %(love) } }
it_behaves_like 'a successful request to the tag timeline'
end
context 'with all param' do
let(:expected_statuses) { [life_status] }
let(:params) { { all: %w(love) } }
it_behaves_like 'a successful request to the tag timeline'
end
context 'with none param' do
let(:expected_statuses) { [war_status] }
let(:hashtag) { 'war' }
let(:params) { { none: %w(life love) } }
it_behaves_like 'a successful request to the tag timeline'
end
context 'with limit param' do
let(:hashtag) { 'love' }
let(:params) { { limit: 1 } }
it 'returns only the requested number of statuses' do
subject
expect(body_as_json.size).to eq(params[:limit])
end
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))
end
end
context 'when the instance allows public preview' do
context 'when the user is not authenticated' do
let(:headers) { {} }
let(:expected_statuses) { [life_status] }
it_behaves_like 'a successful request to the tag timeline'
end
end
context 'when the instance does not allow public preview' do
before do
Form::AdminSettings.new(timeline_preview: false).save
end
context 'when the user is not authenticated' do
let(:headers) { {} }
it 'returns http unauthorized' do
subject
expect(response).to have_http_status(401)
end
end
context 'when the user is authenticated' do
let(:expected_statuses) { [life_status] }
it_behaves_like 'a successful request to the tag timeline'
end
end
end
end

View file

@ -0,0 +1,21 @@
# frozen_string_literal: true
module SignedRequestHelpers
def get(path, headers: nil, sign_with: nil, **args)
return super path, headers: headers, **args if sign_with.nil?
headers ||= {}
headers['Date'] = Time.now.utc.httpdate
headers['Host'] = ENV.fetch('LOCAL_DOMAIN')
signed_headers = headers.merge('(request-target)' => "get #{path}").slice('(request-target)', 'Host', 'Date')
key_id = ActivityPub::TagManager.instance.key_uri_for(sign_with)
keypair = sign_with.keypair
signed_string = signed_headers.map { |key, value| "#{key.downcase}: #{value}" }.join("\n")
signature = Base64.strict_encode64(keypair.sign(OpenSSL::Digest.new('SHA256'), signed_string))
headers['Signature'] = "keyId=\"#{key_id}\",algorithm=\"rsa-sha256\",headers=\"#{signed_headers.keys.join(' ').downcase}\",signature=\"#{signature}\""
super path, headers: headers, **args
end
end

View file

@ -67,39 +67,31 @@ describe MoveWorker do
end
shared_examples 'block and mute handling' do
it 'makes blocks carry over and add a note' do
it 'makes blocks and mutes carry over and adds a note' do
subject.perform(source_account.id, target_account.id)
expect(block_service).to have_received(:call).with(blocking_account, target_account)
expect(AccountNote.find_by(account: blocking_account, target_account: target_account).comment).to include(source_account.acct)
end
it 'makes mutes carry over and add a note' do
subject.perform(source_account.id, target_account.id)
expect(muting_account.muting?(target_account)).to be true
expect(AccountNote.find_by(account: muting_account, target_account: target_account).comment).to include(source_account.acct)
end
end
shared_examples 'followers count handling' do
it 'updates the source account followers count' do
it 'updates the source and target account followers counts' do
subject.perform(source_account.id, target_account.id)
expect(source_account.reload.followers_count).to eq(source_account.passive_relationships.count)
end
it 'updates the target account followers count' do
subject.perform(source_account.id, target_account.id)
expect(source_account.reload.followers_count).to eq(source_account.passive_relationships.count)
expect(target_account.reload.followers_count).to eq(target_account.passive_relationships.count)
end
end
shared_examples 'lists handling' do
it 'puts the new account on the list' do
it 'puts the new account on the list and makes valid lists', sidekiq: :inline do
subject.perform(source_account.id, target_account.id)
expect(list.accounts.include?(target_account)).to be true
end
it 'does not create invalid list memberships' do
subject.perform(source_account.id, target_account.id)
expect(list.accounts.include?(target_account)).to be true
expect(ListAccount.all).to all be_valid
end
end