Merge upstream 2.0ish #165
This commit is contained in:
@@ -0,0 +1,4 @@
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe Admin::AccountModerationNotesController, type: :controller do
|
||||
end
|
@@ -0,0 +1,59 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe Admin::EmailDomainBlocksController, type: :controller do
|
||||
render_views
|
||||
|
||||
before do
|
||||
sign_in Fabricate(:user, admin: true), scope: :user
|
||||
end
|
||||
|
||||
describe 'GET #index' do
|
||||
around do |example|
|
||||
default_per_page = EmailDomainBlock.default_per_page
|
||||
EmailDomainBlock.paginates_per 1
|
||||
example.run
|
||||
EmailDomainBlock.paginates_per default_per_page
|
||||
end
|
||||
|
||||
it 'renders email blacks' do
|
||||
2.times { Fabricate(:email_domain_block) }
|
||||
|
||||
get :index, params: { page: 2 }
|
||||
|
||||
assigned = assigns(:email_domain_blocks)
|
||||
expect(assigned.count).to eq 1
|
||||
expect(assigned.klass).to be EmailDomainBlock
|
||||
expect(response).to have_http_status(:success)
|
||||
end
|
||||
end
|
||||
|
||||
describe 'GET #new' do
|
||||
it 'assigns a new email black' do
|
||||
get :new
|
||||
|
||||
expect(assigns(:email_domain_block)).to be_instance_of(EmailDomainBlock)
|
||||
expect(response).to have_http_status(:success)
|
||||
end
|
||||
end
|
||||
|
||||
describe 'POST #create' do
|
||||
it 'blocks the domain when succeeded to save' do
|
||||
post :create, params: { email_domain_block: { domain: 'example.com'} }
|
||||
|
||||
expect(flash[:notice]).to eq I18n.t('admin.email_domain_blocks.created_msg')
|
||||
expect(response).to redirect_to(admin_email_domain_blocks_path)
|
||||
end
|
||||
end
|
||||
|
||||
describe 'DELETE #destroy' do
|
||||
it 'unblocks the domain' do
|
||||
email_domain_block = Fabricate(:email_domain_block)
|
||||
delete :destroy, params: { id: email_domain_block.id }
|
||||
|
||||
expect(flash[:notice]).to eq I18n.t('admin.email_domain_blocks.destroyed_msg')
|
||||
expect(response).to redirect_to(admin_email_domain_blocks_path)
|
||||
end
|
||||
end
|
||||
end
|
@@ -46,8 +46,8 @@ RSpec.describe Api::SalmonController, type: :controller do
|
||||
post :update, params: { id: account.id }
|
||||
end
|
||||
|
||||
it 'returns http success' do
|
||||
expect(response).to have_http_status(202)
|
||||
it 'returns http client error' do
|
||||
expect(response).to have_http_status(400)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
43
spec/controllers/api/v1/apps/credentials_controller_spec.rb
Normal file
43
spec/controllers/api/v1/apps/credentials_controller_spec.rb
Normal file
@@ -0,0 +1,43 @@
|
||||
require 'rails_helper'
|
||||
|
||||
describe Api::V1::Apps::CredentialsController do
|
||||
render_views
|
||||
|
||||
let(:token) { Fabricate(:accessible_access_token, scopes: 'read', application: Fabricate(:application)) }
|
||||
|
||||
context 'with an oauth token' do
|
||||
before do
|
||||
allow(controller).to receive(:doorkeeper_token) { token }
|
||||
end
|
||||
|
||||
describe 'GET #show' do
|
||||
before do
|
||||
get :show
|
||||
end
|
||||
|
||||
it 'returns http success' do
|
||||
expect(response).to have_http_status(:success)
|
||||
end
|
||||
|
||||
it 'does not contain client credentials' do
|
||||
json = body_as_json
|
||||
|
||||
expect(json).to_not have_key(:client_secret)
|
||||
expect(json).to_not have_key(:client_id)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'without an oauth token' do
|
||||
before do
|
||||
allow(controller).to receive(:doorkeeper_token) { nil }
|
||||
end
|
||||
|
||||
describe 'GET #show' do
|
||||
it 'returns http unauthorized' do
|
||||
get :show
|
||||
expect(response).to have_http_status(:unauthorized)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
@@ -6,15 +6,47 @@ RSpec.describe Api::V1::BlocksController, type: :controller do
|
||||
let(:user) { Fabricate(:user, account: Fabricate(:account, username: 'alice')) }
|
||||
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: 'follow') }
|
||||
|
||||
before do
|
||||
Fabricate(:block, account: user.account)
|
||||
allow(controller).to receive(:doorkeeper_token) { token }
|
||||
end
|
||||
before { allow(controller).to receive(:doorkeeper_token) { token } }
|
||||
|
||||
describe 'GET #index' do
|
||||
it 'returns http success' do
|
||||
it 'limits according to limit parameter' do
|
||||
2.times.map { Fabricate(:block, account: user.account) }
|
||||
get :index, params: { limit: 1 }
|
||||
expect(body_as_json.size).to eq 1
|
||||
end
|
||||
|
||||
it 'queries blocks in range according to max_id' do
|
||||
blocks = 2.times.map { Fabricate(:block, account: user.account) }
|
||||
|
||||
get :index, params: { max_id: blocks[1] }
|
||||
|
||||
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
|
||||
blocks = 2.times.map { Fabricate(:block, account: user.account) }
|
||||
|
||||
get :index, params: { since_id: blocks[0] }
|
||||
|
||||
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
|
||||
blocks = 2.times.map { Fabricate(:block, account: user.account) }
|
||||
get :index, params: { limit: 1, since_id: blocks[0] }
|
||||
expect(response.headers['Link'].find_link(['rel', 'next']).href).to eq api_v1_blocks_url(limit: 1, max_id: blocks[1])
|
||||
end
|
||||
|
||||
it 'sets pagination header for previous path' do
|
||||
block = Fabricate(:block, account: user.account)
|
||||
get :index
|
||||
expect(response.headers['Link'].find_link(['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(:success)
|
||||
end
|
||||
end
|
||||
|
@@ -101,4 +101,33 @@ RSpec.describe Api::V1::MediaController, type: :controller do
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'PUT #update' do
|
||||
context 'when somebody else\'s' do
|
||||
let(:media) { Fabricate(:media_attachment, status: nil) }
|
||||
|
||||
it 'returns http not found' do
|
||||
put :update, params: { id: media.id, description: 'Lorem ipsum!!!' }
|
||||
expect(response).to have_http_status(:not_found)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when not attached to a status' do
|
||||
let(:media) { Fabricate(:media_attachment, status: nil, account: user.account) }
|
||||
|
||||
it 'updates the description' do
|
||||
put :update, params: { id: media.id, description: 'Lorem ipsum!!!' }
|
||||
expect(media.reload.description).to eq 'Lorem ipsum!!!'
|
||||
end
|
||||
end
|
||||
|
||||
context 'when attached to a status' do
|
||||
let(:media) { Fabricate(:media_attachment, status: Fabricate(:status), account: user.account) }
|
||||
|
||||
it 'returns http not found' do
|
||||
put :update, params: { id: media.id, description: 'Lorem ipsum!!!' }
|
||||
expect(response).to have_http_status(:not_found)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@@ -8,10 +8,6 @@ describe ManifestsController do
|
||||
get :show, format: :json
|
||||
end
|
||||
|
||||
it 'assigns @instance_presenter' do
|
||||
expect(assigns(:instance_presenter)).to be_kind_of InstancePresenter
|
||||
end
|
||||
|
||||
it 'returns http success' do
|
||||
expect(response).to have_http_status(:success)
|
||||
end
|
||||
|
@@ -5,15 +5,41 @@ describe Settings::FollowerDomainsController do
|
||||
|
||||
let(:user) { Fabricate(:user) }
|
||||
|
||||
before do
|
||||
sign_in user, scope: :user
|
||||
shared_examples 'authenticate user' do
|
||||
it 'redirects when not signed in' do
|
||||
is_expected.to redirect_to '/auth/sign_in'
|
||||
end
|
||||
end
|
||||
|
||||
describe 'GET #show' do
|
||||
subject { get :show, params: { page: 2 } }
|
||||
|
||||
it 'assigns @account' do
|
||||
sign_in user, scope: :user
|
||||
subject
|
||||
expect(assigns(:account)).to eq user.account
|
||||
end
|
||||
|
||||
it 'assigns @domains' do
|
||||
Fabricate(:account, domain: 'old').follow!(user.account)
|
||||
Fabricate(:account, domain: 'recent').follow!(user.account)
|
||||
|
||||
sign_in user, scope: :user
|
||||
subject
|
||||
|
||||
assigned = assigns(:domains).per(1).to_a
|
||||
expect(assigned.size).to eq 1
|
||||
expect(assigned[0].accounts_from_domain).to eq 1
|
||||
expect(assigned[0].domain).to eq 'old'
|
||||
end
|
||||
|
||||
it 'returns http success' do
|
||||
get :show
|
||||
sign_in user, scope: :user
|
||||
subject
|
||||
expect(response).to have_http_status(:success)
|
||||
end
|
||||
|
||||
include_examples 'authenticate user'
|
||||
end
|
||||
|
||||
describe 'PATCH #update' do
|
||||
@@ -21,16 +47,39 @@ describe Settings::FollowerDomainsController do
|
||||
|
||||
before do
|
||||
stub_request(:post, 'http://example.com/salmon').to_return(status: 200)
|
||||
poopfeast.follow!(user.account)
|
||||
patch :update, params: { select: ['example.com'] }
|
||||
end
|
||||
|
||||
it 'redirects back to followers page' do
|
||||
expect(response).to redirect_to(settings_follower_domains_path)
|
||||
shared_examples 'redirects back to followers page' do |notice|
|
||||
it 'redirects back to followers page' do
|
||||
poopfeast.follow!(user.account)
|
||||
|
||||
sign_in user, scope: :user
|
||||
subject
|
||||
|
||||
expect(flash[:notice]).to eq notice
|
||||
expect(response).to redirect_to(settings_follower_domains_path)
|
||||
end
|
||||
end
|
||||
|
||||
it 'soft-blocks followers from selected domains' do
|
||||
expect(poopfeast.following?(user.account)).to be false
|
||||
context 'when select parameter is not provided' do
|
||||
subject { patch :update }
|
||||
include_examples 'redirects back to followers page', 'In the process of soft-blocking followers from 0 domains...'
|
||||
end
|
||||
|
||||
context 'when select parameter is provided' do
|
||||
subject { patch :update, params: { select: ['example.com'] } }
|
||||
|
||||
it 'soft-blocks followers from selected domains' do
|
||||
poopfeast.follow!(user.account)
|
||||
|
||||
sign_in user, scope: :user
|
||||
subject
|
||||
|
||||
expect(poopfeast.following?(user.account)).to be false
|
||||
end
|
||||
|
||||
include_examples 'authenticate user'
|
||||
include_examples 'redirects back to followers page', 'In the process of soft-blocking followers from one domain...'
|
||||
end
|
||||
end
|
||||
end
|
||||
|
37
spec/controllers/settings/notifications_controller_spec.rb
Normal file
37
spec/controllers/settings/notifications_controller_spec.rb
Normal file
@@ -0,0 +1,37 @@
|
||||
require 'rails_helper'
|
||||
|
||||
describe Settings::NotificationsController do
|
||||
render_views
|
||||
|
||||
let(:user) { Fabricate(:user) }
|
||||
|
||||
before do
|
||||
sign_in user, scope: :user
|
||||
end
|
||||
|
||||
describe 'GET #show' do
|
||||
it 'returns http success' do
|
||||
get :show
|
||||
expect(response).to have_http_status(:success)
|
||||
end
|
||||
end
|
||||
|
||||
describe 'PUT #update' do
|
||||
it 'updates notifications settings' do
|
||||
user.settings['notification_emails'] = user.settings['notification_emails'].merge('follow' => false)
|
||||
user.settings['interactions'] = user.settings['interactions'].merge('must_be_follower' => true)
|
||||
|
||||
put :update, params: {
|
||||
user: {
|
||||
notification_emails: { follow: '1' },
|
||||
interactions: { must_be_follower: '0' },
|
||||
}
|
||||
}
|
||||
|
||||
expect(response).to redirect_to(settings_notifications_path)
|
||||
user.reload
|
||||
expect(user.settings['notification_emails']['follow']).to be true
|
||||
expect(user.settings['interactions']['must_be_follower']).to be false
|
||||
end
|
||||
end
|
||||
end
|
@@ -29,15 +29,11 @@ describe Settings::PreferencesController do
|
||||
it 'updates user settings' do
|
||||
user.settings['boost_modal'] = false
|
||||
user.settings['delete_modal'] = true
|
||||
user.settings['notification_emails'] = user.settings['notification_emails'].merge('follow' => false)
|
||||
user.settings['interactions'] = user.settings['interactions'].merge('must_be_follower' => true)
|
||||
|
||||
put :update, params: {
|
||||
user: {
|
||||
setting_boost_modal: '1',
|
||||
setting_delete_modal: '0',
|
||||
notification_emails: { follow: '1' },
|
||||
interactions: { must_be_follower: '0' },
|
||||
}
|
||||
}
|
||||
|
||||
@@ -45,8 +41,6 @@ describe Settings::PreferencesController do
|
||||
user.reload
|
||||
expect(user.settings['boost_modal']).to be true
|
||||
expect(user.settings['delete_modal']).to be false
|
||||
expect(user.settings['notification_emails']['follow']).to be true
|
||||
expect(user.settings['interactions']['must_be_follower']).to be false
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@@ -5,9 +5,9 @@ RSpec.describe TagsController, type: :controller do
|
||||
|
||||
describe 'GET #show' do
|
||||
let!(:tag) { Fabricate(:tag, name: 'test') }
|
||||
let!(:local) { Fabricate(:status, tags: [ tag ], text: 'local #test') }
|
||||
let!(:remote) { Fabricate(:status, tags: [ tag ], text: 'remote #test', account: Fabricate(:account, domain: 'remote')) }
|
||||
let!(:late) { Fabricate(:status, tags: [ tag ], text: 'late #test') }
|
||||
let!(:local) { Fabricate(:status, tags: [tag], text: 'local #test') }
|
||||
let!(:remote) { Fabricate(:status, tags: [tag], text: 'remote #test', account: Fabricate(:account, domain: 'remote')) }
|
||||
let!(:late) { Fabricate(:status, tags: [tag], text: 'late #test') }
|
||||
|
||||
context 'when tag exists' do
|
||||
it 'returns http success' do
|
||||
@@ -15,41 +15,9 @@ RSpec.describe TagsController, type: :controller do
|
||||
expect(response).to have_http_status(:success)
|
||||
end
|
||||
|
||||
it 'renders public layout' do
|
||||
it 'renders application layout' do
|
||||
get :show, params: { id: 'test', max_id: late.id }
|
||||
expect(response).to render_template layout: 'public'
|
||||
end
|
||||
|
||||
it 'renders only local statuses if local parameter is specified' do
|
||||
get :show, params: { id: 'test', local: true, max_id: late.id }
|
||||
|
||||
expect(assigns(:tag)).to eq tag
|
||||
statuses = assigns(:statuses).to_a
|
||||
expect(statuses.size).to eq 1
|
||||
expect(statuses[0]).to eq local
|
||||
end
|
||||
|
||||
it 'renders local and remote statuses if local parameter is not specified' do
|
||||
get :show, params: { id: 'test', max_id: late.id }
|
||||
|
||||
expect(assigns(:tag)).to eq tag
|
||||
statuses = assigns(:statuses).to_a
|
||||
expect(statuses.size).to eq 2
|
||||
expect(statuses[0]).to eq remote
|
||||
expect(statuses[1]).to eq local
|
||||
end
|
||||
|
||||
it 'filters statuses by the current account' do
|
||||
user = Fabricate(:user)
|
||||
user.account.block!(remote.account)
|
||||
|
||||
sign_in(user)
|
||||
get :show, params: { id: 'test', max_id: late.id }
|
||||
|
||||
expect(assigns(:tag)).to eq tag
|
||||
statuses = assigns(:statuses).to_a
|
||||
expect(statuses.size).to eq 1
|
||||
expect(statuses[0]).to eq local
|
||||
expect(response).to render_template layout: 'application'
|
||||
end
|
||||
end
|
||||
|
||||
|
4
spec/fabricators/account_moderation_note_fabricator.rb
Normal file
4
spec/fabricators/account_moderation_note_fabricator.rb
Normal file
@@ -0,0 +1,4 @@
|
||||
Fabricator(:account_moderation_note) do
|
||||
content "MyText"
|
||||
account nil
|
||||
end
|
3
spec/fabricators/email_domain_block_fabricator.rb
Normal file
3
spec/fabricators/email_domain_block_fabricator.rb
Normal file
@@ -0,0 +1,3 @@
|
||||
Fabricator(:email_domain_block) do
|
||||
domain { sequence(:domain) { |i| "#{i}#{Faker::Internet.domain_name}" } }
|
||||
end
|
15
spec/helpers/admin/account_moderation_notes_helper_spec.rb
Normal file
15
spec/helpers/admin/account_moderation_notes_helper_spec.rb
Normal file
@@ -0,0 +1,15 @@
|
||||
require 'rails_helper'
|
||||
|
||||
# Specs in this file have access to a helper object that includes
|
||||
# the Admin::AccountModerationNotesHelper. For example:
|
||||
#
|
||||
# describe Admin::AccountModerationNotesHelper do
|
||||
# describe "string concat" do
|
||||
# it "concats two strings with spaces" do
|
||||
# expect(helper.concat_strings("this","that")).to eq("this that")
|
||||
# end
|
||||
# end
|
||||
# end
|
||||
RSpec.describe Admin::AccountModerationNotesHelper, type: :helper do
|
||||
pending "add some examples to (or delete) #{__FILE__}"
|
||||
end
|
@@ -30,6 +30,39 @@ describe JsonLdHelper do
|
||||
end
|
||||
|
||||
describe '#fetch_resource' do
|
||||
pending
|
||||
context 'when the second argument is false' do
|
||||
it 'returns resource even if the retrieved ID and the given URI does not match' do
|
||||
stub_request(:get, 'https://bob/').to_return body: '{"id": "https://alice/"}'
|
||||
stub_request(:get, 'https://alice/').to_return body: '{"id": "https://alice/"}'
|
||||
|
||||
expect(fetch_resource('https://bob/', false)).to eq({ 'id' => 'https://alice/' })
|
||||
end
|
||||
|
||||
it 'returns nil if the object identified by the given URI and the object identified by the retrieved ID does not match' do
|
||||
stub_request(:get, 'https://mallory/').to_return body: '{"id": "https://marvin/"}'
|
||||
stub_request(:get, 'https://marvin/').to_return body: '{"id": "https://alice/"}'
|
||||
|
||||
expect(fetch_resource('https://mallory/', false)).to eq nil
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the second argument is true' do
|
||||
it 'returns nil if the retrieved ID and the given URI does not match' do
|
||||
stub_request(:get, 'https://mallory/').to_return body: '{"id": "https://alice/"}'
|
||||
expect(fetch_resource('https://mallory/', true)).to eq nil
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#fetch_resource_without_id_validation' do
|
||||
it 'returns nil if the status code is not 200' do
|
||||
stub_request(:get, 'https://host/').to_return status: 400, body: '{}'
|
||||
expect(fetch_resource_without_id_validation('https://host/')).to eq nil
|
||||
end
|
||||
|
||||
it 'returns hash' do
|
||||
stub_request(:get, 'https://host/').to_return status: 200, body: '{}'
|
||||
expect(fetch_resource_without_id_validation('https://host/')).to eq({})
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@@ -1,8 +1,9 @@
|
||||
import React from 'react';
|
||||
import Avatar from '../../../app/javascript/mastodon/components/avatar';
|
||||
|
||||
import { expect } from 'chai';
|
||||
import { render } from 'enzyme';
|
||||
import { fromJS } from 'immutable';
|
||||
import React from 'react';
|
||||
import Avatar from '../../../app/javascript/mastodon/components/avatar';
|
||||
|
||||
describe('<Avatar />', () => {
|
||||
const account = fromJS({
|
||||
@@ -12,27 +13,28 @@ describe('<Avatar />', () => {
|
||||
avatar: '/animated/alice.gif',
|
||||
avatar_static: '/static/alice.jpg',
|
||||
});
|
||||
|
||||
const size = 100;
|
||||
const animated = render(<Avatar account={account} animate size={size} />);
|
||||
const still = render(<Avatar account={account} size={size} />);
|
||||
|
||||
// Autoplay
|
||||
it('renders a div element with the given src as background', () => {
|
||||
xit('renders a div element with the given src as background', () => {
|
||||
expect(animated.find('div')).to.have.style('background-image', `url(${account.get('avatar')})`);
|
||||
});
|
||||
|
||||
it('renders a div element of the given size', () => {
|
||||
xit('renders a div element of the given size', () => {
|
||||
['width', 'height'].map((attr) => {
|
||||
expect(animated.find('div')).to.have.style(attr, `${size}px`);
|
||||
});
|
||||
});
|
||||
|
||||
// Still
|
||||
it('renders a div element with the given static src as background if not autoplay', () => {
|
||||
xit('renders a div element with the given static src as background if not autoplay', () => {
|
||||
expect(still.find('div')).to.have.style('background-image', `url(${account.get('avatar_static')})`);
|
||||
});
|
||||
|
||||
it('renders a div element of the given size if not autoplay', () => {
|
||||
xit('renders a div element of the given size if not autoplay', () => {
|
||||
['width', 'height'].map((attr) => {
|
||||
expect(still.find('div')).to.have.style(attr, `${size}px`);
|
||||
});
|
||||
|
@@ -1,8 +1,9 @@
|
||||
import React from 'react';
|
||||
import AvatarOverlay from '../../../app/javascript/mastodon/components/avatar_overlay';
|
||||
|
||||
import { expect } from 'chai';
|
||||
import { render } from 'enzyme';
|
||||
import { fromJS } from 'immutable';
|
||||
import React from 'react';
|
||||
import AvatarOverlay from '../../../app/javascript/mastodon/components/avatar_overlay';
|
||||
|
||||
describe('<Avatar />', () => {
|
||||
const account = fromJS({
|
||||
@@ -12,6 +13,7 @@ describe('<Avatar />', () => {
|
||||
avatar: '/animated/alice.gif',
|
||||
avatar_static: '/static/alice.jpg',
|
||||
});
|
||||
|
||||
const friend = fromJS({
|
||||
username: 'eve',
|
||||
acct: 'eve@blackhat.lair',
|
||||
@@ -22,12 +24,12 @@ describe('<Avatar />', () => {
|
||||
|
||||
const overlay = render(<AvatarOverlay account={account} friend={friend} />);
|
||||
|
||||
it('renders account static src as base of overlay avatar', () => {
|
||||
xit('renders account static src as base of overlay avatar', () => {
|
||||
expect(overlay.find('.account__avatar-overlay-base'))
|
||||
.to.have.style('background-image', `url(${account.get('avatar_static')})`);
|
||||
});
|
||||
|
||||
it('renders friend static src as overlay of overlay avatar', () => {
|
||||
xit('renders friend static src as overlay of overlay avatar', () => {
|
||||
expect(overlay.find('.account__avatar-overlay-overlay'))
|
||||
.to.have.style('background-image', `url(${friend.get('avatar_static')})`);
|
||||
});
|
||||
|
@@ -1,16 +1,17 @@
|
||||
import { expect } from 'chai';
|
||||
import { shallow } from 'enzyme';
|
||||
import sinon from 'sinon';
|
||||
import React from 'react';
|
||||
import Button from '../../../app/javascript/mastodon/components/button';
|
||||
|
||||
import { expect } from 'chai';
|
||||
import { shallow } from 'enzyme';
|
||||
import sinon from 'sinon';
|
||||
|
||||
describe('<Button />', () => {
|
||||
it('renders a button element', () => {
|
||||
xit('renders a button element', () => {
|
||||
const wrapper = shallow(<Button />);
|
||||
expect(wrapper).to.match('button');
|
||||
});
|
||||
|
||||
it('renders the given text', () => {
|
||||
xit('renders the given text', () => {
|
||||
const text = 'foo';
|
||||
const wrapper = shallow(<Button text={text} />);
|
||||
expect(wrapper.find('button')).to.have.text(text);
|
||||
@@ -30,18 +31,18 @@ describe('<Button />', () => {
|
||||
expect(handler.called).to.equal(false);
|
||||
});
|
||||
|
||||
it('renders a disabled attribute if props.disabled given', () => {
|
||||
xit('renders a disabled attribute if props.disabled given', () => {
|
||||
const wrapper = shallow(<Button disabled />);
|
||||
expect(wrapper.find('button')).to.be.disabled();
|
||||
});
|
||||
|
||||
it('renders the children', () => {
|
||||
xit('renders the children', () => {
|
||||
const children = <p>children</p>;
|
||||
const wrapper = shallow(<Button>{children}</Button>);
|
||||
expect(wrapper.find('button')).to.contain(children);
|
||||
});
|
||||
|
||||
it('renders the props.text instead of children', () => {
|
||||
xit('renders the props.text instead of children', () => {
|
||||
const text = 'foo';
|
||||
const children = <p>children</p>;
|
||||
const wrapper = shallow(<Button text={text}>{children}</Button>);
|
||||
@@ -49,22 +50,22 @@ describe('<Button />', () => {
|
||||
expect(wrapper.find('button')).to.not.contain(children);
|
||||
});
|
||||
|
||||
it('renders style="display: block; width: 100%;" if props.block given', () => {
|
||||
xit('renders style="display: block; width: 100%;" if props.block given', () => {
|
||||
const wrapper = shallow(<Button block />);
|
||||
expect(wrapper.find('button')).to.have.className('button--block');
|
||||
});
|
||||
|
||||
it('renders style="display: inline-block; width: auto;" by default', () => {
|
||||
xit('renders style="display: inline-block; width: auto;" by default', () => {
|
||||
const wrapper = shallow(<Button />);
|
||||
expect(wrapper.find('button')).to.not.have.className('button--block');
|
||||
});
|
||||
|
||||
it('adds class "button-secondary" if props.secondary given', () => {
|
||||
xit('adds class "button-secondary" if props.secondary given', () => {
|
||||
const wrapper = shallow(<Button secondary />);
|
||||
expect(wrapper.find('button')).to.have.className('button-secondary');
|
||||
});
|
||||
|
||||
it('does not add class "button-secondary" by default', () => {
|
||||
xit('does not add class "button-secondary" by default', () => {
|
||||
const wrapper = shallow(<Button />);
|
||||
expect(wrapper.find('button')).to.not.have.className('button-secondary');
|
||||
});
|
||||
|
@@ -1,11 +1,12 @@
|
||||
import { expect } from 'chai';
|
||||
import { render } from 'enzyme';
|
||||
import { fromJS } from 'immutable';
|
||||
import React from 'react';
|
||||
import DisplayName from '../../../app/javascript/mastodon/components/display_name';
|
||||
|
||||
import { expect } from 'chai';
|
||||
import { render } from 'enzyme';
|
||||
import { fromJS } from 'immutable';
|
||||
|
||||
describe('<DisplayName />', () => {
|
||||
it('renders display name + account name', () => {
|
||||
xit('renders display name + account name', () => {
|
||||
const account = fromJS({
|
||||
username: 'bar',
|
||||
acct: 'bar@baz',
|
||||
|
111
spec/javascript/components/emoji_index.test.js
Normal file
111
spec/javascript/components/emoji_index.test.js
Normal file
@@ -0,0 +1,111 @@
|
||||
import { expect } from 'chai';
|
||||
import { search } from '../../../app/javascript/mastodon/features/emoji/emoji_mart_search_light';
|
||||
import { emojiIndex } from 'emoji-mart';
|
||||
import { pick } from 'lodash';
|
||||
|
||||
const trimEmojis = emoji => pick(emoji, ['id', 'unified', 'native', 'custom']);
|
||||
|
||||
// hack to fix https://github.com/chaijs/type-detect/issues/98
|
||||
// see: https://github.com/chaijs/type-detect/issues/98#issuecomment-325010785
|
||||
import jsdom from 'jsdom';
|
||||
global.window = new jsdom.JSDOM().window;
|
||||
global.document = window.document;
|
||||
global.HTMLElement = window.HTMLElement;
|
||||
|
||||
describe('emoji_index', () => {
|
||||
|
||||
it('should give same result for emoji_index_light and emoji-mart', () => {
|
||||
let expected = [{
|
||||
id: 'pineapple',
|
||||
unified: '1f34d',
|
||||
native: '🍍',
|
||||
}];
|
||||
expect(search('pineapple').map(trimEmojis)).to.deep.equal(expected);
|
||||
expect(emojiIndex.search('pineapple').map(trimEmojis)).to.deep.equal(expected);
|
||||
});
|
||||
|
||||
it('orders search results correctly', () => {
|
||||
let expected = [{
|
||||
id: 'apple',
|
||||
unified: '1f34e',
|
||||
native: '🍎',
|
||||
}, {
|
||||
id: 'pineapple',
|
||||
unified: '1f34d',
|
||||
native: '🍍',
|
||||
}, {
|
||||
id: 'green_apple',
|
||||
unified: '1f34f',
|
||||
native: '🍏',
|
||||
}, {
|
||||
id: 'iphone',
|
||||
unified: '1f4f1',
|
||||
native: '📱',
|
||||
}];
|
||||
expect(search('apple').map(trimEmojis)).to.deep.equal(expected);
|
||||
expect(emojiIndex.search('apple').map(trimEmojis)).to.deep.equal(expected);
|
||||
});
|
||||
|
||||
it('handles custom emoji', () => {
|
||||
let custom = [{
|
||||
id: 'mastodon',
|
||||
name: 'mastodon',
|
||||
short_names: ['mastodon'],
|
||||
text: '',
|
||||
emoticons: [],
|
||||
keywords: ['mastodon'],
|
||||
imageUrl: 'http://example.com',
|
||||
custom: true,
|
||||
}];
|
||||
search('', { custom });
|
||||
emojiIndex.search('', { custom });
|
||||
let expected = [ { id: 'mastodon', custom: true } ];
|
||||
expect(search('masto').map(trimEmojis)).to.deep.equal(expected);
|
||||
expect(emojiIndex.search('masto').map(trimEmojis)).to.deep.equal(expected);
|
||||
});
|
||||
|
||||
it('should filter only emojis we care about, exclude pineapple', () => {
|
||||
let emojisToShowFilter = (unified) => unified !== '1F34D';
|
||||
expect(search('apple', { emojisToShowFilter }).map((obj) => obj.id))
|
||||
.not.to.contain('pineapple');
|
||||
expect(emojiIndex.search('apple', { emojisToShowFilter }).map((obj) => obj.id))
|
||||
.not.to.contain('pineapple');
|
||||
});
|
||||
|
||||
it('can include/exclude categories', () => {
|
||||
expect(search('flag', { include: ['people'] }))
|
||||
.to.deep.equal([]);
|
||||
expect(emojiIndex.search('flag', { include: ['people'] }))
|
||||
.to.deep.equal([]);
|
||||
});
|
||||
|
||||
it('does an emoji whose unified name is irregular', () => {
|
||||
let expected = [{
|
||||
'id': 'water_polo',
|
||||
'unified': '1f93d',
|
||||
'native': '🤽',
|
||||
}, {
|
||||
'id': 'man-playing-water-polo',
|
||||
'unified': '1f93d-200d-2642-fe0f',
|
||||
'native': '🤽♂️',
|
||||
}, {
|
||||
'id': 'woman-playing-water-polo',
|
||||
'unified': '1f93d-200d-2640-fe0f',
|
||||
'native': '🤽♀️',
|
||||
}];
|
||||
expect(search('polo').map(trimEmojis)).to.deep.equal(expected);
|
||||
expect(emojiIndex.search('polo').map(trimEmojis)).to.deep.equal(expected);
|
||||
});
|
||||
|
||||
it('can search for thinking_face', () => {
|
||||
let expected = [ { id: 'thinking_face', unified: '1f914', native: '🤔' } ];
|
||||
expect(search('thinking_fac').map(trimEmojis)).to.deep.equal(expected);
|
||||
expect(emojiIndex.search('thinking_fac').map(trimEmojis)).to.deep.equal(expected);
|
||||
});
|
||||
|
||||
it('can search for woman-facepalming', () => {
|
||||
let expected = [ { id: 'woman-facepalming', unified: '1f926-200d-2640-fe0f', native: '🤦♀️' } ];
|
||||
expect(search('woman-facep').map(trimEmojis)).to.deep.equal(expected);
|
||||
expect(emojiIndex.search('woman-facep').map(trimEmojis)).deep.equal(expected);
|
||||
});
|
||||
});
|
@@ -1,5 +1,5 @@
|
||||
import { expect } from 'chai';
|
||||
import emojify from '../../../app/javascript/mastodon/emoji';
|
||||
import emojify from '../../../app/javascript/mastodon/features/emoji/emoji';
|
||||
|
||||
describe('emojify', () => {
|
||||
it('ignores unknown shortcodes', () => {
|
||||
@@ -44,4 +44,18 @@ describe('emojify', () => {
|
||||
it('ignores unicode inside of tags', () => {
|
||||
expect(emojify('<p data-foo="\uD83D\uDC69\uD83D\uDC69\uD83D\uDC66"></p>')).to.equal('<p data-foo="\uD83D\uDC69\uD83D\uDC69\uD83D\uDC66"></p>');
|
||||
});
|
||||
|
||||
it('does multiple emoji properly (issue 5188)', () => {
|
||||
expect(emojify('👌🌈💕')).to.equal('<img draggable="false" class="emojione" alt="👌" title=":ok_hand:" src="/emoji/1f44c.svg" /><img draggable="false" class="emojione" alt="🌈" title=":rainbow:" src="/emoji/1f308.svg" /><img draggable="false" class="emojione" alt="💕" title=":two_hearts:" src="/emoji/1f495.svg" />');
|
||||
expect(emojify('👌 🌈 💕')).to.equal('<img draggable="false" class="emojione" alt="👌" title=":ok_hand:" src="/emoji/1f44c.svg" /> <img draggable="false" class="emojione" alt="🌈" title=":rainbow:" src="/emoji/1f308.svg" /> <img draggable="false" class="emojione" alt="💕" title=":two_hearts:" src="/emoji/1f495.svg" />');
|
||||
});
|
||||
|
||||
it('does an emoji that has no shortcode', () => {
|
||||
expect(emojify('🕉️')).to.equal('<img draggable="false" class="emojione" alt="🕉️" title="" src="/emoji/1f549.svg" />');
|
||||
});
|
||||
|
||||
it('does an emoji whose filename is irregular', () => {
|
||||
expect(emojify('↙️')).to.equal('<img draggable="false" class="emojione" alt="↙️" title=":arrow_lower_left:" src="/emoji/2199.svg" />');
|
||||
});
|
||||
|
||||
});
|
||||
|
@@ -1,11 +1,13 @@
|
||||
import { JSDOM } from 'jsdom';
|
||||
import chai from 'chai';
|
||||
import chaiEnzyme from 'chai-enzyme';
|
||||
chai.use(chaiEnzyme());
|
||||
import Enzyme from 'enzyme';
|
||||
import Adapter from 'enzyme-adapter-react-16';
|
||||
|
||||
Enzyme.configure({ adapter: new Adapter() });
|
||||
|
||||
const { window } = new JSDOM('', {
|
||||
userAgent: 'node.js',
|
||||
});
|
||||
|
||||
Object.keys(window).forEach(property => {
|
||||
if (typeof global[property] === 'undefined') {
|
||||
global[property] = window[property];
|
||||
|
@@ -290,7 +290,9 @@ RSpec.describe ActivityPub::Activity::Create do
|
||||
tag: [
|
||||
{
|
||||
type: 'Emoji',
|
||||
href: 'http://example.com/emoji.png',
|
||||
icon: {
|
||||
url: 'http://example.com/emoji.png',
|
||||
},
|
||||
name: 'tinking',
|
||||
},
|
||||
],
|
||||
@@ -314,7 +316,9 @@ RSpec.describe ActivityPub::Activity::Create do
|
||||
tag: [
|
||||
{
|
||||
type: 'Emoji',
|
||||
href: 'http://example.com/emoji.png',
|
||||
icon: {
|
||||
url: 'http://example.com/emoji.png',
|
||||
},
|
||||
},
|
||||
],
|
||||
}
|
||||
@@ -326,7 +330,7 @@ RSpec.describe ActivityPub::Activity::Create do
|
||||
end
|
||||
end
|
||||
|
||||
context 'with emojis missing href' do
|
||||
context 'with emojis missing icon' do
|
||||
let(:object_json) do
|
||||
{
|
||||
id: 'bar',
|
||||
|
71
spec/lib/delivery_failure_tracker_spec.rb
Normal file
71
spec/lib/delivery_failure_tracker_spec.rb
Normal file
@@ -0,0 +1,71 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require 'rails_helper'
|
||||
|
||||
describe DeliveryFailureTracker do
|
||||
subject { described_class.new('http://example.com/inbox') }
|
||||
|
||||
describe '#track_success!' do
|
||||
before do
|
||||
subject.track_failure!
|
||||
subject.track_success!
|
||||
end
|
||||
|
||||
it 'marks URL as available again' do
|
||||
expect(described_class.available?('http://example.com/inbox')).to be true
|
||||
end
|
||||
|
||||
it 'resets days to 0' do
|
||||
expect(subject.days).to be_zero
|
||||
end
|
||||
end
|
||||
|
||||
describe '#track_failure!' do
|
||||
it 'marks URL as unavailable after 7 days of being called' do
|
||||
6.times { |i| Redis.current.sadd('exhausted_deliveries:http://example.com/inbox', i) }
|
||||
subject.track_failure!
|
||||
|
||||
expect(subject.days).to eq 7
|
||||
expect(described_class.unavailable?('http://example.com/inbox')).to be true
|
||||
end
|
||||
|
||||
it 'repeated calls on the same day do not count' do
|
||||
subject.track_failure!
|
||||
subject.track_failure!
|
||||
|
||||
expect(subject.days).to eq 1
|
||||
end
|
||||
end
|
||||
|
||||
describe '.filter' do
|
||||
before do
|
||||
Redis.current.sadd('unavailable_inboxes', 'http://example.com/unavailable/inbox')
|
||||
end
|
||||
|
||||
it 'removes URLs that are unavailable' do
|
||||
result = described_class.filter(['http://example.com/good/inbox', 'http://example.com/unavailable/inbox'])
|
||||
|
||||
expect(result).to include('http://example.com/good/inbox')
|
||||
expect(result).to_not include('http://example.com/unavailable/inbox')
|
||||
end
|
||||
end
|
||||
|
||||
describe '.track_inverse_success!' do
|
||||
let(:from_account) { Fabricate(:account, inbox_url: 'http://example.com/inbox', shared_inbox_url: 'http://example.com/shared/inbox') }
|
||||
|
||||
before do
|
||||
Redis.current.sadd('unavailable_inboxes', 'http://example.com/inbox')
|
||||
Redis.current.sadd('unavailable_inboxes', 'http://example.com/shared/inbox')
|
||||
|
||||
described_class.track_inverse_success!(from_account)
|
||||
end
|
||||
|
||||
it 'marks inbox URL as available again' do
|
||||
expect(described_class.available?('http://example.com/inbox')).to be true
|
||||
end
|
||||
|
||||
it 'marks shared inbox URL as available again' do
|
||||
expect(described_class.available?('http://example.com/shared/inbox')).to be true
|
||||
end
|
||||
end
|
||||
end
|
@@ -1,6 +1,10 @@
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe FeedManager do
|
||||
it 'tracks at least as many statuses as reblogs' do
|
||||
expect(FeedManager::REBLOG_FALLOFF).to be <= FeedManager::MAX_ITEMS
|
||||
end
|
||||
|
||||
describe '#key' do
|
||||
subject { FeedManager.instance.key(:home, 1) }
|
||||
|
||||
@@ -150,5 +154,110 @@ RSpec.describe FeedManager do
|
||||
|
||||
expect(Redis.current.zcard("feed:type:#{account.id}")).to eq FeedManager::MAX_ITEMS
|
||||
end
|
||||
|
||||
it 'sends push updates for non-home timelines' do
|
||||
account = Fabricate(:account)
|
||||
status = Fabricate(:status)
|
||||
allow(Redis.current).to receive_messages(publish: nil)
|
||||
|
||||
FeedManager.instance.push('type', account, status)
|
||||
|
||||
expect(Redis.current).to have_received(:publish).with("timeline:#{account.id}", any_args).at_least(:once)
|
||||
end
|
||||
|
||||
context 'reblogs' do
|
||||
it 'saves reblogs of unseen statuses' do
|
||||
account = Fabricate(:account)
|
||||
reblogged = Fabricate(:status)
|
||||
reblog = Fabricate(:status, reblog: reblogged)
|
||||
|
||||
expect(FeedManager.instance.push('type', account, reblog)).to be true
|
||||
end
|
||||
|
||||
it 'does not save a new reblog of a recent status' do
|
||||
account = Fabricate(:account)
|
||||
reblogged = Fabricate(:status)
|
||||
reblog = Fabricate(:status, reblog: reblogged)
|
||||
|
||||
FeedManager.instance.push('type', account, reblogged)
|
||||
|
||||
expect(FeedManager.instance.push('type', account, reblog)).to be false
|
||||
end
|
||||
|
||||
it 'saves a new reblog of an old status' do
|
||||
account = Fabricate(:account)
|
||||
reblogged = Fabricate(:status)
|
||||
reblog = Fabricate(:status, reblog: reblogged)
|
||||
|
||||
FeedManager.instance.push('type', account, reblogged)
|
||||
|
||||
# Fill the feed with intervening statuses
|
||||
FeedManager::REBLOG_FALLOFF.times do
|
||||
FeedManager.instance.push('type', account, Fabricate(:status))
|
||||
end
|
||||
|
||||
expect(FeedManager.instance.push('type', account, reblog)).to be true
|
||||
end
|
||||
|
||||
it 'does not save a new reblog of a recently-reblogged status' do
|
||||
account = Fabricate(:account)
|
||||
reblogged = Fabricate(:status)
|
||||
reblogs = 2.times.map { Fabricate(:status, reblog: reblogged) }
|
||||
|
||||
# The first reblog will be accepted
|
||||
FeedManager.instance.push('type', account, reblogs.first)
|
||||
|
||||
# The second reblog should be ignored
|
||||
expect(FeedManager.instance.push('type', account, reblogs.last)).to be false
|
||||
end
|
||||
|
||||
it 'saves a new reblog of a long-ago-reblogged status' do
|
||||
account = Fabricate(:account)
|
||||
reblogged = Fabricate(:status)
|
||||
reblogs = 2.times.map { Fabricate(:status, reblog: reblogged) }
|
||||
|
||||
# The first reblog will be accepted
|
||||
FeedManager.instance.push('type', account, reblogs.first)
|
||||
|
||||
# Fill the feed with intervening statuses
|
||||
FeedManager::REBLOG_FALLOFF.times do
|
||||
FeedManager.instance.push('type', account, Fabricate(:status))
|
||||
end
|
||||
|
||||
# The second reblog should also be accepted
|
||||
expect(FeedManager.instance.push('type', account, reblogs.last)).to be true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#unpush' do
|
||||
it 'leaves a reblogged status when deleting the reblog' do
|
||||
account = Fabricate(:account)
|
||||
reblogged = Fabricate(:status)
|
||||
status = Fabricate(:status, reblog: reblogged)
|
||||
|
||||
FeedManager.instance.push('type', account, status)
|
||||
|
||||
# The reblogging status should show up under normal conditions.
|
||||
expect(Redis.current.zrange("feed:type:#{account.id}", 0, -1)).to eq [status.id.to_s]
|
||||
|
||||
FeedManager.instance.unpush('type', account, status)
|
||||
|
||||
# Because we couldn't tell if the status showed up any other way,
|
||||
# we had to stick the reblogged status in by itself.
|
||||
expect(Redis.current.zrange("feed:type:#{account.id}", 0, -1)).to eq [reblogged.id.to_s]
|
||||
end
|
||||
|
||||
it 'sends push updates' do
|
||||
account = Fabricate(:account)
|
||||
status = Fabricate(:status)
|
||||
FeedManager.instance.push('type', account, status)
|
||||
|
||||
allow(Redis.current).to receive_messages(publish: nil)
|
||||
FeedManager.instance.unpush('type', account, status)
|
||||
|
||||
deletion = Oj.dump(event: :delete, payload: status.id.to_s)
|
||||
expect(Redis.current).to have_received(:publish).with("timeline:#{account.id}", deletion)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
5
spec/models/account_moderation_note_spec.rb
Normal file
5
spec/models/account_moderation_note_spec.rb
Normal file
@@ -0,0 +1,5 @@
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe AccountModerationNote, type: :model do
|
||||
pending "add some examples to (or delete) #{__FILE__}"
|
||||
end
|
21
spec/models/email_domain_block_spec.rb
Normal file
21
spec/models/email_domain_block_spec.rb
Normal file
@@ -0,0 +1,21 @@
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe EmailDomainBlock, type: :model do
|
||||
describe 'validations' do
|
||||
it 'has a valid fabricator' do
|
||||
email_domain_block = Fabricate.build(:email_domain_block)
|
||||
expect(email_domain_block).to be_valid
|
||||
end
|
||||
end
|
||||
|
||||
describe 'block?' do
|
||||
it 'returns true if the domain is registed' do
|
||||
Fabricate(:email_domain_block, domain: 'example.com')
|
||||
expect(EmailDomainBlock.block?('nyarn@example.com')).to eq true
|
||||
end
|
||||
it 'returns true if the domain is not registed' do
|
||||
Fabricate(:email_domain_block, domain: 'domain')
|
||||
expect(EmailDomainBlock.block?('example')).to eq false
|
||||
end
|
||||
end
|
||||
end
|
@@ -9,7 +9,7 @@ RSpec.describe Feed, type: :model do
|
||||
Fabricate(:status, account: account, id: 3)
|
||||
Fabricate(:status, account: account, id: 10)
|
||||
Redis.current.zadd(FeedManager.instance.key(:home, account.id),
|
||||
[[4, 'deleted'], [3, 'val3'], [2, 'val2'], [1, 'val1']])
|
||||
[[4, 4], [3, 3], [2, 2], [1, 1]])
|
||||
|
||||
feed = Feed.new(:home, account)
|
||||
results = feed.get(3)
|
||||
|
@@ -17,7 +17,6 @@ RSpec.describe MediaAttachment, type: :model do
|
||||
expect(media.file.meta["original"]["height"]).to eq 128
|
||||
expect(media.file.meta["original"]["aspect"]).to eq 1.0
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
describe 'non-animated gif non-conversion' do
|
||||
@@ -50,4 +49,12 @@ RSpec.describe MediaAttachment, type: :model do
|
||||
expect(media.file.meta["small"]["aspect"]).to eq 400.0/267
|
||||
end
|
||||
end
|
||||
|
||||
describe 'descriptions for remote attachments' do
|
||||
it 'are cut off at 140 characters' do
|
||||
media = Fabricate(:media_attachment, description: 'foo' * 1000, remote_url: 'http://example.com/blah.jpg')
|
||||
|
||||
expect(media.description.size).to be <= 420
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@@ -16,7 +16,7 @@ RSpec.describe ActivityPub::FetchRemoteAccountService do
|
||||
end
|
||||
|
||||
describe '#call' do
|
||||
let(:account) { subject.call('https://example.com/alice') }
|
||||
let(:account) { subject.call('https://example.com/alice', id: true) }
|
||||
|
||||
shared_examples 'sets profile data' do
|
||||
it 'returns an account' do
|
||||
|
@@ -15,21 +15,11 @@ RSpec.describe ActivityPub::FetchRemoteStatusService do
|
||||
}
|
||||
end
|
||||
|
||||
let(:create) do
|
||||
{
|
||||
'@context': 'https://www.w3.org/ns/activitystreams',
|
||||
id: "https://#{valid_domain}/@foo/1234/activity",
|
||||
type: 'Create',
|
||||
actor: ActivityPub::TagManager.instance.uri_for(sender),
|
||||
object: note,
|
||||
}
|
||||
end
|
||||
|
||||
subject { described_class.new }
|
||||
|
||||
describe '#call' do
|
||||
before do
|
||||
subject.call(object[:id], Oj.dump(object))
|
||||
subject.call(object[:id], prefetched_body: Oj.dump(object))
|
||||
end
|
||||
|
||||
context 'with Note object' do
|
||||
@@ -42,34 +32,5 @@ RSpec.describe ActivityPub::FetchRemoteStatusService do
|
||||
expect(status.text).to eq 'Lorem ipsum'
|
||||
end
|
||||
end
|
||||
|
||||
context 'with Create activity' do
|
||||
let(:object) { create }
|
||||
|
||||
it 'creates status' do
|
||||
status = sender.statuses.first
|
||||
|
||||
expect(status).to_not be_nil
|
||||
expect(status.text).to eq 'Lorem ipsum'
|
||||
end
|
||||
end
|
||||
|
||||
context 'with Announce activity' do
|
||||
let(:status) { Fabricate(:status, account: recipient) }
|
||||
|
||||
let(:object) do
|
||||
{
|
||||
'@context': 'https://www.w3.org/ns/activitystreams',
|
||||
id: "https://#{valid_domain}/@foo/1234/activity",
|
||||
type: 'Announce',
|
||||
actor: ActivityPub::TagManager.instance.uri_for(sender),
|
||||
object: ActivityPub::TagManager.instance.uri_for(status),
|
||||
}
|
||||
end
|
||||
|
||||
it 'creates a reblog by sender of status' do
|
||||
expect(sender.reblogged?(status)).to be true
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@@ -28,7 +28,7 @@ RSpec.describe ActivityPub::ProcessCollectionService do
|
||||
|
||||
it 'processes payload with sender if no signature exists' do
|
||||
expect_any_instance_of(ActivityPub::LinkedDataSignature).not_to receive(:verify_account!)
|
||||
expect(ActivityPub::Activity).to receive(:factory).with(instance_of(Hash), forwarder)
|
||||
expect(ActivityPub::Activity).to receive(:factory).with(instance_of(Hash), forwarder, instance_of(Hash))
|
||||
|
||||
subject.call(json, forwarder)
|
||||
end
|
||||
@@ -37,7 +37,7 @@ RSpec.describe ActivityPub::ProcessCollectionService do
|
||||
payload['signature'] = {'type' => 'RsaSignature2017'}
|
||||
|
||||
expect_any_instance_of(ActivityPub::LinkedDataSignature).to receive(:verify_account!).and_return(actor)
|
||||
expect(ActivityPub::Activity).to receive(:factory).with(instance_of(Hash), actor)
|
||||
expect(ActivityPub::Activity).to receive(:factory).with(instance_of(Hash), actor, instance_of(Hash))
|
||||
|
||||
subject.call(json, forwarder)
|
||||
end
|
||||
|
@@ -5,7 +5,7 @@ RSpec.describe BatchedRemoveStatusService do
|
||||
|
||||
let!(:alice) { Fabricate(:account) }
|
||||
let!(:bob) { Fabricate(:account, username: 'bob', domain: 'example.com', salmon_url: 'http://example.com/salmon') }
|
||||
let!(:jeff) { Fabricate(:account) }
|
||||
let!(:jeff) { Fabricate(:user).account }
|
||||
let!(:hank) { Fabricate(:account, username: 'hank', protocol: :activitypub, domain: 'example.com', inbox_url: 'http://example.com/inbox') }
|
||||
|
||||
let(:status1) { PostStatusService.new.call(alice, 'Hello @bob@example.com') }
|
||||
@@ -19,6 +19,7 @@ RSpec.describe BatchedRemoveStatusService do
|
||||
stub_request(:post, 'http://example.com/inbox').to_return(status: 200)
|
||||
|
||||
Fabricate(:subscription, account: alice, callback_url: 'http://example.com/push', confirmed: true, expires_at: 30.days.from_now)
|
||||
jeff.user.update(current_sign_in_at: Time.now)
|
||||
jeff.follow!(alice)
|
||||
hank.follow!(alice)
|
||||
|
||||
|
@@ -22,7 +22,7 @@ describe FetchRemoteResourceService do
|
||||
allow(FetchAtomService).to receive(:new).and_return service
|
||||
feed_url = 'http://feed-url'
|
||||
feed_content = '<feed>contents</feed>'
|
||||
allow(service).to receive(:call).with(url).and_return([feed_url, feed_content])
|
||||
allow(service).to receive(:call).with(url).and_return([feed_url, { prefetched_body: feed_content }])
|
||||
|
||||
account_service = double
|
||||
allow(FetchRemoteAccountService).to receive(:new).and_return(account_service)
|
||||
@@ -39,7 +39,7 @@ describe FetchRemoteResourceService do
|
||||
allow(FetchAtomService).to receive(:new).and_return service
|
||||
feed_url = 'http://feed-url'
|
||||
feed_content = '<entry>contents</entry>'
|
||||
allow(service).to receive(:call).with(url).and_return([feed_url, feed_content])
|
||||
allow(service).to receive(:call).with(url).and_return([feed_url, { prefetched_body: feed_content }])
|
||||
|
||||
account_service = double
|
||||
allow(FetchRemoteStatusService).to receive(:new).and_return(account_service)
|
||||
|
@@ -16,7 +16,7 @@ RSpec.describe PrecomputeFeedService do
|
||||
|
||||
subject.call(account)
|
||||
|
||||
expect(Redis.current.zscore(FeedManager.instance.key(:home, account.id), reblog.id)).to eq status.id
|
||||
expect(Redis.current.zscore(FeedManager.instance.key(:home, account.id), reblog.id)).to eq status.id.to_f
|
||||
end
|
||||
|
||||
it 'does not raise an error even if it could not find any status' do
|
||||
|
Reference in New Issue
Block a user