# frozen_string_literal: true require 'discourse_js_processor' RSpec.describe DiscourseJsProcessor do describe 'should_transpile?' do it "returns false for empty strings" do expect(DiscourseJsProcessor.should_transpile?(nil)).to eq(false) expect(DiscourseJsProcessor.should_transpile?('')).to eq(false) end it "returns false for a regular js file" do expect(DiscourseJsProcessor.should_transpile?("file.js")).to eq(false) end it "returns true for deprecated .es6 files" do expect(DiscourseJsProcessor.should_transpile?("file.es6")).to eq(true) expect(DiscourseJsProcessor.should_transpile?("file.js.es6")).to eq(true) expect(DiscourseJsProcessor.should_transpile?("file.js.es6.erb")).to eq(true) end end describe "skip_module?" do it "returns false for empty strings" do expect(DiscourseJsProcessor.skip_module?(nil)).to eq(false) expect(DiscourseJsProcessor.skip_module?('')).to eq(false) end it "returns true if the header is present" do expect(DiscourseJsProcessor.skip_module?("// cool comment\n// discourse-skip-module")).to eq(true) end it "returns false if the header is not present" do expect(DiscourseJsProcessor.skip_module?("// just some JS\nconsole.log()")).to eq(false) end end it "correctly transpiles widget hbs" do result = DiscourseJsProcessor.transpile(<<~JS, "blah", "blah/mymodule") import hbs from "discourse/widgets/hbs-compiler"; const template = hbs`{{somevalue}}`; JS expect(result).to eq <<~JS.strip define("blah/mymodule", [], function () { "use strict"; const template = function (attrs, state) { var _r = []; _r.push(somevalue); return _r; }; }); JS end it "correctly transpiles ember hbs" do result = DiscourseJsProcessor.transpile(<<~JS, "blah", "blah/mymodule") import { hbs } from 'ember-cli-htmlbars'; const template = hbs`{{somevalue}}`; JS expect(result).to eq <<~JS.strip define("blah/mymodule", ["@ember/template-factory"], function (_templateFactory) { "use strict"; const template = (0, _templateFactory.createTemplateFactory)( /* {{somevalue}} */ { "id": null, "block": "[[[1,[34,0]]],[],false,[\\"somevalue\\"]]", "moduleName": "(unknown template module)", "isStrictMode": false }); }); JS end describe "Raw template theme transformations" do # For the raw templates, we can easily render them serverside, so let's do that let(:compiler) { DiscourseJsProcessor::Transpiler.new } let(:theme_id) { 22 } let(:helpers) { <<~JS Handlebars.registerHelper('theme-prefix', function(themeId, string) { return `theme_translations.${themeId}.${string}` }) Handlebars.registerHelper('theme-i18n', function(themeId, string) { return `translated(theme_translations.${themeId}.${string})` }) Handlebars.registerHelper('theme-setting', function(themeId, string) { return `setting(${themeId}:${string})` }) Handlebars.registerHelper('dummy-helper', function(string) { return `dummy(${string})` }) JS } let(:mini_racer) { ctx = MiniRacer::Context.new ctx.eval(File.open("#{Rails.root}/app/assets/javascripts/node_modules/handlebars/dist/handlebars.js").read) ctx.eval(helpers) ctx } def render(template) compiled = compiler.compile_raw_template(template, theme_id: theme_id) mini_racer.eval "Handlebars.template(#{compiled.squish})({})" end it 'adds the theme id to the helpers' do # Works normally expect(render("{{theme-prefix 'translation_key'}}")). to eq('theme_translations.22.translation_key') expect(render("{{theme-i18n 'translation_key'}}")). to eq('translated(theme_translations.22.translation_key)') expect(render("{{theme-setting 'setting_key'}}")). to eq('setting(22:setting_key)') # Works when used inside other statements expect(render("{{dummy-helper (theme-prefix 'translation_key')}}")). to eq('dummy(theme_translations.22.translation_key)') end it "doesn't duplicate number parameter inside {{each}}" do expect(compiler.compile_raw_template("{{#each item as |test test2|}}{{theme-setting 'setting_key'}}{{/each}}", theme_id: theme_id)). to include('{"name":"theme-setting","hash":{},"hashTypes":{},"hashContexts":{},"types":["NumberLiteral","StringLiteral"]') # Fail would be if theme-setting is defined with types:["NumberLiteral","NumberLiteral","StringLiteral"] end end describe "Ember template transformations" do # For the Ember (Glimmer) templates, serverside rendering is not trivial, # so we compile the expected result with the standard compiler and compare to the theme compiler let(:theme_id) { 22 } def theme_compile(template) script = <<~JS import { hbs } from 'ember-cli-htmlbars'; export default hbs(#{template.to_json}); JS result = DiscourseJsProcessor.transpile(script, "", "theme/blah", theme_id: theme_id) result.gsub(/\/\*(.*)\*\//m, "/* (js comment stripped) */") end def standard_compile(template) script = <<~JS import { hbs } from 'ember-cli-htmlbars'; export default hbs(#{template.to_json}); JS result = DiscourseJsProcessor.transpile(script, "", "theme/blah") result.gsub(/\/\*(.*)\*\//m, "/* (js comment stripped) */") end it 'adds the theme id to the helpers' do expect( theme_compile "{{theme-prefix 'translation_key'}}" ).to eq( standard_compile "{{theme-prefix #{theme_id} 'translation_key'}}" ) expect( theme_compile "{{theme-i18n 'translation_key'}}" ).to eq( standard_compile "{{theme-i18n #{theme_id} 'translation_key'}}" ) expect( theme_compile "{{theme-setting 'setting_key'}}" ).to eq( standard_compile "{{theme-setting #{theme_id} 'setting_key'}}" ) # Works when used inside other statements expect( theme_compile "{{dummy-helper (theme-prefix 'translation_key')}}" ).to eq( standard_compile "{{dummy-helper (theme-prefix #{theme_id} 'translation_key')}}" ) end end end