Merge upstream!! #64 <3 <3

This commit is contained in:
kibigo!
2017-07-12 02:03:17 -07:00
340 changed files with 4980 additions and 2321 deletions

View File

@@ -3,11 +3,64 @@ require 'rails_helper'
RSpec.describe Admin::AccountsController, type: :controller do
render_views
let(:user) { Fabricate(:user, admin: true) }
before do
sign_in Fabricate(:user, admin: true), scope: :user
sign_in user, scope: :user
end
describe 'GET #index' do
around do |example|
default_per_page = Account.default_per_page
Account.paginates_per 1
example.run
Account.paginates_per default_per_page
end
it 'filters with parameters' do
new = AccountFilter.method(:new)
expect(AccountFilter).to receive(:new) do |params|
h = params.to_h
expect(h[:local]).to eq '1'
expect(h[:remote]).to eq '1'
expect(h[:by_domain]).to eq 'domain'
expect(h[:silenced]).to eq '1'
expect(h[:recent]).to eq '1'
expect(h[:suspended]).to eq '1'
expect(h[:username]).to eq 'username'
expect(h[:display_name]).to eq 'display name'
expect(h[:email]).to eq 'local-part@domain'
expect(h[:ip]).to eq '0.0.0.42'
new.call({})
end
get :index, params: {
local: '1',
remote: '1',
by_domain: 'domain',
silenced: '1',
recent: '1',
suspended: '1',
username: 'username',
display_name: 'display name',
email: 'local-part@domain',
ip: '0.0.0.42'
}
end
it 'paginates accounts' do
Fabricate(:account)
get :index, params: { page: 2 }
accounts = assigns(:accounts)
expect(accounts.count).to eq 1
expect(accounts.klass).to be Account
end
it 'returns http success' do
get :index
expect(response).to have_http_status(:success)

View File

@@ -31,7 +31,7 @@ RSpec.describe Admin::SettingsController, type: :controller do
it 'cannot create a setting value for a non-admin key' do
expect(Setting.new_setting_key).to be_blank
patch :update, params: { new_setting_key: 'New key value' }
patch :update, params: { form_admin_settings: { new_setting_key: 'New key value' } }
expect(response).to redirect_to(edit_admin_settings_path)
expect(Setting.new_setting_key).to be_nil
@@ -40,7 +40,7 @@ RSpec.describe Admin::SettingsController, type: :controller do
it 'creates a settings value that didnt exist before for eligible key' do
expect(Setting.site_extended_description).to be_blank
patch :update, params: { site_extended_description: 'New key value' }
patch :update, params: { form_admin_settings: { site_extended_description: 'New key value' } }
expect(response).to redirect_to(edit_admin_settings_path)
expect(Setting.site_extended_description).to eq 'New key value'
@@ -56,7 +56,7 @@ RSpec.describe Admin::SettingsController, type: :controller do
it 'updates a settings value' do
Setting.site_title = 'Original'
patch :update, params: { site_title: 'New title' }
patch :update, params: { form_admin_settings: { site_title: 'New title' } }
expect(response).to redirect_to(edit_admin_settings_path)
expect(Setting.site_title).to eq 'New title'
@@ -72,7 +72,7 @@ RSpec.describe Admin::SettingsController, type: :controller do
it 'typecasts open_registrations to boolean' do
Setting.open_registrations = false
patch :update, params: { open_registrations: 'true' }
patch :update, params: { form_admin_settings: { open_registrations: '1' } }
expect(response).to redirect_to(edit_admin_settings_path)
expect(Setting.open_registrations).to eq true

View File

@@ -94,7 +94,7 @@ describe AuthorizeFollowsController do
end
it 'follows account when found' do
target_account = double(id: '123')
target_account = Fabricate(:account)
result_account = double(target_account: target_account)
service = double
allow(FollowService).to receive(:new).and_return(service)
@@ -103,7 +103,7 @@ describe AuthorizeFollowsController do
post :create, params: { acct: 'acct:user@hostname' }
expect(service).to have_received(:call).with(account, 'user@hostname')
expect(response).to redirect_to(web_url('accounts/123'))
expect(response).to render_template(:success)
end
end
end

View File

