locomotivecms_steam 1.1.2 → 1.2.0.beta1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (67) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +2 -2
  3. data/Gemfile.lock +41 -52
  4. data/lib/locomotive/steam/adapters/filesystem/sanitizers/page.rb +30 -35
  5. data/lib/locomotive/steam/adapters/filesystem.rb +8 -0
  6. data/lib/locomotive/steam/adapters/mongodb/command.rb +8 -1
  7. data/lib/locomotive/steam/adapters/mongodb.rb +10 -1
  8. data/lib/locomotive/steam/entities/content_entry.rb +13 -6
  9. data/lib/locomotive/steam/entities/page.rb +4 -0
  10. data/lib/locomotive/steam/entities/site.rb +1 -0
  11. data/lib/locomotive/steam/errors.rb +3 -0
  12. data/lib/locomotive/steam/initializers/dragonfly.rb +3 -5
  13. data/lib/locomotive/steam/initializers/sprockets.rb +10 -0
  14. data/lib/locomotive/steam/liquid/drops/content_entry.rb +8 -0
  15. data/lib/locomotive/steam/liquid/drops/content_entry_collection.rb +1 -1
  16. data/lib/locomotive/steam/liquid/tags/action.rb +59 -0
  17. data/lib/locomotive/steam/middlewares/entry_submission.rb +1 -1
  18. data/lib/locomotive/steam/middlewares/helpers.rb +8 -0
  19. data/lib/locomotive/steam/middlewares/locale.rb +1 -5
  20. data/lib/locomotive/steam/middlewares/locale_redirection.rb +1 -7
  21. data/lib/locomotive/steam/middlewares/renderer.rb +6 -3
  22. data/lib/locomotive/steam/middlewares/site.rb +12 -5
  23. data/lib/locomotive/steam/middlewares/sitemap.rb +6 -2
  24. data/lib/locomotive/steam/middlewares/thread_safe.rb +0 -4
  25. data/lib/locomotive/steam/models/associations/many_to_many.rb +1 -1
  26. data/lib/locomotive/steam/models/entity.rb +5 -0
  27. data/lib/locomotive/steam/models/repository.rb +4 -0
  28. data/lib/locomotive/steam/repositories/content_entry_repository.rb +23 -4
  29. data/lib/locomotive/steam/repositories/content_type_field_repository.rb +4 -0
  30. data/lib/locomotive/steam/services/action_service.rb +92 -0
  31. data/lib/locomotive/steam/services/content_entry_service.rb +114 -0
  32. data/lib/locomotive/steam/services/email_service.rb +102 -0
  33. data/lib/locomotive/steam/services/entry_submission_service.rb +6 -58
  34. data/lib/locomotive/steam/services/liquid_parser_service.rb +6 -0
  35. data/lib/locomotive/steam/services/url_builder_service.rb +5 -2
  36. data/lib/locomotive/steam/services.rb +13 -1
  37. data/lib/locomotive/steam/version.rb +1 -1
  38. data/lib/locomotive/steam.rb +5 -3
  39. data/locomotivecms_steam.gemspec +2 -0
  40. data/spec/fixtures/default/data/messages.yml +0 -0
  41. data/spec/integration/services/content_entry_service_spec.rb +110 -0
  42. data/spec/unit/adapters/filesystem_adapter_spec.rb +10 -0
  43. data/spec/unit/adapters/mongodb_adapter_spec.rb +18 -0
  44. data/spec/unit/entities/content_entry_spec.rb +34 -0
  45. data/spec/unit/entities/editable_element_spec.rb +19 -0
  46. data/spec/unit/entities/page_spec.rb +29 -0
  47. data/spec/unit/liquid/drops/content_entry_collection_spec.rb +4 -0
  48. data/spec/unit/liquid/drops/content_entry_spec.rb +5 -2
  49. data/spec/unit/liquid/tags/action_spec.rb +23 -0
  50. data/spec/unit/liquid/tags/link_to_spec.rb +12 -4
  51. data/spec/unit/liquid/tags/locale_switcher_spec.rb +15 -7
  52. data/spec/unit/liquid/tags/nav_spec.rb +19 -11
  53. data/spec/unit/liquid/tags/path_to_spec.rb +12 -4
  54. data/spec/unit/middlewares/helpers_spec.rb +29 -0
  55. data/spec/unit/middlewares/locale_redirection_spec.rb +11 -29
  56. data/spec/unit/middlewares/site_spec.rb +66 -13
  57. data/spec/unit/middlewares/sitemap_spec.rb +44 -0
  58. data/spec/unit/models/i18n_field_spec.rb +23 -0
  59. data/spec/unit/repositories/content_entry_repository_spec.rb +39 -7
  60. data/spec/unit/repositories/content_type_field_repository_spec.rb +10 -0
  61. data/spec/unit/services/action_service_spec.rb +173 -0
  62. data/spec/unit/services/content_entry_service_spec.rb +63 -0
  63. data/spec/unit/services/email_service_spec.rb +198 -0
  64. data/spec/unit/services/entry_submission_service_spec.rb +28 -112
  65. data/spec/unit/services/url_builder_service_spec.rb +14 -5
  66. metadata +50 -6
  67. data/spec/unit/middlewares/locale_spec.rb +0 -52
@@ -42,38 +42,91 @@ describe Locomotive::Steam::Middlewares::Site do
42
42
 
43
43
  end
44
44
 
45
- describe 'redirection to the first domain' do
45
+ describe 'redirection' do
46
46
 
47
- let(:redirect_to_first_domain) { false }
47
+ let(:redirect_to_first_domain) { false }
48
+ let(:redirect_to_https) { false }
48
49
  let(:url) { 'http://acme.com' }
49
- let(:site) { instance_double('SiteWithDomains', name: 'Acme', domains: ['www.acme.com', 'acme.com'], redirect_to_first_domain: redirect_to_first_domain) }
50
+ let(:site) { instance_double('SiteWithDomains', name: 'Acme', domains: ['www.acme.com', 'acme.com'], redirect_to_first_domain: redirect_to_first_domain, redirect_to_https: redirect_to_https) }
50
51
 
51
52
  before { expect(services).to receive(:current_site).and_return(site) }
52
53
 
53
- it { is_expected.to eq [200, nil] }
54
+ describe 'redirection to https' do
54
55
 
55
- describe 'option enabled' do
56
+ it { is_expected.to eq [200, nil] }
56
57
 
57
- let(:redirect_to_first_domain) { true }
58
+ describe 'option enabled' do
58
59
 
59
- it { is_expected.to eq [301, 'http://www.acme.com/'] }
60
+ let(:redirect_to_https) { true }
60
61
 
61
- context 'first domain requested' do
62
+ it { is_expected.to eq [301, 'https://www.acme.com/'] }
62
63
 
63
- let(:url) { 'http://www.acme.com' }
64
- it { is_expected.to eq [200, nil] }
64
+ context 'https requested' do
65
+
66
+ let(:url) { 'https://www.acme.com' }
67
+ it { is_expected.to eq [200, nil] }
68
+
69
+ end
70
+
71
+ context 'requesting the default host' do
72
+
73
+ let(:is_default_host) { true }
74
+ it { is_expected.to eq [200, nil] }
75
+
76
+ end
65
77
 
66
78
  end
67
79
 
68
- context 'requesting the default host' do
80
+ end
81
+
82
+ describe 'redirection to the first domain' do
83
+
84
+ it { is_expected.to eq [200, nil] }
85
+
86
+ describe 'option enabled' do
87
+
88
+ let(:redirect_to_first_domain) { true }
89
+
90
+ it { is_expected.to eq [301, 'http://www.acme.com/'] }
91
+
92
+ context 'first domain requested' do
93
+
94
+ let(:url) { 'http://www.acme.com' }
95
+ it { is_expected.to eq [200, nil] }
69
96
 
70
- let(:is_default_host) { true }
71
- it { is_expected.to eq [200, nil] }
97
+ end
98
+
99
+ context 'requesting the default host' do
100
+
101
+ let(:is_default_host) { true }
102
+ it { is_expected.to eq [200, nil] }
103
+
104
+ end
72
105
 
