ckeditor5 1.15.8 → 1.15.9

Sign up to get free protection for your applications and to get access to all the features.
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
@@ -0,0 +1,337 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ RSpec.describe CKEditor5::Rails::Presets::PresetBuilder do
6
+ let(:builder) { described_class.new }
7
+
8
+ describe '#initialize' do
9
+ it 'sets default values' do
10
+ expect(builder.version).to be_nil
11
+ expect(builder.premium?).to be false
12
+ expect(builder.cdn).to eq(:jsdelivr)
13
+ expect(builder.translations).to eq([:en])
14
+ expect(builder.license_key).to be_nil
15
+ expect(builder.type).to eq(:classic)
16
+ expect(builder.ckbox).to be_nil
17
+ expect(builder.editable_height).to be_nil
18
+ expect(builder.config).to eq({ plugins: [], toolbar: [] })
19
+ end
20
+
21
+ it 'accepts a configuration block' do
22
+ builder = described_class.new do
23
+ version '35.0.0'
24
+ premium true
25
+ translations :en, :pl
26
+ end
27
+
28
+ expect(builder.version).to eq('35.0.0')
29
+ expect(builder.premium?).to be true
30
+ expect(builder.translations).to eq(%i[en pl])
31
+ end
32
+ end
33
+
34
+ describe '#initialize_copy' do
35
+ let(:original) do
36
+ described_class.new do
37
+ version '35.0.0'
38
+ translations :en, :pl
39
+ ckbox '1.0.0'
40
+ toolbar :bold, :italic
41
+ plugins :Essentials
42
+ end
43
+ end
44
+ let(:copy) { original.dup }
45
+
46
+ it 'creates a deep copy' do
47
+ expect(copy.translations.object_id).not_to eq(original.translations.object_id)
48
+ expect(copy.ckbox.object_id).not_to eq(original.ckbox.object_id)
49
+ expect(copy.config[:plugins].object_id).not_to eq(original.config[:plugins].object_id)
50
+ expect(copy.config[:toolbar].object_id).not_to eq(original.config[:toolbar].object_id)
51
+ end
52
+
53
+ it 'maintains the same values' do
54
+ expect(copy.version).to eq(original.version)
55
+ expect(copy.translations).to eq(original.translations)
56
+ expect(copy.ckbox).to eq(original.ckbox)
57
+
58
+ # Compare toolbar separately
59
+ expect(copy.config[:toolbar][:items]).to eq(original.config[:toolbar][:items])
60
+ expect(copy.config[:toolbar][:shouldNotGroupWhenFull]).to eq(
61
+ original.config[:toolbar][:shouldNotGroupWhenFull]
62
+ )
63
+
64
+ # Compare plugin names
65
+ copy_names = copy.config[:plugins].map { |p| p.name.to_s }
66
+ original_names = original.config[:plugins].map { |p| p.name.to_s }
67
+ expect(copy_names).to eq(original_names)
68
+ end
69
+ end
70
+
71
+ describe 'configuration methods' do
72
+ describe '#automatic_upgrades' do
73
+ it 'enables automatic upgrades' do
74
+ builder.automatic_upgrades
75
+ expect(builder.automatic_upgrades?).to be true
76
+ end
77
+
78
+ it 'detects latest safe version when enabled' do
79
+ allow(CKEditor5::Rails::VersionDetector).to receive(:latest_safe_version)
80
+ .with('35.0.0')
81
+ .and_return('35.1.0')
82
+
83
+ builder.automatic_upgrades
84
+ builder.version '35.0.0'
85
+
86
+ expect(builder.version).to eq('35.1.0')
87
+ end
88
+ end
89
+
90
+ describe '#license_key' do
91
+ it 'sets license key and switches to cloud CDN for non-GPL licenses' do
92
+ builder.license_key('commercial-key')
93
+ expect(builder.license_key).to eq('commercial-key')
94
+ expect(builder.cdn).to eq(:cloud)
95
+ end
96
+
97
+ it 'keeps current CDN for GPL license' do
98
+ builder.cdn(:jsdelivr)
99
+ builder.license_key('GPL')
100
+ expect(builder.cdn).to eq(:jsdelivr)
101
+ end
102
+ end
103
+
104
+ describe '#menubar' do
105
+ it 'configures menubar visibility' do
106
+ builder.menubar(visible: true)
107
+ expect(builder.config[:menuBar]).to eq({ isVisible: true })
108
+ expect(builder.menubar?).to be true
109
+ end
110
+ end
111
+
112
+ describe '#toolbar' do
113
+ it 'configures toolbar items' do
114
+ builder.toolbar(:bold, :italic, should_group_when_full: false)
115
+ expect(builder.config[:toolbar]).to eq({
116
+ items: %i[bold italic],
117
+ shouldNotGroupWhenFull: true
118
+ })
119
+ end
120
+
121
+ it 'doesn\'t override existing toolbar if no items provided' do
122
+ original_config = { items: [:bold], shouldNotGroupWhenFull: true }
123
+ builder.config[:toolbar] = original_config
124
+ builder.toolbar
125
+ expect(builder.config[:toolbar]).to eq(original_config)
126
+ end
127
+
128
+ it 'overrides existing toolbar if items provided' do
129
+ builder.config[:toolbar] = { items: [:bold], shouldNotGroupWhenFull: true }
130
+ builder.toolbar(:italic)
131
+ expect(builder.config[:toolbar][:items]).to eq([:italic])
132
+ end
133
+
134
+ it 'accepts a configuration block' do
135
+ builder.toolbar do
136
+ append :bold, :italic
137
+ prepend :undo
138
+ remove :|
139
+ end
140
+ expect(builder.config[:toolbar][:items]).to include(:bold, :italic, :undo)
141
+ end
142
+ end
143
+
144
+ describe '#plugins' do
145
+ it 'adds plugins' do
146
+ builder.plugins(:Essentials, :Paragraph)
147
+ plugin_names = builder.config[:plugins].map { |p| p.name.to_s }
148
+ expect(plugin_names).to eq(%w[Essentials Paragraph])
149
+ end
150
+
151
+ it 'accepts a configuration block' do
152
+ builder.plugins do
153
+ append :Essentials
154
+ prepend :Paragraph
155
+ remove :Base64UploadAdapter
156
+ end
157
+ plugin_names = builder.config[:plugins].map { |p| p.name.to_s }
158
+ expect(plugin_names).to eq(%w[Paragraph Essentials])
159
+ end
160
+ end
161
+
162
+ describe '#simple_upload_adapter' do
163
+ it 'configures simple upload adapter' do
164
+ builder.simple_upload_adapter('/custom/upload')
165
+ expect(builder.config[:simpleUpload]).to eq({ uploadUrl: '/custom/upload' })
166
+
167
+ plugin_names = builder.config[:plugins].map(&:name)
168
+ expect(plugin_names).to include(:SimpleUploadAdapter)
169
+ end
170
+ end
171
+ end
172
+
173
+ describe '#inline_plugin' do
174
+ let(:plugin_code) do
175
+ <<~JAVASCRIPT
176
+ import Plugin from 'ckeditor5/src/plugin';
177
+ export default class CustomPlugin extends Plugin {
178
+ init() {
179
+ // plugin initialization
180
+ }
181
+ }
182
+ JAVASCRIPT
183
+ end
184
+
185
+ it 'adds inline plugin to configuration' do
186
+ builder.inline_plugin(:CustomPlugin, plugin_code)
187
+
188
+ plugin = builder.config[:plugins].first
189
+ expect(plugin).to be_a(CKEditor5::Rails::Editor::PropsInlinePlugin)
190
+ expect(plugin.name).to eq(:CustomPlugin)
191
+ expect(plugin.code).to eq(plugin_code)
192
+ end
193
+
194
+ it 'allows multiple inline plugins' do
195
+ builder.inline_plugin(:Plugin1, plugin_code)
196
+ builder.inline_plugin(:Plugin2, plugin_code)
197
+
198
+ plugin_names = builder.config[:plugins].map(&:name)
199
+ expect(plugin_names).to eq(%i[Plugin1 Plugin2])
200
+ end
201
+ end
202
+
203
+ describe '#cdn' do
204
+ it 'returns current cdn when called without arguments' do
205
+ expect(builder.cdn).to eq(:jsdelivr)
206
+ end
207
+
208
+ it 'sets cdn when string/symbol provided' do
209
+ builder.cdn(:cloud)
210
+ expect(builder.cdn).to eq(:cloud)
211
+ end
212
+
213
+ context 'with block' do
214
+ it 'accepts block with correct arity' do
215
+ cdn_block = ->(bundle, version, path) { "#{bundle}/#{version}/#{path}" }
216
+ builder.cdn(&cdn_block)
217
+ expect(builder.cdn).to eq(cdn_block)
218
+ end
219
+
220
+ it 'raises error when block has wrong arity' do
221
+ expect do
222
+ builder.cdn { |bundle| bundle }
223
+ end.to raise_error(ArgumentError, 'Block must accept exactly 3 arguments: bundle, version, path')
224
+ end
225
+
226
+ it 'raises error when block has wrong arity (too many args)' do
227
+ expect do
228
+ builder.cdn { |bundle, version, path, extra| bundle } # rubocop:disable Lint/UnusedBlockArgument
229
+ end.to raise_error(ArgumentError, 'Block must accept exactly 3 arguments: bundle, version, path')
230
+ end
231
+ end
232
+ end
233
+
234
+ describe '#type' do
235
+ it 'returns current type when called without arguments' do
236
+ expect(builder.type).to eq(:classic)
237
+ end
238
+
239
+ it 'sets type when valid type provided' do
240
+ allow(CKEditor5::Rails::Editor::Props).to receive(:valid_editor_type?)
241
+ .with(:inline)
242
+ .and_return(true)
243
+
244
+ builder.type(:inline)
245
+ expect(builder.type).to eq(:inline)
246
+ end
247
+
248
+ it 'raises error when invalid type provided' do
249
+ allow(CKEditor5::Rails::Editor::Props).to receive(:valid_editor_type?)
250
+ .with(:invalid)
251
+ .and_return(false)
252
+
253
+ expect do
254
+ builder.type(:invalid)
255
+ end.to raise_error(ArgumentError, 'Invalid editor type: invalid')
256
+ end
257
+ end
258
+
259
+ describe '#to_h_with_overrides' do
260
+ let(:builder) do
261
+ described_class.new do
262
+ version '35.0.0'
263
+ premium true
264
+ translations :en, :pl
265
+ end
266
+ end
267
+
268
+ it 'returns hash with default values' do
269
+ result = builder.to_h_with_overrides
270
+ expect(result).to include(
271
+ version: '35.0.0',
272
+ premium: true,
273
+ translations: %i[en pl]
274
+ )
275
+ end
276
+
277
+ it 'applies overrides' do
278
+ result = builder.to_h_with_overrides(
279
+ version: '36.0.0',
280
+ premium: false,
281
+ translations: [:en]
282
+ )
283
+ expect(result).to include(
284
+ version: '36.0.0',
285
+ premium: false,
286
+ translations: [:en]
287
+ )
288
+ end
289
+ end
290
+
291
+ describe '#language' do
292
+ it 'returns language config when called without arguments' do
293
+ builder.language(:pl, content: :en)
294
+ expect(builder.language).to eq({ ui: :pl, content: :en })
295
+ end
296
+
297
+ it 'sets both UI and content language to same value by default' do
298
+ builder.language(:pl)
299
+ expect(builder.config[:language]).to eq({ ui: :pl, content: :pl })
300
+ end
301
+
302
+ it 'allows different UI and content languages' do
303
+ builder.language(:pl, content: :en)
304
+ expect(builder.config[:language]).to eq({ ui: :pl, content: :en })
305
+ end
306
+ end
307
+
308
+ describe '#deep_copy_toolbar' do
309
+ context 'with array toolbar' do
310
+ it 'returns duplicated array' do
311
+ original = %i[bold italic]
312
+ copy = builder.send(:deep_copy_toolbar, original)
313
+ expect(copy.object_id).not_to eq(original.object_id)
314
+ expect(copy).to eq(original)
315
+ end
316
+ end
317
+
318
+ context 'with hash toolbar' do
319
+ it 'returns deep copy of toolbar config' do
320
+ original = {
321
+ items: %i[bold italic],
322
+ shouldNotGroupWhenFull: true
323
+ }
324
+ copy = builder.send(:deep_copy_toolbar, original)
325
+
326
+ expect(copy[:items].object_id).not_to eq(original[:items].object_id)
327
+ expect(copy).to eq(original)
328
+ end
329
+ end
330
+
331
+ context 'with nil toolbar' do
332
+ it 'returns empty hash' do
333
+ expect(builder.send(:deep_copy_toolbar, nil)).to eq({})
334
+ end
335
+ end
336
+ end
337
+ end
@@ -0,0 +1,70 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ RSpec.describe CKEditor5::Rails::Presets::ToolbarBuilder do
6
+ let(:items) { %i[bold italic | link] }
7
+ let(:builder) { described_class.new(items) }
8
+
9
+ describe '#initialize' do
10
+ it 'creates a builder with given items' do
11
+ expect(builder.items).to eq(%i[bold italic | link])
12
+ end
13
+ end
14
+
15
+ describe '#remove' do
16
+ it 'removes specified items' do
17
+ builder.remove(:italic, :|)
18
+ expect(builder.items).to eq(%i[bold link])
19
+ end
20
+
21
+ it 'ignores non-existent items' do
22
+ builder.remove(:nonexistent)
23
+ expect(builder.items).to eq(%i[bold italic | link])
24
+ end
25
+ end
26
+
27
+ describe '#prepend' do
28
+ context 'without before option' do
29
+ it 'adds items at the beginning' do
30
+ builder.prepend(:underline, :strike)
31
+ expect(builder.items).to eq(%i[underline strike bold italic | link])
32
+ end
33
+ end
34
+
35
+ context 'with before option' do
36
+ it 'adds items before specified item' do
37
+ builder.prepend(:underline, before: :italic)
38
+ expect(builder.items).to eq(%i[bold underline italic | link])
39
+ end
40
+
41
+ it 'raises error when target item not found' do
42
+ expect do
43
+ builder.prepend(:underline, before: :nonexistent)
44
+ end.to raise_error(ArgumentError, "Item 'nonexistent' not found in array")
45
+ end
46
+ end
47
+ end
48
+
49
+ describe '#append' do
50
+ context 'without after option' do
51
+ it 'adds items at the end' do
52
+ builder.append(:underline, :strike)
53
+ expect(builder.items).to eq(%i[bold italic | link underline strike])
54
+ end
55
+ end
56
+
57
+ context 'with after option' do
58
+ it 'adds items after specified item' do
59
+ builder.append(:underline, after: :italic)
60
+ expect(builder.items).to eq(%i[bold italic underline | link])
61
+ end
62
+
63
+ it 'raises error when target item not found' do
64
+ expect do
65
+ builder.append(:underline, after: :nonexistent)
66
+ end.to raise_error(ArgumentError, "Item 'nonexistent' not found in array")
67
+ end
68
+ end
69
+ end
70
+ end
@@ -42,4 +42,62 @@ RSpec.describe CKEditor5::Rails::Semver do
42
42
  expect(semver.version).to eq(version)
