locomotivecms_steam 1.0.0.pre.beta.3 → 1.0.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (124) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +1 -1
  3. data/Gemfile +1 -1
  4. data/Gemfile.lock +16 -11
  5. data/Rakefile +14 -2
  6. data/lib/locomotive/steam/adapters/filesystem/yaml_loader.rb +13 -3
  7. data/lib/locomotive/steam/adapters/filesystem/yaml_loaders/content_type.rb +10 -5
  8. data/lib/locomotive/steam/adapters/filesystem/yaml_loaders/page.rb +9 -0
  9. data/lib/locomotive/steam/adapters/filesystem.rb +3 -1
  10. data/lib/locomotive/steam/adapters/memory.rb +6 -1
  11. data/lib/locomotive/steam/adapters/mongodb.rb +3 -1
  12. data/lib/locomotive/steam/decorators/i18n_decorator.rb +16 -0
  13. data/lib/locomotive/steam/entities/content_entry.rb +23 -2
  14. data/lib/locomotive/steam/entities/content_type.rb +9 -0
  15. data/lib/locomotive/steam/entities/content_type_field.rb +9 -0
  16. data/lib/locomotive/steam/entities/editable_element.rb +6 -2
  17. data/lib/locomotive/steam/entities/page.rb +4 -0
  18. data/lib/locomotive/steam/entities/site.rb +11 -3
  19. data/lib/locomotive/steam/liquid/drops/base.rb +4 -0
  20. data/lib/locomotive/steam/liquid/drops/content_entry.rb +23 -0
  21. data/lib/locomotive/steam/liquid/drops/content_entry_collection.rb +7 -1
  22. data/lib/locomotive/steam/liquid/drops/content_types.rb +6 -10
  23. data/lib/locomotive/steam/liquid/filters/json.rb +21 -14
  24. data/lib/locomotive/steam/liquid/tags/editable/base.rb +14 -2
  25. data/lib/locomotive/steam/liquid/tags/editable/text.rb +15 -1
  26. data/lib/locomotive/steam/liquid/tags/google_analytics.rb +8 -12
  27. data/lib/locomotive/steam/middlewares/default_env.rb +3 -1
  28. data/lib/locomotive/steam/middlewares/entry_submission.rb +1 -1
  29. data/lib/locomotive/steam/middlewares/favicon.rb +3 -1
  30. data/lib/locomotive/steam/middlewares/helpers.rb +2 -2
  31. data/lib/locomotive/steam/middlewares/logging.rb +3 -1
  32. data/lib/locomotive/steam/middlewares/page.rb +2 -0
  33. data/lib/locomotive/steam/middlewares/path.rb +4 -2
  34. data/lib/locomotive/steam/middlewares/renderer.rb +1 -1
  35. data/lib/locomotive/steam/middlewares/robots.rb +3 -1
  36. data/lib/locomotive/steam/middlewares/sitemap.rb +1 -1
  37. data/lib/locomotive/steam/middlewares/{threadsafe.rb → thread_safe.rb} +2 -1
  38. data/lib/locomotive/steam/middlewares.rb +1 -1
  39. data/lib/locomotive/steam/models/concerns/to_json.rb +31 -0
  40. data/lib/locomotive/steam/models/entity.rb +1 -0
  41. data/lib/locomotive/steam/models/i18n_field.rb +11 -0
  42. data/lib/locomotive/steam/models.rb +1 -0
  43. data/lib/locomotive/steam/repositories.rb +3 -1
  44. data/lib/locomotive/steam/server.rb +1 -1
  45. data/lib/locomotive/steam/services/asset_host_service.rb +3 -1
  46. data/lib/locomotive/steam/services/csrf_protection_service.rb +3 -1
  47. data/lib/locomotive/steam/services/editable_element_service.rb +3 -1
  48. data/lib/locomotive/steam/services/entry_submission_service.rb +4 -2
  49. data/lib/locomotive/steam/services/image_resizer_service.rb +3 -1
  50. data/lib/locomotive/steam/services/liquid_parser_service.rb +3 -1
  51. data/lib/locomotive/steam/services/page_finder_service.rb +3 -1
  52. data/lib/locomotive/steam/services/site_finder_service.rb +3 -1
  53. data/lib/locomotive/steam/services/snippet_finder_service.rb +3 -1
  54. data/lib/locomotive/steam/services/theme_asset_url_service.rb +3 -1
  55. data/lib/locomotive/steam/services/translator_service.rb +3 -1
  56. data/lib/locomotive/steam/services/url_builder_service.rb +3 -1
  57. data/lib/locomotive/steam/services.rb +4 -2
  58. data/lib/locomotive/steam/version.rb +1 -1
  59. data/locomotivecms_steam.gemspec +3 -3
  60. data/spec/fixtures/default/README +11 -0
  61. data/spec/fixtures/default/app/views/pages/layouts/simple.liquid +14 -0
  62. data/spec/fixtures/default/config/deploy.yml +4 -3
  63. data/spec/fixtures/default/config/site.yml +1 -1
  64. data/spec/fixtures/mongodb/locomotive_accounts.bson +0 -0
  65. data/spec/fixtures/mongodb/locomotive_accounts.metadata.json +1 -1
  66. data/spec/fixtures/mongodb/locomotive_activities.bson +0 -0
  67. data/spec/fixtures/mongodb/locomotive_activities.metadata.json +1 -0
  68. data/spec/fixtures/mongodb/locomotive_content_assets.bson +0 -0
  69. data/spec/fixtures/mongodb/locomotive_content_assets.metadata.json +1 -1
  70. data/spec/fixtures/mongodb/locomotive_content_entries.bson +0 -0
  71. data/spec/fixtures/mongodb/locomotive_content_entries.metadata.json +1 -1
  72. data/spec/fixtures/mongodb/locomotive_content_types.bson +0 -0
  73. data/spec/fixtures/mongodb/locomotive_content_types.metadata.json +1 -1
  74. data/spec/fixtures/mongodb/locomotive_pages.bson +0 -0
  75. data/spec/fixtures/mongodb/locomotive_pages.metadata.json +1 -1
  76. data/spec/fixtures/mongodb/locomotive_sites.bson +0 -0
  77. data/spec/fixtures/mongodb/locomotive_sites.metadata.json +1 -1
  78. data/spec/fixtures/mongodb/locomotive_snippets.bson +0 -0
  79. data/spec/fixtures/mongodb/locomotive_snippets.metadata.json +1 -1
  80. data/spec/fixtures/mongodb/locomotive_theme_assets.bson +0 -0
  81. data/spec/fixtures/mongodb/locomotive_theme_assets.metadata.json +1 -1
  82. data/spec/fixtures/mongodb/locomotive_translations.bson +0 -0
  83. data/spec/fixtures/mongodb/locomotive_translations.metadata.json +1 -1
  84. data/spec/fixtures/mongodb/system.indexes.bson +0 -0
  85. data/spec/integration/liquid/tags/paginate_spec.rb +1 -1
  86. data/spec/integration/repositories/content_entry_repository_spec.rb +2 -2
  87. data/spec/integration/repositories/content_type_repository_spec.rb +1 -1
  88. data/spec/integration/repositories/page_repository_spec.rb +3 -3
  89. data/spec/integration/repositories/site_repository_spec.rb +3 -3
  90. data/spec/integration/repositories/snippet_repository_spec.rb +1 -1
  91. data/spec/integration/repositories/theme_asset_repository_spec.rb +3 -3
  92. data/spec/integration/repositories/translation_repository_spec.rb +1 -1
  93. data/spec/integration/server/contact_form_spec.rb +1 -1
  94. data/spec/integration/server/sitemap_spec.rb +17 -1
  95. data/spec/support/helpers.rb +4 -0
  96. data/spec/support/liquid.rb +5 -1
  97. data/spec/unit/adapters/filesystem/yaml_loaders/content_type_spec.rb +1 -0
  98. data/spec/unit/adapters/filesystem/yaml_loaders/page_spec.rb +7 -4
  99. data/spec/unit/adapters/filesystem/yaml_loaders/site_spec.rb +1 -1
  100. data/spec/unit/decorators/i18n_decorator_spec.rb +9 -0
  101. data/spec/unit/entities/content_entry_spec.rb +29 -0
  102. data/spec/unit/entities/content_type_field_spec.rb +41 -0
  103. data/spec/unit/entities/content_type_spec.rb +10 -0
  104. data/spec/unit/entities/page_spec.rb +24 -0
  105. data/spec/unit/entities/site_spec.rb +44 -6
  106. data/spec/unit/liquid/drops/content_entry_spec.rb +16 -0
  107. data/spec/unit/liquid/filters/json_spec.rb +26 -3
  108. data/spec/unit/liquid/tags/editable/control_spec.rb +1 -1
  109. data/spec/unit/liquid/tags/editable/file_spec.rb +1 -1
  110. data/spec/unit/liquid/tags/editable/model_spec.rb +1 -1
  111. data/spec/unit/liquid/tags/editable/text_spec.rb +32 -6
  112. data/spec/unit/liquid/tags/extends_spec.rb +1 -1
  113. data/spec/unit/liquid/tags/google_analytics_spec.rb +2 -1
  114. data/spec/unit/liquid/tags/inherited_block_spec.rb +1 -1
  115. data/spec/unit/middlewares/locale_redirection_spec.rb +1 -1
  116. data/spec/unit/middlewares/renderer_spec.rb +1 -1
  117. data/spec/unit/middlewares/site_spec.rb +1 -1
  118. data/spec/unit/models/concerns/to_json_spec.rb +81 -0
  119. data/spec/unit/services/asset_host_service_spec.rb +15 -0
  120. data/spec/unit/services/entry_submission_service_spec.rb +9 -1
  121. data/spec/unit/services/translator_service_spec.rb +1 -1
  122. metadata +18 -13
  123. data/spec/fixtures/mongodb/sessions.bson +0 -0
  124. data/spec/fixtures/mongodb/sessions.metadata.json +0 -1
@@ -1 +1 @@
1
- { "indexes" : [ { "v" : 1, "key" : { "_id" : 1 }, "name" : "_id_", "ns" : "locomotive_engine_2_5_dev.locomotive_theme_assets" } ] }
1
+ { "indexes" : [ { "v" : 1, "key" : { "_id" : 1 }, "name" : "_id_", "ns" : "locomotive_engine_wagon_dev.locomotive_theme_assets" } ] }
@@ -1 +1 @@
1
- { "indexes" : [ { "v" : 1, "key" : { "_id" : 1 }, "name" : "_id_", "ns" : "locomotive_engine_2_5_dev.locomotive_translations" } ] }
1
+ { "indexes" : [ { "v" : 1, "key" : { "_id" : 1 }, "name" : "_id_", "ns" : "locomotive_engine_wagon_dev.locomotive_translations" } ] }
@@ -69,7 +69,7 @@ EOF
69
69
 
70
70
  it_should_behave_like 'pagination' do
71
71
 
72
- let(:site_id) { BSON::ObjectId.from_string('54eb49c12475804b2b000002') }
72
+ let(:site_id) { mongodb_site_id }
73
73
  let(:adapter) { Locomotive::Steam::MongoDBAdapter.new(database: 'steam_test', hosts: ['127.0.0.1:27017']) }
74
74
 
75
75
  end
@@ -82,9 +82,9 @@ describe Locomotive::Steam::ContentEntryRepository do
82
82
 
83
83
  it_should_behave_like 'a repository' do
84
84
 
85
- let(:site_id) { BSON::ObjectId.from_string('54eb49c12475804b2b000002') }
85
+ let(:site_id) { mongodb_site_id }
86
86
  let(:adapter) { Locomotive::Steam::MongoDBAdapter.new(database: 'steam_test', hosts: ['127.0.0.1:27017']) }
87
- let(:entry_id) { BSON::ObjectId.from_string('54eb4bbc2475804b2b00003f') }
87
+ let(:entry_id) { BSON::ObjectId.from_string('5610310b87f6431588000029') }
88
88
 
89
89
  end
90
90
 
@@ -46,7 +46,7 @@ describe Locomotive::Steam::ContentTypeRepository do
46
46
 
47
47
  it_should_behave_like 'a repository' do
48
48
 
49
- let(:site_id) { BSON::ObjectId.from_string('54eb49c12475804b2b000002') }
49
+ let(:site_id) { mongodb_site_id }
50
50
  let(:adapter) { Locomotive::Steam::MongoDBAdapter.new(database: 'steam_test', hosts: ['127.0.0.1:27017']) }
51
51
 
52
52
  end
@@ -19,7 +19,7 @@ describe Locomotive::Steam::PageRepository do
19
19
  describe '#all' do
20
20
  let(:conditions) { {} }
21
21
  subject { repository.all(conditions) }
22
- it { expect(subject.size).to eq 24 }
22
+ it { expect(subject.size).to eq 26 }
23
23
 
24
24
  context 'with conditions' do
25
25
  let(:conditions) { { fullpath: 'index', 'slug.ne' => '404' } }
@@ -83,7 +83,7 @@ describe Locomotive::Steam::PageRepository do
83
83
  describe '#children_of' do
84
84
  let(:page) { repository.root }
85
85
  subject { repository.children_of(page) }
86
- it { expect(subject.size).to eq 14 }
86
+ it { expect(subject.size).to eq 15 }
87
87
  end
88
88
 
89
89
  describe '#editable_element_for' do
@@ -98,7 +98,7 @@ describe Locomotive::Steam::PageRepository do
98
98
 
99
99
  it_should_behave_like 'a repository' do
100
100
 
101
- let(:site_id) { BSON::ObjectId.from_string('54eb49c12475804b2b000002') }
101
+ let(:site_id) { mongodb_site_id }
102
102
  let(:adapter) { Locomotive::Steam::MongoDBAdapter.new(database: 'steam_test', hosts: ['127.0.0.1:27017']) }
103
103
 
104
104
  end
@@ -15,12 +15,12 @@ describe Locomotive::Steam::SiteRepository do
15
15
  end
16
16
 
17
17
  describe '#query' do
18
- subject { repository.query { where(subdomain: 'sample') }.first }
19
- it { expect(subject.name).to eq 'Sample website' }
18
+ subject { repository.query { where(handle: 'sample') }.first }
19
+ it { expect(subject.name).to eq 'Sample site' }
20
20
  end
21
21
 
22
22
  describe '#by_domain' do
23
- subject { repository.by_domain('sample.lvh.me') }
23
+ subject { repository.by_domain('sample.example.com') }
24
24
  it { expect(subject).not_to eq nil }
25
25
  end
26
26
 
@@ -27,7 +27,7 @@ describe Locomotive::Steam::SnippetRepository do
27
27
 
