locomotivecms_steam 1.0.0 → 1.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (54) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile.lock +7 -7
  3. data/bin/steam.rb +1 -1
  4. data/lib/locomotive/steam/adapters/filesystem.rb +8 -1
  5. data/lib/locomotive/steam/adapters/filesystem/sanitizers/content_entry.rb +27 -1
  6. data/lib/locomotive/steam/adapters/filesystem/sanitizers/site.rb +51 -0
  7. data/lib/locomotive/steam/adapters/filesystem/yaml_loaders/site.rb +8 -0
  8. data/lib/locomotive/steam/adapters/mongodb.rb +20 -1
  9. data/lib/locomotive/steam/adapters/mongodb/command.rb +8 -0
  10. data/lib/locomotive/steam/adapters/mongodb/query.rb +20 -1
  11. data/lib/locomotive/steam/entities/content_type.rb +1 -0
  12. data/lib/locomotive/steam/entities/content_type_field.rb +2 -1
  13. data/lib/locomotive/steam/entities/site.rb +3 -1
  14. data/lib/locomotive/steam/initializers/sprockets.rb +13 -3
  15. data/lib/locomotive/steam/liquid/drops/content_entry.rb +1 -1
  16. data/lib/locomotive/steam/liquid/drops/metafields.rb +97 -0
  17. data/lib/locomotive/steam/liquid/drops/site.rb +4 -0
  18. data/lib/locomotive/steam/liquid/filters/misc.rb +4 -0
  19. data/lib/locomotive/steam/liquid/tags/consume.rb +17 -6
  20. data/lib/locomotive/steam/liquid/tags/nav.rb +17 -11
  21. data/lib/locomotive/steam/middlewares/helpers.rb +1 -1
  22. data/lib/locomotive/steam/middlewares/page.rb +1 -0
  23. data/lib/locomotive/steam/middlewares/renderer.rb +8 -2
  24. data/lib/locomotive/steam/models/repository.rb +4 -0
  25. data/lib/locomotive/steam/repositories/content_type_field_repository.rb +4 -0
  26. data/lib/locomotive/steam/version.rb +1 -1
  27. data/locomotivecms_steam.gemspec +1 -1
  28. data/spec/fixtures/default/app/content_types/events.yml +1 -0
  29. data/spec/fixtures/default/app/views/pages/basic.liquid.haml +12 -0
  30. data/spec/fixtures/default/app/views/pages/tags/nav.liquid.haml +2 -0
  31. data/spec/fixtures/default/config/metafields_schema.yml +33 -0
  32. data/spec/fixtures/default/config/site.yml +13 -0
  33. data/spec/fixtures/default/data/events.yml +1 -2
  34. data/spec/integration/adapters/mongodb_spec.rb +49 -0
  35. data/spec/integration/repositories/content_entry_repository_spec.rb +26 -0
  36. data/spec/integration/server/metafields_spec.rb +26 -0
  37. data/spec/integration/server/nav_spec.rb +8 -0
  38. data/spec/unit/adapters/filesystem/sanitizers/site_spec.rb +59 -0
  39. data/spec/unit/adapters/filesystem/yaml_loaders/site_spec.rb +12 -2
  40. data/spec/unit/adapters/filesystem_adapter_spec.rb +18 -0
  41. data/spec/unit/adapters/mongodb/query_spec.rb +25 -1
  42. data/spec/unit/entities/content_type_spec.rb +10 -0
  43. data/spec/unit/initializers/sprockets_spec.rb +36 -0
  44. data/spec/unit/liquid/drops/content_entry_spec.rb +3 -1
  45. data/spec/unit/liquid/drops/metafields_spec.rb +81 -0
  46. data/spec/unit/liquid/filters/misc_spec.rb +13 -0
  47. data/spec/unit/liquid/tags/consume_spec.rb +7 -0
  48. data/spec/unit/liquid/tags/nav_spec.rb +9 -1
  49. data/spec/unit/liquid/tags/path_to_spec.rb +1 -1
  50. data/spec/unit/middlewares/helpers_spec.rb +32 -0
  51. data/spec/unit/middlewares/renderer_spec.rb +17 -2
  52. data/spec/unit/repositories/content_entry_repository_spec.rb +11 -11
  53. data/spec/unit/repositories/content_type_field_repository_spec.rb +10 -0
  54. metadata +18 -4
