Merge remote-tracking branch 'parent/main' into upstream-20231120
This commit is contained in:
commit
abec232dd7
85 changed files with 1314 additions and 458 deletions
5
spec/fabricators/account_deletion_request_fabricator.rb
Normal file
5
spec/fabricators/account_deletion_request_fabricator.rb
Normal file
|
@ -0,0 +1,5 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
Fabricator(:account_deletion_request) do
|
||||
account
|
||||
end
|
7
spec/fabricators/import_fabricator.rb
Normal file
7
spec/fabricators/import_fabricator.rb
Normal file
|
@ -0,0 +1,7 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
Fabricator(:import) do
|
||||
account
|
||||
type :following
|
||||
data { attachment_fixture('imports.txt') }
|
||||
end
|
|
@ -13,14 +13,13 @@ RSpec.describe AdminMailer do
|
|||
recipient.user.update(locale: :en)
|
||||
end
|
||||
|
||||
it 'renders the headers' do
|
||||
expect(mail.subject).to eq("New report for cb6e6126.ngrok.io (##{report.id})")
|
||||
expect(mail.to).to eq [recipient.user_email]
|
||||
expect(mail.from).to eq ['notifications@localhost']
|
||||
end
|
||||
|
||||
it 'renders the body' do
|
||||
expect(mail.body.encoded).to eq("Mike,\r\n\r\nJohn has reported Mike\r\n\r\nView: https://cb6e6126.ngrok.io/admin/reports/#{report.id}\r\n")
|
||||
it 'renders the email' do
|
||||
expect(mail)
|
||||
.to be_present
|
||||
.and(deliver_to(recipient.user_email))
|
||||
.and(deliver_from('notifications@localhost'))
|
||||
.and(have_subject("New report for cb6e6126.ngrok.io (##{report.id})"))
|
||||
.and(have_body_text("Mike,\r\n\r\nJohn has reported Mike\r\n\r\nView: https://cb6e6126.ngrok.io/admin/reports/#{report.id}\r\n"))
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -33,14 +32,13 @@ RSpec.describe AdminMailer do
|
|||
recipient.user.update(locale: :en)
|
||||
end
|
||||
|
||||
it 'renders the headers' do
|
||||
expect(mail.subject).to eq("#{appeal.account.username} is appealing a moderation decision on cb6e6126.ngrok.io")
|
||||
expect(mail.to).to eq [recipient.user_email]
|
||||
expect(mail.from).to eq ['notifications@localhost']
|
||||
end
|
||||
|
||||
it 'renders the body' do
|
||||
expect(mail.body.encoded).to match "#{appeal.account.username} is appealing a moderation decision by #{appeal.strike.account.username}"
|
||||
it 'renders the email' do
|
||||
expect(mail)
|
||||
.to be_present
|
||||
.and(deliver_to(recipient.user_email))
|
||||
.and(deliver_from('notifications@localhost'))
|
||||
.and(have_subject("#{appeal.account.username} is appealing a moderation decision on cb6e6126.ngrok.io"))
|
||||
.and(have_body_text("#{appeal.account.username} is appealing a moderation decision by #{appeal.strike.account.username}"))
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -53,14 +51,13 @@ RSpec.describe AdminMailer do
|
|||
recipient.user.update(locale: :en)
|
||||
end
|
||||
|
||||
it 'renders the headers' do
|
||||
expect(mail.subject).to eq("New account up for review on cb6e6126.ngrok.io (#{user.account.username})")
|
||||
expect(mail.to).to eq [recipient.user_email]
|
||||
expect(mail.from).to eq ['notifications@localhost']
|
||||
end
|
||||
|
||||
it 'renders the body' do
|
||||
expect(mail.body.encoded).to match 'The details of the new account are below. You can approve or reject this application.'
|
||||
it 'renders the email' do
|
||||
expect(mail)
|
||||
.to be_present
|
||||
.and(deliver_to(recipient.user_email))
|
||||
.and(deliver_from('notifications@localhost'))
|
||||
.and(have_subject("New account up for review on cb6e6126.ngrok.io (#{user.account.username})"))
|
||||
.and(have_body_text('The details of the new account are below. You can approve or reject this application.'))
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -95,14 +92,13 @@ RSpec.describe AdminMailer do
|
|||
recipient.user.update(locale: :en)
|
||||
end
|
||||
|
||||
it 'renders the headers' do
|
||||
expect(mail.subject).to eq('New trends up for review on cb6e6126.ngrok.io')
|
||||
expect(mail.to).to eq [recipient.user_email]
|
||||
expect(mail.from).to eq ['notifications@localhost']
|
||||
end
|
||||
|
||||
it 'renders the body' do
|
||||
expect(mail.body.encoded).to match 'The following items need a review before they can be displayed publicly'
|
||||
it 'renders the email' do
|
||||
expect(mail)
|
||||
.to be_present
|
||||
.and(deliver_to(recipient.user_email))
|
||||
.and(deliver_from('notifications@localhost'))
|
||||
.and(have_subject('New trends up for review on cb6e6126.ngrok.io'))
|
||||
.and(have_body_text('The following items need a review before they can be displayed publicly'))
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -114,14 +110,13 @@ RSpec.describe AdminMailer do
|
|||
recipient.user.update(locale: :en)
|
||||
end
|
||||
|
||||
it 'renders the headers' do
|
||||
expect(mail.subject).to eq('New Mastodon versions are available for cb6e6126.ngrok.io!')
|
||||
expect(mail.to).to eq [recipient.user_email]
|
||||
expect(mail.from).to eq ['notifications@localhost']
|
||||
end
|
||||
|
||||
it 'renders the body' do
|
||||
expect(mail.body.encoded).to match 'New Mastodon versions have been released, you may want to update!'
|
||||
it 'renders the email' do
|
||||
expect(mail)
|
||||
.to be_present
|
||||
.and(deliver_to(recipient.user_email))
|
||||
.and(deliver_from('notifications@localhost'))
|
||||
.and(have_subject('New Mastodon versions are available for cb6e6126.ngrok.io!'))
|
||||
.and(have_body_text('New Mastodon versions have been released, you may want to update!'))
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -133,18 +128,16 @@ RSpec.describe AdminMailer do
|
|||
recipient.user.update(locale: :en)
|
||||
end
|
||||
|
||||
it 'renders the headers', :aggregate_failures do
|
||||
expect(mail.subject).to eq('Critical Mastodon updates are available for cb6e6126.ngrok.io!')
|
||||
expect(mail.to).to eq [recipient.user_email]
|
||||
expect(mail.from).to eq ['notifications@localhost']
|
||||
|
||||
expect(mail['Importance'].value).to eq 'high'
|
||||
expect(mail['Priority'].value).to eq 'urgent'
|
||||
expect(mail['X-Priority'].value).to eq '1'
|
||||
end
|
||||
|
||||
it 'renders the body' do
|
||||
expect(mail.body.encoded).to match 'New critical versions of Mastodon have been released, you may want to update as soon as possible!'
|
||||
it 'renders the email' do
|
||||
expect(mail)
|
||||
.to be_present
|
||||
.and(deliver_to(recipient.user_email))
|
||||
.and(deliver_from('notifications@localhost'))
|
||||
.and(have_subject('Critical Mastodon updates are available for cb6e6126.ngrok.io!'))
|
||||
.and(have_body_text('New critical versions of Mastodon have been released, you may want to update as soon as possible!'))
|
||||
.and(have_header('Importance', 'high'))
|
||||
.and(have_header('Priority', 'urgent'))
|
||||
.and(have_header('X-Priority', '1'))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -8,24 +8,27 @@ RSpec.describe NotificationMailer do
|
|||
let(:foreign_status) { Fabricate(:status, account: sender, text: 'The body of the foreign status') }
|
||||
let(:own_status) { Fabricate(:status, account: receiver.account, text: 'The body of the own status') }
|
||||
|
||||
shared_examples 'headers' do |type, thread|
|
||||
it 'renders the to and from headers' do
|
||||
expect(mail[:to].value).to eq "#{receiver.account.username} <#{receiver.email}>"
|
||||
expect(mail.from).to eq ['notifications@localhost']
|
||||
shared_examples 'standard headers' do |type|
|
||||
it 'renders the email' do
|
||||
expect(mail)
|
||||
.to be_present
|
||||
.and(have_header('To', "#{receiver.account.username} <#{receiver.email}>"))
|
||||
.and(have_header('List-ID', "<#{type}.alice.cb6e6126.ngrok.io>"))
|
||||
.and(have_header('List-Unsubscribe', %r{<https://cb6e6126.ngrok.io/unsubscribe\?token=.+>}))
|
||||
.and(have_header('List-Unsubscribe', /&type=#{type}/))
|
||||
.and(have_header('List-Unsubscribe-Post', 'List-Unsubscribe=One-Click'))
|
||||
.and(deliver_to("#{receiver.account.username} <#{receiver.email}>"))
|
||||
.and(deliver_from('notifications@localhost'))
|
||||
end
|
||||
end
|
||||
|
||||
it 'renders the list headers' do
|
||||
expect(mail['List-ID'].value).to eq "<#{type}.alice.cb6e6126.ngrok.io>"
|
||||
expect(mail['List-Unsubscribe'].value).to match(%r{<https://cb6e6126.ngrok.io/unsubscribe\?token=.+>})
|
||||
expect(mail['List-Unsubscribe'].value).to match("&type=#{type}")
|
||||
expect(mail['List-Unsubscribe-Post'].value).to eq 'List-Unsubscribe=One-Click'
|
||||
end
|
||||
|
||||
if thread
|
||||
it 'renders the thread headers' do
|
||||
expect(mail['In-Reply-To'].value).to match(/<conversation-\d+.\d\d\d\d-\d\d-\d\d@cb6e6126.ngrok.io>/)
|
||||
expect(mail['References'].value).to match(/<conversation-\d+.\d\d\d\d-\d\d-\d\d@cb6e6126.ngrok.io>/)
|
||||
end
|
||||
shared_examples 'thread headers' do
|
||||
it 'renders the email with conversation thread headers' do
|
||||
conversation_header_regex = /<conversation-\d+.\d\d\d\d-\d\d-\d\d@cb6e6126.ngrok.io>/
|
||||
expect(mail)
|
||||
.to be_present
|
||||
.and(have_header('In-Reply-To', conversation_header_regex))
|
||||
.and(have_header('References', conversation_header_regex))
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -35,15 +38,15 @@ RSpec.describe NotificationMailer do
|
|||
let(:mail) { prepared_mailer_for(receiver.account).mention }
|
||||
|
||||
include_examples 'localized subject', 'notification_mailer.mention.subject', name: 'bob'
|
||||
include_examples 'headers', 'mention', true
|
||||
include_examples 'standard headers', 'mention'
|
||||
include_examples 'thread headers'
|
||||
|
||||
it 'renders the subject' do
|
||||
expect(mail.subject).to eq('You were mentioned by bob')
|
||||
end
|
||||
|
||||
it 'renders the body' do
|
||||
expect(mail.body.encoded).to match('You were mentioned by bob')
|
||||
expect(mail.body.encoded).to include 'The body of the foreign status'
|
||||
it 'renders the email' do
|
||||
expect(mail)
|
||||
.to be_present
|
||||
.and(have_subject('You were mentioned by bob'))
|
||||
.and(have_body_text('You were mentioned by bob'))
|
||||
.and(have_body_text('The body of the foreign status'))
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -53,14 +56,13 @@ RSpec.describe NotificationMailer do
|
|||
let(:mail) { prepared_mailer_for(receiver.account).follow }
|
||||
|
||||
include_examples 'localized subject', 'notification_mailer.follow.subject', name: 'bob'
|
||||
include_examples 'headers', 'follow', false
|
||||
include_examples 'standard headers', 'follow'
|
||||
|
||||
it 'renders the subject' do
|
||||
expect(mail.subject).to eq('bob is now following you')
|
||||
end
|
||||
|
||||
it 'renders the body' do
|
||||
expect(mail.body.encoded).to match('bob is now following you')
|
||||
it 'renders the email' do
|
||||
expect(mail)
|
||||
.to be_present
|
||||
.and(have_subject('bob is now following you'))
|
||||
.and(have_body_text('bob is now following you'))
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -70,15 +72,15 @@ RSpec.describe NotificationMailer do
|
|||
let(:mail) { prepared_mailer_for(own_status.account).favourite }
|
||||
|
||||
include_examples 'localized subject', 'notification_mailer.favourite.subject', name: 'bob'
|
||||
include_examples 'headers', 'favourite', true
|
||||
include_examples 'standard headers', 'favourite'
|
||||
include_examples 'thread headers'
|
||||
|
||||
it 'renders the subject' do
|
||||
expect(mail.subject).to eq('bob favorited your post')
|
||||
end
|
||||
|
||||
it 'renders the body' do
|
||||
expect(mail.body.encoded).to match('Your post was favorited by bob')
|
||||
expect(mail.body.encoded).to include 'The body of the own status'
|
||||
it 'renders the email' do
|
||||
expect(mail)
|
||||
.to be_present
|
||||
.and(have_subject('bob favorited your post'))
|
||||
.and(have_body_text('Your post was favorited by bob'))
|
||||
.and(have_body_text('The body of the own status'))
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -88,15 +90,15 @@ RSpec.describe NotificationMailer do
|
|||
let(:mail) { prepared_mailer_for(own_status.account).reblog }
|
||||
|
||||
include_examples 'localized subject', 'notification_mailer.reblog.subject', name: 'bob'
|
||||
include_examples 'headers', 'reblog', true
|
||||
include_examples 'standard headers', 'reblog'
|
||||
include_examples 'thread headers'
|
||||
|
||||
it 'renders the subject' do
|
||||
expect(mail.subject).to eq('bob boosted your post')
|
||||
end
|
||||
|
||||
it 'renders the body' do
|
||||
expect(mail.body.encoded).to match('Your post was boosted by bob')
|
||||
expect(mail.body.encoded).to include 'The body of the own status'
|
||||
it 'renders the email' do
|
||||
expect(mail)
|
||||
.to be_present
|
||||
.and(have_subject('bob boosted your post'))
|
||||
.and(have_body_text('Your post was boosted by bob'))
|
||||
.and(have_body_text('The body of the own status'))
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -106,14 +108,13 @@ RSpec.describe NotificationMailer do
|
|||
let(:mail) { prepared_mailer_for(receiver.account).follow_request }
|
||||
|
||||
include_examples 'localized subject', 'notification_mailer.follow_request.subject', name: 'bob'
|
||||
include_examples 'headers', 'follow_request', false
|
||||
include_examples 'standard headers', 'follow_request'
|
||||
|
||||
it 'renders the subject' do
|
||||
expect(mail.subject).to eq('Pending follower: bob')
|
||||
end
|
||||
|
||||
it 'renders the body' do
|
||||
expect(mail.body.encoded).to match('bob has requested to follow you')
|
||||
it 'renders the email' do
|
||||
expect(mail)
|
||||
.to be_present
|
||||
.and(have_subject('Pending follower: bob'))
|
||||
.and(have_body_text('bob has requested to follow you'))
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -10,9 +10,12 @@ describe UserMailer do
|
|||
|
||||
it 'renders confirmation instructions' do
|
||||
receiver.update!(locale: nil)
|
||||
expect(mail.body.encoded).to include I18n.t('devise.mailer.confirmation_instructions.title')
|
||||
expect(mail.body.encoded).to include 'spec'
|
||||
expect(mail.body.encoded).to include Rails.configuration.x.local_domain
|
||||
|
||||
expect(mail)
|
||||
.to be_present
|
||||
.and(have_body_text(I18n.t('devise.mailer.confirmation_instructions.title')))
|
||||
.and(have_body_text('spec'))
|
||||
.and(have_body_text(Rails.configuration.x.local_domain))
|
||||
end
|
||||
|
||||
include_examples 'localized subject',
|
||||
|
@ -25,13 +28,17 @@ describe UserMailer do
|
|||
|
||||
it 'renders reconfirmation instructions' do
|
||||
receiver.update!(email: 'new-email@example.com', locale: nil)
|
||||
expect(mail.body.encoded).to include I18n.t('devise.mailer.reconfirmation_instructions.title')
|
||||
expect(mail.body.encoded).to include 'spec'
|
||||
expect(mail.body.encoded).to include Rails.configuration.x.local_domain
|
||||
expect(mail.subject).to eq I18n.t('devise.mailer.reconfirmation_instructions.subject',
|
||||
instance: Rails.configuration.x.local_domain,
|
||||
locale: I18n.default_locale)
|
||||
|
||||
expect(mail)
|
||||
.to be_present
|
||||
.and(have_body_text(I18n.t('devise.mailer.reconfirmation_instructions.title')))
|
||||
.and(have_body_text('spec'))
|
||||
.and(have_body_text(Rails.configuration.x.local_domain))
|
||||
end
|
||||
|
||||
include_examples 'localized subject',
|
||||
'devise.mailer.confirmation_instructions.subject',
|
||||
instance: Rails.configuration.x.local_domain
|
||||
end
|
||||
|
||||
describe '#reset_password_instructions' do
|
||||
|
@ -39,8 +46,11 @@ describe UserMailer do
|
|||
|
||||
it 'renders reset password instructions' do
|
||||
receiver.update!(locale: nil)
|
||||
expect(mail.body.encoded).to include I18n.t('devise.mailer.reset_password_instructions.title')
|
||||
expect(mail.body.encoded).to include 'spec'
|
||||
|
||||
expect(mail)
|
||||
.to be_present
|
||||
.and(have_body_text(I18n.t('devise.mailer.reset_password_instructions.title')))
|
||||
.and(have_body_text('spec'))
|
||||
end
|
||||
|
||||
include_examples 'localized subject',
|
||||
|
@ -52,7 +62,10 @@ describe UserMailer do
|
|||
|
||||
it 'renders password change notification' do
|
||||
receiver.update!(locale: nil)
|
||||
expect(mail.body.encoded).to include I18n.t('devise.mailer.password_change.title')
|
||||
|
||||
expect(mail)
|
||||
.to be_present
|
||||
.and(have_body_text(I18n.t('devise.mailer.password_change.title')))
|
||||
end
|
||||
|
||||
include_examples 'localized subject',
|
||||
|
@ -64,7 +77,10 @@ describe UserMailer do
|
|||
|
||||
it 'renders email change notification' do
|
||||
receiver.update!(locale: nil)
|
||||
expect(mail.body.encoded).to include I18n.t('devise.mailer.email_changed.title')
|
||||
|
||||
expect(mail)
|
||||
.to be_present
|
||||
.and(have_body_text(I18n.t('devise.mailer.email_changed.title')))
|
||||
end
|
||||
|
||||
include_examples 'localized subject',
|
||||
|
@ -77,8 +93,11 @@ describe UserMailer do
|
|||
|
||||
it 'renders warning notification' do
|
||||
receiver.update!(locale: nil)
|
||||
expect(mail.body.encoded).to include I18n.t('user_mailer.warning.title.suspend', acct: receiver.account.acct)
|
||||
expect(mail.body.encoded).to include strike.text
|
||||
|
||||
expect(mail)
|
||||
.to be_present
|
||||
.and(have_body_text(I18n.t('user_mailer.warning.title.suspend', acct: receiver.account.acct)))
|
||||
.and(have_body_text(strike.text))
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -88,7 +107,10 @@ describe UserMailer do
|
|||
|
||||
it 'renders webauthn credential deleted notification' do
|
||||
receiver.update!(locale: nil)
|
||||
expect(mail.body.encoded).to include I18n.t('devise.mailer.webauthn_credential.deleted.title')
|
||||
|
||||
expect(mail)
|
||||
.to be_present
|
||||
.and(have_body_text(I18n.t('devise.mailer.webauthn_credential.deleted.title')))
|
||||
end
|
||||
|
||||
include_examples 'localized subject',
|
||||
|
@ -103,7 +125,10 @@ describe UserMailer do
|
|||
|
||||
it 'renders suspicious sign in notification' do
|
||||
receiver.update!(locale: nil)
|
||||
expect(mail.body.encoded).to include I18n.t('user_mailer.suspicious_sign_in.explanation')
|
||||
|
||||
expect(mail)
|
||||
.to be_present
|
||||
.and(have_body_text(I18n.t('user_mailer.suspicious_sign_in.explanation')))
|
||||
end
|
||||
|
||||
include_examples 'localized subject',
|
||||
|
@ -115,8 +140,10 @@ describe UserMailer do
|
|||
let(:mail) { described_class.appeal_approved(receiver, appeal) }
|
||||
|
||||
it 'renders appeal_approved notification' do
|
||||
expect(mail.subject).to eq I18n.t('user_mailer.appeal_approved.subject', date: I18n.l(appeal.created_at))
|
||||
expect(mail.body.encoded).to include I18n.t('user_mailer.appeal_approved.title')
|
||||
expect(mail)
|
||||
.to be_present
|
||||
.and(have_subject(I18n.t('user_mailer.appeal_approved.subject', date: I18n.l(appeal.created_at))))
|
||||
.and(have_body_text(I18n.t('user_mailer.appeal_approved.title')))
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -125,8 +152,10 @@ describe UserMailer do
|
|||
let(:mail) { described_class.appeal_rejected(receiver, appeal) }
|
||||
|
||||
it 'renders appeal_rejected notification' do
|
||||
expect(mail.subject).to eq I18n.t('user_mailer.appeal_rejected.subject', date: I18n.l(appeal.created_at))
|
||||
expect(mail.body.encoded).to include I18n.t('user_mailer.appeal_rejected.title')
|
||||
expect(mail)
|
||||
.to be_present
|
||||
.and(have_subject(I18n.t('user_mailer.appeal_rejected.subject', date: I18n.l(appeal.created_at))))
|
||||
.and(have_body_text(I18n.t('user_mailer.appeal_rejected.title')))
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -134,8 +163,10 @@ describe UserMailer do
|
|||
let(:mail) { described_class.two_factor_enabled(receiver) }
|
||||
|
||||
it 'renders two_factor_enabled mail' do
|
||||
expect(mail.subject).to eq I18n.t('devise.mailer.two_factor_enabled.subject')
|
||||
expect(mail.body.encoded).to include I18n.t('devise.mailer.two_factor_enabled.explanation')
|
||||
expect(mail)
|
||||
.to be_present
|
||||
.and(have_subject(I18n.t('devise.mailer.two_factor_enabled.subject')))
|
||||
.and(have_body_text(I18n.t('devise.mailer.two_factor_enabled.explanation')))
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -143,8 +174,10 @@ describe UserMailer do
|
|||
let(:mail) { described_class.two_factor_disabled(receiver) }
|
||||
|
||||
it 'renders two_factor_disabled mail' do
|
||||
expect(mail.subject).to eq I18n.t('devise.mailer.two_factor_disabled.subject')
|
||||
expect(mail.body.encoded).to include I18n.t('devise.mailer.two_factor_disabled.explanation')
|
||||
expect(mail)
|
||||
.to be_present
|
||||
.and(have_subject(I18n.t('devise.mailer.two_factor_disabled.subject')))
|
||||
.and(have_body_text(I18n.t('devise.mailer.two_factor_disabled.explanation')))
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -152,8 +185,10 @@ describe UserMailer do
|
|||
let(:mail) { described_class.webauthn_enabled(receiver) }
|
||||
|
||||
it 'renders webauthn_enabled mail' do
|
||||
expect(mail.subject).to eq I18n.t('devise.mailer.webauthn_enabled.subject')
|
||||
expect(mail.body.encoded).to include I18n.t('devise.mailer.webauthn_enabled.explanation')
|
||||
expect(mail)
|
||||
.to be_present
|
||||
.and(have_subject(I18n.t('devise.mailer.webauthn_enabled.subject')))
|
||||
.and(have_body_text(I18n.t('devise.mailer.webauthn_enabled.explanation')))
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -161,8 +196,10 @@ describe UserMailer do
|
|||
let(:mail) { described_class.webauthn_disabled(receiver) }
|
||||
|
||||
it 'renders webauthn_disabled mail' do
|
||||
expect(mail.subject).to eq I18n.t('devise.mailer.webauthn_disabled.subject')
|
||||
expect(mail.body.encoded).to include I18n.t('devise.mailer.webauthn_disabled.explanation')
|
||||
expect(mail)
|
||||
.to be_present
|
||||
.and(have_subject(I18n.t('devise.mailer.webauthn_disabled.subject')))
|
||||
.and(have_body_text(I18n.t('devise.mailer.webauthn_disabled.explanation')))
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -170,8 +207,10 @@ describe UserMailer do
|
|||
let(:mail) { described_class.two_factor_recovery_codes_changed(receiver) }
|
||||
|
||||
it 'renders two_factor_recovery_codes_changed mail' do
|
||||
expect(mail.subject).to eq I18n.t('devise.mailer.two_factor_recovery_codes_changed.subject')
|
||||
expect(mail.body.encoded).to include I18n.t('devise.mailer.two_factor_recovery_codes_changed.explanation')
|
||||
expect(mail)
|
||||
.to be_present
|
||||
.and(have_subject(I18n.t('devise.mailer.two_factor_recovery_codes_changed.subject')))
|
||||
.and(have_body_text(I18n.t('devise.mailer.two_factor_recovery_codes_changed.explanation')))
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -180,8 +219,10 @@ describe UserMailer do
|
|||
let(:mail) { described_class.webauthn_credential_added(receiver, credential) }
|
||||
|
||||
it 'renders webauthn_credential_added mail' do
|
||||
expect(mail.subject).to eq I18n.t('devise.mailer.webauthn_credential.added.subject')
|
||||
expect(mail.body.encoded).to include I18n.t('devise.mailer.webauthn_credential.added.explanation')
|
||||
expect(mail)
|
||||
.to be_present
|
||||
.and(have_subject(I18n.t('devise.mailer.webauthn_credential.added.subject')))
|
||||
.and(have_body_text(I18n.t('devise.mailer.webauthn_credential.added.explanation')))
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -189,8 +230,10 @@ describe UserMailer do
|
|||
let(:mail) { described_class.welcome(receiver) }
|
||||
|
||||
it 'renders welcome mail' do
|
||||
expect(mail.subject).to eq I18n.t('user_mailer.welcome.subject')
|
||||
expect(mail.body.encoded).to include I18n.t('user_mailer.welcome.explanation')
|
||||
expect(mail)
|
||||
.to be_present
|
||||
.and(have_subject(I18n.t('user_mailer.welcome.subject')))
|
||||
.and(have_body_text(I18n.t('user_mailer.welcome.explanation')))
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -199,8 +242,10 @@ describe UserMailer do
|
|||
let(:mail) { described_class.backup_ready(receiver, backup) }
|
||||
|
||||
it 'renders backup_ready mail' do
|
||||
expect(mail.subject).to eq I18n.t('user_mailer.backup_ready.subject')
|
||||
expect(mail.body.encoded).to include I18n.t('user_mailer.backup_ready.explanation')
|
||||
expect(mail)
|
||||
.to be_present
|
||||
.and(have_subject(I18n.t('user_mailer.backup_ready.subject')))
|
||||
.and(have_body_text(I18n.t('user_mailer.backup_ready.explanation')))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -23,12 +23,14 @@ RSpec.describe AccountRelationshipsPresenter do
|
|||
let(:options) { {} }
|
||||
|
||||
it 'sets default maps' do
|
||||
expect(presenter.following).to eq default_map
|
||||
expect(presenter.followed_by).to eq default_map
|
||||
expect(presenter.blocking).to eq default_map
|
||||
expect(presenter.muting).to eq default_map
|
||||
expect(presenter.requested).to eq default_map
|
||||
expect(presenter.domain_blocking).to eq default_map
|
||||
expect(presenter).to have_attributes(
|
||||
following: default_map,
|
||||
followed_by: default_map,
|
||||
blocking: default_map,
|
||||
muting: default_map,
|
||||
requested: default_map,
|
||||
domain_blocking: default_map
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -22,9 +22,12 @@ RSpec.describe FamiliarFollowersPresenter do
|
|||
it 'returns followers you follow' do
|
||||
result = subject.accounts.first
|
||||
|
||||
expect(result).to_not be_nil
|
||||
expect(result.id).to eq requested_accounts.first.id
|
||||
expect(result.accounts).to contain_exactly(familiar_follower)
|
||||
expect(result)
|
||||
.to be_present
|
||||
.and have_attributes(
|
||||
id: requested_accounts.first.id,
|
||||
accounts: contain_exactly(familiar_follower)
|
||||
)
|
||||
end
|
||||
|
||||
context 'when requested account hides followers' do
|
||||
|
@ -35,9 +38,12 @@ RSpec.describe FamiliarFollowersPresenter do
|
|||
it 'does not return followers you follow' do
|
||||
result = subject.accounts.first
|
||||
|
||||
expect(result).to_not be_nil
|
||||
expect(result.id).to eq requested_accounts.first.id
|
||||
expect(result.accounts).to be_empty
|
||||
expect(result)
|
||||
.to be_present
|
||||
.and have_attributes(
|
||||
id: requested_accounts.first.id,
|
||||
accounts: be_empty
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -49,9 +55,12 @@ RSpec.describe FamiliarFollowersPresenter do
|
|||
it 'does not return followers you follow' do
|
||||
result = subject.accounts.first
|
||||
|
||||
expect(result).to_not be_nil
|
||||
expect(result.id).to eq requested_accounts.first.id
|
||||
expect(result.accounts).to be_empty
|
||||
expect(result)
|
||||
.to be_present
|
||||
.and have_attributes(
|
||||
id: requested_accounts.first.id,
|
||||
accounts: be_empty
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -22,11 +22,13 @@ RSpec.describe StatusRelationshipsPresenter do
|
|||
let(:options) { {} }
|
||||
|
||||
it 'sets default maps' do
|
||||
expect(presenter.reblogs_map).to eq default_map
|
||||
expect(presenter.favourites_map).to eq default_map
|
||||
expect(presenter.bookmarks_map).to eq default_map
|
||||
expect(presenter.mutes_map).to eq default_map
|
||||
expect(presenter.pins_map).to eq default_map
|
||||
expect(presenter).to have_attributes(
|
||||
reblogs_map: eq(default_map),
|
||||
favourites_map: eq(default_map),
|
||||
bookmarks_map: eq(default_map),
|
||||
mutes_map: eq(default_map),
|
||||
pins_map: eq(default_map)
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -80,18 +82,30 @@ RSpec.describe StatusRelationshipsPresenter do
|
|||
|
||||
it 'sets @filters_map to filter top-level status' do
|
||||
matched_filters = presenter.filters_map[statuses[0].id]
|
||||
expect(matched_filters.size).to eq 1
|
||||
|
||||
expect(matched_filters[0].filter.title).to eq 'filter1'
|
||||
expect(matched_filters[0].keyword_matches).to eq ['banned']
|
||||
expect(matched_filters)
|
||||
.to be_an(Array)
|
||||
.and have_attributes(size: 1)
|
||||
.and contain_exactly(
|
||||
have_attributes(
|
||||
filter: have_attributes(title: 'filter1'),
|
||||
keyword_matches: contain_exactly('banned')
|
||||
)
|
||||
)
|
||||
end
|
||||
|
||||
it 'sets @filters_map to filter reblogged status' do
|
||||
matched_filters = presenter.filters_map[statuses[1].reblog_of_id]
|
||||
expect(matched_filters.size).to eq 1
|
||||
|
||||
expect(matched_filters[0].filter.title).to eq 'filter1'
|
||||
expect(matched_filters[0].keyword_matches).to eq ['irrelevant']
|
||||
expect(matched_filters)
|
||||
.to be_an(Array)
|
||||
.and have_attributes(size: 1)
|
||||
.and contain_exactly(
|
||||
have_attributes(
|
||||
filter: have_attributes(title: 'filter1'),
|
||||
keyword_matches: contain_exactly('irrelevant')
|
||||
)
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -107,18 +121,30 @@ RSpec.describe StatusRelationshipsPresenter do
|
|||
|
||||
it 'sets @filters_map to filter top-level status' do
|
||||
matched_filters = presenter.filters_map[statuses[0].id]
|
||||
expect(matched_filters.size).to eq 1
|
||||
|
||||
expect(matched_filters[0].filter.title).to eq 'filter1'
|
||||
expect(matched_filters[0].status_matches).to eq [statuses[0].id]
|
||||
expect(matched_filters)
|
||||
.to be_an(Array)
|
||||
.and have_attributes(size: 1)
|
||||
.and contain_exactly(
|
||||
have_attributes(
|
||||
filter: have_attributes(title: 'filter1'),
|
||||
status_matches: contain_exactly(statuses.first.id)
|
||||
)
|
||||
)
|
||||
end
|
||||
|
||||
it 'sets @filters_map to filter reblogged status' do
|
||||
matched_filters = presenter.filters_map[statuses[1].reblog_of_id]
|
||||
expect(matched_filters.size).to eq 1
|
||||
|
||||
expect(matched_filters[0].filter.title).to eq 'filter1'
|
||||
expect(matched_filters[0].status_matches).to eq [statuses[1].reblog_of_id]
|
||||
expect(matched_filters)
|
||||
.to be_an(Array)
|
||||
.and have_attributes(size: 1)
|
||||
.and contain_exactly(
|
||||
have_attributes(
|
||||
filter: have_attributes(title: 'filter1'),
|
||||
status_matches: contain_exactly(statuses.second.reblog_of_id)
|
||||
)
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -4,7 +4,6 @@ ENV['RAILS_ENV'] ||= 'test'
|
|||
|
||||
# This needs to be defined before Rails is initialized
|
||||
RUN_SYSTEM_SPECS = ENV.fetch('RUN_SYSTEM_SPECS', false)
|
||||
RUN_SEARCH_SPECS = ENV.fetch('RUN_SEARCH_SPECS', false)
|
||||
|
||||
if RUN_SYSTEM_SPECS
|
||||
STREAMING_PORT = ENV.fetch('TEST_STREAMING_PORT', '4020')
|
||||
|
@ -21,6 +20,7 @@ require 'webmock/rspec'
|
|||
require 'paperclip/matchers'
|
||||
require 'capybara/rspec'
|
||||
require 'chewy/rspec'
|
||||
require 'email_spec/rspec'
|
||||
|
||||
Dir[Rails.root.join('spec', 'support', '**', '*.rb')].each { |f| require f }
|
||||
|
||||
|
@ -54,20 +54,28 @@ RSpec.configure do |config|
|
|||
case type
|
||||
when :system
|
||||
!RUN_SYSTEM_SPECS
|
||||
when :search
|
||||
!RUN_SEARCH_SPECS
|
||||
end
|
||||
}
|
||||
|
||||
# By default, skip the elastic search integration specs
|
||||
config.filter_run_excluding search: true
|
||||
|
||||
config.fixture_path = Rails.root.join('spec', 'fixtures')
|
||||
config.use_transactional_fixtures = true
|
||||
config.order = 'random'
|
||||
config.infer_spec_type_from_file_location!
|
||||
config.filter_rails_from_backtrace!
|
||||
|
||||
# Set type to `cli` for all CLI specs
|
||||
config.define_derived_metadata(file_path: Regexp.new('spec/lib/mastodon/cli')) do |metadata|
|
||||
metadata[:type] = :cli
|
||||
end
|
||||
|
||||
# Set `search` metadata true for all specs in spec/search/
|
||||
config.define_derived_metadata(file_path: Regexp.new('spec/search/*')) do |metadata|
|
||||
metadata[:search] = true
|
||||
end
|
||||
|
||||
config.include Devise::Test::ControllerHelpers, type: :controller
|
||||
config.include Devise::Test::ControllerHelpers, type: :helper
|
||||
config.include Devise::Test::ControllerHelpers, type: :view
|
||||
|
|
|
@ -1,53 +0,0 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'rails_helper'
|
||||
|
||||
describe 'GET /api/v1/accounts/{account_id}' do
|
||||
it 'returns account entity as 200 OK' do
|
||||
account = Fabricate(:account)
|
||||
|
||||
get "/api/v1/accounts/#{account.id}"
|
||||
|
||||
aggregate_failures do
|
||||
expect(response).to have_http_status(200)
|
||||
expect(body_as_json[:id]).to eq(account.id.to_s)
|
||||
end
|
||||
end
|
||||
|
||||
it 'returns 404 if account not found' do
|
||||
get '/api/v1/accounts/1'
|
||||
|
||||
aggregate_failures do
|
||||
expect(response).to have_http_status(404)
|
||||
expect(body_as_json[:error]).to eq('Record not found')
|
||||
end
|
||||
end
|
||||
|
||||
context 'when with token' do
|
||||
it 'returns account entity as 200 OK if token is valid' do
|
||||
account = Fabricate(:account)
|
||||
user = Fabricate(:user, account: account)
|
||||
token = Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: 'read:accounts').token
|
||||
|
||||
get "/api/v1/accounts/#{account.id}", headers: { Authorization: "Bearer #{token}" }
|
||||
|
||||
aggregate_failures do
|
||||
expect(response).to have_http_status(200)
|
||||
expect(body_as_json[:id]).to eq(account.id.to_s)
|
||||
end
|
||||
end
|
||||
|
||||
it 'returns 403 if scope of token is invalid' do
|
||||
account = Fabricate(:account)
|
||||
user = Fabricate(:user, account: account)
|
||||
token = Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: 'write:statuses').token
|
||||
|
||||
get "/api/v1/accounts/#{account.id}", headers: { Authorization: "Bearer #{token}" }
|
||||
|
||||
aggregate_failures do
|
||||
expect(response).to have_http_status(403)
|
||||
expect(body_as_json[:error]).to eq('This action is outside the authorized scopes')
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -2,65 +2,108 @@
|
|||
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe Api::V1::AccountsController do
|
||||
render_views
|
||||
describe '/api/v1/accounts' do
|
||||
let(:user) { Fabricate(:user) }
|
||||
let(:scopes) { '' }
|
||||
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) }
|
||||
let(:headers) { { 'Authorization' => "Bearer #{token.token}" } }
|
||||
|
||||
let(:user) { Fabricate(:user) }
|
||||
let(:scopes) { '' }
|
||||
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) }
|
||||
describe 'GET /api/v1/accounts/:id' do
|
||||
context 'when logged out' do
|
||||
let(:account) { Fabricate(:account) }
|
||||
|
||||
before do
|
||||
allow(controller).to receive(:doorkeeper_token) { token }
|
||||
it 'returns account entity as 200 OK', :aggregate_failures do
|
||||
get "/api/v1/accounts/#{account.id}"
|
||||
|
||||
expect(response).to have_http_status(200)
|
||||
expect(body_as_json[:id]).to eq(account.id.to_s)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the account does not exist' do
|
||||
it 'returns http not found' do
|
||||
get '/api/v1/accounts/1'
|
||||
|
||||
expect(response).to have_http_status(404)
|
||||
expect(body_as_json[:error]).to eq('Record not found')
|
||||
end
|
||||
end
|
||||
|
||||
context 'when logged in' do
|
||||
subject do
|
||||
get "/api/v1/accounts/#{account.id}", headers: headers
|
||||
end
|
||||
|
||||
let(:account) { Fabricate(:account) }
|
||||
let(:scopes) { 'read:accounts' }
|
||||
|
||||
it 'returns account entity as 200 OK', :aggregate_failures do
|
||||
subject
|
||||
|
||||
expect(response).to have_http_status(200)
|
||||
expect(body_as_json[:id]).to eq(account.id.to_s)
|
||||
end
|
||||
|
||||
it_behaves_like 'forbidden for wrong scope', 'write:statuses'
|
||||
end
|
||||
end
|
||||
|
||||
describe 'POST #create' do
|
||||
let(:app) { Fabricate(:application) }
|
||||
let(:token) { Doorkeeper::AccessToken.find_or_create_for(application: app, resource_owner: nil, scopes: 'read write', use_refresh_token: false) }
|
||||
let(:agreement) { nil }
|
||||
|
||||
before do
|
||||
post :create, params: { username: 'test', password: '12345678', email: 'hello@world.tld', agreement: agreement }
|
||||
describe 'POST /api/v1/accounts' do
|
||||
subject do
|
||||
post '/api/v1/accounts', headers: headers, params: { username: 'test', password: '12345678', email: 'hello@world.tld', agreement: agreement }
|
||||
end
|
||||
|
||||
let(:client_app) { Fabricate(:application) }
|
||||
let(:token) { Doorkeeper::AccessToken.find_or_create_for(application: client_app, resource_owner: nil, scopes: 'read write', use_refresh_token: false) }
|
||||
let(:agreement) { nil }
|
||||
|
||||
context 'when given truthy agreement' do
|
||||
let(:agreement) { 'true' }
|
||||
|
||||
it 'creates a user', :aggregate_failures do
|
||||
subject
|
||||
|
||||
expect(response).to have_http_status(200)
|
||||
expect(body_as_json[:access_token]).to_not be_blank
|
||||
|
||||
user = User.find_by(email: 'hello@world.tld')
|
||||
expect(user).to_not be_nil
|
||||
expect(user.created_by_application_id).to eq app.id
|
||||
expect(user.created_by_application_id).to eq client_app.id
|
||||
end
|
||||
end
|
||||
|
||||
context 'when given no agreement' do
|
||||
it 'returns http unprocessable entity' do
|
||||
subject
|
||||
|
||||
expect(response).to have_http_status(422)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'POST #follow' do
|
||||
describe 'POST /api/v1/accounts/:id/follow' do
|
||||
let(:scopes) { 'write:follows' }
|
||||
let(:my_actor_type) { 'Person' }
|
||||
let(:lock_follow_from_bot) { false }
|
||||
let(:other_account) { Fabricate(:account, username: 'bob', locked: locked) }
|
||||
|
||||
context 'when posting to an other account' do
|
||||
subject do
|
||||
post "/api/v1/accounts/#{other_account.id}/follow", headers: headers
|
||||
end
|
||||
|
||||
before do
|
||||
other_account.user.settings['lock_follow_from_bot'] = lock_follow_from_bot
|
||||
other_account.user.save!
|
||||
user.account.update!(actor_type: my_actor_type)
|
||||
|
||||
post :follow, params: { id: other_account.id }
|
||||
end
|
||||
|
||||
context 'with unlocked account' do
|
||||
let(:locked) { false }
|
||||
|
||||
it 'creates a following relation between user and target user', :aggregate_failures do
|
||||
subject
|
||||
|
||||
expect(response).to have_http_status(200)
|
||||
|
||||
json = body_as_json
|
||||
|
@ -78,6 +121,8 @@ RSpec.describe Api::V1::AccountsController do
|
|||
let(:locked) { true }
|
||||
|
||||
it 'creates a follow request relation between user and target user', :aggregate_failures do
|
||||
subject
|
||||
|
||||
expect(response).to have_http_status(200)
|
||||
|
||||
json = body_as_json
|
||||
|
@ -97,10 +142,14 @@ RSpec.describe Api::V1::AccountsController do
|
|||
let(:my_actor_type) { 'Service' }
|
||||
|
||||
it 'returns http success' do
|
||||
subject
|
||||
|
||||
expect(response).to have_http_status(200)
|
||||
end
|
||||
|
||||
it 'returns JSON with following=false and requested=true' do
|
||||
subject
|
||||
|
||||
json = body_as_json
|
||||
|
||||
expect(json[:following]).to be false
|
||||
|
@ -108,6 +157,8 @@ RSpec.describe Api::V1::AccountsController do
|
|||
end
|
||||
|
||||
it 'creates a follow request relation between user and target user' do
|
||||
subject
|
||||
|
||||
expect(user.account.requested?(other_account)).to be true
|
||||
end
|
||||
|
||||
|
@ -123,48 +174,53 @@ RSpec.describe Api::V1::AccountsController do
|
|||
end
|
||||
|
||||
it 'changes reblogs option' do
|
||||
post :follow, params: { id: other_account.id, reblogs: true }
|
||||
post "/api/v1/accounts/#{other_account.id}/follow", headers: headers, params: { reblogs: true }
|
||||
|
||||
json = body_as_json
|
||||
|
||||
expect(json[:following]).to be true
|
||||
expect(json[:showing_reblogs]).to be true
|
||||
expect(json[:notifying]).to be false
|
||||
expect(body_as_json).to include({
|
||||
following: true,
|
||||
showing_reblogs: true,
|
||||
notifying: false,
|
||||
})
|
||||
end
|
||||
|
||||
it 'changes notify option' do
|
||||
post :follow, params: { id: other_account.id, notify: true }
|
||||
post "/api/v1/accounts/#{other_account.id}/follow", headers: headers, params: { notify: true }
|
||||
|
||||
json = body_as_json
|
||||
|
||||
expect(json[:following]).to be true
|
||||
expect(json[:showing_reblogs]).to be false
|
||||
expect(json[:notifying]).to be true
|
||||
expect(body_as_json).to include({
|
||||
following: true,
|
||||
showing_reblogs: false,
|
||||
notifying: true,
|
||||
})
|
||||
end
|
||||
|
||||
it 'changes languages option' do
|
||||
post :follow, params: { id: other_account.id, languages: %w(en es) }
|
||||
post "/api/v1/accounts/#{other_account.id}/follow", headers: headers, params: { languages: %w(en es) }
|
||||
|
||||
json = body_as_json
|
||||
|
||||
expect(json[:following]).to be true
|
||||
expect(json[:showing_reblogs]).to be false
|
||||
expect(json[:notifying]).to be false
|
||||
expect(json[:languages]).to match_array %w(en es)
|
||||
expect(body_as_json).to include({
|
||||
following: true,
|
||||
showing_reblogs: false,
|
||||
notifying: false,
|
||||
languages: match_array(%w(en es)),
|
||||
})
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'POST #unfollow' do
|
||||
describe 'POST /api/v1/accounts/:id/unfollow' do
|
||||
subject do
|
||||
post "/api/v1/accounts/#{other_account.id}/unfollow", headers: headers
|
||||
end
|
||||
|
||||
let(:scopes) { 'write:follows' }
|
||||
let(:other_account) { Fabricate(:account, username: 'bob') }
|
||||
|
||||
before do
|
||||
user.account.follow!(other_account)
|
||||
post :unfollow, params: { id: other_account.id }
|
||||
end
|
||||
|
||||
it 'removes the following relation between user and target user', :aggregate_failures do
|
||||
subject
|
||||
|
||||
expect(response).to have_http_status(200)
|
||||
expect(user.account.following?(other_account)).to be false
|
||||
end
|
||||
|
@ -172,16 +228,21 @@ RSpec.describe Api::V1::AccountsController do
|
|||
it_behaves_like 'forbidden for wrong scope', 'read:accounts'
|
||||
end
|
||||
|
||||
describe 'POST #remove_from_followers' do
|
||||
describe 'POST /api/v1/accounts/:id/remove_from_followers' do
|
||||
subject do
|
||||
post "/api/v1/accounts/#{other_account.id}/remove_from_followers", headers: headers
|
||||
end
|
||||
|
||||
let(:scopes) { 'write:follows' }
|
||||
let(:other_account) { Fabricate(:account, username: 'bob') }
|
||||
|
||||
before do
|
||||
other_account.follow!(user.account)
|
||||
post :remove_from_followers, params: { id: other_account.id }
|
||||
end
|
||||
|
||||
it 'removes the followed relation between user and target user', :aggregate_failures do
|
||||
subject
|
||||
|
||||
expect(response).to have_http_status(200)
|
||||
expect(user.account.followed_by?(other_account)).to be false
|
||||
end
|
||||
|
@ -189,16 +250,21 @@ RSpec.describe Api::V1::AccountsController do
|
|||
it_behaves_like 'forbidden for wrong scope', 'read:accounts'
|
||||
end
|
||||
|
||||
describe 'POST #block' do
|
||||
describe 'POST /api/v1/accounts/:id/block' do
|
||||
subject do
|
||||
post "/api/v1/accounts/#{other_account.id}/block", headers: headers
|
||||
end
|
||||
|
||||
let(:scopes) { 'write:blocks' }
|
||||
let(:other_account) { Fabricate(:account, username: 'bob') }
|
||||
|
||||
before do
|
||||
user.account.follow!(other_account)
|
||||
post :block, params: { id: other_account.id }
|
||||
end
|
||||
|
||||
it 'creates a blocking relation', :aggregate_failures do
|
||||
subject
|
||||
|
||||
expect(response).to have_http_status(200)
|
||||
expect(user.account.following?(other_account)).to be false
|
||||
expect(user.account.blocking?(other_account)).to be true
|
||||
|
@ -207,16 +273,21 @@ RSpec.describe Api::V1::AccountsController do
|
|||
it_behaves_like 'forbidden for wrong scope', 'read:accounts'
|
||||
end
|
||||
|
||||
describe 'POST #unblock' do
|
||||
describe 'POST /api/v1/accounts/:id/unblock' do
|
||||
subject do
|
||||
post "/api/v1/accounts/#{other_account.id}/unblock", headers: headers
|
||||
end
|
||||
|
||||
let(:scopes) { 'write:blocks' }
|
||||
let(:other_account) { Fabricate(:account, username: 'bob') }
|
||||
|
||||
before do
|
||||
user.account.block!(other_account)
|
||||
post :unblock, params: { id: other_account.id }
|
||||
end
|
||||
|
||||
it 'removes the blocking relation between user and target user', :aggregate_failures do
|
||||
subject
|
||||
|
||||
expect(response).to have_http_status(200)
|
||||
expect(user.account.blocking?(other_account)).to be false
|
||||
end
|
||||
|
@ -224,16 +295,21 @@ RSpec.describe Api::V1::AccountsController do
|
|||
it_behaves_like 'forbidden for wrong scope', 'read:accounts'
|
||||
end
|
||||
|
||||
describe 'POST #mute' do
|
||||
describe 'POST /api/v1/accounts/:id/mute' do
|
||||
subject do
|
||||
post "/api/v1/accounts/#{other_account.id}/mute", headers: headers
|
||||
end
|
||||
|
||||
let(:scopes) { 'write:mutes' }
|
||||
let(:other_account) { Fabricate(:account, username: 'bob') }
|
||||
|
||||
before do
|
||||
user.account.follow!(other_account)
|
||||
post :mute, params: { id: other_account.id }
|
||||
end
|
||||
|
||||
it 'mutes notifications', :aggregate_failures do
|
||||
subject
|
||||
|
||||
expect(response).to have_http_status(200)
|
||||
expect(user.account.following?(other_account)).to be true
|
||||
expect(user.account.muting?(other_account)).to be true
|
||||
|
@ -243,16 +319,21 @@ RSpec.describe Api::V1::AccountsController do
|
|||
it_behaves_like 'forbidden for wrong scope', 'read:accounts'
|
||||
end
|
||||
|
||||
describe 'POST #mute with notifications set to false' do
|
||||
describe 'POST /api/v1/accounts/:id/mute with notifications set to false' do
|
||||
subject do
|
||||
post "/api/v1/accounts/#{other_account.id}/mute", headers: headers, params: { notifications: false }
|
||||
end
|
||||
|
||||
let(:scopes) { 'write:mutes' }
|
||||
let(:other_account) { Fabricate(:account, username: 'bob') }
|
||||
|
||||
before do
|
||||
user.account.follow!(other_account)
|
||||
post :mute, params: { id: other_account.id, notifications: false }
|
||||
end
|
||||
|
||||
it 'does not mute notifications', :aggregate_failures do
|
||||
subject
|
||||
|
||||
expect(response).to have_http_status(200)
|
||||
expect(user.account.following?(other_account)).to be true
|
||||
expect(user.account.muting?(other_account)).to be true
|
||||
|
@ -262,16 +343,21 @@ RSpec.describe Api::V1::AccountsController do
|
|||
it_behaves_like 'forbidden for wrong scope', 'read:accounts'
|
||||
end
|
||||
|
||||
describe 'POST #mute with nonzero duration set' do
|
||||
describe 'POST /api/v1/accounts/:id/mute with nonzero duration set' do
|
||||
subject do
|
||||
post "/api/v1/accounts/#{other_account.id}/mute", headers: headers, params: { duration: 300 }
|
||||
end
|
||||
|
||||
let(:scopes) { 'write:mutes' }
|
||||
let(:other_account) { Fabricate(:account, username: 'bob') }
|
||||
|
||||
before do
|
||||
user.account.follow!(other_account)
|
||||
post :mute, params: { id: other_account.id, duration: 300 }
|
||||
end
|
||||
|
||||
it 'mutes notifications', :aggregate_failures do
|
||||
subject
|
||||
|
||||
expect(response).to have_http_status(200)
|
||||
expect(user.account.following?(other_account)).to be true
|
||||
expect(user.account.muting?(other_account)).to be true
|
||||
|
@ -281,16 +367,21 @@ RSpec.describe Api::V1::AccountsController do
|
|||
it_behaves_like 'forbidden for wrong scope', 'read:accounts'
|
||||
end
|
||||
|
||||
describe 'POST #unmute' do
|
||||
describe 'POST /api/v1/accounts/:id/unmute' do
|
||||
subject do
|
||||
post "/api/v1/accounts/#{other_account.id}/unmute", headers: headers
|
||||
end
|
||||
|
||||
let(:scopes) { 'write:mutes' }
|
||||
let(:other_account) { Fabricate(:account, username: 'bob') }
|
||||
|
||||
before do
|
||||
user.account.mute!(other_account)
|
||||
post :unmute, params: { id: other_account.id }
|
||||
end
|
||||
|
||||
it 'removes the muting relation between user and target user', :aggregate_failures do
|
||||
subject
|
||||
|
||||
expect(response).to have_http_status(200)
|
||||
expect(user.account.muting?(other_account)).to be false
|
||||
end
|
|
@ -8,18 +8,12 @@ RSpec.describe 'Account actions' do
|
|||
let(:scopes) { 'admin:write admin:write:accounts' }
|
||||
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) }
|
||||
let(:headers) { { 'Authorization' => "Bearer #{token.token}" } }
|
||||
let(:mailer) { instance_double(ActionMailer::MessageDelivery, deliver_later!: nil) }
|
||||
|
||||
before do
|
||||
allow(UserMailer).to receive(:warning).with(target_account.user, anything).and_return(mailer)
|
||||
end
|
||||
|
||||
shared_examples 'a successful notification delivery' do
|
||||
it 'notifies the user about the action taken' do
|
||||
subject
|
||||
|
||||
expect(UserMailer).to have_received(:warning).with(target_account.user, anything).once
|
||||
expect(mailer).to have_received(:deliver_later!).once
|
||||
expect { subject }
|
||||
.to have_enqueued_job(ActionMailer::MailDeliveryJob)
|
||||
.with('UserMailer', 'warning', 'deliver_now!', args: [User, AccountWarning])
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -2,24 +2,26 @@
|
|||
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe Api::V1::StatusesController 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, application: app, scopes: scopes) }
|
||||
|
||||
describe '/api/v1/statuses' do
|
||||
context 'with an oauth token' do
|
||||
before do
|
||||
allow(controller).to receive(:doorkeeper_token) { token }
|
||||
end
|
||||
let(:user) { Fabricate(:user) }
|
||||
let(:client_app) { Fabricate(:application, name: 'Test app', website: 'http://testapp.com') }
|
||||
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, application: client_app, scopes: scopes) }
|
||||
let(:headers) { { 'Authorization' => "Bearer #{token.token}" } }
|
||||
|
||||
describe 'GET /api/v1/statuses/:id' do
|
||||
subject do
|
||||
get "/api/v1/statuses/#{status.id}", headers: headers
|
||||
end
|
||||
|
||||
describe 'GET #show' do
|
||||
let(:scopes) { 'read:statuses' }
|
||||
let(:status) { Fabricate(:status, account: user.account) }
|
||||
|
||||
it_behaves_like 'forbidden for wrong scope', 'write write:statuses'
|
||||
|
||||
it 'returns http success' do
|
||||
get :show, params: { id: status.id }
|
||||
subject
|
||||
|
||||
expect(response).to have_http_status(200)
|
||||
end
|
||||
|
||||
|
@ -31,11 +33,10 @@ RSpec.describe Api::V1::StatusesController do
|
|||
end
|
||||
|
||||
it 'returns filter information', :aggregate_failures do
|
||||
get :show, params: { id: status.id }
|
||||
json = body_as_json
|
||||
subject
|
||||
|
||||
expect(response).to have_http_status(200)
|
||||
expect(json[:filtered][0]).to include({
|
||||
expect(body_as_json[:filtered][0]).to include({
|
||||
filter: a_hash_including({
|
||||
id: user.account.custom_filters.first.id.to_s,
|
||||
title: 'filter1',
|
||||
|
@ -55,11 +56,10 @@ RSpec.describe Api::V1::StatusesController do
|
|||
end
|
||||
|
||||
it 'returns filter information', :aggregate_failures do
|
||||
get :show, params: { id: status.id }
|
||||
json = body_as_json
|
||||
subject
|
||||
|
||||
expect(response).to have_http_status(200)
|
||||
expect(json[:filtered][0]).to include({
|
||||
expect(body_as_json[:filtered][0]).to include({
|
||||
filter: a_hash_including({
|
||||
id: user.account.custom_filters.first.id.to_s,
|
||||
title: 'filter1',
|
||||
|
@ -78,11 +78,10 @@ RSpec.describe Api::V1::StatusesController do
|
|||
end
|
||||
|
||||
it 'returns filter information', :aggregate_failures do
|
||||
get :show, params: { id: status.id }
|
||||
json = body_as_json
|
||||
subject
|
||||
|
||||
expect(response).to have_http_status(200)
|
||||
expect(json[:reblog][:filtered][0]).to include({
|
||||
expect(body_as_json[:reblog][:filtered][0]).to include({
|
||||
filter: a_hash_including({
|
||||
id: user.account.custom_filters.first.id.to_s,
|
||||
title: 'filter1',
|
||||
|
@ -94,7 +93,7 @@ RSpec.describe Api::V1::StatusesController do
|
|||
end
|
||||
end
|
||||
|
||||
describe 'GET #context' do
|
||||
describe 'GET /api/v1/statuses/:id/context' do
|
||||
let(:scopes) { 'read:statuses' }
|
||||
let(:status) { Fabricate(:status, account: user.account) }
|
||||
let!(:thread) { Fabricate(:status, account: user.account, thread: status) }
|
||||
|
@ -142,7 +141,8 @@ RSpec.describe Api::V1::StatusesController do
|
|||
end
|
||||
|
||||
it 'returns http success' do
|
||||
get :context, params: { id: status.id }
|
||||
get "/api/v1/statuses/#{status.id}/context", headers: headers
|
||||
|
||||
expect(response).to have_http_status(200)
|
||||
end
|
||||
|
||||
|
@ -190,15 +190,20 @@ RSpec.describe Api::V1::StatusesController do
|
|||
end
|
||||
end
|
||||
|
||||
describe 'POST #create' do
|
||||
describe 'POST /api/v1/statuses' do
|
||||
subject do
|
||||
post '/api/v1/statuses', headers: headers, params: params
|
||||
end
|
||||
|
||||
let(:scopes) { 'write:statuses' }
|
||||
let(:params) { { status: 'Hello world' } }
|
||||
|
||||
it_behaves_like 'forbidden for wrong scope', 'read read:statuses'
|
||||
|
||||
context 'with a basic status body' do
|
||||
before do
|
||||
post :create, params: { status: 'Hello world' }
|
||||
end
|
||||
|
||||
it 'returns rate limit headers', :aggregate_failures do
|
||||
subject
|
||||
|
||||
expect(response).to have_http_status(200)
|
||||
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
|
||||
|
@ -209,22 +214,22 @@ RSpec.describe Api::V1::StatusesController do
|
|||
let!(:alice) { Fabricate(:account, username: 'alice') }
|
||||
let!(:bob) { Fabricate(:account, username: 'bob') }
|
||||
|
||||
before do
|
||||
post :create, params: { status: '@alice hm, @bob is really annoying lately', allowed_mentions: [alice.id] }
|
||||
end
|
||||
let(:params) { { status: '@alice hm, @bob is really annoying lately', allowed_mentions: [alice.id] } }
|
||||
|
||||
it 'returns serialized extra accounts in body', :aggregate_failures do
|
||||
subject
|
||||
|
||||
expect(response).to have_http_status(422)
|
||||
expect(body_as_json[:unexpected_accounts].map { |a| a.slice(:id, :acct) }).to eq [{ id: bob.id.to_s, acct: bob.acct }]
|
||||
end
|
||||
end
|
||||
|
||||
context 'with missing parameters' do
|
||||
before do
|
||||
post :create, params: {}
|
||||
end
|
||||
let(:params) { {} }
|
||||
|
||||
it 'returns rate limit headers', :aggregate_failures do
|
||||
subject
|
||||
|
||||
expect(response).to have_http_status(422)
|
||||
expect(response.headers['X-RateLimit-Limit']).to eq RateLimiter::FAMILIES[:statuses][:limit].to_s
|
||||
end
|
||||
|
@ -234,10 +239,11 @@ RSpec.describe Api::V1::StatusesController do
|
|||
before do
|
||||
rate_limiter = RateLimiter.new(user.account, family: :statuses)
|
||||
300.times { rate_limiter.record! }
|
||||
post :create, params: { status: 'Hello world' }
|
||||
end
|
||||
|
||||
it 'returns rate limit headers', :aggregate_failures do
|
||||
subject
|
||||
|
||||
expect(response).to have_http_status(429)
|
||||
expect(response.headers['X-RateLimit-Limit']).to eq RateLimiter::FAMILIES[:statuses][:limit].to_s
|
||||
expect(response.headers['X-RateLimit-Remaining']).to eq '0'
|
||||
|
@ -245,29 +251,37 @@ RSpec.describe Api::V1::StatusesController do
|
|||
end
|
||||
end
|
||||
|
||||
describe 'DELETE #destroy' do
|
||||
describe 'DELETE /api/v1/statuses/:id' do
|
||||
subject do
|
||||
delete "/api/v1/statuses/#{status.id}", headers: headers
|
||||
end
|
||||
|
||||
let(:scopes) { 'write:statuses' }
|
||||
let(:status) { Fabricate(:status, account: user.account) }
|
||||
|
||||
before do
|
||||
post :destroy, params: { id: status.id }
|
||||
end
|
||||
it_behaves_like 'forbidden for wrong scope', 'read read:statuses'
|
||||
|
||||
it 'removes the status', :aggregate_failures do
|
||||
subject
|
||||
|
||||
expect(response).to have_http_status(200)
|
||||
expect(Status.find_by(id: status.id)).to be_nil
|
||||
end
|
||||
end
|
||||
|
||||
describe 'PUT #update' do
|
||||
describe 'PUT /api/v1/statuses/:id' do
|
||||
subject do
|
||||
put "/api/v1/statuses/#{status.id}", headers: headers, params: { status: 'I am updated' }
|
||||
end
|
||||
|
||||
let(:scopes) { 'write:statuses' }
|
||||
let(:status) { Fabricate(:status, account: user.account) }
|
||||
|
||||
before do
|
||||
put :update, params: { id: status.id, status: 'I am updated' }
|
||||
end
|
||||
it_behaves_like 'forbidden for wrong scope', 'read read:statuses'
|
||||
|
||||
it 'updates the status', :aggregate_failures do
|
||||
subject
|
||||
|
||||
expect(response).to have_http_status(200)
|
||||
expect(status.reload.text).to eq 'I am updated'
|
||||
end
|
||||
|
@ -275,49 +289,49 @@ RSpec.describe Api::V1::StatusesController do
|
|||
end
|
||||
|
||||
context 'without an oauth token' do
|
||||
before do
|
||||
allow(controller).to receive(:doorkeeper_token).and_return(nil)
|
||||
end
|
||||
|
||||
context 'with a private status' do
|
||||
let(:status) { Fabricate(:status, account: user.account, visibility: :private) }
|
||||
let(:status) { Fabricate(:status, visibility: :private) }
|
||||
|
||||
describe 'GET #show' do
|
||||
describe 'GET /api/v1/statuses/:id' do
|
||||
it 'returns http unauthorized' do
|
||||
get :show, params: { id: status.id }
|
||||
get "/api/v1/statuses/#{status.id}"
|
||||
|
||||
expect(response).to have_http_status(404)
|
||||
end
|
||||
end
|
||||
|
||||
describe 'GET #context' do
|
||||
describe 'GET /api/v1/statuses/:id/context' do
|
||||
before do
|
||||
Fabricate(:status, account: user.account, thread: status)
|
||||
Fabricate(:status, thread: status)
|
||||
end
|
||||
|
||||
it 'returns http unauthorized' do
|
||||
get :context, params: { id: status.id }
|
||||
get "/api/v1/statuses/#{status.id}/context"
|
||||
|
||||
expect(response).to have_http_status(404)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'with a public status' do
|
||||
let(:status) { Fabricate(:status, account: user.account, visibility: :public) }
|
||||
let(:status) { Fabricate(:status, visibility: :public) }
|
||||
|
||||
describe 'GET #show' do
|
||||
describe 'GET /api/v1/statuses/:id' do
|
||||
it 'returns http success' do
|
||||
get :show, params: { id: status.id }
|
||||
get "/api/v1/statuses/#{status.id}"
|
||||
|
||||
expect(response).to have_http_status(200)
|
||||
end
|
||||
end
|
||||
|
||||
describe 'GET #context' do
|
||||
describe 'GET /api/v1/statuses/:id/context' do
|
||||
before do
|
||||
Fabricate(:status, account: user.account, thread: status)
|
||||
Fabricate(:status, thread: status)
|
||||
end
|
||||
|
||||
it 'returns http success' do
|
||||
get :context, params: { id: status.id }
|
||||
get "/api/v1/statuses/#{status.id}/context"
|
||||
|
||||
expect(response).to have_http_status(200)
|
||||
end
|
||||
end
|
|
@ -60,7 +60,7 @@ RSpec.configure do |config|
|
|||
end
|
||||
end
|
||||
|
||||
config.around :each, type: :search do |example|
|
||||
config.around :each, :search do |example|
|
||||
search_data_manager.populate_indexes
|
||||
example.run
|
||||
search_data_manager.remove_indexes
|
||||
|
@ -73,6 +73,6 @@ RSpec.configure do |config|
|
|||
end
|
||||
|
||||
def search_examples_present?
|
||||
RUN_SEARCH_SPECS
|
||||
RSpec.world.filtered_examples.values.flatten.any? { |example| example.metadata[:search] == true }
|
||||
end
|
||||
end
|
||||
|
|
52
spec/workers/account_refresh_worker_spec.rb
Normal file
52
spec/workers/account_refresh_worker_spec.rb
Normal file
|
@ -0,0 +1,52 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'rails_helper'
|
||||
|
||||
describe AccountRefreshWorker do
|
||||
let(:worker) { described_class.new }
|
||||
let(:service) { instance_double(ResolveAccountService, call: true) }
|
||||
|
||||
describe '#perform' do
|
||||
before do
|
||||
allow(ResolveAccountService).to receive(:new).and_return(service)
|
||||
end
|
||||
|
||||
context 'when account does not exist' do
|
||||
it 'returns immediately without processing' do
|
||||
worker.perform(123_123_123)
|
||||
|
||||
expect(service).to_not have_received(:call)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when account exists' do
|
||||
context 'when account does not need refreshing' do
|
||||
let(:account) { Fabricate(:account, last_webfingered_at: recent_webfinger_at) }
|
||||
|
||||
it 'returns immediately without processing' do
|
||||
worker.perform(account.id)
|
||||
|
||||
expect(service).to_not have_received(:call)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when account needs refreshing' do
|
||||
let(:account) { Fabricate(:account, last_webfingered_at: outdated_webfinger_at) }
|
||||
|
||||
it 'schedules an account update' do
|
||||
worker.perform(account.id)
|
||||
|
||||
expect(service).to have_received(:call)
|
||||
end
|
||||
end
|
||||
|
||||
def recent_webfinger_at
|
||||
(Account::BACKGROUND_REFRESH_INTERVAL - 3.days).ago
|
||||
end
|
||||
|
||||
def outdated_webfinger_at
|
||||
(Account::BACKGROUND_REFRESH_INTERVAL + 3.days).ago
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
18
spec/workers/activitypub/post_upgrade_worker_spec.rb
Normal file
18
spec/workers/activitypub/post_upgrade_worker_spec.rb
Normal file
|
@ -0,0 +1,18 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'rails_helper'
|
||||
|
||||
describe ActivityPub::PostUpgradeWorker do
|
||||
let(:worker) { described_class.new }
|
||||
|
||||
describe '#perform' do
|
||||
let(:domain) { 'host.example' }
|
||||
|
||||
it 'updates relevant values' do
|
||||
account = Fabricate(:account, domain: domain, last_webfingered_at: 1.day.ago, protocol: :ostatus)
|
||||
worker.perform(domain)
|
||||
|
||||
expect(account.reload.last_webfingered_at).to be_nil
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,29 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'rails_helper'
|
||||
|
||||
describe ActivityPub::SynchronizeFeaturedTagsCollectionWorker do
|
||||
let(:worker) { described_class.new }
|
||||
let(:service) { instance_double(ActivityPub::FetchFeaturedTagsCollectionService, call: true) }
|
||||
|
||||
describe '#perform' do
|
||||
before do
|
||||
allow(ActivityPub::FetchFeaturedTagsCollectionService).to receive(:new).and_return(service)
|
||||
end
|
||||
|
||||
let(:account) { Fabricate(:account) }
|
||||
let(:url) { 'https://host.example' }
|
||||
|
||||
it 'sends the account and url to the service' do
|
||||
worker.perform(account.id, url)
|
||||
|
||||
expect(service).to have_received(:call).with(account, url)
|
||||
end
|
||||
|
||||
it 'returns true for non-existent record' do
|
||||
result = worker.perform(123_123_123, url)
|
||||
|
||||
expect(result).to be(true)
|
||||
end
|
||||
end
|
||||
end
|
28
spec/workers/admin/suspension_worker_spec.rb
Normal file
28
spec/workers/admin/suspension_worker_spec.rb
Normal file
|
@ -0,0 +1,28 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'rails_helper'
|
||||
|
||||
describe Admin::SuspensionWorker do
|
||||
let(:worker) { described_class.new }
|
||||
let(:service) { instance_double(SuspendAccountService, call: true) }
|
||||
|
||||
describe '#perform' do
|
||||
before do
|
||||
allow(SuspendAccountService).to receive(:new).and_return(service)
|
||||
end
|
||||
|
||||
let(:account) { Fabricate(:account) }
|
||||
|
||||
it 'sends the account to the service' do
|
||||
worker.perform(account.id)
|
||||
|
||||
expect(service).to have_received(:call).with(account)
|
||||
end
|
||||
|
||||
it 'returns true for non-existent record' do
|
||||
result = worker.perform(123_123_123)
|
||||
|
||||
expect(result).to be(true)
|
||||
end
|
||||
end
|
||||
end
|
29
spec/workers/after_account_domain_block_worker_spec.rb
Normal file
29
spec/workers/after_account_domain_block_worker_spec.rb
Normal file
|
@ -0,0 +1,29 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'rails_helper'
|
||||
|
||||
describe AfterAccountDomainBlockWorker do
|
||||
let(:worker) { described_class.new }
|
||||
let(:service) { instance_double(AfterBlockDomainFromAccountService, call: true) }
|
||||
|
||||
describe '#perform' do
|
||||
before do
|
||||
allow(AfterBlockDomainFromAccountService).to receive(:new).and_return(service)
|
||||
end
|
||||
|
||||
let(:account) { Fabricate(:account) }
|
||||
let(:domain) { 'host.example' }
|
||||
|
||||
it 'sends the account and domain to the service' do
|
||||
worker.perform(account.id, domain)
|
||||
|
||||
expect(service).to have_received(:call).with(account, domain)
|
||||
end
|
||||
|
||||
it 'returns true for non-existent record' do
|
||||
result = worker.perform(123_123_123, domain)
|
||||
|
||||
expect(result).to be(true)
|
||||
end
|
||||
end
|
||||
end
|
36
spec/workers/backup_worker_spec.rb
Normal file
36
spec/workers/backup_worker_spec.rb
Normal file
|
@ -0,0 +1,36 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'rails_helper'
|
||||
|
||||
describe BackupWorker do
|
||||
let(:worker) { described_class.new }
|
||||
let(:service) { instance_double(BackupService, call: true) }
|
||||
|
||||
describe '#perform' do
|
||||
before do
|
||||
allow(BackupService).to receive(:new).and_return(service)
|
||||
end
|
||||
|
||||
let(:backup) { Fabricate(:backup) }
|
||||
let!(:other_backup) { Fabricate(:backup, user: backup.user) }
|
||||
|
||||
it 'sends the backup to the service and removes other backups' do
|
||||
expect do
|
||||
worker.perform(backup.id)
|
||||
end.to change(UserMailer.deliveries, :size).by(1)
|
||||
|
||||
expect(service).to have_received(:call).with(backup)
|
||||
expect { other_backup.reload }.to raise_error(ActiveRecord::RecordNotFound)
|
||||
end
|
||||
|
||||
context 'when sidekiq retries are exhausted' do
|
||||
it 'destroys the backup' do
|
||||
described_class.within_sidekiq_retries_exhausted_block({ 'args' => [backup.id] }) do
|
||||
worker.perform(backup.id)
|
||||
end
|
||||
|
||||
expect { backup.reload }.to raise_error(ActiveRecord::RecordNotFound)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
42
spec/workers/delete_mute_worker_spec.rb
Normal file
42
spec/workers/delete_mute_worker_spec.rb
Normal file
|
@ -0,0 +1,42 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'rails_helper'
|
||||
|
||||
describe DeleteMuteWorker do
|
||||
let(:worker) { described_class.new }
|
||||
let(:service) { instance_double(UnmuteService, call: true) }
|
||||
|
||||
describe '#perform' do
|
||||
before do
|
||||
allow(UnmuteService).to receive(:new).and_return(service)
|
||||
end
|
||||
|
||||
context 'with an expired mute' do
|
||||
let(:mute) { Fabricate(:mute, expires_at: 1.day.ago) }
|
||||
|
||||
it 'sends the mute to the service' do
|
||||
worker.perform(mute.id)
|
||||
|
||||
expect(service).to have_received(:call).with(mute.account, mute.target_account)
|
||||
end
|
||||
end
|
||||
|
||||
context 'with an unexpired mute' do
|
||||
let(:mute) { Fabricate(:mute, expires_at: 1.day.from_now) }
|
||||
|
||||
it 'does not send the mute to the service' do
|
||||
worker.perform(mute.id)
|
||||
|
||||
expect(service).to_not have_received(:call)
|
||||
end
|
||||
end
|
||||
|
||||
context 'with a non-existent mute' do
|
||||
it 'does not send the mute to the service' do
|
||||
worker.perform(123_123_123)
|
||||
|
||||
expect(service).to_not have_received(:call)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -12,6 +12,7 @@ describe FeedInsertWorker do
|
|||
describe 'perform' do
|
||||
let(:follower) { Fabricate(:account) }
|
||||
let(:status) { Fabricate(:status) }
|
||||
let(:list) { Fabricate(:list) }
|
||||
|
||||
context 'when there are no records' do
|
||||
it 'skips push with missing status' do
|
||||
|
@ -46,11 +47,29 @@ describe FeedInsertWorker do
|
|||
it 'pushes the status onto the home timeline without filter' do
|
||||
instance = instance_double(FeedManager, push_to_home: nil, filter?: false)
|
||||
allow(FeedManager).to receive(:instance).and_return(instance)
|
||||
result = subject.perform(status.id, follower.id)
|
||||
result = subject.perform(status.id, follower.id, :home)
|
||||
|
||||
expect(result).to be_nil
|
||||
expect(instance).to have_received(:push_to_home).with(follower, status, update: nil)
|
||||
end
|
||||
|
||||
it 'pushes the status onto the tags timeline without filter' do
|
||||
instance = instance_double(FeedManager, push_to_home: nil, filter?: false)
|
||||
allow(FeedManager).to receive(:instance).and_return(instance)
|
||||
result = subject.perform(status.id, follower.id, :tags)
|
||||
|
||||
expect(result).to be_nil
|
||||
expect(instance).to have_received(:push_to_home).with(follower, status, update: nil)
|
||||
end
|
||||
|
||||
it 'pushes the status onto the list timeline without filter' do
|
||||
instance = instance_double(FeedManager, push_to_list: nil, filter?: false)
|
||||
allow(FeedManager).to receive(:instance).and_return(instance)
|
||||
result = subject.perform(status.id, list.id, :list)
|
||||
|
||||
expect(result).to be_nil
|
||||
expect(instance).to have_received(:push_to_list).with(list, status, update: nil)
|
||||
end
|
||||
end
|
||||
|
||||
context 'with notification' do
|
||||
|
|
23
spec/workers/import_worker_spec.rb
Normal file
23
spec/workers/import_worker_spec.rb
Normal file
|
@ -0,0 +1,23 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'rails_helper'
|
||||
|
||||
describe ImportWorker do
|
||||
let(:worker) { described_class.new }
|
||||
let(:service) { instance_double(ImportService, call: true) }
|
||||
|
||||
describe '#perform' do
|
||||
before do
|
||||
allow(ImportService).to receive(:new).and_return(service)
|
||||
end
|
||||
|
||||
let(:import) { Fabricate(:import) }
|
||||
|
||||
it 'sends the import to the service' do
|
||||
worker.perform(import.id)
|
||||
|
||||
expect(service).to have_received(:call).with(import)
|
||||
expect { import.reload }.to raise_error(ActiveRecord::RecordNotFound)
|
||||
end
|
||||
end
|
||||
end
|
|
@ -2,12 +2,38 @@
|
|||
|
||||
require 'rails_helper'
|
||||
|
||||
describe PostProcessMediaWorker do
|
||||
describe PostProcessMediaWorker, :paperclip_processing do
|
||||
let(:worker) { described_class.new }
|
||||
|
||||
describe 'perform' do
|
||||
it 'runs without error for missing record' do
|
||||
expect { worker.perform(nil) }.to_not raise_error
|
||||
describe '#perform' do
|
||||
let(:media_attachment) { Fabricate(:media_attachment) }
|
||||
|
||||
it 'reprocesses and updates the media attachment' do
|
||||
worker.perform(media_attachment.id)
|
||||
|
||||
expect(media_attachment.processing).to eq('complete')
|
||||
end
|
||||
|
||||
it 'returns true for non-existent record' do
|
||||
result = worker.perform(123_123_123)
|
||||
|
||||
expect(result).to be(true)
|
||||
end
|
||||
|
||||
context 'when sidekiq retries are exhausted' do
|
||||
it 'sets state to failed' do
|
||||
described_class.within_sidekiq_retries_exhausted_block({ 'args' => [media_attachment.id] }) do
|
||||
worker.perform(media_attachment.id)
|
||||
end
|
||||
|
||||
expect(media_attachment.reload.processing).to eq('failed')
|
||||
end
|
||||
|
||||
it 'returns true for non-existent record' do
|
||||
described_class.within_sidekiq_retries_exhausted_block({ 'args' => [123_123_123] }) do
|
||||
expect(worker.perform(123_123_123)).to be(true)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
38
spec/workers/publish_announcement_reaction_worker_spec.rb
Normal file
38
spec/workers/publish_announcement_reaction_worker_spec.rb
Normal file
|
@ -0,0 +1,38 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'rails_helper'
|
||||
|
||||
describe PublishAnnouncementReactionWorker do
|
||||
let(:worker) { described_class.new }
|
||||
|
||||
describe '#perform' do
|
||||
before { Fabricate(:account, user: Fabricate(:user, current_sign_in_at: 1.hour.ago)) }
|
||||
|
||||
let(:announcement) { Fabricate(:announcement) }
|
||||
let(:name) { 'name value' }
|
||||
|
||||
it 'sends the announcement and name to the service when subscribed' do
|
||||
allow(redis).to receive(:exists?).and_return(true)
|
||||
allow(redis).to receive(:publish)
|
||||
|
||||
worker.perform(announcement.id, name)
|
||||
|
||||
expect(redis).to have_received(:publish)
|
||||
end
|
||||
|
||||
it 'does not send the announcement and name to the service when not subscribed' do
|
||||
allow(redis).to receive(:exists?).and_return(false)
|
||||
allow(redis).to receive(:publish)
|
||||
|
||||
worker.perform(announcement.id, name)
|
||||
|
||||
expect(redis).to_not have_received(:publish)
|
||||
end
|
||||
|
||||
it 'returns true for non-existent record' do
|
||||
result = worker.perform(123_123_123, name)
|
||||
|
||||
expect(result).to be(true)
|
||||
end
|
||||
end
|
||||
end
|
|
@ -5,9 +5,48 @@ require 'rails_helper'
|
|||
describe RedownloadAvatarWorker do
|
||||
let(:worker) { described_class.new }
|
||||
|
||||
describe 'perform' do
|
||||
it 'runs without error for missing record' do
|
||||
expect { worker.perform(nil) }.to_not raise_error
|
||||
describe '#perform' do
|
||||
it 'returns nil for non-existent record' do
|
||||
result = worker.perform(123_123_123)
|
||||
|
||||
expect(result).to be_nil
|
||||
end
|
||||
|
||||
it 'returns nil for suspended account' do
|
||||
account = Fabricate(:account, suspended_at: 10.days.ago)
|
||||
|
||||
expect(worker.perform(account.id)).to be_nil
|
||||
end
|
||||
|
||||
it 'returns nil with a domain block' do
|
||||
account = Fabricate(:account, domain: 'host.example')
|
||||
Fabricate(:domain_block, domain: account.domain, reject_media: true)
|
||||
|
||||
expect(worker.perform(account.id)).to be_nil
|
||||
end
|
||||
|
||||
it 'returns nil without an avatar remote url' do
|
||||
account = Fabricate(:account, avatar_remote_url: '')
|
||||
|
||||
expect(worker.perform(account.id)).to be_nil
|
||||
end
|
||||
|
||||
it 'returns nil when avatar file name is present' do
|
||||
stub_request(:get, 'https://example.host/file').to_return request_fixture('avatar.txt')
|
||||
account = Fabricate(:account, avatar_remote_url: 'https://example.host/file', avatar_file_name: 'test.jpg')
|
||||
|
||||
expect(worker.perform(account.id)).to be_nil
|
||||
end
|
||||
|
||||
it 'reprocesses a remote avatar' do
|
||||
stub_request(:get, 'https://example.host/file').to_return request_fixture('avatar.txt')
|
||||
account = Fabricate(:account, avatar_remote_url: 'https://example.host/file')
|
||||
account.update_column(:avatar_file_name, nil) # rubocop:disable Rails/SkipsModelValidations
|
||||
|
||||
result = worker.perform(account.id)
|
||||
|
||||
expect(result).to be(true)
|
||||
expect(account.reload.avatar_file_name).to_not be_nil
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -5,9 +5,48 @@ require 'rails_helper'
|
|||
describe RedownloadHeaderWorker do
|
||||
let(:worker) { described_class.new }
|
||||
|
||||
describe 'perform' do
|
||||
it 'runs without error for missing record' do
|
||||
expect { worker.perform(nil) }.to_not raise_error
|
||||
describe '#perform' do
|
||||
it 'returns nil for non-existent record' do
|
||||
result = worker.perform(123_123_123)
|
||||
|
||||
expect(result).to be_nil
|
||||
end
|
||||
|
||||
it 'returns nil for suspended account' do
|
||||
account = Fabricate(:account, suspended_at: 10.days.ago)
|
||||
|
||||
expect(worker.perform(account.id)).to be_nil
|
||||
end
|
||||
|
||||
it 'returns nil with a domain block' do
|
||||
account = Fabricate(:account, domain: 'host.example')
|
||||
Fabricate(:domain_block, domain: account.domain, reject_media: true)
|
||||
|
||||
expect(worker.perform(account.id)).to be_nil
|
||||
end
|
||||
|
||||
it 'returns nil without an header remote url' do
|
||||
account = Fabricate(:account, header_remote_url: '')
|
||||
|
||||
expect(worker.perform(account.id)).to be_nil
|
||||
end
|
||||
|
||||
it 'returns nil when header file name is present' do
|
||||
stub_request(:get, 'https://example.host/file').to_return request_fixture('avatar.txt')
|
||||
account = Fabricate(:account, header_remote_url: 'https://example.host/file', header_file_name: 'test.jpg')
|
||||
|
||||
expect(worker.perform(account.id)).to be_nil
|
||||
end
|
||||
|
||||
it 'reprocesses a remote header' do
|
||||
stub_request(:get, 'https://example.host/file').to_return request_fixture('avatar.txt')
|
||||
account = Fabricate(:account, header_remote_url: 'https://example.host/file')
|
||||
account.update_column(:header_file_name, nil) # rubocop:disable Rails/SkipsModelValidations
|
||||
|
||||
result = worker.perform(account.id)
|
||||
|
||||
expect(result).to be(true)
|
||||
expect(account.reload.header_file_name).to_not be_nil
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
37
spec/workers/redownload_media_worker_spec.rb
Normal file
37
spec/workers/redownload_media_worker_spec.rb
Normal file
|
@ -0,0 +1,37 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'rails_helper'
|
||||
|
||||
describe RedownloadMediaWorker do
|
||||
let(:worker) { described_class.new }
|
||||
|
||||
describe '#perform' do
|
||||
it 'returns nil for non-existent record' do
|
||||
result = worker.perform(123_123_123)
|
||||
|
||||
expect(result).to be_nil
|
||||
end
|
||||
|
||||
it 'returns nil without a remote_url' do
|
||||
media_attachment = Fabricate(:media_attachment, remote_url: '')
|
||||
|
||||
result = worker.perform(media_attachment.id)
|
||||
|
||||
expect(result).to be_nil
|
||||
end
|
||||
|
||||
context 'with a valid remote url' do
|
||||
let(:url) { 'https://example.host/file.txt' }
|
||||
|
||||
before { stub_request(:get, url).to_return(status: 200) }
|
||||
|
||||
it 'processes downloads for valid record' do
|
||||
media_attachment = Fabricate(:media_attachment, remote_url: url)
|
||||
|
||||
worker.perform(media_attachment.id)
|
||||
|
||||
expect(a_request(:get, url)).to have_been_made
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
28
spec/workers/removal_worker_spec.rb
Normal file
28
spec/workers/removal_worker_spec.rb
Normal file
|
@ -0,0 +1,28 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'rails_helper'
|
||||
|
||||
describe RemovalWorker do
|
||||
let(:worker) { described_class.new }
|
||||
let(:service) { instance_double(RemoveStatusService, call: true) }
|
||||
|
||||
describe '#perform' do
|
||||
before do
|
||||
allow(RemoveStatusService).to receive(:new).and_return(service)
|
||||
end
|
||||
|
||||
let(:status) { Fabricate(:status) }
|
||||
|
||||
it 'sends the status to the service' do
|
||||
worker.perform(status.id)
|
||||
|
||||
expect(service).to have_received(:call).with(status)
|
||||
end
|
||||
|
||||
it 'returns true for non-existent record' do
|
||||
result = worker.perform(123_123_123)
|
||||
|
||||
expect(result).to be(true)
|
||||
end
|
||||
end
|
||||
end
|
60
spec/workers/scheduler/self_destruct_scheduler_spec.rb
Normal file
60
spec/workers/scheduler/self_destruct_scheduler_spec.rb
Normal file
|
@ -0,0 +1,60 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'rails_helper'
|
||||
|
||||
describe Scheduler::SelfDestructScheduler do
|
||||
let(:worker) { described_class.new }
|
||||
|
||||
describe '#perform' do
|
||||
let!(:account) { Fabricate(:account, domain: nil, suspended_at: nil) }
|
||||
|
||||
context 'when not in self destruct mode' do
|
||||
before do
|
||||
allow(SelfDestructHelper).to receive(:self_destruct?).and_return(false)
|
||||
end
|
||||
|
||||
it 'returns without processing' do
|
||||
worker.perform
|
||||
|
||||
expect(account.reload.suspended_at).to be_nil
|
||||
end
|
||||
end
|
||||
|
||||
context 'when in self-destruct mode' do
|
||||
before do
|
||||
allow(SelfDestructHelper).to receive(:self_destruct?).and_return(true)
|
||||
end
|
||||
|
||||
context 'when sidekiq is overwhelmed' do
|
||||
before do
|
||||
stats = instance_double(Sidekiq::Stats, enqueued: described_class::MAX_ENQUEUED**2)
|
||||
allow(Sidekiq::Stats).to receive(:new).and_return(stats)
|
||||
end
|
||||
|
||||
it 'returns without processing' do
|
||||
worker.perform
|
||||
|
||||
expect(account.reload.suspended_at).to be_nil
|
||||
end
|
||||
end
|
||||
|
||||
context 'when sidekiq is operational' do
|
||||
it 'suspends local non-suspended accounts' do
|
||||
worker.perform
|
||||
|
||||
expect(account.reload.suspended_at).to_not be_nil
|
||||
end
|
||||
|
||||
it 'suspends local suspended accounts marked for deletion' do
|
||||
account.update(suspended_at: 10.days.ago)
|
||||
deletion_request = Fabricate(:account_deletion_request, account: account)
|
||||
|
||||
worker.perform
|
||||
|
||||
expect(account.reload.suspended_at).to be > 1.day.ago
|
||||
expect { deletion_request.reload }.to raise_error(ActiveRecord::RecordNotFound)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -5,9 +5,21 @@ require 'rails_helper'
|
|||
describe Webhooks::DeliveryWorker do
|
||||
let(:worker) { described_class.new }
|
||||
|
||||
describe 'perform' do
|
||||
it 'runs without error' do
|
||||
expect { worker.perform(nil, nil) }.to_not raise_error
|
||||
describe '#perform' do
|
||||
let(:webhook) { Fabricate(:webhook) }
|
||||
|
||||
it 'reprocesses and updates the webhook' do
|
||||
stub_request(:post, webhook.url).to_return(status: 200, body: '')
|
||||
|
||||
worker.perform(webhook.id, 'body')
|
||||
|
||||
expect(a_request(:post, webhook.url)).to have_been_made.at_least_once
|
||||
end
|
||||
|
||||
it 'returns true for non-existent record' do
|
||||
result = worker.perform(123_123_123, '')
|
||||
|
||||
expect(result).to be(true)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue