DEV: Support for running theme test with Ember CLI (third attempt)

The second attempt fixed issues with smoke test.

This one makes sure minification only happens in production mode.
This commit is contained in:
Robin Ward 2022-01-13 15:16:34 -05:00
parent f82f0e1179
commit 6272edd121
30 changed files with 274 additions and 153 deletions

View File

@ -12,7 +12,7 @@ lib/highlight_js/
plugins/**/lib/javascripts/locale
public/
vendor/
app/assets/javascripts/discourse/tests/test_helper.js
app/assets/javascripts/discourse/tests/test-boot-rails.js
app/assets/javascripts/discourse/tests/fixtures
node_modules/
dist/

View File

@ -20,7 +20,7 @@ lib/highlight_js/
plugins/**/lib/javascripts/locale
public/
vendor/
app/assets/javascripts/discourse/tests/test_helper.js
app/assets/javascripts/discourse/tests/test-boot-rails.js
app/assets/javascripts/discourse/tests/fixtures
node_modules/
dist/

View File

@ -11,7 +11,9 @@ let testingFunc = isLegacyEmber() ? run : next;
export default function () {
if (isTesting()) {
return testingFunc(...arguments);
// Don't include the time argument (in ms)
let args = [].slice.call(arguments, 0, -1);
return testingFunc.apply(void 0, args);
} else {
return debounce(...arguments);
}

View File

@ -14,6 +14,7 @@ module.exports = function (defaults) {
let discourseRoot = resolve("../../../..");
let vendorJs = discourseRoot + "/vendor/assets/javascripts/";
const isProduction = EmberApp.env().includes("production");
let app = new EmberApp(defaults, {
autoRun: false,
"ember-qunit": {
@ -37,8 +38,66 @@ module.exports = function (defaults) {
// We don't use SRI in Rails. Disable here to match:
enabled: false,
},
"ember-cli-terser": {
enabled: isProduction,
exclude: [
"**/test-*.js",
"**/core-tests*.js",
"**/highlightjs/*",
"**/javascripts/*",
],
},
// We need to build tests in prod for theme tests
tests: true,
});
// Patching a private method is not great, but there's no other way for us to tell
// Ember CLI that we want the tests alone in a package without helpers/fixtures, since
// we re-use those in the theme tests.
app._defaultPackager.packageApplicationTests = function (tree) {
let appTestTrees = []
.concat(
this.packageEmberCliInternalFiles(),
this.packageTestApplicationConfig(),
tree
)
.filter(Boolean);
appTestTrees = mergeTrees(appTestTrees, {
overwrite: true,
annotation: "TreeMerger (appTestTrees)",
});
let tests = concat(appTestTrees, {
inputFiles: [
"**/tests/acceptance/*.js",
"**/tests/integration/*.js",
"**tests/unit/*.js",
],
headerFiles: ["vendor/ember-cli/tests-prefix.js"],
footerFiles: ["vendor/ember-cli/app-config.js"],
outputFile: "/assets/core-tests.js",
annotation: "Concat: Core Tests",
sourceMapConfig: false,
});
let testHelpers = concat(appTestTrees, {
inputFiles: [
"**/tests/test-boot-ember-cli.js",
"**/tests/helpers/**/*.js",
"**/tests/fixtures/**/*.js",
"**/tests/setup-tests.js",
],
outputFile: "/assets/test-helpers.js",
annotation: "Concat: Test Helpers",
sourceMapConfig: false,
});
return mergeTrees([tests, testHelpers]);
};
// WARNING: We should only import scripts here if they are not in NPM.
// For example: our very specific version of bootstrap-modal.
app.import(vendorJs + "bootbox.js");
@ -70,7 +129,6 @@ module.exports = function (defaults) {
}),
]);
const isProduction = EmberApp.env().includes("production");
if (isProduction) {
return new AssetRev(mergedTree, {
exclude: [

View File

@ -34,7 +34,7 @@
"discourse-common": "^1.0.0",
"discourse-hbr": "^1.0.0",
"discourse-widget-hbs": "^1.0.0",
"ember-auto-import": "^1.10.1",
"ember-auto-import": "^1.12.0",
"ember-buffered-proxy": "^2.0.0-beta.0",
"ember-cli": "~3.25.3",
"ember-cli-app-version": "^4.0.0",

View File

@ -0,0 +1,4 @@
document.write(
"<style>#ember-testing-container { position: fixed; background: white; bottom: 0; right: 0; width: 640px; height: 384px; overflow: auto; z-index: 9999; border: 1px solid #ccc; transform: translateZ(0)} #ember-testing { width: 200%; height: 200%; transform: scale(0.5); transform-origin: top left; }</style>"
);
require('discourse/tests/test-boot-ember-cli');

View File

@ -8,13 +8,4 @@
require_asset(f)
end
end
Discourse.plugins.each do |p|
root_path = "#{File.dirname(p.path)}/test/javascripts"
to_glob = [root_path + '/**/**.es6']
to_glob << (root_path + '/**/**.js') if p.transpile_js
Dir.glob(to_glob) { |f| require_asset(f) }
end
%>

View File

@ -1,4 +1,3 @@
//= require_tree ./acceptance
//= require_tree ./integration
//= require_tree ./unit
//= require ./plugin_tests

View File

@ -50,9 +50,14 @@
<script src="{{rootURL}}assets/test-support.js"></script>
<script src="{{rootURL}}assets/discourse.js"></script>
<script src="{{rootURL}}assets/discourse-markdown.js"></script>
<script src="{{rootURL}}assets/discourse/tests/core_plugins_tests.js"></script>
<script src="{{rootURL}}assets/discourse/tests/active-plugins.js"></script>
<script src="{{rootURL}}assets/admin.js"></script>
<script src="{{rootURL}}assets/tests.js"></script>
<script src="{{rootURL}}assets/test-helpers.js"></script>
<script src="{{rootURL}}assets/core-tests.js"></script>
<script src="{{rootURL}}assets/discourse/tests/plugin-tests.js"></script>
<script>
require('discourse/tests/test-boot-ember-cli');
</script>
<script src="{{rootURL}}assets/scripts/discourse-boot.js"></script>
{{content-for "body-footer"}}

View File

@ -0,0 +1,10 @@
<%
Discourse.plugins.each do |p|
root_path = "#{File.dirname(p.path)}/test/javascripts"
to_glob = [root_path + '/**/**.es6']
to_glob << (root_path + '/**/**.js') if p.transpile_js
Dir.glob(to_glob) { |f| require_asset(f) }
end
%>

View File

@ -34,3 +34,4 @@ document.addEventListener("discourse-booted", () => {
setupEmberOnerrorValidation: !skippingCore,
});
});
window.EmberENV.TESTS_FILE_LOADED = true;

View File

@ -3,4 +3,3 @@
//= require_tree ./helpers
//= require_tree ./fixtures
//= require ./setup-tests
//= require test-shims

View File

@ -5,11 +5,10 @@
//= require fake_xml_http_request
//= require route-recognizer
//= require pretender
// These are not loaded in prod or development
// But we need them for testing handlebars templates in qunit
//= require handlebars
//= require ember-template-compiler
//= require sinon
//= require break_string
//= require test-shims
//= require jquery.magnific-popup.min.js
//= require handlebars
//= require ember-template-compiler
//= require markdown-it-bundle

View File

@ -1,38 +0,0 @@
// discourse-skip-module
//= require env
//= require jquery.debug
//= require jquery.ui.widget
//= require ember.debug
//= require message-bus
//= require qunit
//= require ember-qunit
//= require fake_xml_http_request
//= require route-recognizer
//= require pretender
//= require locales/i18n
//= require locales/en
//= require discourse-loader
// Our base application
//= require vendor
//= require discourse-shims
//= require markdown-it-bundle
//= require application
//= require admin
// These are not loaded in prod or development
// But we need them for testing handlebars templates in qunit
//= require handlebars
//= require ember-template-compiler
// Test helpers
//= require sinon
//= require_tree ./helpers
//= require break_string
//= require_tree ./fixtures
//= require ./setup-tests
//= require test-shims
//= require jquery.magnific-popup.min.js

View File

@ -1,30 +0,0 @@
// This bundle contains the same dependencies as app/assets/javascripts/vendor.js
// minus ember_jquery.
// ember_jquery doesn't work with theme tests in production because it
// contains production builds of Ember and jQuery, so we have a separate bundle
// caled theme_qunit_ember_jquery which contains a debug build for Ember and jQuery.
// We don't put theme_qunit_ember_jquery in this bundle because it would make the
// bundle too big and cause OOM exceptions during rebuilds for self-hosters on
// low-end machines.
//= require logster
//= require template_include.js
//= require message-bus
//= require jquery.ui.widget.js
//= require Markdown.Converter.js
//= require bootbox.js
//= require popper.js
//= require bootstrap-modal.js
//= require caret_position
//= require jquery.sortable.js
//= require lodash.js
//= require itsatrap.js
//= require rsvp.js
//= require uppy.js
//= require buffered-proxy
//= require virtual-dom
//= require virtual-dom-amd
//= require discourse-shims
//= require pretty-text-bundle

View File

@ -1,5 +1,5 @@
<%
if Rails.env.development? || Rails.env.test?
if @force_ember_debug || Rails.env.development? || Rails.env.test?
require_asset ("ember.debug.js")
else
require_asset ("ember.prod.js")

View File

@ -0,0 +1,21 @@
//= require logster
//= require template_include.js
//= require message-bus
//= require jquery.ui.widget.js
//= require Markdown.Converter.js
//= require bootbox.js
//= require popper.js
//= require bootstrap-modal.js
//= require caret_position
//= require jquery.sortable.js
//= require lodash.js
//= require itsatrap.js
//= require rsvp.js
//= require uppy.js
//= require buffered-proxy
//= require virtual-dom
//= require virtual-dom-amd
//= require discourse-shims
//= require pretty-text-bundle

View File

@ -0,0 +1,6 @@
//= require set-prototype-polyfill
//= require env
//= require jquery
//= require ember.debug.js
//= require discourse-loader
//= require vendor-common

View File

@ -1,23 +1,2 @@
//= require ember_jquery
//= require logster
//= require template_include.js
//= require message-bus
//= require jquery.ui.widget.js
//= require Markdown.Converter.js
//= require bootbox.js
//= require popper.js
//= require bootstrap-modal.js
//= require caret_position
//= require jquery.sortable.js
//= require lodash.js
//= require itsatrap.js
//= require rsvp.js
//= require uppy.js
//= require buffered-proxy
//= require virtual-dom
//= require virtual-dom-amd
//= require discourse-shims
//= require pretty-text-bundle
//= require vendor-common

View File

@ -4810,6 +4810,41 @@ ember-auto-import@^1.10.1, ember-auto-import@^1.5.3:
walk-sync "^0.3.3"
webpack "^4.43.0"
ember-auto-import@^1.12.0:
version "1.12.0"
resolved "https://registry.yarnpkg.com/ember-auto-import/-/ember-auto-import-1.12.0.tgz#52246b04891090e2608244e65c4c6af7710df12b"
integrity sha512-fzMGnyHGfUNFHchpLbJ98Vs/c5H2wZBMR9r/XwW+WOWPisZDGLUPPyhJQsSREPoUQ+o8GvyLaD/rkrKqW8bmgw==
dependencies:
"@babel/core" "^7.1.6"
"@babel/preset-env" "^7.10.2"
"@babel/traverse" "^7.1.6"
"@babel/types" "^7.1.6"
"@embroider/core" "^0.33.0"
babel-core "^6.26.3"
babel-loader "^8.0.6"
babel-plugin-syntax-dynamic-import "^6.18.0"
babylon "^6.18.0"
broccoli-debug "^0.6.4"
broccoli-node-api "^1.7.0"
broccoli-plugin "^4.0.0"
broccoli-source "^3.0.0"
debug "^3.1.0"
ember-cli-babel "^7.0.0"
enhanced-resolve "^4.0.0"
fs-extra "^6.0.1"
fs-tree-diff "^2.0.0"
handlebars "^4.3.1"
js-string-escape "^1.0.1"
lodash "^4.17.19"
mkdirp "^0.5.1"
resolve-package-path "^3.1.0"
rimraf "^2.6.2"
semver "^7.3.4"
symlink-or-copy "^1.2.0"
typescript-memoize "^1.0.0-alpha.3"
walk-sync "^0.3.3"
webpack "^4.43.0"
ember-buffered-proxy@^2.0.0-beta.0:
version "2.0.0-beta.0"
resolved "https://registry.yarnpkg.com/ember-buffered-proxy/-/ember-buffered-proxy-2.0.0-beta.0.tgz#65be4e2d0dcf40a5a2dab548c84a21aa332555a2"

View File

@ -69,7 +69,7 @@ class BootstrapController < ApplicationController
locale_script: locale,
stylesheets: @stylesheets,
plugin_js: plugin_js,
plugin_test_js: [script_asset_path("plugin_tests")],
plugin_test_js: [script_asset_path("plugin-tests")],
setup_data: client_side_setup_data,
preloaded: @preloaded,
html: create_html,

View File

@ -8,15 +8,32 @@ class QunitController < ApplicationController
}
layout false
def is_ember_cli_proxy?
request.headers["HTTP_X_DISCOURSE_EMBER_CLI"] == "true"
end
# only used in test / dev
def index
raise Discourse::NotFound.new if request.headers["HTTP_X_DISCOURSE_EMBER_CLI"] == "true"
raise Discourse::NotFound.new if is_ember_cli_proxy?
raise Discourse::InvalidAccess.new if Rails.env.production?
end
def theme
raise Discourse::NotFound.new if !can_see_theme_qunit?
@is_proxied = is_ember_cli_proxy?
@legacy_ember = if Rails.env.production?
ENV['EMBER_CLI_PROD_ASSETS'] != "1"
else
!@is_proxied
end
# In production mode all bundles use `application`
@app_bundle = "application"
if Rails.env.development? && @is_proxied
@app_bundle = "discourse"
end
param_key = nil
@suggested_themes = nil
if (id = get_param(:id)).present?

View File

@ -13,9 +13,11 @@ module ApplicationHelper
@extra_body_classes ||= Set.new
end
def discourse_config_environment
def discourse_config_environment(testing: false)
# TODO: Can this come from Ember CLI somehow?
{ modulePrefix: "discourse",
config = {
modulePrefix: "discourse",
environment: Rails.env,
rootURL: Discourse.base_path,
locationType: "auto",
@ -32,7 +34,16 @@ module ApplicationHelper
version: "#{Discourse::VERSION::STRING} #{Discourse.git_version}",
exportApplicationGlobal: true
}
}.to_json
}
if testing
config[:environment] = "test"
config[:locationType] = "none"
config[:APP][:autoboot] = false
config[:APP][:rootElement] = '#ember-testing'
end
config.to_json
end
def google_universal_analytics_json(ua_domain_name = nil)