28
28
  it_should_behave_like 'a repository' do
29
29
 
30
- let(:site_id) { BSON::ObjectId.from_string('54eb49c12475804b2b000002') }
30
+ let(:site_id) { mongodb_site_id }
31
31
  let(:adapter) { Locomotive::Steam::MongoDBAdapter.new(database: 'steam_test', hosts: ['127.0.0.1:27017']) }
32
32
 
33
33
  end
@@ -10,7 +10,7 @@ describe Locomotive::Steam::ThemeAssetRepository do
10
10
 
11
11
  context 'MongoDB' do
12
12
 
13
- let(:site_id) { BSON::ObjectId.from_string('54eb49c12475804b2b000002') }
13
+ let(:site_id) { mongodb_site_id }
14
14
  let(:adapter) { Locomotive::Steam::MongoDBAdapter.new(database: 'steam_test', hosts: ['127.0.0.1:27017']) }
15
15
 
16
16
  describe '#all' do
@@ -20,13 +20,13 @@ describe Locomotive::Steam::ThemeAssetRepository do
20
20
 
21
21
  describe '#url_for' do
22
22
  subject { repository.url_for('stylesheets/application.css') }
23
- it { is_expected.to eq '/sites/54eb49c12475804b2b000002/theme/stylesheets/application.css' }
23
+ it { is_expected.to eq "/sites/#{mongodb_site_id}/theme/stylesheets/application.css" }
24
24
  end
25
25
 
26
26
  describe '#checksums' do
27
27
  subject { repository.checksums }
28
28
  it { expect(subject.size).to eq 16 }
29
- it { expect(subject['stylesheets/application.css']).to eq 'aa017461d702a80ef8837e51e65deb4f' }
29
+ it { expect(subject['stylesheets/application.css']).to eq '3bacf4c2b7877e230e6990d72dae7724' }
30
30
  end
31
31
 
32
32
  end
@@ -27,7 +27,7 @@ describe Locomotive::Steam::TranslationRepository do
27
27
 
28
28
  it_should_behave_like 'a repository' do
29
29
 
30
- let(:site_id) { BSON::ObjectId.from_string('54eb49c12475804b2b000002') }
30
+ let(:site_id) { mongodb_site_id }
31
31
  let(:adapter) { Locomotive::Steam::MongoDBAdapter.new(database: 'steam_test', hosts: ['127.0.0.1:27017']) }
32
32
 
33
33
  end
@@ -32,7 +32,7 @@ describe 'ContactForm' do
32
32
 
33
33
  let(:url) { '/entry_submissions/foo' }
34
34
 
35
- it { expect { response }.to raise_error('Unknown content type "foo"') }
35
+ it { expect { response }.to raise_error('Unknown content type "foo" or public_submission_enabled property not true') }
36
36
 
37
37
  end
38
38
 
@@ -1,5 +1,7 @@
1
1
  require File.dirname(__FILE__) + '/../integration_helper'
2
2
 
3
+ require 'locomotive/steam/adapters/filesystem.rb'
4
+
3
5
  describe Locomotive::Steam::Server do
4
6
 
5
7
  include Rack::Test::Methods
@@ -11,8 +13,9 @@ describe Locomotive::Steam::Server do
11
13
  describe 'sitemap.xml' do
12
14
 
13
15
  let(:now) { Time.use_zone('America/Chicago') { Time.zone.local(2015, 'mar', 25, 10, 0) } }
16
+ let(:env) { {} }
14
17
 
15
- subject { Timecop.freeze(now) { get '/sitemap.xml' }; last_response.body }
18
+ subject { Timecop.freeze(now) { get('/sitemap.xml', {}, env) }; last_response.body }
16
19
 
17
20
  before { Locomotive::Steam::Adapters::Filesystem::SimpleCacheStore.new.clear }
18
21
 
@@ -29,6 +32,19 @@ describe Locomotive::Steam::Server do
29
32
  EOF
30
33
  ).strip)
31
34
  end
35
+
36
+ context 'existing sitemap page' do
37
+
38
+ let(:template) { %{<?xml version="1.0" encoding="utf-8"?>OK</xml>} }
39
+ let(:page) { instance_double('Page', liquid_source: template, templatized?: false, redirect_url: false, to_liquid: template, not_found?: false, response_type: 'application/xml') }
40
+ let(:env) { { 'steam.page' => page } }
41
+
42
+ it 'renders the existing sitemap page' do
43
+ expect(subject).to eq %{<?xml version="1.0" encoding="utf-8"?>OK</xml>}
44
+ end
45
+
46
+ end
47
+
32
48
  end
33
49
 
34
50
  end
@@ -3,6 +3,10 @@ require 'locomotive/common'
3
3
  module Spec
4
4
  module Helpers
5
5
 
6
+ def mongodb_site_id
7
+ BSON::ObjectId.from_string('561030e287f6431555000006')
8
+ end
9
+
6
10
  def reset!
7
11
  FileUtils.rm_rf(File.expand_path('../../../site', __FILE__))