73
106
  end
74
107
 
75
108
  end
76
109
 
110
+ describe 'redirection to both https and the first domain' do
111
+
112
+ let(:redirect_to_https) { true }
113
+ let(:redirect_to_first_domain) { true }
114
+ let(:url) { 'http://acme.com/foo/bar' }
115
+
116
+ it { is_expected.to eq [301, 'https://www.acme.com/foo/bar'] }
117
+
118
+ end
119
+
120
+ describe 'redirection to the first domain' do
121
+
122
+ let(:redirect_to_https) { true }
123
+ let(:redirect_to_first_domain) { true }
124
+ let(:url) { 'https://acme.com/foo/bar' }
125
+
126
+ it { is_expected.to eq [301, 'https://www.acme.com/foo/bar'] }
127
+
128
+ end
129
+
77
130
  end
78
131
 
79
132
  end
@@ -0,0 +1,44 @@
1
+ require 'spec_helper'
2
+
3
+ require_relative '../../../lib/locomotive/steam/middlewares/thread_safe'
4
+ require_relative '../../../lib/locomotive/steam/middlewares/helpers'
5
+ require_relative '../../../lib/locomotive/steam/middlewares/sitemap'
6
+
7
+ describe Locomotive::Steam::Middlewares::Sitemap do
8
+
9
+ let(:pages) { [] }
10
+ let(:page_repository) { instance_double('PageRepository', published: pages) }
11
+ let(:app) { ->(env) { [200, env, 'app'] }}
12
+ let(:middleware) { described_class.new(app) }
13
+
14
+ before do
15
+ allow_any_instance_of(described_class).to receive(:base_url).and_return('http://localhost/')
16
+ allow_any_instance_of(described_class).to receive(:page_repository).and_return(page_repository)
17
+ end
18
+
19
+ describe '#call' do
20
+
21
+ let(:env) { { 'PATH_INFO' => '/sitemap.xml', 'steam.page' => nil } }
22
+ subject { middleware.call(env) }
23
+
24
+ describe 'no pages' do
25
+
26
+ it 'renders a blank sitemap' do
27
+ is_expected.to eq [200, { "Content-Type"=>"text/plain" }, ["<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<urlset xmlns=\"http://www.sitemaps.org/schemas/sitemap/0.9\">\n <url>\n <loc>http://localhost/</loc>\n <priority>1.0</priority>\n </url>\n\n</urlset>\n"]]
28
+ end
29
+
30
+ end
31
+
32
+ describe 'only layouts' do
33
+
34
+ let(:pages) { [instance_double('Page', index?: false, not_found?: false, layout?: true)] }
35
+
36
+ it 'renders a blank sitemap' do
37
+ is_expected.to eq [200, { "Content-Type"=>"text/plain" }, ["<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<urlset xmlns=\"http://www.sitemaps.org/schemas/sitemap/0.9\">\n <url>\n <loc>http://localhost/</loc>\n <priority>1.0</priority>\n </url>\n\n</urlset>\n"]]
38
+ end
39
+
40
+ end
41
+
42
+ end
43
+
44
+ end
@@ -22,4 +22,27 @@ describe Locomotive::Steam::Models::I18nField do
22
22
 
23
23
  end
24
24
 
25
+ describe '#dup' do
26
+
27
+ let(:translations) { { en: 'Hello world', fr: nil } }
28
+
29
+ subject { field.dup }
30
+
31
+ it 'gets a fresh copy of the translations' do
32
+ expect(subject[:en]).to eq 'Hello world'
33
+ expect(subject.translations.object_id).not_to eq field.translations.object_id
34
+ end
35
+
36
+ end
37
+
38
+ describe '#to_json' do
39
+
40
+ let(:translations) { { en: 'Hello world', fr: nil } }
41
+
42
+ subject { field.to_json }
43
+
44
+ it { is_expected.to eq("{\"en\":\"Hello world\",\"fr\":null}") }
45
+
46
+ end
47
+
25
48
  end