@@ -23,41 +23,14 @@ RSpec.describe HomeController, type: :controller do
expect(assigns(:body_classes)).to eq 'app-body'
end
it 'assigns @token' do
app = Doorkeeper::Application.create!(name: 'Web', superapp: true, redirect_uri: Doorkeeper.configuration.native_redirect_uri)
allow(Doorkeeper.configuration).to receive(:access_token_expires_in).and_return(42)
it 'assigns @initial_state_json' do
subject
token = Doorkeeper::AccessToken.find_by(token: assigns(:token))
expect(token.application).to eq app
expect(token.resource_owner_id).to eq user.id
expect(token.scopes).to eq Doorkeeper::OAuth::Scopes.from_string('read write follow')
expect(token.expires_in_seconds).to eq 42
expect(token.use_refresh_token?).to eq false
end
it 'assigns @web_settings for {} if not available' do
subject
expect(assigns(:web_settings)).to eq({})
end
it 'assigns @web_settings for Web::Setting if available' do
setting = Fabricate('Web::Setting', data: '{"home":{}}', user: user)
subject
expect(assigns(:web_settings)).to eq setting.data
end
it 'assigns @admin' do
admin = Fabricate(:account)
Setting.site_contact_username = admin.username
subject
expect(assigns(:admin)).to eq admin
end
it 'assigns streaming_api_base_url' do
subject
expect(assigns(:streaming_api_base_url)).to eq 'ws://localhost:4000'
initial_state_json = json_str_to_hash(assigns(:initial_state_json))
expect(initial_state_json[:meta]).to_not be_nil
expect(initial_state_json[:compose]).to_not be_nil
expect(initial_state_json[:accounts]).to_not be_nil
expect(initial_state_json[:settings]).to_not be_nil
expect(initial_state_json[:media_attachments]).to_not be_nil
end
end
end

View File

@@ -0,0 +1,19 @@
require 'rails_helper'
describe ManifestsController do
render_views
describe 'GET #show' do
before 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
end
end

20
spec/fixtures/requests/koi8-r.txt vendored Normal file
View File

@@ -0,0 +1,20 @@
HTTP/1.1 200 OK
Server: nginx/1.11.10
Date: Tue, 04 Jul 2017 16:43:39 GMT
Content-Type: text/html
Content-Length: 273
Connection: keep-alive
Last-Modified: Tue, 04 Jul 2017 16:41:34 GMT
Accept-Ranges: bytes
<HTML>
<HEAD>
<META NAME="GENERATOR" CONTENT="Adobe PageMill 3.0J Mac">
<META HTTP-EQUIV="Content-Type" CONTENT="text/html;CHARSET=koi8-r">
<TITLE><3E><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><> XVI <20><>. <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>.</TITLE>
</HEAD>
<BODY>
<P><CENTER><B><FONT SIZE="+2"><3E><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><> XVI <20><>. <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>.</FONT></B><BR>
<HR><BR>
</BODY>
</HTML>

20
spec/fixtures/requests/sjis.txt vendored Normal file
View File