8
12
  end
@@ -12,12 +12,16 @@ module Liquid
12
12
 
13
13
  class TestDrop < Liquid::Drop
14
14
  def initialize(source)
15
- @_source = source
15
+ @_source = source.with_indifferent_access
16
16
  end
17
17
 
18
18
  def before_method(meth)
19
19
  @_source[meth.to_sym]
20
20
  end
21
+
22
+ def as_json(options = nil)
23
+ @_source.as_json(options)
24
+ end
21
25
  end
22
26
 
23
27
  class SimpleEventsListener
@@ -18,6 +18,7 @@ describe Locomotive::Steam::Adapters::Filesystem::YAMLLoaders::ContentType do
18
18
  expect(subject.size).to eq 5
19
19
  expect(subject.first[:slug]).to eq('bands')
20
20
  expect(subject.first[:entries_custom_fields].size).to eq 5
21
+ expect(subject.first[:entries_custom_fields].first[:position]).to eq 0
21
22
  end
22
23
 
23
24
  end
@@ -15,11 +15,14 @@ describe Locomotive::Steam::Adapters::Filesystem::YAMLLoaders::Page do
15
15
  subject { loader.load(scope).sort { |a, b| a[:_fullpath] <=> b[:_fullpath] } }
16
16
 
17
17
  it 'tests various stuff' do
18
- expect(subject.size).to eq 24
18
+ expect(subject.size).to eq 26
19
19
  expect(subject.first[:title]).to eq(en: 'Page not found')
20
- expect(subject[14][:slug]).to eq(en: 'music', fr: 'notre-musique')
21
- expect(subject[15][:_fullpath]).to eq 'songs'
22
- expect(subject[15][:template_path]).to eq(en: false)
20
+ expect(subject[15][:is_layout]).to eq true
21
+ expect(subject[15][:listed]).to eq false
22
+ expect(subject[15][:published]).to eq false
23
+ expect(subject[16][:slug]).to eq(en: 'music', fr: 'notre-musique')
24
+ expect(subject[17][:_fullpath]).to eq 'songs'
25
+ expect(subject[17][:template_path]).to eq(en: false)
23
26
  end
24
27
 
25
28
  end
@@ -12,7 +12,7 @@ describe Locomotive::Steam::Adapters::Filesystem::YAMLLoaders::Site do
12
12
 
13
13
  subject { loader.load(nil) }
14
14
 
15
- it { expect(subject.first[:name]).to eq 'Sample website' }
15
+ it { expect(subject.first[:name]).to eq 'Sample site' }
16
16
 
17
17
  end
18
18
 
@@ -83,6 +83,15 @@ describe Locomotive::Steam::Decorators::I18nDecorator do
83
83
  expect(decorated.__locale__).to eq :fr
84
84
  end
85
85
 
86
+ describe '#to_hash' do
87
+
88
+ before { expect(page).to receive(:to_hash).and_return('title' => { 'en' => 'some stuff', 'fr' => 'some stuff' }) }
89
+ subject { decorated.to_hash }
90
+
91
+ it { expect(subject).to eq('title' => 'Bonjour monde', 'slug' => 'hello-world') }
92
+
93
+ end
94
+
86
95
  def i18n_field(name, translations)
87
96
  Locomotive::Steam::Models::I18nField.new(name, translations)
88
97
  end
@@ -55,6 +55,35 @@ describe Locomotive::Steam::ContentEntry do
55
55
 
56
56
  end
57
57
 
58
+ describe '#to_hash' do
59
+
60
+ let(:fields) { [instance_double('TitleField', name: :title, type: :string), instance_double('PictureField', name: :picture, type: :file, localized: true)] }
61
+ let(:attributes) { { id: 42, title: 'Hello world', _slug: 'hello-world', picture: Locomotive::Steam::Models::I18nField.new(:picture, fr: 'foo.png', en: 'bar.png'), custom_fields_recipe: ['hello', 'world'], _type: 'Entry' } }
62
+
63
+ subject { content_entry.to_hash }
64
+
65
+ before do
66
+ allow(type).to receive(:fields_by_name).and_return({ title: fields.first, picture: fields.last })
67
+ allow(type).to receive(:persisted_field_names).and_return([:title, :picture])
68
+ allow(content_entry).to receive(:base_url).and_return('/assets')
69
+ end
70
+
71
+ it { expect(Set.new(subject.keys)).to eq(Set.new(['_id', '_position', '_visible', '_label', '_slug', 'content_type_slug', 'title', 'picture', 'created_at', 'updated_at'])) }
72
+
73
+ context 'when decorated' do
74
+
75
+ let(:decorated) { Locomotive::Steam::Decorators::I18nDecorator.new(content_entry, :fr, :en) }
76
+
77
+ before { allow(content_entry).to receive(:localized_attributes).and_return({ picture: true }) }
78
+
79
+ subject { decorated.to_hash }
80
+
81
+ it { expect(subject['picture'].url).to eq '/assets/foo.png' }
82
+
83
+ end
84
+
85
+ end
86
+
58
87
  describe 'dynamic attributes' do