43
43
  end
44
44
  end
45
+
46
+ describe '#<=>' do
47
+ let(:version1) { described_class.new('1.2.3') }
48
+
49
+ it 'compares versions correctly' do
50
+ expect(version1).to be < described_class.new('1.2.4')
51
+ expect(version1).to be < described_class.new('1.3.0')
52
+ expect(version1).to be < described_class.new('2.0.0')
53
+ expect(version1).to be > described_class.new('1.2.2')
54
+ expect(version1).to be > described_class.new('1.1.9')
55
+ expect(version1).to be > described_class.new('0.9.9')
56
+ expect(version1).to eq described_class.new('1.2.3')
57
+ end
58
+
59
+ it 'returns nil when comparing with non-Semver object' do
60
+ expect(version1 <=> 'not a version').to be_nil
61
+ end
62
+ end
63
+
64
+ describe '#safe_update?' do
65
+ let(:base_version) { described_class.new('1.2.3') }
66
+
67
+ context 'when major version changes' do
68
+ it 'returns false for major version increase' do
69
+ expect(base_version.safe_update?('2.0.0')).to be false
70
+ end
71
+
72
+ it 'returns false for major version decrease' do
73
+ expect(base_version.safe_update?('0.2.3')).to be false
74
+ end
75
+ end
76
+
77
+ context 'when minor version changes' do
78
+ it 'returns true for minor version increase' do
79
+ expect(base_version.safe_update?('1.3.0')).to be true
80
+ end
81
+
82
+ it 'returns false for minor version decrease' do
83
+ expect(base_version.safe_update?('1.1.9')).to be false
84
+ end
85
+ end
86
+
87
+ context 'when patch version changes' do
88
+ it 'returns true for patch version increase' do
89
+ expect(base_version.safe_update?('1.2.4')).to be true
90
+ end
91
+
92
+ it 'returns false for patch version decrease' do
93
+ expect(base_version.safe_update?('1.2.2')).to be false
94
+ end
95
+ end
96
+
97
+ context 'when version is the same' do
98
+ it 'returns false for identical version' do
99
+ expect(base_version.safe_update?('1.2.3')).to be false
100
+ end
101
+ end
102
+ end
45
103
  end
