ckeditor5 1.15.8 → 1.15.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +6 -5
  3. data/README.md +3 -0
  4. data/lib/ckeditor5/rails/cdn/ckbox_bundle.rb +2 -2
  5. data/lib/ckeditor5/rails/cdn/helpers.rb +6 -0
  6. data/lib/ckeditor5/rails/context/helpers.rb +1 -1
  7. data/lib/ckeditor5/rails/editor/editable_height_normalizer.rb +50 -0
  8. data/lib/ckeditor5/rails/editor/helpers/config_helpers.rb +3 -3
  9. data/lib/ckeditor5/rails/editor/helpers/editor_helpers.rb +5 -4
  10. data/lib/ckeditor5/rails/editor/props.rb +3 -20
  11. data/lib/ckeditor5/rails/plugins/simple_upload_adapter.rb +1 -1
  12. data/lib/ckeditor5/rails/presets/preset_builder.rb +2 -3
  13. data/lib/ckeditor5/rails/version.rb +1 -1
  14. data/lib/ckeditor5/rails/version_detector.rb +6 -0
  15. data/spec/lib/ckeditor5/rails/assets/asset_bundle_hml_serializer_spec.rb +104 -0
  16. data/spec/lib/ckeditor5/rails/assets/assets_bundle_spec.rb +191 -0
  17. data/spec/lib/ckeditor5/rails/cdn/ckbox_bundle_spec.rb +69 -0
  18. data/spec/lib/ckeditor5/rails/cdn/ckeditor_bundle_spec.rb +72 -0
  19. data/spec/lib/ckeditor5/rails/cdn/helpers_spec.rb +217 -0
  20. data/spec/lib/ckeditor5/rails/context/helpers_spec.rb +67 -0
  21. data/spec/lib/ckeditor5/rails/context/props_spec.rb +70 -0
  22. data/spec/lib/ckeditor5/rails/editor/editable_height_normalizer_spec.rb +50 -0
  23. data/spec/lib/ckeditor5/rails/editor/helpers/config_helpers_spec.rb +52 -0
  24. data/spec/lib/ckeditor5/rails/editor/helpers/editor_helpers_spec.rb +192 -0
  25. data/spec/lib/ckeditor5/rails/editor/props_inline_plugin_spec.rb +43 -0
  26. data/spec/lib/ckeditor5/rails/editor/props_plugin_spec.rb +66 -0
  27. data/spec/lib/ckeditor5/rails/editor/props_spec.rb +104 -0
  28. data/spec/lib/ckeditor5/rails/hooks/form_spec.rb +47 -0
  29. data/spec/lib/ckeditor5/rails/presets/manager_spec.rb +100 -0
  30. data/spec/lib/ckeditor5/rails/presets/plugins_builder_spec.rb +98 -0
  31. data/spec/lib/ckeditor5/rails/presets/preset_builder_spec.rb +337 -0
  32. data/spec/lib/ckeditor5/rails/presets/toolbar_builder_spec.rb +70 -0
  33. data/spec/lib/ckeditor5/rails/semver_spec.rb +58 -0
  34. data/spec/lib/ckeditor5/rails/version_detector_spec.rb +131 -0
  35. data/spec/lib/ckeditor5/rails/version_spec.rb +25 -0
  36. data/spec/spec_helper.rb +8 -2
  37. data/spec/support/test_models.rb +6 -0
  38. metadata +44 -1
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 127f81c39ea4df2b13a4095bd335f7b8698549249851de0f90ed948e309b2ca0
4
- data.tar.gz: cd9711cd4b70b4c89091b166a694065973b4d12eff6d587e8cb761abdcd5b43e
3
+ metadata.gz: 604312ff3ad324ca5ebbccca70efe7157e9ee67608d6a3b8d3b2d4b7c070213b
4
+ data.tar.gz: 8c44e0810acd1bb837cdcc8a37c4fb3051b5323a243e7b5a16341e9c8e3ef9a7
5
5
  SHA512:
6
- metadata.gz: 0b0fd8c78086d0f46b10b63a01a6394b493958d82d022d9cdebae203df0f57fbe396ed02609fc7049d0dbf6415deb8a35eddc88593dcbda51a84f0ae3fbf4f56
7
- data.tar.gz: 8eeea41e9de0d98c7d3613c915f3fb7e93bb55fd80ebe24aa97d7a3761af1a9ed0f6a1f4e502dcff53bc11d4eb04f7776f26d768da2adfdfe73868f1becd3b65
6
+ metadata.gz: 54fc1a049c23a9c45bee8fc307de81f7976407850d068f018e715396b93a47e3c37f77c45682ba7ee4f36fe1d5cef156eeb5791dbf0793c35503a93e09e41f8a
7
+ data.tar.gz: 23a2299e6b8685cf120fa40be70d23737ec68f732e6e96af4428d785234600ab17a24596f4d4794093b14fdd0625b20e3a2953950659e0ab0c9deda7fc2c1cc9
data/Gemfile CHANGED
@@ -13,14 +13,9 @@ group :development do
13
13
  gem 'pry-rails', '~> 0.3', '>= 0.3.11'
14
14
  gem 'rails', '~> 7.0', '>= 7.0.0'
15
15
  gem 'rake', '~> 13.2', '>= 13.2.1'
16
- gem 'rspec', '~> 3.13'
17
- gem 'rspec-expectations', '~> 3.13'
18
- gem 'rspec-rails', '~> 7.0'
19
16
  gem 'rubocop', '~> 1.66', require: false
20
17
  gem 'rubocop-rails', '~> 2.26', '>= 2.26.2', require: false
21
18
  gem 'rubocop-rails-omakase', '~> 1.0.0', require: false
22
- gem 'simplecov', '~> 0.21', '>= 0.21.2', require: false
23
- gem 'simplecov_json_formatter', '~> 0.1.4', require: false
24
19
  gem 'simple_form', '~> 5.3', '>= 5.3.0'
25
20
  gem 'slim', '~> 5.2', '>= 5.2.0'
26
21
  gem 'sprockets-rails', '~> 3.2', '>= 3.2.2'
@@ -29,6 +24,12 @@ end
29
24
 
30
25
  group :test, :development do
31
26
  gem 'capybara', '~> 3.40'
27
+ gem 'rspec', '~> 3.13'
28
+ gem 'rspec-expectations', '~> 3.13'
29
+ gem 'rspec-html-matchers', '~> 0.10.0'
30
+ gem 'rspec-rails', '~> 7.0'
31
+ gem 'simplecov', '~> 0.21', '>= 0.21.2', require: false
32
+ gem 'simplecov_json_formatter', '~> 0.1.4', require: false
32
33
  end
33
34
 
34
35
  gemspec
data/README.md CHANGED
@@ -74,6 +74,9 @@ CKEditor5::Rails.configure do
74
74
  # Optionally, you can specify version of CKEditor 5 to use.
75
75
  # If it's not specified the default version specified in the gem will be used.
76
76
  # version '43.3.1'
77
+
78
+ # Upload images to the server using the simple upload adapter, instead of Base64 encoding.
79
+ # simple_upload_adapter
77
80
  end