@@ -4,7 +4,7 @@ require_relative '../../../lib/locomotive/steam/adapters/filesystem.rb'
4
4
 
5
5
  describe Locomotive::Steam::ContentEntryRepository do
6
6
 
7
- let(:_fields) { instance_double('Fields', selects: [], belongs_to: [], many_to_many: []) }
7
+ let(:_fields) { instance_double('Fields', selects: [], belongs_to: [], many_to_many: [], dates_and_date_times: []) }
8
8
  let(:type) { build_content_type('Articles', label_field_name: :title, localized_names: [:title], fields: _fields, fields_by_name: { title: instance_double('Field', name: :title, type: :string) }, fields_with_default: []) }
9
9
  let(:entries) { [{ content_type_id: 1, _position: 0, _label: 'Update #1', title: { fr: 'Mise a jour #1' }, text: { en: 'added some free stuff', fr: 'phrase FR' }, date: '2009/05/12', category: 'General' }] }
10
10
  let(:locale) { :en }
@@ -274,7 +274,7 @@ describe Locomotive::Steam::ContentEntryRepository do
274
274
  let(:other_type) { build_content_type('Authors', _id: 2, label_field_name: :name, fields: _fields, fields_by_name: { name: instance_double('Field', name: :name, type: :string) }, fields_with_default: []) }
275
275
  let(:other_entries) { [{ content_type_id: 2, _id: 'john-doe', name: 'John Doe' }] }
276
276
 
277
- let(:type_repository) { instance_double('ArticleBelongsToRepository', selects: [], belongs_to: [], many_to_many: []) }
277
+ let(:type_repository) { instance_double('ArticleBelongsToRepository', selects: [], belongs_to: [], many_to_many: [], dates_and_date_times: []) }
278
278
 
279
279
  before do
280
280
  allow(type).to receive(:fields).and_return(type_repository)
@@ -307,7 +307,7 @@ describe Locomotive::Steam::ContentEntryRepository do
307
307
  ]
308
308
  }
309
309
 
310
- let(:type_repository) { instance_double('AuthorRepository', selects: [], belongs_to: [], many_to_many: []) }
310
+ let(:type_repository) { instance_double('AuthorRepository', selects: [], belongs_to: [], many_to_many: [], dates_and_date_times: []) }
311
311
 
312
312
  before do
313
313
  allow(type).to receive(:fields).and_return(type_repository)
@@ -340,7 +340,7 @@ describe Locomotive::Steam::ContentEntryRepository do
340
340
  ]
341
341
  }
342
342
 
343
- let(:type_repository) { instance_double('AuthorRepository', selects: [], belongs_to: [], many_to_many: []) }
343
+ let(:type_repository) { instance_double('AuthorRepository', selects: [], belongs_to: [], many_to_many: [], dates_and_date_times: []) }
344
344
 
345
345
  before do
346
346
  allow(type).to receive(:fields).and_return(type_repository)
@@ -373,18 +373,42 @@ describe Locomotive::Steam::ContentEntryRepository do
373
373
  let(:option) { instance_double('Option', _id: 42)}
374
374
  let(:options) { instance_double('OptionRepository', by_name: option) }
375
375
  let(:field) { instance_double('SelectField', name: 'category', persisted_name: 'category_id', select_options: options) }
376
- let(:_fields) { instance_double('Fields', selects: [field], belongs_to: [], many_to_many: []) }
376
+ let(:_fields) { instance_double('Fields', selects: [field], belongs_to: [], many_to_many: [], dates_and_date_times: []) }
377
377
  let(:conditions) { { 'category' => value } }
378
378
 
379
379
  it { is_expected.to eq([{ _visible: true, content_type_id: 1, 'category_id' => 42 }, nil]) }
380
380
 
381
381
  end
382
382
 