@@ -0,0 +1,20 @@
HTTP/1.1 200 OK
Server: nginx/1.11.10
Date: Tue, 04 Jul 2017 16:43:39 GMT
Content-Type: text/html
Content-Length: 273
Connection: keep-alive
Last-Modified: Tue, 04 Jul 2017 16:41:34 GMT
Accept-Ranges: bytes
<HTML>
<HEAD>
<META NAME="GENERATOR" CONTENT="Adobe PageMill 3.0J Mac">
<META HTTP-EQUIV="Content-Type" CONTENT="text/html;CHARSET=x-sjis">
<TITLE>SJIS<49>̃y<CC83>[<5B>W</TITLE>
</HEAD>
<BODY>
<P><CENTER><B><FONT SIZE="+2"><3E><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>N<EFBFBD>܂<EFBFBD><DC82>Ă<EFBFBD><C482><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>L<EFBFBD>O<EFBFBD>l<EFBFBD><6C><EFBFBD>Ă<EFBFBD><C482>̂̎<CC82><CC8E>ł<EFBFBD><C582><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ł<EFBFBD><C582>B<EFBFBD><42><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ԂɈӖ<C988><D396>҂͐<D282><CD90><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ǂ<EFBFBD><C782>Ȕ<EFBFBD><C894><EFBFBD><EFBFBD>܂<EFBFBD><DC82><EFBFBD><EFBFBD>܂ł<DC82><C582>\<5C><><EFBFBD><EFBFBD><E382B0><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ɂ͎Q<CD8E>l<EFBFBD>A<EFBFBD><EFBFBD><E982BD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>A<EFBFBD><41><EFBFBD><EFBFBD><EFBFBD>ɂ<EFBFBD><C982><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>܂<EFBFBD><DC82>Ȃ<EFBFBD><C882>B<EFBFBD><42><EFBFBD><EFBFBD><EFBFBD><EFBFBD><E782A2><EFBFBD>Ȃ<EFBFBD><C882>̂͂ǂ<CD82><C782><EFBFBD><EFBFBD><EFBFBD><E38C8E><EFBFBD>ł<EFBFBD><C582><EFBFBD><E982BE><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>B<EFBFBD><42><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ĉ<EFBFBD><C489>c<EFBFBD><63><EFBFBD><EFBFBD><EFBFBD>ɔ<EFBFBD><C994>R<EFBFBD>K<EFBFBD><4B><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ɉ]<5D><><EFBFBD>ł<EFBFBD><C582><EFBFBD><EFBFBD><EFBFBD><EFBFBD>͂<EFBFBD><CD82><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>͂<EFBFBD><CD82>Ȃ<EFBFBD><C882><EFBFBD><EFBFBD>w<EFBFBD>}<7D><><EFBFBD>Ƃ<EFBFBD><C682><EFBFBD><EFBFBD><EFBFBD><EFBFBD>o<EFBFBD><6F><EFBFBD><EFBFBD><EFBFBD>Ȃ<EFBFBD><C882><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ȃ<EFBFBD><C882><EFBFBD><EFBFBD>āA<C481><41><EFBFBD>͎̐̂<CC82><CD8E><EFBFBD><EFBFBD><EFBFBD><EFBFBD>͉A<CD89><41><EFBFBD>{<7B><EFBFBD><E782A9><EFBFBD>A<EFBFBD>v<EFBFBD><76><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>̂<EFBFBD><CC82>̂<EFBFBD><CC82><EFBFBD><EFBFBD><EFBFBD><EFBFBD>̂<EFBFBD><CC82>‚<EFBFBD><C282><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ɂ<EFBFBD><C982><EFBFBD><EFBFBD>]<5D>ƌ<EFBFBD><C68C><EFBFBD><EFBFBD>΂<EFBFBD><CE82><EFBFBD>man<61>ɂ<EFBFBD><C982><EFBFBD><EFBFBD><EFBFBD><EFBFBD>֎Q<D68E><51><EFBFBD><EFBFBD>ɓ<EFBFBD><C993><EFBFBD><EFBFBD>ɂ<EFBFBD><C982><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>łȂ<C582><C882>̂ŁA<C581><41><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>\<5C><><EFBFBD>ɕς<C995><CF82><EFBFBD><EFBFBD>Ă<EFBFBD><C482><EFBFBD><EFBFBD>ł<EFBFBD><C582><EFBFBD><EFBFBD>ōl<C58D><6C><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>B<EFBFBD><42><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>΂<EFBFBD><CE82><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ƃǂ܂<C782><DC82><EFBFBD><EFBFBD>̂<EFBFBD><CC82><EFBFBD><EFBFBD>ۂނ<DB82><DE82>݂Ƃ<DD82><C682><EFBFBD><EFBFBD>ł<EFBFBD><C582>āA<C481><41><EFBFBD>̎<EFBFBD><CC8E><EFBFBD><EFBFBD>ł͐\<5C><><EFBFBD><EFBFBD><EFBFBD>ĂƂ<C482><C682>Đ<EFBFBD><C490>Ԃɕ<D482><C995>ׂ̂ɍs<C98D><73><EFBFBD>Ȃ<EFBFBD><C882><EFBFBD><EFBFBD>ȁB</FONT></B><BR>
<HR><BR>
</BODY>
</HTML>

View File