@@ -0,0 +1,26 @@
1
+ require File.dirname(__FILE__) + '/../integration_helper'
2
+
3
+ describe 'Site metafields' do
4
+
5
+ include Rack::Test::Methods
6
+
7
+ def app
8
+ run_server
9
+ end
10
+
11
+ it 'returns all the values of the site metafields' do
12
+ get '/basic'
13
+ expect(last_response.body).to include 'Color scheme=white'
14
+ expect(last_response.body).to include 'Facebook ID=FB42'
15
+ expect(last_response.body).to include 'Google ID=G42'
16
+ expect(last_response.body).to include 'API URL=https://api.github.com/repos/vmg/redcarpet/issues?state=closed'
17
+ expect(last_response.body).to include 'Expires In=42'
18
+ end
19
+
20
+ it 'iterates over the metafields of a namespace' do
21
+ get '/basic'
22
+ expect(last_response.body).to include "<li class='property'>Facebook(facebook_id)=FB42</li>"
23
+ expect(last_response.body).to include "<li class='property'>Google(google_id)=G42</li>"
24
+ end
25
+
26
+ end
@@ -37,6 +37,14 @@ describe Locomotive::Steam::Server do
37
37
 
38
38
  end
39
39
 
40
+ describe 'with snippet to render the label' do
41
+
42
+ subject { get '/tags/nav'; last_response.body }
43
+
44
+ it { is_expected.to include('<li id="store-link" class="link"><a href="/store">-Store-</a></li>') }
45
+
46
+ end
47
+
40
48
  describe 'very deep' do
41
49
 
42
50
  subject { get '/tags/nav-in-deep'; last_response.body }
@@ -0,0 +1,59 @@
1
+ require 'spec_helper'
2
+
3
+ require_relative '../../../../../lib/locomotive/steam/adapters/filesystem/sanitizer.rb'
4
+ require_relative '../../../../../lib/locomotive/steam/adapters/filesystem/sanitizers/site.rb'
5
+
6
+ describe Locomotive::Steam::Adapters::Filesystem::Sanitizers::Site do
7
+
8
+ let(:schema) { nil }
9
+ let(:entity) { instance_double('SiteEntity', metafields_schema: schema) }
10
+ let(:sanitizer) { described_class.new }
11
+
12
+ describe '#apply_to_entity' do
13
+
14
+ subject { sanitizer.apply_to_entity(entity) }
15
+
16
+ it { expect(entity).to receive(:metafields_schema=).with(nil); subject }
17
+
18
+ end
19
+
20
+ describe '#clean_metafields_schema' do
21
+
22
+ subject { sanitizer.send(:clean_metafields_schema, schema) }
23
+
24
+ it { is_expected.to eq nil }
25
+
26
+ describe 'with a schema' do
27
+
28
+ # see the metafields_schema.yml in the fixtures folder
29
+ let(:schema) { {:social=>{:label=>{:fr=>"Social (FR)"}, :position=>1, :fields=>["facebook_id", "google_id"]}, :github=>{:position=>0, :fields=>{:api_url=>{:label=>"API Url", :type=>"string", :hint=>"API endpoint"}, :expires_in=>{:label=>{:en=>"Expires in", :fr=>"Expire dans"}, :hint=>{:en=>"Cache - In milliseconds", :fr=>"Cache - En millisecondes"}, :type=>"integer", :min=>0, :max=>3600}}}} }
30
+
31
+ it 'loads the full schema' do
32
+ # First namespace
33
+ expect(subject[0]['name']).to eq 'social'
34
+ expect(subject[0]['label']).to eq('fr' => 'Social (FR)')
35
+ expect(subject[0]['position']).to eq 1
36
+ expect(subject[0]['fields']).to eq([{ 'name' => 'facebook_id', 'position' => 0 }, { 'name' => 'google_id', 'position' => 1 }])
37
+
38
+ # Second namespace
39
+ expect(subject[1]['label']).to eq('default' => 'github')
40
+ expect(subject[1]['position']).to eq 0
41
+ expect(subject[1]['fields'].count).to eq 2
42
+ expect(subject[1]['fields'][0]).to eq('name' => 'api_url', 'position' => 0, 'label' => { 'default' => 'API Url' }, 'type' => 'string', 'hint' => { 'default' => 'API endpoint' })
43
+ end
44
+
45
+ context 'label is a string instead of a hash' do
46
+
47
+ let(:schema) { {:social=>{:label=>"Social", :position=>1, :fields=>["facebook_id", "google_id"]}, :github=>{:position=>0, :fields=>{:api_url=>{:label=>"API Url", :type=>"string", :hint=>"API endpoint"}, :expires_in=>{:label=>{:en=>"Expires in", :fr=>"Expire dans"}, :hint=>{:en=>"Cache - In milliseconds", :fr=>"Cache - En millisecondes"}, :type=>"integer", :min=>0, :max=>3600}}}} }
48
+
49
+ it 'loads the full schema' do
50
+ expect(subject[0]['label']).to eq('default' => 'Social')
51
+ end
52
+
53
+ end
54
+
55
+ end
56
+
57
+ end
58
+
59
+ end
@@ -10,9 +10,19 @@ describe Locomotive::Steam::Adapters::Filesystem::YAMLLoaders::Site do
10
10
 