383
+ context 'date fields' do
384
+
385
+ let(:value) { '2009/09/10' }
386
+ let(:field) { instance_double('DateField', name: 'launched_at', persisted_name: 'launched_at', type: :date) }
387
+ let(:_fields) { instance_double('Fields', selects: [], belongs_to: [], many_to_many: [], dates_and_date_times: [field]) }
388
+ let(:conditions) { { 'launched_at' => value } }
389
+
390
+ it { is_expected.to eq([{ _visible: true, content_type_id: 1, 'launched_at' => Date.parse('2009/09/10') }, nil]) }
391
+
392
+ end
393
+
394
+ context 'date time fields' do
395
+
396
+ before { Time.zone = 'Paris' }
397
+
398
+ let(:value) { '2007/06/29 21:15:00' }
399
+ let(:field) { instance_double('DateField', name: 'launched_at', persisted_name: 'launched_at', type: :date_time) }
400
+ let(:_fields) { instance_double('Fields', selects: [], belongs_to: [], many_to_many: [], dates_and_date_times: [field]) }
401
+ let(:conditions) { { 'launched_at' => value } }
402
+
403
+ it { is_expected.to eq([{ _visible: true, content_type_id: 1, 'launched_at' => Time.zone.parse('2007/06/29 21:15:00').to_datetime }, nil]) }
404
+
405
+ end
406
+
383
407
  context 'belongs_to fields' do
384
408
 
385
409
  let(:value) { 42 }
386
410
  let(:field) { instance_double('BelongsToField', name: 'person', persisted_name: 'person_id') }
387
- let(:_fields) { instance_double('Fields', selects: [], belongs_to: [field], many_to_many: []) }
411
+ let(:_fields) { instance_double('Fields', selects: [], belongs_to: [field], many_to_many: [], dates_and_date_times: []) }
388
412
  let(:conditions) { { 'person' => value } }
389
413
 
390
414
  it { is_expected.to eq([{ _visible: true, content_type_id: 1, 'person_id' => 42 }, nil]) }
@@ -397,6 +421,14 @@ describe Locomotive::Steam::ContentEntryRepository do
397
421
 
398
422
  end
399
423
 
424
+ context 'the target is a hash' do
425
+
426
+ let(:value) { { '_id' => 42 } }
427
+
428
+ it { is_expected.to eq([{ _visible: true, content_type_id: 1, 'person_id' => 42 }, nil]) }
429
+
430
+ end
431
+
400
432
  context 'the target value is an arry of content entry' do
401
433
 
402
434
  let(:value) { [instance_double('TargetContentEntry', _id: 1), instance_double('TargetContentEntry', _id: 2)] }
@@ -419,7 +451,7 @@ describe Locomotive::Steam::ContentEntryRepository do
419
451
 
420
452
  let(:value) { 42 }
421
453
  let(:field) { instance_double('ManyToManyField', name: 'tags', persisted_name: 'tag_ids') }
422
- let(:_fields) { instance_double('Fields', selects: [], belongs_to: [], many_to_many: [field]) }
454
+ let(:_fields) { instance_double('Fields', selects: [], belongs_to: [], many_to_many: [field], dates_and_date_times: []) }
423
455
  let(:conditions) { { 'tags.in' => value } }
424
456
 
425
457
  it { is_expected.to eq([{ _visible: true, content_type_id: 1, 'tag_ids.in' => [42] }, nil]) }
@@ -70,4 +70,14 @@ describe Locomotive::Steam::ContentTypeFieldRepository do
70
70
 
71
71
  end
72
72
 
73
+ describe '#dates_and_date_times' do
74
+
75
+ let(:collection) { [{ name: 'name', type: 'string' }, { name: 'launched_at', type: 'date' }, { name: 'updated_at', type: 'date_time' }] }
76
+
77
+ subject { repository.dates_and_date_times }
78
+
79
+ it { expect(subject.map(&:name)).to eq(['launched_at', 'updated_at']) }
80
+
81
+ end
82
+
73
83
  end
