DEV: Stop building test assets in production under Embroider (#23388)
Until now, we have allowed testing themes in production environments via `/theme-qunit`. This was made possible by hacking the ember-cli build so that it would create the `tests.js` bundle in production. However, this is fundamentally problematic because a number of test-specific things are still optimized out of the Ember build in production mode. It also makes asset compilation significantly slower, and makes it more difficult for us to update our build pipeline (e.g. to introduce Embroider). This commit removes the ability to run qunit tests in production builds of the JS app when the Embdroider flag is enabled. If a production instance of Discourse exists exclusively for the development of themes (e.g. discourse.theme-creator.io) then they can add `EMBER_ENV: development` to their `app.yml` file. This will build the entire app in development mode, and has a significant performance impact. This must not be used for real production sites. This commit also refactors many of the request specs into system specs. This means that the tests are guaranteed to have Ember assets built, and is also a better end-to-end test than simply checking for the presence of certain `<script>` tags in the HTML.
This commit is contained in:
parent
d28f113ce0
commit
9667485951
|
@ -103,12 +103,9 @@ module.exports = function (defaults) {
|
|||
|
||||
"ember-cli-terser": {
|
||||
enabled: isProduction,
|
||||
exclude: [
|
||||
"**/test-*.js",
|
||||
"**/core-tests*.js",
|
||||
"**/highlightjs/*",
|
||||
"**/javascripts/*",
|
||||
],
|
||||
exclude:
|
||||
["**/highlightjs/*", "**/javascripts/*"] +
|
||||
(isEmbroider ? [] : ["**/test-*.js", "**/core-tests*.js"]),
|
||||
},
|
||||
|
||||
"ember-cli-babel": {
|
||||
|
@ -119,8 +116,9 @@ module.exports = function (defaults) {
|
|||
plugins: [require.resolve("deprecation-silencer")],
|
||||
},
|
||||
|
||||
// We need to build tests in prod for theme tests
|
||||
tests: true,
|
||||
// Was previously true so that we could run theme tests in production
|
||||
// but we're moving away from that as part of the Embroider migration
|
||||
tests: isEmbroider ? !isProduction : true,
|
||||
|
||||
vendorFiles: {
|
||||
// Freedom patch - includes bug fix and async stack support
|
||||
|
|
|
@ -7,6 +7,8 @@ class QunitController < ApplicationController
|
|||
def theme
|
||||
raise Discourse::NotFound.new if !can_see_theme_qunit?
|
||||
|
||||
@has_test_bundle = EmberCli.has_tests?
|
||||
|
||||
param_key = nil
|
||||
@suggested_themes = nil
|
||||
if (id = get_param(:id)).present?
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<%= discourse_color_scheme_stylesheets %>
|
||||
<meta name="color-scheme" content="light dark">
|
||||
|
||||
<%- if !@suggested_themes %>
|
||||
<%- if @has_test_bundle && !@suggested_themes %>
|
||||
<%= preload_script "locales/#{I18n.locale}" %>
|
||||
<%= preload_script "vendor" %>
|
||||
<%= preload_script "test-support" %>
|
||||
|
@ -44,7 +44,10 @@
|
|||
<%- end %>
|
||||
</head>
|
||||
<body>
|
||||
<%- if @suggested_themes %>
|
||||
<%- if !@has_test_bundle %>
|
||||
This is a production installation of Discourse, and cannot be used for theme testing.
|
||||
For more information, see <a href="https://meta.discourse.org/t/66857">this guide</a>.
|
||||
<% elsif @suggested_themes %>
|
||||
<h2>Theme QUnit Test Runner</h2>
|
||||
|
||||
<%- if @suggested_themes.size == 0 %>
|
||||
|
@ -55,9 +58,7 @@
|
|||
<h4><%= link_to name, theme_qunit_path(id: id) %></h4>
|
||||
<%- end %>
|
||||
<%- end %>
|
||||
<%- end %>
|
||||
|
||||
<%- if !@suggested_themes %>
|
||||
<% else %>
|
||||
<%= preload_script "scripts/discourse-test-listen-boot" %>
|
||||
<%= preload_script "scripts/discourse-boot" %>
|
||||
<%- end %>
|
||||
|
|
|
@ -103,4 +103,8 @@ module EmberCli
|
|||
|
||||
chunk_infos
|
||||
end
|
||||
|
||||
def self.has_tests?
|
||||
File.exist?("#{dist_dir}/tests/index.html")
|
||||
end
|
||||
end
|
||||
|
|
|
@ -9,13 +9,15 @@ task "assets:precompile:before": "environment" do
|
|||
end
|
||||
|
||||
if ENV["EMBER_CLI_COMPILE_DONE"] != "1"
|
||||
compile_command = "yarn --cwd app/assets/javascripts/discourse run ember build -prod"
|
||||
compile_command = "yarn --cwd app/assets/javascripts/discourse run ember build"
|
||||
|
||||
if check_node_heap_size_limit < 1024
|
||||
STDERR.puts "Detected low Node.js heap_size_limit. Using --max-old-space-size=1024."
|
||||
compile_command = "NODE_OPTIONS='--max-old-space-size=1024' #{compile_command}"
|
||||
end
|
||||
|
||||
compile_command = "EMBER_ENV=production #{compile_command}" if ENV["EMBER_ENV"].nil?
|
||||
|
||||
only_assets_precompile_remaining = (ARGV.last == "assets:precompile")
|
||||
|
||||
if only_assets_precompile_remaining
|
||||
|
|
|
@ -1,108 +1,30 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
RSpec.describe QunitController do
|
||||
describe "#theme" do
|
||||
let(:theme) { Fabricate(:theme, name: "main-theme") }
|
||||
let(:component) { Fabricate(:theme, component: true, name: "enabled-component") }
|
||||
let(:disabled_component) do
|
||||
Fabricate(:theme, component: true, enabled: false, name: "disabled-component")
|
||||
end
|
||||
let(:theme_without_tests) { Fabricate(:theme, name: "no-tests-guy") }
|
||||
def production_sign_in(user)
|
||||
# We need to call sign_in before stubbing the method because SessionController#become
|
||||
# checks for the current env when the file is loaded.
|
||||
# We need to make sure become is called once before stubbing, or the method
|
||||
# wont'be available for future tests if this one runs first.
|
||||
sign_in(user) if user
|
||||
Rails.env.stubs(:production?).returns(true)
|
||||
end
|
||||
|
||||
before do
|
||||
Theme.destroy_all
|
||||
theme.set_default!
|
||||
component.add_relative_theme!(:parent, theme)
|
||||
disabled_component.add_relative_theme!(:parent, theme)
|
||||
[theme, component, disabled_component].each do |t|
|
||||
t.set_field(
|
||||
target: :extra_js,
|
||||
type: :js,
|
||||
name: "discourse/initializers/my-#{t.id}-initializer.js",
|
||||
value: "console.log(#{t.id});",
|
||||
)
|
||||
t.set_field(
|
||||
target: :tests_js,
|
||||
type: :js,
|
||||
name: "acceptance/some-test-#{t.id}.js",
|
||||
value: "assert.ok(#{t.id});",
|
||||
)
|
||||
t.save!
|
||||
end
|
||||
end
|
||||
it "hides page for regular users in production" do
|
||||
production_sign_in(Fabricate(:user))
|
||||
get "/theme-qunit"
|
||||
expect(response.status).to eq(404)
|
||||
end
|
||||
|
||||
context "with non-admin users on production" do
|
||||
before do
|
||||
# We need to call sign_in before stubbing the method because SessionController#become
|
||||
# checks for the current env when the file is loaded.
|
||||
# We need to make sure become is called once before stubbing, or the method
|
||||
# wont'be available for future tests if this one runs first.
|
||||
sign_in(Fabricate(:user))
|
||||
Rails.env.stubs(:production?).returns(true)
|
||||
end
|
||||
it "hides page for anon in production" do
|
||||
production_sign_in(nil)
|
||||
get "/theme-qunit"
|
||||
expect(response.status).to eq(404)
|
||||
end
|
||||
|
||||
it "regular users cannot see the page" do
|
||||
get "/theme-qunit"
|
||||
expect(response.status).to eq(404)
|
||||
end
|
||||
|
||||
it "anons cannot see the page" do
|
||||
sign_out
|
||||
get "/theme-qunit"
|
||||
expect(response.status).to eq(404)
|
||||
end
|
||||
end
|
||||
|
||||
context "with admin users" do
|
||||
before { sign_in(Fabricate(:admin)) }
|
||||
|
||||
context "when no theme is specified" do
|
||||
it "renders a list of themes and components that have tests" do
|
||||
get "/theme-qunit"
|
||||
expect(response.status).to eq(200)
|
||||
[theme, component, disabled_component].each do |t|
|
||||
expect(response.body).to include(t.name)
|
||||
expect(response.body).to include("/theme-qunit?id=#{t.id}")
|
||||
end
|
||||
expect(response.body).not_to include(theme_without_tests.name)
|
||||
expect(response.body).not_to include("/theme-qunit?id=#{theme_without_tests.id}")
|
||||
end
|
||||
end
|
||||
|
||||
it "can specify theme by id" do
|
||||
get "/theme-qunit?id=#{theme.id}"
|
||||
expect(response.status).to eq(200)
|
||||
expect(response.body).to include("/theme-javascripts/tests/#{theme.id}-")
|
||||
end
|
||||
|
||||
it "can specify theme by name" do
|
||||
get "/theme-qunit?name=#{theme.name}"
|
||||
expect(response.status).to eq(200)
|
||||
expect(response.body).to include("/theme-javascripts/tests/#{theme.id}-")
|
||||
end
|
||||
|
||||
it "can specify theme by url" do
|
||||
theme.build_remote_theme(remote_url: "git@github.com:discourse/discourse.git").save!
|
||||
theme.save!
|
||||
get "/theme-qunit?url=#{theme.remote_theme.remote_url}"
|
||||
expect(response.status).to eq(200)
|
||||
expect(response.body).to include("/theme-javascripts/tests/#{theme.id}-")
|
||||
end
|
||||
|
||||
it "themes qunit page includes all the JS/CSS it needs" do
|
||||
get "/theme-qunit?id=#{theme.id}"
|
||||
expect(response.status).to eq(200)
|
||||
expect(response.body).to include("/stylesheets/color_definitions_base_")
|
||||
expect(response.body).to include("/stylesheets/desktop_")
|
||||
expect(response.body).to include("* https://qunitjs.com/") # inlined QUnit CSS
|
||||
expect(response.body).to include("/assets/locales/en.js")
|
||||
expect(response.body).to include("/test-support.js")
|
||||
expect(response.body).to include("/test-site-settings.js")
|
||||
expect(response.body).to include("/assets/markdown-it-bundle.js")
|
||||
expect(response.body).to include("/assets/admin.js")
|
||||
expect(response.body).to match(/\/theme-javascripts\/\h{40}\.js/)
|
||||
expect(response.body).to include("/theme-javascripts/tests/#{theme.id}-")
|
||||
end
|
||||
end
|
||||
it "shows page for admin in production" do
|
||||
production_sign_in(Fabricate(:admin))
|
||||
get "/theme-qunit"
|
||||
expect(response.status).to eq(200)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
describe "Theme qunit testing", type: :system do
|
||||
let!(:theme_without_tests) { Fabricate(:theme, name: "no-tests-guy") }
|
||||
let!(:theme_with_test) do
|
||||
t = Fabricate(:theme, name: "My Theme")
|
||||
t = Fabricate(:theme, name: "Theme With Tests")
|
||||
t.set_field(target: :tests_js, type: :js, name: "acceptance/some-test.js", value: <<~JS)
|
||||
import { module, test } from "qunit";
|
||||
|
||||
|
@ -12,16 +13,27 @@ describe "Theme qunit testing", type: :system do
|
|||
});
|
||||
});
|
||||
JS
|
||||
t.build_remote_theme(remote_url: "https://example.com/mytheme")
|
||||
t.save!
|
||||
t
|
||||
end
|
||||
|
||||
it "can run theme tests correctly" do
|
||||
it "lists themes and can run tests by id, name and url" do
|
||||
visit "/theme-qunit"
|
||||
|
||||
expect(page).to have_css("a[href^='/theme-qunit?id=']", count: 1)
|
||||
|
||||
find("a[href=\"/theme-qunit?id=#{theme_with_test.id}\"]").click
|
||||
|
||||
success_count = find("#qunit-testresult-display .passed").text
|
||||
expect(success_count).to eq("1")
|
||||
|
||||
visit "/theme-qunit?name=#{theme_with_test.name}"
|
||||
success_count = find("#qunit-testresult-display .passed").text
|
||||
expect(success_count).to eq("1")
|
||||
|
||||
visit "/theme-qunit?url=#{theme_with_test.remote_theme.remote_url}"
|
||||
success_count = find("#qunit-testresult-display .passed").text
|
||||
expect(success_count).to eq("1")
|
||||
end
|
||||
end
|
||||
|
|
Loading…
Reference in New Issue