@@ -0,0 +1,131 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ RSpec.describe CKEditor5::Rails::VersionDetector do
6
+ let(:current_version) { '35.1.0' }
7
+
8
+ let(:npm_response) do
9
+ {
10
+ 'versions' => {
11
+ '34.0.0' => {},
12
+ '34.1.0' => {},
13
+ '35.0.0' => {},
14
+ '35.1.0' => {},
15
+ '35.2.0' => {},
16
+ '36.0.0' => {},
17
+ '35.2.1-dev' => {},
18
+ '36.0.0-nightly' => {}
19
+ }
20
+ }.to_json
21
+ end
22
+
23
+ let(:success_response) do
24
+ double('Net::HTTPSuccess',
25
+ body: npm_response,
26
+ is_a?: true)
27
+ end
28
+
29
+ before do
30
+ described_class.instance.clear_cache!
31
+
32
+ allow(Net::HTTP).to receive(:new).and_return(
33
+ double('Net::HTTP').tap do |http|
34
+ allow(http).to receive(:use_ssl=)
35
+ allow(http).to receive(:open_timeout=)
36
+ allow(http).to receive(:read_timeout=)
37
+ allow(http).to receive(:get).and_return(success_response)
38
+ end
39
+ )
40
+ end
41
+
42
+ describe '.latest_safe_version' do
43
+ before do
44
+ described_class.instance.clear_cache!
45
+ setup_http_mock(success_response)
46
+ end
47
+
48
+ it 'returns the latest safe version' do
49
+ expect(described_class.latest_safe_version(current_version)).to eq('35.2.0')
50
+ end
51
+
52
+ it 'caches the result' do
53
+ first_call = described_class.latest_safe_version(current_version)
54
+
55
+ # Simulate different NPM response
56
+ allow(success_response).to receive(:body).and_return(
57
+ { 'versions' => { '35.3.0' => {} } }.to_json
58
+ )
59
+
60
+ second_call = described_class.latest_safe_version(current_version)
61
+
62
+ expect(first_call).to eq(second_call)
63
+ end
64
+ end
65
+
66
+ describe 'error handling' do
67
+ before do
68
+ described_class.instance.clear_cache!
69
+ end
70
+
71
+ context 'when HTTP request fails' do
72
+ before do
73
+ allow(Net::HTTP).to receive(:new).and_raise(StandardError.new('Connection failed'))
74
+ allow_any_instance_of(Kernel).to receive(:warn)
75
+ end
76
+
77
+ it 'returns nil and logs warning' do
78
+ expect_any_instance_of(Kernel).to receive(:warn).with('Error fetching versions: Connection failed')
79
+ expect(described_class.latest_safe_version(current_version)).to be_nil
80
+ end
81
+ end
82
+
83
+ context 'when response is not successful' do
84
+ let(:error_response) do
85
+ double('Net::HTTPNotFound',
86
+ is_a?: false)
87
+ end
88
+
89
+ before do
90
+ setup_http_mock(error_response)
91
+ allow_any_instance_of(Kernel).to receive(:warn)
92
+ end
93
+
94
+ it 'returns nil and logs warning' do
95
+ expect_any_instance_of(Kernel).to receive(:warn).with('Failed to fetch CKEditor versions')
96
+ expect(described_class.latest_safe_version(current_version)).to be_nil
97
+ end
98
+ end
99
+ end
100
+
101
+ describe 'version filtering' do
102
+ before do
103
+ described_class.instance.clear_cache!
104
+ setup_http_mock(success_response)
105
+ end
106
+
107
+ it 'ignores nightly and dev versions' do
108
+ latest = described_class.latest_safe_version(current_version)
109
+ expect(latest).not_to include('nightly')
110
+ expect(latest).not_to include('dev')
111
+ end
112
+
113
+ it 'only returns versions safe to update to' do
114
+ expect(described_class.latest_safe_version('35.0.0')).to eq('35.2.0')
115
+ expect(described_class.latest_safe_version('34.0.0')).to eq('34.1.0')
116
+ end
117
+ end
118
+
119
+ private
120
+
121
+ def setup_http_mock(response) # rubocop:disable Metrics/AbcSize
122
+ allow(Net::HTTP).to receive(:new).and_return(
123
+ double('Net::HTTP').tap do |http|
124
+ allow(http).to receive(:use_ssl=)
125
+ allow(http).to receive(:open_timeout=)
126
+ allow(http).to receive(:read_timeout=)
127
+ allow(http).to receive(:get).and_return(response)
128
+ end
129
+ )
130
+ end
131
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ RSpec.describe CKEditor5::Rails do
6
+ describe 'VERSION' do
7
+ it 'is defined as a string' do
8
+ expect(described_class::VERSION).to be_a(String)
9
+ end
10
+
11
+ it 'follows semantic versioning format' do
12
+ expect(described_class::VERSION).to match(/^\d+\.\d+\.\d+$/)
13
+ end
14
+ end
15
+
16
+ describe 'DEFAULT_CKEDITOR_VERSION' do
17
+ it 'is defined as a string' do
18
+ expect(described_class::DEFAULT_CKEDITOR_VERSION).to be_a(String)
19
+ end
20
+
21
+ it 'follows semantic versioning format' do
22
+ expect(described_class::DEFAULT_CKEDITOR_VERSION).to match(/^\d+\.\d+\.\d+$/)
23
+ end
24
+ end
25
+ end
data/spec/spec_helper.rb CHANGED
@@ -8,12 +8,13 @@ SimpleCov.start do
8
8
  enable_coverage :line