View File

@ -1,6 +1,38 @@
# frozen_string_literal: true
module QunitHelper
def vendor_theme_tests
return preload_script("vendor-theme-tests") if @legacy_ember
preload_script("vendor")
end
def support_bundles
result = []
if Rails.env.production? || @legacy_ember
result << preload_script("discourse/tests/test-support-rails")
result << preload_script("discourse/tests/test-helpers-rails")
else
result << preload_script("test-support")
result << preload_script("test-helpers")
end
result.join("\n").html_safe
end
def boot_bundles
result = []
if @legacy_ember
result << preload_script("discourse/tests/test_starter")
elsif @is_proxied
result << preload_script("scripts/discourse-test-listen-boot")
result << preload_script("scripts/discourse-boot")
else
result << preload_script("discourse-test-listen-boot")
result << preload_script("discourse-boot")
end
result.join("\n").html_safe
end
def theme_tests
theme = Theme.find_by(id: request.env[:resolved_theme_id])
return "" if theme.blank?

View File

@ -5,8 +5,15 @@
<%= discourse_color_scheme_stylesheets %>
<%= discourse_stylesheet_link_tag(:desktop, theme_id: nil) %>
<%= discourse_stylesheet_link_tag(:test_helper, theme_id: nil) %>
<%= preload_script "discourse/tests/test_helper" %>
<%= preload_script "discourse/tests/core_plugins_tests" %>
<%= preload_script "locales/#{I18n.locale}" %>
<%= preload_script "vendor" %>
<%= preload_script "application" %>
<%= preload_script "admin" %>
<%= preload_script "discourse/tests/test-support-rails" %>
<%= preload_script "discourse/tests/test-helpers-rails" %>
<%= preload_script "discourse/tests/active-plugins" %>
<%= preload_script "discourse/tests/core-tests" %>
<%= preload_script "discourse/tests/plugin-tests" %>
<%= preload_script "discourse/tests/test_starter" %>
<%= csrf_meta_tags %>
<meta property="og:title" content="">

