ckeditor5 1.19.5 → 1.20.0

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.
@@ -3,6 +3,7 @@
3
3
  require 'capybara'
4
4
  require 'capybara/rspec'
5
5
  require 'capybara/cuprite'
6
+ require 'rspec/retry'
6
7
 
7
8
  ENV['RAILS_ENV'] ||= 'test'
8
9
 
@@ -40,16 +41,10 @@ Capybara.server = :webrick
40
41
  Capybara.default_driver = :cuprite
41
42
  Capybara.javascript_driver = :cuprite
42
43
 
43
- require 'rspec/retry'
44
-
45
44
  RSpec.configure do |config|
46
- config.verbose_retry = true
47
-
48
45
  config.around :each, :js do |example|
49
- example.run_with_retry retry: 3, retry_wait: 5
46
+ example.run_with_retry retry: 4, retry_wait: 5, default_sleep_interval: 2
50
47
  end
51
-
52
- config.profile_examples = 10
53
48
  end
54
49
 
55
50
  Dir[File.expand_path('support/**/*.rb', __dir__)].each { |f| require f }
@@ -42,6 +42,13 @@ RSpec.describe CKEditor5::Rails::Assets::AssetsBundleHtmlSerializer do
42
42
  })
43
43
  end
44
44
 
45
+ it 'should not include importmap if not requested' do
46
+ serializer = described_class.new(bundle, importmap: false)
47
+ html = serializer.to_html
48
+
49
+ expect(html).not_to have_tag('script', with: { type: 'importmap' })
50
+ end
51
+
45
52
  it 'includes import map' do
46
53
  expect(html).to have_tag('script', with: { type: 'importmap' }) do
47
54
  with_text(%r{"@ckeditor/script2":"https://cdn\.com/script2\.js"})
@@ -131,13 +138,6 @@ RSpec.describe CKEditor5::Rails::Assets::AssetsBundleHtmlSerializer do
131
138
  nonce: 'true'
132
139
  })
133
140
  end
134
-
135
- it 'memoizes scripts import map' do
136
- first_call = serializer.send(:scripts_import_map_tag)
137
- second_call = serializer.send(:scripts_import_map_tag)
138
-
139
- expect(first_call.object_id).to eq(second_call.object_id)
140
- end
141
141
  end
142
142
 
143
143
  describe '.url_resource_preload_type' do
@@ -153,17 +153,60 @@ RSpec.describe CKEditor5::Rails::Assets::AssetsBundleHtmlSerializer do
153
153
  expect(described_class.url_resource_preload_type('file.unknown')).to eq('fetch')
154
154
  end
155
155
  end
156
+ end
156
157
 
157
- describe '#looks_like_url? (private)' do
158
- subject(:serializer) { described_class.new(CKEditor5::Rails::Assets::AssetsBundle.new) }
158
+ RSpec.describe CKEditor5::Rails::Assets::AssetsImportMap do
159
+ let(:scripts) do
160
+ [
161
+ CKEditor5::Rails::Assets::JSUrlImportMeta.new(
162
+ 'https://cdn.com/script1.js',
163
+ window_name: 'WindowScript'
164
+ ),
165
+ CKEditor5::Rails::Assets::JSUrlImportMeta.new(
166
+ 'https://cdn.com/script2.js',
167
+ import_name: '@ckeditor/module'
168
+ ),
169
+ CKEditor5::Rails::Assets::JSUrlImportMeta.new(
170
+ 'https://cdn.com/script3.js',
171
+ import_name: 'https://example.com/module'
172
+ )
173
+ ]
174
+ end
175
+
176
+ let(:bundle) { CKEditor5::Rails::Assets::AssetsBundle.new(scripts: scripts) }
177
+ subject(:import_map) { described_class.new(bundle) }
178
+
179
+ describe '#to_json' do
180
+ it 'includes only ESM scripts without URL-like imports' do
181
+ json = JSON.parse(import_map.to_json)
182
+ expect(json['imports']).to eq({
183
+ '@ckeditor/module' => 'https://cdn.com/script2.js'
184
+ })
185
+ end
186
+ end
187
+
188
+ describe '#to_html' do
189
+ it 'generates script tag with import map' do
190
+ html = import_map.to_html
191
+ expect(html).to have_tag('script', with: { type: 'importmap', nonce: 'true' }) do
192
+ with_text('{"imports":{"@ckeditor/module":"https://cdn.com/script2.js"}}')
193
+ end
194
+ end
195
+ end
159
196
 
197
+ describe '#looks_like_url? (private)' do
160
198
  it 'returns false for invalid URIs' do