9
9
 
10
10
  add_filter 'sandbox/'
11
+ add_filter 'spec/'
12
+ add_filter 'lib/ckeditor5/rails/version.rb' # Fix bug in coverage calculation
11
13
  add_group 'Library', 'lib/'
12
14
 
13
15
  track_files 'lib/**/*.rb'
14
16
 
15
- # minimum_coverage 90
16
- # minimum_coverage_by_file 80
17
+ minimum_coverage 98
17
18
 
18
19
  formatters = [
19
20
  SimpleCov::Formatter::HTMLFormatter,
@@ -31,6 +32,9 @@ require 'pry'
31
32
  require 'spec_helper'
32
33
  require 'rspec/rails'
33
34
  require 'rspec/expectations'
35
+ require 'rspec-html-matchers'
36
+
37
+ Dir[File.expand_path('support/**/*.rb', __dir__)].each { |f| require f }
34
38
 
35
39
  Rails.application.initialize!
36
40
 
@@ -57,4 +61,6 @@ RSpec.configure do |config|
57
61
  config.before(:each) do
58
62
  Rails.application.load_seed
59
63
  end
64
+
65
+ config.include RSpecHtmlMatchers
60
66
  end
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Post
4
+ include ActiveModel::Model
5
+ attr_accessor :content
6
+ end