View File

@ -6,17 +6,12 @@
<%- if !@suggested_themes %>
<%= discourse_stylesheet_link_tag(:desktop, theme_id: nil) %>
<%= discourse_stylesheet_link_tag(:test_helper, theme_id: nil) %>
<%= preload_script "locales/en" %>
<%= preload_script "discourse/tests/theme_qunit_ember_jquery" %>
<%= preload_script "discourse/tests/theme_qunit_vendor" %>
<%= preload_script "discourse/tests/theme_qunit_tests_vendor" %>
<%= preload_script "markdown-it-bundle" %>
<%= preload_script "application" %>
<%- Discourse.find_plugin_js_assets(include_official: allow_plugins?, include_unofficial: allow_third_party_plugins?, request: request).each do |file| %>
<%= preload_script file %>
<%- end %>
<%= preload_script "locales/#{I18n.locale}" %>
<%= vendor_theme_tests %>
<%= preload_script @app_bundle %>
<%= preload_script "admin" %>
<%= preload_script "discourse/tests/theme_qunit_helper" %>
<%= preload_script "discourse/tests/active-plugins" %>
<%= support_bundles %>
<%= theme_translations_lookup %>
<%= theme_js_lookup %>
<%= theme_lookup("head_tag") %>
@ -24,7 +19,7 @@
<%= tag.meta id: 'data-discourse-setup', data: client_side_setup_data %>
<meta property="og:title" content="">
<meta property="og:url" content="">
<%= preload_script "discourse/tests/test_starter" %>
<meta name="discourse/config/environment" content="<%=u discourse_config_environment(testing: true) %>" />
<%- else %>
<style>
html {
@ -35,8 +30,10 @@
</head>
<body>
<%- if !@suggested_themes %>
<div id="qunit"></div>
<div id="qunit-fixture"></div>
<%- if @legacy_ember %>
<div id="qunit"></div>
<div id="qunit-fixture"></div>
<%- end %>
<%- else %>
<h2>Theme QUnit Test Runner</h2>
<%- if @suggested_themes.size == 0 %>
@ -49,4 +46,7 @@
<%- end %>
<%- end %>
</body>
<%- if !@suggested_themes %>
<%= boot_bundles %>
<%- end %>
</html>

View File

@ -176,13 +176,18 @@ module Discourse
confirm-new-email/bootstrap.js
onpopstate-handler.js
embed-application.js
discourse/tests/theme_qunit_ember_jquery.js
discourse/tests/theme_qunit_vendor.js
discourse/tests/theme_qunit_tests_vendor.js
discourse/tests/theme_qunit_helper.js
discourse/tests/active-plugins.js
discourse/tests/test_starter.js
}
if ENV['EMBER_CLI_PROD_ASSETS'] != "1"
config.assets.precompile += %w{
discourse/tests/test-support-rails.js
discourse/tests/test-helpers-rails.js
vendor-theme-tests.js
}
end
# Precompile all available locales
unless GlobalSetting.try(:omit_base_locales)
Dir.glob("#{config.root}/app/assets/javascripts/locales/*.js.erb").each do |file|
@ -370,7 +375,7 @@ module Discourse
%w{qunit.js
qunit.css
test_helper.css
discourse/tests/test_helper.js
discourse/tests/test-boot-rails.js
wizard/test/test_helper.js
}.include?(logical_path) ||
logical_path =~ /\/node_modules/ ||