@@ -0,0 +1,173 @@
1
+ require 'spec_helper'
2
+
3
+ describe Locomotive::Steam::ActionService do
4
+
5
+ let(:site_hash) { { 'name' => 'Acme Corp' } }
6
+ let(:site) { instance_double('Site', as_json: site_hash ) }
7
+ let(:email_service) { instance_double('EmailService') }
8
+ let(:entry_service) { instance_double('ContentService') }
9
+ let(:service) { described_class.new(site, email_service, entry_service) }
10
+
11
+ describe '#run' do
12
+
13
+ let(:script) { 'return 1 + 1;' }
14
+ let(:params) { {} }
15
+ let(:assigns) { {} }
16
+ let(:session) { {} }
17
+ let(:context) { ::Liquid::Context.new(assigns, {}, { session: session }) }
18
+
19
+ subject { service.run(script, params, context) }
20
+
21
+ it { is_expected.to eq 2.0 }
22
+
23
+ describe 'with params' do
24
+
25
+ let(:params) { { 'foo' => 'hello' } }
26
+ let(:script) { "return params.foo + ' world';" }
27
+
28
+ it { is_expected.to eq 'hello world' }
29
+
30
+ describe "messing with params" do
31
+
32
+ let(:script) { "params.foo += ' world!';" }
33
+
34
+ it { is_expected.to eq nil }
35
+
36
+ it "can't change a param value" do
37
+ subject
38
+ expect(params['foo']).to eq 'hello'
39
+ end
40
+
41
+ end
42
+
43
+ end
44
+
45
+ describe 'built-in functions / getters / setters' do
46
+
47
+ describe 'site' do
48
+
49
+ let(:script) { 'return "Name: " + site.name;' }
50
+
51
+ it { is_expected.to eq 'Name: Acme Corp' }
52
+
53
+ end
54
+
55
+ describe 'getProp' do
56
+
57
+ let(:assigns) { { 'name' => 'John' } }
58
+ let(:script) { "return getProp('name');" }
59
+
60
+ it { is_expected.to eq 'John' }
61
+
62
+ end
63
+
64
+ describe 'setProp' do
65
+
66
+ let(:script) { "return setProp('done', true);" }
67
+
68
+ it { subject; expect(context['done']).to eq true }
69
+
70
+ end
71
+
72
+ describe 'getSessionProp' do
73
+
74
+ let(:session) { { name: 'John' } }
75
+ let(:script) { "return getSessionProp('name');" }
76
+
77
+ it { is_expected.to eq 'John' }
78
+
79
+ end
80
+
81
+ describe 'sendSessionProp' do
82
+
83
+ let(:script) { "return setSessionProp('done', true);" }
84
+
85
+ it { subject; expect(session[:done]).to eq true }
86
+
87
+ end
88
+
89
+ describe 'allEntries' do
90
+
91
+ let(:now) { Time.use_zone('America/Chicago') { Time.zone.local(2015, 'mar', 25, 10, 0) } }
92
+ let(:assigns) { { 'now' => now } }
93
+ let(:script) {
94
+ <<-JS
95
+ var entries = allEntries('bands', { 'created_at.lte': getProp('now'), published: true });
96
+ var names = []
97
+
98
+ for (var i = 0; i < entries.length; i++) {
99
+ names.push(entries[i].name)
100
+ }
101
+
102
+ return names.join(', ')
103
+ JS
104
+ }
105
+
106
+ before do
107
+ expect(entry_service).to receive(:all).with('bands', { "created_at.lte" => "2015-03-25T10:00:00.000-05:00", "published" => true }, true).and_return([
108
+ { 'name' => 'Pearl Jam' },
109
+ { 'name' => 'Nirvana' },
110
+ { 'name' => 'Soundgarden' }
111
+ ])
112
+ end
113
+
114
+ it { is_expected.to eq('Pearl Jam, Nirvana, Soundgarden') }
115
+
116
+ end
117
+
118
+ describe 'findEntry' do
119
+
120
+ let(:script) { "return findEntry('bands', '42').name;" }
121
+
122
+ before do
123
+ expect(entry_service).to receive(:find).with('bands', '42', true).and_return('name' => 'Pearl Jam')
124
+ end
125
+
126
+ it { is_expected.to eq('Pearl Jam') }
127
+
128
+ end
129
+
130
+ describe 'createEntry' do
131
+
132
+ let(:script) { "return createEntry('bands', { name: 'Pearl Jam'}).name;" }
133
+
134
+ before do
135
+ expect(entry_service).to receive(:create).with('bands', { 'name' => 'Pearl Jam' }, true).and_return('name' => 'Pearl Jam')
136
+ end
137
+
138
+ it { is_expected.to eq('Pearl Jam') }
139
+
140
+ end
141
+
142
+ describe 'updateEntry' do
143
+
144
+ let(:script) { "return updateEntry('bands', 'pearl-jam', { name: 'Pearl Jam'}).name;" }
145
+
146
+ before do
147
+ expect(entry_service).to receive(:update).with('bands', 'pearl-jam', { 'name' => 'Pearl Jam' }, true).and_return('name' => 'Pearl Jam')
148
+ end
149
+
150
+ it { is_expected.to eq('Pearl Jam') }
151
+
152
+ end
153
+
154
+ describe 'sendEmail' do
155
+
156
+ let(:params) { { 'to' => 'estelle@locomotivecms.com' } }
157
+ let(:script) { "sendEmail({ to: params.to, from: 'did@locomotivecms.com', subject: 'Happy Easter' })" }
158
+
159
+ it 'forwards the action to the email service' do
160
+ expect(email_service).to receive(:send_email).with({
161
+ 'to' => 'estelle@locomotivecms.com',
162
+ 'from' => 'did@locomotivecms.com',
163
+ 'subject' => 'Happy Easter' }, context)
164
+ subject
165
+ end
166
+
167
+ end
168
+
169
+ end
170
+
171
+ end
172
+
173
+ end
@@ -0,0 +1,63 @@
1
+ require 'spec_helper'
2
+
3
+ describe Locomotive::Steam::ContentEntryService do
4
+
5
+ let(:site) { instance_double('Site', default_locale: 'en') }
6
+ let(:locale) { 'en' }
7
+ let(:type_repository) { instance_double('ContentTypeRepository') }
8
+ let(:entry_repository) { instance_double('Repository', site: site, locale: locale, content_type_repository: type_repository) }
9
+ let(:service) { described_class.new(type_repository, entry_repository, locale) }
10
+
11
+ before { allow(entry_repository).to receive(:with).and_return(entry_repository) }
12
+
13
+ describe '#validate' do
14
+
15
+ let(:attributes) { { title: 'Hello world' } }
16
+ let(:unique_fields) { {} }
17
+ let(:first_validation) { false }
18
+ let(:errors) { [:title] }
19
+ let(:type) { instance_double('Comments') }
20
+ let(:entry) { instance_double('Entry', title: 'Hello world', content_type: type, valid?: first_validation, errors: errors, attributes: { title: 'Hello world' }, localized_attributes: []) }
21
+
22
+ before do
23
+ allow(type_repository).to receive(:by_slug).and_return(type)
24
+ allow(type_repository).to receive(:look_for_unique_fields).and_return(unique_fields)
25
+ allow(entry_repository).to receive(:build).with(attributes).and_return(entry)
26
+ end
27
+
28
+ subject { service.send(:validate, entry_repository, entry) }
29
+
30
+ context 'valid' do
31
+
32
+ let(:first_validation) { true }
33
+ let(:errors) { {} }
34
+
35
+ it { is_expected.to eq true }
36
+ it { subject; expect(entry.errors.empty?).to eq true }
37
+
38
+ end
39
+
40
+ context 'not valid' do
41
+
42
+ it { is_expected.to eq false }
43
+ it { subject; expect(entry.errors).to eq([:title]) }
44
+
45
+ context 'with unique fields' do
46
+
47
+ let(:unique_fields) { { title: instance_double('Field', name: 'title') } }
48
+
49
+ before do
50
+ allow(entry_repository).to receive(:exists?).with(title: 'Hello world').and_return(true)
51
+ expect(entry.errors).to receive(:add).with(:title, :unique).and_return(true)
52
+ end
53
+
54
+ it { is_expected.to eq false }
55
+ it { subject; expect(entry.errors).to eq([:title]) }
56
+
57
+ end
58
+
59
+ end
60
+
61
+ end
62
+
63
+ end