78
81
  ```
79
82
 
@@ -22,9 +22,9 @@ module CKEditor5::Rails
22
22
  @scripts ||= [
23
23
  Assets::JSExportsMeta.new(
24
24
  create_cdn_url('ckbox', version, 'ckbox.js'),
25
- *translations_js_exports_meta,
26
25
  window_name: 'CKBox'
27
- )
26
+ ),
27
+ *translations_js_exports_meta
28
28
  ]
29
29
  end
30
30
 
@@ -1,5 +1,11 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require_relative '../semver'
4
+ require_relative '../editor/props'
5
+ require_relative '../editor/helpers/config_helpers'
6
+ require_relative '../presets/manager'
7
+ require_relative '../assets/assets_bundle_html_serializer'
8
+
3
9
  require_relative 'url_generator'
4
10
  require_relative 'ckeditor_bundle'
5
11
  require_relative 'ckbox_bundle'
@@ -7,7 +7,7 @@ module CKEditor5::Rails::Context
7
7
  def ckeditor5_context(**config, &block)
8
8
  context_props = Props.new(config)
9
9
 
10
- tag.send(:'ckeditor-context-component', **context_props.to_attributes, &block)
10
+ tag.public_send(:'ckeditor-context-component', **context_props.to_attributes, &block)
11
11
  end
12
12
  end
13
13
  end
@@ -0,0 +1,50 @@
1
+ # frozen_string_literal: true
2
+
3
+ module CKEditor5::Rails::Editor
4
+ class InvalidEditableHeightError < ArgumentError; end
5
+
6
+ class EditableHeightNormalizer
7
+ def initialize(editor_type)
8
+ @editor_type = editor_type
9
+ end
10
+
11
+ def normalize(value)
12
+ return nil if value.nil?
13
+
14
+ validate_editor_type!
15
+ convert_to_pixel_value(value)
16
+ end
17
+
18
+ private
19
+
20
+ attr_reader :editor_type
21
+
22
+ def validate_editor_type!
23
+ return if editor_type == :classic
24
+
25
+ raise InvalidEditableHeightError,
26
+ 'editable_height can be used only with ClassicEditor'
27
+ end
28
+
29
+ def convert_to_pixel_value(value)
30
+ case value
31
+ when Integer then "#{value}px"
32
+ when String then convert_string_to_pixel_value(value)
33
+ else
34
+ raise_invalid_height_error(value)
35
+ end
36
+ end
37
+
38
+ def convert_string_to_pixel_value(value)
39
+ return value if value.match?(/^\d+px$/)
40
+
41
+ raise_invalid_height_error(value)
42
+ end
43
+
44
+ def raise_invalid_height_error(value)
45
+ raise InvalidEditableHeightError,
46
+ "editable_height must be an integer representing pixels or string ending with 'px'\n" \
47
+ "(e.g. 500 or '500px'). Got: #{value.inspect}"
48
+ end
49
+ end
50
+ end
@@ -1,13 +1,13 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- module CKEditor5::Rails
4
- module Editor::Helpers::Config
3
+ module CKEditor5::Rails::Editor::Helpers
4
+ module Config
5
5
  def ckeditor5_element_ref(selector)
6
6
  { '$element': selector }
7
7
  end
8
8
 
9
9
  def ckeditor5_preset(name = nil, &block)
10
- return Engine.find_preset(name) if name
10
+ return CKEditor5::Rails::Engine.find_preset(name) if name
11
11
 
12
12
  raise ArgumentError, 'Configuration block is required for preset definition' unless block_given?
13
13
 
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require_relative '../../version_detector'
4
+ require_relative '../../presets/preset_builder'
3
5
  require_relative 'config_helpers'
4
6
 
5
7
  module CKEditor5::Rails
@@ -8,7 +10,6 @@ module CKEditor5::Rails
8
10
 
9
11
  class EditorContextError < StandardError; end
10
12
  class PresetNotFoundError < ArgumentError; end
11
- class InvalidEditableHeightError < ArgumentError; end
12
13
 
13
14
  # Creates a CKEditor 5 editor instance
14
15
  #
@@ -45,15 +46,15 @@ module CKEditor5::Rails
45
46
 
46
47
  tag_attributes = html_attributes.merge(editor_props.to_attributes)
47
48
 
48
- tag.send(:'ckeditor-component', **tag_attributes, &block)
49
+ tag.public_send(:'ckeditor-component', **tag_attributes, &block)
49
50
  end
50
51
 
51
52
  def ckeditor5_editable(name = nil, **kwargs, &block)
52
- tag.send(:'ckeditor-editable-component', name: name, **kwargs, &block)
53
+ tag.public_send(:'ckeditor-editable-component', name: name, **kwargs, &block)
53
54
  end
54
55
 
55
56
  def ckeditor5_ui_part(name, **kwargs, &block)
56
- tag.send(:'ckeditor-ui-part-component', name: name, **kwargs, &block)
57
+ tag.public_send(:'ckeditor-ui-part-component', name: name, **kwargs, &block)
57
58
  end
58
59
 
59
60
  def ckeditor5_toolbar(**kwargs)
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require_relative 'props_plugin'
4
+ require_relative 'editable_height_normalizer'
4
5
 
5
6
  module CKEditor5::Rails::Editor
6
7
  class Props
@@ -19,7 +20,7 @@ module CKEditor5::Rails::Editor
19
20
  @watchdog = watchdog
20
21
  @type = type
21
22
  @config = config
22
- @editable_height = normalize_editable_height(editable_height)
23
+ @editable_height = EditableHeightNormalizer.new(type).normalize(editable_height)
23
24
  end
24
25
 
25
26
  def to_attributes
@@ -48,7 +49,7 @@ module CKEditor5::Rails::Editor
48
49
  end
49
50
 
50
51
  def serialize_translations
51
- controller_context[:bundle].translations_scripts.map(&:to_h).to_json
52
+ controller_context[:bundle]&.translations_scripts&.map(&:to_h).to_json || '[]'
52
53
  end
53
54
 
54
55
  def serialize_plugins
@@ -61,23 +62,5 @@ module CKEditor5::Rails::Editor
61
62
  .tap { |cfg| cfg[:licenseKey] = controller_context[:license_key] if controller_context[:license_key] }
62
63
  .to_json
63
64
  end
64
-
65
- def normalize_editable_height(editable_height)
66
- return nil if editable_height.nil?
67
-
68
- unless type == :classic
69
- raise InvalidEditableHeightError,
70
- 'editable_height can be used only with ClassicEditor'
71
- end
72
-
73
- case editable_height
74
- when String, /^\d+px$/ then editable_height
75
- when Integer, /^\d+$/ then "#{editable_height}px"
76
- else
77
- raise InvalidEditableHeightError,
78
- "editable_height must be an integer representing pixels or string ending with 'px'\n" \
79
- "(e.g. 500 or '500px'). Got: #{editable_height.inspect}"
80
- end
81
- end
82
65
  end
83
66
  end
@@ -81,7 +81,7 @@ module CKEditor5::Rails::Plugins
81
81
  JAVASCRIPT
82
82
 
83
83
  def initialize
84
- super(:SimpleUpload, PLUGIN_CODE)
84
+ super(:SimpleUploadAdapter, PLUGIN_CODE)
85
85
  end
86
86
  end
87
87
  end
@@ -104,7 +104,7 @@ module CKEditor5::Rails
104
104
  end
105
105
 
106
106
  def version(version = nil)
107
- return @version.to_s if version.nil?
107
+ return @version&.to_s if version.nil?
108
108
 
109
109
  if @automatic_upgrades && version
110
110
  detected = VersionDetector.latest_safe_version(version)
@@ -164,7 +164,7 @@ module CKEditor5::Rails
164
164
 
165
165
  return unless block
166
166
 
167
- builder = ArrayBuilder.new(@config[:toolbar][:items])
167
+ builder = ToolbarBuilder.new(@config[:toolbar][:items])
168
168
  builder.instance_eval(&block)
169
169
  end
170
170
 
@@ -174,7 +174,6 @@ module CKEditor5::Rails
174
174
 
175
175
  def plugin(name, **kwargs)
176
176
  plugin_obj = PluginsBuilder.create_plugin(name, **kwargs)
177
-
178
177
  @config[:plugins] << plugin_obj
179
178
  plugin_obj
180
179
  end
@@ -2,7 +2,7 @@
2
2
 
3
3
  module CKEditor5
4
4
  module Rails
5
- VERSION = '1.15.8'
5
+ VERSION = '1.15.9'
6
6
 
7
7
  DEFAULT_CKEDITOR_VERSION = '43.3.1'
8
8
  end
@@ -4,6 +4,8 @@ require 'net/http'
4
4
  require 'json'
5
5
  require 'singleton'
6
6
  require 'monitor'
7
+
8
+ require_relative 'version'
7
9
  require_relative 'semver'
8
10
 
9
11
  module CKEditor5::Rails
@@ -22,6 +24,10 @@ module CKEditor5::Rails
22
24
  @monitor = Monitor.new
23
25
  end
24
26
 
27
+ def clear_cache!
28
+ @monitor.synchronize { @cache.clear }
29
+ end
30
+
25
31
  def latest_safe_version(current_version)
26
32
  @monitor.synchronize do
27
33
  cache_key = "#{current_version}_latest"
@@ -0,0 +1,104 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ RSpec.describe CKEditor5::Rails::Assets::AssetsBundleHtmlSerializer do
6
+ let(:test_bundle_class) do
7
+ Class.new(CKEditor5::Rails::Assets::AssetsBundle) do
8
+ attr_accessor :scripts, :stylesheets
9
+
10
+ def initialize(scripts, stylesheets)
11
+ @scripts = scripts
12
+ @stylesheets = stylesheets
13
+ super()
14
+ end
15
+ end
16
+ end
17
+
18
+ let(:bundle) { test_bundle_class.new(scripts, stylesheets) }
19
+
20
+ let(:scripts) do
21
+ [
22
+ CKEditor5::Rails::Assets::JSExportsMeta.new(
23
+ 'https://cdn.com/script1.js',
24
+ window_name: 'CKEditor5'
25
+ ),
26
+ CKEditor5::Rails::Assets::JSExportsMeta.new(
27
+ 'https://cdn.com/script2.js',
28
+ import_name: '@ckeditor/script2'
29
+ )
30
+ ]
31
+ end
32
+
33
+ let(:stylesheets) { ['https://cdn.com/style1.css', 'https://cdn.com/style2.css'] }
34
+ let(:preloads) { bundle.preloads }
35
+
36
+ subject(:serializer) { described_class.new(bundle) }
37
+
38
+ describe '#initialize' do
39
+ context 'with invalid bundle' do
40
+ let(:bundle) { 'not a bundle' }
41
+
42
+ it 'raises TypeError' do
43
+ expect { serializer }.to raise_error(TypeError, 'bundle must be an instance of AssetsBundle')
44
+ end
45
+ end
46
+ end
47
+
48
+ describe '#to_html' do
49
+ subject(:html) { serializer.to_html }
50
+
51
+ it 'includes window scripts' do
52
+ expect(html).to include(
53
+ '<script src="https://cdn.com/script1.js" nonce="true" crossorigin="anonymous">'
54
+ )
55
+ end
56
+
57
+ it 'includes import map' do
58
+ expect(html).to include('type="importmap"')
59
+ expect(html).to include('"@ckeditor/script2":"https://cdn.com/script2.js"')
60
+ end
61
+
62
+ it 'includes stylesheet links' do
63
+ stylesheets.each do |url|
64
+ expect(html).to include("<link href=\"#{url}\" rel=\"stylesheet\" crossorigin=\"anonymous\">")
65
+ end
66
+ end
67
+
68
+ it 'includes preload links' do
69
+ expect(html).to include(
70
+ '<link href="https://cdn.com/style1.css" rel="preload" as="style" crossorigin="anonymous">'
71
+ )
72
+
73
+ expect(html).to include(
74
+ '<link href="https://cdn.com/style2.css" rel="preload" as="style" crossorigin="anonymous">'
75
+ )
76
+
77
+ expect(html).to include(
78
+ '<link href="https://cdn.com/script1.js" rel="preload" as="script" crossorigin="anonymous">'
79
+ )
80
+
81
+ expect(html).to include(
82
+ '<link href="https://cdn.com/script2.js" rel="preload" as="script" crossorigin="anonymous">'
83
+ )
84
+ end
85
+
86
+ it 'includes web component script' do
87
+ expect(html).to include('<script type="module" nonce="true">')
88
+ end
89
+ end
90
+
91
+ describe '.url_resource_preload_type' do
92
+ it 'returns correct type for js files' do
93
+ expect(described_class.url_resource_preload_type('file.js')).to eq('script')
94
+ end
95
+
96
+ it 'returns correct type for css files' do
97
+ expect(described_class.url_resource_preload_type('file.css')).to eq('style')
98
+ end
99
+
100
+ it 'returns fetch for unknown extensions' do
101
+ expect(described_class.url_resource_preload_type('file.unknown')).to eq('fetch')
102
+ end
103
+ end
104
+ end
@@ -0,0 +1,191 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ RSpec.describe CKEditor5::Rails::Assets::AssetsBundle do
6
+ let(:concrete_class) do
7
+ Class.new(described_class) do
8
+ def scripts
9
+ []
10
+ end
11
+
12
+ def stylesheets
13
+ []
14
+ end
15
+ end
16
+ end
17
+
18
+ describe '#initialize' do
19
+ it 'raises error when required methods are not implemented' do
20
+ expect { described_class.new }.to raise_error(NotImplementedError)
21
+ end
22
+
23
+ it 'initializes successfully when required methods are implemented' do
24
+ expect { concrete_class.new }.not_to raise_error
25
+ end
26
+ end
27
+
28
+ describe '#empty?' do
29
+ subject(:bundle) { concrete_class.new }
30
+
31
+ it 'returns true when no assets are present' do
32
+ expect(bundle).to be_empty
33
+ end
34
+ end
35
+
36
+ describe '#translations_scripts' do
37
+ let(:bundle) { concrete_class.new }
38
+ let(:translation_script) { instance_double(CKEditor5::Rails::Assets::JSExportsMeta, translation?: true) }
39
+ let(:regular_script) { instance_double(CKEditor5::Rails::Assets::JSExportsMeta, translation?: false) }
40
+
41
+ before do
42
+ allow(bundle).to receive(:scripts).and_return([translation_script, regular_script])
43
+ end
44
+
45
+ it 'returns only translation scripts' do
46
+ expect(bundle.translations_scripts).to eq([translation_script])
47
+ end
48
+ end
49
+
50
+ describe '#<<' do
51
+ let(:script1) { instance_double(CKEditor5::Rails::Assets::JSExportsMeta) }
52
+ let(:script2) { instance_double(CKEditor5::Rails::Assets::JSExportsMeta) }
53
+ let(:stylesheet1) { '/path/to/style1.css' }
54
+ let(:stylesheet2) { '/path/to/style2.css' }
55
+
56
+ let(:bundle1) do
57
+ Class.new(described_class) do
58
+ attr_writer :scripts, :stylesheets
59
+
60
+ def scripts
61
+ @scripts ||= []
62
+ end
63
+
64
+ def stylesheets
65
+ @stylesheets ||= []
66
+ end
67
+ end.new
68
+ end
69
+
70
+ let(:bundle2) do
71
+ Class.new(described_class) do
72
+ attr_writer :scripts, :stylesheets
73
+
74
+ def scripts
75
+ @scripts ||= []
76
+ end
77
+
78
+ def stylesheets
79
+ @stylesheets ||= []
80
+ end
81
+ end.new
82
+ end
83
+
84
+ before do
85
+ bundle1.scripts = [script1]
86
+ bundle1.stylesheets = [stylesheet1]
87
+ bundle2.scripts = [script2]
88
+ bundle2.stylesheets = [stylesheet2]
89
+ end
90
+
91
+ it 'raises TypeError when argument is not an AssetsBundle' do
92
+ expect { bundle1 << 'not a bundle' }.to raise_error(TypeError)
93
+ end
94
+
95
+ it 'merges scripts and stylesheets from both bundles' do
96
+ bundle1 << bundle2
97
+
98
+ expect(bundle1.scripts).to eq([script1, script2])
99
+ expect(bundle1.stylesheets).to eq([stylesheet1, stylesheet2])
100
+ end
101
+ end
102
+
103
+ describe '#preloads' do
104
+ let(:script1) { instance_double(CKEditor5::Rails::Assets::JSExportsMeta, url: '/js/script1.js') }
105
+ let(:script2) { instance_double(CKEditor5::Rails::Assets::JSExportsMeta, url: '/js/script2.js') }
106
+ let(:stylesheet1) { '/css/style1.css' }
107
+ let(:stylesheet2) { '/css/style2.css' }
108
+
109
+ let(:bundle) do
110
+ Class.new(described_class) do
111
+ attr_writer :scripts, :stylesheets
112
+
113
+ def scripts
114
+ @scripts ||= []
115
+ end
116
+
117
+ def stylesheets
118
+ @stylesheets ||= []
119
+ end
120
+ end.new
121
+ end
122
+
123
+ before do
124
+ bundle.scripts = [script1, script2]
125
+ bundle.stylesheets = [stylesheet1, stylesheet2]
126
+ end
127
+
128
+ it 'returns array of stylesheet paths and script urls' do
129
+ expect(bundle.preloads).to eq([
130
+ '/css/style1.css',
131
+ '/css/style2.css',
132
+ '/js/script1.js',
133
+ '/js/script2.js'
134
+ ])
135
+ end
136
+ end
137
+ end
138
+
139
+ RSpec.describe CKEditor5::Rails::Assets::JSExportsMeta do
140
+ let(:url) { '/path/to/script.js' }
141
+
142
+ describe '#initialize' do
143
+ it 'creates instance with import_name' do
144
+ meta = described_class.new(url, import_name: 'module')
145
+ expect(meta.import_name).to eq('module')
146
+ end
147
+
148
+ it 'creates instance with window_name' do
149
+ meta = described_class.new(url, window_name: 'MyModule')
150
+ expect(meta.window_name).to eq('MyModule')
151
+ end
152
+
153
+ it 'marks as translation when specified' do
154
+ meta = described_class.new(url, translation: true, import_name: 'module')
155
+ expect(meta).to be_translation
156
+ end
157
+ end
158
+ end
159
+
160
+ RSpec.describe CKEditor5::Rails::Assets::JSImportMeta do
161
+ describe '#initialize' do
162
+ it 'raises error when neither import_name nor window_name is provided' do
163
+ expect { described_class.new }.to raise_error(ArgumentError)
164
+ end
165
+
166
+ it 'raises error when import_as is present without import_name' do
167
+ expect { described_class.new(import_as: 'alias', window_name: 'Module') }
168
+ .to raise_error(ArgumentError)
169
+ end
170
+
171
+ it 'creates valid instance with import_name' do
172
+ meta = described_class.new(import_name: 'module')
173
+ expect(meta).to be_esm
174
+ end
175
+
176
+ it 'creates valid instance with window_name' do
177
+ meta = described_class.new(window_name: 'Module')
178
+ expect(meta).to be_window
179
+ end
180
+ end
181
+
182
+ describe '#to_h' do
183
+ it 'returns hash with only present values' do
184
+ meta = described_class.new(import_name: 'module', import_as: 'alias')
185
+ expect(meta.to_h).to eq({
186
+ import_name: 'module',
187
+ import_as: 'alias'
188
+ })
189
+ end
190
+ end
191
+ end
@@ -0,0 +1,69 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ RSpec.describe CKEditor5::Rails::Cdn::CKBoxBundle do
6
+ let(:version) { CKEditor5::Rails::Semver.new('2.6.0') }
7
+ let(:cdn) { :jsdelivr }
8
+ let(:theme) { :lark }
9
+ let(:translations) { [] }
10
+ let(:bundle) { described_class.new(version, theme: theme, cdn: cdn, translations: translations) }
11
+
12
+ describe '#initialize' do
13
+ context 'with valid parameters' do
14
+ it 'creates bundle successfully' do
15
+ expect { bundle }.not_to raise_error
16
+ end
17
+ end
18
+
19
+ context 'with invalid parameters' do
20
+ it 'raises error for invalid version' do
21
+ expect { described_class.new('invalid', theme: theme) }
22
+ .to raise_error(ArgumentError, 'version must be semver')
23
+ end
24
+
25
+ it 'raises error for invalid theme type' do
26
+ expect { described_class.new(version, theme: 123) }
27
+ .to raise_error(ArgumentError, 'theme must be a string or symbol')
28
+ end
29
+
30
+ it 'raises error for invalid translations type' do
31
+ expect { described_class.new(version, theme: theme, translations: 'invalid') }
32
+ .to raise_error(ArgumentError, 'translations must be an array')
33
+ end
34
+ end
35
+ end
36
+
37
+ describe '#scripts' do
38
+ it 'returns array with main script' do
39
+ expect(bundle.scripts.first).to be_a(CKEditor5::Rails::Assets::JSExportsMeta)
40
+ expect(bundle.scripts.first.url).to include('ckbox.js')
41
+ expect(bundle.scripts.first.window_name).to eq('CKBox')
42
+ end
43
+
44
+ context 'with translations' do
45
+ let(:translations) { [:pl] }
46
+
47
+ it 'includes translation scripts' do
48
+ translation_script = bundle.scripts.last
49
+ expect(translation_script.url).to include('translations/pl.js')
50
+ expect(translation_script.window_name).to eq('CKBOX_TRANSLATIONS')
51
+ expect(translation_script.translation?).to be true
52
+ end
53
+ end
54
+ end
55
+
56
+ describe '#stylesheets' do
57
+ it 'returns array with theme stylesheet' do
58
+ expect(bundle.stylesheets.first).to include('styles/themes/lark.css')
59
+ end
60
+
61
+ context 'with custom theme' do
62
+ let(:theme) { :custom }
63
+
64
+ it 'uses custom theme in stylesheet path' do
65
+ expect(bundle.stylesheets.first).to include('styles/themes/custom.css')
66
+ end
67
+ end
68
+ end
69
+ end