about summary refs log tree commit diff
path: root/spec
diff options
context:
space:
mode:
Diffstat (limited to 'spec')
-rw-r--r--spec/controllers/admin/accounts_controller_spec.rb55
-rw-r--r--spec/controllers/admin/settings_controller_spec.rb8
-rw-r--r--spec/controllers/authorize_follows_controller_spec.rb4
-rw-r--r--spec/controllers/home_controller_spec.rb41
-rw-r--r--spec/controllers/manifests_controller_spec.rb19
-rw-r--r--spec/fixtures/requests/koi8-r.txt20
-rw-r--r--spec/fixtures/requests/sjis.txt20
-rw-r--r--spec/fixtures/requests/sjis_with_wrong_charset.txt20
-rw-r--r--spec/javascript/components/display_name.test.js6
-rw-r--r--spec/javascript/components/emojify.test.js83
-rw-r--r--spec/javascript/setup.js18
-rw-r--r--spec/lib/feed_manager_spec.rb13
-rw-r--r--spec/lib/inline_rabl_scope_spec.rb23
-rw-r--r--spec/lib/user_settings_decorator_spec.rb14
-rw-r--r--spec/models/feed_spec.rb8
-rw-r--r--spec/models/user_spec.rb8
-rw-r--r--spec/rails_helper.rb17
-rw-r--r--spec/requests/localization_spec.rb8
-rw-r--r--spec/services/fetch_link_card_service_spec.rb33
-rw-r--r--spec/services/precompute_feed_service_spec.rb23
-rw-r--r--spec/views/about/show.html.haml_spec.rb9
-rw-r--r--spec/workers/scheduler/feed_cleanup_scheduler_spec.rb7
22 files changed, 358 insertions, 99 deletions
diff --git a/spec/controllers/admin/accounts_controller_spec.rb b/spec/controllers/admin/accounts_controller_spec.rb
index 305260475..8be27d866 100644
--- a/spec/controllers/admin/accounts_controller_spec.rb
+++ b/spec/controllers/admin/accounts_controller_spec.rb
@@ -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)
diff --git a/spec/controllers/admin/settings_controller_spec.rb b/spec/controllers/admin/settings_controller_spec.rb
index d9dde3c92..609bc762b 100644
--- a/spec/controllers/admin/settings_controller_spec.rb
+++ b/spec/controllers/admin/settings_controller_spec.rb
@@ -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
diff --git a/spec/controllers/authorize_follows_controller_spec.rb b/spec/controllers/authorize_follows_controller_spec.rb
index b801aa661..26e46a23c 100644
--- a/spec/controllers/authorize_follows_controller_spec.rb
+++ b/spec/controllers/authorize_follows_controller_spec.rb
@@ -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
diff --git a/spec/controllers/home_controller_spec.rb b/spec/controllers/home_controller_spec.rb
index cc1dbe5a1..d44d720b1 100644
--- a/spec/controllers/home_controller_spec.rb
+++ b/spec/controllers/home_controller_spec.rb
@@ -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)
-
-        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
+      it 'assigns @initial_state_json' 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
diff --git a/spec/controllers/manifests_controller_spec.rb b/spec/controllers/manifests_controller_spec.rb
new file mode 100644
index 000000000..6f188fa35
--- /dev/null
+++ b/spec/controllers/manifests_controller_spec.rb
@@ -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
diff --git a/spec/fixtures/requests/koi8-r.txt b/spec/fixtures/requests/koi8-r.txt
new file mode 100644
index 000000000..d4242af01
--- /dev/null
+++ b/spec/fixtures/requests/koi8-r.txt
@@ -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>íÏÓËÏ×Ñ ÎÁÞÉÎÁÅÔß ÔÏÌØËÏ ×ß XVI ÓÔ. ÐÒÉ×ÌÅËÁÔØ ×ÎÉÍÁÎÅ ÉÎÏÓÔÒÁÎÃÅ×ß.</TITLE>
+</HEAD>
+<BODY>
+<P><CENTER><B><FONT SIZE="+2">íÏÓËÏ×Ñ ÎÁÞÉÎÁÅÔß ÔÏÌØËÏ ×ß XVI ÓÔ. ÐÒÉ×ÌÅËÁÔØ ×ÎÉÍÁÎÅ ÉÎÏÓÔÒÁÎÃÅ×ß.</FONT></B><BR>
+<HR><BR>
+</BODY>
+</HTML>
diff --git a/spec/fixtures/requests/sjis.txt b/spec/fixtures/requests/sjis.txt
new file mode 100644
index 000000000..faf18d35c
--- /dev/null
+++ b/spec/fixtures/requests/sjis.txt
@@ -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‚̃y[ƒW</TITLE>
+</HEAD>
+<BODY>
+<P><CENTER><B><FONT SIZE="+2">Ž„‚à“¯”N‚Ü‚µ‚Ä‚¢‚í‚ä‚é‹L”Ol‚Á‚Ä‚à‚Ì‚ÌŽž‚Å‚µ‚ ‚è‚Å‚·B‚à‚µŽžŠÔ‚ɈӖ¡ŽÒ‚ͳ‚µ‚­‚Ç‚ñ‚È”­‰ï‚Ü‚¹‚¾‚Ü‚Å‚ª\‚µã‚°‚ª‚¢‚ç‚Á‚µ‚á‚邽‚É‚ÍŽQl‹A‚邽‚¢‚¾‚©‚çA­‚µ‚É‚à‚â‚Á‚ ‚Á‚Ü‚µ‚È‚½B‹à‚©‚ç‚¢‚¤‚È‚¢‚Ì‚Í‚Ç‚¤‚à‹ãŒŽ‚ð‚Å‚«‚邾‚¯‚½‚½‚­‚½B‚¯‚Á‚µ‚ĉª“c‚³‚ñ‚É”½RK­‚µ’¥‚ɉ]‚¨‚Å‚µ‚å‹à—Í‚±‚¤‚µ‚½Œ —Í‚ ‚È‚½‚©Žw}‚ª‚Æ‚¢‚¤‚¨o“ü‚è‚È‚­‚¾‚ë‚È‚ ‚è‚ÄA‚»‚ÌÌ‚ÍŽ„‚©‹à—͉A‚ð“{‚ç‚©‚çA‹vŒ´‚³‚ñ‚Ì‚à‚Ì‚ð‚ª‚½‚Ì‚¢‚‚ª‚µ‚©‚é‚É‚²Šó–]‚ÆŒü‚¢‚΂»‚êman‚É‚²–µ‚‚ÖŽQ‚è‚悤‚É“¯Žž‚É‚²‰‰à‚ª‚µ‚Å‚È‚ç‚Ì‚ÅA‘½•ª‚à‚µ•\— ‚É•Ï‚Á‚½‚Ä‚­‚ê‚Å‚·Ž–‚Ål‚¦‚½‚½B‚µ‚©‚à—Ⴆ‚΂²‚ª‚½‚ª‚Æ‚Ç‚Ü‚ç‚à‚Ì‚àŽÀÛ‚Þ‚â‚Ý‚Æ‚ ‚è‚Å‚·‚ÄA‚±‚ÌŽ©•ª‚Å‚Í\‚µ‚ñ‚Ä‚Æ‚µ‚Ä¢ŠÔ‚É•À‚ׂ̂És‚©‚È‚©‚Á‚ÈB</FONT></B><BR>
+<HR><BR>
+</BODY>
+</HTML>
diff --git a/spec/fixtures/requests/sjis_with_wrong_charset.txt b/spec/fixtures/requests/sjis_with_wrong_charset.txt
new file mode 100644
index 000000000..456750c6b
--- /dev/null
+++ b/spec/fixtures/requests/sjis_with_wrong_charset.txt
@@ -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‚̃y[ƒW</TITLE>
+</HEAD>
+<BODY>
+<P><CENTER><B><FONT SIZE="+2">Ž„‚à“¯”N‚Ü‚µ‚Ä‚¢‚í‚ä‚é‹L”Ol‚Á‚Ä‚à‚Ì‚ÌŽž‚Å‚µ‚ ‚è‚Å‚·B‚à‚µŽžŠÔ‚ɈӖ¡ŽÒ‚ͳ‚µ‚­‚Ç‚ñ‚È”­‰ï‚Ü‚¹‚¾‚Ü‚Å‚ª\‚µã‚°‚ª‚¢‚ç‚Á‚µ‚á‚邽‚É‚ÍŽQl‹A‚邽‚¢‚¾‚©‚çA­‚µ‚É‚à‚â‚Á‚ ‚Á‚Ü‚µ‚È‚½B‹à‚©‚ç‚¢‚¤‚È‚¢‚Ì‚Í‚Ç‚¤‚à‹ãŒŽ‚ð‚Å‚«‚邾‚¯‚½‚½‚­‚½B‚¯‚Á‚µ‚ĉª“c‚³‚ñ‚É”½RK­‚µ’¥‚ɉ]‚¨‚Å‚µ‚å‹à—Í‚±‚¤‚µ‚½Œ —Í‚ ‚È‚½‚©Žw}‚ª‚Æ‚¢‚¤‚¨o“ü‚è‚È‚­‚¾‚ë‚È‚ ‚è‚ÄA‚»‚ÌÌ‚ÍŽ„‚©‹à—͉A‚ð“{‚ç‚©‚çA‹vŒ´‚³‚ñ‚Ì‚à‚Ì‚ð‚ª‚½‚Ì‚¢‚‚ª‚µ‚©‚é‚É‚²Šó–]‚ÆŒü‚¢‚΂»‚êman‚É‚²–µ‚‚ÖŽQ‚è‚悤‚É“¯Žž‚É‚²‰‰à‚ª‚µ‚Å‚È‚ç‚Ì‚ÅA‘½•ª‚à‚µ•\— ‚É•Ï‚Á‚½‚Ä‚­‚ê‚Å‚·Ž–‚Ål‚¦‚½‚½B‚µ‚©‚à—Ⴆ‚΂²‚ª‚½‚ª‚Æ‚Ç‚Ü‚ç‚à‚Ì‚àŽÀÛ‚Þ‚â‚Ý‚Æ‚ ‚è‚Å‚·‚ÄA‚±‚ÌŽ©•ª‚Å‚Í\‚µ‚ñ‚Ä‚Æ‚µ‚Ä¢ŠÔ‚É•À‚ׂ̂És‚©‚È‚©‚Á‚ÈB</FONT></B><BR>
+<HR><BR>
+</BODY>
+</HTML>
diff --git a/spec/javascript/components/display_name.test.js b/spec/javascript/components/display_name.test.js
index d6dc7edc0..ad9288d4d 100644
--- a/spec/javascript/components/display_name.test.js
+++ b/spec/javascript/components/display_name.test.js
@@ -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: '',
diff --git a/spec/javascript/components/emojify.test.js b/spec/javascript/components/emojify.test.js
new file mode 100644
index 000000000..3e8b25af9
--- /dev/null
+++ b/spec/javascript/components/emojify.test.js
@@ -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>');
+  });
+
+});
diff --git a/spec/javascript/setup.js b/spec/javascript/setup.js
index 7d4b2866e..c9c8aed07 100644
--- a/spec/javascript/setup.js
+++ b/spec/javascript/setup.js
@@ -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',
-};
diff --git a/spec/lib/feed_manager_spec.rb b/spec/lib/feed_manager_spec.rb
index bf474c354..4bdc96866 100644
--- a/spec/lib/feed_manager_spec.rb
+++ b/spec/lib/feed_manager_spec.rb
@@ -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
diff --git a/spec/lib/inline_rabl_scope_spec.rb b/spec/lib/inline_rabl_scope_spec.rb
deleted file mode 100644
index 3fff176e4..000000000
--- a/spec/lib/inline_rabl_scope_spec.rb
+++ /dev/null
@@ -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
diff --git a/spec/lib/user_settings_decorator_spec.rb b/spec/lib/user_settings_decorator_spec.rb
index 66e42fa0e..a67487779 100644
--- a/spec/lib/user_settings_decorator_spec.rb
+++ b/spec/lib/user_settings_decorator_spec.rb
@@ -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
diff --git a/spec/models/feed_spec.rb b/spec/models/feed_spec.rb
index 15033e9eb..1c377c17f 100644
--- a/spec/models/feed_spec.rb
+++ b/spec/models/feed_spec.rb
@@ -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
diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb
index a6df3fb26..2019ec0f6 100644
--- a/spec/models/user_spec.rb
+++ b/spec/models/user_spec.rb
@@ -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
diff --git a/spec/rails_helper.rb b/spec/rails_helper.rb
index cfc9eec9e..4f7399505 100644
--- a/spec/rails_helper.rb
+++ b/spec/rails_helper.rb
@@ -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|
diff --git a/spec/requests/localization_spec.rb b/spec/requests/localization_spec.rb
index 2f7a5e91e..f625a93a4 100644
--- a/spec/requests/localization_spec.rb
+++ b/spec/requests/localization_spec.rb
@@ -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
diff --git a/spec/services/fetch_link_card_service_spec.rb b/spec/services/fetch_link_card_service_spec.rb
index 9df41cf55..698eb0324 100644
--- a/spec/services/fetch_link_card_service_spec.rb
+++ b/spec/services/fetch_link_card_service_spec.rb
@@ -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
diff --git a/spec/services/precompute_feed_service_spec.rb b/spec/services/precompute_feed_service_spec.rb
index 9f56b0256..dbd08ac1b 100644
--- a/spec/services/precompute_feed_service_spec.rb
+++ b/spec/services/precompute_feed_service_spec.rb
@@ -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)
+      reblog = Fabricate(:status, account: followed_account)
+      status = Fabricate(:status, account: account, reblog: reblog)
 
-      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)
+      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
diff --git a/spec/views/about/show.html.haml_spec.rb b/spec/views/about/show.html.haml_spec.rb
index 2c5130d84..c0ead6349 100644
--- a/spec/views/about/show.html.haml_spec.rb
+++ b/spec/views/about/show.html.haml_spec.rb
@@ -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
 
diff --git a/spec/workers/scheduler/feed_cleanup_scheduler_spec.rb b/spec/workers/scheduler/feed_cleanup_scheduler_spec.rb
index 4c709a2c9..b8487b03f 100644
--- a/spec/workers/scheduler/feed_cleanup_scheduler_spec.rb
+++ b/spec/workers/scheduler/feed_cleanup_scheduler_spec.rb
@@ -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)