11
11
  describe '#load' do
12
12
 
13
- subject { loader.load(nil) }
13
+ subject { loader.load(nil).first }
14
14
 
15
- it { expect(subject.first[:name]).to eq 'Sample site' }
15
+ it { expect(subject[:name]).to eq 'Sample site' }
16
+
17
+ describe '#metafields_schema' do
18
+
19
+ subject { loader.load(nil).first[:metafields_schema] }
20
+
21
+ it 'loads the full schema' do
22
+ expect(subject.count).to eq 3
23
+ end
24
+
25
+ end
16
26
 
17
27
  end
18
28
 
@@ -50,4 +50,22 @@ describe Locomotive::Steam::FilesystemAdapter do
50
50
 
51
51
  end
52
52
 
53
+ describe '#inc' do
54
+
55
+ let(:entity) { OpenStruct.new(name: 'My post', views: 41) }
56
+
57
+ subject { adapter.inc(mapper, entity, :views) }
58
+
59
+ it { expect(subject.views).to eq 42 }
60
+
61
+ describe 'by an amount different from 1' do
62
+
63
+ subject { adapter.inc(mapper, entity, :views, 3) }
64
+
65
+ it { expect(subject.views).to eq 44 }
66
+
67
+ end
68
+
69
+ end
70
+
53
71
  end
@@ -40,7 +40,31 @@ describe Locomotive::Steam::Adapters::MongoDB::Query do
40
40
 
41
41
  describe '#order_by' do
42
42
 
43
- it { expect(query.order_by(title: :asc, published: :desc).sort).to eq [{title: :asc, published: :desc}] }
43
+ subject { query.order_by(order_by).sort }
44
+
45
+ context 'passing a hash' do
46
+
47
+ let(:order_by) { { title: :asc, published: :desc } }
48
+
49
+ it { is_expected.to eq [{title: :asc, published: :desc}] }
50
+
51
+ end
52
+
53
+ context 'passing an array of strings' do
54
+
55
+ let(:order_by) { ['title.asc', 'published'] }
56
+
57
+ it { is_expected.to eq [[['title', 'asc'], ['published']]] }
58
+
59
+ end
60
+
61
+ context 'passing a string' do
62
+
63
+ let(:order_by) { 'title.asc, published' }
64
+
65
+ it { is_expected.to eq [[['title', 'asc'], ['published']]] }
66
+
67
+ end
44
68
 
45
69
  end
46
70
 
@@ -30,6 +30,16 @@ describe Locomotive::Steam::ContentType do
30
30
 
31
31
  end
32
32
 
33
+ describe '#default' do
34
+
35
+ subject { content_type.fields_with_default }
36
+
37
+ before { expect(repository).to receive(:default).and_return([true]) }
38
+
39
+ it { expect(subject).to eq([true]) }
40
+
41
+ end
42
+
33
43
  describe '#order_by' do
34
44
 
35
45
  subject { content_type.order_by }
@@ -22,4 +22,40 @@ describe Locomotive::Steam::SprocketsEnvironment do
22
22
 
23
23
  end
24
24
 
25
+ describe '#install_autoprefixer' do
26
+
27
+ let(:options) { { minify: false } }
28
+
29
+ subject { env }
30
+
31
+ context "config/autoprefixer.yml doesn't exist" do
32
+
33
+ before { allow(File).to receive(:exists?).and_return false }
34
+
35
+ it { expect(AutoprefixerRails).not_to receive(:install); subject }
36
+
37
+ end
38
+
39
+ context "config/autoprefixer.yml exists" do
40
+
41
+ before {
42
+ allow(File).to receive(:exists?).and_return(true)
43
+ allow(YAML).to receive(:load_file).and_return({})
44
+ }
45
+
46
+ it { expect(AutoprefixerRails).to receive(:install).and_return(true); subject }
47
+
48
+ it 'warns developers if they notice bad performance when using autoprefixer' do
49
+ curent_execjs_runtime = ENV['EXECJS_RUNTIME']
50
+ ENV['EXECJS_RUNTIME'] = 'NodeJS'
51
+ expect(Locomotive::Common::Logger).not_to receive(:warn)
52
+ expect(AutoprefixerRails).to receive(:install).and_return(true)
53
+ subject
54
+ ENV['EXECJS_RUNTIME'] = curent_execjs_runtime
55
+ end
56
+
57
+ end
58
+
59
+ end
60
+
25
61
  end
