discourse/spec/requests/qunit_controller_spec.rb
Godfrey Chan e1373c3e84
DEV: introduce Embroider behind a flag, and start testing in CI (#23005)
Discourse core now builds and runs with Embroider! This commit adds
the Embroider-based build pipeline (`USE_EMBROIDER=1`) and start
testing it on CI.

The new pipeline uses Embroider's compat mode + webpack bundler to
build discourse code, and leave everything else (admin, wizard,
markdown-it, plugins, etc) exactly the same using the existing
Broccoli-based build as external bundles (<script> tags), passed
to the build as `extraPublicTress` (which just means they get
placed in the `/public` folder).

At runtime, these "external" bundles are glued back together with
`loader.js`. Specifically, the external bundles are compiled as
AMD modules (just as they were before) and registered with the
global `loader.js` instance. They expect their `import`s (outside
of whatever is included in the bundle) to be already available in
the `loader.js` runtime registry.

In the classic build, _every_ module gets compiled into AMD and
gets added to the `loader.js` runtime registry. In Embroider,
the goal is to do this as little as possible, to give the bundler
more flexibility to optimize modules, or omit them entirely if it
is confident that the module is unused (i.e. tree-shaking).

Even in the most compatible mode, there are cases where Embroider
is confident enough to omit modules in the runtime `loader.js`
registry (notably, "auto-imported" non-addon NPM packages). So we
have to be mindful of that an manage those dependencies ourselves,
as seen in #22703.

In the longer term, we will look into using modern features (such
as `import()`) to express these inter-dependencies.

This will only be behind a flag for a short period of time while we
perform some final testing. Within the next few weeks, we intend
to enable by default and remove the flag.

---------

Co-authored-by: David Taylor <david@taylorhq.com>
2023-09-07 13:15:43 +01:00

109 lines
4.1 KiB
Ruby

# 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") }
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
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 "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
end
end