nesta 0.11.1 → 0.13.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.
Files changed (86) hide show
  1. checksums.yaml +5 -5
  2. data/.github/workflows/tests.yml +21 -0
  3. data/.gitmodules +0 -0
  4. data/CHANGES +44 -2
  5. data/Gemfile +1 -1
  6. data/Gemfile.lock +73 -55
  7. data/LICENSE +1 -1
  8. data/README.md +7 -14
  9. data/RELEASING.md +10 -9
  10. data/Rakefile +20 -3
  11. data/bin/nesta +1 -1
  12. data/config/deploy.rb.sample +1 -1
  13. data/lib/nesta/app.rb +4 -8
  14. data/lib/nesta/commands/demo/content.rb +28 -12
  15. data/lib/nesta/commands/edit.rb +2 -6
  16. data/lib/nesta/commands/new.rb +9 -11
  17. data/lib/nesta/commands/plugin/create.rb +7 -9
  18. data/lib/nesta/commands/template.rb +20 -0
  19. data/lib/nesta/commands/theme/create.rb +8 -8
  20. data/lib/nesta/commands/theme/enable.rb +3 -5
  21. data/lib/nesta/commands/theme/install.rb +12 -14
  22. data/lib/nesta/commands.rb +8 -0
  23. data/lib/nesta/config_file.rb +25 -0
  24. data/lib/nesta/helpers.rb +14 -0
  25. data/lib/nesta/models.rb +26 -22
  26. data/lib/nesta/navigation.rb +1 -1
  27. data/lib/nesta/system_command.rb +15 -0
  28. data/lib/nesta/version.rb +1 -1
  29. data/lib/nesta.rb +6 -1
  30. data/nesta.gemspec +11 -12
  31. data/templates/config/config.yml +1 -1
  32. data/{spec → test}/fixtures/nesta-plugin-test/Gemfile +0 -0
  33. data/{spec → test}/fixtures/nesta-plugin-test/Rakefile +0 -0
  34. data/{spec → test}/fixtures/nesta-plugin-test/lib/nesta-plugin-test/init.rb +0 -0
  35. data/{spec → test}/fixtures/nesta-plugin-test/lib/nesta-plugin-test/version.rb +0 -0
  36. data/{spec → test}/fixtures/nesta-plugin-test/lib/nesta-plugin-test.rb +0 -0
  37. data/{spec → test}/fixtures/nesta-plugin-test/nesta-plugin-test.gemspec +0 -0
  38. data/test/integration/atom_feed_test.rb +178 -0
  39. data/test/integration/commands/demo/content_test.rb +33 -0
  40. data/test/integration/commands/edit_test.rb +21 -0
  41. data/test/integration/commands/new_test.rb +91 -0
  42. data/test/integration/commands/plugin/create_test.rb +131 -0
  43. data/test/integration/commands/theme/create_test.rb +41 -0
  44. data/test/integration/commands/theme/enable_test.rb +28 -0
  45. data/test/integration/commands/theme/install_test.rb +66 -0
  46. data/test/integration/default_theme_test.rb +220 -0
  47. data/test/integration/overrides_test.rb +118 -0
  48. data/test/integration/route_handlers_test.rb +96 -0
  49. data/test/integration/sitemap_test.rb +85 -0
  50. data/test/integration_test_helper.rb +61 -0
  51. data/test/support/model_factory.rb +169 -0
  52. data/test/support/temporary_files.rb +33 -0
  53. data/test/support/test_configuration.rb +19 -0
  54. data/test/test_helper.rb +26 -0
  55. data/test/unit/config_test.rb +138 -0
  56. data/test/unit/file_model_test.rb +71 -0
  57. data/test/unit/menu_test.rb +82 -0
  58. data/test/unit/page_test.rb +571 -0
  59. data/test/unit/path_test.rb +41 -0
  60. data/test/unit/plugin_test.rb +47 -0
  61. data/test/unit/system_command_test.rb +20 -0
  62. data/views/master.sass +1 -1
  63. metadata +90 -89
  64. data/.hound.yml +0 -2
  65. data/.rspec +0 -1
  66. data/.travis.yml +0 -6
  67. data/lib/nesta/commands/command.rb +0 -58
  68. data/smoke-test.sh +0 -107
  69. data/spec/atom_spec.rb +0 -141
  70. data/spec/commands/demo/content_spec.rb +0 -65
  71. data/spec/commands/edit_spec.rb +0 -27
  72. data/spec/commands/new_spec.rb +0 -88
  73. data/spec/commands/plugin/create_spec.rb +0 -97
  74. data/spec/commands/system_spec.rb +0 -25
  75. data/spec/commands/theme/create_spec.rb +0 -41
  76. data/spec/commands/theme/enable_spec.rb +0 -44
  77. data/spec/commands/theme/install_spec.rb +0 -56
  78. data/spec/config_spec.rb +0 -127
  79. data/spec/model_factory.rb +0 -92
  80. data/spec/models_spec.rb +0 -700
  81. data/spec/overrides_spec.rb +0 -132
  82. data/spec/page_spec.rb +0 -560
  83. data/spec/path_spec.rb +0 -28
  84. data/spec/plugin_spec.rb +0 -51
  85. data/spec/sitemap_spec.rb +0 -105
  86. data/spec/spec_helper.rb +0 -114