59
88
 
60
89
  let(:field_type) { :string }
@@ -74,4 +74,45 @@ describe Locomotive::Steam::ContentTypeField do
74
74
 
75
75
  end
76
76
 
77
+ describe '#persisted_name' do
78
+
79
+ subject { field.persisted_name }
80
+
81
+ context 'string type' do
82
+
83
+ let(:attributes) { { name: 'title', type: 'string' } }
84
+ it { is_expected.to eq 'title' }
85
+
86
+ end
87
+
88
+ context 'select type' do
89
+
90
+ let(:attributes) { { name: 'category', type: 'select' } }
91
+ it { is_expected.to eq 'category_id' }
92
+
93
+ end
94
+
95
+ context 'belongs_to type' do
96
+
97
+ let(:attributes) { { name: 'article', class_name: 'articles', type: 'belongs_to' } }
98
+ it { is_expected.to eq 'article_id' }
99
+
100
+ end
101
+
102
+ context 'many_to_many type' do
103
+
104
+ let(:attributes) { { name: 'articles', class_name: 'articles', type: 'many_to_many' } }
105
+ it { is_expected.to eq 'article_ids' }
106
+
107
+ end
108
+
109
+ context 'has_many type' do
110
+
111
+ let(:attributes) { { name: 'articles', class_name: 'articles', type: 'has_many', inverse_of: 'author' } }
112
+ it { is_expected.to eq nil }
113
+
114
+ end
115
+
116
+ end
117
+
77
118
  end
@@ -56,4 +56,14 @@ describe Locomotive::Steam::ContentType do
56
56
 
57
57
  end
58
58
 
59
+ describe '#persisted_field_names' do
60
+
61
+ let(:fields) { [instance_double('Field1', name: :title, persisted_name: 'title'), instance_double('Field2', name: :author, persisted_name: nil)] }
62
+
63
+ subject { content_type.persisted_field_names }
64
+
65
+ it { is_expected.to eq(['title']) }
66
+
67
+ end
68
+
59
69
  end
@@ -53,4 +53,28 @@ describe Locomotive::Steam::Page do
53
53
  end
54
54
  end
55
55
 
56
+ describe '#redirect?' do
57
+
58
+ subject { page.redirect? }
59
+
60
+ it { is_expected.to eq false }
61
+
62
+ context 'redirect_url has been set' do
63
+
64
+ let(:attributes) { { redirect: nil, redirect_url: 'http://www.google.fr' } }
65
+
66
+ it { is_expected.to eq true }
67
+
68
+ context 'but redirect is set to false' do
69
+
70
+ let(:attributes) { { redirect: false, redirect_url: 'http://www.google.fr' } }
71
+
72
+ it { is_expected.to eq false }
73
+
74
+ end
75
+
76
+ end
77
+
78
+ end
79
+
56
80
  end
@@ -23,19 +23,35 @@ describe Locomotive::Steam::Site do
23
23
 
24
24
  describe '#locales' do
25
25
 
26
- let(:attributes) { { locales: %w(en fr) } }
27
-
28
26
  subject { site.locales }
29
- it { is_expected.to eq [:en, :fr] }
27
+
28
+ context 'without locales' do
29
+ it { is_expected.to eq [:en] }
30
+ end
31
+
32
+ context 'with locales' do
33
+
34
+ let(:attributes) { { locales: %w(en fr) } }
35
+ it { is_expected.to eq [:en, :fr] }
36
+
37
+ end
30
38
 
31
39
  end
32
40
 
33
41
  describe '#default_locale' do
34
42
 
35
- let(:attributes) { { locales: %w(en fr) } }
36
-
37
43
  subject { site.default_locale }
38
- it { is_expected.to eq :en }
44
+
45
+ context 'without locales' do
46
+ it { is_expected.to eq :en }
47
+ end
48
+
49
+ context 'with locales' do
50
+
51
+ let(:attributes) { { locales: %w(en fr) } }
52
+ it { is_expected.to eq :en }
53
+
54
+ end
39
55
 
40
56
  end
41
57
 
@@ -60,4 +76,26 @@ describe Locomotive::Steam::Site do
60
76
 
61
77
  end
62
78
 
79
+ describe '#last_modified_at' do
80
+
81
+ subject { site.last_modified_at }
82
+
83
+ it { is_expected.to eq nil }
84
+
85
+ context 'only updated_at is defined' do
86
+
87
+ let(:attributes) { { updated_at: DateTime.parse('2015/10/16 00:00:00') } }
88
+ it { is_expected.to eq DateTime.parse('2015/10/16 00:00:00') }
89
+
90
+ end
91
+
92
+ context 'template_version or content_version are defined' do
93
+
94
+ let(:attributes) { { updated_at: DateTime.parse('2015/10/16 00:00:00'), template_version: DateTime.parse('2007/06/29 00:00:00'), content_version: DateTime.parse('2009/09/10 00:00:00') } }
95
+ it { is_expected.to eq DateTime.parse('2009/09/10 00:00:00') }
96
+
97
+ end
98
+
99
+ end
100
+
63
101
  end
