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,131 @@
1
+ require 'test_helper'
2
+ require_relative '../../../../lib/nesta/commands'
3
+
4
+ describe 'nesta plugin:create' do
5
+ include TemporaryFiles
6
+
7
+ def working_directory
8
+ temp_path('plugins')
9
+ end
10
+
11
+ before do
12
+ FileUtils.mkdir_p(working_directory)
13
+ end
14
+
15
+ after do
16
+ remove_temp_directory
17
+ end
18
+
19
+ def plugin_name
20
+ 'my-feature'
21
+ end
22
+
23
+ def gem_name
24
+ "nesta-plugin-#{plugin_name}"
25
+ end
26
+
27
+ def process_stub
28
+ Object.new.tap do |stub|
29
+ def stub.run(*args); end
30
+ end
31
+ end
32
+
33
+ def create_plugin(&block)
34
+ Dir.chdir(working_directory) do
35
+ command = Nesta::Commands::Plugin::Create.new(plugin_name)
36
+ command.execute(process_stub)
37
+ end
38
+ end
39
+
40
+ def assert_exists_in_plugin(path)
41
+ full_path = File.join(gem_name, path)
42
+ assert File.exist?(full_path), "#{path} not found in plugin"
43
+ end
44
+
45
+ def assert_file_contains(path, pattern)
46
+ assert_match pattern, File.read(File.join(gem_name, path))
47
+ end
48
+
49
+ it "creates the gem's directory" do
50
+ create_plugin { assert File.directory?(gem_name), 'gem directory not found' }
51
+ end
52
+
53
+ it 'creates README.md file' do
54
+ create_plugin { assert_exists_in_plugin('README.md') }
55
+ end
56
+
57
+ it 'includes installation instructions in README.md' do
58
+ create_plugin do
59
+ assert_file_contains('README.md', /echo 'gem "#{gem_name}"' >> Gemfile/)
60
+ end
61
+ end
62
+
63
+ it 'creates .gitignore file' do
64
+ create_plugin { assert_exists_in_plugin('.gitignore') }
65
+ end
66
+
67
+ it 'creates the gemspec' do
68
+ create_plugin do
69
+ gemspec = "#{gem_name}.gemspec"
70
+ assert_exists_in_plugin(gemspec)
71
+ assert_file_contains(gemspec, %r{require "#{gem_name}/version"})
72
+ assert_file_contains(gemspec, %r{Nesta::Plugin::My::Feature::VERSION})
73
+ end
74
+ end
75
+
76
+ it 'creates a Gemfile' do
77
+ create_plugin { assert_exists_in_plugin('Gemfile') }
78
+ end
79
+
80
+ it 'creates Rakefile for packaging the gem' do
81
+ create_plugin { assert_exists_in_plugin('Rakefile') }
82
+ end
83
+
84
+ it "creates default folder for Ruby files" do
85
+ create_plugin do
86
+ code_directory = File.join(gem_name, 'lib', gem_name)
87
+ assert File.directory?(code_directory), 'directory for code not found'
88
+ end
89
+ end
90
+
91
+ it 'creates file required when gem loaded' do
92
+ create_plugin do
93
+ path = "#{File.join('lib', gem_name)}.rb"
94
+ assert_exists_in_plugin(path)
95
+ assert_file_contains(path, %r{require "#{gem_name}/version"})
96
+ end
97
+ end
98
+
99
+ it 'creates version.rb' do
100
+ create_plugin do
101
+ version = File.join('lib', gem_name, 'version.rb')
102
+ assert_exists_in_plugin(version)
103
+ assert_file_contains version, <<-EOF
104
+ module Nesta
105
+ module Plugin
106
+ module My
107
+ module Feature
108
+ VERSION = '0.1.0'
109
+ end
110
+ end
111
+ end
112
+ end
113
+ EOF
114
+ end
115
+ end
116
+
117
+ it 'creates skeleton code for the plugin in init.rb' do
118
+ create_plugin do
119
+ init = File.join('lib', gem_name, 'init.rb')
120
+ assert_exists_in_plugin(init)
121
+
122
+ assert_file_contains init, <<-MODULE
123
+ module Nesta
124
+ module Plugin
125
+ module My::Feature
126
+ MODULE
127
+
128
+ assert_file_contains init, 'helpers Nesta::Plugin::My::Feature::Helpers'
129
+ end
130
+ end
131
+ end
@@ -0,0 +1,41 @@
1
+ require 'test_helper'
2
+ require_relative '../../../../lib/nesta/commands'
3
+
4
+ describe 'nesta theme:create' do
5
+ include TemporaryFiles
6
+
7
+ def theme_path(path = '')
8
+ File.join('themes', 'theme-name', path)
9
+ end
10
+
11
+ before do
12
+ FileUtils.mkdir_p(project_root)
13
+ end
14
+
15
+ after do
16
+ remove_temp_directory
17
+ end
18
+
19
+ def process_stub
20
+ Object.new.tap do |stub|
21
+ def stub.run(*args); end
22
+ end
23
+ end
24
+
25
+ it 'creates default files in the theme directory' do
26
+ Dir.chdir(project_root) do
27
+ Nesta::Commands::Theme::Create.new('theme-name').execute(process_stub)
28
+ end
29
+ assert_exists_in_project theme_path('README.md')
30
+ assert_exists_in_project theme_path('app.rb')
31
+ end
32
+
33
+ it 'copies default view templates into views directory' do
34
+ Dir.chdir(project_root) do
35
+ Nesta::Commands::Theme::Create.new('theme-name').execute(process_stub)
36
+ end
37
+ %w(layout.haml page.haml master.sass).each do |template|
38
+ assert_exists_in_project theme_path("views/#{template}")
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,28 @@
1
+ require 'test_helper'
2
+ require_relative '../../../../lib/nesta/commands'
3
+
4
+ describe 'nesta theme:enable' do
5
+ include TemporaryFiles
6
+
7
+ before do
8
+ FileUtils.mkdir_p(File.join(project_root, 'config'))
9
+ File.open(File.join(project_root, 'config', 'config.yml'), 'w').close
10
+ end
11
+
12
+ after do
13
+ remove_temp_directory
14
+ end
15
+
16
+ def process_stub
17
+ Object.new.tap do |stub|
18
+ def stub.run(*args); end
19
+ end
20
+ end
21
+
22
+ it 'enables the theme' do
23
+ Dir.chdir(project_root) do
24
+ Nesta::Commands::Theme::Enable.new('theme-name').execute(process_stub)
25
+ assert_match /^theme: theme-name/, File.read('config/config.yml')
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,66 @@
1
+ require 'test_helper'
2
+ require_relative '../../../../lib/nesta/commands'
3
+
4
+ describe 'nesta theme:install' do
5
+ include TemporaryFiles
6
+
7
+ def theme_name
8
+ 'test'
9
+ end
10
+
11
+ def repo_url
12
+ "../../fixtures/nesta-theme-#{theme_name}.git"
13
+ end
14
+
15
+ def theme_dir
16
+ project_path("themes/#{theme_name}")
17
+ end
18
+
19
+ before do
20
+ FileUtils.mkdir_p(project_root)
21
+ end
22
+
23
+ after do
24
+ remove_temp_directory
25
+ end
26
+
27
+ def process_stub
28
+ Object.new.tap do |stub|
29
+ def stub.run(*args); end
30
+ end
31
+ end
32
+
33
+ it 'clones the repository' do
34
+ process = Minitest::Mock.new
35
+ process.expect(:run, true, ['git', 'clone', repo_url, "themes/#{theme_name}"])
36
+ in_temporary_project do
37
+ Nesta::Commands::Theme::Install.new(repo_url).execute(process)
38
+ end
39
+ end
40
+
41
+ it "removes the theme's .git directory" do
42
+ in_temporary_project do
43
+ Nesta::Commands::Theme::Install.new(repo_url).execute(process_stub)
44
+ refute File.exist?("#{theme_dir}/.git"), '.git folder found'
45
+ end
46
+ end
47
+
48
+ it 'enables the freshly installed theme' do
49
+ in_temporary_project do
50
+ Nesta::Commands::Theme::Install.new(repo_url).execute(process_stub)
51
+ assert_match /theme: #{theme_name}/, File.read('config/config.yml')
52
+ end
53
+ end
54
+
55
+ it 'determines name of theme from name of repository' do
56
+ url = 'https://foobar.com/path/to/nesta-theme-the-name.git'
57
+ command = Nesta::Commands::Theme::Install.new(url)
58
+ assert_equal 'the-name', command.theme_name
59
+ end
60
+
61
+ it "falls back to name of repo when theme name doesn't match correct format" do
62
+ url = 'https://foobar.com/path/to/mytheme.git'
63
+ command = Nesta::Commands::Theme::Install.new(url)
64
+ assert_equal 'mytheme', command.theme_name
65
+ end
66
+ end
@@ -0,0 +1,220 @@
1
+ require 'integration_test_helper'
2
+
3
+ describe 'Default theme' do
4
+ include Nesta::IntegrationTest
5
+
6
+ def in_categories(*categories)
7
+ { 'categories' => categories.map(&:path).join(', ') }
8
+ end
9
+
10
+ it 'includes description meta tag' do
11
+ with_temp_content_directory do
12
+ model = create(:page, metadata: { 'Description' => 'A good page' })
13
+ visit model.path
14
+ xpath = "//meta[@name='description'][@content='A good page']"
15
+ assert_has_xpath xpath, visible: false
16
+ end
17
+ end
18
+
19
+ it 'includes keywords meta tag' do
20
+ with_temp_content_directory do
21
+ model = create(:page, metadata: { 'Keywords' => 'good, content' })
22
+ visit model.path
23
+ xpath = "//meta[@name='keywords'][@content='good, content']"
24
+ assert_has_xpath xpath, visible: false
25
+ end
26
+ end
27
+
28
+ it "doesn't include Google Analytics JavaScript snippet by default" do
29
+ with_temp_content_directory do
30
+ visit '/'
31
+ assert_has_no_css 'script', text: 'google-analytics.com'
32
+ end
33
+ end
34
+
35
+ it 'includes Google Analytics JavaScript when configured' do
36
+ analytics_code = { 'google_analytics_code' => 'UA-1234' }
37
+ stub_config(temp_content.merge('test' => analytics_code)) do
38
+ visit '/'
39
+ assert_nil all('script').find { |s| s[:src].match /analytics\.js/ }
40
+ end
41
+ end
42
+
43
+ it 'displays site title' do
44
+ site_config = {
45
+ 'title' => 'My blog',
46
+ 'subtitle' => 'about stuff',
47
+ }
48
+ stub_config(temp_content.merge(site_config)) do
49
+ visit '/'
50
+ assert_has_css 'h1', text: 'My blog'
51
+ assert_has_css 'h2', text: 'about stuff'
52
+ end
53
+ end
54
+
55
+ describe 'menus' do
56
+ def create_pages_in_menu
57
+ pages
58
+ end
59
+
60
+ it "doesn't include menu markup if menu not configured" do
61
+ with_temp_content_directory do
62
+ visit '/'
63
+ assert_has_no_css 'ul.menu'
64
+ end
65
+ end
66
+
67
+ it 'only displays first two levels of menu items' do
68
+ with_temp_content_directory do
69
+ level1, level2, level3 = (0..2).map { create(:page) }
70
+ text = "%s\n %s\n %s\n" % [level1, level2, level3].map(&:abspath)
71
+ create_menu(text)
72
+ visit '/'
73
+ assert_has_css "ul.menu li a:contains('#{level1.link_text}')"
74
+ assert_has_css "ul.menu li ul li a:contains('#{level2.link_text}')"
75
+ assert_has_no_css "ul.menu a:contains('#{level3.link_text}')"
76
+ end
77
+ end
78
+
79
+ def create_page_and_menu
80
+ model = create(:page)
81
+ create_menu(model.path)
82
+ model
83
+ end
84
+
85
+ it "highlights current page's menu item" do
86
+ with_temp_content_directory do
87
+ model = create_page_and_menu
88
+ visit model.path
89
+ assert_has_css "ul.menu li[class='current']:contains('#{model.link_text}')"
90
+ end
91
+ end
92
+
93
+ it "highlights current page's menu item when app mounted at /prefix" do
94
+ Capybara.app = Rack::Builder.new do
95
+ map '/prefix' do
96
+ run Nesta::App.new
97
+ end
98
+ end
99
+
100
+ with_temp_content_directory do
101
+ model = create_page_and_menu
102
+ visit "/prefix/#{model.path}"
103
+ assert_has_css "ul.menu li[class='current']:contains('#{model.link_text}')"
104
+ end
105
+ end
106
+ end
107
+
108
+ it 'only displays read more link for summarised pages' do
109
+ with_temp_content_directory do
110
+ category = create(:category)
111
+ metadata = in_categories(category)
112
+ summarised = create(:page, metadata: metadata.merge('summary' => 'Summary'))
113
+ not_summarised = create(:page, metadata: metadata)
114
+ visit category.path
115
+ assert_has_css 'li:nth-child(1) p', text: summarised.read_more
116
+ assert_has_no_css 'li:nth-child(2) p', text: not_summarised.read_more
117
+ end
118
+ end
119
+
120
+ it 'displays page summaries or full content of unsummarised pages' do
121
+ with_temp_content_directory do
122
+ category = create(:category)
123
+ metadata = in_categories(category)
124
+ summarised = create(:page,
125
+ content: 'Summarised content',
126
+ metadata: metadata.merge(summary: 'Summary'))
127
+ not_summarised = create(:page,
128
+ content: 'Unsummarised content',
129
+ metadata: metadata)
130
+ visit category.path
131
+
132
+ # Page with a summary
133
+ assert_has_css 'li:nth-child(1) p', text: 'Summary'
134
+ assert_has_no_css 'li:nth-child(1) p', text: 'content'
135
+
136
+ # Page without a summary
137
+ assert_has_css 'li:nth-child(2) p', text: 'Unsummarised content'
138
+ assert_has_no_css 'li:nth-child(2) p', text: 'Summary'
139
+ end
140
+ end
141
+
142
+ it 'displays contents of page' do
143
+ with_temp_content_directory do
144
+ model = create(:page, content: 'Body of page')
145
+ visit model.path
146
+ assert_has_css 'p', text: 'Body of page'
147
+ end
148
+ end
149
+
150
+ describe 'category' do
151
+ it 'displays its "articles heading" above the articles' do
152
+ with_temp_content_directory do
153
+ category = create(:category, metadata: {
154
+ 'articles heading' => 'Articles on this topic'
155
+ })
156
+ create(:article, metadata: in_categories(category))
157
+ visit category.path
158
+ assert_has_css 'h1', text: 'Articles on this topic'
159
+ end
160
+ end
161
+
162
+ it 'links to articles in category using article title' do
163
+ with_temp_content_directory do
164
+ category = create(:category)
165
+ article = create(:article, metadata: in_categories(category))
166
+ visit category.path
167
+ link_text, href = article.link_text, article.abspath
168
+ assert_has_css "ol h1 a[href$='#{href}']", text: link_text
169
+ end
170
+ end
171
+ end
172
+
173
+ describe 'article' do
174
+ it 'displays the date' do
175
+ with_temp_content_directory do
176
+ article = create(:article)
177
+ visit article.path
178
+ assert_has_css "time[datetime='#{article.date}']"
179
+ end
180
+ end
181
+
182
+ it 'links to parent page in breadcrumb' do
183
+ with_temp_content_directory do
184
+ parent = create(:category)
185
+ article = create(:article, path: "#{parent.path}/child")
186
+ visit article.path
187
+ href, link_text = parent.abspath, parent.link_text
188
+ assert_has_css "nav.breadcrumb a[href='#{href}']", text: link_text
189
+ end
190
+ end
191
+
192
+ it 'links to its categories at end of article' do
193
+ with_temp_content_directory do
194
+ categories = [create(:category), create(:category)]
195
+ article = create(:article, metadata: in_categories(*categories))
196
+ visit article.path
197
+ categories.each do |category|
198
+ href, link_text = category.abspath, category.link_text
199
+ assert_has_css "p.meta a[href$='#{href}']", text: link_text
200
+ end
201
+ end
202
+ end
203
+
204
+ it 'displays comments from Disqus' do
205
+ stub_config(temp_content.merge('disqus_short_name' => 'mysite')) do
206
+ article = create(:article)
207
+ visit article.path
208
+ assert_has_css '#disqus_thread'
209
+ assert_has_css 'script[src*="mysite.disqus.com"]', visible: false
210
+ end
211
+ end
212
+
213
+ it "doesn't use Disqus if it's not configured" do
214
+ with_temp_content_directory do
215
+ visit create(:article).path
216
+ assert_has_no_css '#disqus_thread'
217
+ end
218
+ end
219
+ end
220
+ end
@@ -0,0 +1,118 @@
1
+ require 'integration_test_helper'
2
+
3
+ describe 'Overriding files in gem and themes' do
4
+ include Nesta::IntegrationTest
5
+
6
+ def in_nesta_project(config = {}, &block)
7
+ app_root = temp_path('root')
8
+ content_config = { 'content' => File.join(app_root, 'content') }
9
+ stub_config(content_config.merge(config)) do
10
+ with_app_root(app_root) do
11
+ yield
12
+ end
13
+ end
14
+ ensure
15
+ remove_temp_directory
16
+ end
17
+
18
+ def theme_name
19
+ 'my-theme'
20
+ end
21
+
22
+ def create_fixture(type, name, content)
23
+ base_path = {
24
+ local: Nesta::Path.local,
25
+ theme: Nesta::Path.themes(theme_name)
26
+ }[type]
27
+ path = File.join(base_path, name)
28
+ FileUtils.mkdir_p(File.dirname(path))
29
+ open(path, 'w') { |file| file.write(content) }
30
+ end
31
+
32
+ def create_app_file(type)
33
+ create_fixture(type, 'app.rb', "FROM_#{type.to_s.upcase} = true")
34
+ end
35
+
36
+ describe 'app.rb' do
37
+ it 'loads app.rb from configured theme' do
38
+ in_nesta_project('theme' => theme_name) do
39
+ create_app_file(:theme)
40
+ Nesta::Overrides.load_theme_app
41
+ assert Object.const_get(:FROM_THEME), 'should load app.rb in theme'
42
+ end
43
+ end
44
+
45
+ it 'loads both local and theme app.rb files' do
46
+ in_nesta_project('theme' => theme_name) do
47
+ create_app_file(:local)
48
+ Nesta::Overrides.load_local_app
49
+ create_app_file(:theme)
50
+ Nesta::Overrides.load_theme_app
51
+ assert Object.const_get(:FROM_THEME), 'should load app.rb in theme'
52
+ assert Object.const_get(:FROM_LOCAL), 'should load local app.rb'
53
+ end
54
+ end
55
+ end
56
+
57
+ def create_view(type, name, content)
58
+ create_fixture(type, File.join('views', name), content)
59
+ end
60
+
61
+ describe 'rendering stylesheets' do
62
+ it 'renders Sass stylesheets' do
63
+ in_nesta_project do
64
+ create_view(:local, 'master.sass', "body\n width: 10px * 2")
65
+ visit '/css/master.css'
66
+ assert_match /width: 20px;/, body, 'should match /width: 20px;/'
67
+ end
68
+ end
69
+
70
+ it 'renders SCSS stylesheets' do
71
+ in_nesta_project do
72
+ create_view(:local, 'master.scss', "body {\n width: 10px * 2;\n}")
73
+ visit '/css/master.css'
74
+ assert_match /width: 20px;/, body, 'should match /width: 20px;/'
75
+ end
76
+ end
77
+
78
+ it 'renders stylesheet in the the gem if no others found' do
79
+ in_nesta_project do
80
+ visit '/css/master.css'
81
+ assert_equal 200, page.status_code
82
+ end
83
+ end
84
+ end
85
+
86
+ def create_haml(type, name, content)
87
+ create_view(type, 'layout.haml', '= yield')
88
+ create_view(type, name, content)
89
+ end
90
+
91
+ describe 'rendering Haml' do
92
+ it 'uses local template in place of default' do
93
+ in_nesta_project do
94
+ create_haml(:local, 'page.haml', '%p Local template')
95
+ visit create(:category).abspath
96
+ assert_has_xpath '//p', text: 'Local template'
97
+ end
98
+ end
99
+
100
+ it 'uses theme template in place of default' do
101
+ in_nesta_project('theme' => theme_name) do
102
+ create_haml(:theme, 'page.haml', '%p Theme template')
103
+ visit create(:category).abspath
104
+ assert_has_xpath '//p', text: 'Theme template'
105
+ end
106
+ end
107
+
108
+ it 'prioritise local templates over theme templates' do
109
+ in_nesta_project('theme' => theme_name) do
110
+ create_haml(:local, 'page.haml', '%p Local template')
111
+ create_haml(:theme, 'page.haml', '%p Theme template')
112
+ visit create(:category).abspath
113
+ assert_has_xpath '//p', text: 'Local template'
114
+ assert_has_no_xpath '//p', text: 'Theme template'
115
+ end
116
+ end
117
+ end
118
+ end
@@ -0,0 +1,96 @@
1
+ require 'integration_test_helper'
2
+
3
+ describe 'Routing' do
4
+ include Nesta::IntegrationTest
5
+
6
+ it 'redirects requests with trailing slash' do
7
+ with_temp_content_directory do
8
+ model = create(:page)
9
+ visit model.path + '/'
10
+ assert_equal model.abspath, page.current_path
11
+ end
12
+ end
13
+
14
+ describe 'not_found handler' do
15
+ it 'returns HTTP code 404' do
16
+ with_temp_content_directory do
17
+ visit '/no-such-page'
18
+ assert_equal 404, page.status_code
19
+ end
20
+ end
21
+ end
22
+
23
+ describe 'default route' do
24
+ it 'provides access to helper methods in Haml pages' do
25
+ with_temp_content_directory do
26
+ model = create(:category,
27
+ ext: 'haml',
28
+ content: '%div= format_date(Date.new(2010, 11, 23))')
29
+ visit model.path
30
+ assert_has_css 'div', text: '23 November 2010'
31
+ end
32
+ end
33
+
34
+ it "should access helpers when rendering articles on a category page" do
35
+ with_temp_content_directory do
36
+ category = create(:page)
37
+ markup = "%h1 Heading\n\n%div= format_date(Date.new(2010, 11, 23))"
38
+ article = create(:article,
39
+ ext: 'haml',
40
+ metadata: { 'categories' => category.path },
41
+ content: markup)
42
+ visit category.path
43
+ assert_has_css 'div', text: '23 November 2010'
44
+ end
45
+ end
46
+ end
47
+
48
+ def create_attachment_in(directory)
49
+ path = File.join(directory, 'test.txt')
50
+ FileUtils.mkdir_p(directory)
51
+ File.open(path, 'w') { |file| file.write("I'm a test attachment") }
52
+ end
53
+
54
+ describe 'attachments route' do
55
+ it 'returns HTTP code 200' do
56
+ with_temp_content_directory do
57
+ create_attachment_in(Nesta::Config.attachment_path)
58
+ visit '/attachments/test.txt'
59
+ assert_equal 200, page.status_code
60
+ end
61
+ end
62
+
63
+ it 'serves attachment to the client' do
64
+ with_temp_content_directory do
65
+ create_attachment_in(Nesta::Config.attachment_path)
66
+ visit '/attachments/test.txt'
67
+ assert_equal "I'm a test attachment", page.body
68
+ end
69
+ end
70
+
71
+ it 'sets the appropriate MIME type' do
72
+ with_temp_content_directory do
73
+ create_attachment_in(Nesta::Config.attachment_path)
74
+ visit '/attachments/test.txt'
75
+ assert_match %r{^text/plain}, page.response_headers['Content-Type']
76
+ end
77
+ end
78
+
79
+ it 'refuses to serve files outside the attachments directory' do
80
+ # On earlier versions of Sinatra this test would have been handed
81
+ # to the attachments handler. On the current version (1.4.5) it
82
+ # appears as though the request is no longer matched by the
83
+ # attachments route handler, which means we're not in danger of
84
+ # serving serving files to attackers via `#send_file`.
85
+ #
86
+ # I've left the test in anyway, as without it we wouldn't become
87
+ # aware of a security hole if there was a regression in Sinatra.
88
+ #
89
+ with_temp_content_directory do
90
+ model = create(:page)
91
+ visit "/attachments/../pages/#{File.basename(model.filename)}"
92
+ assert_equal 404, page.status_code
93
+ end
94
+ end
95
+ end
96
+ end