@@ -0,0 +1,85 @@
1
+ require 'integration_test_helper'
2
+
3
+ describe 'XML sitemap' do
4
+ include Nesta::IntegrationTest
5
+
6
+ def visit_sitemap
7
+ visit '/sitemap.xml'
8
+ end
9
+
10
+ def for_site_with_page(&block)
11
+ with_temp_content_directory do
12
+ model = create(:page)
13
+ visit_sitemap
14
+ yield(model)
15
+ end
16
+ end
17
+
18
+ def for_site_with_article(&block)
19
+ with_temp_content_directory do
20
+ article = create(:article)
21
+ visit_sitemap
22
+ yield(article)
23
+ end
24
+ end
25
+
26
+ it 'renders successfully' do
27
+ for_site_with_page do
28
+ assert_equal 200, page.status_code
29
+ end
30
+ end
31
+
32
+ it 'has a urlset tag' do
33
+ for_site_with_page do
34
+ namespace = 'http://www.sitemaps.org/schemas/sitemap/0.9'
35
+ assert_has_xpath "//urlset[@xmlns='#{namespace}']"
36
+ end
37
+ end
38
+
39
+ it 'references the home page' do
40
+ for_site_with_page do
41
+ assert_has_xpath '//urlset/url/loc', text: 'http://www.example.com/'
42
+ end
43
+ end
44
+
45
+ it 'configures home page to be checked frequently' do
46
+ for_site_with_page do
47
+ assert_has_xpath '//urlset/url/loc', text: "http://www.example.com/"
48
+ assert_has_xpath '//urlset/url/changefreq', text: "daily"
49
+ assert_has_xpath '//urlset/url/priority', text: "1.0"
50
+ end
51
+ end
52
+
53
+ it "sets homepage lastmod from timestamp of most recently modified page" do
54
+ for_site_with_article do |article|
55
+ timestamp = article.last_modified
56
+ assert_has_xpath '//urlset/url/loc', text: "http://www.example.com/"
57
+ assert_has_xpath '//urlset/url/lastmod', text: timestamp.xmlschema
58
+ end
59
+ end
60
+
61
+ def site_url(path)
62
+ "http://www.example.com/#{path}"
63
+ end
64
+
65
+ it 'references category pages' do
66
+ for_site_with_page do |model|
67
+ assert_has_xpath '//urlset/url/loc', text: site_url(model.path)
68
+ end
69
+ end
70
+
71
+ it 'references article pages' do
72
+ for_site_with_article do |article|
73
+ assert_has_xpath '//urlset/url/loc', text: site_url(article.path)
74
+ end
75
+ end
76
+
77
+ it 'omits pages that have the skip-sitemap flag set' do
78
+ with_temp_content_directory do
79
+ create(:category)
80
+ omitted = create(:page, metadata: { 'flags' => 'skip-sitemap' })
81
+ visit_sitemap
82
+ assert_has_no_xpath '//urlset/url/loc', text: site_url(omitted.path)
83
+ end
84
+ end
85
+ end
@@ -0,0 +1,61 @@
1
+ require 'capybara/dsl'
2
+
3
+ require_relative 'test_helper'
4
+
5
+ module Nesta
6
+ class App < Sinatra::Base
7
+ set :environment, :test
8
+ set :reload_templates, true
9
+ end
10
+
11
+ module IntegrationTest
12
+ include Capybara::DSL
13
+
14
+ include ModelFactory
15
+ include TestConfiguration
16
+
17
+ def setup
18
+ Capybara.app = App.new
19
+ end
20
+
21
+ def teardown
22
+ Capybara.reset_sessions!
23
+ Capybara.use_default_driver
24
+
25
+ remove_temp_directory
26
+ Nesta::FileModel.purge_cache
27
+ end
28
+
29
+ def assert_has_xpath(query, options = {})
30
+ if ! page.has_xpath?(query, options)
31
+ message = "not found in page: '#{query}'"
32
+ message << ", #{options.inspect}" unless options.empty?
33
+ fail message
34
+ end
35
+ end
36
+
37
+ def assert_has_no_xpath(query, options = {})
38
+ if page.has_xpath?(query, options)
39
+ message = "found in page: '#{query}'"
40
+ message << ", #{options.inspect}" unless options.empty?
41
+ fail message
42
+ end
43
+ end
44
+
45
+ def assert_has_css(query, options = {})
46
+ if ! page.has_css?(query, options)
47
+ message = "not found in page: '#{query}'"
48
+ message << ", #{options.inspect}" unless options.empty?
49
+ fail message
50
+ end
51
+ end
52
+
53
+ def assert_has_no_css(query, options = {})
54
+ if ! page.has_no_css?(query, options)
55
+ message = "found in page: '#{query}'"
56
+ message << ", #{options.inspect}" unless options.empty?
57
+ fail message
58
+ end
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,169 @@
1
+ module ModelFactory
2
+ class FileModelWriter
3
+ def initialize(type, data = {})
4
+ @type = type
5
+ @data = data
6
+ end
7
+
8
+ def model_class
9
+ Nesta::FileModel
10
+ end
11
+
12
+ def instantiate_model
13
+ model_class.new(filename)
14
+ end
15
+
16
+ def extension
17
+ data.fetch(:ext, 'mdown')
18
+ end
19
+
20
+ def filename
21
+ File.join(model_class.model_path, "#{data[:path]}.#{extension}")
22
+ end
23
+
24
+ def sequence_prefix
25
+ 'file-'
26
+ end
27
+
28
+ def default_data
29
+ { path: default_path }
30
+ end
31
+
32
+ def default_path
33
+ sequence_prefix + ModelFactory.next_sequence_number.to_s
34
+ end
35
+
36
+ def data
37
+ if @memoized_data.nil?
38
+ @memoized_data = default_data
39
+ if @memoized_data.has_key?(:metadata)
40
+ @memoized_data[:metadata].merge!(@data.delete(:metadata) || {})
41
+ end
42
+ @memoized_data.merge!(@data)
43
+ end
44
+ @memoized_data
45
+ end
46
+
47
+ def write
48
+ metadata = data[:metadata] || {}
49
+ metatext = metadata.map { |key, value| "#{key}: #{value}" }.join("\n")
50
+ contents =<<-EOF
51
+ #{metatext}
52
+
53
+ #{heading}#{data[:content]}
54
+ EOF
55
+ FileUtils.mkdir_p(File.dirname(filename))
56
+ File.open(filename, 'w') { |file| file.write(contents) }
57
+ yield(filename) if block_given?
58
+ end
59
+
60
+ def heading
61
+ return '' unless data[:heading]
62
+ prefix = {
63
+ 'haml' => "%div\n %h1",
64
+ 'textile' => "<div>\nh1."
65
+ }.fetch(data[:ext], '# ')
66
+ "#{prefix} #{data[:heading]}\n\n"
67
+ end
68
+ end
69
+
70
+ class PageWriter < FileModelWriter
71
+ def model_class
72
+ Nesta::Page
73
+ end
74
+
75
+ def sequence_prefix
76
+ 'page-'
77
+ end
78
+
79
+ def default_data
80
+ path = default_path
81
+ { path: path, heading: heading_from_path(path) }
82
+ end
83
+
84
+ def heading_from_path(path)
85
+ File.basename(path).sub('-', ' ').capitalize
86
+ end
87
+ end
88
+
89
+ class ArticleWriter < PageWriter
90
+ def sequence_prefix
91
+ 'articles/page-'
92
+ end
93
+
94
+ def default_data
95
+ path = default_path
96
+ {
97
+ path: path,
98
+ heading: heading_from_path(path),
99
+ content: 'Content goes here',
100
+ metadata: {
101
+ 'date' => '29 December 2008'
102
+ }
103
+ }
104
+ end
105
+ end
106
+
107
+ class CategoryWriter < PageWriter
108
+ def sequence_prefix
109
+ 'categories/page-'
110
+ end
111
+
112
+ def default_data
113
+ path = default_path
114
+ {
115
+ path: path,
116
+ heading: heading_from_path(path),
117
+ content: 'Content goes here'
118
+ }
119
+ end
120
+ end
121
+
122
+ @@sequence = 0
123
+ def self.next_sequence_number
124
+ @@sequence += 1
125
+ end
126
+
127
+ def before_setup
128
+ # This is a minitest hook. We reset file sequence number at the
129
+ # start of each test so that we can automatically generate a unique
130
+ # path for each file we create within a test.
131
+ @@sequence = 0
132
+ end
133
+
134
+ def create(type, data = {}, &block)
135
+ file_writer = writer_class(type).new(type, data)
136
+ file_writer.write(&block)
137
+ file_writer.instantiate_model
138
+ end
139
+
140
+ def write_menu_item(indent, file, menu_item)
141
+ if menu_item.is_a?(Array)
142
+ indent.sub!(/^/, ' ')
143
+ menu_item.each { |path| write_menu_item(indent, file, path) }
144
+ indent.sub!(/^ /, '')
145
+ else
146
+ file.write("#{indent}#{menu_item}\n")
147
+ end
148
+ end
149
+
150
+ def create_menu(menu_text)
151
+ file = filename(Nesta::Config.content_path, 'menu', :txt)
152
+ File.open(file, 'w') { |file| file.write(menu_text) }
153
+ end
154
+
155
+ def create_content_directories
156
+ FileUtils.mkdir_p(Nesta::Config.page_path)
157
+ FileUtils.mkdir_p(Nesta::Config.attachment_path)
158
+ end
159
+
160
+ private
161
+ def filename(directory, basename, extension = :mdown)
162
+ File.join(directory, "#{basename}.#{extension}")
163
+ end
164
+
165
+ def writer_class(type)
166
+ camelcased_type = type.to_s.gsub(/(?:^|_)(\w)/) { $1.upcase }
167
+ ModelFactory.const_get(camelcased_type + 'Writer')
168
+ end
169
+ end
@@ -0,0 +1,33 @@
1
+ module TemporaryFiles
2
+ TEMP_DIR = File.expand_path('tmp', File.join(File.dirname(__FILE__), '..'))
3
+
4
+ def remove_temp_directory
5
+ if File.exist?(TemporaryFiles::TEMP_DIR)
6
+ FileUtils.rm_r(TemporaryFiles::TEMP_DIR)
7
+ end
8
+ end
9
+
10
+ def temp_path(base)
11
+ File.join(TemporaryFiles::TEMP_DIR, base)
12
+ end
13
+
14
+ def project_root
15
+ temp_path('mysite.com')
16
+ end
17
+
18
+ def project_path(path)
19
+ File.join(project_root, path)
20
+ end
21
+
22
+ def in_temporary_project(*args, &block)
23
+ FileUtils.mkdir_p(File.join(project_root, 'config'))
24
+ File.open(File.join(project_root, 'config', 'config.yml'), 'w').close
25
+ Dir.chdir(project_root) { yield }
26
+ ensure
27
+ remove_temp_directory
28
+ end
29
+
30
+ def assert_exists_in_project(path)
31
+ assert File.exist?(project_path(path)), "#{path} should exist"
32
+ end
33
+ end
@@ -0,0 +1,19 @@
1
+ module TestConfiguration
2
+ include TemporaryFiles
3
+
4
+ def stub_config(config, &block)
5
+ Nesta::Config.stub(:yaml_exists?, true) do
6
+ Nesta::Config.stub(:yaml_conf, config) do
7
+ yield
8
+ end
9
+ end
10
+ end
11
+
12
+ def temp_content
13
+ { 'content' => temp_path('content') }
14
+ end
15
+
16
+ def with_temp_content_directory(&block)
17
+ stub_config(temp_content) { yield }
18
+ end
19
+ end
@@ -0,0 +1,26 @@
1
+ require 'sinatra'
2
+ require 'minitest/autorun'
3
+
4
+ require 'minitest/reporters'
5
+
6
+ reporter_setting = ENV.fetch('REPORTER', 'progress')
7
+ camel_case = reporter_setting.split(/_/).map { |word| word.capitalize }.join('')
8
+ Minitest::Reporters.use! Minitest::Reporters.const_get("#{camel_case}Reporter").new
9
+
10
+ require File.expand_path('../lib/nesta/env', File.dirname(__FILE__))
11
+ require File.expand_path('../lib/nesta/app', File.dirname(__FILE__))
12
+
13
+ require_relative 'support/model_factory'
14
+ require_relative 'support/temporary_files'
15
+ require_relative 'support/test_configuration'
16
+
17
+ Nesta::App.environment = 'test'
18
+
19
+ class Minitest::Test
20
+ def with_app_root(path, &block)
21
+ original, Nesta::App.root = Nesta::App.root, path
22
+ yield
23
+ ensure
24
+ Nesta::App.root = original
25
+ end
26
+ end
@@ -0,0 +1,138 @@
1
+ require 'test_helper'
2
+
3
+ describe Nesta::Config do
4
+ include TestConfiguration
5
+
6
+ after do
7
+ ENV.keys.each { |variable| ENV.delete(variable) if variable =~ /NESTA_/ }
8
+ end
9
+
10
+ it 'returns default value for "Read more"' do
11
+ assert_equal 'Continue reading', Nesta::Config.read_more
12
+ end
13
+
14
+ it 'returns nil for author when not defined' do
15
+ assert_nil Nesta::Config.author
16
+ end
17
+
18
+ describe 'when settings defined in ENV' do
19
+ before do
20
+ @title = 'Title from ENV'
21
+ ENV['NESTA_TITLE'] = @title
22
+ end
23
+
24
+ it 'falls back to config.yml' do
25
+ stub_config('subtitle' => 'Subtitle in YAML file') do
26
+ assert_equal 'Subtitle in YAML file', Nesta::Config.subtitle
27
+ end
28
+ end
29
+
30
+ it 'overrides config.yml' do
31
+ stub_config('title' => 'Title in YAML file') do
32
+ assert_equal @title, Nesta::Config.title
33
+ end
34
+ end
35
+
36
+ it 'knows how to cope with boolean values' do
37
+ Nesta::Config.settings << 'a_boolean'
38
+ begin
39
+ ENV['NESTA_A_BOOLEAN'] = 'true'
40
+ assert_equal true, Nesta::Config.a_boolean, 'should be true'
41
+ ENV['NESTA_A_BOOLEAN'] = 'false'
42
+ assert_equal false, Nesta::Config.a_boolean, 'should be false'
43
+ ensure
44
+ Nesta::Config.settings.pop
45
+ ENV.delete('NESTA_A_BOOLEAN')
46
+ end
47
+ end
48
+
49
+ it 'should return configured value for "Read more"' do
50
+ ENV['NESTA_READ_MORE'] = 'Read on'
51
+ begin
52
+ assert_equal 'Read on', Nesta::Config.read_more
53
+ ensure
54
+ ENV.delete('NESTA_READ_MORE')
55
+ end
56
+ end
57
+
58
+ it 'sets author hash from ENV' do
59
+ name = 'Name from ENV'
60
+ uri = 'URI from ENV'
61
+ ENV['NESTA_AUTHOR__NAME'] = name
62
+ ENV['NESTA_AUTHOR__URI'] = uri
63
+ assert_equal name, Nesta::Config.author['name']
64
+ assert_equal uri, Nesta::Config.author['uri']
65
+ assert Nesta::Config.author['email'].nil?, 'should be nil'
66
+ end
67
+ end
68
+
69
+ describe 'when settings only defined in config.yml' do
70
+ before do
71
+ @title = 'Title in YAML file'
72
+ end
73
+
74
+ it 'reads configuration from YAML' do
75
+ stub_config('subtitle' => @title) do
76
+ assert_equal @title, Nesta::Config.subtitle
77
+ end
78
+ end
79
+
80
+ it 'sets author hash from YAML' do
81
+ name = 'Name from YAML'
82
+ uri = 'URI from YAML'
83
+ stub_config('author' => { 'name' => name, 'uri' => uri }) do
84
+ assert_equal name, Nesta::Config.author['name']
85
+ assert_equal uri, Nesta::Config.author['uri']
86
+ assert Nesta::Config.author['email'].nil?, 'should be nil'
87
+ end
88
+ end
89
+
90
+ it 'overrides top level settings with environment specific settings' do
91
+ config = {
92
+ 'content' => 'general/path',
93
+ 'test' => { 'content' => 'rack_env_specific/path' }
94
+ }
95
+ stub_config(config) do
96
+ assert_equal 'rack_env_specific/path', Nesta::Config.content
97
+ end
98
+ end
99
+ end
100
+
101
+ describe 'Nesta::Config.fetch' do
102
+ it 'retrieves settings from environment' do
103
+ ENV['NESTA_MY_SETTING'] = 'value in ENV'
104
+ begin
105
+ assert_equal 'value in ENV', Nesta::Config.fetch('my_setting')
106
+ assert_equal 'value in ENV', Nesta::Config.fetch(:my_setting)
107
+ ensure
108
+ ENV.delete('NESTA_MY_SETTING')
109
+ end
110
+ end
111
+
112
+ it 'retrieves settings from YAML' do
113
+ stub_config('my_setting' => 'value in YAML') do
114
+ assert_equal 'value in YAML', Nesta::Config.fetch('my_setting')
115
+ assert_equal 'value in YAML', Nesta::Config.fetch(:my_setting)
116
+ end
117
+ end
118
+
119
+ it "throws NotDefined if a setting isn't defined" do
120
+ assert_raises(Nesta::Config::NotDefined) do
121
+ Nesta::Config.fetch('no such setting')
122
+ end
123
+ end
124
+
125
+ it 'allows default values to be set' do
126
+ assert_equal 'default', Nesta::Config.fetch('no such setting', 'default')
127
+ end
128
+
129
+ it 'copes with non-truthy boolean values' do
130
+ ENV['NESTA_SETTING'] = 'false'
131
+ begin
132
+ assert_equal false, Nesta::Config.fetch('setting')
133
+ ensure
134
+ ENV.delete('NESTA_SETTING')
135
+ end
136
+ end
137
+ end
138
+ end
@@ -0,0 +1,71 @@
1
+ require 'test_helper'
2
+
3
+ describe Nesta::FileModel do
4
+ include ModelFactory
5
+ include TestConfiguration
6
+
7
+ after do
8
+ Nesta::FileModel.purge_cache
9
+ remove_temp_directory
10
+ end
11
+
12
+ it 'can find all files of this type' do
13
+ with_temp_content_directory do
14
+ model = create(:file_model)
15
+ assert_equal [model], Nesta::FileModel.find_all
16
+ end
17
+ end
18
+
19
+ describe '.find_file_for_path' do
20
+ it 'returns filename for path' do
21
+ with_temp_content_directory do
22
+ model = create(:file_model)
23
+ filename = Nesta::FileModel.find_file_for_path(model.path)
24
+ assert_equal filename, model.filename
25
+ end
26
+ end
27
+
28
+ it 'returns nil if file not found' do
29
+ with_temp_content_directory do
30
+ assert_nil Nesta::FileModel.find_file_for_path('foobar')
31
+ end
32
+ end
33
+ end
34
+
35
+ it 'can parse metadata at top of a file' do
36
+ with_temp_content_directory do
37
+ model = create(:file_model)
38
+ metadata = model.parse_metadata('My key: some value')
39
+ assert_equal 'some value', metadata['my key']
40
+ end
41
+ end
42
+
43
+ it "doesn't break loading pages with badly formatted metadata" do
44
+ with_temp_content_directory do
45
+ dodgy_metadata = "Key: value\nKey without value\nAnother key: value"
46
+ page = create(:page) do |path|
47
+ text = File.read(path)
48
+ File.open(path, 'w') do |file|
49
+ file.puts(dodgy_metadata)
50
+ file.write(text)
51
+ end
52
+ end
53
+ Nesta::Page.find_by_path(page.path)
54
+ end
55
+ end
56
+
57
+ it 'invalidates cached models when files are modified' do
58
+ with_temp_content_directory do
59
+ create(:file_model, path: 'a-page', metadata: { 'Version' => '1' })
60
+ now = Time.now
61
+ File.stub(:mtime, now - 1) do
62
+ Nesta::FileModel.load('a-page')
63
+ end
64
+ create(:file_model, path: 'a-page', metadata: { 'Version' => '2' })
65
+ model = File.stub(:mtime, now) do
66
+ Nesta::FileModel.load('a-page')
67
+ end
68
+ assert_equal '2', model.metadata('version')
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,82 @@
1
+ require 'test_helper'
2
+
3
+ describe Nesta::Menu do
4
+ include ModelFactory
5
+ include TestConfiguration
6
+
7
+ def with_page(&block)
8
+ with_temp_content_directory do
9
+ page = create(:page)
10
+ create_menu(page.path)
11
+ yield(page)
12
+ end
13
+ end
14
+
15
+ def with_hierarchy_of_pages(&block)
16
+ with_temp_content_directory do
17
+ pages = (1..6).map { |i| create(:page) }
18
+ text = <<-EOF
19
+ #{pages[0].path}
20
+ #{pages[1].path}
21
+ #{pages[2].path}
22
+ #{pages[3].path}
23
+ "no-such-page"
24
+ "another-missing-page"
25
+ #{pages[4].path}
26
+ #{pages[5].path}
27
+ EOF
28
+ create_menu(text)
29
+ yield(pages)
30
+ end
31
+ end
32
+
33
+ after do
34
+ remove_temp_directory
35
+ Nesta::FileModel.purge_cache
36
+ end
37
+
38
+ it 'retrieves Page objects for the menu' do
39
+ with_page do |page|
40
+ assert_equal [page], Nesta::Menu.full_menu
41
+ assert_equal [page], Nesta::Menu.for_path('/')
42
+ end
43
+ end
44
+
45
+ it "filters pages that don't exist out of the menu" do
46
+ with_temp_content_directory do
47
+ page = create(:page)
48
+ text = ['no-such-page', page.path].join("\n")
49
+ create_menu(text)
50
+ assert_equal [page], Nesta::Menu.top_level
51
+ end
52
+ end
53
+
54
+ describe 'nested sub menus' do
55
+ it 'returns top level menu items' do
56
+ with_hierarchy_of_pages do |pages|
57
+ assert_equal [pages[0], pages[4]], Nesta::Menu.top_level
58
+ end
59
+ end
60
+
61
+ it 'returns full tree of menu items' do
62
+ with_hierarchy_of_pages do |pages|
63
+ page1, page2, page3, page4, page5, page6 = pages
64
+ expected = [page1, [page2, [page3, page4]], page5, [page6]]
65
+ assert_equal expected, Nesta::Menu.full_menu
66
+ end
67
+ end
68
+
69
+ it 'returns part of the tree of menu items' do
70
+ with_hierarchy_of_pages do |pages|
71
+ page1, page2, page3, page4, page5, page6 = pages
72
+ assert_equal [page2, [page3, page4]], Nesta::Menu.for_path(page2.path)
73
+ end
74
+ end
75
+
76
+ it 'deems menu for path not in menu to be nil' do
77
+ with_hierarchy_of_pages do
78
+ assert_nil Nesta::Menu.for_path('wibble')
79
+ end
80
+ end
81
+ end
82
+ end