@@ -0,0 +1,20 @@
HTTP/1.1 200 OK
Server: nginx/1.11.10
Date: Tue, 04 Jul 2017 16:43:39 GMT
Content-Type: text/html; charset=utf-8
Content-Length: 273
Connection: keep-alive
Last-Modified: Tue, 04 Jul 2017 16:41:34 GMT
Accept-Ranges: bytes
<HTML>
<HEAD>
<META NAME="GENERATOR" CONTENT="Adobe PageMill 3.0J Mac">
<META HTTP-EQUIV="Content-Type" CONTENT="text/html;CHARSET=x-sjis">
<TITLE>SJIS<49>̃y<CC83>[<5B>W</TITLE>
</HEAD>
<BODY>
<P><CENTER><B><FONT SIZE="+2"><3E><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>N<EFBFBD>܂<EFBFBD><DC82>Ă<EFBFBD><C482><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>L<EFBFBD>O<EFBFBD>l<EFBFBD><6C><EFBFBD>Ă<EFBFBD><C482>̂̎<CC82><CC8E>ł<EFBFBD><C582><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ł<EFBFBD><C582>B<EFBFBD><42><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ԂɈӖ<C988><D396>҂͐<D282><CD90><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ǂ<EFBFBD><C782>Ȕ<EFBFBD><C894><EFBFBD><EFBFBD>܂<EFBFBD><DC82><EFBFBD><EFBFBD>܂ł<DC82><C582>\<5C><><EFBFBD><EFBFBD><E382B0><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ɂ͎Q<CD8E>l<EFBFBD>A<EFBFBD><EFBFBD><E982BD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>A<EFBFBD><41><EFBFBD><EFBFBD><EFBFBD>ɂ<EFBFBD><C982><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>܂<EFBFBD><DC82>Ȃ<EFBFBD><C882>B<EFBFBD><42><EFBFBD><EFBFBD><EFBFBD><EFBFBD><E782A2><EFBFBD>Ȃ<EFBFBD><C882>̂͂ǂ<CD82><C782><EFBFBD><EFBFBD><EFBFBD><E38C8E><EFBFBD>ł<EFBFBD><C582><EFBFBD><E982BE><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>B<EFBFBD><42><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ĉ<EFBFBD><C489>c<EFBFBD><63><EFBFBD><EFBFBD><EFBFBD>ɔ<EFBFBD><C994>R<EFBFBD>K<EFBFBD><4B><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ɉ]<5D><><EFBFBD>ł<EFBFBD><C582><EFBFBD><EFBFBD><EFBFBD><EFBFBD>͂<EFBFBD><CD82><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>͂<EFBFBD><CD82>Ȃ<EFBFBD><C882><EFBFBD><EFBFBD>w<EFBFBD>}<7D><><EFBFBD>Ƃ<EFBFBD><C682><EFBFBD><EFBFBD><EFBFBD><EFBFBD>o<EFBFBD><6F><EFBFBD><EFBFBD><EFBFBD>Ȃ<EFBFBD><C882><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ȃ<EFBFBD><C882><EFBFBD><EFBFBD>āA<C481><41><EFBFBD>͎̐̂<CC82><CD8E><EFBFBD><EFBFBD><EFBFBD><EFBFBD>͉A<CD89><41><EFBFBD>{<7B><EFBFBD><E782A9><EFBFBD>A<EFBFBD>v<EFBFBD><76><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>̂<EFBFBD><CC82>̂<EFBFBD><CC82><EFBFBD><EFBFBD><EFBFBD><EFBFBD>̂<EFBFBD><CC82>‚<EFBFBD><C282><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ɂ<EFBFBD><C982><EFBFBD><EFBFBD>]<5D>ƌ<EFBFBD><C68C><EFBFBD><EFBFBD>΂<EFBFBD><CE82><EFBFBD>man<61>ɂ<EFBFBD><C982><EFBFBD><EFBFBD><EFBFBD><EFBFBD>֎Q<D68E><51><EFBFBD><EFBFBD>ɓ<EFBFBD><C993><EFBFBD><EFBFBD>ɂ<EFBFBD><C982><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>łȂ<C582><C882>̂ŁA<C581><41><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>\<5C><><EFBFBD>ɕς<C995><CF82><EFBFBD><EFBFBD>Ă<EFBFBD><C482><EFBFBD><EFBFBD>ł<EFBFBD><C582><EFBFBD><EFBFBD>ōl<C58D><6C><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>B<EFBFBD><42><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>΂<EFBFBD><CE82><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ƃǂ܂<C782><DC82><EFBFBD><EFBFBD>̂<EFBFBD><CC82><EFBFBD><EFBFBD>ۂނ<DB82><DE82>݂Ƃ<DD82><C682><EFBFBD><EFBFBD>ł<EFBFBD><C582>āA<C481><41><EFBFBD>̎<EFBFBD><CC8E><EFBFBD><EFBFBD>ł͐\<5C><><EFBFBD><EFBFBD><EFBFBD>ĂƂ<C482><C682>Đ<EFBFBD><C490>Ԃɕ<D482><C995>ׂ̂ɍs<C98D><73><EFBFBD>Ȃ<EFBFBD><C882><EFBFBD><EFBFBD>ȁB</FONT></B><BR>
<HR><BR>
</BODY>
</HTML>

View File

