ckeditor5 1.15.8 → 1.15.10
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile +6 -5
- data/README.md +3 -0
- data/lib/ckeditor5/rails/cdn/ckbox_bundle.rb +2 -2
- data/lib/ckeditor5/rails/cdn/helpers.rb +6 -0
- data/lib/ckeditor5/rails/context/helpers.rb +1 -1
- data/lib/ckeditor5/rails/editor/editable_height_normalizer.rb +50 -0
- data/lib/ckeditor5/rails/editor/helpers/config_helpers.rb +3 -3
- data/lib/ckeditor5/rails/editor/helpers/editor_helpers.rb +5 -4
- data/lib/ckeditor5/rails/editor/props.rb +3 -20
- data/lib/ckeditor5/rails/engine.rb +3 -2
- data/lib/ckeditor5/rails/plugins/simple_upload_adapter.rb +1 -1
- data/lib/ckeditor5/rails/presets/plugins_builder.rb +9 -9
- data/lib/ckeditor5/rails/presets/preset_builder.rb +6 -9
- data/lib/ckeditor5/rails/version.rb +1 -1
- data/lib/ckeditor5/rails/version_detector.rb +6 -0
- data/spec/lib/ckeditor5/rails/assets/asset_bundle_hml_serializer_spec.rb +111 -0
- data/spec/lib/ckeditor5/rails/assets/assets_bundle_spec.rb +191 -0
- data/spec/lib/ckeditor5/rails/cdn/ckbox_bundle_spec.rb +69 -0
- data/spec/lib/ckeditor5/rails/cdn/ckeditor_bundle_spec.rb +72 -0
- data/spec/lib/ckeditor5/rails/cdn/helpers_spec.rb +235 -0
- data/spec/lib/ckeditor5/rails/context/helpers_spec.rb +67 -0
- data/spec/lib/ckeditor5/rails/context/props_spec.rb +70 -0
- data/spec/lib/ckeditor5/rails/editor/editable_height_normalizer_spec.rb +50 -0
- data/spec/lib/ckeditor5/rails/editor/helpers/config_helpers_spec.rb +52 -0
- data/spec/lib/ckeditor5/rails/editor/helpers/editor_helpers_spec.rb +192 -0
- data/spec/lib/ckeditor5/rails/editor/props_inline_plugin_spec.rb +43 -0
- data/spec/lib/ckeditor5/rails/editor/props_plugin_spec.rb +66 -0
- data/spec/lib/ckeditor5/rails/editor/props_spec.rb +104 -0
- data/spec/lib/ckeditor5/rails/engine_spec.rb +88 -0
- data/spec/lib/ckeditor5/rails/hooks/form_spec.rb +203 -0
- data/spec/lib/ckeditor5/rails/hooks/simple_form_spec.rb +100 -0
- data/spec/lib/ckeditor5/rails/presets/manager_spec.rb +100 -0
- data/spec/lib/ckeditor5/rails/presets/plugins_builder_spec.rb +98 -0
- data/spec/lib/ckeditor5/rails/presets/preset_builder_spec.rb +347 -0
- data/spec/lib/ckeditor5/rails/presets/toolbar_builder_spec.rb +70 -0
- data/spec/lib/ckeditor5/rails/semver_spec.rb +58 -0
- data/spec/lib/ckeditor5/rails/version_detector_spec.rb +131 -0
- data/spec/lib/ckeditor5/rails/version_spec.rb +25 -0
- data/spec/spec_helper.rb +8 -2
- data/spec/support/test_models.rb +6 -0
- metadata +49 -2
@@ -0,0 +1,203 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
RSpec.describe CKEditor5::Rails::Hooks::Form do
|
6
|
+
describe CKEditor5::Rails::Hooks::Form::EditorInputBuilder do
|
7
|
+
let(:post) { Post.new(content: 'Initial content') }
|
8
|
+
let(:builder) { described_class.new(:post, post, template) }
|
9
|
+
let(:template) do
|
10
|
+
ActionView::Base.new(ActionView::LookupContext.new([]), {}, nil)
|
11
|
+
end
|
12
|
+
|
13
|
+
before do
|
14
|
+
template.ckeditor5_assets(version: '34.1.0')
|
15
|
+
end
|
16
|
+
|
17
|
+
describe '#build_editor' do
|
18
|
+
subject(:rendered_editor) { builder.build_editor(:content) }
|
19
|
+
|
20
|
+
it 'renders ckeditor element' do
|
21
|
+
attrs = {
|
22
|
+
name: 'post[content]',
|
23
|
+
id: 'post_content',
|
24
|
+
type: 'ClassicEditor',
|
25
|
+
translations: '[{"import_name":"ckeditor5/translations/en.js"}]',
|
26
|
+
watchdog: 'true'
|
27
|
+
}
|
28
|
+
|
29
|
+
expect(rendered_editor).to have_tag('ckeditor-component', with: attrs)
|
30
|
+
end
|
31
|
+
|
32
|
+
context 'with custom attributes' do
|
33
|
+
subject(:rendered_editor) do
|
34
|
+
builder.build_editor(:content, class: 'custom-class', id: 'custom-id', name: 'custom-name')
|
35
|
+
end
|
36
|
+
|
37
|
+
it 'respects custom HTML attributes' do
|
38
|
+
expect(rendered_editor).to have_tag('ckeditor-component', with: {
|
39
|
+
class: 'custom-class',
|
40
|
+
id: 'custom-id',
|
41
|
+
name: 'custom-name'
|
42
|
+
})
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
context 'with as parameter' do
|
47
|
+
subject(:rendered_editor) do
|
48
|
+
builder.build_editor(:content, as: 'custom_field')
|
49
|
+
end
|
50
|
+
|
51
|
+
it 'uses custom field name' do
|
52
|
+
expect(rendered_editor).to have_tag('ckeditor-component', with: {
|
53
|
+
name: 'post[custom_field]'
|
54
|
+
})
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
context 'without object_name' do
|
59
|
+
let(:builder) { described_class.new('', post, template) }
|
60
|
+
|
61
|
+
it 'uses method name as field name' do
|
62
|
+
expect(rendered_editor).to have_tag('ckeditor-component', with: {
|
63
|
+
name: 'content'
|
64
|
+
})
|
65
|
+
end
|
66
|
+
|
67
|
+
context 'with as parameter' do
|
68
|
+
subject(:rendered_editor) do
|
69
|
+
builder.build_editor(:content, as: 'custom_field')
|
70
|
+
end
|
71
|
+
|
72
|
+
it 'uses as parameter as field name' do
|
73
|
+
expect(rendered_editor).to have_tag('ckeditor-component', with: {
|
74
|
+
name: 'custom_field'
|
75
|
+
})
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
context 'with initial data handling' do
|
81
|
+
before do
|
82
|
+
allow(template).to receive(:ckeditor5_editor)
|
83
|
+
end
|
84
|
+
|
85
|
+
context 'when object responds to the method' do
|
86
|
+
it 'passes object method value as initial_data' do
|
87
|
+
builder.build_editor(:content)
|
88
|
+
|
89
|
+
expect(template).to have_received(:ckeditor5_editor)
|
90
|
+
.with(hash_including(initial_data: 'Initial content'))
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
context 'when object does not respond to the method' do
|
95
|
+
let(:post) { double('Post') }
|
96
|
+
|
97
|
+
it 'passes options initial_data value' do
|
98
|
+
builder.build_editor(:content, initial_data: 'Provided content')
|
99
|
+
|
100
|
+
expect(template).to have_received(:ckeditor5_editor)
|
101
|
+
.with(hash_including(initial_data: 'Provided content'))
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
context 'with validation classes handling' do
|
107
|
+
before do
|
108
|
+
allow(template).to receive(:ckeditor5_editor)
|
109
|
+
end
|
110
|
+
|
111
|
+
context 'when object has errors on the field' do
|
112
|
+
let(:post) do
|
113
|
+
instance_double('Post', errors: { content: ['is invalid'] })
|
114
|
+
end
|
115
|
+
|
116
|
+
it 'adds is-invalid class' do
|
117
|
+
builder.build_editor(:content, class: 'custom-class')
|
118
|
+
|
119
|
+
expect(template).to have_received(:ckeditor5_editor)
|
120
|
+
.with(hash_including(class: 'custom-class is-invalid'))
|
121
|
+
end
|
122
|
+
|
123
|
+
it 'adds is-invalid class when no initial class exists' do
|
124
|
+
builder.build_editor(:content)
|
125
|
+
|
126
|
+
expect(template).to have_received(:ckeditor5_editor)
|
127
|
+
.with(hash_including(class: 'is-invalid'))
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
context 'when object has no errors' do
|
132
|
+
let(:post) do
|
133
|
+
instance_double('Post', errors: {})
|
134
|
+
end
|
135
|
+
|
136
|
+
it 'keeps original class unchanged' do
|
137
|
+
builder.build_editor(:content, class: 'custom-class')
|
138
|
+
|
139
|
+
expect(template).to have_received(:ckeditor5_editor)
|
140
|
+
.with(hash_including(class: 'custom-class'))
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
context 'when object does not respond to errors' do
|
145
|
+
let(:post) { double('Post') }
|
146
|
+
|
147
|
+
it 'keeps original class unchanged' do
|
148
|
+
builder.build_editor(:content, class: 'custom-class')
|
149
|
+
|
150
|
+
expect(template).to have_received(:ckeditor5_editor)
|
151
|
+
.with(hash_including(class: 'custom-class'))
|
152
|
+
end
|
153
|
+
end
|
154
|
+
end
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
describe CKEditor5::Rails::Hooks::Form::FormBuilderExtension do
|
159
|
+
let(:template) { instance_double('ActionView::Base') }
|
160
|
+
let(:object) { double('Post') }
|
161
|
+
let(:builder) do
|
162
|
+
Class.new do
|
163
|
+
include CKEditor5::Rails::Hooks::Form::FormBuilderExtension
|
164
|
+
attr_reader :object_name, :object, :template
|
165
|
+
|
166
|
+
def initialize(object_name, object, template)
|
167
|
+
@object_name = object_name
|
168
|
+
@object = object
|
169
|
+
@template = template
|
170
|
+
end
|
171
|
+
end.new('post', object, template)
|
172
|
+
end
|
173
|
+
|
174
|
+
describe '#ckeditor5' do
|
175
|
+
let(:input_builder) { instance_double(CKEditor5::Rails::Hooks::Form::EditorInputBuilder) }
|
176
|
+
|
177
|
+
before do
|
178
|
+
allow(CKEditor5::Rails::Hooks::Form::EditorInputBuilder)
|
179
|
+
.to receive(:new)
|
180
|
+
.with('post', object, template)
|
181
|
+
.and_return(input_builder)
|
182
|
+
allow(input_builder).to receive(:build_editor)
|
183
|
+
end
|
184
|
+
|
185
|
+
it 'creates EditorInputBuilder with correct parameters' do
|
186
|
+
builder.ckeditor5(:content, class: 'custom-class')
|
187
|
+
|
188
|
+
expect(CKEditor5::Rails::Hooks::Form::EditorInputBuilder)
|
189
|
+
.to have_received(:new)
|
190
|
+
.with('post', object, template)
|
191
|
+
end
|
192
|
+
|
193
|
+
it 'calls build_editor with correct parameters' do
|
194
|
+
options = { class: 'custom-class' }
|
195
|
+
builder.ckeditor5(:content, options)
|
196
|
+
|
197
|
+
expect(input_builder)
|
198
|
+
.to have_received(:build_editor)
|
199
|
+
.with(:content, options)
|
200
|
+
end
|
201
|
+
end
|
202
|
+
end
|
203
|
+
end
|
@@ -0,0 +1,100 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
RSpec.describe CKEditor5::Rails::Hooks::SimpleForm::CKEditor5Input do
|
6
|
+
let(:template) { instance_double('ActionView::Base') }
|
7
|
+
let(:object) { double('Post', content: 'Initial content') }
|
8
|
+
let(:object_name) { 'post' }
|
9
|
+
let(:builder) do
|
10
|
+
double('FormBuilder',
|
11
|
+
object: object,
|
12
|
+
object_name: object_name,
|
13
|
+
template: template)
|
14
|
+
end
|
15
|
+
let(:attribute_name) { :content }
|
16
|
+
let(:input_html_options) { {} }
|
17
|
+
let(:input_options) { {} }
|
18
|
+
|
19
|
+
subject(:input) do
|
20
|
+
described_class.new(builder, attribute_name, nil, input_html_options, input_options)
|
21
|
+
end
|
22
|
+
|
23
|
+
before do
|
24
|
+
allow(template).to receive(:ckeditor5_editor)
|
25
|
+
end
|
26
|
+
|
27
|
+
describe '#input' do
|
28
|
+
it 'renders ckeditor with default options' do
|
29
|
+
input.input
|
30
|
+
|
31
|
+
expect(template).to have_received(:ckeditor5_editor).with(
|
32
|
+
hash_including(
|
33
|
+
preset: :default,
|
34
|
+
type: :classic,
|
35
|
+
config: nil,
|
36
|
+
initial_data: 'Initial content',
|
37
|
+
name: 'post[content]',
|
38
|
+
class: [{}, :required] # Simple Form adds these classes by default
|
39
|
+
)
|
40
|
+
)
|
41
|
+
end
|
42
|
+
|
43
|
+
context 'with custom options' do
|
44
|
+
let(:input_options) do
|
45
|
+
{
|
46
|
+
preset: :custom_preset,
|
47
|
+
type: :inline,
|
48
|
+
config: { toolbar: [:bold] }
|
49
|
+
}
|
50
|
+
end
|
51
|
+
let(:input_html_options) do
|
52
|
+
{ class: 'custom-class', id: 'custom-id' }
|
53
|
+
end
|
54
|
+
|
55
|
+
it 'renders ckeditor with merged options' do
|
56
|
+
input.input
|
57
|
+
|
58
|
+
expect(template).to have_received(:ckeditor5_editor).with(
|
59
|
+
hash_including(
|
60
|
+
preset: :custom_preset,
|
61
|
+
type: :inline,
|
62
|
+
config: { toolbar: [:bold] },
|
63
|
+
initial_data: 'Initial content',
|
64
|
+
name: 'post[content]',
|
65
|
+
class: [{ class: 'custom-class', id: 'custom-id' }, :required]
|
66
|
+
)
|
67
|
+
)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
context 'when object does not respond to attribute' do
|
72
|
+
let(:object) { double('Post') }
|
73
|
+
let(:input_options) { { initial_data: 'Provided content' } }
|
74
|
+
|
75
|
+
it 'uses initial_data from options' do
|
76
|
+
input.input
|
77
|
+
|
78
|
+
expect(template).to have_received(:ckeditor5_editor).with(
|
79
|
+
hash_including(initial_data: 'Provided content')
|
80
|
+
)
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
context 'with wrapper options' do
|
85
|
+
let(:wrapper_options) { { wrapper_class: 'wrapper' } }
|
86
|
+
let(:input_html_options) { { class: 'input' } }
|
87
|
+
|
88
|
+
it 'merges wrapper options with input options' do
|
89
|
+
input.input(wrapper_options)
|
90
|
+
|
91
|
+
expect(template).to have_received(:ckeditor5_editor).with(
|
92
|
+
hash_including(
|
93
|
+
class: [{ class: 'input' }, :required],
|
94
|
+
wrapper_class: 'wrapper'
|
95
|
+
)
|
96
|
+
)
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
@@ -0,0 +1,100 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
RSpec.describe CKEditor5::Rails::Presets::Manager do
|
6
|
+
subject(:manager) { described_class.new }
|
7
|
+
|
8
|
+
describe '#initialize' do
|
9
|
+
it 'creates empty presets hash' do
|
10
|
+
expect(manager.presets).to be_a(Hash)
|
11
|
+
end
|
12
|
+
|
13
|
+
it 'defines default preset' do
|
14
|
+
expect(manager.default).to be_a(CKEditor5::Rails::Presets::PresetBuilder)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
describe '#define' do
|
19
|
+
context 'with inheritance' do
|
20
|
+
it 'creates new preset based on default' do
|
21
|
+
manager.define(:custom) do
|
22
|
+
automatic_upgrades enabled: false
|
23
|
+
version '36.0.0'
|
24
|
+
end
|
25
|
+
|
26
|
+
expect(manager[:custom].version).to eq('36.0.0')
|
27
|
+
expect(manager[:custom].type).to eq(manager.default.type)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
context 'without inheritance' do
|
32
|
+
it 'creates completely new preset' do
|
33
|
+
manager.define(:custom, inherit: false) do
|
34
|
+
automatic_upgrades enabled: false
|
35
|
+
version '36.0.0'
|
36
|
+
end
|
37
|
+
|
38
|
+
expect(manager[:custom].version).to eq('36.0.0')
|
39
|
+
expect(manager[:custom].config).to eq({ plugins: [], toolbar: [] })
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
describe '#override/#extend' do
|
45
|
+
before do
|
46
|
+
manager.define(:custom) do
|
47
|
+
automatic_upgrades enabled: false
|
48
|
+
version '35.0.0'
|
49
|
+
toolbar :bold
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
it 'modifies existing preset' do
|
54
|
+
manager.override(:custom) do
|
55
|
+
automatic_upgrades enabled: false
|
56
|
+
version '36.0.0'
|
57
|
+
toolbar :italic
|
58
|
+
end
|
59
|
+
|
60
|
+
expect(manager[:custom].version).to eq('36.0.0')
|
61
|
+
expect(manager[:custom].config[:toolbar][:items]).to eq([:italic])
|
62
|
+
end
|
63
|
+
|
64
|
+
it 'allows using extend as alias for override' do
|
65
|
+
manager.extend(:custom) do
|
66
|
+
automatic_upgrades enabled: false
|
67
|
+
version '36.0.0'
|
68
|
+
end
|
69
|
+
|
70
|
+
expect(manager[:custom].version).to eq('36.0.0')
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
describe '#[]' do
|
75
|
+
it 'returns preset by name' do
|
76
|
+
manager.define(:custom) do
|
77
|
+
automatic_upgrades enabled: false
|
78
|
+
version '36.0.0'
|
79
|
+
end
|
80
|
+
|
81
|
+
expect(manager[:custom]).to be_a(CKEditor5::Rails::Presets::PresetBuilder)
|
82
|
+
expect(manager[:custom].version).to eq('36.0.0')
|
83
|
+
end
|
84
|
+
|
85
|
+
it 'returns nil for non-existent preset' do
|
86
|
+
expect(manager[:non_existent]).to be_nil
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
describe '#default' do
|
91
|
+
it 'has default configuration' do
|
92
|
+
expect(manager.default.version).to eq(CKEditor5::Rails::DEFAULT_CKEDITOR_VERSION)
|
93
|
+
expect(manager.default.type).to eq(:classic)
|
94
|
+
expect(manager.default.automatic_upgrades?).to be true
|
95
|
+
expect(manager.default.menubar?).to be true
|
96
|
+
expect(manager.default.config[:plugins]).not_to be_empty
|
97
|
+
expect(manager.default.config[:toolbar][:items]).not_to be_empty
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
@@ -0,0 +1,98 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
RSpec.describe CKEditor5::Rails::Presets::PluginsBuilder do
|
6
|
+
let(:items) { [] }
|
7
|
+
let(:builder) { described_class.new(items) }
|
8
|
+
|
9
|
+
describe '.create_plugin' do
|
10
|
+
context 'when name is a string' do
|
11
|
+
it 'creates a new PropsPlugin' do
|
12
|
+
plugin = described_class.create_plugin('Test')
|
13
|
+
expect(plugin).to be_a(CKEditor5::Rails::Editor::PropsPlugin)
|
14
|
+
expect(plugin.name).to eq('Test')
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
context 'when name is already a plugin instance' do
|
19
|
+
let(:existing_plugin) { CKEditor5::Rails::Editor::PropsPlugin.new('Test') }
|
20
|
+
|
21
|
+
it 'returns the plugin instance unchanged' do
|
22
|
+
plugin = described_class.create_plugin(existing_plugin)
|
23
|
+
expect(plugin).to eq(existing_plugin)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
describe '#remove' do
|
29
|
+
before do
|
30
|
+
items.push(
|
31
|
+
CKEditor5::Rails::Editor::PropsPlugin.new('Plugin1'),
|
32
|
+
CKEditor5::Rails::Editor::PropsPlugin.new('Plugin2'),
|
33
|
+
CKEditor5::Rails::Editor::PropsPlugin.new('Plugin3')
|
34
|
+
)
|
35
|
+
end
|
36
|
+
|
37
|
+
it 'removes specified plugins' do
|
38
|
+
builder.remove('Plugin1', 'Plugin3')
|
39
|
+
expect(items.map(&:name)).to eq(['Plugin2'])
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
describe '#prepend' do
|
44
|
+
let(:existing_plugin) { CKEditor5::Rails::Editor::PropsPlugin.new('ExistingPlugin') }
|
45
|
+
|
46
|
+
before do
|
47
|
+
items.push(existing_plugin)
|
48
|
+
end
|
49
|
+
|
50
|
+
context 'without before option' do
|
51
|
+
it 'adds plugins at the beginning' do
|
52
|
+
builder.prepend('NewPlugin1', 'NewPlugin2')
|
53
|
+
expect(items.map(&:name)).to eq(%w[NewPlugin1 NewPlugin2 ExistingPlugin])
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
context 'with before option' do
|
58
|
+
it 'adds plugins before specified plugin' do
|
59
|
+
builder.prepend('NewPlugin', before: 'ExistingPlugin')
|
60
|
+
expect(items.map(&:name)).to eq(%w[NewPlugin ExistingPlugin])
|
61
|
+
end
|
62
|
+
|
63
|
+
it 'raises error when target plugin not found' do
|
64
|
+
expect do
|
65
|
+
builder.prepend('NewPlugin', before: 'NonExistent')
|
66
|
+
end.to raise_error(ArgumentError, "Plugin 'NonExistent' not found")
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
describe '#append' do
|
72
|
+
let(:existing_plugin) { CKEditor5::Rails::Editor::PropsPlugin.new('ExistingPlugin') }
|
73
|
+
|
74
|
+
before do
|
75
|
+
items.push(existing_plugin)
|
76
|
+
end
|
77
|
+
|
78
|
+
context 'without after option' do
|
79
|
+
it 'adds plugins at the end' do
|
80
|
+
builder.append('NewPlugin1', 'NewPlugin2')
|
81
|
+
expect(items.map(&:name)).to eq(%w[ExistingPlugin NewPlugin1 NewPlugin2])
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
context 'with after option' do
|
86
|
+
it 'adds plugins after specified plugin' do
|
87
|
+
builder.append('NewPlugin', after: 'ExistingPlugin')
|
88
|
+
expect(items.map(&:name)).to eq(%w[ExistingPlugin NewPlugin])
|
89
|
+
end
|
90
|
+
|
91
|
+
it 'raises error when target plugin not found' do
|
92
|
+
expect do
|
93
|
+
builder.append('NewPlugin', after: 'NonExistent')
|
94
|
+
end.to raise_error(ArgumentError, "Plugin 'NonExistent' not found")
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|