@@ -96,4 +96,20 @@ describe Locomotive::Steam::Liquid::Drops::ContentEntry do
96
96
 
97
97
  end
98
98
 
99
+ describe '#as_json' do
100
+
101
+ let(:type) { instance_double('Type', fields_by_name: { title: instance_double('StringField', type: :string ), picture: instance_double('FileField', type: :file), category: instance_double('SelectField', type: :select) }) }
102
+ let(:picture_field) { Locomotive::Steam::ContentEntry::FileField.new('foo.png', 'http://assets.dev', 42) }
103
+
104
+ before do
105
+ allow(entry).to receive(:to_hash).and_return({ '_id' => 1, 'title' => 'Hello world', 'picture' => picture_field, 'category_id' => 42 })
106
+ allow(entry).to receive(:category).and_return('Test')
107
+ end
108
+
109
+ subject { drop.as_json }
110
+
111
+ it { is_expected.to eq('id' => 1, '_id' => 1, 'title' => 'Hello world', 'picture' => 'http://assets.dev/foo.png?42', 'picture_url' => 'http://assets.dev/foo.png?42', 'category_id' => 42, 'category' => 'Test') }
112
+
113
+ end
114
+
99
115
  end
@@ -19,7 +19,7 @@ describe Locomotive::Steam::Liquid::Filters::Json do
19
19
  describe 'includes only the fields specified' do
20
20
 
21
21
  let(:input) { [Liquid::TestDrop.new(title: 'Acme', body: 'Lorem ipsum'), 'title'] }
22
- it { expect(subject).to eq %("title":"Acme") }
22
+ it { expect(subject).to eq %({"title":"Acme"}) }
23
23
 
24
24
  end
25
25
 
@@ -39,7 +39,7 @@ describe Locomotive::Steam::Liquid::Filters::Json do
39
39
  let(:input) {
40
40
  [[Liquid::TestDrop.new(title: 'Acme', body: 'Lorem ipsum'),
41
41
  Liquid::TestDrop.new(title: 'Hello world', body: 'Lorem ipsum')], 'title'] }
42
- it { expect(subject).to eq %("Acme","Hello world") }
42
+ it { expect(subject).to eq %(["Acme","Hello world"]) }
43
43
 
44
44
  end
45
45
 
@@ -48,7 +48,30 @@ describe Locomotive::Steam::Liquid::Filters::Json do
48
48
  let(:input) {
49
49
  [[Liquid::TestDrop.new(title: 'Acme', body: 'Lorem ipsum', date: '2013-12-13'),
50
50
  Liquid::TestDrop.new(title: 'Hello world', body: 'Lorem ipsum', date: '2013-12-12')], 'title, body'] }
51
- it { expect(subject).to eq %({"title":"Acme","body":"Lorem ipsum"},{"title":"Hello world","body":"Lorem ipsum"}) }
51
+ it { expect(subject).to eq %([{"title":"Acme","body":"Lorem ipsum"},{"title":"Hello world","body":"Lorem ipsum"}]) }
52
+
53
+ end
54
+
55
+ end
56
+
57
+ describe '#open_json' do
58
+
59
+ let(:input) { '' }
60
+ subject { open_json(input) }
61
+
62
+ it { expect(subject).to eq '' }
63
+
64
+ context 'without leading and trailing brackets' do
65
+
66
+ let(:input) { %(["foo",[1,2],"bar"]) }
67
+ it { expect(subject).to eq %("foo",[1,2],"bar") }
68
+
69
+ end
70
+
71
+ context 'without leading and trailing braces' do
72
+
73
+ let(:input) { %({"title":"Acme","body":"Lorem ipsum"}) }
74
+ it { expect(subject).to eq %("title":"Acme","body":"Lorem ipsum") }
52
75
 
53
76
  end
54
77
 
@@ -2,7 +2,7 @@ require 'spec_helper'
2
2
 
3
3
  describe Locomotive::Steam::Liquid::Tags::Editable::Control do
4
4
 
5
- let(:page) { instance_double('Page') }
5
+ let(:page) { instance_double('Page', fullpath: 'hello-world') }
6
6
  let!(:listener) { Liquid::SimpleEventsListener.new }
7
7
  let(:options) { { page: page } }
8
8
 
@@ -2,7 +2,7 @@ require 'spec_helper'
2
2
 
3
3
  describe Locomotive::Steam::Liquid::Tags::Editable::File do
4
4
 
5
- let(:page) { instance_double('Page', updated_at: DateTime.parse('2007-06-29 21:00:00')) }
5
+ let(:page) { instance_double('Page', fullpath: 'hello-world', updated_at: DateTime.parse('2007-06-29 21:00:00')) }
6
6
  let!(:listener) { Liquid::SimpleEventsListener.new }