@@ -1,12 +1,12 @@
import { expect } from 'chai';
import { render } from 'enzyme';
import Immutable from 'immutable';
import { fromJS } from 'immutable';
import React from 'react';
import DisplayName from '../../../app/javascript/mastodon/components/display_name';
describe('<DisplayName />', () => {
it('renders display name + account name', () => {
const account = Immutable.fromJS({
const account = fromJS({
username: 'bar',
acct: 'bar@baz',
display_name: 'Foo',
@@ -16,7 +16,7 @@ describe('<DisplayName />', () => {
});
it('renders the username + account name if display name is empty', () => {
const account = Immutable.fromJS({
const account = fromJS({
username: 'bar',
acct: 'bar@baz',
display_name: '',

View File

@@ -0,0 +1,83 @@
import { expect } from 'chai';
import emojify from '../../../app/javascript/mastodon/emoji';
describe('emojify', () => {
it('does a basic emojify', () => {
expect(emojify(':smile:')).to.equal(
'<img draggable="false" class="emojione" alt="😄" title=":smile:" src="/emoji/1f604.svg" />');
});
it('does a double emojify', () => {
expect(emojify(':smile: and :wink:')).to.equal(
'<img draggable="false" class="emojione" alt="😄" title=":smile:" src="/emoji/1f604.svg" /> and <img draggable="false" class="emojione" alt="😉" title=":wink:" src="/emoji/1f609.svg" />');
});
it('works with random colons', () => {
expect(emojify(':smile: : :wink:')).to.equal(
'<img draggable="false" class="emojione" alt="😄" title=":smile:" src="/emoji/1f604.svg" /> : <img draggable="false" class="emojione" alt="😉" title=":wink:" src="/emoji/1f609.svg" />');
expect(emojify(':smile::::wink:')).to.equal(
'<img draggable="false" class="emojione" alt="😄" title=":smile:" src="/emoji/1f604.svg" />::<img draggable="false" class="emojione" alt="😉" title=":wink:" src="/emoji/1f609.svg" />');
expect(emojify(':smile:::::wink:')).to.equal(
'<img draggable="false" class="emojione" alt="😄" title=":smile:" src="/emoji/1f604.svg" />:::<img draggable="false" class="emojione" alt="😉" title=":wink:" src="/emoji/1f609.svg" />');
});
it('works with tags', () => {
expect(emojify('<p>:smile:</p>')).to.equal(
'<p><img draggable="false" class="emojione" alt="😄" title=":smile:" src="/emoji/1f604.svg" /></p>');
expect(emojify('<p>:smile:</p> and <p>:wink:</p>')).to.equal(
'<p><img draggable="false" class="emojione" alt="😄" title=":smile:" src="/emoji/1f604.svg" /></p> and <p><img draggable="false" class="emojione" alt="😉" title=":wink:" src="/emoji/1f609.svg" /></p>');
});
it('ignores unknown shortcodes', () => {
expect(emojify(':foobarbazfake:')).to.equal(':foobarbazfake:');
});
it('ignores shortcodes inside of tags', () => {
expect(emojify('<p data-foo=":smile:"></p>')).to.equal('<p data-foo=":smile:"></p>');
});
it('works with unclosed tags', () => {
expect(emojify('hello>')).to.equal('hello>');
expect(emojify('<hello')).to.equal('<hello');
});
it('works with unclosed shortcodes', () => {
expect(emojify('smile:')).to.equal('smile:');
expect(emojify(':smile')).to.equal(':smile');
});
it('does two emoji next to each other', () => {
expect(emojify(':smile::wink:')).to.equal(
'<img draggable="false" class="emojione" alt="😄" title=":smile:" src="/emoji/1f604.svg" /><img draggable="false" class="emojione" alt="😉" title=":wink:" src="/emoji/1f609.svg" />');
});
it('does unicode', () => {
expect(emojify('\uD83D\uDC69\u200D\uD83D\uDC69\u200D\uD83D\uDC66\u200D\uD83D\uDC66')).to.equal(
'<img draggable="false" class="emojione" alt="👩‍👩‍👦‍👦" title=":family_wwbb:" src="/emoji/1f469-1f469-1f466-1f466.svg" />');
expect(emojify('\uD83D\uDC68\uD83D\uDC69\uD83D\uDC67\uD83D\uDC67')).to.equal(
'<img draggable="false" class="emojione" alt="👨👩👧👧" title=":family_mwgg:" src="/emoji/1f468-1f469-1f467-1f467.svg" />');
expect(emojify('\uD83D\uDC69\uD83D\uDC69\uD83D\uDC66')).to.equal('<img draggable="false" class="emojione" alt="👩👩👦" title=":family_wwb:" src="/emoji/1f469-1f469-1f466.svg" />');
expect(emojify('\u2757')).to.equal(
'<img draggable="false" class="emojione" alt="❗" title=":exclamation:" src="/emoji/2757.svg" />');
});
it('does multiple unicode', () => {
expect(emojify('\u2757 #\uFE0F\u20E3')).to.equal(
'<img draggable="false" class="emojione" alt="❗" title=":exclamation:" src="/emoji/2757.svg" /> <img draggable="false" class="emojione" alt="#️⃣" title=":hash:" src="/emoji/0023-20e3.svg" />');
expect(emojify('\u2757#\uFE0F\u20E3')).to.equal(
'<img draggable="false" class="emojione" alt="❗" title=":exclamation:" src="/emoji/2757.svg" /><img draggable="false" class="emojione" alt="#️⃣" title=":hash:" src="/emoji/0023-20e3.svg" />');
expect(emojify('\u2757 #\uFE0F\u20E3 \u2757')).to.equal(
'<img draggable="false" class="emojione" alt="❗" title=":exclamation:" src="/emoji/2757.svg" /> <img draggable="false" class="emojione" alt="#️⃣" title=":hash:" src="/emoji/0023-20e3.svg" /> <img draggable="false" class="emojione" alt="❗" title=":exclamation:" src="/emoji/2757.svg" />');
expect(emojify('foo \u2757 #\uFE0F\u20E3 bar')).to.equal(
'foo <img draggable="false" class="emojione" alt="❗" title=":exclamation:" src="/emoji/2757.svg" /> <img draggable="false" class="emojione" alt="#️⃣" title=":hash:" src="/emoji/0023-20e3.svg" /> bar');
});
it('does mixed unicode and shortnames', () => {
expect(emojify(':smile:#\uFE0F\u20E3:wink:\u2757')).to.equal('<img draggable="false" class="emojione" alt="😄" title=":smile:" src="/emoji/1f604.svg" /><img draggable="false" class="emojione" alt="#️⃣" title=":hash:" src="/emoji/0023-20e3.svg" /><img draggable="false" class="emojione" alt="😉" title=":wink:" src="/emoji/1f609.svg" /><img draggable="false" class="emojione" alt="❗" title=":exclamation:" src="/emoji/2757.svg" />');
});
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>');
});
});

View File

@@ -1,19 +1,13 @@
import { jsdom } from 'jsdom/lib/old-api';
import { JSDOM } from 'jsdom';
import chai from 'chai';
import chaiEnzyme from 'chai-enzyme';
chai.use(chaiEnzyme());
var exposedProperties = ['window', 'navigator', 'document'];
global.document = jsdom('');
global.window = document.defaultView;
Object.keys(document.defaultView).forEach((property) => {
const { window } = new JSDOM('', {
userAgent: 'node.js',
});
Object.keys(window).forEach(property => {
if (typeof global[property] === 'undefined') {
exposedProperties.push(property);
global[property] = document.defaultView[property];
global[property] = window[property];
}
});
global.navigator = {
userAgent: 'node.js',
};

View File

@@ -131,4 +131,17 @@ RSpec.describe FeedManager do
end
end
end
describe '#push' do
it 'trims timelines if they will have more than FeedManager::MAX_ITEMS' do
account = Fabricate(:account)
status = Fabricate(:status)
members = FeedManager::MAX_ITEMS.times.map { |count| [count, count] }
Redis.current.zadd("feed:type:#{account.id}", members)
FeedManager.instance.push('type', account, status)
expect(Redis.current.zcard("feed:type:#{account.id}")).to eq FeedManager::MAX_ITEMS
end
end
end

View File

@@ -1,23 +0,0 @@
# frozen_string_literal: true
require 'rails_helper'
describe InlineRablScope do
describe '#current_account' do
it 'returns the given account' do
account = Fabricate(:account)
expect(InlineRablScope.new(account).current_account).to eq account
end
end
describe '#current_user' do
it 'returns nil if the given account is nil' do
expect(InlineRablScope.new(nil).current_user).to eq nil
end
it 'returns user of account if the given account is not nil' do
user = Fabricate(:user)
expect(InlineRablScope.new(user.account).current_user).to eq user
end
end
end

View File

@@ -28,6 +28,13 @@ describe UserSettingsDecorator do
expect(user.settings['default_privacy']).to eq 'public'
end
it 'updates the user settings value for sensitive' do
values = { 'setting_default_sensitive' => '1' }
settings.update(values)
expect(user.settings['default_sensitive']).to eq true
end
it 'updates the user settings value for boost modal' do
values = { 'setting_boost_modal' => '1' }
@@ -48,5 +55,12 @@ describe UserSettingsDecorator do
settings.update(values)
expect(user.settings['auto_play_gif']).to eq false
end
it 'updates the user settings value for system font in UI' do
values = { 'setting_system_font_ui' => '0' }
settings.update(values)
expect(user.settings['system_font_ui']).to eq false
end
end
end

View File

@@ -2,19 +2,19 @@ require 'rails_helper'
RSpec.describe Feed, type: :model do
describe '#get' do
it 'gets statuses with ids in the range, maintining the order from Redis' do
it 'gets statuses with ids in the range' do
account = Fabricate(:account)
Fabricate(:status, account: account, id: 1)
Fabricate(:status, account: account, id: 2)
Fabricate(:status, account: account, id: 3)
Fabricate(:status, account: account, id: 10)
redis = double(zrevrangebyscore: [['val2', 2.0], ['val1', 1.0], ['val3', 3.0], ['deleted', 4.0]], exists: false)
allow(Redis).to receive(:current).and_return(redis)
Redis.current.zadd(FeedManager.instance.key(:home, account.id),
[[4, 'deleted'], [3, 'val3'], [2, 'val2'], [1, 'val1']])
feed = Feed.new(:home, account)
results = feed.get(3)
expect(results.map(&:id)).to eq [2, 1, 3]
expect(results.map(&:id)).to eq [3, 2]
expect(results.first.attributes.keys).to eq %w(id updated_at)
end
end

View File

@@ -184,6 +184,14 @@ RSpec.describe User, type: :model do
expect(user.setting_auto_play_gif).to eq false
end
end
describe '#setting_system_font_ui' do
it 'returns system font ui setting' do
user = Fabricate(:user)
user.settings[:system_font_ui] = false
expect(user.setting_system_font_ui).to eq false
end
end
describe '#setting_boost_modal' do
it 'returns boost modal setting' do

View File

@@ -13,17 +13,23 @@ Dir[Rails.root.join('spec/support/**/*.rb')].each { |f| require f }
ActiveRecord::Migration.maintain_test_schema!
WebMock.disable_net_connect!
Redis.current = Redis::Namespace.new("mastodon_test#{ENV['TEST_ENV_NUMBER']}", redis: Redis.current)
Sidekiq::Testing.inline!
Sidekiq::Logging.logger = nil
Devise::Test::ControllerHelpers.module_eval do
alias_method :original_sign_in, :sign_in
def sign_in(resource, deprecated = nil, scope: nil)
def sign_in(resource, _deprecated = nil, scope: nil)
original_sign_in(resource, scope: scope)
SessionActivation.deactivate warden.raw_session["auth_id"]
warden.raw_session["auth_id"] = resource.activate_session(warden.request)
SessionActivation.deactivate warden.cookies.signed['_session_id']
warden.cookies.signed['_session_id'] = {
value: resource.activate_session(warden.request),
expires: 1.year.from_now,
httponly: true,
}
end
end
@@ -43,6 +49,11 @@ RSpec.configure do |config|
https = ENV['LOCAL_HTTPS'] == 'true'
Capybara.app_host = "http#{https ? 's' : ''}://#{ENV.fetch('LOCAL_DOMAIN')}"
end
config.after :each do
keys = Redis.current.keys
Redis.current.del(keys) if keys.any?
end
end
RSpec::Sidekiq.configure do |config|

View File

@@ -6,13 +6,13 @@ describe 'Localization' do
after(:all) do
I18n.locale = I18n.default_locale
end
it 'uses a specific region when provided' do
headers = { 'Accept-Language' => 'zh-HK' }
get "/about", headers: headers
expect(response.body).to include(
I18n.t('about.about_mastodon', locale: 'zh-HK')
I18n.t('about.about_mastodon_html', locale: 'zh-HK')
)
end
@@ -21,7 +21,7 @@ describe 'Localization' do
get "/about", headers: headers
expect(response.body).to include(
I18n.t('about.about_mastodon', locale: 'es')
I18n.t('about.about_mastodon_html', locale: 'es')
)
end
it 'falls back to english when locale is missing' do
@@ -29,7 +29,7 @@ describe 'Localization' do
get "/about", headers: headers
expect(response.body).to include(
I18n.t('about.about_mastodon', locale: 'en')
I18n.t('about.about_mastodon_html', locale: 'en')
)
end
end

View File

@@ -6,6 +6,12 @@ RSpec.describe FetchLinkCardService do
before do
stub_request(:head, 'http://example.xn--fiqs8s/').to_return(status: 200, headers: { 'Content-Type' => 'text/html' })
stub_request(:get, 'http://example.xn--fiqs8s/').to_return(request_fixture('idn.txt'))
stub_request(:head, 'http://example.com/sjis').to_return(status: 200, headers: { 'Content-Type' => 'text/html' })
stub_request(:get, 'http://example.com/sjis').to_return(request_fixture('sjis.txt'))
stub_request(:head, 'http://example.com/sjis_with_wrong_charset').to_return(status: 200, headers: { 'Content-Type' => 'text/html' })
stub_request(:get, 'http://example.com/sjis_with_wrong_charset').to_return(request_fixture('sjis_with_wrong_charset.txt'))
stub_request(:head, 'http://example.com/koi8-r').to_return(status: 200, headers: { 'Content-Type' => 'text/html' })
stub_request(:get, 'http://example.com/koi8-r').to_return(request_fixture('koi8-r.txt'))
stub_request(:head, 'https://github.com/qbi/WannaCry').to_return(status: 404)
subject.call(status)
@@ -19,6 +25,33 @@ RSpec.describe FetchLinkCardService do
expect(a_request(:get, 'http://example.xn--fiqs8s/')).to have_been_made.at_least_once
end
end
context do
let(:status) { Fabricate(:status, text: 'Check out http://example.com/sjis') }
it 'works with SJIS' do
expect(a_request(:get, 'http://example.com/sjis')).to have_been_made.at_least_once
expect(status.preview_card.title).to eq("SJISのページ")
end
end
context do
let(:status) { Fabricate(:status, text: 'Check out http://example.com/sjis_with_wrong_charset') }
it 'works with SJIS even with wrong charset header' do
expect(a_request(:get, 'http://example.com/sjis_with_wrong_charset')).to have_been_made.at_least_once
expect(status.preview_card.title).to eq("SJISのページ")
end
end
context do
let(:status) { Fabricate(:status, text: 'Check out http://example.com/koi8-r') }
it 'works with koi8-r' do
expect(a_request(:get, 'http://example.com/koi8-r')).to have_been_made.at_least_once
expect(status.preview_card.title).to eq("Московя начинаетъ только въ XVI ст. привлекать внимане иностранцевъ.")
end
end
end
context 'in a remote status' do

View File

@@ -11,12 +11,29 @@ RSpec.describe PrecomputeFeedService do
account = Fabricate(:account)
followed_account = Fabricate(:account)
Fabricate(:follow, account: account, target_account: followed_account)
status = Fabricate(:status, account: followed_account)
expected_redis_args = FeedManager.instance.key(:home, account.id), status.id, status.id
expect_any_instance_of(Redis).to receive(:zadd).with(*expected_redis_args)
reblog = Fabricate(:status, account: followed_account)
status = Fabricate(:status, account: account, reblog: reblog)
subject.call(account)
expect(Redis.current.zscore(FeedManager.instance.key(:home, account.id), reblog.id)).to eq status.id
end
it 'does not raise an error even if it could not find any status' do
account = Fabricate(:account)
subject.call(account)
end
it 'filters statuses' do
account = Fabricate(:account)
muted_account = Fabricate(:account)
Fabricate(:mute, account: account, target_account: muted_account)
reblog = Fabricate(:status, account: muted_account)
status = Fabricate(:status, account: account, reblog: reblog)
subject.call(account)
expect(Redis.current.zscore(FeedManager.instance.key(:home, account.id), reblog.id)).to eq nil
end
end
end

View File

@@ -10,10 +10,11 @@ describe 'about/show.html.haml', without_verify_partial_doubles: true do
it 'has valid open graph tags' do
instance_presenter = double(:instance_presenter,
site_description: 'something',
open_registrations: false,
closed_registrations_message: 'yes',
)
site_title: 'something',
site_description: 'something',
version_number: '1.0',
open_registrations: false,
closed_registrations_message: 'yes')
assign(:instance_presenter, instance_presenter)
render

View File

@@ -7,10 +7,13 @@ describe Scheduler::FeedCleanupScheduler do
let!(:inactive_user) { Fabricate(:user, current_sign_in_at: 22.days.ago) }
it 'clears feeds of inactives' do
expect_any_instance_of(Redis).to receive(:del).with(feed_key_for(inactive_user))
expect_any_instance_of(Redis).not_to receive(:del).with(feed_key_for(active_user))
Redis.current.zadd(feed_key_for(inactive_user), 1, 1)
Redis.current.zadd(feed_key_for(active_user), 1, 1)
subject.perform
expect(Redis.current.zcard(feed_key_for(inactive_user))).to eq 0
expect(Redis.current.zcard(feed_key_for(active_user))).to eq 1
end
def feed_key_for(user)