2019-04-30 10:27:42 +10:00
# frozen_string_literal: true
2022-07-28 05:27:38 +03:00
RSpec . describe ThemeJavascriptCompiler do
2022-09-01 11:50:46 +01:00
let ( :compiler ) { ThemeJavascriptCompiler . new ( 1 , "marks" ) }
2019-01-17 11:46:11 +00:00
2020-03-06 10:35:52 -06:00
describe "#append_raw_template" do
2020-05-05 12:15:03 -04:00
it "uses the correct template paths" do
2020-03-06 10:35:52 -06:00
template = "<h1>hello</h1>"
name = "/path/to/templates1"
compiler . append_raw_template ( " #{ name } .raw" , template )
2022-10-18 18:20:10 +01:00
expect ( compiler . raw_content . to_s ) . to include ( "addRawTemplate( \" #{ name } \" " )
2020-03-06 10:35:52 -06:00
name = "/path/to/templates2"
compiler . append_raw_template ( " #{ name } .hbr" , template )
2022-10-18 18:20:10 +01:00
expect ( compiler . raw_content . to_s ) . to include ( "addRawTemplate( \" #{ name } \" " )
2020-03-06 10:35:52 -06:00
name = "/path/to/templates3"
compiler . append_raw_template ( " #{ name } .hbs" , template )
2022-10-18 18:20:10 +01:00
expect ( compiler . raw_content . to_s ) . to include ( "addRawTemplate( \" #{ name } .hbs \" " )
2020-03-06 10:35:52 -06:00
end
end
2021-04-12 15:02:58 +03:00
describe "#append_ember_template" do
2022-09-01 11:50:46 +01:00
it "maintains module names so that discourse-boot.js can correct them" do
2021-04-12 15:02:58 +03:00
compiler . append_ember_template ( "/connectors/blah-1" , "{{var}}" )
2022-10-18 18:20:10 +01:00
expect ( compiler . raw_content . to_s ) . to include (
2023-09-05 11:16:12 +02:00
"define( \" discourse/theme-1/connectors/blah-1 \" , [ \" exports \" , " ,
2022-10-18 18:20:10 +01:00
)
2021-04-12 15:02:58 +03:00
compiler . append_ember_template ( "connectors/blah-2" , "{{var}}" )
2022-10-18 18:20:10 +01:00
expect ( compiler . raw_content . to_s ) . to include (
2023-09-05 11:16:12 +02:00
"define( \" discourse/theme-1/connectors/blah-2 \" , [ \" exports \" , " ,
2022-10-18 18:20:10 +01:00
)
2021-04-12 15:02:58 +03:00
compiler . append_ember_template ( "javascripts/connectors/blah-3" , "{{var}}" )
2022-10-18 18:20:10 +01:00
expect ( compiler . raw_content . to_s ) . to include (
2023-09-05 11:16:12 +02:00
"define( \" discourse/theme-1/javascripts/connectors/blah-3 \" , [ \" exports \" , " ,
2022-10-18 18:20:10 +01:00
)
2022-09-01 11:50:46 +01:00
end
end
describe "connector module name handling" do
it "separates colocated connectors to avoid module name clash" do
# Colocated under `/connectors`
compiler = ThemeJavascriptCompiler . new ( 1 , "marks" )
2022-10-19 10:49:01 +01:00
compiler . append_tree (
{
"connectors/outlet/blah-1.hbs" => "{{var}}" ,
"connectors/outlet/blah-1.js" => "console.log('test')" ,
},
)
2022-10-18 18:20:10 +01:00
expect ( compiler . raw_content . to_s ) . to include ( "discourse/theme-1/connectors/outlet/blah-1" )
expect ( compiler . raw_content . to_s ) . to include (
"discourse/theme-1/templates/connectors/outlet/blah-1" ,
)
2022-10-19 10:49:01 +01:00
expect ( JSON . parse ( compiler . source_map ) [ "sources" ] ) . to contain_exactly (
"connectors/outlet/blah-1.js" ,
"templates/connectors/outlet/blah-1.js" ,
)
2022-09-01 11:50:46 +01:00
# Colocated under `/templates/connectors`
compiler = ThemeJavascriptCompiler . new ( 1 , "marks" )
2022-10-19 10:49:01 +01:00
compiler . append_tree (
{
"templates/connectors/outlet/blah-1.hbs" => "{{var}}" ,
"templates/connectors/outlet/blah-1.js" => "console.log('test')" ,
},
)
2022-10-18 18:20:10 +01:00
expect ( compiler . raw_content . to_s ) . to include ( "discourse/theme-1/connectors/outlet/blah-1" )
expect ( compiler . raw_content . to_s ) . to include (
"discourse/theme-1/templates/connectors/outlet/blah-1" ,
)
2022-10-19 10:49:01 +01:00
expect ( JSON . parse ( compiler . source_map ) [ "sources" ] ) . to contain_exactly (
"connectors/outlet/blah-1.js" ,
"templates/connectors/outlet/blah-1.js" ,
)
2022-09-01 11:50:46 +01:00
# Not colocated
compiler = ThemeJavascriptCompiler . new ( 1 , "marks" )
2022-10-19 10:49:01 +01:00
compiler . append_tree (
{
"templates/connectors/outlet/blah-1.hbs" => "{{var}}" ,
"connectors/outlet/blah-1.js" => "console.log('test')" ,
},
)
2022-10-18 18:20:10 +01:00
expect ( compiler . raw_content . to_s ) . to include ( "discourse/theme-1/connectors/outlet/blah-1" )
expect ( compiler . raw_content . to_s ) . to include (
"discourse/theme-1/templates/connectors/outlet/blah-1" ,
)
2022-10-19 10:49:01 +01:00
expect ( JSON . parse ( compiler . source_map ) [ "sources" ] ) . to contain_exactly (
"connectors/outlet/blah-1.js" ,
"templates/connectors/outlet/blah-1.js" ,
)
2022-09-01 11:50:46 +01:00
end
end
describe "error handling" do
it "handles syntax errors in raw templates" do
expect do
compiler . append_raw_template ( "sometemplate.hbr" , "{{invalidtemplate" )
end . to raise_error ( ThemeJavascriptCompiler :: CompileError , /Parse error on line 1/ )
end
it "handles syntax errors in ember templates" do
expect do
compiler . append_ember_template ( "sometemplate" , "{{invalidtemplate" )
end . to raise_error ( ThemeJavascriptCompiler :: CompileError , /Parse error on line 1/ )
2021-04-12 15:02:58 +03:00
end
end
2022-10-17 15:04:04 +01:00
describe "#append_tree" do
it "can handle multiple modules" do
compiler . append_tree (
{
"discourse/components/mycomponent.js" => <<~ JS ,
import Component from "@glimmer/component" ;
export default class MyComponent extends Component {}
JS
"discourse/templates/components/mycomponent.hbs" => "{{my-component-template}}" ,
},
)
2023-08-18 18:15:23 +01:00
expect ( compiler . raw_content ) . to include (
'define("discourse/theme-1/discourse/components/mycomponent"' ,
)
2022-10-18 18:20:10 +01:00
expect ( compiler . raw_content ) . to include (
'define("discourse/theme-1/discourse/templates/components/mycomponent"' ,
)
2022-10-17 15:04:04 +01:00
end
2022-10-17 14:47:16 +01:00
it "handles colocated components" do
compiler . append_tree (
{
"discourse/components/mycomponent.js" => <<~ JS ,
import Component from "@glimmer/component" ;
export default class MyComponent extends Component {}
JS
"discourse/components/mycomponent.hbs" => "{{my-component-template}}" ,
},
)
2022-10-18 18:20:10 +01:00
expect ( compiler . raw_content ) . to include ( "__COLOCATED_TEMPLATE__ =" )
expect ( compiler . raw_content ) . to include ( "setComponentTemplate" )
2022-10-17 14:47:16 +01:00
end
2022-12-07 14:24:03 +00:00
it "handles colocated admin components" do
compiler . append_tree (
{
"admin/components/mycomponent.js" => <<~ JS ,
import Component from "@glimmer/component" ;
export default class MyComponent extends Component {}
JS
"admin/components/mycomponent.hbs" => "{{my-component-template}}" ,
},
)
expect ( compiler . raw_content ) . to include ( "__COLOCATED_TEMPLATE__ =" )
expect ( compiler . raw_content ) . to include ( "setComponentTemplate" )
end
2022-10-21 19:05:34 +01:00
it "applies theme AST transforms to colocated components" do
compiler = ThemeJavascriptCompiler . new ( 12_345_678_910 , "my theme name" )
compiler . append_tree (
{ "discourse/components/mycomponent.hbs" => '{{theme-i18n "my_translation_key"}}' },
)
template_compiled_line = compiler . raw_content . lines . find { | l | l . include? ( '"block":' ) }
expect ( template_compiled_line ) . to include ( "12345678910" )
end
2022-10-17 14:47:16 +01:00
it "prints error when default export missing" do
compiler . append_tree (
{
"discourse/components/mycomponent.js" => <<~ JS ,
import Component from "@glimmer/component" ;
class MyComponent extends Component {}
JS
"discourse/components/mycomponent.hbs" => "{{my-component-template}}" ,
},
)
2022-10-18 18:20:10 +01:00
expect ( compiler . raw_content ) . to include ( "__COLOCATED_TEMPLATE__ =" )
expect ( compiler . raw_content ) . to include ( "throw new Error" )
2022-10-17 14:47:16 +01:00
end
it "handles template-only components" do
compiler . append_tree (
{ "discourse/components/mycomponent.hbs" => "{{my-component-template}}" },
)
2022-10-18 18:20:10 +01:00
expect ( compiler . raw_content ) . to include ( "__COLOCATED_TEMPLATE__ =" )
expect ( compiler . raw_content ) . to include ( "setComponentTemplate" )
expect ( compiler . raw_content ) . to include ( "@ember/component/template-only" )
end
end
describe "terser compilation" do
it "applies terser and provides sourcemaps" do
sources = {
"multiply.js" => "let multiply = (firstValue, secondValue) => firstValue * secondValue;" ,
"add.js" => "let add = (firstValue, secondValue) => firstValue + secondValue;" ,
}
compiler . append_tree ( sources )
expect ( compiler . content ) . to include ( "multiply" )
expect ( compiler . content ) . to include ( "add" )
map = JSON . parse ( compiler . source_map )
expect ( map [ "sources" ] ) . to contain_exactly ( * sources . keys )
expect ( map [ "sourcesContent" ]. to_s ) . to include ( "let multiply" )
expect ( map [ "sourcesContent" ]. to_s ) . to include ( "let add" )
expect ( map [ "sourceRoot" ] ) . to eq ( "theme-1/" )
end
it "handles invalid JS" do
compiler . append_raw_script ( "filename.js" , "if(someCondition" )
expect ( compiler . content ) . to include ( 'console.error("[THEME 1' )
expect ( compiler . content ) . to include ( "Unexpected token" )
2022-10-17 14:47:16 +01:00
end
2022-10-17 15:04:04 +01:00
end
2023-09-05 11:16:12 +02:00
describe "ember-this-fallback" do
it "applies its transforms" do
compiler . append_tree (
{
"discourse/components/my-component.js" => <<~ JS ,
import Component from "@glimmer/component" ;
export default class MyComponent extends Component {
value = "foo" ;
}
JS
"discourse/components/my-component.hbs" => "{{value}}" ,
},
)
expect ( compiler . raw_content ) . to include ( "ember-this-fallback" )
expect ( compiler . raw_content ) . to include (
"The `value` property path was used in the `discourse/components/my-component.hbs` template without using `this`. This fallback behavior has been deprecated, all properties must be looked up on `this` when used in the template: {{this.value}}" ,
)
end
end
2023-10-02 12:36:06 +02:00
describe "ember-template-imports" do
it "applies its transforms" do
compiler . append_tree ({ "discourse/components/my-component.gjs" => <<~ JS })
import Component from "@glimmer/component" ;
export default class MyComponent extends Component {
< template >
{{ this . value }}
< /template>
value = "foo";
}
JS
expect(compiler.raw_content).to include(
"define(\"discourse/ theme - 1 / discourse / components / my - component \ ", [ \" exports \" ," ,
)
expect ( compiler . raw_content ) . to include ( "_defineProperty(this, \" value \" , \" foo \" );" )
expect ( compiler . raw_content ) . to include ( "setComponentTemplate" )
expect ( compiler . raw_content ) . to include ( "createTemplateFactory" )
end
end
2019-01-17 11:46:11 +00:00
end