7
7
  let(:options) { { page: page } }
8
8
 
@@ -2,7 +2,7 @@ require 'spec_helper'
2
2
 
3
3
  describe Locomotive::Steam::Liquid::Tags::Editable::Model do
4
4
 
5
- let(:page) { instance_double('Page') }
5
+ let(:page) { instance_double('Page', fullpath: 'hello-world') }
6
6
  let!(:listener) { Liquid::SimpleEventsListener.new }
7
7
  let(:options) { { page: page } }
8
8
 
@@ -2,7 +2,7 @@ require 'spec_helper'
2
2
 
3
3
  describe Locomotive::Steam::Liquid::Tags::Editable::Text do
4
4
 
5
- let(:page) { instance_double('Page') }
5
+ let(:page) { instance_double('Page', fullpath: 'hello-world') }
6
6
  let!(:listener) { Liquid::SimpleEventsListener.new }
7
7
  let(:options) { { page: page } }
8
8
 
@@ -74,10 +74,10 @@ describe Locomotive::Steam::Liquid::Tags::Editable::Text do
74
74
  let(:live_editing) { false }
75
75
  let(:element_editing) { true }
76
76
 
77
- let(:page) { instance_double('Page', fullpath: 'hello-world') }
78
- let(:element) { instance_double('EditableText', _id: 42, id: 42, default_content?: true, inline_editing?: element_editing, inline_editing: element_editing) }
77
+ let(:child_page) { instance_double('Page', fullpath: 'child-page') }
78
+ let(:element) { instance_double('EditableText', _id: 42, id: 42, default_content?: true, inline_editing?: element_editing, inline_editing: element_editing, format: 'html') }
79
79
  let(:services) { Locomotive::Steam::Services.build_instance(nil) }
80
- let(:context) { ::Liquid::Context.new({}, {}, { page: page, services: services, live_editing: live_editing }) }
80
+ let(:context) { ::Liquid::Context.new({}, {}, { page: child_page, services: services, live_editing: live_editing }) }
81
81
 
82
82
  before { allow(services.editable_element).to receive(:find).and_return(element) }
83
83
 
@@ -85,6 +85,11 @@ describe Locomotive::Steam::Liquid::Tags::Editable::Text do
85
85
 
86
86
  it { is_expected.to eq 'Hello world' }
87
87
 
88
+ it "doesn't try to find the element in another page" do
89
+ expect(services.page_finder).not_to receive(:find).with('hello-world')
90
+ is_expected.to eq 'Hello world'
91
+ end
92
+
88
93
  context 'no element found, render the default content' do
89
94
 
90
95
  let(:element) { nil }
@@ -92,9 +97,23 @@ describe Locomotive::Steam::Liquid::Tags::Editable::Text do
92
97
 
93
98
  end
94
99
 
100
+ context 'fixed element' do
101
+
102
+ let(:layout) { instance_double('Page', fullpath: 'layout') }
103
+ let(:source) { "{% editable_text title, hint: 'Simple short text', fixed: true %}Hello world{% endeditable_text %}" }
104
+ let(:options) { { page: layout } }
105
+ let(:element) { instance_double('EditableText', _id: 42, id: 42, default_content?: true, inline_editing?: element_editing, inline_editing: element_editing, format: 'html', fixed: true) }
106
+
107
+ it 'fetches the related page in order to get the element' do
108
+ expect(services.page_finder).to receive(:find).with('layout').and_return(layout)
109
+ is_expected.to eq 'Hello world'
110
+ end
111
+
112
+ end
113
+
95
114
  context 'modified content' do
96
115
 
97
- let(:element) { instance_double('EditableText', content: 'Hello world!', default_content?: false) }
116
+ let(:element) { instance_double('EditableText', content: 'Hello world!', default_content?: false, format: 'html') }
98
117
  it { is_expected.to eq 'Hello world!' }
99
118
 
100
119
  end
@@ -103,11 +122,18 @@ describe Locomotive::Steam::Liquid::Tags::Editable::Text do
103
122
 
104
123
  let(:source) { '{% block wrapper %}{% block sidebar %}{% editable_text title %}Hello world{% endeditable_text %}{% endblock %}{% endblock %}' }
105
124
 
106
- before { expect(services.editable_element).to receive(:find).with(page, 'wrapper/sidebar', 'title').and_return(element) }
125
+ before { expect(services.editable_element).to receive(:find).with(child_page, 'wrapper/sidebar', 'title').and_return(element) }
107
126
  it { is_expected.to eq 'Hello world' }
108
127
 
109
128
  end
110
129
 
130
+ context 'markdown format' do
131
+
132
+ let(:element) { instance_double('EditableText', content: "#Hello world!\nLorem ipsum", default_content?: false, format: 'markdown') }
133
+ it { is_expected.to eq "<h1>Hello world!</h1>\n<p>Lorem ipsum</p>\n" }
134
+
135
+ end
136
+
111
137
  context 'inline-editing mode' do
112
138
 
113
139
  let(:live_editing) { true }