161
- expect(serializer.send(:looks_like_url?, '@ckeditor/foo')).to be false
162
- expect(serializer.send(:looks_like_url?, 'http')).to be false
163
- expect(serializer.send(:looks_like_url?, 'invalid')).to be false
164
- expect(serializer.send(:looks_like_url?, 'http://[invalid')).to be false
165
- expect(serializer.send(:looks_like_url?, "http://example.com\nmalicious")).to be false
166
- expect(serializer.send(:looks_like_url?, 'http://<invalid>')).to be false
199
+ expect(import_map.send(:looks_like_url?, '@ckeditor/foo')).to be false
200
+ expect(import_map.send(:looks_like_url?, 'http')).to be false
201
+ expect(import_map.send(:looks_like_url?, 'invalid')).to be false
202
+ expect(import_map.send(:looks_like_url?, 'http://[invalid')).to be false
203
+ expect(import_map.send(:looks_like_url?, "http://example.com\nmalicious")).to be false
204
+ expect(import_map.send(:looks_like_url?, 'http://<invalid>')).to be false
205
+ end
206
+
207
+ it 'returns true for valid HTTP(S) URLs' do
208
+ expect(import_map.send(:looks_like_url?, 'http://example.com')).to be true
209
+ expect(import_map.send(:looks_like_url?, 'https://cdn.com/script.js')).to be true
167
210
  end
168
211
  end
169
212
  end
@@ -3,7 +3,16 @@
3
3
  require 'spec_helper'
4
4
 
5
5
  RSpec.describe CKEditor5::Rails::Cdn::Helpers do
6
- let(:test_class) { Class.new { include CKEditor5::Rails::Cdn::Helpers } }
6
+ let(:test_class) do
7
+ Class.new do
8
+ include CKEditor5::Rails::Cdn::Helpers
9
+
10
+ def importmap_rendered?
11
+ false
12
+ end
13
+ end
14
+ end
15
+
7
16
  let(:helper) { test_class.new }
8
17
  let(:preset) do
9
18
  CKEditor5::Rails::Presets::PresetBuilder.new do
@@ -32,10 +41,6 @@ RSpec.describe CKEditor5::Rails::Cdn::Helpers do
32
41
 
33
42
  describe '#ckeditor5_assets' do
34
43
  context 'with valid preset' do
35
- it 'returns serialized bundle html' do
36
- expect(helper.ckeditor5_assets(preset: :default)).to eq(bundle_html)
37
- end
38
-
39
44
  it 'creates base bundle' do
40
45
  expect(CKEditor5::Rails::Cdn::CKEditorBundle).to receive(:new)