@@ -4,7 +4,7 @@ describe Locomotive::Steam::Liquid::Drops::ContentEntry do
4
4
 
5
5
  let(:site) { instance_double('Site', default_locale: 'en') }
6
6
  let(:type) { instance_double('Type', fields_by_name: { title: instance_double('Field', type: :string ) }) }
7
- let(:entry) { instance_double('Article', _id: 42, localized_attributes: {}, content_type: type, title: 'Hello world', _label: 'Hello world', _slug: 'hello-world', _translated: false, seo_title: 'seo title', meta_keywords: 'keywords', meta_description: 'description') }
7
+ let(:entry) { instance_double('Article', _id: 42, localized_attributes: {}, content_type: type, title: 'Hello world', _label: 'Hello world', _slug: 'hello-world', _translated: false, seo_title: 'seo title', meta_keywords: 'keywords', meta_description: 'description', created_at: 0, updated_at: 1) }
8
8
  let(:assigns) { {} }
9
9
  let(:services) { Locomotive::Steam::Services.build_instance }
10
10
  let(:context) { ::Liquid::Context.new(assigns, {}, { services: services, site: site, locale: 'en' }) }
@@ -20,6 +20,8 @@ describe Locomotive::Steam::Liquid::Drops::ContentEntry do
20
20
  expect(subject.seo_title).to eq 'seo title'
21
21
  expect(subject.meta_keywords).to eq 'keywords'
22
22
  expect(subject.meta_description).to eq 'description'
23
+ expect(subject.created_at).to eq 0
24
+ expect(subject.updated_at).to eq 1
23
25
  end
24
26
 
25
27
  describe '#before_method (dynamic attributes)' do
@@ -0,0 +1,81 @@
1
+ require 'spec_helper'
2
+
3
+ describe Locomotive::Steam::Liquid::Drops::Metafields do
4
+
5
+ let(:metafields) { { 'my_namespace' => { 'analytics_id' => { 'default' => '42' }, 'street' => { 'en' => '7 Albert Camus Alley', 'fr' => '7 allée Albert Camus' } } } }
6
+ let(:schema) { [ { 'name' => 'my_namespace', fields: [{ name: 'analytics_id' }, { name: 'street', localized: true }, { name: 'country' }] }].as_json }
7
+ let(:site) { instance_double('Site', metafields: metafields, metafields_schema: schema) }
8
+ let(:context) { ::Liquid::Context.new({}, {}, { locale: 'en' }) }
9
+ let(:drop) { described_class.new(site).tap { |d| d.context = context } }
10
+
11
+ describe 'calling a metafield' do
12
+
13
+ context 'unknown namespace' do
14
+
15
+ subject { drop.before_method(:unknown_namespace) }
16
+
17
+ it { is_expected.to eq nil }
18
+
19
+ end
20
+
21
+ context 'existing namespace' do
22
+
23
+ let(:namespace) { drop.before_method(:my_namespace).tap { |d| d.context = context } }
24
+
25
+ context 'unknown field' do
26
+
27
+ subject { namespace.before_method(:unknown_field) }
28
+
29
+ it { is_expected.to eq nil }
30
+
31
+ end
32
+
33
+ context 'not a localized field' do
34
+
35
+ context 'the value exists' do
36
+
37
+ subject { namespace.before_method(:analytics_id) }
38
+
39
+ it { is_expected.to eq '42' }
40
+
41
+ end
42
+
43
+ context "the value doesn't exist" do
44
+
45
+ subject { namespace.before_method(:country) }
46
+
47
+ it { is_expected.to eq nil }
48
+
49
+ end
50
+
51
+ end
52
+
53
+ context 'localized field' do
54
+
55
+ subject { namespace.before_method(:street) }
56
+
57
+ it { is_expected.to eq '7 Albert Camus Alley' }
58
+
59
+ context 'in another locale' do
60
+
61
+ let(:context) { ::Liquid::Context.new({}, {}, { locale: 'fr' }) }
62
+
63
+ it { is_expected.to eq '7 allée Albert Camus' }
64
+
65
+ end
66
+
67
+ context 'in a locale with no translation' do
68
+
69
+ let(:context) { ::Liquid::Context.new({}, {}, { locale: 'de' }) }
70
+
71
+ it { is_expected.to eq nil }
72
+
73
+ end
74
+
75
+ end
76
+
77
+ end
78
+
79
+ end
80
+
81
+ end
@@ -119,4 +119,17 @@ describe Locomotive::Steam::Liquid::Filters::Misc do
119
119
 
