discourse/spec/rails_helper.rb
David Taylor 0e303c7f5d
FEATURE: Automatically generate optimized site metadata icons (#7372)
This change automatically resizes icons for various purposes. Admins can now upload `logo` and `logo_small`, and everything else will be auto-generated. Specific icons can still be uploaded separately if required.

## Core

- Adds an SiteIconManager module which manages automatic resizing and fallback

- Icons are looked up in the OptimizedImage table at runtime, and then cached in Redis. If the resized version is missing for some reason, then most icons will fall back to the original files. Some icons (e.g. PWA Manifest) will return `nil` (because an incorrectly sized icon is worse than a missing icon). 

- `SiteSetting.site_large_icon_url` will return the optimized version, including any fallback. `SiteSetting.large_icon` continues to return the upload object. This means that (almost) no changes are required in core/plugins to support this new system.

- Icons are resized whenever a relevant site setting is changed, and during post-deploy migrations

## Wizard

- Allows `requiresRefresh` wizard steps to reload data via AJAX instead of a full page reload

- Add placeholders to the **icons** step of the wizard, which automatically update from the "Square Logo"

- Various copy updates to support the changes

- Remove the "upload-time" resizing for `large_icon`. This is no longer required.

## Site Settings UX

- Move logo/icon settings under a new "Branding" tab

- Various copy changes to support the changes

- Adds placeholder support to the `image-uploader` component

- Automatically reloads site settings after saving. This allows setting placeholders to change based on changes to other settings

- Upload site settings will be assigned a placeholder if SiteIconManager `responds_to?` an icon of the same name

## Dashboard Warnings

- Remove PWA icon and PWA title warnings. Both are now handled automatically.

## Bonus

- Updated the sketch logos to use @awesomerobot's new high-res designs
2019-05-01 14:44:45 +01:00

351 lines
8.9 KiB
Ruby

# frozen_string_literal: true
if ENV['COVERAGE']
require 'simplecov'
SimpleCov.start
end
require 'rubygems'
require 'rbtrace'
# Loading more in this block will cause your tests to run faster. However,
# if you change any configuration or code from libraries loaded here, you'll
# need to restart spork for it take effect.
require 'fabrication'
require 'mocha/api'
require 'certified'
require 'webmock/rspec'
class RspecErrorTracker
def self.last_exception=(ex)
@ex = ex
end
def self.last_exception
@ex
end
def initialize(app, config = {})
@app = app
end
def call(env)
begin
@app.call(env)
rescue => e
RspecErrorTracker.last_exception = e
raise e
end
ensure
end
end
ENV["RAILS_ENV"] ||= 'test'
require File.expand_path("../../config/environment", __FILE__)
require 'rspec/rails'
require 'shoulda-matchers'
require 'sidekiq/testing'
# The shoulda-matchers gem no longer detects the test framework
# you're using or mixes itself into that framework automatically.
Shoulda::Matchers.configure do |config|
config.integrate do |with|
with.test_framework :rspec
with.library :active_record
with.library :active_model
end
end
# Requires supporting ruby files with custom matchers and macros, etc,
# in spec/support/ and its subdirectories.
Dir[Rails.root.join("spec/support/**/*.rb")].each { |f| require f }
Dir[Rails.root.join("spec/fabricators/*.rb")].each { |f| require f }
# Require plugin helpers at plugin/[plugin]/spec/plugin_helper.rb (includes symlinked plugins).
if ENV['LOAD_PLUGINS'] == "1"
Dir[Rails.root.join("plugins/*/spec/plugin_helper.rb")].each do |f|
require f
end
end
# let's not run seed_fu every test
SeedFu.quiet = true if SeedFu.respond_to? :quiet
SiteSetting.automatically_download_gravatars = false
SeedFu.seed
RSpec.configure do |config|
config.fail_fast = ENV['RSPEC_FAIL_FAST'] == "1"
config.include Helpers
config.include MessageBus
config.include RSpecHtmlMatchers
config.include IntegrationHelpers, type: :request
config.include SiteSettingsHelpers
config.mock_framework = :mocha
config.order = 'random'
config.infer_spec_type_from_file_location!
# If you're not using ActiveRecord, or you'd prefer not to run each of your
# examples within a transaction, remove the following line or assign false
# instead of true.
config.use_transactional_fixtures = true
# If true, the base class of anonymous controllers will be inferred
# automatically. This will be the default behavior in future versions of
# rspec-rails.
config.infer_base_class_for_anonymous_controllers = true
config.before(:suite) do
Sidekiq.error_handlers.clear
# Ugly, but needed until we have a user creator
User.skip_callback(:create, :after, :ensure_in_trust_level_group)
DiscoursePluginRegistry.clear if ENV['LOAD_PLUGINS'] != "1"
Discourse.current_user_provider = TestCurrentUserProvider
SiteSetting.refresh!
# Rebase defaults
#
# We nuke the DB storage provider from site settings, so need to yank out the existing settings
# and pretend they are default.
# There are a bunch of settings that are seeded, they must be loaded as defaults
SiteSetting.current.each do |k, v|
# skip setting defaults for settings that are in unloaded plugins
SiteSetting.defaults.set_regardless_of_locale(k, v) if SiteSetting.respond_to? k
end
require_dependency 'site_settings/local_process_provider'
SiteSetting.provider = SiteSettings::LocalProcessProvider.new
WebMock.disable_net_connect!
end
class DiscourseMockRedis < MockRedis
def without_namespace
self
end
def delete_prefixed(prefix)
keys("#{prefix}*").each { |k| del(k) }
end
end
config.after :each do |x|
if x.exception && ex = RspecErrorTracker.last_exception
# magic in a cause if we have none
unless x.exception.cause
class << x.exception
attr_accessor :cause
end
x.exception.cause = ex
end
end
unfreeze_time
ActionMailer::Base.deliveries.clear
if ActiveRecord::Base.connection_pool.stat[:busy] > 1
raise ActiveRecord::Base.connection_pool.stat.inspect
end
end
config.before :each do |x|
# TODO not sure about this, we could use a mock redis implementation here:
# this gives us really clean "flush" semantics, howere the side-effect is that
# we are no longer using a clean redis implementation, a preferable solution may
# be simply flushing before tests, trouble is that redis may be reused with dev
# so that would mean the dev would act weird
#
# perf benefit seems low (shaves 20 secs off a 4 minute test suite)
#
# $redis = DiscourseMockRedis.new
RateLimiter.disable
PostActionNotifier.disable
SearchIndexer.disable
UserActionManager.disable
NotificationEmailer.disable
SiteIconManager.disable
SiteSetting.provider.all.each do |setting|
SiteSetting.remove_override!(setting.name)
end
# very expensive IO operations
SiteSetting.automatically_download_gravatars = false
Discourse.clear_readonly!
Sidekiq::Worker.clear_all
I18n.locale = :en
RspecErrorTracker.last_exception = nil
if $test_cleanup_callbacks
$test_cleanup_callbacks.reverse_each(&:call)
$test_cleanup_callbacks = nil
end
# Running jobs are expensive and most of our tests are not concern with
# code that runs inside jobs. run_later! means they are put on the redis
# queue and never processed.
Jobs.run_later!
end
config.before(:each, type: :multisite) do
Rails.configuration.multisite = true
RailsMultisite::ConnectionManagement.config_filename =
"spec/fixtures/multisite/two_dbs.yml"
end
config.after(:each, type: :multisite) do
ActiveRecord::Base.clear_all_connections!
Rails.configuration.multisite = false
RailsMultisite::ConnectionManagement.clear_settings!
ActiveRecord::Base.establish_connection
end
class TestCurrentUserProvider < Auth::DefaultCurrentUserProvider
def log_on_user(user, session, cookies, opts = {})
session[:current_user_id] = user.id
super
end
def log_off_user(session, cookies)
session[:current_user_id] = nil
super
end
end
# Normally we `use_transactional_fixtures` to clear out a database after a test
# runs. However, this does not apply to tests done for multisite. The second time
# a test runs you can end up with stale data that breaks things. This method will
# force a rollback after using a multisite connection.
def test_multisite_connection(name)
RailsMultisite::ConnectionManagement.with_connection(name) do
spec_exception = nil
ActiveRecord::Base.transaction do
begin
yield
rescue Exception => spec_exception
ensure
raise ActiveRecord::Rollback
end
end
raise spec_exception if spec_exception
end
end
end
class TrackTimeStub
def self.stubbed
false
end
end
def before_next_spec(&callback)
($test_cleanup_callbacks ||= []) << callback
end
def global_setting(name, value)
GlobalSetting.reset_s3_cache!
GlobalSetting.stubs(name).returns(value)
before_next_spec do
GlobalSetting.reset_s3_cache!
end
end
def set_env(var, value)
old = ENV.fetch var, :missing
ENV[var] = value
before_next_spec do
if old == :missing
ENV.delete var
else
ENV[var] = old
end
end
end
def set_cdn_url(cdn_url)
global_setting :cdn_url, cdn_url
Rails.configuration.action_controller.asset_host = cdn_url
ActionController::Base.asset_host = cdn_url
before_next_spec do
Rails.configuration.action_controller.asset_host = nil
ActionController::Base.asset_host = nil
end
end
def freeze_time(now = Time.now)
time = now
datetime = now
if Time === now
datetime = now.to_datetime
elsif DateTime === now
time = now.to_time
else
datetime = DateTime.parse(now.to_s)
time = Time.parse(now.to_s)
end
if block_given?
raise "nested freeze time not supported" if TrackTimeStub.stubbed
end
DateTime.stubs(:now).returns(datetime)
Time.stubs(:now).returns(time)
Date.stubs(:today).returns(datetime.to_date)
TrackTimeStub.stubs(:stubbed).returns(true)
if block_given?
begin
yield
ensure
unfreeze_time
end
end
end
def unfreeze_time
DateTime.unstub(:now)
Time.unstub(:now)
Date.unstub(:today)
TrackTimeStub.unstub(:stubbed)
end
def file_from_fixtures(filename, directory = "images")
FileUtils.mkdir_p("#{Rails.root}/tmp/spec") unless Dir.exists?("#{Rails.root}/tmp/spec")
FileUtils.cp("#{Rails.root}/spec/fixtures/#{directory}/#{filename}", "#{Rails.root}/tmp/spec/#{filename}")
File.new("#{Rails.root}/tmp/spec/#{filename}")
end
def has_trigger?(trigger_name)
DB.exec(<<~SQL) != 0
SELECT 1
FROM INFORMATION_SCHEMA.TRIGGERS
WHERE trigger_name = '#{trigger_name}'
SQL
end
def silence_stdout
STDOUT.stubs(:write)
yield
ensure
STDOUT.unstub(:write)
end