mirror of
https://github.com/discourse/discourse.git
synced 2025-05-22 02:41:13 +08:00
FEATURE: Introduce theme/component QUnit tests (#12517)
This commit allows themes and theme components to have QUnit tests. To add tests to your theme/component, create a top-level directory in your theme and name it `test`, and Discourse will save all the files in that directory (and its sub-directories) as "tests files" in the database. While tests files/directories are not required to be organized in a specific way, we recommend that you follow Discourse core's tests [structure](https://github.com/discourse/discourse/tree/master/app/assets/javascripts/discourse/tests). Writing theme tests should be identical to writing plugins or core tests; all the `import` statements and APIs that you see in core (or plugins) to define/setup tests should just work in themes. You do need a working Discourse install to run theme tests, and you have 2 ways to run theme tests: * In the browser at the `/qunit` route. `/qunit` will run tests of all active themes/components as well as core and plugins. The `/qunit` now accepts a `theme_name` or `theme_url` params that you can use to run tests of a specific theme/component like so: `/qunit?theme_name=<your_theme_name>`. * In the command line using the `themes:qunit` rake task. This take is meant to run tests of a single theme/component so you need to provide it with a theme name or URL like so: `bundle exec rake themes:qunit[name=<theme_name>]` or `bundle exec rake themes:qunit[url=<theme_url>]`. There are some refactors to internal code that's responsible for processing themes/components in Discourse, most notably: * `<script type="text/discourse-plugin">` tags are automatically converted to modules. * The `theme-settings` service is removed in favor of a simple `lib` file responsible for managing theme settings. This was done to allow us to register/lookup theme settings very early in our Ember app lifecycle and because there was no reason for it to be an Ember service. These refactors should 100% backward compatible and invisible to theme developers.
This commit is contained in:
@ -151,6 +151,18 @@ class ThemeJavascriptCompiler
|
||||
class CompileError < StandardError
|
||||
end
|
||||
|
||||
def self.force_default_settings(content, theme)
|
||||
settings_hash = {}
|
||||
theme.settings.each do |setting|
|
||||
settings_hash[setting.name] = setting.default
|
||||
end
|
||||
content.prepend <<~JS
|
||||
(function() {
|
||||
require("discourse/lib/theme-settings-store").registerSettings(#{theme.id}, #{settings_hash.to_json}, { force: true });
|
||||
})();
|
||||
JS
|
||||
end
|
||||
|
||||
attr_accessor :content
|
||||
|
||||
def initialize(theme_id, theme_name)
|
||||
@ -162,10 +174,8 @@ class ThemeJavascriptCompiler
|
||||
def prepend_settings(settings_hash)
|
||||
@content.prepend <<~JS
|
||||
(function() {
|
||||
if ('Discourse' in window && Discourse.__container__) {
|
||||
Discourse.__container__
|
||||
.lookup("service:theme-settings")
|
||||
.registerSettings(#{@theme_id}, #{settings_hash.to_json});
|
||||
if ('require' in window) {
|
||||
require("discourse/lib/theme-settings-store").registerSettings(#{@theme_id}, #{settings_hash.to_json});
|
||||
}
|
||||
})();
|
||||
JS
|
||||
@ -173,8 +183,10 @@ class ThemeJavascriptCompiler
|
||||
|
||||
# TODO Error handling for handlebars templates
|
||||
def append_ember_template(name, hbs_template)
|
||||
name = "javascripts/#{name}" if !name.start_with?("javascripts/")
|
||||
name = name.inspect
|
||||
compiled = EmberTemplatePrecompiler.new(@theme_id).compile(hbs_template)
|
||||
# the `'Ember' in window` check is needed for no_ember pages
|
||||
content << <<~JS
|
||||
(function() {
|
||||
if ('Ember' in window) {
|
||||
@ -204,18 +216,19 @@ class ThemeJavascriptCompiler
|
||||
raise CompileError.new e.instance_variable_get(:@error) # e.message contains the entire template, which could be very long
|
||||
end
|
||||
|
||||
def append_plugin_script(script, api_version)
|
||||
@content << transpile(script, api_version)
|
||||
end
|
||||
|
||||
def append_raw_script(script)
|
||||
@content << script + "\n"
|
||||
end
|
||||
|
||||
def append_module(script, name, include_variables: true)
|
||||
script = "#{theme_variables}#{script}" if include_variables
|
||||
name = "discourse/theme-#{@theme_id}/#{name.gsub(/^discourse\//, '')}"
|
||||
script = "#{theme_settings}#{script}" if include_variables
|
||||
transpiler = DiscourseJsProcessor::Transpiler.new
|
||||
@content << transpiler.perform(script, "", name)
|
||||
@content << <<~JS
|
||||
if ('define' in window) {
|
||||
#{transpiler.perform(script, "", name).strip}
|
||||
}
|
||||
JS
|
||||
rescue MiniRacer::RuntimeError => ex
|
||||
raise CompileError.new ex.message
|
||||
end
|
||||
@ -226,11 +239,9 @@ class ThemeJavascriptCompiler
|
||||
|
||||
private
|
||||
|
||||
def theme_variables
|
||||
def theme_settings
|
||||
<<~JS
|
||||
const __theme_name__ = "#{@theme_name.gsub('"', "\\\"")}";
|
||||
const settings = Discourse.__container__
|
||||
.lookup("service:theme-settings")
|
||||
const settings = require("discourse/lib/theme-settings-store")
|
||||
.getObjectForTheme(#{@theme_id});
|
||||
const themePrefix = (key) => `theme_translations.#{@theme_id}.${key}`;
|
||||
JS
|
||||
@ -241,7 +252,8 @@ class ThemeJavascriptCompiler
|
||||
wrapped = <<~PLUGIN_API_JS
|
||||
(function() {
|
||||
if ('Discourse' in window && typeof Discourse._registerPluginCode === 'function') {
|
||||
#{theme_variables}
|
||||
const __theme_name__ = #{@theme_name.to_s.inspect};
|
||||
#{theme_settings}
|
||||
Discourse._registerPluginCode('#{version}', api => {
|
||||
try {
|
||||
#{es6_source}
|
||||
|
Reference in New Issue
Block a user