120
120
  end
121
121
 
122
+ describe '#shuffle' do
123
+
124
+ let(:array) { [1, 2, 3, 4] }
125
+
126
+ subject { shuffle(array) }
127
+
128
+ it 'returns an array in a random order' do
129
+ expect(subject.size).to eq 4
130
+ expect(subject).not_to eq([1, 2, 3, 4])
131
+ end
132
+
133
+ end
134
+
122
135
  end
@@ -71,6 +71,13 @@ describe Locomotive::Steam::Liquid::Tags::Consume do
71
71
 
72
72
  end
73
73
 
74
+ describe "don't render it if the url is blank" do
75
+
76
+ let(:source) { "{% consume blog from \"\" %}{{ blog.title }}{% endconsume %}" }
77
+ it { is_expected.to eq '' }
78
+
79
+ end
80
+
74
81
  end
75
82
 
76
83
  describe 'timeout' do
@@ -174,7 +174,7 @@ describe 'Locomotive::Steam::Liquid::Tags::Nav' do
174
174
  describe 'from a registered snippet' do
175
175
 
176
176
  let(:source) { %({% nav site, snippet: nav_title %}) }
177
- let(:snippet) { instance_double('Snippet', source: '{{ page.title }}!') }
177
+ let(:snippet) { instance_double('Snippet', liquid_source: '{{ page.title }}!') }
178
178
 
179
179
  before do
180
180
  allow(services.snippet_finder).to receive(:find).with('nav_title').and_return(snippet)
@@ -182,6 +182,14 @@ describe 'Locomotive::Steam::Liquid::Tags::Nav' do
182
182
 
183
183
  it { is_expected.to include %{<a href="/child-1">Child #1!</a>} }
184
184
 
185
+ context "the snippet doesn't exist" do
186
+
187
+ let(:snippet) { nil }
188
+
189
+ it { is_expected.to include %{<a href="/child-1">Child #1</a>} }
190
+
191
+ end
192
+
185
193
  end
186
194
 
187
195
  end
@@ -57,7 +57,7 @@ describe Locomotive::Steam::Liquid::Tags::PathTo do
57
57
 
58
58
  let(:assigns) { { 'about_us' => drop } }
59
59
  let(:drop) { Locomotive::Steam::Liquid::Drops::Page.new(page) }
60
- let(:page) { liquid_instance_double('AboutUs', title: 'About us', handle: 'index', localized_attributes: { fullpath: true }, fullpath: fullpath, localized_attributes: [:fullpath], templatized?: false) }
60
+ let(:page) { liquid_instance_double('AboutUs', title: 'About us', handle: 'index', localized_attributes: { fullpath: true }, fullpath: fullpath, templatized?: false) }
61
61
  let(:fullpath) { { en: 'about-us', fr: 'a-notre-sujet' } }
62
62
  let(:source) { '{% path_to about_us %}' }
63
63
 
@@ -0,0 +1,32 @@
1
+ require 'spec_helper'
2
+
3
+ require_relative '../../../lib/locomotive/steam/middlewares/helpers'
4
+
5
+ describe Locomotive::Steam::Middlewares::Helpers do
6
+
7
+ let(:middleware) { Class.new { include Locomotive::Steam::Middlewares::Helpers } }
8
+ let(:instance) { middleware.new }
9
+
10
+ describe '#redirect_to' do
11
+
12
+ subject { instance.redirect_to(location)[1]['Location'] }
13
+
14
+ context 'mounted_on is not blank' do
15
+
16
+ before { allow(instance).to receive(:mounted_on).and_return('/my_app') }
17
+
18
+ let(:location) { '/foo/bar' }
19
+ it { is_expected.to eq '/my_app/foo/bar' }
20
+
21
+ describe 'the location already includes mounted_on' do
22
+
23
+ let(:location) { '/my_app/foo' }
24
+ it { is_expected.to eq '/my_app/foo' }
25
+
26
+ end
27
+
28
+ end
29
+
30
+ end
31
+
32
+ end