dugway 1.0.14 → 1.2.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.
- checksums.yaml +4 -4
- data/.bundle/config +2 -0
- data/.github/workflows/main.yml +1 -1
- data/.gitignore +1 -0
- data/README.md +9 -0
- data/lib/dugway/application.rb +5 -3
- data/lib/dugway/assets/big_cartel_logo.svg +4 -0
- data/lib/dugway/cli/build.rb +18 -1
- data/lib/dugway/cli/server.rb +2 -2
- data/lib/dugway/cli/templates/source/settings.json +8 -0
- data/lib/dugway/cli/validate.rb +20 -2
- data/lib/dugway/controller.rb +5 -1
- data/lib/dugway/liquid/drops/account_drop.rb +4 -0
- data/lib/dugway/liquid/drops/features_drop.rb +144 -0
- data/lib/dugway/liquid/drops/product_drop.rb +8 -0
- data/lib/dugway/liquid/drops/products_drop.rb +1 -1
- data/lib/dugway/liquid/drops/related_products_drop.rb +88 -0
- data/lib/dugway/liquid/drops/theme_drop.rb +23 -0
- data/lib/dugway/liquid/drops/translations_drop.rb +122 -0
- data/lib/dugway/liquifier.rb +44 -8
- data/lib/dugway/store.rb +7 -2
- data/lib/dugway/theme.rb +169 -3
- data/lib/dugway/version.rb +1 -1
- data/lib/dugway.rb +31 -1
- data/locales/storefront.de.yml +79 -0
- data/locales/storefront.en-CA.yml +79 -0
- data/locales/storefront.en-GB.yml +79 -0
- data/locales/storefront.en-US.yml +79 -0
- data/locales/storefront.es-ES.yml +79 -0
- data/locales/storefront.es-MX.yml +79 -0
- data/locales/storefront.fr-CA.yml +79 -0
- data/locales/storefront.fr-FR.yml +79 -0
- data/locales/storefront.id.yml +79 -0
- data/locales/storefront.it.yml +79 -0
- data/locales/storefront.ja.yml +79 -0
- data/locales/storefront.ko.yml +79 -0
- data/locales/storefront.nl.yml +79 -0
- data/locales/storefront.pl.yml +79 -0
- data/locales/storefront.pt-BR.yml +79 -0
- data/locales/storefront.pt-PT.yml +79 -0
- data/locales/storefront.ro.yml +79 -0
- data/locales/storefront.sv.yml +79 -0
- data/locales/storefront.tr.yml +79 -0
- data/locales/storefront.zh-CN.yml +79 -0
- data/locales/storefront.zh-TW.yml +79 -0
- data/log/dugway.log +1 -0
- data/spec/features/page_rendering_spec.rb +4 -4
- data/spec/fixtures/theme/layout.html +2 -0
- data/spec/fixtures/theme/settings.json +6 -0
- data/spec/spec_helper.rb +4 -0
- data/spec/units/dugway/liquid/drops/features_drop_spec.rb +182 -0
- data/spec/units/dugway/liquid/drops/product_drop_spec.rb +36 -0
- data/spec/units/dugway/liquid/drops/related_products_drop_spec.rb +80 -0
- data/spec/units/dugway/liquid/drops/theme_drop_spec.rb +45 -0
- data/spec/units/dugway/liquid/drops/translations_drop_spec.rb +292 -0
- data/spec/units/dugway/store_spec.rb +37 -0
- data/spec/units/dugway/theme_spec.rb +456 -0
- metadata +35 -2
@@ -4,18 +4,30 @@ describe Dugway::Theme do
|
|
4
4
|
let(:theme) { Dugway.theme }
|
5
5
|
|
6
6
|
describe "#layout" do
|
7
|
+
before(:each) do
|
8
|
+
allow_any_instance_of(Dugway::Theme).to receive(:validate_required_color_settings) { true }
|
9
|
+
end
|
10
|
+
|
7
11
|
it "should return the theme's layout" do
|
8
12
|
theme.layout.should == read_file('layout.html')
|
9
13
|
end
|
10
14
|
end
|
11
15
|
|
12
16
|
describe "#settings" do
|
17
|
+
before(:each) do
|
18
|
+
allow_any_instance_of(Dugway::Theme).to receive(:validate_required_color_settings) { true }
|
19
|
+
end
|
20
|
+
|
13
21
|
it "should return a hash of the theme's settings" do
|
14
22
|
theme.settings.should == JSON.parse(read_file('settings.json'))
|
15
23
|
end
|
16
24
|
end
|
17
25
|
|
18
26
|
describe "#fonts" do
|
27
|
+
before(:each) do
|
28
|
+
allow_any_instance_of(Dugway::Theme).to receive(:validate_required_color_settings) { true }
|
29
|
+
end
|
30
|
+
|
19
31
|
it "should return a hash of font settings values" do
|
20
32
|
theme.fonts.should == {
|
21
33
|
'text_font' => 'Georgia',
|
@@ -25,6 +37,10 @@ describe Dugway::Theme do
|
|
25
37
|
end
|
26
38
|
|
27
39
|
describe "#images" do
|
40
|
+
before(:each) do
|
41
|
+
allow_any_instance_of(Dugway::Theme).to receive(:validate_required_color_settings) { true }
|
42
|
+
end
|
43
|
+
|
28
44
|
it "should return a hash of the image settings" do
|
29
45
|
theme.images.should == {
|
30
46
|
'logo' => { :url => 'images/logo_bc.png', :width => 1, :height => 1 }
|
@@ -33,6 +49,10 @@ describe Dugway::Theme do
|
|
33
49
|
end
|
34
50
|
|
35
51
|
describe "#image_sets" do
|
52
|
+
before(:each) do
|
53
|
+
allow_any_instance_of(Dugway::Theme).to receive(:validate_required_color_settings) { true }
|
54
|
+
end
|
55
|
+
|
36
56
|
it "should return a hash of the image set settings" do
|
37
57
|
theme.image_sets.should == {
|
38
58
|
'slideshow_images' => [
|
@@ -47,6 +67,10 @@ describe Dugway::Theme do
|
|
47
67
|
end
|
48
68
|
|
49
69
|
describe "#customization" do
|
70
|
+
before(:each) do
|
71
|
+
allow_any_instance_of(Dugway::Theme).to receive(:validate_required_color_settings) { true }
|
72
|
+
end
|
73
|
+
|
50
74
|
it "should return a hash of font, color, option, images and image sets settings values" do
|
51
75
|
theme.customization.should == {
|
52
76
|
'background_color' => 'white',
|
@@ -76,6 +100,8 @@ describe Dugway::Theme do
|
|
76
100
|
Dugway.stub(:theme) {
|
77
101
|
Dugway::Theme.new(:fixed_sidebar => false, :link_text_color => 'blue')
|
78
102
|
}
|
103
|
+
|
104
|
+
allow_any_instance_of(Dugway::Theme).to receive(:validate_required_color_settings) { true }
|
79
105
|
end
|
80
106
|
|
81
107
|
it "should merge those values into the defaults" do
|
@@ -105,18 +131,30 @@ describe Dugway::Theme do
|
|
105
131
|
end
|
106
132
|
|
107
133
|
describe "#name" do
|
134
|
+
before(:each) do
|
135
|
+
allow_any_instance_of(Dugway::Theme).to receive(:validate_required_color_settings) { true }
|
136
|
+
end
|
137
|
+
|
108
138
|
it "should return the theme's name" do
|
109
139
|
theme.name.should == 'Test Theme'
|
110
140
|
end
|
111
141
|
end
|
112
142
|
|
113
143
|
describe "#version" do
|
144
|
+
before(:each) do
|
145
|
+
allow_any_instance_of(Dugway::Theme).to receive(:validate_required_color_settings) { true }
|
146
|
+
end
|
147
|
+
|
114
148
|
it "should return the theme's version" do
|
115
149
|
theme.version.should == '1.2.3'
|
116
150
|
end
|
117
151
|
end
|
118
152
|
|
119
153
|
describe "#file_content" do
|
154
|
+
before(:each) do
|
155
|
+
allow_any_instance_of(Dugway::Theme).to receive(:validate_required_color_settings) { true }
|
156
|
+
end
|
157
|
+
|
120
158
|
it "should return the file content for most files" do
|
121
159
|
%w( home.html products.html screenshot.jpg ).each { |file_name|
|
122
160
|
theme.file_content(file_name).should == read_file(file_name)
|
@@ -133,6 +171,10 @@ describe Dugway::Theme do
|
|
133
171
|
end
|
134
172
|
|
135
173
|
describe "#build_file" do
|
174
|
+
before(:each) do
|
175
|
+
allow_any_instance_of(Dugway::Theme).to receive(:validate_required_color_settings) { true }
|
176
|
+
end
|
177
|
+
|
136
178
|
it "should return the file content for most files" do
|
137
179
|
%w( home.html products.html screenshot.jpg ).each { |file_name|
|
138
180
|
theme.build_file(file_name).should == read_file(file_name)
|
@@ -149,25 +191,55 @@ describe Dugway::Theme do
|
|
149
191
|
end
|
150
192
|
|
151
193
|
describe "#files" do
|
194
|
+
before(:each) do
|
195
|
+
allow_any_instance_of(Dugway::Theme).to receive(:validate_required_color_settings) { true }
|
196
|
+
end
|
197
|
+
|
152
198
|
it "should return an array of all files" do
|
153
199
|
theme.files.should =~ ["cart.html", "contact.html", "home.html", "layout.html", "maintenance.html", "product.html", "products.html", "screenshot.jpg", "settings.json", "theme.css", "theme.js", "images/logo_bc.png", "images/slideshow/1.gif", "images/slideshow/2.gif", "images/slideshow/3.gif", "images/slideshow/4.gif", "images/slideshow/5.gif", "images/small.svg", "fonts/icons.ttf", "fonts/icons.woff"]
|
154
200
|
end
|
155
201
|
end
|
156
202
|
|
157
203
|
describe "#image_files" do
|
204
|
+
before(:each) do
|
205
|
+
allow_any_instance_of(Dugway::Theme).to receive(:validate_required_color_settings) { true }
|
206
|
+
end
|
207
|
+
|
158
208
|
it "should return an array of all image files" do
|
159
209
|
theme.image_files.should =~ ["images/logo_bc.png", "images/slideshow/1.gif", "images/slideshow/2.gif", "images/slideshow/3.gif", "images/slideshow/4.gif", "images/slideshow/5.gif", "images/small.svg"]
|
160
210
|
end
|
161
211
|
end
|
162
212
|
|
163
213
|
describe "#font_files" do
|
214
|
+
before(:each) do
|
215
|
+
allow_any_instance_of(Dugway::Theme).to receive(:validate_required_color_settings) { true }
|
216
|
+
end
|
217
|
+
|
164
218
|
it "should return an array of all font files" do
|
165
219
|
theme.font_files.should include("fonts/icons.ttf", "fonts/icons.woff")
|
166
220
|
end
|
167
221
|
end
|
168
222
|
|
169
223
|
describe "#valid?" do
|
224
|
+
let(:required_colors) {[
|
225
|
+
'background_color',
|
226
|
+
'primary_text_color',
|
227
|
+
'link_text_color',
|
228
|
+
'link_hover_color',
|
229
|
+
'button_background_color',
|
230
|
+
'button_text_color',
|
231
|
+
'button_hover_background_color'
|
232
|
+
]}
|
233
|
+
|
170
234
|
it "should return true when a theme has everything it needs" do
|
235
|
+
allow(theme).to receive(:validate_required_color_settings) { true }
|
236
|
+
|
237
|
+
allow(theme).to receive(:settings).and_return({
|
238
|
+
'name' => 'Test Theme',
|
239
|
+
'version' => '1.2.3',
|
240
|
+
'colors' => required_colors.map { |color| {'variable' => color} }
|
241
|
+
})
|
242
|
+
|
171
243
|
theme.valid?.should be(true)
|
172
244
|
theme.errors.should be_empty
|
173
245
|
end
|
@@ -175,6 +247,7 @@ describe Dugway::Theme do
|
|
175
247
|
describe "when missing a required file" do
|
176
248
|
before(:each) do
|
177
249
|
theme.stub(:read_source_file).with('cart.html') { theme.unstub(:read_source_file); nil }
|
250
|
+
allow_any_instance_of(Dugway::Theme).to receive(:validate_required_color_settings) { true }
|
178
251
|
end
|
179
252
|
|
180
253
|
it "should not be valid" do
|
@@ -187,6 +260,7 @@ describe Dugway::Theme do
|
|
187
260
|
describe "when missing a name" do
|
188
261
|
before(:each) do
|
189
262
|
theme.stub(:name) { nil }
|
263
|
+
allow_any_instance_of(Dugway::Theme).to receive(:validate_required_color_settings) { true }
|
190
264
|
end
|
191
265
|
|
192
266
|
it "should not be valid" do
|
@@ -199,6 +273,7 @@ describe Dugway::Theme do
|
|
199
273
|
describe "when missing a version" do
|
200
274
|
before(:each) do
|
201
275
|
theme.stub(:version) { nil }
|
276
|
+
allow_any_instance_of(Dugway::Theme).to receive(:validate_required_color_settings) { true }
|
202
277
|
end
|
203
278
|
|
204
279
|
it "should not be valid" do
|
@@ -211,6 +286,7 @@ describe Dugway::Theme do
|
|
211
286
|
describe "when having an invalid version" do
|
212
287
|
before(:each) do
|
213
288
|
theme.stub(:version) { '1.3' }
|
289
|
+
allow_any_instance_of(Dugway::Theme).to receive(:validate_required_color_settings) { true }
|
214
290
|
end
|
215
291
|
|
216
292
|
it "should not be valid" do
|
@@ -224,6 +300,7 @@ describe Dugway::Theme do
|
|
224
300
|
before(:each) do
|
225
301
|
theme.stub(:name) { nil }
|
226
302
|
theme.stub(:version) { nil }
|
303
|
+
allow_any_instance_of(Dugway::Theme).to receive(:validate_required_color_settings) { true }
|
227
304
|
end
|
228
305
|
|
229
306
|
it "should return all of them" do
|
@@ -273,6 +350,7 @@ describe Dugway::Theme do
|
|
273
350
|
end
|
274
351
|
|
275
352
|
before(:each) do
|
353
|
+
allow(theme).to receive(:validate_required_color_settings) { true }
|
276
354
|
allow(theme).to receive(:name) { "Test Theme" }
|
277
355
|
allow(theme).to receive(:version) { "1.2.3" }
|
278
356
|
end
|
@@ -293,6 +371,384 @@ describe Dugway::Theme do
|
|
293
371
|
theme.errors.should include('Style in group \'Classic\' - Missing style_name')
|
294
372
|
end
|
295
373
|
end
|
374
|
+
|
375
|
+
describe "when missing option descriptions" do
|
376
|
+
before(:each) do
|
377
|
+
allow_any_instance_of(Dugway::Theme).to receive(:validate_required_color_settings) { true }
|
378
|
+
theme.stub(:settings) { {
|
379
|
+
'name' => 'Test Theme',
|
380
|
+
'version' => '1.2.3',
|
381
|
+
'colors' => [
|
382
|
+
{'variable' => 'background_color'},
|
383
|
+
{'variable' => 'primary_text_color'},
|
384
|
+
{'variable' => 'link_text_color'},
|
385
|
+
{'variable' => 'link_hover_color'},
|
386
|
+
{'variable' => 'button_background_color'},
|
387
|
+
{'variable' => 'button_text_color'},
|
388
|
+
{'variable' => 'button_hover_background_color'}
|
389
|
+
],
|
390
|
+
'options' => [{ 'variable' => 'show_search', 'section' => 'global_navigation', 'label' => 'Show search' }]
|
391
|
+
} }
|
392
|
+
end
|
393
|
+
|
394
|
+
it "should not be valid" do
|
395
|
+
theme.valid?.should be(false)
|
396
|
+
theme.errors.size.should == 1
|
397
|
+
theme.errors.first.should == 'Missing descriptions for settings: show_search'
|
398
|
+
end
|
399
|
+
|
400
|
+
it "should be valid when skipping options validation" do
|
401
|
+
theme.valid?(validate_options: false).should be(true)
|
402
|
+
end
|
403
|
+
end
|
404
|
+
|
405
|
+
describe "when validating option requirements" do
|
406
|
+
let(:required_colors) {[
|
407
|
+
'background_color',
|
408
|
+
'primary_text_color',
|
409
|
+
'link_text_color',
|
410
|
+
'link_hover_color',
|
411
|
+
'button_background_color',
|
412
|
+
'button_text_color',
|
413
|
+
'button_hover_background_color'
|
414
|
+
]}
|
415
|
+
|
416
|
+
it "allows options with no requires" do
|
417
|
+
settings = theme.settings.merge({
|
418
|
+
'options' => [{
|
419
|
+
'variable' => 'show_search',
|
420
|
+
'section' => 'global_navigation',
|
421
|
+
'label' => 'Show search',
|
422
|
+
'description' => 'Show search in header'
|
423
|
+
}]
|
424
|
+
})
|
425
|
+
allow(theme).to receive(:settings).and_return(settings)
|
426
|
+
|
427
|
+
theme.valid?.should be(true)
|
428
|
+
theme.errors.should be_empty
|
429
|
+
end
|
430
|
+
|
431
|
+
it "should not be valid when colors section is missing" do
|
432
|
+
allow(theme).to receive(:settings).and_return({
|
433
|
+
'name' => 'Test Theme',
|
434
|
+
'version' => '1.2.3',
|
435
|
+
'options' => []
|
436
|
+
})
|
437
|
+
|
438
|
+
theme.valid?.should be(false)
|
439
|
+
theme.errors.should include("Missing colors section in theme settings")
|
440
|
+
end
|
441
|
+
|
442
|
+
it "should not be valid when required colors are missing" do
|
443
|
+
|
444
|
+
allow(theme).to receive(:settings).and_return({
|
445
|
+
'name' => 'Test Theme',
|
446
|
+
'version' => '1.2.3',
|
447
|
+
'colors' => [
|
448
|
+
{ 'variable' => 'background_color' }
|
449
|
+
],
|
450
|
+
'options' => []
|
451
|
+
})
|
452
|
+
|
453
|
+
theme.valid?.should be(false)
|
454
|
+
theme.errors.first.should match(/Missing required color settings:/)
|
455
|
+
end
|
456
|
+
|
457
|
+
it "validates feature flag format and values" do
|
458
|
+
settings = theme.settings.merge({
|
459
|
+
'options' => [{
|
460
|
+
'variable' => 'show_foo',
|
461
|
+
'section' => 'general',
|
462
|
+
'description' => 'Show foo thing',
|
463
|
+
'requires' => [
|
464
|
+
'feature:', # invalid: empty
|
465
|
+
'feature:foo_flag gt visible', # invalid operator
|
466
|
+
'feature:foo_flag eq invalid_value', # invalid value
|
467
|
+
'feature:foo_flag neq visible', # valid
|
468
|
+
'feature:foo_flag eq visible' # valid
|
469
|
+
]
|
470
|
+
}]
|
471
|
+
})
|
472
|
+
allow(theme).to receive(:settings).and_return(settings)
|
473
|
+
|
474
|
+
theme.valid?.should be(false)
|
475
|
+
theme.errors.should include("Option 'show_foo' has invalid feature flag format")
|
476
|
+
theme.errors.should include("Option 'show_foo' has invalid operator 'gt'. Feature flags can only use `eq` or `neq`.")
|
477
|
+
theme.errors.should include("Option 'show_foo' has invalid comparison value 'invalid_value'. Feature flags can only check for `visible`.")
|
478
|
+
|
479
|
+
end
|
480
|
+
end
|
481
|
+
|
482
|
+
describe "when validating option sections" do
|
483
|
+
let(:valid_sections_string) { Dugway::Theme::VALID_SECTIONS.join(', ') }
|
484
|
+
let(:base_settings) do
|
485
|
+
{
|
486
|
+
'name' => 'Test Theme',
|
487
|
+
'version' => '1.2.3',
|
488
|
+
'colors' => required_colors.map { |color| {'variable' => color} },
|
489
|
+
'options' => []
|
490
|
+
}
|
491
|
+
end
|
492
|
+
|
493
|
+
# Define required_colors here if not already available in this scope
|
494
|
+
let(:required_colors) {[
|
495
|
+
'background_color',
|
496
|
+
'primary_text_color',
|
497
|
+
'link_text_color',
|
498
|
+
'link_hover_color',
|
499
|
+
'button_background_color',
|
500
|
+
'button_text_color',
|
501
|
+
'button_hover_background_color'
|
502
|
+
]}
|
503
|
+
|
504
|
+
# Fix for the failing tests - define constant if needed
|
505
|
+
before(:each) do
|
506
|
+
unless defined?(Dugway::Theme::REQUIRED_FILES)
|
507
|
+
stub_const("Dugway::Theme::REQUIRED_FILES", [
|
508
|
+
"cart.html", "contact.html", "home.html", "layout.html", "maintenance.html",
|
509
|
+
"product.html", "products.html", "screenshot.jpg", "settings.json", "theme.css", "theme.js"
|
510
|
+
])
|
511
|
+
end
|
512
|
+
end
|
513
|
+
|
514
|
+
it "passes with a valid section" do
|
515
|
+
settings = base_settings.merge({
|
516
|
+
'options' => [{
|
517
|
+
'variable' => 'valid_option',
|
518
|
+
'description' => 'Valid option',
|
519
|
+
'section' => 'homepage'
|
520
|
+
}]
|
521
|
+
})
|
522
|
+
# Stub settings
|
523
|
+
allow(theme).to receive(:settings).and_return(settings)
|
524
|
+
|
525
|
+
# Stub ALL required files first
|
526
|
+
Dugway::Theme::REQUIRED_FILES.each do |file|
|
527
|
+
allow(theme).to receive(:read_source_file).with(file).and_return("some content")
|
528
|
+
end
|
529
|
+
|
530
|
+
# Then override the specific stub for layout.html
|
531
|
+
allow(theme).to receive(:read_source_file).with('layout.html')
|
532
|
+
.and_return('<body data-bc-page-type="home"><div data-bc-hook="header"></div><div data-bc-hook="footer"></div></body>')
|
533
|
+
|
534
|
+
# Stub color validation
|
535
|
+
allow(theme).to receive(:validate_required_color_settings).and_return(true)
|
536
|
+
|
537
|
+
expect(Kernel).not_to receive(:warn)
|
538
|
+
theme.valid?.should be(true)
|
539
|
+
end
|
540
|
+
|
541
|
+
it "warns appropriately for multiple options with missing or invalid sections" do
|
542
|
+
settings = base_settings.merge({
|
543
|
+
'options' => [
|
544
|
+
{ 'variable' => 'option_1_valid', 'description' => 'Valid', 'section' => 'homepage' },
|
545
|
+
{ 'variable' => 'option_2_missing', 'description' => 'Missing section' }, # Missing section
|
546
|
+
{ 'variable' => 'option_3_invalid', 'description' => 'Invalid section', 'section' => 'bad_section' }, # Invalid section
|
547
|
+
{ 'variable' => 'option_4_valid', 'description' => 'Valid again', 'section' => 'general' },
|
548
|
+
{ 'variable' => 'option_5_missing', 'description' => 'Missing section again' }, # Missing section again
|
549
|
+
{ 'description' => 'Option 6 missing variable and section' }, # Missing variable and section
|
550
|
+
{ 'variable' => 'option_7_invalid', 'description' => 'Invalid section again', 'section' => 'another_bad_one' } # Invalid section again
|
551
|
+
]
|
552
|
+
})
|
553
|
+
# Stub settings
|
554
|
+
allow(theme).to receive(:settings).and_return(settings)
|
555
|
+
|
556
|
+
# Stub ALL required files first
|
557
|
+
Dugway::Theme::REQUIRED_FILES.each do |file|
|
558
|
+
allow(theme).to receive(:read_source_file).with(file).and_return("some content")
|
559
|
+
end
|
560
|
+
|
561
|
+
# Then override the specific stub for layout.html
|
562
|
+
allow(theme).to receive(:read_source_file).with('layout.html')
|
563
|
+
.and_return('<body data-bc-page-type="home"><div data-bc-hook="header"></div><div data-bc-hook="footer"></div></body>')
|
564
|
+
|
565
|
+
# Stub color validation
|
566
|
+
allow(theme).to receive(:validate_required_color_settings).and_return(true)
|
567
|
+
|
568
|
+
# Allow warn to be called so we can spy on it
|
569
|
+
allow(Kernel).to receive(:warn)
|
570
|
+
|
571
|
+
# Call valid? and assert true (since warnings don't invalidate)
|
572
|
+
theme.valid?.should be(true)
|
573
|
+
|
574
|
+
# Verify calls
|
575
|
+
expect(Kernel).to have_received(:warn).with("Warning: Theme setting 'option_2_missing' is missing the 'section' property.")
|
576
|
+
expect(Kernel).to have_received(:warn).with("Warning: Theme setting 'option_3_invalid' has an invalid 'section' value: 'bad_section'. Allowed values are: #{valid_sections_string}.")
|
577
|
+
expect(Kernel).to have_received(:warn).with("Warning: Theme setting 'option_5_missing' is missing the 'section' property.")
|
578
|
+
expect(Kernel).to have_received(:warn).with("Warning: Theme setting 'unknown' is missing the 'section' property.")
|
579
|
+
expect(Kernel).to have_received(:warn).with("Warning: Theme setting 'option_7_invalid' has an invalid 'section' value: 'another_bad_one'. Allowed values are: #{valid_sections_string}.")
|
580
|
+
end
|
581
|
+
|
582
|
+
it "handles options without a variable name gracefully when section is invalid" do
|
583
|
+
settings = base_settings.merge({
|
584
|
+
'options' => [{
|
585
|
+
# 'variable' key is missing
|
586
|
+
'description' => 'Option without variable',
|
587
|
+
'section' => 'invalid_area' # Invalid section to trigger warning
|
588
|
+
}]
|
589
|
+
})
|
590
|
+
|
591
|
+
# Stub all necessary methods
|
592
|
+
allow(theme).to receive(:settings).and_return(settings)
|
593
|
+
allow(theme).to receive(:validate_required_color_settings).and_return(true)
|
594
|
+
allow(theme).to receive(:validate_required_layout_attributes).and_return(true)
|
595
|
+
allow(theme).to receive(:validate_options_requires).and_return(true)
|
596
|
+
allow(theme).to receive(:validate_options_descriptions).and_return(true)
|
597
|
+
allow(theme).to receive(:validate_option_defaults).and_return(true)
|
598
|
+
|
599
|
+
# Stub file checks - this is crucial
|
600
|
+
Dugway::Theme::REQUIRED_FILES.each do |file|
|
601
|
+
allow(theme).to receive(:read_source_file).with(file).and_return("some content")
|
602
|
+
end
|
603
|
+
|
604
|
+
# Allow warn to be called
|
605
|
+
allow(Kernel).to receive(:warn)
|
606
|
+
|
607
|
+
# Run the validation
|
608
|
+
theme.valid?.should be(true)
|
609
|
+
|
610
|
+
# Check that the warning was issued
|
611
|
+
expect(Kernel).to have_received(:warn).with("Warning: Theme setting 'unknown' has an invalid 'section' value: 'invalid_area'. Allowed values are: #{valid_sections_string}.")
|
612
|
+
end
|
613
|
+
|
614
|
+
it "handles options without a variable name gracefully when section is missing" do
|
615
|
+
settings = base_settings.merge({
|
616
|
+
'options' => [{
|
617
|
+
# 'variable' key is missing
|
618
|
+
'description' => 'Option without variable or section'
|
619
|
+
# 'section' key is missing
|
620
|
+
}]
|
621
|
+
})
|
622
|
+
|
623
|
+
# Stub all necessary methods
|
624
|
+
allow(theme).to receive(:settings).and_return(settings)
|
625
|
+
allow(theme).to receive(:validate_required_color_settings).and_return(true)
|
626
|
+
allow(theme).to receive(:validate_required_layout_attributes).and_return(true)
|
627
|
+
allow(theme).to receive(:validate_options_requires).and_return(true)
|
628
|
+
allow(theme).to receive(:validate_options_descriptions).and_return(true)
|
629
|
+
allow(theme).to receive(:validate_option_defaults).and_return(true)
|
630
|
+
|
631
|
+
# Stub file checks
|
632
|
+
Dugway::Theme::REQUIRED_FILES.each do |file|
|
633
|
+
allow(theme).to receive(:read_source_file).with(file).and_return("some content")
|
634
|
+
end
|
635
|
+
|
636
|
+
# Allow warn to be called
|
637
|
+
allow(Kernel).to receive(:warn)
|
638
|
+
|
639
|
+
# Run the validation
|
640
|
+
theme.valid?.should be(true)
|
641
|
+
|
642
|
+
# Check that the warning was issued
|
643
|
+
expect(Kernel).to have_received(:warn).with("Warning: Theme setting 'unknown' is missing the 'section' property.")
|
644
|
+
end
|
645
|
+
end
|
646
|
+
|
647
|
+
end
|
648
|
+
|
649
|
+
shared_examples "option value validation" do |value_type|
|
650
|
+
context "when type is 'select' with explicit options" do
|
651
|
+
let(:options) do
|
652
|
+
[{
|
653
|
+
'type' => 'select',
|
654
|
+
'variable' => 'hero_overlay_opacity',
|
655
|
+
'options' => [['Bright', 'bright'], ['Dark', 'dark']],
|
656
|
+
value_type => 'bright'
|
657
|
+
}]
|
658
|
+
end
|
659
|
+
|
660
|
+
it "passes when #{value_type} matches a valid option" do
|
661
|
+
theme.instance_variable_set(:@errors, [])
|
662
|
+
theme.send(:validate_option_defaults)
|
663
|
+
expect(theme.errors).to be_empty
|
664
|
+
end
|
665
|
+
|
666
|
+
it "flags invalid #{value_type} values" do
|
667
|
+
options.first[value_type] = 'invalid'
|
668
|
+
theme.instance_variable_set(:@errors, [])
|
669
|
+
theme.send(:validate_option_defaults)
|
670
|
+
expect(theme.errors).to include("#{value_type.capitalize} 'invalid' is not a valid option for hero_overlay_opacity")
|
671
|
+
end
|
672
|
+
end
|
673
|
+
|
674
|
+
context "when type is 'select' with numeric range" do
|
675
|
+
let(:options) do
|
676
|
+
[{
|
677
|
+
'type' => 'select',
|
678
|
+
'variable' => 'featured_products',
|
679
|
+
'options' => '0..100',
|
680
|
+
value_type => 50
|
681
|
+
}]
|
682
|
+
end
|
683
|
+
|
684
|
+
it "passes when #{value_type} is within range" do
|
685
|
+
theme.instance_variable_set(:@errors, [])
|
686
|
+
theme.send(:validate_option_defaults)
|
687
|
+
expect(theme.errors).to be_empty
|
688
|
+
end
|
689
|
+
|
690
|
+
it "flags #{value_type} outside the range" do
|
691
|
+
options.first[value_type] = 101
|
692
|
+
theme.instance_variable_set(:@errors, [])
|
693
|
+
theme.send(:validate_option_defaults)
|
694
|
+
expect(theme.errors).to include("#{value_type.capitalize} '101' is out of range for featured_products")
|
695
|
+
end
|
696
|
+
end
|
697
|
+
|
698
|
+
context "when type is 'boolean'" do
|
699
|
+
let(:options) do
|
700
|
+
[{
|
701
|
+
'type' => 'boolean',
|
702
|
+
'variable' => 'show_home_page_categories',
|
703
|
+
value_type => true
|
704
|
+
}]
|
705
|
+
end
|
706
|
+
|
707
|
+
it "passes when #{value_type} is a valid boolean" do
|
708
|
+
theme.instance_variable_set(:@errors, [])
|
709
|
+
theme.send(:validate_option_defaults)
|
710
|
+
expect(theme.errors).to be_empty
|
711
|
+
end
|
712
|
+
|
713
|
+
it "flags non-boolean #{value_type}" do
|
714
|
+
options.first[value_type] = 'true'
|
715
|
+
theme.instance_variable_set(:@errors, [])
|
716
|
+
theme.send(:validate_option_defaults)
|
717
|
+
expect(theme.errors).to include("#{value_type.capitalize} 'true' is not a boolean for show_home_page_categories")
|
718
|
+
end
|
719
|
+
end
|
720
|
+
|
721
|
+
context "when type is 'select' with product_orders" do
|
722
|
+
let(:options) do
|
723
|
+
[{
|
724
|
+
'type' => 'select',
|
725
|
+
'variable' => 'related_products_order',
|
726
|
+
'options' => 'product_orders',
|
727
|
+
value_type => 'top-selling'
|
728
|
+
}]
|
729
|
+
end
|
730
|
+
|
731
|
+
it "passes when #{value_type} matches a valid product_orders value" do
|
732
|
+
theme.instance_variable_set(:@errors, [])
|
733
|
+
theme.send(:validate_option_defaults)
|
734
|
+
expect(theme.errors).to be_empty
|
735
|
+
end
|
736
|
+
|
737
|
+
it "flags invalid #{value_type} values" do
|
738
|
+
options.first[value_type] = 'invalid'
|
739
|
+
theme.instance_variable_set(:@errors, [])
|
740
|
+
theme.send(:validate_option_defaults)
|
741
|
+
expect(theme.errors).to include("#{value_type.capitalize} 'invalid' is not a valid option for related_products_order")
|
742
|
+
end
|
743
|
+
end
|
744
|
+
end
|
745
|
+
|
746
|
+
describe "#validate_option_defaults" do
|
747
|
+
let(:settings) { { 'options' => options } }
|
748
|
+
before { allow(theme).to receive(:settings).and_return(settings) }
|
749
|
+
|
750
|
+
it_behaves_like "option value validation", 'default'
|
751
|
+
it_behaves_like "option value validation", 'upgrade_default'
|
296
752
|
end
|
297
753
|
|
298
754
|
def read_file(file_name)
|