41
46
  .with(
@@ -218,6 +223,37 @@ RSpec.describe CKEditor5::Rails::Cdn::Helpers do
218
223
  .to raise_error(ArgumentError, /forgot to define version/)
219
224
  end
220
225
  end
226
+
227
+ context 'when Rails.application.importmap is defined' do
228
+ before do
229
+ allow(helper).to receive(:importmap_available?).and_return(true)
230
+ allow(helper).to receive(:importmap_rendered?).and_return(false)
231
+ end
232
+
233
+ it 'returns nil and stores html tags in context' do
234
+ result = helper.ckeditor5_assets(preset: :default)
235
+ expect(result).to be_nil
236
+ expect(context[:html_tags]).to eq(bundle_html)
237
+ end
238
+
239
+ it 'raise exception if importmap_rendered?' do
240
+ allow(helper).to receive(:importmap_rendered?).and_return(true)
241
+ expect { helper.ckeditor5_assets(preset: :default) }
242
+ .to raise_error(CKEditor5::Rails::Cdn::Helpers::ImportmapAlreadyRenderedError)
243
+ end
244
+ end
245
+
246
+ context 'when importmap_available? is true returns html' do
247
+ before do
248
+ allow(helper).to receive(:importmap_available?).and_return(nil)
249
+ end
250
+
251
+ it 'returns html directly' do
252
+ result = helper.ckeditor5_assets(preset: :default)
253
+ expect(result).to eq(bundle_html)
254
+ expect(context[:html_tags]).to be_nil
255
+ end
256
+ end
221
257
  end
222
258
 
223
259
  describe 'cdn helper methods' do
@@ -102,5 +102,37 @@ RSpec.describe CKEditor5::Rails::Engine do
102
102
  end
103
103
  end
104
104
  end
105
+
106
+ describe 'importmap initializer' do
107
+ context 'when Importmap is defined' do
108
+ module Importmap # rubocop:disable Lint/ConstantDefinitionInBlock
109
+ module ImportmapTagsHelper; end
110
+ end
111
+
112
+ it 'prepends CKEditor5 importmap helper' do
113
+ initializer = described_class.initializers.find { |i| i.name == 'ckeditor5.importmap' }
114
+ initializer.run(Rails.application)
115
+
116
+ expect(Importmap::ImportmapTagsHelper.ancestors)
117
+ .to include(CKEditor5::Rails::Hooks::Importmap::ImportmapTagsHelper)
118
+ end
119
+ end
120
+
121
+ context 'when Importmap is not defined' do
122
+ before do
123
+ @importmap = Importmap if defined?(Importmap)
124
+ Object.send(:remove_const, :Importmap) if defined?(Importmap)
125
+ end
126
+
127
+ after do
128
+ Object.const_set(:Importmap, @importmap) if @importmap
129
+ end
130
+
131
+ it 'does not raise error' do
132
+ initializer = described_class.initializers.find { |i| i.name == 'ckeditor5.importmap' }
133
+ expect { initializer.run(Rails.application) }.not_to raise_error
134
+ end
135
+ end
136
+ end
105
137
  end
106
138
  end
@@ -0,0 +1,131 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ RSpec.describe CKEditor5::Rails::Hooks::Importmap::ImportmapTagsHelper do
6
+ let(:test_class) do
7
+ Class.new do
8
+ include ActionView::Helpers::TagHelper
9
+ include CKEditor5::Rails::Hooks::Importmap::ImportmapTagsHelper
10
+
11
+ def javascript_importmap_module_preload_tags(*)
12
+ '<script type="modulepreload">preload</script>'
13
+ end
14
+
15
+ def javascript_import_module_tag(*)
16
+ '<script type="module">import</script>'
17
+ end
18
+
19
+ def javascript_inline_importmap_tag(json)
20
+ "<script type=\"importmap\">#{json}</script>"
21
+ end
22
+ end
23
+ end
24
+
25
+ let(:helper) { test_class.new }
26
+ let(:importmap) { double('Importmap', to_json: '{"imports":{}}') }
27
+
28
+ before do
29
+ allow(Rails.application).to receive(:importmap).and_return(importmap)
30
+ end
31
+
32
+ describe '#javascript_importmap_tags' do
33
+ context 'without CKEditor context' do
34
+ it 'generates basic importmap tags' do
35
+ result = helper.javascript_importmap_tags
36
+
37
+ expect(result).to include('modulepreload')
38
+ expect(result).to include('module')
39
+ expect(helper).to be_importmap_rendered
40
+ end
41
+ end
42
+
43
+ context 'with CKEditor context' do
44
+ let(:bundle) do
45
+ CKEditor5::Rails::Assets::AssetsBundle.new(
46
+ scripts: [
47
+ CKEditor5::Rails::Assets::JSUrlImportMeta.new(
48
+ 'https://cdn.com/script.js',
49
+ import_name: '@ckeditor/module'
50
+ )
51
+ ]
52
+ )
53
+ end
54
+
55
+ let(:html_tags) { '<script src="ckeditor.js"></script>' }
56
+
57
+ before do
58
+ helper.instance_variable_set(:@__ckeditor_context, {
59
+ bundle: bundle,
60
+ html_tags: html_tags
61
+ })
62
+ end
63
+
64
+ it 'merges CKEditor importmap with base importmap' do
65
+ result = CGI.unescapeHTML(helper.javascript_importmap_tags)
66
+
67
+ expect(result).to include('@ckeditor/module')
68
+ expect(result).to include('https://cdn.com/script.js')
69
+ expect(result).to include(html_tags)
70
+ end
71
+
72
+ it 'handles invalid JSON gracefully' do
73
+ allow(importmap).to receive(:to_json).and_return('invalid json')
74
+
75
+ expect(Rails.logger).to receive(:error).with(/Failed to merge import maps/)
76
+ helper.javascript_importmap_tags
77
+ end
78
+
79
+ it 'processes importmap in correct order when context is present' do
80
+ html = CGI.unescapeHTML(helper.javascript_importmap_tags)
81
+ doc = Nokogiri::HTML::DocumentFragment.parse(html)
82
+ scripts = doc.css('script')
83
+
84
+ expect(scripts[0]['type']).to eq('importmap')
85
+ expect(scripts[1]['type']).to eq('modulepreload')
86
+ expect(scripts[2]['type']).to eq('module')
87
+ expect(scripts[3]['src']).to eq('ckeditor.js')
88
+ end
89
+
90
+ it 'adds inline importmap when context is missing' do
91
+ helper.instance_variable_set(:@__ckeditor_context, nil)
92
+ html = CGI.unescapeHTML(helper.javascript_importmap_tags)
93
+ doc = Nokogiri::HTML::DocumentFragment.parse(html)
94
+ scripts = doc.css('script')
95
+
96
+ expect(scripts[0]['type']).to eq('importmap')
97
+ expect(doc.css('script[src="ckeditor.js"]')).to be_empty
98
+ end
99
+ end
100
+ end
101
+
102
+ describe '#importmap_rendered?' do
103
+ it 'returns false by default' do
104
+ expect(helper).not_to be_importmap_rendered
105
+ end
106
+
107
+ it 'returns true after rendering importmap' do
108
+ helper.javascript_importmap_tags
109
+ expect(helper).to be_importmap_rendered
110
+ end
111
+ end
112
+
113
+ describe '#merge_import_maps_json (private)' do
114
+ it 'correctly merges two valid import maps' do
115
+ map_a = '{"imports":{"a":"1"}}'
116
+ map_b = '{"imports":{"b":"2"}}'
117
+
118
+ result = JSON.parse(helper.send(:merge_import_maps_json, map_a, map_b))
119
+ expect(result['imports']).to eq('a' => '1', 'b' => '2')
120
+ end
121
+
122
+ it 'returns second map when first is invalid' do
123
+ map_a = 'invalid json'
124
+ map_b = '{"imports":{"b":"2"}}'
125
+
126
+ expect(Rails.logger).to receive(:error).with(/Failed to merge import maps/)
127
+ result = helper.send(:merge_import_maps_json, map_a, map_b)
128
+ expect(result).to eq(map_b)
129
+ end
130
+ end
131
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ckeditor5
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.19.5
4
+ version: 1.20.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Mateusz Bagiński
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2024-11-29 00:00:00.000000000 Z
12
+ date: 2024-12-02 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rails
@@ -70,6 +70,7 @@ files:
70
70
  - lib/ckeditor5/rails/engine.rb
71
71
  - lib/ckeditor5/rails/helpers.rb
72
72
  - lib/ckeditor5/rails/hooks/form.rb
73
+ - lib/ckeditor5/rails/hooks/importmap.rb
73
74
  - lib/ckeditor5/rails/hooks/simple_form.rb
74
75
  - lib/ckeditor5/rails/plugins/simple_upload_adapter.rb
75
76
  - lib/ckeditor5/rails/plugins/wproofreader.rb
@@ -89,7 +90,7 @@ files:
89
90
  - spec/e2e/spec_helper.rb
90
91
  - spec/e2e/support/eventually.rb
91
92
  - spec/e2e/support/form_helpers.rb
92
- - spec/lib/ckeditor5/rails/assets/asset_bundle_hml_serializer_spec.rb
93
+ - spec/lib/ckeditor5/rails/assets/assets_bundle_hml_serializer_spec.rb
93
94
  - spec/lib/ckeditor5/rails/assets/assets_bundle_spec.rb
94
95
  - spec/lib/ckeditor5/rails/cdn/ckbox_bundle_spec.rb
95
96
  - spec/lib/ckeditor5/rails/cdn/ckeditor_bundle_spec.rb
@@ -108,6 +109,7 @@ files:
108
109
  - spec/lib/ckeditor5/rails/editor/props_spec.rb
109
110
  - spec/lib/ckeditor5/rails/engine_spec.rb
110
111
  - spec/lib/ckeditor5/rails/hooks/form_spec.rb
112
+ - spec/lib/ckeditor5/rails/hooks/importmap_spec.rb
111
113
  - spec/lib/ckeditor5/rails/hooks/simple_form_spec.rb
112
114
  - spec/lib/ckeditor5/rails/plugins/wproofreader_spec.rb
113
115
  - spec/lib/ckeditor5/rails/presets/manager_spec.rb
@@ -154,7 +156,7 @@ test_files:
154
156
  - spec/e2e/spec_helper.rb
155
157
  - spec/e2e/support/eventually.rb
156
158
  - spec/e2e/support/form_helpers.rb
157
- - spec/lib/ckeditor5/rails/assets/asset_bundle_hml_serializer_spec.rb
159
+ - spec/lib/ckeditor5/rails/assets/assets_bundle_hml_serializer_spec.rb
158
160
  - spec/lib/ckeditor5/rails/assets/assets_bundle_spec.rb
159
161
  - spec/lib/ckeditor5/rails/cdn/ckbox_bundle_spec.rb
160
162
  - spec/lib/ckeditor5/rails/cdn/ckeditor_bundle_spec.rb
@@ -173,6 +175,7 @@ test_files:
173
175
  - spec/lib/ckeditor5/rails/editor/props_spec.rb
174
176
  - spec/lib/ckeditor5/rails/engine_spec.rb
175
177
  - spec/lib/ckeditor5/rails/hooks/form_spec.rb
178
+ - spec/lib/ckeditor5/rails/hooks/importmap_spec.rb
176
179
  - spec/lib/ckeditor5/rails/hooks/simple_form_spec.rb
177
180
  - spec/lib/ckeditor5/rails/plugins/wproofreader_spec.rb
178
181
  - spec/lib/ckeditor5/rails/presets/manager_spec.rb