View File

@ -32,7 +32,7 @@ module Autospec
# Discourse specific
reload(%r{^discourse/tests/javascripts/fixtures/.+_fixtures\.js(\.es6)?$})
reload(%r{^discourse/tests/javascripts/(helpers|mixins)/.+\.js(\.es6)?$})
reload("app/assets/javascripts/discoruse/tests/javascripts/test_helper.js")
reload("app/assets/javascripts/discoruse/tests/javascripts/test-boot-rails.js")
watch(%r{^plugins/.*/test/.+\.js(\.es6)?$})

View File

@ -39,8 +39,7 @@ task 'assets:precompile:before' do
# Remove the assets that Ember CLI will handle for us
Rails.configuration.assets.precompile.reject! do |asset|
asset.is_a?(String) &&
(%w(application.js admin.js ember_jquery.js pretty-text-bundle.js start-discourse.js vendor.js).include?(asset) ||
asset.start_with?("discourse/tests"))
(%w(application.js admin.js ember_jquery.js pretty-text-bundle.js start-discourse.js vendor.js).include?(asset))
end
end
end
@ -250,9 +249,14 @@ def copy_ember_cli_assets
# Copy assets and generate manifest data
log_task_duration('Copy assets and generate manifest data') {
Dir["#{ember_cli_assets}**/*"].each do |f|
if f !~ /test/ && File.file?(f)
if File.file?(f)
rel_file = f.sub(ember_cli_assets, "")
digest = f.scan(/\-([a-f0-9]+)\./)[0][0]
file_digest = Digest::SHA384.digest(File.read(f))
digest = if f =~ /\-([a-f0-9]+)\./
Regexp.last_match[1]
else
Digest.hexencode(file_digest)[0...32]
end
dest = "public/assets"
dest_sub = dest
@ -263,10 +267,17 @@ def copy_ember_cli_assets
FileUtils.mkdir_p(dest_sub) unless Dir.exist?(dest_sub)
log_file = File.basename(rel_file).sub("-#{digest}", "")
# It's simpler to serve the file as `application.js`
if log_file == "discourse.js"
# We need a few hacks here to move what Ember uses to what Rails wants
case log_file
when "discourse.js"
log_file = "application.js"
rel_file.sub!(/^discourse/, "application")
when "test-support.js"
log_file = "discourse/tests/test-support-rails.js"
rel_file = "discourse/tests/test-support-rails-#{digest}.js"
when "test-helpers.js"
log_file = "discourse/tests/test-helpers-rails.js"
rel_file = "discourse/tests/test-helpers-rails-#{digest}.js"
end
res = FileUtils.cp(f, "#{dest}/#{rel_file}")
@ -277,7 +288,7 @@ def copy_ember_cli_assets
"mtime" => File.mtime(f).iso8601(9),
"size" => File.size(f),
"digest" => digest,
"integrity" => "sha384-#{Base64.encode64(Digest::SHA384.digest(File.read(f))).chomp}"
"integrity" => "sha384-#{Base64.encode64(file_digest).chomp}"
}
end
end

View File

@ -98,16 +98,13 @@ describe QunitController do
expect(response.body).to include("/stylesheets/desktop_")
expect(response.body).to include("/stylesheets/test_helper_")
expect(response.body).to include("/assets/locales/en.js")
expect(response.body).to include("/assets/discourse/tests/theme_qunit_ember_jquery.js")
expect(response.body).to include("/assets/discourse/tests/theme_qunit_vendor.js")
expect(response.body).to include("/assets/discourse/tests/theme_qunit_tests_vendor.js")
expect(response.body).to include("/test-support")
expect(response.body).to include("/test-helpers")
expect(response.body).to include("/assets/markdown-it-bundle.js")
expect(response.body).to include("/assets/application.js")
expect(response.body).to include("/assets/admin.js")
expect(response.body).to include("/assets/discourse/tests/theme_qunit_helper.js")
expect(response.body).to match(/\/theme-javascripts\/\h{40}\.js/)
expect(response.body).to include("/theme-javascripts/tests/#{theme.id}-")
expect(response.body).to include("/assets/discourse/tests/test_starter.js")
end
end
end